assets/js/just-the-docs.js in just-the-docs-0.2.5 vs assets/js/just-the-docs.js in just-the-docs-0.2.6

- old
+ new

@@ -1,176 +1,294 @@ +--- +--- +(function (jtd, undefined) { + // Event handling -function addEvent(el, type, handler) { - if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); +jtd.addEvent = function(el, type, handler) { + if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); } -function removeEvent(el, type, handler) { - if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); +jtd.removeEvent = function(el, type, handler) { + if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); } +jtd.onReady = function(ready) { + // in case the document is already rendered + if (document.readyState!='loading') ready(); + // modern browsers + else if (document.addEventListener) document.addEventListener('DOMContentLoaded', ready); + // IE <= 8 + else document.attachEvent('onreadystatechange', function(){ + if (document.readyState=='complete') ready(); + }); +} // Show/hide mobile menu -function toggleNav(){ - const nav = document.querySelector('.js-main-nav'); - const auxNav = document.querySelector('.js-aux-nav'); +function initNav() { + const mainNav = document.querySelector('.js-main-nav'); + const pageHeader = document.querySelector('.js-page-header'); const navTrigger = document.querySelector('.js-main-nav-trigger'); - const search = document.querySelector('.js-search'); - addEvent(navTrigger, 'click', function(){ + jtd.addEvent(navTrigger, 'click', function(e){ + e.preventDefault(); var text = navTrigger.innerText; var textToggle = navTrigger.getAttribute('data-text-toggle'); - nav.classList.toggle('nav-open'); - auxNav.classList.toggle('nav-open'); + mainNav.classList.toggle('nav-open'); + pageHeader.classList.toggle('nav-open'); navTrigger.classList.toggle('nav-open'); - search.classList.toggle('nav-open'); navTrigger.innerText = textToggle; navTrigger.setAttribute('data-text-toggle', text); textToggle = text; }) } // Site search function initSearch() { - var index = lunr(function () { - this.ref('id'); - this.field('title', { boost: 20 }); - this.field('content', { boost: 10 }); - this.field('url'); - }); - - // Get the generated search_data.json file so lunr.js can search it locally. - - sc = document.getElementsByTagName("script"); - source = ''; - - for(idx = 0; idx < sc.length; idx++) - { - s = sc.item(idx); - - if(s.src && s.src.match(/just-the-docs\.js$/)) - { source = s.src; } - } - - jsPath = source.replace('just-the-docs.js', ''); - - jsonPath = jsPath + 'search-data.json'; - var request = new XMLHttpRequest(); - request.open('GET', jsonPath, true); + request.open('GET', '{{ "assets/js/search-data.json" | absolute_url }}', true); - request.onload = function() { + request.onload = function(){ if (request.status >= 200 && request.status < 400) { // Success! var data = JSON.parse(request.responseText); - var keys = Object.keys(data); - for(var i in data) { - index.add({ - id: data[i].id, - title: data[i].title, - content: data[i].content, - url: data[i].url - }); - } - searchResults(data); + lunr.tokenizer.separator = /[\s\-/]+/ + var index = lunr(function () { + this.ref('id'); + this.field('title', { boost: 200 }); + this.field('content', { boost: 2 }); + this.field('url'); + this.metadataWhitelist = ['position'] + + for (var i in data) { + this.add({ + id: i, + title: data[i].title, + content: data[i].content, + url: data[i].url + }); + } + }); + + searchResults(index, data); } else { // We reached our target server, but it returned an error console.log('Error loading ajax request. Request status:' + request.status); } }; - request.onerror = function() { + request.onerror = function(){ // There was a connection error of some sort console.log('There was a connection error'); }; request.send(); - function searchResults(dataStore) { + function searchResults(index, data) { + var index = index; + var docs = data; var searchInput = document.querySelector('.js-search-input'); var searchResults = document.querySelector('.js-search-results'); - var store = dataStore; function hideResults() { searchResults.innerHTML = ''; searchResults.classList.remove('active'); } - addEvent(searchInput, 'keyup', function(e){ - var query = this.value; + jtd.addEvent(searchInput, 'keydown', function(e){ + switch (e.keyCode) { + case 38: // arrow up + e.preventDefault(); + var active = document.querySelector('.search-result.active'); + if (active) { + active.classList.remove('active'); + if (active.parentElement.previousSibling) { + var previous = active.parentElement.previousSibling.querySelector('.search-result'); + previous.classList.add('active'); + } + } + return; + case 40: // arrow down + e.preventDefault(); + var active = document.querySelector('.search-result.active'); + if (active) { + if (active.parentElement.nextSibling) { + var next = active.parentElement.nextSibling.querySelector('.search-result'); + active.classList.remove('active'); + next.classList.add('active'); + } + } else { + var next = document.querySelector('.search-result'); + if (next) { + next.classList.add('active'); + } + } + return; + case 13: // enter + e.preventDefault(); + var active = document.querySelector('.search-result.active'); + if (active) { + active.click(); + } else { + var first = document.querySelector('.search-result'); + if (first) { + first.click(); + } + } + return; + } + }); - searchResults.innerHTML = ''; - searchResults.classList.remove('active'); + jtd.addEvent(searchInput, 'keyup', function(e){ + switch (e.keyCode) { + case 27: // When esc key is pressed, hide the results and clear the field + hideResults(); + searchInput.value = ''; + return; + case 38: // arrow up + case 40: // arrow down + case 13: // enter + e.preventDefault(); + return; + } - if (query === '') { - hideResults(); - } else { - var results = index.search(query); + hideResults(); - if (results.length > 0) { - searchResults.classList.add('active'); - var resultsList = document.createElement('ul'); - searchResults.appendChild(resultsList); + var input = this.value; + if (input === '') { + return; + } - for (var i in results) { - var resultsListItem = document.createElement('li'); - var resultsLink = document.createElement('a'); - var resultsUrlDesc = document.createElement('span'); - var resultsUrl = store[results[i].ref].url; - var resultsRelUrl = store[results[i].ref].relUrl; - var resultsTitle = store[results[i].ref].title; + var results = index.query(function (query) { + var tokens = lunr.tokenizer(input) + query.term(tokens, { + boost: 10 + }); + query.term(tokens, { + wildcard: lunr.Query.wildcard.TRAILING + }); + }); - resultsLink.setAttribute('href', resultsUrl); - resultsLink.innerText = resultsTitle; - resultsUrlDesc.innerText = resultsRelUrl; + if (results.length > 0) { + searchResults.classList.add('active'); + var resultsList = document.createElement('ul'); + resultsList.classList.add('search-results-list'); + searchResults.appendChild(resultsList); - resultsList.classList.add('search-results-list'); - resultsListItem.classList.add('search-results-list-item'); - resultsLink.classList.add('search-results-link'); - resultsUrlDesc.classList.add('fs-2','text-grey-dk-000','d-block'); + for (var i in results) { + var result = results[i]; + var doc = docs[result.ref]; - resultsList.appendChild(resultsListItem); - resultsListItem.appendChild(resultsLink); - resultsLink.appendChild(resultsUrlDesc); + var resultsListItem = document.createElement('li'); + resultsListItem.classList.add('search-results-list-item'); + resultsList.appendChild(resultsListItem); + + var resultLink = document.createElement('a'); + resultLink.classList.add('search-result'); + resultLink.setAttribute('href', doc.url); + resultsListItem.appendChild(resultLink); + + var resultTitle = document.createElement('div'); + resultTitle.classList.add('search-result-title'); + resultTitle.innerText = doc.title; + resultLink.appendChild(resultTitle); + + var resultRelUrl = document.createElement('span'); + resultRelUrl.classList.add('search-result-rel-url'); + resultRelUrl.innerText = doc.relUrl; + resultTitle.appendChild(resultRelUrl); + + var metadata = result.matchData.metadata; + var contentFound = false; + for (var j in metadata) { + if (metadata[j].title) { + var position = metadata[j].title.position[0]; + var start = position[0]; + var end = position[0] + position[1]; + 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>'; + + } else if (metadata[j].content && !contentFound) { + contentFound = true; + + var position = metadata[j].content.position[0]; + var start = position[0]; + var end = position[0] + position[1]; + var previewStart = start; + var previewEnd = end; + var ellipsesBefore = true; + var ellipsesAfter = true; + for (var k = 0; k < 3; k++) { + var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2); + var nextDot = doc.content.lastIndexOf('.', previewStart - 2); + if ((nextDot > 0) && (nextDot > nextSpace)) { + previewStart = nextDot + 1; + ellipsesBefore = false; + break; + } + if (nextSpace < 0) { + previewStart = 0; + ellipsesBefore = false; + break; + } + previewStart = nextSpace + 1; + } + for (var k = 0; k < 10; k++) { + var nextSpace = doc.content.indexOf(' ', previewEnd + 1); + var nextDot = doc.content.indexOf('.', previewEnd + 1); + if ((nextDot > 0) && (nextDot < nextSpace)) { + previewEnd = nextDot; + ellipsesAfter = false; + break; + } + if (nextSpace < 0) { + previewEnd = doc.content.length; + ellipsesAfter = false; + break; + } + previewEnd = nextSpace; + } + var preview = doc.content.substring(previewStart, start); + if (ellipsesBefore) { + preview = '... ' + preview; + } + preview += '<span class="search-result-highlight">' + doc.content.substring(start, end) + '</span>'; + preview += doc.content.substring(end, previewEnd); + if (ellipsesAfter) { + preview += ' ...'; + } + + var resultPreview = document.createElement('div'); + resultPreview.classList.add('search-result-preview'); + resultPreview.innerHTML = preview; + resultLink.appendChild(resultPreview); + } } } - - // When esc key is pressed, hide the results and clear the field - if (e.keyCode == 27) { - hideResults(); - searchInput.value = ''; - } } }); - addEvent(searchInput, 'blur', function(){ + jtd.addEvent(searchInput, 'blur', function(){ setTimeout(function(){ hideResults() }, 300); }); } } function pageFocus() { var mainContent = document.querySelector('.js-main-content'); mainContent.focus(); } - // Document ready -function ready(){ - toggleNav(); +jtd.onReady(function(){ + initNav(); pageFocus(); if (typeof lunr !== 'undefined') { initSearch(); } -} - -// in case the document is already rendered -if (document.readyState!='loading') ready(); -// modern browsers -else if (document.addEventListener) document.addEventListener('DOMContentLoaded', ready); -// IE <= 8 -else document.attachEvent('onreadystatechange', function(){ - if (document.readyState=='complete') ready(); }); + +})(window.jtd = window.jtd || {}); + +{% include js/custom.js %}