1(function (jtd, undefined) { 2 3// Event handling 4 5jtd.addEvent = function(el, type, handler) { 6 if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); 7} 8jtd.removeEvent = function(el, type, handler) { 9 if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); 10} 11jtd.onReady = function(ready) { 12 // in case the document is already rendered 13 if (document.readyState!='loading') ready(); 14 // modern browsers 15 else if (document.addEventListener) document.addEventListener('DOMContentLoaded', ready); 16 // IE <= 8 17 else document.attachEvent('onreadystatechange', function(){ 18 if (document.readyState=='complete') ready(); 19 }); 20} 21 22// Show/hide mobile menu 23 24function initNav() { 25 const mainNav = document.querySelector('.js-main-nav'); 26 const pageHeader = document.querySelector('.js-page-header'); 27 const navTrigger = document.querySelector('.js-main-nav-trigger'); 28 29 jtd.addEvent(navTrigger, 'click', function(e){ 30 e.preventDefault(); 31 var text = navTrigger.innerText; 32 var textToggle = navTrigger.getAttribute('data-text-toggle'); 33 34 mainNav.classList.toggle('nav-open'); 35 pageHeader.classList.toggle('nav-open'); 36 navTrigger.classList.toggle('nav-open'); 37 navTrigger.innerText = textToggle; 38 navTrigger.setAttribute('data-text-toggle', text); 39 textToggle = text; 40 }) 41} 42 43// Site search 44 45function initSearch() { 46 var request = new XMLHttpRequest(); 47 request.open('GET', 'https://w3c.studio24.net/assets/js/search-data.json', true); 48 49 request.onload = function(){ 50 if (request.status >= 200 && request.status < 400) { 51 // Success! 52 var data = JSON.parse(request.responseText); 53 54 55 lunr.tokenizer.separator = /[\s\-/]+/ 56 57 58 var index = lunr(function () { 59 this.ref('id'); 60 this.field('title', { boost: 200 }); 61 this.field('content', { boost: 2 }); 62 this.field('url'); 63 this.metadataWhitelist = ['position'] 64 65 for (var i in data) { 66 this.add({ 67 id: i, 68 title: data[i].title, 69 content: data[i].content, 70 url: data[i].url 71 }); 72 } 73 }); 74 75 searchResults(index, data); 76 } else { 77 // We reached our target server, but it returned an error 78 console.log('Error loading ajax request. Request status:' + request.status); 79 } 80 }; 81 82 request.onerror = function(){ 83 // There was a connection error of some sort 84 console.log('There was a connection error'); 85 }; 86 87 request.send(); 88 89 function searchResults(index, data) { 90 var index = index; 91 var docs = data; 92 var searchInput = document.querySelector('.js-search-input'); 93 var searchResults = document.querySelector('.js-search-results'); 94 95 function hideResults() { 96 searchResults.innerHTML = ''; 97 searchResults.classList.remove('active'); 98 } 99 100 jtd.addEvent(searchInput, 'keydown', function(e){ 101 switch (e.keyCode) { 102 case 38: // arrow up 103 e.preventDefault(); 104 var active = document.querySelector('.search-result.active'); 105 if (active) { 106 active.classList.remove('active'); 107 if (active.parentElement.previousSibling) { 108 var previous = active.parentElement.previousSibling.querySelector('.search-result'); 109 previous.classList.add('active'); 110 } 111 } 112 return; 113 case 40: // arrow down 114 e.preventDefault(); 115 var active = document.querySelector('.search-result.active'); 116 if (active) { 117 if (active.parentElement.nextSibling) { 118 var next = active.parentElement.nextSibling.querySelector('.search-result'); 119 active.classList.remove('active'); 120 next.classList.add('active'); 121 } 122 } else { 123 var next = document.querySelector('.search-result'); 124 if (next) { 125 next.classList.add('active'); 126 } 127 } 128 return; 129 case 13: // enter 130 e.preventDefault(); 131 var active = document.querySelector('.search-result.active'); 132 if (active) { 133 active.click(); 134 } else { 135 var first = document.querySelector('.search-result'); 136 if (first) { 137 first.click(); 138 } 139 } 140 return; 141 } 142 }); 143 144 jtd.addEvent(searchInput, 'keyup', function(e){ 145 switch (e.keyCode) { 146 case 27: // When esc key is pressed, hide the results and clear the field 147 hideResults(); 148 searchInput.value = ''; 149 return; 150 case 38: // arrow up 151 case 40: // arrow down 152 case 13: // enter 153 e.preventDefault(); 154 return; 155 } 156 157 hideResults(); 158 159 var input = this.value; 160 if (input === '') { 161 return; 162 } 163 164 var results = index.query(function (query) { 165 var tokens = lunr.tokenizer(input) 166 query.term(tokens, { 167 boost: 10 168 }); 169 query.term(tokens, { 170 wildcard: lunr.Query.wildcard.TRAILING 171 }); 172 }); 173 174 if (results.length > 0) { 175 searchResults.classList.add('active'); 176 var resultsList = document.createElement('ul'); 177 resultsList.classList.add('search-results-list'); 178 searchResults.appendChild(resultsList); 179 180 for (var i in results) { 181 var result = results[i]; 182 var doc = docs[result.ref]; 183 184 var resultsListItem = document.createElement('li'); 185 resultsListItem.classList.add('search-results-list-item'); 186 resultsList.appendChild(resultsListItem); 187 188 var resultLink = document.createElement('a'); 189 resultLink.classList.add('search-result'); 190 resultLink.setAttribute('href', doc.url); 191 resultsListItem.appendChild(resultLink); 192 193 var resultTitle = document.createElement('div'); 194 resultTitle.classList.add('search-result-title'); 195 resultTitle.innerText = doc.title; 196 resultLink.appendChild(resultTitle); 197 198 var resultRelUrl = document.createElement('span'); 199 resultRelUrl.classList.add('search-result-rel-url'); 200 resultRelUrl.innerText = doc.relUrl; 201 resultTitle.appendChild(resultRelUrl); 202 203 var metadata = result.matchData.metadata; 204 var contentFound = false;
205 for (var j in metadata) { 206 if (metadata[j].title) { 207 var position = metadata[j].title.position[0]; 208 var start = position[0]; 209 var end = position[0] + position[1]; 210 resultTitle.innerHTML = doc.title.substring(0, start) + '<span class="search-result-highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length)+'<span class="search-result-rel-url">'+doc.relUrl+'</span>'; 211 212 } else if (metadata[j].content && !contentFound) { 213 contentFound = true; 214 215 var position = metadata[j].content.position[0]; 216 var start = position[0]; 217 var end = position[0] + position[1]; 218 var previewStart = start; 219 var previewEnd = end; 220 var ellipsesBefore = true; 221 var ellipsesAfter = true; 222 for (var k = 0; k < 3; k++) { 223 var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2); 224 var nextDot = doc.content.lastIndexOf('.', previewStart - 2); 225 if ((nextDot > 0) && (nextDot > nextSpace)) { 226 previewStart = nextDot + 1; 227 ellipsesBefore = false; 228 break; 229 } 230 if (nextSpace < 0) { 231 previewStart = 0; 232 ellipsesBefore = false; 233 break; 234 } 235 previewStart = nextSpace + 1; 236 } 237 for (var k = 0; k < 10; k++) { 238 var nextSpace = doc.content.indexOf(' ', previewEnd + 1); 239 var nextDot = doc.content.indexOf('.', previewEnd + 1); 240 if ((nextDot > 0) && (nextDot < nextSpace)) { 241 previewEnd = nextDot; 242 ellipsesAfter = false; 243 break; 244 } 245 if (nextSpace < 0) { 246 previewEnd = doc.content.length; 247 ellipsesAfter = false; 248 break; 249 } 250 previewEnd = nextSpace; 251 } 252 var preview = doc.content.substring(previewStart, start); 253 if (ellipsesBefore) { 254 preview = '... ' + preview; 255 } 256 preview += '<span class="search-result-highlight">' + doc.content.substring(start, end) + '</span>'; 257 preview += doc.content.substring(end, previewEnd); 258 if (ellipsesAfter) { 259 preview += ' ...'; 260 } 261 262 var resultPreview = document.createElement('div'); 263 resultPreview.classList.add('search-result-preview'); 264 resultPreview.innerHTML = preview; 265 resultLink.appendChild(resultPreview); 266 } 267 } 268 } 269 } 270 }); 271 272 jtd.addEvent(searchInput, 'blur', function(){ 273 setTimeout(function(){ hideResults() }, 300); 274 }); 275 } 276} 277 278function pageFocus() { 279 var mainContent = document.querySelector('.js-main-content'); 280 mainContent.focus(); 281} 282 283// Document ready 284 285jtd.onReady(function(){ 286 initNav(); 287 pageFocus(); 288 if (typeof lunr !== 'undefined') { 289 initSearch(); 290 } 291}); 292 293})(window.jtd = window.jtd || {}); 294 295
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.