diff options
author | Alan Pearce | 2024-05-04 19:50:26 +0200 |
---|---|---|
committer | Alan Pearce | 2024-05-04 19:50:26 +0200 |
commit | 87ec9ecf21781c5289257750fd41c6b9991f1f6e (patch) | |
tree | e8c80247f2db58a52553b404c0e9606b8879a0f5 /frontend/static | |
parent | e96fa5ff6835a3bb8b28f14ff0e0771d80631d2c (diff) | |
download | searchix-87ec9ecf21781c5289257750fd41c6b9991f1f6e.tar.lz searchix-87ec9ecf21781c5289257750fd41c6b9991f1f6e.tar.zst searchix-87ec9ecf21781c5289257750fd41c6b9991f1f6e.zip |
feat: browser history management
Diffstat (limited to 'frontend/static')
-rw-r--r-- | frontend/static/search.js | 56 |
1 files changed, 53 insertions, 3 deletions
diff --git a/frontend/static/search.js b/frontend/static/search.js index 20f1a7d..5bbc374 100644 --- a/frontend/static/search.js +++ b/frontend/static/search.js @@ -1,15 +1,47 @@ const search = document.getElementById("search"); const results = document.getElementById("results"); +let state = history.state || { + url: new URL(location).toJSON(), + opened: [], +}; + +let escapePolicy = null; +if (window.trustedTypes && trustedTypes.createPolicy) { + escapePolicy = trustedTypes.createPolicy("fetch", { + createHTML: (string, sink) => string, + }); +} + +function detailsToggled(ev) { + const nextURL = new URL(location); + if (ev.newState == "open" || ev.target.open === true) { + state.opened.push(this.id); + nextURL.hash = this.id; + } else { + state.opened = state.opened.filter((x) => x != this.id); + nextURL.hash = ""; + } + state.url = nextURL.toJSON(); + history.replaceState(state, "", nextURL); +} +function addToggleEventListeners() { + results.querySelectorAll("details").forEach((details) => + // toggle event doesn't bubble :( + details.addEventListener("toggle", detailsToggled, { passive: true }), + ); +} search.addEventListener("submit", function (ev) { const url = new URL(this.action); url.search = new URLSearchParams(new FormData(this)).toString(); - const res = fetch(url, { + fetch(url, { headers: { fetch: "true", }, }) .then(function (res) { - window.history.pushState(null, null, url); + state.url = url.toJSON(); + state.opened = []; + history.pushState(state, null, url); if (res.ok) { return res.text(); } else { @@ -17,10 +49,28 @@ search.addEventListener("submit", function (ev) { } }) .then(function (html) { - results.innerHTML = html; + results.innerHTML = + escapePolicy !== null ? escapePolicy.createHTML(html) : html; + addToggleEventListeners(); }) .catch(function (error) { console.error("fetch failed", error); }); ev.preventDefault(); }); + +addToggleEventListeners(); + +if (state.opened.length > 0) { + state.opened.forEach((id) => + document.getElementById(id).setAttribute("open", "open"), + ); +} else if (location.hash) { + document.getElementById(location.hash.slice(1)).setAttribute("open", "open"); +} + +addEventListener("popstate", function (ev) { + if (ev.state == null || ev.state.url.pathname == "/") { + results.replaceChildren(); + } +}); |