incngrnt/public/js/search.js
2025-03-16 11:20:59 -06:00

135 lines
4.3 KiB
JavaScript

(() => {
// <stdin>
var seachOpnBtn = null;
var closeBtn = null;
var searchCntr = null;
var resultCntr = null;
var searchBtn = null;
var searchTxt = null;
var isSearchOpen = false;
var isJsonIndexed = false;
var isResEmpty = true;
var fuse;
function fetchJSON(path, callback) {
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var data = JSON.parse(httpRequest.responseText);
if (callback) callback(data);
}
}
};
httpRequest.open("GET", path);
httpRequest.send();
}
function buildIndex() {
var baseURL = searchCntr.getAttribute("data-url");
baseURL = baseURL.replace(/\/?$/, "/");
fetchJSON(baseURL + "index.json", function(data) {
var options = {
shouldSort: true,
ignoreLocation: true,
threshold: 0,
includeMatches: true,
keys: [
{ name: "title", weight: 0.8 },
{ name: "section", weight: 0.2 },
{ name: "summary", weight: 0.6 },
{ name: "content", weight: 0.4 }
]
};
fuse = new Fuse(data, options);
isJsonIndexed = true;
});
}
function openSearch() {
if (!isJsonIndexed) {
buildIndex();
}
if (!isSearchOpen) {
searchCntr.style.display = "flex";
document.body.style.overflow = "hidden";
isSearchOpen = true;
searchTxt.focus();
}
}
function closeSearch() {
if (isSearchOpen) {
searchCntr.style.display = "none";
document.body.style.overflow = "";
isSearchOpen = false;
}
}
function executeQuery(query) {
let results = fuse.search(query);
let resultsHtml = "";
if (results.length > 1) {
results.forEach(function(value, key) {
var meta = value.item.section + " | ";
meta = meta + value.item.date ? value.item.date + " | " : "";
meta = meta + `<span class="srch-link">${value.item.permalink}</span>`;
resultsHtml = resultsHtml + `<li><a href="${value.item.permalink}">
<p class="srch-title">${value.item.title}</p>
<p class="srch-meta">${meta}</p>
<p class="srch-smry">${value.item.summary}</p>
</a></li>`;
});
isResEmpty = false;
} else {
resultsHtml = "";
isResEmpty = true;
}
resultCntr.innerHTML = resultsHtml;
}
window.addEventListener("DOMContentLoaded", (event) => {
seachOpnBtn = document.getElementById("search-open");
searchBtn = document.getElementById("search-btn");
closeBtn = document.getElementById("search-close");
searchCntr = document.getElementById("search-container");
resultCntr = document.getElementById("search-results");
searchTxt = document.getElementById("search-query");
seachOpnBtn.addEventListener("click", openSearch);
closeBtn.addEventListener("click", closeSearch);
searchTxt.onkeyup = function(event2) {
executeQuery(this.value);
};
searchTxt.onkeydown = function(event2) {
if (event2.key == "Enter" && !isResEmpty) {
resultCntr.firstChild.firstElementChild.focus();
event2.preventDefault();
}
};
});
document.addEventListener("keydown", function(event) {
if (event.key == "/") {
event.preventDefault();
openSearch();
}
if (isSearchOpen) {
if (event.key == "Escape") {
event.preventDefault();
closeSearch();
} else if (event.key == "ArrowDown" && !isResEmpty) {
if (document.activeElement == searchTxt) {
resultCntr.firstChild.firstElementChild.focus();
} else if (document.activeElement == resultCntr.lastChild.firstElementChild) {
searchTxt.focus();
} else {
document.activeElement.parentElement.nextSibling.firstElementChild.focus();
}
event.preventDefault();
} else if (event.key == "ArrowUp" && !isResEmpty) {
if (document.activeElement == searchTxt) {
resultCntr.lastChild.firstElementChild.focus();
} else if (document.activeElement == resultCntr.firstChild.firstElementChild) {
searchTxt.focus();
} else {
document.activeElement.parentElement.previousSibling.firstElementChild.focus();
}
event.preventDefault();
}
}
});
})();