Updated lunr.js, added search navigation and preview/highlighting

This commit is contained in:
Silvio Giebl
2019-05-18 23:07:02 +02:00
parent e9f016ac0f
commit e64a6aa239
5 changed files with 219 additions and 69 deletions

View File

@@ -31,13 +31,6 @@ function toggleNav(){
// 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");
@@ -62,17 +55,25 @@ function initSearch() {
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);
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: data[i].id,
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);
@@ -86,66 +87,168 @@ function initSearch() {
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;
searchResults.innerHTML = '';
searchResults.classList.remove('active');
if (query === '') {
hideResults();
} else {
var results = index.search(query);
if (results.length > 0) {
searchResults.classList.add('active');
var resultsList = document.createElement('ul');
searchResults.appendChild(resultsList);
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;
resultsLink.setAttribute('href', resultsUrl);
resultsLink.innerText = resultsTitle;
resultsUrlDesc.innerText = resultsRelUrl;
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');
resultsList.appendChild(resultsListItem);
resultsListItem.appendChild(resultsLink);
resultsLink.appendChild(resultsUrlDesc);
addEvent(searchInput, 'keydown', function(e){
switch (e.keyCode) {
case 38: // arrow up
var active = document.querySelector('.search-result.active');
if (active.parentElement.previousSibling) {
var previous = active.parentElement.previousSibling.querySelector('.search-result');
active.classList.remove('active');
previous.classList.add('active');
}
}
return;
case 40: // arrow down
var active = document.querySelector('.search-result.active');
if (active.parentElement.nextSibling) {
var next = active.parentElement.nextSibling.querySelector('.search-result');
active.classList.remove('active');
next.classList.add('active');
}
return;
case 13: // enter
var active = document.querySelector('.search-result.active');
active.click();
return;
}
});
// When esc key is pressed, hide the results and clear the field
if (e.keyCode == 27) {
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
return;
}
hideResults();
var input = this.value;
if (input === '') {
return;
}
var results = index.query(function (query) {
var tokens = lunr.tokenizer(input)
query.term(tokens, {
boost: 10
});
query.term(tokens, {
wildcard: lunr.Query.wildcard.TRAILING
});
});
if (results.length > 0) {
searchResults.classList.add('active');
var resultsList = document.createElement('ul');
resultsList.classList.add('search-results-list');
searchResults.appendChild(resultsList);
for (var i in results) {
var result = results[i];
var doc = docs[result.ref];
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');
if (i == 0) {
resultLink.classList.add('active');
}
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 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);
} 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 + 1;
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);
}
}
}
}
});
addEvent(searchInput, 'blur', function(){
setTimeout(function(){ hideResults() }, 300);
});
addEvent(searchInput, 'blur', hideResults);
}
}

File diff suppressed because one or more lines are too long