1 line
39 KiB
JavaScript
1 line
39 KiB
JavaScript
(()=>{const n="plotline.theme",t=document.querySelectorAll("[data-theme-choice]"),r=()=>{try{return localStorage.getItem(n)}catch{return null}},u=t=>{try{localStorage.setItem(n,t)}catch{}},i=n=>{const i=n==="dark"?"dark":"light";document.documentElement.dataset.theme=i;document.documentElement.dataset.bsTheme=i;u(i);t.forEach(n=>{const t=n.dataset.themeChoice===i;n.classList.toggle("active",t);n.setAttribute("aria-pressed",String(t))})};t.forEach(n=>{n.addEventListener("click",()=>i(n.dataset.themeChoice))});i(r()||"light")})();(()=>{const t=document.getElementById("plotlineConfirmModal"),f=t&&window.bootstrap?new bootstrap.Modal(t):null,e=t?.querySelector("#plotlineConfirmModalTitle"),o=t?.querySelector("#plotlineConfirmModalMessage"),i=t?.querySelector("[data-confirm-submit]"),s=t?.querySelector("[data-delete-confirm-field]"),r=t?.querySelector("[data-delete-confirm-input]");let n=null,u=null;const h=n=>{const t=n.split(/\n\s*\n/);return{title:t.shift()?.trim()||"Confirm action",body:t.join("\n\n").trim()}},c=()=>{n=null,u=null,r&&(r.value=""),s?.classList.add("d-none"),i?.removeAttribute("disabled")};t?.addEventListener("hidden.bs.modal",c);r?.addEventListener("input",()=>{n?.dataset.requireDeleteText==="true"&&i&&(i.disabled=r.value.trim()!=="DELETE")});i?.addEventListener("click",()=>{if(n){if(n.dataset.requireDeleteText==="true"){const t=n.querySelector("[data-delete-confirm-target], [name='confirmationText']");t&&(t.value=r?.value.trim()||"")}n.dataset.confirmed="true";f?.hide();n.requestSubmit&&u?n.requestSubmit(u):n.requestSubmit?n.requestSubmit():n.submit()}});document.addEventListener("submit",c=>{const l=c.target;if(l instanceof HTMLFormElement&&l.dataset.confirmed!=="true"&&l.dataset.confirmSkip!=="true"){const b=l.dataset.confirmMessage,k=c.submitter instanceof HTMLElement?c.submitter:l.querySelector("button[type='submit']"),a=k?.textContent||"",p=l.getAttribute("action")||"",y=/restore/i.test(a)||/\/restore\b/i.test(p),v=/delete forever/i.test(a)||/\/deleteforever\b/i.test(p),d=!y&&!v&&(/archive/i.test(a)||/\/archive\b/i.test(p)),nt=!v&&/(delete|remove)/i.test(a);if(b||d||y||nt||v){const tt=b||(d?"Archive this item?\n\nThis will hide it from active lists and timelines, but the data will be kept and can be restored later.":y?"Restore this item?\n\nThis will return it to active lists and timelines where applicable.":v?"Permanently delete this item?\n\nThis cannot be undone. Any linked planning data may also be removed or become unavailable. Only continue if you are certain.":"Remove this item?\n\nThis removes the link or supporting record. Major story items are archived instead of permanently deleted.");if(f&&t&&e&&o&&i){c.preventDefault();const g=h(tt);n=l;u=k;e.textContent=l.dataset.confirmTitle||g.title;o.textContent=l.dataset.confirmBody||g.body;i.textContent=l.dataset.confirmButtonText||a.trim()||"Confirm";i.className=`btn ${l.dataset.confirmButtonClass||(y?"btn-primary":"btn-danger")}`;const w=l.dataset.requireDeleteText==="true"||v;s?.classList.toggle("d-none",!w);w&&i&&(i.disabled=!0,r?.focus());f.show();w&&window.setTimeout(()=>r?.focus(),200)}}}})})();(()=>{const r=document.querySelectorAll("[data-help-icon]");if(r.length&&window.bootstrap){const u=new Map;let n=null;const f=n=>n.querySelector("[data-help-tooltip]")||n,i=n=>bootstrap.Tooltip.getInstance(f(n))?.hide(),t=(t=null)=>{n&&n!==t&&bootstrap.Popover.getInstance(n)?.hide()},e=()=>r.forEach(n=>i(n));r.forEach(r=>{const o=f(r),s=o.dataset.helpMicro||"Help article not found.",h=r.dataset.helpTitle||"Help unavailable",c=r.dataset.helpSummary||"Help content has not yet been written for this feature.";bootstrap.Tooltip.getOrCreateInstance(o,{title:s,trigger:"hover focus",placement:"top",container:"body"});const l=bootstrap.Popover.getOrCreateInstance(r,{title:h,trigger:"click",placement:"auto",container:"body",html:!0,customClass:"plotline-help-popover",content(){const u=document.createElement("div"),i=document.createElement("p");i.className="mb-2";i.textContent=c;const n=document.createElement("a");return n.href="#",n.textContent="More...",n.className="plotline-help-more",n.addEventListener("click",n=>{n.preventDefault(),t(),e(),r.dispatchEvent(new CustomEvent("plotline:help-more",{bubbles:!0,detail:{key:r.dataset.helpKey||""}}))}),u.append(i,n),u}});u.set(r,l);r.addEventListener("click",n=>{window.PlotLineHelpDrawer?.isActive?.()&&(n.preventDefault(),n.stopPropagation(),t(),i(r),window.PlotLineHelpPopovers?.hideAll(),window.PlotLineHelpDrawer.open(r.dataset.helpKey||""))});r.addEventListener("show.bs.popover",n=>{if(window.PlotLineHelpDrawer?.isActive?.()){n.preventDefault();return}t(r);i(r)});r.addEventListener("shown.bs.popover",()=>{n=r,i(r)});r.addEventListener("hidden.bs.popover",()=>{n===r&&(n=null)})});document.addEventListener("click",i=>{const r=i.target instanceof Element?i.target:null;if(r&&n&&!r.closest("[data-help-icon]")){const u=document.querySelector(`#${n.getAttribute("aria-describedby")}`);u?.contains(r)||t()}});document.addEventListener("keydown",n=>{n.key==="Escape"&&t()});window.PlotLineHelpPopovers={hideAll(){u.forEach(n=>n.hide());e();n=null}}}})();(()=>{const n=document.querySelector("[data-help-layout]"),p=document.querySelector("[data-help-drawer]"),i=document.querySelector("[data-help-content]"),l=document.querySelector("[data-help-splitter]"),w=document.querySelector("[data-help-close]"),h=document.querySelector("[data-help-collapse]"),a=document.querySelector("[data-help-expand]"),u=document.querySelector("[data-help-pin]"),f=document.querySelector("[data-help-drawer-heading]");if(n&&p&&i){const t={width:"plotline.helpDrawer.width",pinned:"plotline.helpDrawer.pinned",key:"plotline.helpDrawer.key",collapsed:"plotline.helpDrawer.collapsed"},b=(n,t,i)=>Math.min(i,Math.max(t,n)),e=n=>{try{return localStorage.getItem(n)==="true"}catch{return!1}},o=(n,t)=>{try{localStorage.setItem(n,t)}catch{}},v=i=>{const r=`${b(Number.parseFloat(i)||25,20,50)}%`;n.style.setProperty("--help-drawer-width",r);o(t.width,r)},c=n=>{o(t.pinned,String(n)),u?.setAttribute("aria-pressed",String(n)),u&&(u.textContent=n?"Unpin":"Pin")},r=i=>{n.classList.toggle("help-collapsed",i),o(t.collapsed,String(i)),h&&(h.textContent=i?"Expand":"Collapse")},s=async(u,e={})=>{const s=u||"";n.classList.add("help-open");e.keepCollapsed||r(!1);o(t.key,s);f&&(f.textContent=s||"Help");i.innerHTML='<p class="muted">Loading help...<\/p>';try{const n=await fetch(`/HelpDrawer/Article?key=${encodeURIComponent(s)}`,{headers:{"X-Requested-With":"XMLHttpRequest"}});i.innerHTML=n.ok?await n.text():'<p class="muted">Help for this feature has not yet been written.<\/p>';const t=i.querySelector(".help-drawer-article h2")?.textContent?.trim();f&&t&&(f.textContent=t)}catch{i.innerHTML='<p class="muted">Help for this feature has not yet been written.<\/p>'}},k=()=>{n.classList.remove("help-open","help-collapsed"),c(!1)};window.PlotLineHelpDrawer={isActive(){return n.classList.contains("help-open")},open(n){return s(n)}};v(localStorage.getItem(t.width)||"25%");c(e(t.pinned));r(e(t.collapsed));document.addEventListener("plotline:help-more",n=>{const t=n.detail?.key||n.target?.dataset?.helpKey||"";window.PlotLineHelpPopovers?.hideAll();s(t)});document.addEventListener("click",n=>{const t=n.target instanceof Element?n.target.closest("[data-help-open]"):null;t&&(n.preventDefault(),window.PlotLineHelpPopovers?.hideAll(),s(t.dataset.helpOpen||""))});w?.addEventListener("click",k);h?.addEventListener("click",()=>r(!n.classList.contains("help-collapsed")));a?.addEventListener("click",()=>r(!1));a?.addEventListener("keydown",n=>{(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),r(!1))});u?.addEventListener("click",()=>c(!e(t.pinned)));l?.addEventListener("pointerdown",t=>{if(n.classList.contains("help-open")&&!n.classList.contains("help-collapsed")){t.preventDefault();document.body.classList.add("help-resizing");l.setPointerCapture?.(t.pointerId);const i=t=>{const i=n.getBoundingClientRect(),r=(i.right-t.clientX)/i.width*100;v(r)},r=()=>{document.body.classList.remove("help-resizing"),document.removeEventListener("pointermove",i),document.removeEventListener("pointerup",r)};document.addEventListener("pointermove",i);document.addEventListener("pointerup",r)}});const y=(()=>{try{return localStorage.getItem(t.key)||""}catch{return""}})();e(t.pinned)&&y&&s(y,{keepCollapsed:!0})}})();(()=>{const n=document.querySelectorAll(".scene-inspector-root");if(n.length){const t=n=>n.toLowerCase().replace(/&/g,"and").replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"");n.forEach(n=>{const o=n.dataset.sceneId||n.querySelector(".scene-inspector-form [name='SceneID']")?.value||"new",f=`plotline.inspector.${o}.`,s=new Set(["overview","timing","characters"]),u=[...n.querySelectorAll(".inspector-section")],r=n.querySelector(".scene-inspector-form"),i=n.querySelector("[data-scene-time-editor]");if(r&&i&&i.dataset.enhanced!=="true"){i.dataset.enhanced="true";const n=r.querySelector("[name='TimeModeID']"),e=i.dataset.exactDatetimeModeId||"",o=i.dataset.exactDateModeId||"",s=[...i.querySelectorAll("[data-time-part-field]")],h={StartDateTime:i.querySelector("[data-date-part-for='StartDateTime']"),EndDateTime:i.querySelector("[data-date-part-for='EndDateTime']")},c={StartDateTime:i.querySelector("[data-time-part-for='StartDateTime']"),EndDateTime:i.querySelector("[data-time-part-for='EndDateTime']")},l={StartDateTime:r.querySelector("input[type='hidden'][name='StartDateTime']"),EndDateTime:r.querySelector("input[type='hidden'][name='EndDateTime']")},t=()=>n?.value===e,a=()=>n?.value===o,u=()=>{const n=t();s.forEach(t=>{t.hidden=!n,t.classList.toggle("d-none",!n)})},f=n=>{const i=l[n],r=h[n]?.value||"",f=c[n]?.value||"";if(i){if(!r){i.value="";return}if(t()){i.value=`${r}T${f||"00:00"}`;return}if(a()){i.value=r;return}const u=i.value.match(/^\\d{4}-\\d{2}-\\d{2}T(\\d{2}:\\d{2})/)?.[1];i.value=u?`${r}T${u}`:r}},v=()=>{f("StartDateTime"),f("EndDateTime")};n?.addEventListener("change",u);r.addEventListener("submit",v);u()}u.forEach(n=>{if(n.dataset.enhanced!=="true"){const l=n.querySelector("h3, h2"),u=n.dataset.sectionTitle||l?.textContent?.trim()||"Overview",a=t(u),o=n.dataset.sectionId||`inspector-${a}`,e=o.replace(/^inspector-/,"");n.id=o;n.dataset.searchText=`${u} ${n.textContent}`.toLowerCase();n.dataset.enhanced="true";const r=document.createElement("div");for(r.className="inspector-accordion-body";n.firstChild;)r.appendChild(n.firstChild);const i=document.createElement("button");i.type="button";i.className="inspector-accordion-toggle";i.setAttribute("aria-expanded","false");n.append(i,r);const v=r.querySelectorAll(".asset-event-item, .thread-event-item, .warning-mini-card, .dependency-card, .metric-slider").length;i.innerHTML=`<span>${u}</span><span class="accordion-count">${v||""}</span>`;const h=localStorage.getItem(`${f}${e}`),c=h===null?s.has(e):h==="open";n.classList.toggle("is-open",c);i.setAttribute("aria-expanded",String(c));i.addEventListener("click",()=>{const t=!n.classList.contains("is-open");n.classList.toggle("is-open",t);i.setAttribute("aria-expanded",String(t));localStorage.setItem(`${f}${e}`,t?"open":"closed")})}});n.querySelectorAll(".inspector-nav-links a").forEach(t=>{t.addEventListener("click",i=>{const r=n.querySelector(t.getAttribute("href"));r&&(i.preventDefault(),r.classList.add("is-open"),r.querySelector(".inspector-accordion-toggle")?.setAttribute("aria-expanded","true"),r.scrollIntoView({behavior:"smooth",block:"start"}))})});const e=n.querySelector("[data-inspector-search]");if(e?.addEventListener("input",()=>{const n=e.value.trim().toLowerCase();u.forEach(t=>{const i=!n||t.dataset.searchText.includes(n);t.classList.toggle("is-filtered-out",!i);i&&n&&(t.classList.add("is-open"),t.querySelector(".inspector-accordion-toggle")?.setAttribute("aria-expanded","true"))})}),"IntersectionObserver"in window){const t=[...n.querySelectorAll(".inspector-nav-links a")],i=new IntersectionObserver(n=>{n.forEach(n=>{n.isIntersecting&&t.forEach(t=>{t.classList.toggle("active",t.getAttribute("href")===`#${n.target.id}`)})})},{root:n.closest(".scene-inspector-panel")||null,rootMargin:"-10% 0px -70% 0px"});u.forEach(n=>i.observe(n))}})}})();(()=>{const n=document.querySelectorAll("[data-metric-shape-chart]");if(n.length){const t=["#2f6f63","#b35f3b","#6750a4","#c58b2b","#7d3f52","#33759b","#9c4d8f","#a33d3d","#6f8f3d","#d08a2f","#444b57"],u=new Set(["Overall Intensity","Tension","Emotional Weight","Action"]),i=[],r=()=>{window.requestAnimationFrame(()=>{i.forEach(n=>n.resize())})};window.PlotLineMetricCharts={resizeAll:r};window.addEventListener("plotline:timeline-layout-changed",r);const f={id:"plotlineChapterGuides",afterDraw(n){const u=n.config.options.plugins.plotlineScenes||[],{ctx:t,chartArea:r,scales:f}=n;if(u.length&&f.x){t.save();t.strokeStyle="rgba(47, 111, 99, 0.16)";t.fillStyle="rgba(82, 75, 65, 0.58)";t.lineWidth=1;t.font="700 10px system-ui, -apple-system, Segoe UI, sans-serif";const e=[];u.forEach((n,t)=>{t&&n.chapterLabel===u[t-1].chapterLabel||e.push({scene:n,index:t})});const i=e.filter(n=>!n.scene.isPlaceholder),o=i.length>40?5:i.length>24?4:i.length>14?2:1;i.forEach((n,u)=>{const{scene:s,index:c}=n,e=f.x.getPixelForValue(c+.5);t.beginPath();t.moveTo(e,r.top);t.lineTo(e,r.bottom);t.stroke();const h=Number.parseInt(String(s.chapterLabel).replace(/[^0-9]/g,""),10),l=u===0||u===i.length-1||o===1||Number.isFinite(h)&&h%o==0;l&&t.fillText(s.chapterLabel,Math.min(e+4,r.right-70),r.bottom+22)});t.restore()}}};window.Chart&&Chart.register(f);n.forEach(n=>{const p=n.querySelector("script[type='application/json']"),o=n.querySelector("canvas"),w=n.querySelector("[data-metric-toggles]"),b=n.querySelector("[data-chart-fallback]"),k=n.querySelector("[data-timeline-metric-edit-toolbar]"),c=n.querySelector("[data-edit-metric-status]"),v=n.hasAttribute("data-timeline-metric-editor")&&k&&c;if(p&&o){let f;try{f=JSON.parse(p.textContent||"{}")}catch{b?.classList.remove("d-none");return}if(!window.Chart||!f.scenes?.length||!f.metrics?.length){b?.classList.remove("d-none");return}const tt=new Set(f.defaultMetrics?.length?f.defaultMetrics:u),s=f.scenes.length,it=s>80?10:s>40?5:s>24?4:s>14?2:1,l=f.metrics.map((n,i)=>{const u=new Map(n.points.map(n=>[n.sceneId,n.value])),r=t[i%t.length];return{label:n.metricName,metricTypeId:n.metricTypeId,minValue:Number.isFinite(n.minValue)?n.minValue:1,maxValue:Number.isFinite(n.maxValue)?n.maxValue:10,data:f.scenes.map((n,t)=>{const i=u.get(n.sceneId);return i==null?{x:t+.5,y:null,sceneId:n.sceneId}:{x:t+.5,y:i,sceneId:n.sceneId}}),borderColor:r,backgroundColor:r,pointBackgroundColor:r,pointBorderColor:"#fff",pointBorderWidth:1.5,pointRadius:3,pointHoverRadius:5,borderWidth:2,tension:.35,spanGaps:!0,hidden:!tt.has(n.metricName)}});let e=null,a=!1;const h=n=>{c&&(c.textContent=n)},d=()=>l.map((n,t)=>t).filter(n=>r?.isDatasetVisible(n)),g=()=>{const n=d();return n.length===1?n[0]:-1},nt=()=>{if(v){const n=g();l.forEach((t,i)=>{t.pointRadius=i===n?5:3,t.pointHoverRadius=i===n?7:5,t.borderWidth=i===n?3:2});const t=d(),i=n>=0;o.classList.toggle("metric-curve-editing",i);c.classList.toggle("d-none",t.length===0);t.length===0?h(""):i?h("Drag points up or down to edit this metric."):h("Show only one metric line to edit its curve.");r?.update()}};w.innerHTML="";l.forEach((n,t)=>{const u=`metric-toggle-${Math.random().toString(36).slice(2)}-${t}`,i=document.createElement("label");i.className="metric-toggle-pill";i.style.setProperty("--metric-colour",n.borderColor);i.innerHTML=`<input type="checkbox" id="${u}" ${n.hidden?"":"checked"}><span>${n.label}</span>`;w.appendChild(i);i.querySelector("input").addEventListener("change",n=>{r.setDatasetVisibility(t,n.target.checked),nt(),r.update()})});const r=new Chart(o,{type:"line",data:{datasets:l},options:{responsive:!0,maintainAspectRatio:!1,interaction:{mode:"nearest",intersect:!1},scales:{y:{min:1,max:10,ticks:{stepSize:1},grid:{color:"rgba(82, 75, 65, 0.10)"}},x:{type:"linear",min:0,max:s,bounds:"ticks",ticks:{maxRotation:0,autoSkip:!1,maxTicksLimit:16,callback(n){const t=Math.floor(Number(n));if(t<0||t>=s)return"";const i=f.scenes[t];return t!==0&&t!==s-1&&t%it!=0?"":i?.isPlaceholder?"":i?.axisLabel||""}},afterBuildTicks(n){n.ticks=f.scenes.map((n,t)=>({value:t+.5}))},grid:{display:!1}}},plugins:{legend:{display:!1},plotlineScenes:f.scenes,tooltip:{callbacks:{title(n){const i=Math.floor(n[0].parsed.x),t=f.scenes[i];return t.isPlaceholder?t.sceneTitle||"No scene":`${t.chapterLabel}, Scene ${t.sceneNumber}: ${t.sceneTitle}`},label(n){return`${n.dataset.label}: ${n.formattedValue}`},afterBody(n){const r=Math.floor(n[0].parsed.x),t=f.scenes[r],i=[];return t.characterPresence?i.push(t.characterPresence):t.characterAppears!==undefined&&i.push(t.characterAppears?"Character appears":"Character does not appear"),t.bookTitle&&i.push(t.bookTitle),i}}}}}}),rt=n=>{if(!v)return null;const u=g();if(u<0)return null;const f=r.getElementsAtEventForMode(n,"nearest",{intersect:!0},!0),t=f.find(n=>n.datasetIndex===u);if(!t)return null;const e=r.data.datasets[t.datasetIndex],i=e?.data?.[t.index];return!i?.sceneId||i.y==null?null:{datasetIndex:t.datasetIndex,pointIndex:t.index,previousValue:i.y}},ut=(n,t)=>{const i=r.scales.y.getValueForPixel(n.offsetY),u=Math.round(i);return Math.max(t.minValue,Math.min(t.maxValue,u))},ft=async t=>{const u=r.data.datasets[t.datasetIndex],i=u?.data?.[t.pointIndex];if(u&&i?.sceneId){const f=k?.querySelector("input[name='__RequestVerificationToken']")?.value||"";h("Saving...");try{const e=await fetch(n.dataset.updateUrl||"/SceneMetrics/UpdateSceneMetricValue",{method:"POST",headers:{"Content-Type":"application/json",RequestVerificationToken:f},body:JSON.stringify({sceneId:Number(i.sceneId),metricId:Number(u.metricTypeId),value:Number(i.y)})}),t=await e.json().catch(()=>({}));if(!e.ok||!t.success)throw new Error(t.message||"Save failed");i.y=t.value;h("Saved");r.update()}catch{i.y=t.previousValue;h("Save failed");r.update()}}};v&&(nt(),o.addEventListener("pointerdown",n=>{(e=rt(n),e)&&(n.preventDefault(),o.setPointerCapture?.(n.pointerId),a=!0)}),o.addEventListener("pointermove",n=>{if(e){const t=r.data.datasets[e.datasetIndex],i=t?.data?.[e.pointIndex];t&&i&&(i.y=ut(n,t),r.update("none"))}}),o.addEventListener("pointerup",async n=>{if(e){const t=e;e=null;o.releasePointerCapture?.(n.pointerId);await ft(t);window.setTimeout(()=>{a=!1},0)}}),o.addEventListener("pointercancel",n=>{if(e){const i=r.data.datasets[e.datasetIndex],t=i?.data?.[e.pointIndex];t&&(t.y=e.previousValue);e=null;o.releasePointerCapture?.(n.pointerId);a=!1;r.update()}}));o.addEventListener("click",n=>{if(a){n.preventDefault();return}const t=r.getElementsAtEventForMode(n,"nearest",{intersect:!0},!0);if(t.length){const i=r.data.datasets[t[0].datasetIndex]?.data?.[t[0].index],e=i?Math.floor(i.x):t[0].index,u=f.scenes[e];u?.timelineUrl&&(window.PlotLineTimelineScroll?.save(),window.location.href=u.timelineUrl)}});i.push(r);const y=window.ResizeObserver?new ResizeObserver(()=>r.resize()):null;y&&(y.observe(n),y.observe(n.querySelector(".metric-chart-frame")||n))}})}})();(()=>{const i=document.querySelector("[data-timeline-root]"),t=document.querySelector("[data-timeline-controls]");if(i&&t){const r="plotline.timeline.visibility",u={"scene-cards":!0,"plot-lines":!0,assets:!0,characters:!0,locations:!0,warnings:!0,metrics:!0},e=()=>{try{return{...u,...JSON.parse(localStorage.getItem(r)||"{}")}}catch{return{...u}}},f=n=>{Object.entries(n).forEach(([n,t])=>{i.classList.toggle(`hide-${n}`,!t),document.querySelectorAll(`[data-timeline-section='${n}']`).forEach(n=>{n.classList.toggle("timeline-section-hidden",!t)})}),document.querySelectorAll("[data-location-marker]").forEach(t=>{t.classList.toggle("timeline-section-hidden",!n.locations)}),document.querySelectorAll("[data-warning-marker]").forEach(t=>{t.classList.toggle("timeline-section-hidden",!n.warnings)}),document.querySelector("[data-visibility-json]")?.setAttribute("value",JSON.stringify(n))},n=e();t.querySelectorAll("[data-timeline-toggle]").forEach(t=>{const i=t.dataset.timelineToggle;t.checked=n[i]??!0;t.addEventListener("change",()=>{n[i]=t.checked,localStorage.setItem(r,JSON.stringify(n)),f(n)})});t.querySelector("[data-timeline-preset-form]")?.addEventListener("submit",()=>{document.querySelector("[data-visibility-json]")?.setAttribute("value",JSON.stringify(n))});f(n)}})();(()=>{const n=document.querySelector("[data-timeline-root]");if(n){const f=n.querySelector(".timeline-workspace")||n,h=document.querySelector("[data-timeline-density]"),e=document.querySelector("[data-timeline-zoom]"),t=document.querySelector("[data-timeline-search]"),c=n.querySelector("[data-timeline-minimap]"),ft=document.querySelectorAll("[data-timeline-jump], [data-timeline-warning-jump], [data-timeline-entity-jump]"),et=[...n.querySelectorAll(".timeline-scene-card[data-scene-id]")],l="plotline.timeline.collapsed",d="plotline.timeline.density",g="plotline.timeline.zoom",o="plotline.timeline.pending-scroll",a="plotline.timeline.inspectorWidth",ot=".timeline-shell,.plot-lane-board,.asset-lane-board,.character-lane-board,.metric-graph-stack,[data-timeline-minimap]",nt=["compact","comfortable","expanded"],s=["book","chapter","scene-detail"],v=n.querySelector("[data-inspector-drawer]"),i=n.querySelector("[data-inspector-resizer]"),st=n.querySelector("[data-inspector-close]"),ht=n=>{try{return new Set(JSON.parse(localStorage.getItem(n)||"[]"))}catch{return new Set}},ct=localStorage.getItem(l)!==null,r=ht(l),tt=()=>[...n.querySelectorAll(ot)],lt=()=>{const t=n.getBoundingClientRect().width||window.innerWidth,i=Math.min(420,Math.max(320,t-360)),r=Math.max(i,Math.min(t*.65,t-420));return{minimum:i,maximum:r,defaultWidth:Math.max(i,Math.min(r,t*.4))}},y=t=>{if(v){const{minimum:i,maximum:r,defaultWidth:u}=lt(),f=Math.max(i,Math.min(r,Number(t)||u));n.style.setProperty("--timeline-inspector-width",`${Math.round(f)}px`)}};v&&(y(localStorage.getItem(a)),window.addEventListener("resize",()=>y(localStorage.getItem(a))));i?.addEventListener("pointerdown",t=>{t.preventDefault();document.body.classList.add("timeline-inspector-resizing");i.setPointerCapture(t.pointerId);const u=t=>{const i=n.getBoundingClientRect().right,r=i-t.clientX;y(r)},r=()=>{document.body.classList.remove("timeline-inspector-resizing");const n=Math.round(v?.getBoundingClientRect().width||0);n>0&&localStorage.setItem(a,String(n));window.dispatchEvent(new Event("plotline:timeline-layout-changed"));i.removeEventListener("pointermove",u);i.removeEventListener("pointerup",r);i.removeEventListener("pointercancel",r)};i.addEventListener("pointermove",u);i.addEventListener("pointerup",r);i.addEventListener("pointercancel",r)});st?.addEventListener("click",n=>{n.preventDefault();const t=new URL(window.location.href),i=t.searchParams.get("FocusType")||t.searchParams.get("focusType");t.searchParams.delete("SelectedSceneID");t.searchParams.delete("selectedSceneId");t.searchParams.delete("selectedsceneid");i&&i.toLowerCase()!=="scene"||(t.searchParams.delete("FocusType"),t.searchParams.delete("focusType"),t.searchParams.delete("FocusID"),t.searchParams.delete("focusId"));p();window.location.href=t.toString()});const p=()=>{try{sessionStorage.setItem(o,JSON.stringify({path:window.location.pathname,top:window.scrollY,left:window.scrollX,workspaceLeft:f.scrollLeft,workspaceTop:f.scrollTop,containers:tt().map((n,t)=>({index:t,left:n.scrollLeft,top:n.scrollTop}))}))}catch{}},at=()=>{let n=null;try{n=JSON.parse(sessionStorage.getItem(o)||"null");sessionStorage.removeItem(o)}catch{try{sessionStorage.removeItem(o)}catch{}return}n&&n.path===window.location.pathname&&window.requestAnimationFrame(()=>{f.scrollLeft=Number(n.workspaceLeft)||0;f.scrollTop=Number(n.workspaceTop)||0;const t=tt();(n.containers||[]).forEach(n=>{const i=t[n.index];i&&(i.scrollLeft=Number(n.left)||0,i.scrollTop=Number(n.top)||0)});window.scrollTo(Number(n.left)||0,Number(n.top)||0)})};window.PlotLineTimelineScroll={save:p};const it=(t,i,r)=>{r.forEach(i=>n.classList.remove(`${t}-${i}`)),n.classList.add(`${t}-${i}`)},rt=n=>{const t=nt.includes(n)?n:"comfortable";it("density",t,nt);h&&(h.value=t);localStorage.setItem(d,t);window.requestAnimationFrame(u)},w=n=>{const t=s.includes(n)?n:"chapter";it("zoom",t,s);e&&(e.value=t);localStorage.setItem(g,t);window.requestAnimationFrame(u)},vt=t=>n.querySelector(`[data-scene-id='${CSS.escape(String(t))}']`),b=(n,t=true)=>{const i=vt(n);i&&(i.classList.add("keyboard-focus"),i.scrollIntoView({behavior:"smooth",block:"center",inline:"center"}),t&&i.focus({preventScroll:!0}),window.setTimeout(()=>i.classList.remove("keyboard-focus"),1800))},yt=(n="auto")=>{const r=c?.querySelector("[data-active-chapter='true']");if(c&&r){const t=c.getBoundingClientRect(),i=r.getBoundingClientRect(),u=i.left+i.width/2,f=t.left+t.width/2;(i.left<t.left||i.right>t.right)&&c.scrollBy({left:u-f,behavior:n})}},pt=()=>localStorage.setItem(l,JSON.stringify([...r])),u=()=>{n.querySelectorAll("[data-plot-line-svg-board]").forEach(n=>{const t=n.querySelector("[data-plot-line-svg]");if(t){t.replaceChildren();const u=n.getBoundingClientRect(),e=Math.max(n.scrollWidth,u.width),o=Math.max(n.scrollHeight,u.height);t.setAttribute("viewBox",`0 0 ${e} ${o}`);t.setAttribute("width",String(e));t.setAttribute("height",String(o));const i=(n,t={})=>{const i=document.createElementNS("http://www.w3.org/2000/svg",n);return Object.entries(t).forEach(([n,t])=>i.setAttribute(n,String(t))),i},s=n=>{const t=n.getBoundingClientRect();return t.top-u.top+t.height/2},l=(n,t)=>{const i=t.closest("[data-plot-line-slot]");if(!i)return null;const r=i.getBoundingClientRect();return{x:r.left-u.left+r.width/2,y:s(n),type:(t.dataset.plotEventType||"Progress").toLowerCase(),targetPlotLineId:t.dataset.targetPlotLineId||"",targetPlotLineIds:(t.dataset.targetPlotLineIds||"").split(",").map(n=>n.trim()).filter(Boolean)}},f=new Map;n.querySelectorAll("[data-plot-line-row]").forEach(n=>{n.dataset.plotLineId&&f.set(n.dataset.plotLineId,n)});const r=[...f.values()].map(n=>({row:n,plotLineId:n.dataset.plotLineId,colour:n.dataset.plotColour||"#2f6f63",points:[...n.querySelectorAll("[data-plot-event-node]")].map(t=>l(n,t)).filter(Boolean).sort((n,t)=>n.x-t.x),incomingStartXs:[]})),h=new Map(r.map(n=>[n.plotLineId,n])),a=(n,r)=>{const u=i("g",{"class":`plot-event-svg-node plot-event-svg-node-${n.type}`});n.type==="twist"?u.append(i("path",{d:`M ${n.x} ${n.y-7} L ${n.x+7} ${n.y} L ${n.x} ${n.y+7} L ${n.x-7} ${n.y} Z`,fill:r})):n.type==="abandon"?(u.append(i("line",{x1:n.x-6,y1:n.y-6,x2:n.x+6,y2:n.y+6})),u.append(i("line",{x1:n.x+6,y1:n.y-6,x2:n.x-6,y2:n.y+6}))):(u.append(i("circle",{cx:n.x,cy:n.y,r:6,fill:r})),n.type==="resolve"&&u.append(i("circle",{cx:n.x,cy:n.y,r:10,fill:"none",stroke:r})));t.append(u)},c=(n,r,u,f)=>{if(!r){window.console?.warn&&window.console.warn(`Plot line ${f} connector skipped because target plot line data is missing.`);return}const e={x:n.x,y:s(r)},h=Math.max(34,Math.min(78,Math.abs(e.y-n.y)*.42)),o=n.x+h;t.append(i("path",{"class":`plot-line-svg-connector plot-line-svg-connector-${f}`,d:`M ${n.x} ${n.y} C ${o} ${n.y}, ${o} ${e.y}, ${e.x} ${e.y}`,stroke:u}))};r.forEach(n=>{n.points.forEach(n=>{n.type==="branch"&&n.targetPlotLineId&&h.get(n.targetPlotLineId)?.incomingStartXs.push(n.x),n.type==="split"&&n.targetPlotLineIds.forEach(t=>{h.get(t)?.incomingStartXs.push(n.x)})})});r.forEach(({colour:n,points:u,incomingStartXs:r})=>{if(u.length>0){const o=u.find(n=>n.type==="start"),f=r.length?Math.min(...r):null,s=u.find(n=>n.type==="split"||n.type==="merge"),e=u[0],l=u[u.length-1],h=f!==null&&!(o&&o.x<f)?f:e.x,c=s?s.x:l.x;c>h&&t.append(i("path",{"class":"plot-line-svg-path",d:`M ${h} ${e.y} L ${c} ${e.y}`,stroke:n}))}});r.forEach(({points:t,colour:n})=>{t.forEach(t=>{(t.type==="branch"||t.type==="merge")&&c(t,f.get(t.targetPlotLineId),n,t.type),t.type==="split"&&t.targetPlotLineIds.length>=2?t.targetPlotLineIds.forEach(i=>{c(t,f.get(i),n,t.type)}):t.type==="split"&&t.targetPlotLineIds.length>0&&window.console?.warn&&window.console.warn("Plot line split connector skipped because fewer than two targets are available.")})});r.forEach(({points:t,colour:n})=>{t.forEach(t=>a(t,n))})}})},ut=(n,t)=>{document.querySelectorAll(`[data-collapse-body='${CSS.escape(n)}']`).forEach(n=>{n.classList.toggle("timeline-section-collapsed",t)}),document.querySelectorAll(`[data-collapse-toggle='${CSS.escape(n)}']`).forEach(n=>{n.classList.toggle("is-collapsed",t),n.setAttribute("aria-expanded",String(!t))})};document.querySelectorAll("[data-collapse-toggle]").forEach(n=>{const t=n.dataset.collapseToggle;ct||n.dataset.collapseDefault!=="collapsed"||r.add(t);const i=r.has(t);ut(t,i);n.addEventListener("click",()=>{const n=!r.has(t);n?r.add(t):r.delete(t);ut(t,n);pt();u();window.dispatchEvent(new Event("plotline:timeline-layout-changed"))})});h?.addEventListener("change",()=>rt(h.value));e?.addEventListener("change",()=>w(e.value));rt(localStorage.getItem(d)||"comfortable");w(localStorage.getItem(g)||"chapter");const wt=(()=>{try{return sessionStorage.getItem(o)!==null}catch{return!1}})();window.requestAnimationFrame(()=>{u(),yt("auto"),wt&&at()});window.addEventListener("resize",u);window.addEventListener("plotline:timeline-layout-changed",u);const bt=t=>{if(t.button===0&&!t.metaKey&&!t.ctrlKey&&!t.shiftKey&&!t.altKey){const r=t.target instanceof Element?t.target:null,i=r?.closest("a[href]");if(i&&n.contains(i)){const u=new URL(i.href,window.location.href);[...u.searchParams.keys()].some(n=>n.toLowerCase()==="selectedsceneid")&&p()}}};n.addEventListener("click",bt,{capture:!0});const k=()=>{const n=t?.value.trim().toLowerCase()||"";let i=null;return et.forEach(t=>{const r=!n||(t.dataset.timelineSearchText||"").toLowerCase().includes(n);t.classList.toggle("search-hit",Boolean(n&&r));t.classList.toggle("search-dim",Boolean(n&&!r));!i&&n&&r&&(i=t)}),i};t?.addEventListener("input",k);t?.addEventListener("keydown",n=>{if(n.key==="Enter"){const t=k();t&&(n.preventDefault(),b(t.dataset.sceneId))}});ft.forEach(n=>{n.addEventListener("change",()=>{n.value&&b(n.value)})});document.querySelectorAll("[data-jump-scene]").forEach(n=>{n.addEventListener("click",()=>{n.dataset.jumpScene&&b(n.dataset.jumpScene)})});document.addEventListener("keydown",n=>{const i=document.activeElement?.tagName?.toLowerCase(),r=["input","select","textarea"].includes(i)||document.activeElement?.isContentEditable;if((n.ctrlKey||n.metaKey)&&n.key.toLowerCase()==="f"&&t){n.preventDefault();t.focus();t.select();return}if(n.key==="Escape"){const n=new URL(window.location.href),i=n.searchParams.has("FocusType")||n.searchParams.has("FocusID");n.searchParams.delete("FocusType");n.searchParams.delete("FocusID");i?window.location.href=n.toString():t?.value&&(t.value="",k());return}if(!r){if(n.key==="ArrowLeft"||n.key==="ArrowRight"){n.preventDefault();f.scrollBy({left:n.key==="ArrowLeft"?-260:260,behavior:"smooth"});return}if(n.key==="+"||n.key==="="||n.key==="-"){const t=s.indexOf(e?.value||"chapter"),i=n.key==="-"?-1:1,r=Math.min(s.length-1,Math.max(0,t+i));w(s[r])}}})}})();(()=>{const e=document.querySelector("[data-timeline-root]"),t=document.querySelector("[data-drag-drop-panel]");if(t){const i=new Map([...document.querySelectorAll("[data-drag-form]")].map(n=>[n.dataset.dragForm,n])),g=t.querySelector("[data-drag-panel-title]"),nt=t.querySelector("[data-drag-panel-kicker]"),tt=t.querySelector("[data-drag-panel-summary]"),o=document.querySelector("[data-scene-move-modal]"),v=o&&window.bootstrap?.Modal?window.bootstrap.Modal.getOrCreateInstance(o):null,y=o?.querySelector("[data-scene-move-title]"),p=o?.querySelector("[data-scene-move-summary]"),w=o?.querySelector("[data-scene-move-submit]"),s="plotline.timeline.scroll";let h=null,c=0;const n=(n,t,i)=>{const r=n?.querySelector(`[name='${CSS.escape(t)}']`);r&&(r.value=i??"")},l=n=>n?.selectedOptions?.[0]?.textContent?.trim()||"",a=n=>`“${n||"this scene"}”`,b=(n,t,i,r,u)=>t&&i&&t===i?`Move ${a(n.label)} to this new position within ${i}?`:t&&i?`Move ${a(n.label)} from ${t} to ${i}?`:`Move ${a(n.label)} ${r.toLowerCase()} ${u}?`,r=(n,r,u,f)=>{if(n==="scene"){t.classList.add("d-none");t.querySelectorAll("[data-drag-form]").forEach(n=>n.classList.add("d-none"));i.get("scene")?.classList.remove("d-none");y&&(y.textContent=r);p&&(p.textContent=u);w&&w.classList.toggle("d-none",r.toLowerCase().startsWith("cannot")||r.toLowerCase().startsWith("scene already"));v?v.show():t.classList.remove("d-none");return}i.forEach((t,i)=>t.classList.toggle("d-none",i!==n));t.classList.remove("d-none");g.textContent=r;nt.textContent=f;tt.textContent=u;t.scrollIntoView({behavior:"smooth",block:"center"})},it=()=>{t.classList.add("d-none"),i.forEach(n=>n.classList.add("d-none"))},k=()=>{document.querySelectorAll(".drop-target-active, .drop-before, .drop-after, .chapter-drop-active, .drop-chapter-end").forEach(n=>n.classList.remove("drop-target-active","drop-before","drop-after","chapter-drop-active","drop-chapter-end"))},rt=()=>{const n=e?.querySelector(".timeline-shell");try{sessionStorage.setItem(s,JSON.stringify({left:n?.scrollLeft||0,top:window.scrollY||0}))}catch{}};try{const n=JSON.parse(sessionStorage.getItem(s)||"null");n&&(sessionStorage.removeItem(s),requestAnimationFrame(()=>{const t=e?.querySelector(".timeline-shell");t&&(t.scrollLeft=n.left||0);window.scrollTo({top:n.top||0})}))}catch{sessionStorage.removeItem(s)}const f=n=>{try{const t=JSON.parse(n.dataTransfer.getData("application/json")||"{}");return t.type?t:h||{}}catch{return h||{}}},ut=(n,t)=>{const i={type:t.dataset.dragType,id:t.dataset.dragId,label:t.dataset.dragLabel||t.textContent.trim()};n.dataTransfer.effectAllowed="copyMove";n.dataTransfer.setData("application/json",JSON.stringify(i));n.dataTransfer.setData("text/plain",`${i.type}:${i.id}`);h=i;document.body.classList.add("drag-active",`dragging-${i.type}`);t.classList.add("is-dragging")};document.querySelectorAll("[data-drag-type][draggable='true']").forEach(n=>{n.addEventListener("dragstart",t=>ut(t,n)),n.addEventListener("dragend",()=>{n.classList.remove("is-dragging"),document.body.classList.remove("drag-active","dragging-scene","dragging-character","dragging-asset","dragging-location"),h=null,k()})});t.querySelectorAll("[data-drag-cancel]").forEach(n=>n.addEventListener("click",it));i.get("scene")?.addEventListener("submit",rt);e?.querySelectorAll(".timeline-scene-card[data-scene-id]").forEach(t=>{t.addEventListener("click",n=>{Date.now()<c&&(n.preventDefault(),n.stopPropagation())}),t.addEventListener("dragover",n=>{const i=f(n);["scene","character","asset"].includes(i.type)&&(n.preventDefault(),n.stopPropagation(),n.dataTransfer.dropEffect=i.type==="scene"?"move":"copy",t.classList.add("drop-target-active"),t.classList.toggle("drop-before",i.type==="scene"&&n.offsetX<t.clientWidth/2),t.classList.toggle("drop-after",i.type==="scene"&&n.offsetX>=t.clientWidth/2))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active","drop-before","drop-after")),t.addEventListener("drop",u=>{const o=f(u);if(["scene","character","asset"].includes(o.type)){u.preventDefault();u.stopPropagation();c=Date.now()+800;t.classList.remove("drop-target-active","drop-before","drop-after");const s=t.dataset.sceneId;if(o.type==="scene"){if(o.id===s){r("scene","Cannot move scene","Drop a scene before or after a different scene.","Scene move");return}const f=i.get("scene"),h=u.offsetX<t.clientWidth/2?"Before":"After",c=e.querySelector(`.timeline-scene-card[data-scene-id='${CSS.escape(o.id)}']`),l=c?.dataset.chapterLabel||"",a=t.dataset.chapterLabel||"";n(f,"SceneID",o.id);n(f,"AnchorSceneID",s);n(f,"TargetChapterID","");n(f,"Position",h);r("scene","Move Scene?",b(o,l,a,h,t.dataset.dragLabel),"Scene move");return}if(o.type==="character"){const u=i.get("character");n(u,"SceneID",s);n(u,"CharacterID",o.id);r("character","Add character to scene",`Add ${o.label} to ${t.dataset.dragLabel}.`,"Character drop");return}const h=i.get("asset-event");n(h,"SceneID",s);n(h,"StoryAssetID",o.id);n(h,"EventTitle","");r("asset-event","What happens to this asset?",`Add an event for ${o.label} in ${t.dataset.dragLabel}.`,"Asset drop")}})});e?.querySelectorAll(".timeline-scenes[data-chapter-drop-target]").forEach(t=>{const u=t.closest("[data-chapter-drop-target]"),o=t.dataset.chapterId||u?.dataset.chapterId,s=t.dataset.chapterLabel||u?.dataset.chapterLabel||"this chapter";t.addEventListener("dragover",n=>{const i=f(n);i.type==="scene"&&o&&(n.target.closest(".timeline-scene-card[data-scene-id]")||(n.preventDefault(),n.dataTransfer.dropEffect="move",t.classList.add("drop-target-active","drop-chapter-end"),u?.classList.add("chapter-drop-active")))});t.addEventListener("dragleave",n=>{t.contains(n.relatedTarget)||(t.classList.remove("drop-target-active","drop-chapter-end"),u?.classList.remove("chapter-drop-active"))});t.addEventListener("drop",u=>{const h=f(u);if(h.type==="scene"&&o&&!u.target.closest(".timeline-scene-card[data-scene-id]")){u.preventDefault();u.stopPropagation();c=Date.now()+800;k();const a=e.querySelector(`.timeline-scene-card[data-scene-id='${CSS.escape(h.id)}']`);if(a?.dataset.chapterId===o&&t.lastElementChild?.dataset?.sceneId===h.id){r("scene","Scene already here",`${h.label} is already at the end of ${s}.`,"Scene move");return}const l=i.get("scene");n(l,"SceneID",h.id);n(l,"AnchorSceneID","");n(l,"TargetChapterID",o);n(l,"Position","End");r("scene","Move Scene?",b(h,a?.dataset.chapterLabel||"",s,"After",s),"Scene move")}})});const u=i.get("asset-dependency"),d=()=>{const n=u?.dataset.sourceLabel||"Source asset",i=u?.dataset.targetLabel||"Target asset",f=l(u?.querySelector("[name='AssetDependencyTypeID']"))||"Requires",e=l(u?.querySelector("[name='SourceRequiredStateID']"))||"the required state",o=l(u?.querySelector("[name='TargetBlockedStateID']"))||"the blocked state",r=t.querySelector("[data-asset-dependency-preview]");r&&(r.textContent=`${n} ${f.toLowerCase()} ${i}. ${n} should be ${e} before ${i} can be ${o}.`)};u?.querySelectorAll("select").forEach(n=>n.addEventListener("change",d));document.querySelectorAll("[data-asset-drop-target], .drag-chip.asset").forEach(t=>{t.addEventListener("dragover",n=>{const i=f(n);i.type==="asset"&&(n.preventDefault(),n.dataTransfer.dropEffect="copy",t.classList.add("drop-target-active"))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active")),t.addEventListener("drop",i=>{const e=f(i),o=t.dataset.assetId||t.dataset.dragId,s=t.dataset.assetLabel||t.dataset.dragLabel||t.textContent.trim();if(e.type==="asset"&&o){if(i.preventDefault(),t.classList.remove("drop-target-active"),e.id===o){r("asset-dependency","Cannot create dependency","Drop one asset onto a different asset.","Asset dependency");return}n(u,"SourceAssetID",e.id);n(u,"TargetAssetID",o);u.dataset.sourceLabel=e.label;u.dataset.targetLabel=s;d();r("asset-dependency","Create asset dependency",`${e.label} -> ${s}`,"Asset dependency")}})});document.querySelectorAll("[data-drag-type='location']").forEach(t=>{t.addEventListener("dragover",n=>{const i=f(n);i.type==="location"&&(n.preventDefault(),n.dataTransfer.dropEffect="copy",t.classList.add("drop-target-active"))}),t.addEventListener("dragleave",()=>t.classList.remove("drop-target-active")),t.addEventListener("drop",u=>{const e=f(u),o=t.dataset.dragId,h=t.dataset.dragLabel||t.textContent.trim();if(e.type==="location"){if(u.preventDefault(),t.classList.remove("drop-target-active"),e.id===o){r("location-relationship","Cannot create relationship","Drop one location onto a different location.","Location relationship");return}const s=i.get("location-relationship");n(s,"FromLocationID",e.id);n(s,"ToLocationID",o);r("location-relationship","Create location relationship",`${e.label} -> ${h}`,"Location drop")}})})}})(); |