search.js (2309 bytes)
1 // Live search for the bookmark pages of sbm Sync: the results change while 2 // you type, and Enter opens the first result, as in the sbm add-on. 3 // Ctrl+Enter opens it in a new tab. The server does the search: this script 4 // gets the page of the search and shows its results. Without this script the 5 // form still works. 6 "use strict"; 7 8 (() => { 9 const form = document.getElementById("search"); 10 const results = document.getElementById("results"); 11 if (!form || !results) return; 12 const box = form.elements.q; 13 const clears = results.dataset.empty === "clear"; // no results for no query 14 let timer = null; // the update that waits for a pause in the typing 15 let running = Promise.resolve(); // the newest update 16 let newest = 0; // the number of the newest update 17 18 // update shows the results that the server gives for the form. 19 async function update() { 20 const n = ++newest; 21 const query = new URLSearchParams(new FormData(form)).toString(); 22 let fresh = null; 23 if (!clears || box.value.trim() !== "") { 24 try { 25 const resp = await fetch("/bookmarks?" + query); 26 if (!resp.ok) return; 27 const page = new DOMParser().parseFromString(await resp.text(), "text/html"); 28 fresh = page.getElementById("results"); 29 } catch { 30 return; 31 } 32 if (fresh === null) return; // not signed in any more 33 } 34 if (n !== newest) return; // a newer update is on its way 35 results.replaceChildren(...(fresh === null ? [] : fresh.childNodes)); 36 if (!clears) history.replaceState(null, "", "?" + query); 37 } 38 39 function later() { 40 clearTimeout(timer); 41 timer = setTimeout(() => { 42 timer = null; 43 running = update(); 44 }, 150); 45 } 46 47 box.addEventListener("input", later); 48 form.addEventListener("change", (e) => { 49 if (e.target !== box) later(); 50 }); 51 box.addEventListener("keydown", async (e) => { 52 if (e.key !== "Enter" || e.isComposing) return; 53 e.preventDefault(); 54 if (timer !== null) { 55 clearTimeout(timer); 56 timer = null; 57 running = update(); 58 } 59 await running; 60 const first = results.querySelector("a.open"); 61 if (first === null) form.submit(); 62 else if (e.ctrlKey || e.metaKey) window.open(first.href, "_blank", "noopener"); 63 else location.assign(first.href); 64 }); 65 })();