72 lines
2.4 KiB
JavaScript
72 lines
2.4 KiB
JavaScript
// CCN — shared script. Every screen works without it; it only removes a click here and there.
|
|
|
|
document.documentElement.classList.add("js");
|
|
|
|
// Selects marked `data-autosubmit` submit their form on change.
|
|
for (const select of document.querySelectorAll("select[data-autosubmit]")) {
|
|
select.addEventListener("change", () => select.form?.requestSubmit());
|
|
}
|
|
|
|
// The filter rail is a disclosure, open on desktop. Browsers without `::details-content` need it opened here.
|
|
const filters = document.querySelector("details.filters");
|
|
const desktop = window.matchMedia("(min-width: 1024px)");
|
|
|
|
if (filters) {
|
|
const sync = () => {
|
|
if (desktop.matches) {
|
|
filters.open = true;
|
|
}
|
|
};
|
|
|
|
sync();
|
|
desktop.addEventListener("change", sync);
|
|
}
|
|
|
|
// The new-listing form shows every field without scripts; here, only those that apply to the format and grading picked.
|
|
const listingForm = document.querySelector(".listing-form__form");
|
|
|
|
if (listingForm) {
|
|
const apply = () => {
|
|
const format = listingForm.querySelector("input[name=format]:checked")?.value;
|
|
const grading = listingForm.querySelector("input[name=grading]:checked")?.value;
|
|
const single = format === "single-issues";
|
|
const scopes = { "single-issues": single, collected: !single, slabbed: single && grading === "slabbed" };
|
|
|
|
for (const element of listingForm.querySelectorAll("[data-scope]")) {
|
|
element.hidden = !scopes[element.dataset.scope];
|
|
}
|
|
};
|
|
|
|
listingForm.addEventListener("change", apply);
|
|
apply();
|
|
}
|
|
|
|
// Reports each `data-view-event` element the first time it is fully on screen.
|
|
(() => {
|
|
const elements = document.querySelectorAll("[data-view-event]");
|
|
|
|
if (!window.umami || elements.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const prefix = "data-view-event-";
|
|
|
|
// Each `data-view-event-<name>` attribute is a property, as `data-umami-event-<name>` is for a click.
|
|
const properties = (element) => Object.fromEntries(
|
|
[...element.attributes]
|
|
.filter((attribute) => attribute.name.startsWith(prefix))
|
|
.map((attribute) => [attribute.name.slice(prefix.length), attribute.value])
|
|
);
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
for (const entry of entries) {
|
|
if (entry.isIntersecting) {
|
|
observer.unobserve(entry.target);
|
|
window.umami.track(entry.target.getAttribute("data-view-event"), properties(entry.target));
|
|
}
|
|
}
|
|
}, { threshold: 1 });
|
|
|
|
elements.forEach((element) => observer.observe(element));
|
|
})();
|