(function () { const input = document.getElementById("knowledge-search"); const count = document.getElementById("knowledge-count"); const entries = Array.from(document.querySelectorAll("[data-knowledge-entry]")); if (input instanceof HTMLInputElement && count) { function update() { const query = input.value.trim().toLowerCase(); let visible = 0; for (const entry of entries) { const matches = !query || (entry.getAttribute("data-search") || "").includes(query); entry.hidden = !matches; if (matches) visible += 1; } const noResults = document.getElementById("knowledge-no-results"); if (noResults) noResults.hidden = visible > 0; count.textContent = query ? `${visible} of ${entries.length} pages` : `${entries.length} pages`; } input.addEventListener("input", update); } const preview = document.getElementById("knowledge-preview"); const previewTitle = document.getElementById("knowledge-preview-title"); const previewMeta = document.getElementById("knowledge-preview-meta"); const previewSummary = document.getElementById("knowledge-preview-summary"); const previewExcerpt = document.getElementById("knowledge-preview-excerpt"); const previewSources = Array.from(document.querySelectorAll("[data-knowledge-preview-source]")); if ( preview && previewTitle && previewMeta && previewSummary && previewExcerpt && previewSources.length > 0 ) { const normalizePath = (path) => path.length > 1 ? path.replace(/\/$/, "") : path; const sourceByPath = new Map(previewSources.map((source) => [ normalizePath(source.getAttribute("data-preview-href") || ""), source, ])); let activeLink; function sourceForTarget(target) { if (!(target instanceof Element)) return; const link = target.closest("a[href]"); if (!(link instanceof HTMLAnchorElement)) return; const url = new URL(link.href, window.location.href); if (url.origin !== window.location.origin) return; const source = sourceByPath.get(normalizePath(url.pathname)); return source ? { link, source } : undefined; } function showPreview(link, source) { if (activeLink === link) return; activeLink = link; previewTitle.textContent = source.getAttribute("data-preview-title") || ""; previewMeta.textContent = source.getAttribute("data-preview-meta") || ""; previewSummary.textContent = source.getAttribute("data-preview-summary") || ""; previewExcerpt.textContent = source.getAttribute("data-preview-excerpt") || ""; preview.setAttribute("data-active", ""); preview.setAttribute("aria-hidden", "false"); } function hidePreview(link) { if (link && activeLink !== link) return; activeLink = undefined; preview.removeAttribute("data-active"); preview.setAttribute("aria-hidden", "true"); } document.addEventListener("pointerover", (event) => { const target = sourceForTarget(event.target); if (target) showPreview(target.link, target.source); }); document.addEventListener("pointerout", (event) => { const target = sourceForTarget(event.target); if (!target) return; if (event.relatedTarget instanceof Node && target.link.contains(event.relatedTarget)) return; hidePreview(target.link); }); document.addEventListener("focusin", (event) => { const target = sourceForTarget(event.target); if (target) showPreview(target.link, target.source); }); document.addEventListener("focusout", (event) => { const target = sourceForTarget(event.target); if (target) hidePreview(target.link); }); } const contents = document.getElementById("knowledge-contents"); const contentsList = document.getElementById("knowledge-contents-list"); const knowledgeMain = document.querySelector(".knowledge-overview, .knowledge-entry"); if (contents && contentsList && knowledgeMain) { const headings = Array.from(knowledgeMain.querySelectorAll("h1, h2, h3")) .filter((heading) => heading.textContent && !heading.closest(".knowledge-chart")); const usedIds = new Set(Array.from(document.querySelectorAll("[id]")) .map((element) => element.id) .filter(Boolean)); function headingId(heading, index) { if (heading.id) return heading.id; const base = (heading.textContent || "section") .toLowerCase() .normalize("NFKD") .replace(/[\u0300-\u036f]/g, "") .replace(/[^a-z0-9]+/g, "-") .replace(/^-|-$/g, "") || `section-${index + 1}`; let id = base; let suffix = 2; while (usedIds.has(id)) id = `${base}-${suffix++}`; heading.id = id; usedIds.add(id); return id; } const links = headings.map((heading, index) => { const item = document.createElement("li"); const link = document.createElement("a"); const id = headingId(heading, index); item.dataset.level = heading.tagName.slice(1); link.href = `#${id}`; link.textContent = heading.textContent.trim(); item.append(link); contentsList.append(item); return { heading, link }; }); for (const link of document.querySelectorAll("[data-knowledge-heading-link]")) { const id = (link.getAttribute("href") || "").slice(1); if (document.getElementById(id)) link.hidden = false; } if (links.length > 1) { contents.setAttribute("data-active", ""); contents.setAttribute("aria-hidden", "false"); if (window.location.hash.length > 1) { const initialTarget = document.getElementById(decodeURIComponent(window.location.hash.slice(1))); if (initialTarget) window.requestAnimationFrame(() => initialTarget.scrollIntoView()); } let frame; const updateCurrent = () => { frame = undefined; const threshold = window.innerHeight * 0.24; let current = links[0]; for (const candidate of links) { if (candidate.heading.getBoundingClientRect().top <= threshold) current = candidate; else break; } for (const candidate of links) { const active = candidate === current; candidate.link.toggleAttribute("data-current", active); if (active) candidate.link.setAttribute("aria-current", "location"); else candidate.link.removeAttribute("aria-current"); } }; const requestUpdate = () => { if (frame) return; frame = window.requestAnimationFrame(updateCurrent); }; window.addEventListener("scroll", requestUpdate, { passive: true }); window.addEventListener("resize", requestUpdate); updateCurrent(); } } })();