101 lines
3.0 KiB
JavaScript
101 lines
3.0 KiB
JavaScript
|
let pagesIndex, searchIndex;
|
||
|
const MAX_SUMMARY_LENGTH = 100;
|
||
|
const SENTENCE_BOUNDARY_REGEX = /\b\.\s/gm;
|
||
|
const WORD_REGEX = /\b(\w*)[\W|\s|\b]?/gm;
|
||
|
|
||
|
|
||
|
async function initSearchIndex() {
|
||
|
try {
|
||
|
const response = await fetch("/index.json");
|
||
|
pagesIndex = await response.json();
|
||
|
searchIndex = lunr(function () {
|
||
|
this.field("title");
|
||
|
this.field("categories");
|
||
|
this.field("content");
|
||
|
this.ref("href");
|
||
|
pagesIndex.forEach(page => this.add(page));
|
||
|
});
|
||
|
} catch (e) {
|
||
|
console.log(e);
|
||
|
}
|
||
|
}
|
||
|
initSearchIndex();
|
||
|
|
||
|
|
||
|
function getSearchResults(query) {
|
||
|
return searchIndex.search(query).flatMap((hit) => {
|
||
|
if (hit.ref == "undefined") return [];
|
||
|
let pageMatch = pagesIndex.filter((page) => page.href === hit.ref)[0];
|
||
|
pageMatch.score = hit.score;
|
||
|
return [pageMatch];
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function getLunrSearchQuery(query) {
|
||
|
const searchTerms = query.split(" ");
|
||
|
if (searchTerms.length === 1) {
|
||
|
return query;
|
||
|
}
|
||
|
query = "";
|
||
|
for (const term of searchTerms) {
|
||
|
query += `+${term} `;
|
||
|
}
|
||
|
return query.trim();
|
||
|
}
|
||
|
|
||
|
function searchSite(query) {
|
||
|
const originalQuery = query;
|
||
|
query = getLunrSearchQuery(query);
|
||
|
let results = getSearchResults(query);
|
||
|
return results.length
|
||
|
? results
|
||
|
: query !== originalQuery
|
||
|
? getSearchResults(originalQuery)
|
||
|
: [];
|
||
|
}
|
||
|
const node = document.getElementById("search-input");
|
||
|
node.addEventListener('keydown', function (event) {
|
||
|
if (event.code === 'Enter') {
|
||
|
event.preventDefault();
|
||
|
var q = node.value.trim().toLowerCase();
|
||
|
var res = searchSite(q);
|
||
|
console.log(res);
|
||
|
renderSearchResults(res, q);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
function renderSearchResults(results, term){
|
||
|
|
||
|
var target = document.querySelector("#search-result");
|
||
|
while (target.firstChild)
|
||
|
target.removeChild(target.firstChild);
|
||
|
|
||
|
var title = document.createElement("h1");
|
||
|
title.id = "search-results";
|
||
|
title.className = "list-title";
|
||
|
|
||
|
if (results.length == 0)
|
||
|
title.textContent = `No results found for “${term}”`;
|
||
|
else if (results.length == 1)
|
||
|
title.textContent = `Found one result for “${term}”`;
|
||
|
else
|
||
|
title.textContent = `Found ${results.length} results for “${term}”`;
|
||
|
target.appendChild(title);
|
||
|
document.title = title.textContent;
|
||
|
|
||
|
var template = document.getElementById("search-result");
|
||
|
for (var result of results)
|
||
|
{
|
||
|
var doc = lookup[result.ref];
|
||
|
|
||
|
// Fill out search result template, adjust as needed.
|
||
|
var element = template.content.cloneNode(true);
|
||
|
element.querySelector(".summary-title-link").href =
|
||
|
element.querySelector(".read-more-link").href = doc.uri;
|
||
|
element.querySelector(".summary-title-link").textContent = doc.title;
|
||
|
element.querySelector(".summary").textContent = truncate(doc.content, 70);
|
||
|
target.appendChild(element);
|
||
|
}
|
||
|
title.scrollIntoView(true);
|
||
|
|
||
|
}
|