diff options
author | Alan Pearce | 2024-05-08 00:15:52 +0200 |
---|---|---|
committer | Alan Pearce | 2024-05-08 00:16:03 +0200 |
commit | 973345ad50f9b237714fcb364cf7f665b3909f9d (patch) | |
tree | 15225430bd5895b5140df0e301b0e6c3fb5758a8 /frontend/static/search.js | |
parent | f459e84ecf7307fe2eeb7fbaa5b0c50613ec04f4 (diff) | |
download | searchix-973345ad50f9b237714fcb364cf7f665b3909f9d.tar.lz searchix-973345ad50f9b237714fcb364cf7f665b3909f9d.tar.zst searchix-973345ad50f9b237714fcb364cf7f665b3909f9d.zip |
feat: paginate search results
Diffstat (limited to 'frontend/static/search.js')
-rw-r--r-- | frontend/static/search.js | 66 |
1 files changed, 49 insertions, 17 deletions
diff --git a/frontend/static/search.js b/frontend/static/search.js index 60fa30d..2282558 100644 --- a/frontend/static/search.js +++ b/frontend/static/search.js @@ -1,12 +1,14 @@ const search = document.getElementById("search"); let results = document.getElementById("results"); +let pagination = document.getElementById("pagination"); const range = new Range(); range.setStartAfter(search); range.setEndAfter(search.parentNode.lastChild); let state = history.state || { - url: new URL(location).toJSON(), + url: new URL(location).toString(), + fragment: range.cloneContents().innerHTML || "", opened: [], }; @@ -35,44 +37,69 @@ function addToggleEventListeners(results) { 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(); + +function paginationLinkClicked(ev) { + const url = new URL(ev.target.href); + getResults(url); + ev.preventDefault(); +} + +function addPaginationEventListeners() { + pagination.addEventListener("click", paginationLinkClicked); +} + +function renderFragmentHTML(html) { + const fragment = range.createContextualFragment( + escapePolicy !== null ? escapePolicy.createHTML(html) : html, + ); + results = fragment.querySelector("#results"); + pagination = fragment.querySelector("#pagination"); + range.deleteContents(); + range.insertNode(fragment); + addToggleEventListeners(results); + addPaginationEventListeners(pagination); +} + +function getResults(url) { fetch(url, { headers: { fetch: "true", }, }) .then(async function (res) { - state.url = url.toJSON(); - state.opened = []; if (res.ok) { - history.pushState(state, null, url); return res.text(); } else { throw new Error(`${res.status} ${res.statusText}: ${await res.text()}`); } }) .then(function (html) { - const fragment = range.createContextualFragment( - escapePolicy !== null ? escapePolicy.createHTML(html) : html, - ); - const results = fragment.firstElementChild; - range.deleteContents(); - range.insertNode(results); - addToggleEventListeners(results); + state.url = url.toJSON(); + state.opened = []; + state.fragment = html; + history.pushState(state, null, url); + return renderFragmentHTML(html); }) .catch(function (error) { range.deleteContents(); range.insertNode(new Text(error.message)); console.error("fetch failed", error); }); +} + +search.addEventListener("submit", function (ev) { + const url = new URL(this.action); + url.search = new URLSearchParams(new FormData(this)).toString(); + getResults(url); ev.preventDefault(); }); if (results !== null) { addToggleEventListeners(results); } +if (pagination !== null) { + addPaginationEventListeners(pagination); +} if (state.opened.length > 0) { state.opened.forEach((id) => @@ -83,8 +110,13 @@ if (state.opened.length > 0) { } addEventListener("popstate", function (ev) { - if (ev.state == null || ev.state.url.pathname.startsWith("/search/")) { - range.deleteContents(); - search.reset(); + if (ev.state != null) { + url = new URL(ev.state.url); + if (!url.pathname.endsWith("/search") && ev.state.fragment !== null) { + renderFragmentHTML(ev.state.fragment); + return; + } } + range.deleteContents(); + search.reset(); }); |