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.