"use strict"; (() => { const editable = "h1,h2,h3,p,strong,summary,label,button,small,figcaption,svg text"; const protectedAreas = "#run,#matching-query-form input,#encoder-values,#encoder-phrase,#results,#bridge-product,#bridge-adjustment,#bridge-score,#matching-detail,#bridge-calculation,#bridge-prompt,#bridge-region,#sigmoid-chart,#scene-panel .scene-footer,#status,#filename,#runtime,#matching-query-status,.architecture-input,select,option"; let edits = {}, enabled = false, selected = null, selectedKey = null; function keyFor(node) { const parts = []; for (let current = node; current && current !== document.body; current = current.parentElement) { if (current.id) {parts.unshift(`#${CSS.escape(current.id)}`); break;} const siblings = [...current.parentElement.children].filter(sibling => sibling.tagName === current.tagName); parts.unshift(`${current.localName}:nth-of-type(${siblings.indexOf(current) + 1})`); } let context = ""; if (["view-title", "view-copy", "view-reading"].includes(node.id)) context = document.querySelector("[data-view][aria-selected='true']")?.dataset.view || "matching"; if (node.id.startsWith("architecture-description-")) context = document.querySelector("[data-architecture-component].described")?.dataset.componentName || "default"; return `${parts.join(" > ")}||${context}`; } function targets() { return [...document.querySelectorAll(editable)].filter(node => !node.closest("#text-editor") && !node.closest(protectedAreas) && !node.querySelector("input,select,canvas,svg,img") && !node.querySelector(editable)); } function applyEdits() { for (const node of targets()) { const key = keyFor(node); if (Object.hasOwn(edits, key) && node.textContent !== edits[key]) node.textContent = edits[key]; } } // Saved copy also applies when the editing controls are disabled. fetch("/api/text-edits").then(response => { if (!response.ok) throw new Error("Could not load saved text."); return response.json(); }).then(value => {edits = value; applyEdits();}).catch(error => {if (message) message.textContent = error.message;}); const observer = new MutationObserver(applyEdits); observer.observe(document.querySelector("main"), {childList:true, subtree:true, characterData:true}); let message = null; if (document.getElementById("text-editor-script").dataset.enabled !== "true") return; const panel = document.createElement("aside"); panel.id = "text-editor"; panel.innerHTML = '
Text editor (temporary)

'; document.body.append(panel); const toggle = document.getElementById("edit-toggle"), fields = document.getElementById("editor-fields"), input = document.getElementById("edit-value"), save = document.getElementById("edit-save"); message = document.getElementById("edit-message"); function clearSelection() {selected?.classList.remove("text-edit-selected"); selected = null; selectedKey = null; save.disabled = true; input.value = "";} toggle.addEventListener("click", () => { enabled = !enabled; fields.hidden = !enabled; document.body.classList.toggle("editing-copy", enabled); toggle.textContent = enabled ? "Done editing" : "Edit text"; if (!enabled) clearSelection(); }); document.addEventListener("click", event => { if (!enabled || event.target.closest("#text-editor")) return; const node = event.target.closest(editable); if (!node || !targets().includes(node)) return; event.preventDefault(); event.stopImmediatePropagation(); clearSelection(); selected = node; selectedKey = keyFor(node); node.classList.add("text-edit-selected"); input.value = node.textContent; save.disabled = false; input.focus(); message.textContent = ""; }, true); document.getElementById("edit-cancel").addEventListener("click", clearSelection); save.addEventListener("click", async () => { if (!selectedKey) return; const key = selectedKey, text = input.value; save.disabled = true; try { const response = await fetch("/api/text-edits", {method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({key, text})}); const data = await response.json(); if (!response.ok) throw new Error(data.error || "Text could not be saved."); edits[key] = text; applyEdits(); message.textContent = "Saved to text_edits.json. Your text will stay after refresh."; } catch (error) {message.textContent = error.message;} finally {save.disabled = !selected;} }); })();