document.addEventListener("DOMContentLoaded", () => {
// The search widget should only be visible if we're in the options page. Else, we
// want it hidden.
if (window.location.pathname.endsWith("options.html")) {
console.log("Running script on options.html");
// Static
const searchBar = document.createElement("div");
searchBar.id = "search-bar";
searchBar.innerHTML = `
`;
document.body.prepend(searchBar);
// Floating
const searchPopup = document.createElement("div");
searchPopup.id = "search-popup";
searchPopup.innerHTML = `
{
event.stopPropagation(); // also cancel clicks to get rid of that annoying cursor flicker
console.log("Search bar clicked!");
// Visibility
if (searchPopup.style.display === "block") {
searchPopup.style.display = "none";
} else {
searchPopup.style.display = "block";
document.getElementById("search-input-popup").focus();
}
});
// Ctrl+K opens the floating search widget
document.addEventListener("keydown", (event) => {
if (event.ctrlKey && event.key === "k") {
event.preventDefault();
console.log("Ctrl+K pressed!");
searchPopup.style.display = "block";
document.getElementById("search-input-popup").focus();
}
});
// Close the popup when clicking outside
document.addEventListener("click", (event) => {
if (
!searchPopup.contains(event.target) &&
event.target !== searchBar
) {
console.log("Click outside, hiding popup");
searchPopup.style.display = "none";
}
});
// Close the popup with Esc key
document.addEventListener("keydown", (event) => {
if (event.key === "Escape") {
console.log("Escape pressed!");
searchPopup.style.display = "none";
}
});
// Handle input
const searchInput = document.getElementById("search-input-popup");
const searchResultsList = document.getElementById(
"search-results-list",
);
const codeElements = document.querySelectorAll("code.option");
searchInput.addEventListener("input", (event) => {
const query = event.target.value.toLowerCase();
searchResultsList.innerHTML = ""; // clear previous
// Find matching
const matchingOptions = [];
codeElements.forEach((code) => {
const optionText = code.textContent;
if (optionText.toLowerCase().includes(query)) {
// Search should be case-insensitive, since chances are
// the user doesn't *actually* know what they're looking for.
const anchorId = code.closest("a").id;
matchingOptions.push({ text: optionText, id: anchorId });
}
});
// Limit the number of visible entries (e.g., show max 10 matches)
const maxVisibleResults = 10;
const resultsToShow = matchingOptions.slice(0, maxVisibleResults);
// Display matching
resultsToShow.forEach(({ text, id }) => {
const li = document.createElement("li");
li.textContent = text;
li.addEventListener("click", () => {
// Update the hash to the option name with a prefix
// e.g., #vim.enableEditorconfig -> #opt-vim.enableEditorconfig
const optionId = `opt-${text}`;
window.location.hash = `#${optionId}`;
searchPopup.style.display = "none";
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({ behavior: "smooth" }); // doesn't really scroll very smoothly
}
});
searchResultsList.appendChild(li);
});
// If there are items > maxVisibleResults, show a "See More" option
if (matchingOptions.length > maxVisibleResults) {
const li = document.createElement("li");
li.textContent = `See more (${matchingOptions.length - maxVisibleResults} more)`;
li.style.fontStyle = "italic";
searchResultsList.appendChild(li);
}
});
}
});