// Handle search input logic document.body.addEventListener("htmx:configRequest", function (event) { let element = event.detail.elt; if (element.id === "search" && element.value === "") { event.detail.parameters = {}; event.detail.path = window.location.pathname + window.location.search; } }); /** * PersonJumpFilter - Web component for filtering persons list * Works with server-rendered person list and provides client-side filtering */ class PersonJumpFilter extends HTMLElement { constructor() { super(); } connectedCallback() { this.setupEventListeners(); } setupEventListeners() { const searchInput = this.querySelector("#person-search"); const authorsCheckbox = this.querySelector("#authors-only"); const allPersonsList = this.querySelector("#all-persons"); const authorsOnlyList = this.querySelector("#authors-only-list"); if (!searchInput || !authorsCheckbox || !allPersonsList || !authorsOnlyList) { return; } // Search functionality searchInput.addEventListener("input", (e) => { const query = e.target.value.toLowerCase().trim(); this.filterPersons(query); }); // Checkbox functionality authorsCheckbox.addEventListener("change", () => { this.togglePersonsList(); // Clear and re-apply search filter const query = searchInput.value.toLowerCase().trim(); this.filterPersons(query); }); } togglePersonsList() { const authorsCheckbox = this.querySelector("#authors-only"); const allPersonsList = this.querySelector("#all-persons"); const authorsOnlyList = this.querySelector("#authors-only-list"); if (!authorsCheckbox || !allPersonsList || !authorsOnlyList) { return; } if (authorsCheckbox.checked) { allPersonsList.style.display = "none"; authorsOnlyList.style.display = "block"; } else { allPersonsList.style.display = "block"; authorsOnlyList.style.display = "none"; } } filterPersons(query) { // Filter items in the currently visible list const authorsCheckbox = this.querySelector("#authors-only"); const currentList = authorsCheckbox?.checked ? this.querySelector("#authors-only-list") : this.querySelector("#all-persons"); if (!currentList) { return; } const personItems = currentList.querySelectorAll(".person-item"); personItems.forEach((item) => { const name = item.querySelector(".person-name")?.textContent || ""; const life = item.querySelector(".person-life")?.textContent || ""; const matches = !query || name.toLowerCase().includes(query) || life.toLowerCase().includes(query); if (matches) { item.style.display = "block"; } else { item.style.display = "none"; } }); } } // Register the custom element customElements.define("person-jump-filter", PersonJumpFilter); /** * PlaceJumpFilter - Web component for filtering places list */ class PlaceJumpFilter extends HTMLElement { connectedCallback() { const searchInput = this.querySelector("#place-search"); if (searchInput) { searchInput.addEventListener("input", (e) => { const query = e.target.value.toLowerCase().trim(); const placeItems = this.querySelectorAll(".place-item"); placeItems.forEach((item) => { const name = item.querySelector(".place-name")?.textContent || ""; const matches = !query || name.toLowerCase().includes(query); item.style.display = matches ? "block" : "none"; }); }); } } } customElements.define("place-jump-filter", PlaceJumpFilter); /** * CategoryJumpFilter - Web component for filtering categories list */ class CategoryJumpFilter extends HTMLElement { connectedCallback() { const searchInput = this.querySelector("#category-search"); if (searchInput) { searchInput.addEventListener("input", (e) => { const query = e.target.value.toLowerCase().trim(); const categoryItems = this.querySelectorAll(".category-item"); categoryItems.forEach((item) => { const name = item.querySelector(".category-name")?.textContent || ""; const matches = !query || name.toLowerCase().includes(query); item.style.display = matches ? "block" : "none"; }); }); } } } customElements.define("category-jump-filter", CategoryJumpFilter); /** * YearJumpFilter - Unified web component for Jahr-based navigation * Allows jumping by Jahr/Ausgabe or Jahr/Seite */ class YearJumpFilter extends HTMLElement { constructor() { super(); this.issuesByYear = {}; } connectedCallback() { this.parseIssuesData(); this.setupEventListeners(); } parseIssuesData() { // Parse issues data from data attributes const issuesData = this.dataset.issues; if (issuesData) { try { this.issuesByYear = JSON.parse(issuesData); } catch (e) { console.error("Failed to parse issues data:", e); } } } setupEventListeners() { const yearSelect = this.querySelector("#year-select"); const issueNumberSelect = this.querySelector("#issue-number-select"); const issueDateSelect = this.querySelector("#issue-date-select"); const pageInput = this.querySelector("#page-input"); const pageJumpBtn = this.querySelector("#page-jump-btn"); if (!yearSelect) { return; } // Year selection change handler yearSelect.addEventListener("change", () => { this.updateIssueOptions(); this.updatePageInputState(); this.clearPageErrors(); }); // Issue number selection change handler - jump immediately if (issueNumberSelect) { issueNumberSelect.addEventListener("change", () => { const year = yearSelect.value; const issueNum = issueNumberSelect.value; if (year && issueNum) { window.location.href = `/${year}/${issueNum}`; } }); } // Issue date selection change handler - jump immediately if (issueDateSelect) { issueDateSelect.addEventListener("change", () => { const year = yearSelect.value; const issueNum = issueDateSelect.value; // value contains issue number if (year && issueNum) { window.location.href = `/${year}/${issueNum}`; } }); } // Page input handlers if (pageInput) { pageInput.addEventListener("input", () => { this.updatePageJumpButton(); this.clearPageErrors(); }); // Handle Enter key in page input pageInput.addEventListener("keydown", (e) => { if (e.key === "Enter") { e.preventDefault(); this.handlePageJump(); } }); } // Page jump button if (pageJumpBtn) { pageJumpBtn.addEventListener("click", () => { this.handlePageJump(); }); } // Page jump form submission const pageForm = this.querySelector("#page-jump-form"); if (pageForm) { pageForm.addEventListener("submit", (e) => { e.preventDefault(); this.handlePageJump(); }); } // Initialize everything this.updateIssueOptions(); this.updatePageInputState(); this.updatePageJumpButton(); } updateIssueOptions() { const yearSelect = this.querySelector("#year-select"); const issueNumberSelect = this.querySelector("#issue-number-select"); const issueDateSelect = this.querySelector("#issue-date-select"); if (!yearSelect || !issueNumberSelect || !issueDateSelect) { return; } const selectedYear = yearSelect.value; const issues = this.issuesByYear[selectedYear] || []; // Clear existing options issueNumberSelect.innerHTML = ''; issueDateSelect.innerHTML = ''; // Add options for selected year issues.forEach((issue) => { // Issue number select - just the number const numberOption = document.createElement("option"); numberOption.value = issue.number; numberOption.textContent = issue.number; issueNumberSelect.appendChild(numberOption); // Issue date select - date with issue number as value const dateOption = document.createElement("option"); dateOption.value = issue.number; // value is still issue number for navigation dateOption.textContent = `${issue.date} [${issue.number}]`; issueDateSelect.appendChild(dateOption); }); const hasIssues = issues.length > 0 && selectedYear; issueNumberSelect.disabled = !hasIssues; issueDateSelect.disabled = !hasIssues; } async handlePageJump() { const yearSelect = this.querySelector("#year-select"); const pageInput = this.querySelector("#page-input"); const errorContainer = this.querySelector("#jump-errors"); if (!yearSelect || !pageInput) { return; } const year = yearSelect.value; const page = pageInput.value; if (!year || !page) { this.showError("Bitte Jahr und Seite auswählen."); return; } try { const formData = new FormData(); formData.append("year", year); formData.append("page", page); const response = await fetch("/jump", { method: "POST", body: formData, redirect: "manual", }); // Check for HTMX redirect header const hxRedirect = response.headers.get("HX-Redirect"); if (hxRedirect) { window.location.href = hxRedirect; return; } if (response.status === 302 || response.status === 301) { const location = response.headers.get("Location"); if (location) { window.location.href = location; return; } } if (response.ok) { if (errorContainer) { errorContainer.innerHTML = ""; } } else { const errorText = await response.text(); if (errorContainer) { errorContainer.innerHTML = errorText; } } } catch (error) { console.error("Page jump failed:", error); this.showError("Fehler beim Suchen der Seite."); } } showError(message) { const errorContainer = this.querySelector("#jump-errors"); if (errorContainer) { errorContainer.innerHTML = `