2022-02-22 04:40:14 +00:00
|
|
|
/**
|
|
|
|
* This module is used to handle user's interaction with the search form.
|
|
|
|
*/
|
2022-02-20 17:12:49 +00:00
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
import { DeclarationDataCenter } from "./declaration-data.js";
|
2022-02-13 13:25:37 +00:00
|
|
|
|
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
const SEARCH_FORM = document.querySelector("#search_form");
|
|
|
|
const SEARCH_INPUT = SEARCH_FORM.querySelector("input[name=q]");
|
|
|
|
|
|
|
|
// Create an `div#search_results` to hold all search results.
|
|
|
|
let sr = document.createElement("div");
|
|
|
|
sr.id = "search_results";
|
|
|
|
SEARCH_FORM.appendChild(sr);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attach `selected` class to the the selected search result.
|
|
|
|
*/
|
|
|
|
function handleSearchCursorUpDown(down) {
|
|
|
|
const sel = sr.querySelector(`.selected`);
|
|
|
|
if (sel) {
|
|
|
|
sel.classList.remove("selected");
|
|
|
|
const toSelect = down
|
|
|
|
? sel.nextSibling || sr.firstChild
|
|
|
|
: sel.previousSibling || sr.lastChild;
|
|
|
|
toSelect && toSelect.classList.add("selected");
|
|
|
|
} else {
|
|
|
|
const toSelect = down ? sr.firstChild : sr.lastChild;
|
|
|
|
toSelect && toSelect.classList.add("selected");
|
|
|
|
}
|
2022-02-13 13:25:37 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
/**
|
|
|
|
* Perform search (when enter is pressed).
|
|
|
|
*/
|
|
|
|
function handleSearchEnter() {
|
|
|
|
const sel =
|
|
|
|
sr.querySelector(`.selected`) ||
|
|
|
|
sr.firstChild;
|
|
|
|
sel.click();
|
|
|
|
}
|
2022-02-13 13:25:37 +00:00
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
/**
|
|
|
|
* Allow user to navigate search results with up/down arrow keys, and choose with enter.
|
|
|
|
*/
|
|
|
|
SEARCH_INPUT.addEventListener("keydown", (ev) => {
|
|
|
|
switch (ev.key) {
|
|
|
|
case "Down":
|
|
|
|
case "ArrowDown":
|
|
|
|
ev.preventDefault();
|
|
|
|
handleSearchCursorUpDown(true);
|
|
|
|
break;
|
|
|
|
case "Up":
|
|
|
|
case "ArrowUp":
|
|
|
|
ev.preventDefault();
|
|
|
|
handleSearchCursorUpDown(false);
|
|
|
|
break;
|
|
|
|
case "Enter":
|
|
|
|
ev.preventDefault();
|
|
|
|
handleSearchEnter();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2022-02-13 13:25:37 +00:00
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
/**
|
|
|
|
* Remove all children of a DOM node.
|
|
|
|
*/
|
|
|
|
function removeAllChildren(node) {
|
|
|
|
while (node.firstChild) {
|
|
|
|
node.removeChild(node.lastChild);
|
|
|
|
}
|
2022-02-20 17:12:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
/**
|
|
|
|
* Search autocompletion.
|
|
|
|
*/
|
|
|
|
SEARCH_INPUT.addEventListener("input", async (ev) => {
|
|
|
|
const text = ev.target.value;
|
2022-02-20 17:12:49 +00:00
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
// If no input clear all.
|
|
|
|
if (!text) {
|
|
|
|
sr.removeAttribute("state");
|
|
|
|
removeAllChildren(sr);
|
|
|
|
return;
|
2022-02-20 17:12:49 +00:00
|
|
|
}
|
|
|
|
|
2022-02-22 04:40:14 +00:00
|
|
|
// searching
|
|
|
|
sr.setAttribute("state", "loading");
|
|
|
|
const dataCenter = await DeclarationDataCenter.init();
|
2022-02-22 20:26:20 +00:00
|
|
|
const result = dataCenter.search(text, false);
|
2022-02-22 04:40:14 +00:00
|
|
|
|
|
|
|
// in case user has updated the input.
|
|
|
|
if (ev.target.value != text) return;
|
|
|
|
|
|
|
|
// update search results
|
|
|
|
removeAllChildren(sr);
|
2022-02-22 20:26:20 +00:00
|
|
|
for (const { name, docLink } of result) {
|
2022-02-22 04:40:14 +00:00
|
|
|
const d = sr.appendChild(document.createElement("a"));
|
2022-02-22 15:20:20 +00:00
|
|
|
d.innerText = name;
|
|
|
|
d.title = name;
|
2022-02-22 20:26:20 +00:00
|
|
|
d.href = docLink;
|
2022-02-22 04:40:14 +00:00
|
|
|
}
|
|
|
|
sr.setAttribute("state", "done");
|
|
|
|
});
|