(() => { const titles = { "scene-details": "Manage scene details", purpose: "Manage purpose", metrics: "Manage metrics", threads: "Manage threads", dependencies: "Manage dependencies", characters: "Manage characters", attributes: "Manage attributes", suggestions: "Manage suggestions", knowledge: "Manage knowledge", relationships: "Manage relationships", locations: "Manage locations", assets: "Manage assets", custody: "Manage custody", notes: "Manage notes", checklist: "Manage checklist", workflow: "Manage workflow", attachments: "Manage attachments", warnings: "Review warnings" }; const helpKeys = { "scene-details": "sceneInspector.overview", purpose: "sceneInspector.purpose", metrics: "sceneMetrics.overview", threads: "sceneInspector.threads", dependencies: "sceneInspector.dependencies", characters: "sceneInspector.characters", attributes: "sceneInspector.characterAttributes", suggestions: "sceneInspector.suggestions", knowledge: "sceneInspector.knowledge", relationships: "sceneInspector.relationships", locations: "sceneInspector.locations", assets: "sceneInspector.assets", custody: "sceneInspector.custody", notes: "sceneInspector.notes", checklist: "sceneInspector.checklist", workflow: "sceneInspector.writer", attachments: "sceneInspector.attachments", warnings: "sceneInspector.warnings" }; function openOverlay(root, overlay, key) { const title = overlay.querySelector("[data-scene-editor-title]"); if (title) { title.textContent = titles[key] || "Focused editor"; } const helpButton = overlay.querySelector("[data-scene-editor-help]"); if (helpButton) { const helpKey = helpKeys[key] || "sceneInspector.overview"; const helpTitle = titles[key] || "this editor"; helpButton.dataset.helpOpen = helpKey; helpButton.hidden = false; helpButton.title = `Open help for ${helpTitle}`; helpButton.setAttribute("aria-label", `Open help for ${helpTitle}`); } overlay.hidden = false; overlay.setAttribute("aria-hidden", "false"); root.classList.add("editor-overlay-open"); } function closeOverlay(overlay) { const root = overlay?.closest("[data-scene-inspector-v2]"); if (overlay) { overlay.hidden = true; overlay.setAttribute("aria-hidden", "true"); } root?.classList.remove("editor-overlay-open"); } function setEditorBody(overlay, html) { const body = overlay.querySelector("[data-scene-editor-body]"); if (body) { body.innerHTML = html; window.PlotLineHelpIcons?.init(body); } } function setEditorError(form, message) { const error = form.querySelector("[data-scene-editor-error]"); if (!error) { return; } error.textContent = message || "The editor could not be saved."; error.hidden = false; } function replaceSummaryParts(root, html) { if (!html) { return; } Object.entries(html).forEach(([part, markup]) => { if (!markup) { return; } const current = root.querySelector(`[data-scene-summary-part="${part}"]`); if (!current) { return; } const template = document.createElement("template"); template.innerHTML = markup.trim(); const replacement = template.content.firstElementChild; if (replacement) { current.replaceWith(replacement); window.PlotLineHelpIcons?.init(replacement); } }); } function updateTimelineSceneCard(scene) { if (!scene?.sceneID && !scene?.SceneID) { return; } const sceneId = scene.sceneID || scene.SceneID; const card = document.querySelector(`.timeline-scene-card[data-scene-id="${sceneId}"]`); if (!card) { return; } const title = scene.sceneTitle || scene.SceneTitle; const sceneNumber = scene.sceneNumber || scene.SceneNumber; const status = scene.revisionStatusName || scene.RevisionStatusName; const pov = scene.povLabel || scene.PovLabel; const location = scene.primaryLocationName || scene.PrimaryLocationName; if (title) { const titleElement = card.querySelector("strong"); if (titleElement) { titleElement.textContent = title; } } if (sceneNumber) { const numberElement = card.querySelector(".scene-number"); if (numberElement) { numberElement.textContent = `Scene ${sceneNumber}`; } } if (status) { const statusElement = card.querySelector(".status-pill"); if (statusElement) { statusElement.textContent = status; } } if (pov) { const povElement = card.querySelector(".scene-pov-label"); if (povElement) { povElement.textContent = pov; } } const locationElement = card.querySelector(".location-pill"); if (locationElement && location) { locationElement.textContent = location; locationElement.title = location; } } function editorWidthBounds(root) { const rootWidth = root.getBoundingClientRect().width || 960; return { min: Math.min(360, Math.max(280, rootWidth - 420)), max: Math.max(360, rootWidth * 0.5) }; } function setEditEditorWidth(root, width) { const bounds = editorWidthBounds(root); const nextWidth = Math.min(bounds.max, Math.max(bounds.min, width)); root.style.setProperty("--scene-editor-width", `${Math.round(nextWidth)}px`); } document.addEventListener("click", async event => { const openButton = event.target.closest("[data-scene-editor]"); if (openButton) { const root = openButton.closest("[data-scene-inspector-v2]"); const overlay = root?.querySelector("[data-scene-editor-overlay]"); if (!overlay) { return; } const key = openButton.dataset.sceneEditor; const url = openButton.dataset.sceneEditorUrl; openOverlay(root, overlay, key); if (!url) { setEditorBody(overlay, '
This focused editor has not been migrated yet.
'); overlay.querySelector("[data-scene-editor-close]")?.focus(); return; } setEditorBody(overlay, '
Loading editor...
'); try { const response = await fetch(url, { headers: { "X-Requested-With": "XMLHttpRequest" }, credentials: "same-origin" }); if (!response.ok) { throw new Error("Editor load failed"); } setEditorBody(overlay, await response.text()); overlay.querySelector("input, select, textarea, button")?.focus(); } catch { setEditorBody(overlay, '
The editor could not be loaded.
'); } return; } const closeButton = event.target.closest("[data-scene-editor-close]"); if (closeButton) { closeOverlay(closeButton.closest("[data-scene-editor-overlay]")); } }); document.addEventListener("input", event => { const range = event.target.closest("[data-scene-metric-range]"); if (!range) { return; } const output = range.closest(".scene-inspector-editor-metric")?.querySelector("output"); if (output) { output.textContent = range.value; } }); document.addEventListener("submit", async event => { const form = event.target.closest("[data-scene-editor-form]"); if (!form) { return; } event.preventDefault(); const overlay = form.closest("[data-scene-editor-overlay]"); const root = form.closest("[data-scene-inspector-v2]"); const saveButton = form.querySelector("[data-scene-editor-save]"); const originalText = saveButton?.textContent; if (saveButton) { saveButton.disabled = true; saveButton.textContent = "Saving..."; } try { const response = await fetch(form.action, { method: form.method || "POST", body: new FormData(form), headers: { "X-Requested-With": "XMLHttpRequest", "Accept": "application/json" }, credentials: "same-origin" }); const contentType = response.headers.get("content-type") || ""; const payload = contentType.includes("application/json") ? await response.json() : null; if (!response.ok || !payload?.success) { setEditorError(form, payload?.message); return; } replaceSummaryParts(root, payload.html); updateTimelineSceneCard(payload.scene); const timelineHeader = document.querySelector(".scene-inspector-panel .inspector-header h2"); const title = payload.scene?.sceneTitle || payload.scene?.SceneTitle; if (timelineHeader && title) { timelineHeader.textContent = title; } if (payload.editorHtml) { setEditorBody(overlay, payload.editorHtml); overlay.querySelector("input, select, textarea, button")?.focus(); return; } closeOverlay(overlay); } catch { setEditorError(form, "The editor could not be saved."); } finally { if (saveButton) { saveButton.disabled = false; saveButton.textContent = originalText; } } }); document.addEventListener("pointerdown", event => { const resizer = event.target.closest("[data-scene-editor-resizer]"); if (!resizer) { return; } const root = resizer.closest(".scene-inspector-v2-edit"); if (!root) { return; } event.preventDefault(); document.body.classList.add("scene-inspector-editor-resizing"); resizer.setPointerCapture?.(event.pointerId); const onMove = moveEvent => { const rect = root.getBoundingClientRect(); setEditEditorWidth(root, rect.right - moveEvent.clientX); }; const onUp = () => { document.body.classList.remove("scene-inspector-editor-resizing"); document.removeEventListener("pointermove", onMove); document.removeEventListener("pointerup", onUp); }; document.addEventListener("pointermove", onMove); document.addEventListener("pointerup", onUp); }); })();