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); } }); } });