aboutsummaryrefslogtreecommitdiff
path: root/static/js/fixedsearch.ts
diff options
context:
space:
mode:
Diffstat (limited to 'static/js/fixedsearch.ts')
-rw-r--r--static/js/fixedsearch.ts194
1 files changed, 194 insertions, 0 deletions
diff --git a/static/js/fixedsearch.ts b/static/js/fixedsearch.ts
new file mode 100644
index 0000000..26b9ac1
--- /dev/null
+++ b/static/js/fixedsearch.ts
@@ -0,0 +1,194 @@
+(function () {
+ self.addEventListener("DOMContentLoaded", function () {
+ /*
+ Originally Based on fixedsearch, a super fast, client side search for Hugo.io with Fusejs.io
+ based on https://gist.github.com/cmod/5410eae147e4318164258742dd053993
+ */
+
+ const form = document.getElementById("search-form"); // search form
+ const query = document.getElementById("search-input"); // input box for search
+ const submit = document.getElementById("search-submit"); // form submit button
+ const dropdown = document.getElementById("search-results"); // targets the <ul>
+
+ form.addEventListener("focusin", function () {
+ initialize();
+ });
+
+ form.addEventListener("submit", function (event) {
+ event.preventDefault();
+ return false;
+ });
+
+ form.addEventListener("keydown", function (event) {
+ const head =
+ dropdown.firstChild.nextElementSibling.firstChild.nextElementSibling;
+ const tail = dropdown.lastElementChild.firstChild.nextElementSibling;
+
+ // ESC (27)
+ if (query.contains(event.target)) {
+ if (event.keyCode == 27) {
+ document.activeElement.blur();
+ dropdown.setAttribute("hidden", "");
+ }
+ }
+
+ // DOWN (40)
+ if (event.keyCode == 40) {
+ event.preventDefault();
+ if (document.activeElement == query) head.focus();
+ else if (document.activeElement == tail) query.focus();
+ else {
+ document.activeElement.parentElement.nextElementSibling.firstChild
+ .nextElementSibling.focus();
+ }
+ }
+
+ // UP (38)
+ if (event.keyCode == 38) {
+ event.preventDefault();
+ if (document.activeElement == query) tail.focus();
+ else if (document.activeElement == head) query.focus();
+ else {
+ document.activeElement.parentElement.previousElementSibling.firstChild
+ .nextElementSibling.focus();
+ }
+ }
+
+ // BACKSPACE (8)
+ if (event.keyCode == 8) {
+ if (document.activeElement != query) {
+ event.preventDefault();
+ query.focus();
+ }
+ }
+
+ // ENTER (13)
+ if (event.keyCode == 13) {
+ if (dropdown && document.activeElement == query) {
+ event.preventDefault();
+ head.focus();
+ self.window.location = document.activeElement.href;
+ }
+ }
+ });
+
+ let scrolls = 0;
+
+ self.addEventListener("scroll", function () {
+ if (scrolls > 3) {
+ scrolls = 0;
+ document.activeElement.blur();
+ dropdown.setAttribute("hidden", "");
+ }
+ scrolls++;
+ });
+
+ document.addEventListener("click", function (event) {
+ if (!form.contains(event.target)) {
+ dropdown.setAttribute("hidden", "");
+ }
+ });
+
+ function fetch_JSON(path, callback) {
+ const httpRequest = new XMLHttpRequest();
+ httpRequest.onreadystatechange = function () {
+ if (httpRequest.readyState === 4) {
+ if (httpRequest.status === 200) {
+ const data = JSON.parse(httpRequest.responseText);
+ if (callback) callback(data);
+ }
+ }
+ };
+ httpRequest.open("GET", path);
+ httpRequest.send();
+ }
+
+ /* Load script based on https://stackoverflow.com/a/55451823 */
+
+ function load_script(url) {
+ return new Promise(function (resolve, reject) {
+ const script = document.createElement("script");
+ script.onerror = reject;
+ script.onload = resolve;
+ if (document.currentScript) {
+ document.currentScript.parentNode.insertBefore(
+ script,
+ document.currentScript,
+ );
+ } else {
+ document.head.appendChild(script);
+ }
+ script.src = url;
+ });
+ }
+
+ let first_run = true; // allow us to delay loading json data unless search activated
+
+ function initialize() {
+ if (first_run) {
+ load_script(window.location.origin + "/js/fuzzysort.js")
+ .then(() => {
+ first_run = false;
+ fetch_JSON("/index.json", function (data) {
+ const options = {
+ key: ["title"],
+ };
+
+ query.addEventListener("keyup", function () {
+ search(query.value, data.items, options);
+ });
+
+ query.addEventListener("focusin", function () {
+ search(query.value, data.items, options);
+ });
+
+ search(query.value, data.items, options);
+ });
+ }).catch((error) => {
+ console.log("Error failed to load fuzzy sort: " + error);
+ });
+ }
+ }
+
+ function search(term, data, options) {
+ const results = fuzzysort.go(term, data, options);
+ let items = "";
+
+ if (results.length === 0 && term.length >= 0) {
+ let separator = "—";
+ if (term.length === 0) separator = "";
+ items = `
+ <li>
+ <a href="javascript: void(0)" tabindex="0">${term} ${separator} No Results Found</a>
+ </li>
+ `;
+ dropdown.removeAttribute("hidden");
+ } else {
+ dropdown.removeAttribute("hidden");
+ for (const string in results.slice(0, 10)) {
+ const decode = document.createElement("textarea");
+ decode.innerHTML = results[string].obj.title;
+
+ let highlight = fuzzysort.highlight(
+ fuzzysort.single(term, decode.value),
+ "<span>",
+ "</span>",
+ );
+
+ if (highlight === null) {
+ highlight = decode.value;
+ }
+
+ items = items +
+ `
+ <li>
+ <a href="${results[string].obj.url}" tabindex="0">${highlight}</a>
+ </li>
+ `;
+ }
+ }
+
+ dropdown.innerHTML = items;
+ }
+ });
+})();