1 // Taken from https://github.com/gbxyz/webidx/tree/main
2 // BSD 3-Clause License
3 // Copyright (c) 2024, Gavin Brown
4 // Full license: https://github.com/gbxyz/webidx/blob/a28a984d38fd546d1bec4d6a4a5a47ab86cb08f8/LICENSE
7 webidx = window.webidx;
9 webidx.search = async function (params) {
14 webidx.sql = await window.initSqlJs({locateFile: file => `https://sql.js.org/dist/${file}`});
17 if (webidx.hasOwnProperty('db')) {
18 webidx.displayResults(webidx.query(params.query), params);
21 webidx.loadDB(params);
26 webidx.loadDB = function (params) {
27 var xhr = new XMLHttpRequest();
29 xhr.open('GET', params.dbfile);
30 xhr.timeout = params.timeout ?? 5000;
31 xhr.responseType = 'arraybuffer';
33 xhr.ontimeout = function() {
34 if (params.hasOwnProperty('errorCallback')) {
35 params.errorCallback('Unable to load index, please refresh the page.');
39 xhr.onload = function() {
40 webidx.initializeDB(this.response);
41 webidx.displayResults(webidx.query(params.query), params);
47 webidx.initializeDB = function (arrayBuffer) {
48 webidx.db = new webidx.sql.Database(new Uint8Array(arrayBuffer));
53 webidx.wordQuery = webidx.db.prepare("SELECT `id` FROM `words` WHERE (`word`=:word)");
54 webidx.idxQuery = webidx.db.prepare("SELECT `page_id` FROM `index` WHERE (`word`=:word)");
55 webidx.pageQuery = webidx.db.prepare("SELECT `url`,`title` FROM `pages` WHERE (`id`=:id)");
58 webidx.getWordID = function (word) {
59 webidx.wordQuery.bind([word]);
60 webidx.wordQuery.step();
61 var word_id = webidx.wordQuery.get().shift();
63 webidx.wordQuery.reset();
68 webidx.getPagesHavingWord = function (word_id) {
71 webidx.idxQuery.bind([word_id]);
73 while (webidx.idxQuery.step()) {
74 pages.push(webidx.idxQuery.get().shift());
77 webidx.idxQuery.reset();
82 webidx.getPage = function (page_id) {
83 webidx.pageQuery.bind([page_id]);
85 webidx.pageQuery.step();
87 var page = webidx.pageQuery.getAsObject();
89 webidx.pageQuery.reset();
94 webidx.query = function (query) {
96 // split the search term into words
98 var words = query.toLowerCase().split(" ");
101 // this array maps page ID to rank
106 // iterate over each word
108 while (words.length > 0) {
109 var word = words.shift();
112 if (0 == word.indexOf("-")) {
114 word = word.substring(1);
117 var word_id = webidx.getWordID(word);
120 // if the word isn't present, ignore it
123 var pages = webidx.getPagesHavingWord(word_id);
125 pages.forEach(function (page_id) {
127 if (pageRank[page_id]) {
128 pageRank[page_id] -= 65535;
131 pageRank[page_id] = -65535;
136 if (pageRank[page_id]) {
140 pageRank[page_id] = 1;
149 // transform the results into a format that can be sorted
151 var sortedPages = [];
153 pageRank.forEach(function (rank, page_id) {
155 sortedPages.push({rank: rank, page_id: page_id});
160 // sort the results in descending rank order
162 sortedPages.sort(function(a, b) {
163 return b.rank - a.rank;
167 // this will be populated with the actual pages
172 // get page data for each result
174 sortedPages.forEach(function(result) {
175 pages.push(webidx.getPage(result.page_id));
181 webidx.regExpQuote = function (str) {
182 return str.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
185 webidx.displayResults = function (pages, params) {
186 var callback = params.resultCallback ?? webidx.displayDialog;
187 callback(pages, params);
190 webidx.displayDialog = function (pages, params) {
191 var dialog = document.createElement('dialog');
192 dialog.classList.add('webidx-results-dialog')
194 dialog.appendChild(document.createElement('h2')).appendChild(document.createTextNode('Search Results'));
196 if (pages.length < 1) {
197 dialog.appendChild(document.createElement('p')).appendChild(document.createTextNode('Nothing found.'));
200 var ul = dialog.appendChild(document.createElement('ul'));
202 pages.forEach(function(page) {
203 var titleText = page.title;
205 if (params.titleSuffix) {
206 titleText = titleText.replace(new RegExp(webidx.regExpQuote(params.titleSuffix)+'$'), '');
209 if (params.titlePrefix) {
210 titleText = titleText.replace(new RegExp('^' + webidx.regExpQuote(params.titleSuffix)), '');
213 var li = ul.appendChild(document.createElement('li'));
214 var a = li.appendChild(document.createElement('a'));
215 a.setAttribute('href', page.url);
216 a.appendChild(document.createTextNode(titleText));
217 li.appendChild(document.createElement('br'));
219 var span = li.appendChild(document.createElement('span'));
220 span.classList.add('webidx-page-url');
221 span.appendChild(document.createTextNode(page.url));
225 var form = dialog.appendChild(document.createElement('form'));
226 form.setAttribute('method', 'dialog');
228 var button = form.appendChild(document.createElement('button'));
229 button.setAttribute('autofocus', true);
230 button.appendChild(document.createTextNode('Close'));
232 document.body.appendChild(dialog);
234 dialog.addEventListener('close', function() {
235 dialog.parentNode.removeChild(dialog);
239 dialog.scrollTop = 0;