1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
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) => 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();
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) {
results.innerHTML =
escapePolicy !== null ? escapePolicy.createHTML(html) : html;
addToggleEventListeners();
})
.catch(function (error) {
results.innerText = error.message;
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();
}
});
|