PageSourceSearch

https://ecstatic-mccarthy-0be5bd.netlify.app/assets/js/just-the-docs.js

js ecstatic-mccarthy-0be5bd.netlify.app collected 2026-10-03 10:40:49 UTC 9,679 bytes, 295 lines download raw bytes

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.