PageSourceSearch

https://bioschemas.org/assets/js/search.js

js bioschemas.org collected 2026-10-02 06:16:21 UTC 17,139 bytes, 397 lines download raw bytes

1/**
2 * Search based on just the docs and contains minor changes
3 * 
4 * https://github.com/pmarsceill/just-the-docs
5 * The MIT License (MIT)
6 * Copyright (c) 2016 Patrick Marsceill
7 */
8
9(function (Website, undefined) {
10
11    // Event handling
12
13    Website.addEvent = function (el, type, handler) {
14        if (el.attachEvent) el.attachEvent('on' + type, handler); else el.addEventListener(type, handler);
15    }
16    Website.removeEvent = function (el, type, handler) {
17        if (el.detachEvent) el.detachEvent('on' + type, handler); else el.removeEventListener(type, handler);
18    }
19    Website.onReady = function (ready) {
20        // in case the document is already rendered
21        if (document.readyState != 'loading') ready();
22        // modern browsers
23        else if (document.addEventListener) document.addEventListener('DOMContentLoaded', ready);
24        // IE <= 8
25        else document.attachEvent('onreadystatechange', function () {
26            if (document.readyState == 'complete') ready();
27        });
28    }
29
30    function initSearch() {
31        var request = new XMLHttpRequest();
32        request.open('GET', "/assets/js/search-data.json", true);
33
34        request.onload = function () {
35            if (request.status >= 200 && request.status < 400) {
36                var docs = JSON.parse(request.responseText);
37
38                lunr.tokenizer.separator = /[\s/]+/
39
40                var index = lunr(function () {
41                    this.ref('id');
42                    this.field('title', { boost: 200 });
43                    this.field('content', { boost: 2 });
44                    this.field('relUrl');
45                    this.metadataWhitelist = ['position']
46
47                    for (var i in docs) {
48                        this.add({
49                            id: i,
50                            title: docs[i].title,
51                            content: docs[i].content,
52                            relUrl: docs[i].relUrl
53                        });
54                    }
55                });
56
57                searchLoaded(index, docs);
58            } else {
59                console.log('Error loading ajax request. Request status:' + request.status);
60            }
61        };
62
63        request.onerror = function () {
64            console.log('There was a connection error');
65        };
66
67        request.send();
68    }
69
70    function searchLoaded(index, docs) {
71        var index = index;
72        var docs = docs;
73        var searchInput = document.getElementById('search-input');
74        var searchResults = document.getElementById('search-results');
75        var currentInput;
76        var currentSearchIndex = 0;
77
78        function showSearch() {
79            document.documentElement.classList.add('search-active');
80        }
81
82        function hideSearch() {
83            document.documentElement.classList.remove('search-active');
84        }
85
86        function update() {
87            currentSearchIndex++;
88
89            var input = searchInput.value;
90            if (input === '') {
91                hideSearch();
92            } else {
93                showSearch();
94                var hero = document.getElementById("search-section");
95                if(hero){
96                    document.querySelector('#search-section').scrollIntoView();
97                }
98                
99            }
100            if (input === currentInput) {
101                return;
102            }
103            currentInput = input;
104            searchResults.innerHTML = '';
105            if (input === '') {
106                return;
107            }
108
109            var results = index.query(function (query) {
110                var tokens = lunr.tokenizer(input)
111                query.term(tokens, {
112                    boost: 10
113                });
114                query.term(tokens, {
115                    wildcard: lunr.Query.wildcard.TRAILING
116                });
117            });
118
119            if ((results.length == 0) && (input.length > 2)) {
120                var tokens = lunr.tokenizer(input).filter(function (token, i) {
121                    return token.str.length < 20;
122                })
123                if (tokens.length > 0) {
124                    results = index.query(function (query) {
125                        query.term(tokens, {
126                            editDistance: Math.round(Math.sqrt(input.length / 2 - 1))
127                        });
128                    });
129                }
130            }
131
132            if (results.length == 0) {
133                var noResultsDiv = document.createElement('div');
134                noResultsDiv.classList.add('search-no-result');
135                noResultsDiv.innerText = 'No results found';
136                searchResults.appendChild(noResultsDiv);
137
138            } else {
139                var resultsList = document.createElement('ul');
140                searchResults.appendChild(resultsList);
141
142                addResults(resultsList, results, 0, 10, 100, currentSearchIndex);
143            }
144
145            function addResults(resultsList, results, start, batchSize, batchMillis, searchIndex) {
146                if (searchIndex != currentSearchIndex) {
147                    return;
148                }
149                for (var i = start; i < (start + batchSize); i++) {
150                    if (i == results.length) {
151                        return;
152                    }
153                    addResult(resultsList, results[i]);
154                }
155                setTimeout(function () {
156                    addResults(resultsList, results, start + batchSize, batchSize, batchMillis, searchIndex);
157                }, batchMillis);
158            }
159
160            function addResult(resultsList, result) {
161                var doc = docs[result.ref];
162
163                var resultsListItem = document.createElement('li');
164                resultsList.appendChild(resultsListItem);
165
166                var resultLink = document.createElement('a');
167                resultLink.setAttribute('href', doc.url);
168                resultsListItem.appendChild(resultLink);
169
170                var resultTitle = document.createElement('div');
171                resultTitle.classList.add('search-result-title');
172                resultLink.appendChild(resultTitle);
173
174                var resultDoc = document.createElement('div');
175                resultDoc.classList.add('search-result-doc');
176                resultTitle.appendChild(resultDoc);
177
178                var resultDocTitle = document.createElement('div');
179                resultDocTitle.classList.add('search-result-doc-title');
180                resultDocTitle.innerHTML = doc.doc;
181                resultDoc.appendChild(resultDocTitle);
182                var resultDocOrSection = resultDocTitle;
183
184                if (doc.doc != doc.title) {
185                    resultDoc.classList.add('search-result-doc-parent');
186                    var resultSection = document.createElement('div');
187                    resultSection.classList.add('search-result-section');
188                    resultSection.innerHTML = doc.title;
189                    resultTitle.appendChild(resultSection);
190                    resultDocOrSection = resultSection;
191                }
192
193                var metadata = result.matchData.metadata;
194                var titlePositions = [];
195                var contentPositions = [];
196                for (var j in metadata) {
197                    var meta = metadata[j];
198                    if (meta.title) {
199                        var positions = meta.title.position;
200                        for (var k in positions) {
201                            titlePositions.push(positions[k]);
202                        }
203                    }
204                    if (meta.content) {
205                        var positions = meta.content.position;
206                        for (var k in positions) {
207                            var position = positions[k];
208                            var previewStart = position[0];
209                            var previewEnd = position[0] + position[1];
210                            var ellipsesBefore = true;
211                            var ellipsesAfter = true;
212                            for (var k = 0; k < 4; k++) {
213                                var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
214                                var nextDot = doc.content.lastIndexOf('. ', previewStart - 2);
215                                if ((nextDot >= 0) && (nextDot > nextSpace)) {
216                                    previewStart = nextDot + 1;
217                                    ellipsesBefore = false;
218                                    break;
219                                }
220                                if (nextSpace < 0) {
221                                    previewStart = 0;
222                                    ellipsesBefore = false;
223                                    break;
224                                }
225                                previewStart = nextSpace + 1;
226                            }
227                            for (var k = 0; k < 4; k++) {
228                                var nextSpace = doc.content.indexOf(' ', previewEnd + 1);
229                                var nextDot = doc.content.indexOf('. ', previewEnd + 1);
230                                if ((nextDot >= 0) && (nextDot < nextSpace)) {
231                                    previewEnd = nextDot;
232                                    ellipsesAfter = false;
233                                    break;
234                                }
235                                if (nextSpace < 0) {
236                                    previewEnd = doc.content.length;
237                                    ellipsesAfter = false;
238                                    break;
239                                }
240                                previewEnd = nextSpace;
241                            }
242                            contentPositions.push({
243                                highlight: position,
244                                previewStart: previewStart, previewEnd: previewEnd,
245                                ellipsesBefore: ellipsesBefore, ellipsesAfter: ellipsesAfter
246                            });
247                        }
248                    }
249                }
250
251                if (titlePositions.length > 0) {
252                    titlePositions.sort(function (p1, p2) { return p1[0] - p2[0] });
253                    resultDocOrSection.innerHTML = '';
254                    addHighlightedText(resultDocOrSection, doc.title, 0, doc.title.length, titlePositions);
255                }
256
257                if (contentPositions.length > 0) {
258                    contentPositions.sort(function (p1, p2) { return p1.highlight[0] - p2.highlight[0] });
259                    var contentPosition = contentPositions[0];
260                    var previewPosition = {
261                        highlight: [contentPosition.highlight],
262                        previewStart: contentPosition.previewStart, previewEnd: contentPosition.previewEnd,
263                        ellipsesBefore: contentPosition.ellipsesBefore, ellipsesAfter: contentPosition.ellipsesAfter
264                    };
265                    var previewPositions = [previewPosition];
266                    for (var j = 1; j < contentPositions.length; j++) {
267                        contentPosition = contentPositions[j];
268                        if (previewPosition.previewEnd < contentPosition.previewStart) {
269                            previewPosition = {
270                                highlight: [contentPosition.highlight],
271                                previewStart: contentPosition.previewStart, previewEnd: contentPosition.previewEnd,
272                                ellipsesBefore: contentPosition.ellipsesBefore, ellipsesAfter: contentPosition.ellipsesAfter
273                            }
274                            previewPositions.push(previewPosition);
275                        } else {
276                            previewPosition.highlight.push(contentPosition.highlight);
277                            previewPosition.previewEnd = contentPosition.previewEnd;
278                            previewPosition.ellipsesAfter = contentPosition.ellipsesAfter;
279                        }
280                    }
281
282                    var resultPreviews = document.createElement('div');
283                    resultPreviews.classList.add('search-result-previews');
284                    resultLink.appendChild(resultPreviews);
285
286                    var content = doc.content;
287                    for (var j = 0; j < Math.min(previewPositions.length, 3); j++) {
288                        var position = previewPositions[j];
289
290                        var resultPreview = document.createElement('div');
291                        resultPreview.classList.add('search-result-preview');
292                        resultPreviews.appendChild(resultPreview);
293
294                        if (position.ellipsesBefore) {
295                            resultPreview.appendChild(document.createTextNode('... '));
296                        }
297                        addHighlightedText(resultPreview, content, position.previewStart, position.previewEnd, position.highlight);
298                        if (position.ellipsesAfter) {
299                            resultPreview.appendChild(document.createTextNode(' ...'));
300                        }
301                    }
302                }
303                //  Show relative url in search results 
304                //  var resultRelUrl = document.createElement('span');
305                //  resultRelUrl.classList.add('search-result-rel-url');
306                //  resultRelUrl.innerText = doc.relUrl;
307                //  resultTitle.appendChild(resultRelUrl);
308            }
309
310            function addHighlightedText(parent, text, start, end, positions) {
311                var index = start;
312                for (var i in positions) {
313                    var position = positions[i];
314                    var span = document.createElement('span');
315                    span.innerHTML = text.substring(index, position[0]);
316                    parent.appendChild(span);
317                    index = position[0] + position[1];
318                    var highlight = document.createElement('span');
319                    highlight.classList.add('search-result-highlight');
320                    highlight.innerHTML = text.substring(position[0], index);
321                    parent.appendChild(highlight);
322                }
323                var span = document.createElement('span');
324                span.innerHTML = text.substring(index, end);
325                parent.appendChild(span);
326            }
327        }
328
329        Website.addEvent(searchInput, 'focus', function () {
330            setTimeout(update, 0);
331        });
332
333        Website.addEvent(searchInput, 'keyup', function (e) {
334            switch (e.keyCode) {
335                case 27: // When esc key is pressed, hide the results and clear the field
336                    searchInput.value = '';
337                    break;
338                case 38: // arrow up
339                case 40: // arrow down
340                case 13: // enter
341                    e.preventDefault();
342                    return;
343            }
344            update();
345        });
346
347        Website.addEvent(searchInput, 'keydown', function (e) {
348            switch (e.keyCode) {
349                case 38: // arrow up
350                    e.preventDefault();
351                    var active = document.querySelector('.search-results a.active');
352                    if (active) {
353                        active.classList.remove('active');
354                        if (active.parentElement.previousSibling) {
355                            var previous = active.parentElement.previousSibling.querySelector('.search-results a');
356                            previous.classList.add('active');
357                        }
358                    }
359                    return;
360                case 40: // arrow down
361                    e.preventDefault();
362                    var active = document.querySelector('.search-results a.active');
363                    if (active) {
364                        if (active.parentElement.nextSibling) {
365                            var next = active.parentElement.nextSibling.querySelector('.search-results a');
366                            active.classList.remove('active');
367                            next.classList.add('active');
368                        }
369                    } else {
370                        var next = document.querySelector('.search-results a');
371                        if (next) {
372                            next.classList.add('active');
373                        }
374                    }
375                    return;
376                case 13: // enter
377                    e.preventDefault();
378                    var active = document.querySelector('.search-results a.active');
379                    if (active) {
380                        active.click();
381                    } 
382                    return;
383            }
384        });
385
386        Website.addEvent(document, 'click', function (e) {
387            if (e.target != searchInput) {
388                hideSearch();
389            }
390        });
391    }
392
393    Website.onReady(function () {
394        initSearch();
395    });
396
397})(window.Website = window.Website || {});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.