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.ts192
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;
}
});
+ });
})();