diff options
Diffstat (limited to 'static/js/fixedsearch.ts')
-rw-r--r-- | static/js/fixedsearch.ts | 192 |
1 files changed, 107 insertions, 85 deletions
diff --git a/static/js/fixedsearch.ts b/static/js/fixedsearch.ts index 938e1f5..04d318b 100644 --- a/static/js/fixedsearch.ts +++ b/static/js/fixedsearch.ts @@ -1,19 +1,24 @@ /* - Modified Version of Fixed Search: https://gist.github.com/cmod/5410eae147e4318164258742dd053993 - MIT License: https://gist.github.com/Arty2/8b0c43581013753438a3d35c15091a9f#file-license-md + * Fixed Search Copyright (C) 2020 Heracles Papatheodorou + * Copyright (C) Craig Mod, Eddie Webb, and Matthew Daly + * https://gist.github.com/Arty2/8b0c43581013753438a3d35c15091a9f#file-license-md + * Licence: MIT | https://mit-license.org/ */ (function () { - self.addEventListener("DOMContentLoaded", function () { - 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> - const container = document.getElementById("search-frame"); // targets the upper parent container + ["DOMContentLoaded", "URLChangedCustomEvent"].forEach(function (event) { + self.addEventListener(event, function () { + const container = document.querySelector("search-box"); + const dropdown = document.querySelector("search-box ul"); + const form = document.querySelector("search-box form"); + const query = document.querySelector("search-box input"); + const submit = document.querySelector("search-box button"); function first(element) { + if (element.firstChild.nextElementSibling) { return element.firstChild.nextElementSibling.firstChild .nextElementSibling; + } } function last(element) { @@ -35,9 +40,28 @@ document.dispatchEvent(new KeyboardEvent("keydown", { "key": keyname })); } + let selected; + + if (submit === null) return; + submit.addEventListener("click", function (event) { + if (selected) { + event.preventDefault(); + selected.focus(); + return selected.click(); + } first(dropdown).focus(); press("ArrowDown"); + document.activeElement.click(); + }); + + ["keyup", "click"].forEach(function (event) { + form.addEventListener(event, function () { + if (document.activeElement.nodeName === "A") { + return selected = document.activeElement; + } + selected = undefined; + }); }); form.addEventListener("focusin", function () { @@ -51,11 +75,8 @@ }); form.addEventListener("keydown", function (event) { - const head = first(dropdown); - const tail = last(dropdown); - // ESC (27) - if (query.contains(event.target)) { + if (form.contains(event.target)) { if (event.keyCode == 27) { document.activeElement.blur(); dropdown.setAttribute("hidden", ""); @@ -63,6 +84,17 @@ } } + // BACKSPACE (8) + if (event.keyCode == 8) { + if (document.activeElement != query) { + event.preventDefault(); + query.focus(); + } + } + + const head = first(dropdown); + const tail = last(dropdown); + // DOWN (40) if (event.keyCode == 40) { event.preventDefault(); @@ -79,20 +111,12 @@ else previous(document); } - // 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; + head.click(); } } }); @@ -109,46 +133,31 @@ scrolls++; }); - document.addEventListener("click", function (event) { - if (!form.contains(event.target)) { + self.addEventListener("click", function (event) { + if ( + !form.contains(event.target) && + !(document.activeElement === query) && + !(document.activeElement === submit) + ) { dropdown.setAttribute("hidden", ""); container.removeAttribute("data-focus"); } }); - let data = {}; - - function isEmpty(obj) { - return Object.keys(obj).length === 0; - } - - function appendItemsTo(local, remote) { - const paginated = Object.keys(remote).includes("next_url"); - if (isEmpty(local)) { - local = remote; - } else { - local.items = local.items.concat(remote.items); - } - if (paginated) { - fetchJson(remote.next_url, local); - } - data = local; - } - - function fetchJson(url, store) { - const httpRequest = new XMLHttpRequest(); - httpRequest.onreadystatechange = function () { - if (httpRequest.readyState === 4 && httpRequest.status === 200) { - appendItemsTo(store, JSON.parse(httpRequest.responseText)); + function fetch(url, callback) { + const http = new XMLHttpRequest(); + http.onreadystatechange = function () { + if (http.readyState === 4 && http.status === 200 && callback) { + callback(http); } }; - httpRequest.open("GET", url); - httpRequest.send(); + http.open("GET", url); + http.send(); } /* Load script based on https://stackoverflow.com/a/55451823 */ - function loadScript(url) { + function script(url) { return new Promise(function (resolve, reject) { const script = document.createElement("script"); script.onerror = reject; @@ -158,35 +167,54 @@ script, document.currentScript, ); - } else { - document.head.appendChild(script); - } + } else document.head.appendChild(script); script.src = url; }); } - let firstRun = true; + let data = {}; + let boot = true; + + const options = { key: ["title"] }; - function initialize() { - if (firstRun) { - loadScript(window.location.origin + "/js/fuzzysort.js") - .then(() => { - firstRun = false; - fetchJson("/index.json", {}); + function isEmpty(obj) { return Object.keys(obj).length === 0; } - const options = { key: ["title"] }; + function appendItemsTo(local, remote) { + const paginated = Object.keys(remote).includes("next_url"); + if (isEmpty(local)) { + local = remote; + } else { + local.items = local.items.concat(remote.items); + } + if (paginated) { + fetch(remote.next_url, function (request) { + appendItemsTo(local, JSON.parse(request.responseText)); + }); + } else search(query.value, data.items, options); + data = local; + } - query.addEventListener("keyup", function () { - search(query.value, data.items, options); + function initialize() { + if (boot) { + script(window.location.origin + "/js/fuzzysort.js") + .then(function () { + + fetch("/index.json", function (request) { + appendItemsTo({}, JSON.parse(request.responseText)); + search("", data.items, options); + boot = false; }); - query.addEventListener("focusin", function () { - search(query.value, data.items, options); + + ["keyup", "focusin"].forEach(function (event) { + query.addEventListener(event, function () { + if (data.items) search(query.value, data.items, options); + else { boot = true; initialize(); } + }); }); - search(query.value, data.items, options); - }).catch((error) => { - console.log("Error failed to load fuzzy sort: " + error); + }).catch(function (error) { + console.error("ERROR: Failed to load fuzzy search", error); }); } } @@ -204,18 +232,15 @@ if (results.length === 0 && term.length >= 0) { let separator = "—"; if (term.length === 0) separator = ""; - items = ` - <li> - <a href="javascript: void(0)" tabindex="0">${ - escape(term) - } ${separator} No Results Found</a> - </li> - `; + items = '<li><a tabindex="0">'.concat( + escape(term), + " ", + ).concat(separator, " No Results Found</a></li>"); dropdown.removeAttribute("hidden"); container.setAttribute("data-focus", ""); } else { dropdown.removeAttribute("hidden"); - for (const string in results.slice(0, 10)) { + for (var string in results.slice(0, 10)) { const title = results[string].obj.title; let highlight = fuzzysort.highlight( fuzzysort.single(escape(term), escape(title)), @@ -223,20 +248,17 @@ "</span>", ); - if (highlight === null) { - highlight = title; - } + if (highlight === null) highlight = title; items = items + - ` - <li> - <a href="${results[string].obj.url}" tabindex="0">${highlight}</a> - </li> - `; + '\n<li>\n<a href="'.concat( + results[string].obj.url, + '" tabindex="0">', + ).concat(highlight, "</a>\n</li>\n"); } } - dropdown.innerHTML = items; } }); + }); })(); |