domma-cms 1.6.19 → 1.6.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/dist/domma/domma-tools.css +3 -3
- package/admin/dist/domma/domma-tools.min.js +3 -3
- package/admin/js/lib/scribe-composer.js +1 -1
- package/admin/js/templates/docs/usage-actions.html +3 -0
- package/admin/js/views/collection-entries.js +1 -1
- package/package.json +2 -2
- package/public/js/context-menus.js +1 -1
- package/public/js/site.js +1 -1
- package/server/routes/api/actions.js +32 -3
- package/server/services/renderer.js +2 -2
- package/server/templates/page.html +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Domma Tools CSS v0.51.
|
|
2
|
+
* Domma Tools CSS v0.51.11
|
|
3
3
|
* Dynamic Object Manipulation & Modeling API
|
|
4
4
|
* (c) 2026 Darryl Waterhouse & DCBW-IT
|
|
5
|
-
* Built: 2026-10-
|
|
6
|
-
* Commit:
|
|
5
|
+
* Built: 2026-10-12T06:05:33.864Z
|
|
6
|
+
* Commit: a53de2f
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
/*!
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Domma Tools v0.51.
|
|
2
|
+
* Domma Tools v0.51.11
|
|
3
3
|
* Developer tools: Theme Roller & Page Roller
|
|
4
4
|
* (c) 2026 Darryl Waterhouse & DCBW-IT
|
|
5
|
-
* Built: 2026-10-
|
|
6
|
-
* Commit:
|
|
5
|
+
* Built: 2026-10-12T06:05:20.912Z
|
|
6
|
+
* Commit: a53de2f
|
|
7
7
|
*
|
|
8
8
|
* Requires: domma.min.js
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{insertAtCursor as re}from"./markdown-toolbar.js";import{SCRIBE_FIELDS as ae,scribeDefaults as se,scribeLoop as ce,stateToScribeActions as ie,buildScribeShortcode as le}from"./scribe-model.js";const de=20,Q={render:{label:"Render",icon:"edit-3",color:"var(--dm-info,#3b82f6)"},wait:{label:"Wait",icon:"clock",color:"var(--dm-warning,#f59e0b)"},undo:{label:"Undo",icon:"corner-up-left",color:"var(--dm-secondary,#a855f7)"},redraw:{label:"Redraw",icon:"refresh-cw",color:"var(--dm-success,#22c55e)"}},L="padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;box-sizing:border-box;width:100%;",pe="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem;",ue="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.85em;";export function openScribeComposer(s){const r=me(),n=[];let t=null,p=null;function c(){clearTimeout(t),p?.destroy(),p=null}const h=E.slideover({title:"Scribe Composer",size:"lg",position:"right",onClose:c});Ce();const b=document.createElement("div");b.className="scribe-composer",b.style.cssText="display:flex;flex-direction:column;height:100%;";const y=document.createElement("div");y.style.cssText="padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);";const k=document.createElement("div");k.style.cssText="min-height:3.5rem;padding:.85rem 1rem;background:var(--dm-surface,#1a1a1a);border:1px dashed var(--dm-border,#333);border-radius:6px;font-size:1.25rem;line-height:1.5;overflow-wrap:anywhere;",y.appendChild(k);const B=document.createElement("div");B.style.cssText="display:flex;gap:.5rem;margin-top:.75rem;align-items:center;";const Y=V("rotate-cw","Replay"),q=V("code","Show code"),N=document.createElement("span");N.style.cssText="font-size:.8em;color:var(--dm-text-muted,#aaa);flex:1;text-align:right;margin-right:.5rem;",B.appendChild(Y),B.appendChild(N),B.appendChild(q),y.appendChild(B);const M=document.createElement("pre");M.style.cssText="display:none;margin:.75rem 0 0;padding:.6rem .75rem;background:var(--dm-surface,#0a0a0a);border:1px solid var(--dm-border,#333);border-radius:4px;font-family:monospace;font-size:.78em;white-space:pre-wrap;word-break:break-all;color:var(--dm-text-muted,#bbb);max-height:200px;overflow:auto;",y.appendChild(M),q.addEventListener("click",()=>{const e=M.style.display!=="none";M.style.display=e?"none":"block"}),Y.addEventListener("click",()=>{J(),p?.resume(),p&&(N.textContent="Playing preview")}),b.appendChild(y);const R=document.createElement("div");R.style.cssText="display:flex;flex:1;min-height:0;overflow:hidden;";const F=fe(r,()=>{C(),x()});R.appendChild(F.el);const z=document.createElement("main");z.style.cssText="flex:1;overflow-y:auto;padding:1rem 1.25rem;display:flex;flex-direction:column;";const D=document.createElement("h4");D.textContent="Actions",D.style.cssText="margin:0 0 .75rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",z.appendChild(D);const A=document.createElement("div");A.style.cssText="display:flex;flex-direction:column;gap:.6rem;",z.appendChild(A);const P=document.createElement("div");P.style.cssText="display:flex;gap:.4rem;margin-top:.9rem;flex-wrap:wrap;",Object.entries(Q).forEach(([e,a])=>{const i=document.createElement("button");i.type="button",i.style.cssText=`padding:.4rem .8rem;background:transparent;border:1px dashed color-mix(in srgb, ${a.color} 40%, transparent);border-radius:4px;color:${a.color};cursor:pointer;font-size:.85em;display:inline-flex;align-items:center;gap:.35rem;`;const l=document.createElement("span");l.setAttribute("data-icon",a.icon),i.appendChild(l),i.appendChild(document.createTextNode(` + ${a.label}`)),i.addEventListener("click",()=>{C(),r.actions.push(he(e)),$(),x()}),P.appendChild(i)}),z.appendChild(P),R.appendChild(z),b.appendChild(R);const T=document.createElement("div");T.style.cssText="display:flex;padding:.75rem 1rem;border-top:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);gap:.5rem;align-items:center;";const S=document.createElement("button");S.type="button",S.className="btn btn-ghost btn-sm",S.textContent="Undo (Ctrl+Z)",S.addEventListener("click",()=>H()),T.appendChild(S);const U=document.createElement("span");U.style.cssText="font-size:.75em;color:var(--dm-text-muted,#aaa);",T.appendChild(U);const G=document.createElement("div");G.style.flex="1",T.appendChild(G);const W=document.createElement("button");W.type="button",W.className="btn btn-ghost",W.textContent="Cancel",W.addEventListener("click",()=>h.close()),T.appendChild(W);const j=document.createElement("button");j.type="button",j.className="btn btn-primary",j.textContent="Insert Scribe",j.addEventListener("click",()=>{re(s,Z()),h.close()}),T.appendChild(j),b.appendChild(T),h.setContent(b),b.addEventListener("keydown",e=>{const a=(e.key||"").toLowerCase();(e.ctrlKey||e.metaKey)&&a==="z"&&!e.shiftKey&&n.length>0&&(e.preventDefault(),e.stopPropagation(),H())}),$(),x(),O(),requestAnimationFrame(()=>{Domma.icons.scan()}),h.open();function C(){n.push(JSON.stringify(r)),n.length>de&&n.shift(),O()}function H(){if(n.length===0){E.toast("Nothing to undo",{type:"info",duration:700});return}const e=JSON.parse(n.pop());Object.assign(r.globals,e.globals),r.actions.length=0,e.actions.forEach(a=>r.actions.push(a)),F.sync(),$(),x(),O(),E.toast("Undone",{type:"info",duration:500})}function O(){U.textContent=n.length===0?"":`${n.length} step${n.length===1?"":"s"} stored`,S.disabled=n.length===0,S.style.opacity=n.length===0?".4":"1"}function x(e=150){clearTimeout(t),t=setTimeout(J,e)}function J(){c(),ee(k),k.style.color="",k.style.fontStyle="",M.textContent=Z();const e=r.actions.filter(o=>o.type==="render"||o.type==="redraw"?(o.text||"").length>0:!0);if(e.length===0){k.textContent="(add an action to preview)",k.style.color="var(--dm-text-muted,#666)",k.style.fontStyle="italic",N.textContent="";return}const a=document.createElement("span");a.className="dm-fx-scribe",k.appendChild(a);const i=r.globals,{effect:l,controls:g,...w}=i;w.actions=ie(e,l);try{p=Domma.effects.scribe(a,w),N.textContent=i.autoStart?`${e.length} action${e.length===1?"":"s"}`:"Press Replay to start"}catch{N.textContent="Preview error"}}function $(){if(ee(A),r.actions.length===0){const e=document.createElement("p");e.textContent="No actions yet - add one from the buttons below.",e.style.cssText="font-size:.85em;color:var(--dm-text-muted,#888);font-style:italic;margin:.5rem 0;",A.appendChild(e);return}r.actions.forEach((e,a)=>{A.appendChild(ne(e,a))}),requestAnimationFrame(()=>Domma.icons.scan())}function ne(e,a){const i=Q[e.type],l=document.createElement("div");l.style.cssText=`border:1px solid var(--dm-border,#333);border-left:3px solid ${i.color};border-radius:4px;padding:.6rem .75rem;background:var(--dm-surface,#15151a);`;const g=document.createElement("div");g.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const w=document.createElement("span");w.style.cssText=`display:inline-flex;align-items:center;gap:.3rem;font-size:.72rem;font-weight:700;color:${i.color};text-transform:uppercase;letter-spacing:.06em;`;const o=document.createElement("span");o.setAttribute("data-icon",i.icon),w.appendChild(o),w.appendChild(document.createTextNode(i.label)),g.appendChild(w);const m=document.createElement("span");m.textContent=`#${a+1}`,m.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);",g.appendChild(m);const u=document.createElement("div");u.style.flex="1",g.appendChild(u);const d=K("chevron-up","Move up");a===0&&(d.disabled=!0,d.style.opacity=".3"),d.addEventListener("click",()=>X(a,-1)),g.appendChild(d);const f=K("chevron-down","Move down");a===r.actions.length-1&&(f.disabled=!0,f.style.opacity=".3"),f.addEventListener("click",()=>X(a,1)),g.appendChild(f);const v=K("x","Remove");return v.addEventListener("click",()=>{C(),r.actions.splice(a,1),$(),x()}),g.appendChild(v),l.appendChild(g),l.appendChild(oe(e)),l}function X(e,a){const i=e+a;if(i<0||i>=r.actions.length)return;C();const[l]=r.actions.splice(e,1);r.actions.splice(i,0,l),$(),x()}function oe(e){const a=document.createElement("div");if(a.style.cssText="display:flex;flex-direction:column;gap:.5rem;",e.type==="render"||e.type==="redraw"){const o=document.createElement("textarea");o.value=e.text||"",o.placeholder=e.type==="redraw"?"New text - clears everything first, then types this":"Text to type out",o.rows=2,o.style.cssText=L+"resize:vertical;font-family:inherit;min-height:2.2rem;";let m=o.value;o.addEventListener("input",()=>{e.text=o.value,x()}),o.addEventListener("blur",()=>{o.value!==m&&(C(),m=o.value)}),a.appendChild(o);const u=document.createElement("div");u.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8em;";const d=document.createElement("label");d.textContent="Effect:",d.style.color="var(--dm-text-muted,#aaa)";const f=document.createElement("select");return f.style.cssText=L+"width:auto;padding:.25rem .4rem;",["inherit","none","fade","bounce","glow"].forEach(v=>{const _=document.createElement("option");_.value=v,_.textContent=v==="inherit"?"Default effect":v.charAt(0).toUpperCase()+v.slice(1),f.appendChild(_)}),f.value=e.effect||"none",f.addEventListener("change",()=>{C(),e.effect=f.value,x()}),u.appendChild(d),u.appendChild(f),a.appendChild(u),a}if(e.type==="wait"){const o=document.createElement("div");o.style.cssText="display:flex;gap:.4rem;align-items:center;";const m=document.createElement("input");m.type="number",m.min="0",m.step="any",m.value=String(e.duration??1e3),m.style.cssText=L+"flex:1;",m.addEventListener("input",()=>{const d=Number(m.value);!Number.isNaN(d)&&d>=0&&(e.duration=d,x())}),m.addEventListener("blur",()=>C()),o.appendChild(m);const u=document.createElement("select");return u.style.cssText=L+"width:auto;",[["ms","ms"],["s","seconds"]].forEach(([d,f])=>{const v=document.createElement("option");v.value=d,v.textContent=f,u.appendChild(v)}),u.value=e.unit||"ms",u.addEventListener("change",()=>{C(),e.unit=u.value,x()}),o.appendChild(u),a.appendChild(o),a}const i=document.createElement("div");i.style.cssText="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap;font-size:.85em;";const l=document.createElement("input");l.type="number",l.min="1",l.value=String(e.count||5),l.style.cssText=L+"width:5rem;",l.addEventListener("input",()=>{const o=parseInt(l.value,10);!Number.isNaN(o)&&o>0&&(e.count=o,x())}),l.addEventListener("blur",()=>C());const g=`undo-mode-${Math.random().toString(36).slice(2)}`;return[["last","Last render"],["all","All text"],["count","Exactly N units"]].forEach(([o,m])=>{const u=document.createElement("label");u.style.cssText="display:inline-flex;align-items:center;gap:.3rem;cursor:pointer;";const d=document.createElement("input");d.type="radio",d.name=g,d.value=o,d.checked=(e.mode||"last")===o,d.addEventListener("change",()=>{d.checked&&(C(),e.mode=o,l.style.display=o==="count"?"":"none",x())}),u.appendChild(d),u.appendChild(document.createTextNode(m)),i.appendChild(u),o==="count"&&(i.appendChild(l),l.style.display=(e.mode||"last")==="count"?"":"none")}),a.appendChild(i),a}function Z(){return le(r.globals,r.actions)}}function me(){return{globals:se(),actions:[{type:"render",text:"We build things that matter.",effect:"inherit"},{type:"wait",duration:1500,unit:"ms"},{type:"redraw",text:"We create solutions that last.",effect:"inherit"},{type:"wait",duration:1500,unit:"ms"}]}}function he(s){switch(s){case"render":return{type:"render",text:"",effect:"inherit"};case"wait":return{type:"wait",duration:1e3,unit:"ms"};case"undo":return{type:"undo",mode:"last",count:5};case"redraw":return{type:"redraw",text:"",effect:"inherit"}}return{type:"render",text:"",effect:"inherit"}}function fe(s,r){const n=document.createElement("aside");n.style.cssText="width:240px;flex-shrink:0;padding:1rem 1.25rem;border-right:1px solid var(--dm-border,#333);overflow-y:auto;display:flex;flex-direction:column;gap:.75rem;background:var(--dm-background-alt,#0c0c12);";const t=document.createElement("h4");t.textContent="Global settings",t.style.cssText="margin:0 0 .25rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",n.appendChild(t);const p=ae.map(c=>{const h=y=>{r(),s.globals[c.key]=c.key==="loop"?ce(y):y};let b;if(c.type==="checkbox"){const y=ve(s.globals[c.key],h,c.label);n.appendChild(y.wrap),b=y.input}else b=c.type==="select"?ge(c.options,s.globals[c.key],h):c.type==="number"?xe(s.globals[c.key],h,c.min):ye(s.globals[c.key],"",h),n.appendChild(be(c.label,b));return{field:c,input:b}});return{el:n,sync(){p.forEach(({field:c,input:h})=>{c.type==="checkbox"?h.checked=s.globals[c.key]:h.value=String(s.globals[c.key])})}}}function be(s,r){const n=document.createElement("div"),t=document.createElement("label");return t.style.cssText=pe,t.textContent=s,n.appendChild(t),n.appendChild(r),n}function xe(s,r,n=1){const t=document.createElement("input");return t.type="number",t.min=String(n),t.value=String(s),t.style.cssText=L,t.addEventListener("input",()=>{const p=Number(t.value);!Number.isNaN(p)&&p>=n&&r(p)}),t}function ye(s,r,n){const t=document.createElement("input");return t.type="text",t.value=s,t.placeholder=r,t.style.cssText=L,t.addEventListener("input",()=>n(t.value)),t}function ge(s,r,n){const t=document.createElement("select");return t.style.cssText=L,s.forEach(([p,c])=>{const h=document.createElement("option");h.value=p,h.textContent=c,t.appendChild(h)}),t.value=r,t.addEventListener("change",()=>n(t.value)),t}function ve(s,r,n){const t=document.createElement("label");t.style.cssText=ue;const p=document.createElement("input");return p.type="checkbox",p.checked=s,p.addEventListener("change",()=>r(p.checked)),t.appendChild(p),t.appendChild(document.createTextNode(n)),{wrap:t,input:p}}function V(s,r){const n=document.createElement("button");n.type="button",n.className="btn btn-ghost btn-sm",n.style.cssText="display:inline-flex;align-items:center;gap:.35rem;";const t=document.createElement("span");return t.setAttribute("data-icon",s),n.appendChild(t),n.appendChild(document.createTextNode(r)),n}function K(s,r){const n=document.createElement("button");n.type="button",n.title=r,n.style.cssText="padding:.25rem .4rem;background:transparent;border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text-muted,#aaa);cursor:pointer;display:inline-flex;align-items:center;";const t=document.createElement("span");return t.setAttribute("data-icon",s),n.appendChild(t),n}function ee(s){for(;s.firstChild;)s.removeChild(s.firstChild)}function we(s){return String(s).replace(/&/g,"&").replace(/"/g,""")}let te=!1;function Ce(){te||(te=!0,I.register("edit-3",{viewBox:"0 0 24 24",paths:["M12 20h9","M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("clock",{viewBox:"0 0 24 24",paths:["M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z","M12 6v6l4 2"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("corner-up-left",{viewBox:"0 0 24 24",paths:["M9 14 4 9l5-5","M20 20v-7a4 4 0 0 0-4-4H4"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("refresh-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M1 20v-6h6","M3.51 9a9 9 0 0 1 14.85-3.36L23 10","M20.49 15a9 9 0 0 1-14.85 3.36L1 14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("rotate-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M20.49 15a9 9 0 1 1-2.12-9.36L23 10"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("code",{viewBox:"0 0 24 24",paths:["M16 18l6-6-6-6","M8 6l-6 6 6 6"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-up",{viewBox:"0 0 24 24",path:"M18 15l-6-6-6 6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-down",{viewBox:"0 0 24 24",path:"M6 9l6 6 6-6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("x",{viewBox:"0 0 24 24",paths:["M18 6L6 18","M6 6l12 12"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}
|
|
1
|
+
import{insertAtCursor as re}from"./markdown-toolbar.js";import{SCRIBE_FIELDS as ae,scribeDefaults as se,scribeLoop as ce,stateToScribeActions as ie,buildScribeShortcode as le}from"./scribe-model.js";const de=20,Q={render:{label:"Render",icon:"edit-3",color:"var(--dm-info,#3b82f6)"},wait:{label:"Wait",icon:"clock",color:"var(--dm-warning,#f59e0b)"},undo:{label:"Undo",icon:"corner-up-left",color:"var(--dm-secondary,#a855f7)"},redraw:{label:"Redraw",icon:"refresh-cw",color:"var(--dm-success,#22c55e)"}},L="padding:.4rem .6rem;background:var(--dm-input-bg,#1a1a1a);border:1px solid var(--dm-border,#333);border-radius:4px;color:var(--dm-text,#eee);font-size:.9em;box-sizing:border-box;width:100%;",pe="display:block;font-size:.7rem;font-weight:600;color:var(--dm-text-muted,#aaa);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.25rem;",me="display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.85em;";export function openScribeComposer(s){const r=ue(),n=[];let t=null,p=null;function c(){clearTimeout(t),p?.destroy(),p=null}const h=E.slideover({title:"Scribe Composer",size:"lg",position:"right",onClose:c});Ce();const b=document.createElement("div");b.className="scribe-composer",b.style.cssText="display:flex;flex-direction:column;height:100%;";const y=document.createElement("div");y.style.cssText="padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);";const k=document.createElement("div");k.style.cssText="min-height:3.5rem;padding:.85rem 1rem;background:var(--dm-surface,#1a1a1a);border:1px dashed var(--dm-border,#333);border-radius:6px;font-size:1.25rem;line-height:1.5;overflow-wrap:normal;word-break:normal;",y.appendChild(k);const B=document.createElement("div");B.style.cssText="display:flex;gap:.5rem;margin-top:.75rem;align-items:center;";const Y=V("rotate-cw","Replay"),q=V("code","Show code"),N=document.createElement("span");N.style.cssText="font-size:.8em;color:var(--dm-text-muted,#aaa);flex:1;text-align:right;margin-right:.5rem;",B.appendChild(Y),B.appendChild(N),B.appendChild(q),y.appendChild(B);const M=document.createElement("pre");M.style.cssText="display:none;margin:.75rem 0 0;padding:.6rem .75rem;background:var(--dm-surface,#0a0a0a);border:1px solid var(--dm-border,#333);border-radius:4px;font-family:monospace;font-size:.78em;white-space:pre-wrap;word-break:break-all;color:var(--dm-text-muted,#bbb);max-height:200px;overflow:auto;",y.appendChild(M),q.addEventListener("click",()=>{const e=M.style.display!=="none";M.style.display=e?"none":"block"}),Y.addEventListener("click",()=>{J(),p?.resume(),p&&(N.textContent="Playing preview")}),b.appendChild(y);const R=document.createElement("div");R.style.cssText="display:flex;flex:1;min-height:0;overflow:hidden;";const F=fe(r,()=>{C(),x()});R.appendChild(F.el);const z=document.createElement("main");z.style.cssText="flex:1;overflow-y:auto;padding:1rem 1.25rem;display:flex;flex-direction:column;";const D=document.createElement("h4");D.textContent="Actions",D.style.cssText="margin:0 0 .75rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",z.appendChild(D);const A=document.createElement("div");A.style.cssText="display:flex;flex-direction:column;gap:.6rem;",z.appendChild(A);const P=document.createElement("div");P.style.cssText="display:flex;gap:.4rem;margin-top:.9rem;flex-wrap:wrap;",Object.entries(Q).forEach(([e,a])=>{const i=document.createElement("button");i.type="button",i.style.cssText=`padding:.4rem .8rem;background:transparent;border:1px dashed color-mix(in srgb, ${a.color} 40%, transparent);border-radius:4px;color:${a.color};cursor:pointer;font-size:.85em;display:inline-flex;align-items:center;gap:.35rem;`;const l=document.createElement("span");l.setAttribute("data-icon",a.icon),i.appendChild(l),i.appendChild(document.createTextNode(` + ${a.label}`)),i.addEventListener("click",()=>{C(),r.actions.push(he(e)),$(),x()}),P.appendChild(i)}),z.appendChild(P),R.appendChild(z),b.appendChild(R);const T=document.createElement("div");T.style.cssText="display:flex;padding:.75rem 1rem;border-top:1px solid var(--dm-border,#333);background:var(--dm-background-alt,#0f0f17);gap:.5rem;align-items:center;";const S=document.createElement("button");S.type="button",S.className="btn btn-ghost btn-sm",S.textContent="Undo (Ctrl+Z)",S.addEventListener("click",()=>H()),T.appendChild(S);const U=document.createElement("span");U.style.cssText="font-size:.75em;color:var(--dm-text-muted,#aaa);",T.appendChild(U);const G=document.createElement("div");G.style.flex="1",T.appendChild(G);const W=document.createElement("button");W.type="button",W.className="btn btn-ghost",W.textContent="Cancel",W.addEventListener("click",()=>h.close()),T.appendChild(W);const j=document.createElement("button");j.type="button",j.className="btn btn-primary",j.textContent="Insert Scribe",j.addEventListener("click",()=>{re(s,Z()),h.close()}),T.appendChild(j),b.appendChild(T),h.setContent(b),b.addEventListener("keydown",e=>{const a=(e.key||"").toLowerCase();(e.ctrlKey||e.metaKey)&&a==="z"&&!e.shiftKey&&n.length>0&&(e.preventDefault(),e.stopPropagation(),H())}),$(),x(),O(),requestAnimationFrame(()=>{Domma.icons.scan()}),h.open();function C(){n.push(JSON.stringify(r)),n.length>de&&n.shift(),O()}function H(){if(n.length===0){E.toast("Nothing to undo",{type:"info",duration:700});return}const e=JSON.parse(n.pop());Object.assign(r.globals,e.globals),r.actions.length=0,e.actions.forEach(a=>r.actions.push(a)),F.sync(),$(),x(),O(),E.toast("Undone",{type:"info",duration:500})}function O(){U.textContent=n.length===0?"":`${n.length} step${n.length===1?"":"s"} stored`,S.disabled=n.length===0,S.style.opacity=n.length===0?".4":"1"}function x(e=150){clearTimeout(t),t=setTimeout(J,e)}function J(){c(),ee(k),k.style.color="",k.style.fontStyle="",M.textContent=Z();const e=r.actions.filter(o=>o.type==="render"||o.type==="redraw"?(o.text||"").length>0:!0);if(e.length===0){k.textContent="(add an action to preview)",k.style.color="var(--dm-text-muted,#666)",k.style.fontStyle="italic",N.textContent="";return}const a=document.createElement("span");a.className="dm-fx-scribe",k.appendChild(a);const i=r.globals,{effect:l,controls:g,...w}=i;w.actions=ie(e,l);try{p=Domma.effects.scribe(a,w),N.textContent=i.autoStart?`${e.length} action${e.length===1?"":"s"}`:"Press Replay to start"}catch{N.textContent="Preview error"}}function $(){if(ee(A),r.actions.length===0){const e=document.createElement("p");e.textContent="No actions yet - add one from the buttons below.",e.style.cssText="font-size:.85em;color:var(--dm-text-muted,#888);font-style:italic;margin:.5rem 0;",A.appendChild(e);return}r.actions.forEach((e,a)=>{A.appendChild(ne(e,a))}),requestAnimationFrame(()=>Domma.icons.scan())}function ne(e,a){const i=Q[e.type],l=document.createElement("div");l.style.cssText=`border:1px solid var(--dm-border,#333);border-left:3px solid ${i.color};border-radius:4px;padding:.6rem .75rem;background:var(--dm-surface,#15151a);`;const g=document.createElement("div");g.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const w=document.createElement("span");w.style.cssText=`display:inline-flex;align-items:center;gap:.3rem;font-size:.72rem;font-weight:700;color:${i.color};text-transform:uppercase;letter-spacing:.06em;`;const o=document.createElement("span");o.setAttribute("data-icon",i.icon),w.appendChild(o),w.appendChild(document.createTextNode(i.label)),g.appendChild(w);const u=document.createElement("span");u.textContent=`#${a+1}`,u.style.cssText="font-size:.7rem;color:var(--dm-text-muted,#888);",g.appendChild(u);const m=document.createElement("div");m.style.flex="1",g.appendChild(m);const d=K("chevron-up","Move up");a===0&&(d.disabled=!0,d.style.opacity=".3"),d.addEventListener("click",()=>X(a,-1)),g.appendChild(d);const f=K("chevron-down","Move down");a===r.actions.length-1&&(f.disabled=!0,f.style.opacity=".3"),f.addEventListener("click",()=>X(a,1)),g.appendChild(f);const v=K("x","Remove");return v.addEventListener("click",()=>{C(),r.actions.splice(a,1),$(),x()}),g.appendChild(v),l.appendChild(g),l.appendChild(oe(e)),l}function X(e,a){const i=e+a;if(i<0||i>=r.actions.length)return;C();const[l]=r.actions.splice(e,1);r.actions.splice(i,0,l),$(),x()}function oe(e){const a=document.createElement("div");if(a.style.cssText="display:flex;flex-direction:column;gap:.5rem;",e.type==="render"||e.type==="redraw"){const o=document.createElement("textarea");o.value=e.text||"",o.placeholder=e.type==="redraw"?"New text - clears everything first, then types this":"Text to type out",o.rows=2,o.style.cssText=L+"resize:vertical;font-family:inherit;min-height:2.2rem;";let u=o.value;o.addEventListener("input",()=>{e.text=o.value,x()}),o.addEventListener("blur",()=>{o.value!==u&&(C(),u=o.value)}),a.appendChild(o);const m=document.createElement("div");m.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8em;";const d=document.createElement("label");d.textContent="Effect:",d.style.color="var(--dm-text-muted,#aaa)";const f=document.createElement("select");return f.style.cssText=L+"width:auto;padding:.25rem .4rem;",["inherit","none","fade","bounce","glow"].forEach(v=>{const _=document.createElement("option");_.value=v,_.textContent=v==="inherit"?"Default effect":v.charAt(0).toUpperCase()+v.slice(1),f.appendChild(_)}),f.value=e.effect||"none",f.addEventListener("change",()=>{C(),e.effect=f.value,x()}),m.appendChild(d),m.appendChild(f),a.appendChild(m),a}if(e.type==="wait"){const o=document.createElement("div");o.style.cssText="display:flex;gap:.4rem;align-items:center;";const u=document.createElement("input");u.type="number",u.min="0",u.step="any",u.value=String(e.duration??1e3),u.style.cssText=L+"flex:1;",u.addEventListener("input",()=>{const d=Number(u.value);!Number.isNaN(d)&&d>=0&&(e.duration=d,x())}),u.addEventListener("blur",()=>C()),o.appendChild(u);const m=document.createElement("select");return m.style.cssText=L+"width:auto;",[["ms","ms"],["s","seconds"]].forEach(([d,f])=>{const v=document.createElement("option");v.value=d,v.textContent=f,m.appendChild(v)}),m.value=e.unit||"ms",m.addEventListener("change",()=>{C(),e.unit=m.value,x()}),o.appendChild(m),a.appendChild(o),a}const i=document.createElement("div");i.style.cssText="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap;font-size:.85em;";const l=document.createElement("input");l.type="number",l.min="1",l.value=String(e.count||5),l.style.cssText=L+"width:5rem;",l.addEventListener("input",()=>{const o=parseInt(l.value,10);!Number.isNaN(o)&&o>0&&(e.count=o,x())}),l.addEventListener("blur",()=>C());const g=`undo-mode-${Math.random().toString(36).slice(2)}`;return[["last","Last render"],["all","All text"],["count","Exactly N units"]].forEach(([o,u])=>{const m=document.createElement("label");m.style.cssText="display:inline-flex;align-items:center;gap:.3rem;cursor:pointer;";const d=document.createElement("input");d.type="radio",d.name=g,d.value=o,d.checked=(e.mode||"last")===o,d.addEventListener("change",()=>{d.checked&&(C(),e.mode=o,l.style.display=o==="count"?"":"none",x())}),m.appendChild(d),m.appendChild(document.createTextNode(u)),i.appendChild(m),o==="count"&&(i.appendChild(l),l.style.display=(e.mode||"last")==="count"?"":"none")}),a.appendChild(i),a}function Z(){return le(r.globals,r.actions)}}function ue(){return{globals:se(),actions:[{type:"render",text:"We build things that matter.",effect:"inherit"},{type:"wait",duration:1500,unit:"ms"},{type:"redraw",text:"We create solutions that last.",effect:"inherit"},{type:"wait",duration:1500,unit:"ms"}]}}function he(s){switch(s){case"render":return{type:"render",text:"",effect:"inherit"};case"wait":return{type:"wait",duration:1e3,unit:"ms"};case"undo":return{type:"undo",mode:"last",count:5};case"redraw":return{type:"redraw",text:"",effect:"inherit"}}return{type:"render",text:"",effect:"inherit"}}function fe(s,r){const n=document.createElement("aside");n.style.cssText="width:240px;flex-shrink:0;padding:1rem 1.25rem;border-right:1px solid var(--dm-border,#333);overflow-y:auto;display:flex;flex-direction:column;gap:.75rem;background:var(--dm-background-alt,#0c0c12);";const t=document.createElement("h4");t.textContent="Global settings",t.style.cssText="margin:0 0 .25rem;font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--dm-text-muted,#aaa);",n.appendChild(t);const p=ae.map(c=>{const h=y=>{r(),s.globals[c.key]=c.key==="loop"?ce(y):y};let b;if(c.type==="checkbox"){const y=ve(s.globals[c.key],h,c.label);n.appendChild(y.wrap),b=y.input}else b=c.type==="select"?ge(c.options,s.globals[c.key],h):c.type==="number"?xe(s.globals[c.key],h,c.min):ye(s.globals[c.key],"",h),n.appendChild(be(c.label,b));return{field:c,input:b}});return{el:n,sync(){p.forEach(({field:c,input:h})=>{c.type==="checkbox"?h.checked=s.globals[c.key]:h.value=String(s.globals[c.key])})}}}function be(s,r){const n=document.createElement("div"),t=document.createElement("label");return t.style.cssText=pe,t.textContent=s,n.appendChild(t),n.appendChild(r),n}function xe(s,r,n=1){const t=document.createElement("input");return t.type="number",t.min=String(n),t.value=String(s),t.style.cssText=L,t.addEventListener("input",()=>{const p=Number(t.value);!Number.isNaN(p)&&p>=n&&r(p)}),t}function ye(s,r,n){const t=document.createElement("input");return t.type="text",t.value=s,t.placeholder=r,t.style.cssText=L,t.addEventListener("input",()=>n(t.value)),t}function ge(s,r,n){const t=document.createElement("select");return t.style.cssText=L,s.forEach(([p,c])=>{const h=document.createElement("option");h.value=p,h.textContent=c,t.appendChild(h)}),t.value=r,t.addEventListener("change",()=>n(t.value)),t}function ve(s,r,n){const t=document.createElement("label");t.style.cssText=me;const p=document.createElement("input");return p.type="checkbox",p.checked=s,p.addEventListener("change",()=>r(p.checked)),t.appendChild(p),t.appendChild(document.createTextNode(n)),{wrap:t,input:p}}function V(s,r){const n=document.createElement("button");n.type="button",n.className="btn btn-ghost btn-sm",n.style.cssText="display:inline-flex;align-items:center;gap:.35rem;";const t=document.createElement("span");return t.setAttribute("data-icon",s),n.appendChild(t),n.appendChild(document.createTextNode(r)),n}function K(s,r){const n=document.createElement("button");n.type="button",n.title=r,n.style.cssText="padding:.25rem .4rem;background:transparent;border:1px solid var(--dm-border,#333);border-radius:3px;color:var(--dm-text-muted,#aaa);cursor:pointer;display:inline-flex;align-items:center;";const t=document.createElement("span");return t.setAttribute("data-icon",s),n.appendChild(t),n}function ee(s){for(;s.firstChild;)s.removeChild(s.firstChild)}function we(s){return String(s).replace(/&/g,"&").replace(/"/g,""")}let te=!1;function Ce(){te||(te=!0,I.register("edit-3",{viewBox:"0 0 24 24",paths:["M12 20h9","M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5z"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("clock",{viewBox:"0 0 24 24",paths:["M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z","M12 6v6l4 2"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("corner-up-left",{viewBox:"0 0 24 24",paths:["M9 14 4 9l5-5","M20 20v-7a4 4 0 0 0-4-4H4"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("refresh-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M1 20v-6h6","M3.51 9a9 9 0 0 1 14.85-3.36L23 10","M20.49 15a9 9 0 0 1-14.85 3.36L1 14"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("rotate-cw",{viewBox:"0 0 24 24",paths:["M23 4v6h-6","M20.49 15a9 9 0 1 1-2.12-9.36L23 10"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("code",{viewBox:"0 0 24 24",paths:["M16 18l6-6-6-6","M8 6l-6 6 6 6"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-up",{viewBox:"0 0 24 24",path:"M18 15l-6-6-6 6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("chevron-down",{viewBox:"0 0 24 24",path:"M6 9l6 6 6-6",stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}),I.register("x",{viewBox:"0 0 24 24",paths:["M18 6L6 18","M6 6l12 12"],stroke:"currentColor",fill:"none",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"}))}
|
|
@@ -134,6 +134,9 @@ Step 3: email to={{entry.data.email}}
|
|
|
134
134
|
lets holders of either run it, and everyone more senior than either - the same ladder as
|
|
135
135
|
page visibility. All the roles a user holds count, not just their primary one.</li>
|
|
136
136
|
<li><strong>No roles ticked</strong> - admins only (role levels 0 and 1).</li>
|
|
137
|
+
<li><strong>The same in the admin.</strong> The ⚡ menu on a collection's entries offers only the
|
|
138
|
+
actions you may run, and running one checks these roles too - being able to edit actions is
|
|
139
|
+
not the same as being allowed to run every one.</li>
|
|
137
140
|
<li><strong>A role the site does not have</strong> (deleted or renamed) admits only the level-0
|
|
138
141
|
role. The editor keeps it and flags it so you can fix it.</li>
|
|
139
142
|
<li><strong>Row-level rule</strong> - Owner (entries the user created) or Field match (entries
|
|
@@ -4,7 +4,7 @@ import{api as g,apiRequest as it}from"../api.js";import{addBannerAction as z}fro
|
|
|
4
4
|
${Array.from({length:m},(v,a)=>`<td data-col="${a}" title="{{t${a}}}">{{c${a}}}</td>`).join("")}
|
|
5
5
|
<td class="cex-when" title="{{whenFull}}">{{when}}</td>
|
|
6
6
|
<td class="cex-tools"><button type="button" class="cex-run" data-bind-hidden="!runs" title="Run one of this collection's actions">\u26A1 {{runs}}</button><button type="button" class="cex-kebab" aria-label="Actions for this entry" title="Actions">\u22EE</button></td>
|
|
7
|
-
</tr>`}function Ct(m,h){const v={};return m.forEach(a=>{const i={};a.fullWidth?i.span=h:a.span>1&&(i.span=a.span),a.placeholder&&(i.placeholder=a.placeholder),a.helper&&(i.hint=a.helper),a.prefix&&(i.prefix=a.prefix),a.suffix&&(i.suffix=a.suffix);for(const d of["clear","stepper","counter"])a[d]===!0&&(i[d]=!0);const r=a.type==="checkbox"?"boolean":a.type==="date"?"string":a.type;v[a.name]={type:r,label:a.label,required:a.required,options:a.options,...Object.keys(i).length?{formConfig:i}:{}}}),v}function le(m,h){const v={};for(const a of h){const i=[...m.querySelectorAll(`[name="${CSS.escape(a.name)}"]`)];if(!i.length)continue;const r=i[0];r.type==="radio"?v[a.name]=i.find(d=>d.checked)?.value??"":r.type==="checkbox"&&i.length>1?v[a.name]=i.filter(d=>d.checked).map(d=>d.value):r.type==="checkbox"?v[a.name]=r.checked:r.tagName==="SELECT"&&r.multiple?v[a.name]=[...r.selectedOptions].map(d=>d.value):v[a.name]=kt(a,r.value)}return v}function Fe(m,h,v){for(const a of h){if(!(a.name in v))continue;const i=v[a.name],r=[...m.querySelectorAll(`[name="${CSS.escape(a.name)}"]`)];if(!r.length)continue;const d=r[0];d.type==="radio"?r.forEach(l=>{l.checked=l.value===String(i)}):d.type==="checkbox"&&r.length>1?r.forEach(l=>{l.checked=Array.isArray(i)&&i.includes(l.value)}):d.type==="checkbox"?d.checked=i===!0:d.tagName==="SELECT"&&d.multiple?[...d.options].forEach(l=>{l.selected=Array.isArray(i)&&i.includes(l.value)}):d.value=i??"",r.forEach(l=>l.dispatchEvent(new Event("input",{bubbles:!0})))}}const _e=pt(Be);export const collectionEntriesView={templateUrl:"/admin/js/templates/collection-entries.html",async onMount(m){_e.reset();const h=m.get(0).querySelector(".cex")||m.get(0),v=location.hash.match(/^#\/collections\/([^/?#]+)\/entries/),a=v?decodeURIComponent(v[1]):null,i=()=>Be.test(location.hash)&&h.isConnected&&location.hash.includes(`/collections/${encodeURIComponent(a)}/entries`),r=e=>(_e.add(e),e);if(!a){E.toast("No collection selected.",{type:"error"});return}const d=M.observable(null),l=M.observable([]),x=M.observable(0),Y=M.observable(!0),_=M.observable(""),He=M.computed(()=>d.value!==null),ie=M.observable(""),w=M.observable([]),Z=M.observable({key:"created",dir:"desc"}),y=M.observable([]),q=M.observable(X),H=M.observable([]),Q=M.observable({}),A=M.observable(!1);let ee=1;const re=()=>d.peek()?.fields||[],de=M.computed(()=>(d.value?.fields||[]).slice(0,ft)),J=e=>l.peek().find(t=>t.id===e),ve=e=>H.peek().filter(t=>{const n=Q.peek()[t.slug];return n==null||n.has(e)}),T=M.observable([]),be=M.observable([]);r(M.effect(()=>{const e=mt(l.value,{filters:w.value,query:ie.value,sort:Z.value});T.value=e})),r(M.effect(()=>{const e=de.value,t=new Set(y.value);Q.value,H.value,be.value=T.value.slice(0,q.value).map(n=>{const s={id:n.id,sel:t.has(n.id),rowCls:t.has(n.id)?"is-selected":""};e.forEach((c,u)=>{const f=ye(c,n.data?.[c.name]);s[`c${u}`]=ze(f),s[`t${u}`]=Pe(f)});const o=n.meta?.createdAt;s.when=o?xt(o):"",s.whenFull=o?`Created ${P(o)}${n.meta?.updatedAt?` \xB7 changed ${P(n.meta.updatedAt)}`:""}`:"";const p=ve(n.id).length;return s.runs=p?String(p):"",s})}));const Je=M.computed(()=>w.value.map((e,t)=>({key:`${t}:${e.field}:${e.op}:${e.value}`,idx:t,text:gt(e)}))),Ve=M.computed(()=>y.value.length),Ke={schema:d,loaded:l,loading:Y,loadError:_,ready:He,query:ie,rows:be,chips:Je,busy:A,selectedCount:Ve,countLine:M.computed(()=>yt(T.value.length,l.value.length,x.value)),selectedText:M.computed(()=>`${y.value.length} selected`),canClear:M.computed(()=>ht(a)),introText:M.computed(()=>{const e=d.value;return e?`${e.description?`${e.description} - `:""}${(e.fields||[]).length} field${(e.fields||[]).length===1?"":"s"}${e.storage?.adapter==="mongodb"?", on MongoDB":""}.`:""}),emptyText:M.computed(()=>l.value.length?"No entries match the search or filters.":"No entries yet - Add entry in the banner makes one, or Import brings many."),moreText:M.computed(()=>{const e=T.value.length-q.value;if(e>0)return`Show ${Math.min(X,e)} more (${e} not shown)`;const t=x.value-l.value.length;return t>0?`Load the next ${Math.min(oe,t)} from the server`:""})};async function V({reset:e=!0,pending:t=null}={}){Y.value=!0;try{const n=e?Math.max(oe,l.peek().length):oe;e&&(ee=1);const s=await g.collections.listEntries(a,{limit:n,page:ee});if(t&&await t.done(),!i())return;const o=s?.entries||(Array.isArray(s)?s:[]);l.value=e?o:[...l.peek(),...o.filter(c=>!J(c.id))],x.value=Number(s?.total)||l.peek().length,e&&(ee=Math.max(1,Math.ceil(l.peek().length/oe)));const p=new Set(l.peek().map(c=>c.id));y.value=y.peek().filter(c=>p.has(c)),_.value="",await Xe()}catch(n){_.value=`Could not load the entries: ${n.message||n}`}finally{t&&await t.done(),Y.value=!1}}async function Ge(){ee+=1,await V({reset:!1})}async function We(){try{if((await it("/actions/_count",{method:"GET"}).catch(()=>null))?.available===!1)return;const t=await g.actions.forCollection(a);H.value=Array.isArray(t)?t:[]}catch{H.value=[]}}async function Xe(){const e=H.peek().filter(s=>s.access?.rowLevel);if(!e.length||!l.peek().length)return;const t=l.peek().map(s=>s.id),n={...Q.peek()};await Promise.all(e.map(async s=>{try{n[s.slug]=new Set((await g.actions.checkAccess(s.slug,t)).allowed)}catch{n[s.slug]=null}})),Q.value=n}const K=e=>{const t=re()[0];return(t?ze(ye(t,e?.data?.[t.name]),40):"")||`Entry ${String(e?.id||"").slice(0,8)}`};async function ge(e){if(await E.confirm(`Delete \u201C${D(K(e))}\u201D? This cannot be undone.`))try{await g.collections.deleteEntry(a,e.id),l.value=l.peek().filter(t=>t.id!==e.id),x.value=Math.max(0,x.peek()-1),y.value=y.peek().filter(t=>t!==e.id),j("#/collections"),E.toast("Entry deleted.",{type:"success"})}catch(t){E.toast(`Not deleted: ${t.message||t}`,{type:"error"})}}async function Ye(){const e=[...y.peek()];if(!e.length||!await E.confirm(`Delete ${e.length} entr${e.length===1?"y":"ies"}? This cannot be undone.`))return;A.value=!0;let t=0;const n=[];for(const s of e)try{await g.collections.deleteEntry(a,s),t++}catch(o){n.push(o.message||String(o))}A.value=!1,y.value=[],j("#/collections"),E.toast(n.length?`Deleted ${t}; ${n.length} refused (${n[0]}).`:`Deleted ${t} entr${t===1?"y":"ies"}.`,{type:n.length?"warning":"success",duration:n.length?7e3:4e3}),i()&&await V()}async function Ze(){const e=d.peek();if(await E.confirm(`Delete ALL ${x.peek()} entries in \u201C${D(e?.title||a)}\u201D? This cannot be undone.`)){A.value=!0;try{await g.collections.clearEntries(a),l.value=[],x.value=0,y.value=[],j("#/collections"),E.toast("All entries deleted.",{type:"success"})}catch(t){E.toast(`Not cleared: ${t.message||t}`,{type:"error"})}finally{A.value=!1}}}async function Qe(e){try{const t=await g.collections.createEntry(a,{...e.data||{}});l.value=[t,...l.peek()],x.value=x.peek()+1,j("#/collections"),E.toast("Duplicated - the copy is at the top.",{type:"success"})}catch(t){E.toast(`Not duplicated: ${t.message||t}`,{type:"error"})}}async function et(e,t){const n=e.trigger?.confirmMessage;if(!(n&&!await E.confirm(D(n)))){A.value=!0;try{const s=await g.actions.execute(e.slug,t.id);if(s?.success){const o=s.stepsCompleted??0;E.toast(`${e.trigger?.label||e.title||"Action"} done (${o} step${o===1?"":"s"}).`,{type:"success"}),i()&&await V()}else E.toast(s?.results?.find(o=>!o.success)?.error||"The action failed.",{type:"error"})}catch(s){E.toast(s.message||"The action failed.",{type:"error"})}finally{A.value=!1}}}async function Ee(e){try{await navigator.clipboard.writeText(e),E.toast("Copied.",{type:"success",duration:1500})}catch{E.toast("Copy failed - your browser refused the clipboard.",{type:"error"})}}function ue(e){const t=y.peek();y.value=t.includes(e)?t.filter(n=>n!==e):[...t,e]}function ke(e,t,n){w.value=[...w.peek(),{field:e.name,label:e.label||e.name,op:t,value:n}],q.value=X}const pe=new Set;let N=null,xe=!1;function we(e,t,n){const s=e.close.bind(e);let o=!1,p=!1;e.close=async c=>{if(!o&&c!==!0&&!xe&&t()){if(p)return;p=!0;const u=await E.confirm(n);if(p=!1,!u)return}return o=!0,s()}}function te(e,t=()=>{}){pe.add(e),ut(e,()=>{pe.delete(e),t()})}function O(e,t=null){const n=d.peek(),s=re(),o=!!e,p=E.slideover({title:o?`Edit ${D(K(e))}`:"New entry",size:"md",position:"right"}),c=ce(`
|
|
7
|
+
</tr>`}function Ct(m,h){const v={};return m.forEach(a=>{const i={};a.fullWidth?i.span=h:a.span>1&&(i.span=a.span),a.placeholder&&(i.placeholder=a.placeholder),a.helper&&(i.hint=a.helper),a.prefix&&(i.prefix=a.prefix),a.suffix&&(i.suffix=a.suffix);for(const d of["clear","stepper","counter"])a[d]===!0&&(i[d]=!0);const r=a.type==="checkbox"?"boolean":a.type==="date"?"string":a.type;v[a.name]={type:r,label:a.label,required:a.required,options:a.options,...Object.keys(i).length?{formConfig:i}:{}}}),v}function le(m,h){const v={};for(const a of h){const i=[...m.querySelectorAll(`[name="${CSS.escape(a.name)}"]`)];if(!i.length)continue;const r=i[0];r.type==="radio"?v[a.name]=i.find(d=>d.checked)?.value??"":r.type==="checkbox"&&i.length>1?v[a.name]=i.filter(d=>d.checked).map(d=>d.value):r.type==="checkbox"?v[a.name]=r.checked:r.tagName==="SELECT"&&r.multiple?v[a.name]=[...r.selectedOptions].map(d=>d.value):v[a.name]=kt(a,r.value)}return v}function Fe(m,h,v){for(const a of h){if(!(a.name in v))continue;const i=v[a.name],r=[...m.querySelectorAll(`[name="${CSS.escape(a.name)}"]`)];if(!r.length)continue;const d=r[0];d.type==="radio"?r.forEach(l=>{l.checked=l.value===String(i)}):d.type==="checkbox"&&r.length>1?r.forEach(l=>{l.checked=Array.isArray(i)&&i.includes(l.value)}):d.type==="checkbox"?d.checked=i===!0:d.tagName==="SELECT"&&d.multiple?[...d.options].forEach(l=>{l.selected=Array.isArray(i)&&i.includes(l.value)}):d.value=i??"",r.forEach(l=>l.dispatchEvent(new Event("input",{bubbles:!0})))}}const _e=pt(Be);export const collectionEntriesView={templateUrl:"/admin/js/templates/collection-entries.html",async onMount(m){_e.reset();const h=m.get(0).querySelector(".cex")||m.get(0),v=location.hash.match(/^#\/collections\/([^/?#]+)\/entries/),a=v?decodeURIComponent(v[1]):null,i=()=>Be.test(location.hash)&&h.isConnected&&location.hash.includes(`/collections/${encodeURIComponent(a)}/entries`),r=e=>(_e.add(e),e);if(!a){E.toast("No collection selected.",{type:"error"});return}const d=M.observable(null),l=M.observable([]),x=M.observable(0),Y=M.observable(!0),_=M.observable(""),He=M.computed(()=>d.value!==null),ie=M.observable(""),w=M.observable([]),Z=M.observable({key:"created",dir:"desc"}),y=M.observable([]),q=M.observable(X),H=M.observable([]),Q=M.observable({}),A=M.observable(!1);let ee=1;const re=()=>d.peek()?.fields||[],de=M.computed(()=>(d.value?.fields||[]).slice(0,ft)),J=e=>l.peek().find(t=>t.id===e),ve=e=>H.peek().filter(t=>{const n=Q.peek()[t.slug];return n==null||n.has(e)}),T=M.observable([]),be=M.observable([]);r(M.effect(()=>{const e=mt(l.value,{filters:w.value,query:ie.value,sort:Z.value});T.value=e})),r(M.effect(()=>{const e=de.value,t=new Set(y.value);Q.value,H.value,be.value=T.value.slice(0,q.value).map(n=>{const s={id:n.id,sel:t.has(n.id),rowCls:t.has(n.id)?"is-selected":""};e.forEach((c,u)=>{const f=ye(c,n.data?.[c.name]);s[`c${u}`]=ze(f),s[`t${u}`]=Pe(f)});const o=n.meta?.createdAt;s.when=o?xt(o):"",s.whenFull=o?`Created ${P(o)}${n.meta?.updatedAt?` \xB7 changed ${P(n.meta.updatedAt)}`:""}`:"";const p=ve(n.id).length;return s.runs=p?String(p):"",s})}));const Je=M.computed(()=>w.value.map((e,t)=>({key:`${t}:${e.field}:${e.op}:${e.value}`,idx:t,text:gt(e)}))),Ve=M.computed(()=>y.value.length),Ke={schema:d,loaded:l,loading:Y,loadError:_,ready:He,query:ie,rows:be,chips:Je,busy:A,selectedCount:Ve,countLine:M.computed(()=>yt(T.value.length,l.value.length,x.value)),selectedText:M.computed(()=>`${y.value.length} selected`),canClear:M.computed(()=>ht(a)),introText:M.computed(()=>{const e=d.value;return e?`${e.description?`${e.description} - `:""}${(e.fields||[]).length} field${(e.fields||[]).length===1?"":"s"}${e.storage?.adapter==="mongodb"?", on MongoDB":""}.`:""}),emptyText:M.computed(()=>l.value.length?"No entries match the search or filters.":"No entries yet - Add entry in the banner makes one, or Import brings many."),moreText:M.computed(()=>{const e=T.value.length-q.value;if(e>0)return`Show ${Math.min(X,e)} more (${e} not shown)`;const t=x.value-l.value.length;return t>0?`Load the next ${Math.min(oe,t)} from the server`:""})};async function V({reset:e=!0,pending:t=null}={}){Y.value=!0;try{const n=e?Math.max(oe,l.peek().length):oe;e&&(ee=1);const s=await g.collections.listEntries(a,{limit:n,page:ee});if(t&&await t.done(),!i())return;const o=s?.entries||(Array.isArray(s)?s:[]);l.value=e?o:[...l.peek(),...o.filter(c=>!J(c.id))],x.value=Number(s?.total)||l.peek().length,e&&(ee=Math.max(1,Math.ceil(l.peek().length/oe)));const p=new Set(l.peek().map(c=>c.id));y.value=y.peek().filter(c=>p.has(c)),_.value="",await Xe()}catch(n){_.value=`Could not load the entries: ${n.message||n}`}finally{t&&await t.done(),Y.value=!1}}async function Ge(){ee+=1,await V({reset:!1})}async function We(){try{if((await it("/actions/_count",{method:"GET"}).catch(()=>null))?.available===!1)return;const t=await g.actions.forCollection(a);H.value=Array.isArray(t)?t.filter(n=>n.canRun!==!1):[]}catch{H.value=[]}}async function Xe(){const e=H.peek().filter(s=>s.access?.rowLevel);if(!e.length||!l.peek().length)return;const t=l.peek().map(s=>s.id),n={...Q.peek()};await Promise.all(e.map(async s=>{try{n[s.slug]=new Set((await g.actions.checkAccess(s.slug,t)).allowed)}catch{n[s.slug]=null}})),Q.value=n}const K=e=>{const t=re()[0];return(t?ze(ye(t,e?.data?.[t.name]),40):"")||`Entry ${String(e?.id||"").slice(0,8)}`};async function ge(e){if(await E.confirm(`Delete \u201C${D(K(e))}\u201D? This cannot be undone.`))try{await g.collections.deleteEntry(a,e.id),l.value=l.peek().filter(t=>t.id!==e.id),x.value=Math.max(0,x.peek()-1),y.value=y.peek().filter(t=>t!==e.id),j("#/collections"),E.toast("Entry deleted.",{type:"success"})}catch(t){E.toast(`Not deleted: ${t.message||t}`,{type:"error"})}}async function Ye(){const e=[...y.peek()];if(!e.length||!await E.confirm(`Delete ${e.length} entr${e.length===1?"y":"ies"}? This cannot be undone.`))return;A.value=!0;let t=0;const n=[];for(const s of e)try{await g.collections.deleteEntry(a,s),t++}catch(o){n.push(o.message||String(o))}A.value=!1,y.value=[],j("#/collections"),E.toast(n.length?`Deleted ${t}; ${n.length} refused (${n[0]}).`:`Deleted ${t} entr${t===1?"y":"ies"}.`,{type:n.length?"warning":"success",duration:n.length?7e3:4e3}),i()&&await V()}async function Ze(){const e=d.peek();if(await E.confirm(`Delete ALL ${x.peek()} entries in \u201C${D(e?.title||a)}\u201D? This cannot be undone.`)){A.value=!0;try{await g.collections.clearEntries(a),l.value=[],x.value=0,y.value=[],j("#/collections"),E.toast("All entries deleted.",{type:"success"})}catch(t){E.toast(`Not cleared: ${t.message||t}`,{type:"error"})}finally{A.value=!1}}}async function Qe(e){try{const t=await g.collections.createEntry(a,{...e.data||{}});l.value=[t,...l.peek()],x.value=x.peek()+1,j("#/collections"),E.toast("Duplicated - the copy is at the top.",{type:"success"})}catch(t){E.toast(`Not duplicated: ${t.message||t}`,{type:"error"})}}async function et(e,t){const n=e.trigger?.confirmMessage;if(!(n&&!await E.confirm(D(n)))){A.value=!0;try{const s=await g.actions.execute(e.slug,t.id);if(s?.success){const o=s.stepsCompleted??0;E.toast(`${e.trigger?.label||e.title||"Action"} done (${o} step${o===1?"":"s"}).`,{type:"success"}),i()&&await V()}else E.toast(s?.results?.find(o=>!o.success)?.error||"The action failed.",{type:"error"})}catch(s){E.toast(s.message||"The action failed.",{type:"error"})}finally{A.value=!1}}}async function Ee(e){try{await navigator.clipboard.writeText(e),E.toast("Copied.",{type:"success",duration:1500})}catch{E.toast("Copy failed - your browser refused the clipboard.",{type:"error"})}}function ue(e){const t=y.peek();y.value=t.includes(e)?t.filter(n=>n!==e):[...t,e]}function ke(e,t,n){w.value=[...w.peek(),{field:e.name,label:e.label||e.name,op:t,value:n}],q.value=X}const pe=new Set;let N=null,xe=!1;function we(e,t,n){const s=e.close.bind(e);let o=!1,p=!1;e.close=async c=>{if(!o&&c!==!0&&!xe&&t()){if(p)return;p=!0;const u=await E.confirm(n);if(p=!1,!u)return}return o=!0,s()}}function te(e,t=()=>{}){pe.add(e),ut(e,()=>{pe.delete(e),t()})}function O(e,t=null){const n=d.peek(),s=re(),o=!!e,p=E.slideover({title:o?`Edit ${D(K(e))}`:"New entry",size:"md",position:"right"}),c=ce(`
|
|
8
8
|
<div class="cex-form">
|
|
9
9
|
<div class="cex-fields"></div>
|
|
10
10
|
<small class="cex-hint cex-when-line"></small>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "domma-cms",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.21",
|
|
4
4
|
"description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "server/server.js",
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
"@fastify/rate-limit": "^10.3.0",
|
|
85
85
|
"@fastify/static": "9.1.1",
|
|
86
86
|
"bcryptjs": "^3.0.3",
|
|
87
|
-
"domma-js": "0.51.
|
|
87
|
+
"domma-js": "0.51.11",
|
|
88
88
|
"dotenv": "^17.2.3",
|
|
89
89
|
"fastify": "5.8.5",
|
|
90
90
|
"gray-matter": "^4.0.3",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{decodeBase64Json as
|
|
1
|
+
import{decodeBase64Json as T}from"/public/js/utf8-base64.mjs";(function(){"use strict";const f=window.__CMS_CTXMENUS__;if(!Array.isArray(f)||!f.length||typeof Domma>"u"||!Domma.elements||!Domma.elements.contextMenu)return;const s=(e,t)=>{typeof E<"u"&&E.toast&&E.toast(e,{type:t||"info"})},p=".site-search-trigger, .site-search-floating-trigger";function h(e){return e&&e.closest?e.closest("[data-ctx], [data-collection-table]"):null}function l(e){if(!e||!e.closest)return null;const t=e.closest('input, textarea, [contenteditable=""], [contenteditable="true"]');return!t||t.disabled||t.readOnly||t.tagName==="INPUT"&&!/^(text|search|url|tel|email|password|number)$/i.test(t.type)?null:t}function d(e){const t=l(e);if(t&&typeof t.selectionStart=="number")return t.value.slice(t.selectionStart,t.selectionEnd);const n=window.getSelection();return n?n.toString():""}function g(){try{const e=performance.getEntriesByType("navigation")[0];return!!e&&e.type==="back_forward"}catch{return!1}}function m(e,t){const n=e.selectionStart,r=e.selectionEnd;e.value=e.value.slice(0,n)+t+e.value.slice(r);const o=n+t.length;e.setSelectionRange(o,o),e.dispatchEvent(new Event("input",{bubbles:!0}))}const u={reload:{run:()=>window.location.reload()},back:{run:()=>window.history.back(),disabled:()=>window.history.length<=1},forward:{run:()=>window.history.forward(),disabled:()=>!g()},print:{run:()=>window.print()},copy:{run:async e=>{const t=d(e);if(t)try{await navigator.clipboard.writeText(t)}catch{s("Your browser would not let the page copy","error")}},disabled:e=>!d(e)},cut:{run:async e=>{const t=l(e);if(!t)return;const n=d(e);if(n)try{await navigator.clipboard.writeText(n),m(t,"")}catch{s("Your browser would not let the page cut","error")}},disabled:e=>!l(e)||!d(e)},paste:{run:async e=>{const t=l(e);if(t)try{const n=await navigator.clipboard.readText();n&&m(t,n)}catch{s("Your browser blocks paste from a menu - use Ctrl+V","warning")}},disabled:e=>!l(e)},"site-search":{run:()=>{if(window.DommaSiteSearch&&window.DommaSiteSearch.open){window.DommaSiteSearch.open();return}const e=document.querySelector(p);if(e){e.click();return}s("Site search is not available on this site","warning")},disabled:()=>!window.DommaSiteSearch&&!document.querySelector(p)},"select-all":{run:e=>{const t=l(e);if(t){t.select();return}const n=e&&e.closest&&e.closest("[data-ctx], .page-body")||document.body,r=document.createRange();r.selectNodeContents(n);const o=window.getSelection();o.removeAllRanges(),o.addRange(r)}}};function S(e){if(!e||!e.type)return null;if(u[e.type])return u[e.type].run;switch(e.type){case"navigate":return e.url?()=>{window.location.href=e.url}:null;case"copy-link":return async()=>{try{await navigator.clipboard.writeText(window.location.href),s("Link copied","success")}catch{s("Could not copy the link","error")}};case"run-action":return e.slug?async t=>{const n=t&&t.closest?t.closest("[data-entry-id]"):null,r=n&&n.dataset?n.dataset.entryId:"";if(!r){s("Right-click an entry to run this","error");return}const o=window.S;let a=o?o.get("auth_token"):null;if(!a){s("Please sign in to do that","warning");return}const i=c=>fetch(`/api/actions/${encodeURIComponent(e.slug)}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${c}`},body:JSON.stringify({entryId:r})});try{let c=await i(a);if(c.status===401&&o&&o.get("auth_refresh_token")){const b=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:o.get("auth_refresh_token")})});b.ok&&(a=(await b.json()).token,o.set("auth_token",a),c=await i(a))}if(c.status===401){s("Please sign in to do that","warning");return}if(c.status===403){s("You do not have permission to do that","error");return}const y=await c.json().catch(()=>({}));if(!c.ok||y.success===!1)throw new Error(y.error||`HTTP ${c.status}`);s("Done","success")}catch(c){s(c.message||"That did not work","error")}}:null;case"mark-as-spam":return async t=>{const n=t&&t.closest?t.closest("[data-entry-id]"):null,r=n&&n.dataset?n.dataset.entryId:"",o=t&&t.closest?t.closest("[data-ctx]"):null;let a="";try{o&&o.dataset.ctx&&(a=(T(o.dataset.ctx)||{}).slug||"")}catch{}if(!r||!a){s("Right-click an entry in a collection display to mark it","error");return}try{const i=await fetch(`/api/collections/${encodeURIComponent(a)}/entries/${encodeURIComponent(r)}/spam`,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"same-origin",body:JSON.stringify({field:e.field||void 0})});if(i.status===401||i.status===403){s("You do not have permission to do that","error");return}if(!i.ok)throw new Error(`HTTP ${i.status}`);s("Marked as spam","success"),n&&n.setAttribute("data-spam","true")}catch(i){s(`Could not mark as spam: ${i.message}`,"error")}};case"open-modal":return e.block?async()=>{try{const t=await fetch(`/api/blocks/${encodeURIComponent(e.block)}/render`);if(!t.ok)throw new Error(`HTTP ${t.status}`);const{html:n}=await t.json(),r=E.modal({title:e.title||"",closeOnBackdrop:!0}),o=document.createElement("div");o.innerHTML=typeof DOMPurify<"u"?DOMPurify.sanitize(n):n,r.element.appendChild(o),r.open()}catch(t){s(`Could not open: ${t.message}`,"error")}}:null;case"search":return t=>{const n=h(t);n&&n.dispatchEvent(new MouseEvent("contextmenu",{bubbles:!0,cancelable:!0,clientX:0,clientY:0}))};case"filter":case"sort":case"export":return t=>{const n=h(t);n&&n.dispatchEvent(new CustomEvent("dm-ctx-request",{bubbles:!0,detail:{...e}}))};default:return null}}const k=new Set(["search","filter","sort","export"]);function x(e){return u[e]&&u[e].disabled?u[e].disabled:k.has(e)?t=>!h(t):null}function w(e){const t=[];for(const n of e||[]){const r=n.type||"item";if(r==="divider"){t.push({type:"divider"});continue}if(r==="header"){t.push({type:"header",header:n.text||""});continue}if(Array.isArray(n.submenu)&&n.submenu.length){const i=w(n.submenu);i.length&&t.push({label:n.text,icon:n.icon,danger:!!n.danger,className:n.class||void 0,submenu:i});continue}const o=S(n.action);if(!o)continue;const a=x(n.action&&n.action.type);t.push({label:n.text,icon:n.icon||void 0,danger:!!n.danger,className:n.class||void 0,shortcut:n.shortcut||void 0,...a?{disabled:a}:{},action:o})}return t.some(n=>n.label)?t:[]}for(const e of f){const t=w(e.items);if(!t.length)continue;const n=e.target||{};if(!n.selector)continue;const r=e.theme||{};try{Domma.elements.contextMenu(n.selector,{cursor:"glyph",match:n.match||null,exclude:n.exclude||null,inherit:e.inherit===void 0?"append":e.inherit,priority:e.priority||0,items:t,accent:r.accent,surface:r.surface,radius:r.radius,shadow:r.shadow,opacity:r.opacity,density:r.density,transition:r.transition,ariaLabel:e.name||"Context menu",className:e.class||""})}catch(o){console.warn(`[context-menus] Skipped "${e.slug}": ${o.message}`)}}})();
|
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{decodeBase64Json as P}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as Y,applyColour as J,applyPill as te,applyFloat as oe,applyHighlight as R,applyItemHighlight as ne,itemHighlightAttrs as ae,isCurrentItem as X,menuAlign as se,applyClasses as O,cssClasses as W}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{initFloatingMenus as ie}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as U,markInvalidFields as G,showValidationPopup as K}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as re}from"/public/js/form-steps.mjs";import{applyFormClasses as Q,applySubmitButtons as ce,applyWizardButtons as le}from"/public/js/form-submit.mjs";$(()=>{const p=window.__CMS_NAV__||{},c=window.__CMS_SITE__||{};if(c.autoTheme?.enabled){let t=function(e){const a=(e||"07:00").split(":");return+a[0]*60+(+a[1]||0)},s=function(){const e=new Date,a=e.getHours()*60+e.getMinutes();return a>=t(n.dayStart)&&a<t(n.nightStart)?n.dayTheme:n.nightTheme},o=function(e){const a=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(a.theme);for(const f of[...document.body.classList])f.startsWith("dm-custom-")&&document.body.classList.remove(f);a.custom&&document.body.classList.add(a.custom)};const n=c.autoTheme;o(s()),setInterval(()=>o(s()),6e4)}const x=$("#site-navbar");if(x.length&&p.brand){let s=function(l,d=0){return Array.isArray(l)?l.filter(m=>!(m&&(m.type==="spacer"||m.type==="theme-switcher"))).filter(m=>!(m&&m.type==="separator"&&d===0)).map(m=>m&&m.type==="separator"?{divider:!0}:Array.isArray(m?.items)?{...m,items:s(m.items,d+1)}:m):l},o=function(l){return Array.isArray(l)?l.filter(d=>!(d&&(d.type==="separator"||d.type==="spacer"||d.type==="theme-switcher"))):[]};const n={...p.brand},t=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let l="";n.logo?l+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(l+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(l+=`<span class="navbar-brand-text${t}">${n.text}</span>`),n.tagline&&(l+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=l}else t&&n.text&&(n.html=`<span class="navbar-brand-text${t}">${n.text}</span>`);const e=p.position==="floating",a=p.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:n,items:s(p.items||[]),variant:p.variant||"dark",position:e?"static":p.position||"sticky",collapsible:!0,appearOnHover:!!p.appearOnHover}),Domma.icons.scan("#site-navbar");const f=x.get(0);f.classList.add(`dm-nav-align-${se(p)||"centre"}`),a&&x.get(0).classList.add("dm-nav-vertical",p.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const v=p.dock||{};a&&!e&&de(f,p.side==="right"),!a&&v.hideOnScroll&&me(f),R(f,p),O(f,p.class),e&&(oe(x.get(0),p),ie(x.get(0).parentNode||document));const i=f.querySelector(".navbar-toggle"),u=f.querySelector(".navbar-collapse");if(i&&u){let l=null;const d=()=>{u.classList.contains("show")&&i.click()},m=()=>{l&&(l.remove(),l=null),document.body.classList.remove("dm-drawer-open")},g=()=>{l||(l=document.createElement("div"),l.className="dm-navbar-backdrop",l.addEventListener("click",d),document.body.appendChild(l),document.body.classList.add("dm-drawer-open"))};i.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?g():m()})}),u.addEventListener("click",C=>{C.target.closest("a")&&requestAnimationFrame(m)}),document.addEventListener("keydown",C=>{C.key==="Escape"&&u.classList.contains("show")&&d()})}const h=f.querySelector(".navbar-nav");if(h){const l=Array.from(h.children);let d=0;for(const m of p.items||[])if(!(m&&m.type==="separator")){if(m&&m.type==="spacer"){const g=document.createElement("li"),C=["xs","sm","md","lg","xl","flex"].includes(m.size)?m.size:"md";g.className=`dm-menu-spacer dm-menu-spacer--${C}`,g.setAttribute("aria-hidden","true"),h.insertBefore(g,l[d]||null);continue}if(m&&m.type==="theme-switcher"){const g=document.createElement("li");g.className="dm-menu-theme-switcher";const C=document.createElement("span");C.dataset.themeSwitcher="menu",C.dataset.position="inline",g.appendChild(C),h.insertBefore(g,l[d]||null);continue}d++}window.CMSThemeSwitcher?.scan(h)}const b=o(p.items||[]);f.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(l=>{const d=b[parseInt(l.dataset.index,10)];if(!d)return;const m=l.dataset.subindex!=null,g=m&&Array.isArray(d.items)?d.items[parseInt(l.dataset.subindex,10)]:d;if(!g)return;g.colour&&J(l,g.colour),g.pill&&!m&&te(l,g.pill),ne(l,g),O(l.closest("li"),g.class);const C=Y(g.badge);C&&l.appendChild(C),X(g.url,location.pathname)&&(l.classList.add("active"),l.setAttribute("aria-current","page"))})}const y=$("#site-footer");if(y.length){let e=function(r){return String(r??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},a=function(r){return e(r).replace(/'/g,"'")},f=function(r){if(r&&r.type==="separator")return'<li class="footer-sep"><hr></li>';if(r&&r.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md"}" aria-hidden="true"></li>`;if(r&&r.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const A=a(r.url||"#"),k=e(r.text||""),q=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(f).join("")}</ul>`:"",N=ae(r),Z=[N.hover&&` data-menu-item-hover="${a(N.hover)}"`,N.active&&` data-menu-item-active="${a(N.active)}"`].filter(Boolean).join(""),ee=N.accent?` style="--dm-menu-highlight:${a(N.accent)}"`:"",V=W(r.class).join(" ");return`<li${V?` class="${a(V)}"`:""}><a href="${A}"${Z}${ee}>${k}</a>${q}</li>`},v=function(){if(!c.footer)return"";const r=Object.keys(t).filter(k=>n[k]);if(!r.length)return"";const A=W(c.footer.socialClass).join(" ");return`<div class="footer-social">${r.map(k=>{const{label:q,svg:N}=t[k];return`<a href="${n[k]}" target="_blank" rel="noopener noreferrer" aria-label="${q}" class="footer-social-link${A?` ${a(A)}`:""}">${N}</a>`}).join("")}</div>`},b=function(r){if(!r||r.type==="separator"||r.type==="spacer")return"";if(r.type==="theme-switcher")return`<li class="cms-footer-col">${f(r).replace(/^<li[^>]*>|<\/li>$/g,"")}</li>`;const A=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(f).join("")}</ul>`:"",k=h(r)?`<span class="cms-footer-col-title">${e(r.text||"")}</span>`:`<a class="cms-footer-col-title" href="${a(r.url||"#")}">${e(r.text||"")}</a>`,q=["cms-footer-col",...W(r.class)].join(" ");return`<li class="${a(q)}">${k}${A}</li>`},d=function(r,A,k=!1){return(r||[]).forEach(q=>{q&&(q.type==="separator"||q.type==="spacer"||q.type==="theme-switcher")||(k&&h(q)||A.push(q),Array.isArray(q.items)&&q.items.length&&d(q.items,A))}),A};const n=c.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const o=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""},i=["columns","row"].includes(c.footer?.layout)?c.footer.layout:"auto",u=i==="columns"||i==="auto"&&o.primary.some(r=>Array.isArray(r?.items)&&r.items.length),h=r=>u&&!r.url&&Array.isArray(r.items)&&r.items.length>0;if(u){const r=p.brand||{},A=r.text||c.title||"",k=r.logo?`<img src="${a(r.logo)}" class="cms-footer-brand-logo" alt="">`:r.icon?'<span class="cms-footer-brand-icon"></span>':"",q=String(c.footer?.blurb||"").trim();s='<div class="footer-inner footer-inner--columns container"><div class="cms-footer-top">',s+=`<div class="cms-footer-brand">${A||k?`<a class="cms-footer-brand-name" href="${a(r.url||"/")}">${k}<span>${e(A)}</span></a>`:""}${q?`<p class="cms-footer-blurb">${e(q)}</p>`:""}${v()}</div>`,o.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary footer-nav--columns" aria-label="Footer"><ul>${o.primary.map(b).join("")}</ul></nav>`),s+='</div><div class="cms-footer-bottom">',o.copyright&&(s+=`<p class="cms-footer-copyright">${e(o.copyright)}</p>`),o.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal" aria-label="Legal"><ul>${o.legal.map(f).join("")}</ul></nav>`),s+="</div>"}else o.copyright&&(s+=`<p>${e(o.copyright)}</p>`),o.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${o.primary.map(f).join("")}</ul></nav>`),o.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${o.legal.map(f).join("")}</ul></nav>`),s+=v();s+="</div>",y.html(s),window.CMSThemeSwitcher?.scan(y.get(0));const l=y.get(0).querySelector(".cms-footer-brand-icon");l&&p.brand?.icon&&l.setAttribute("data-icon",p.brand.icon),O(y.get(0),c.footer?.class);const m=[...d(o.primary,[],!0),...d(o.legal,[])];y.get(0).querySelectorAll(".footer-nav a").forEach((r,A)=>{const k=m[A];if(!k)return;k.colour&&J(r,k.colour);const q=Y(k.badge);q&&r.appendChild(q),X(k.url,location.pathname)&&(r.classList.add("is-active"),r.setAttribute("aria-current","page"))}),R(y.get(0).querySelector(".footer-nav--primary"),{highlight:o.primaryHighlight}),R(y.get(0).querySelector(".footer-nav--legal"),{highlight:o.legalHighlight}),O(y.get(0).querySelector(".footer-nav--primary"),o.primaryClass),O(y.get(0).querySelector(".footer-nav--legal"),o.legalClass);const C=c.footer?.showMotionToggle!==!1,M=S.get("reduced_motion"),D=c.footer?.motionDefault,z=M!=null?!!M:D==="on"?!0:D==="off"?!1:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),B=c.footer?.motionControl==="checkbox",I=y.get(0).querySelector(".cms-footer-bottom")||y.get(0).querySelector(".footer-inner");if(C&&I){const r=document.createElement("input");r.type="checkbox",r.className=B?"footer-motion-checkbox":"form-switch-input",r.id="dm-motion-switch",r.checked=z,r.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const A=document.createElement("span");A.className=B?"footer-motion-label":"form-switch-label",A.textContent="Reduce motion";const k=document.createElement("label");k.className=B?"footer-motion-check":"form-switch footer-motion-switch",k.title="Reduce motion",k.appendChild(r),k.appendChild(A),I.appendChild(k)}}const L=document.getElementById("site-sidebar");L&&ue(L),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const w=$(".page-body");if(w.length){w.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),w.find(".tabs").each(function(){Domma.elements.tabs(this)}),w.find(".carousel").each(function(){const n={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(n.animationDuration=t)}this.dataset.animationEasing&&(n.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=n),this._dmCarousel=Domma.elements.carousel(this,n)}),w.find(".dm-countdown").each(function(){const n={autoStart:!0},t=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),o=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=o?new Date(+o[1],+o[2]-1,+o[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?n.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(n.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const a=/^dd:/i.test(t);n.format=a?"hh:mm:ss":t||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const f=this,v=u=>String(u).padStart(2,"0"),i=u=>{const h=Math.max(0,Math.floor(u/1e3)),b=f.querySelector(".dm-timer-time");b&&(b.textContent=`${v(Math.floor(h/86400))}:${v(Math.floor(h%86400/3600))}:${v(Math.floor(h%3600/60))}:${v(h%60)}`)};a&&(n.onTick=i),Domma.elements.timer(this,n),a&&i(n.duration||0)}),w.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),w.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(o=>{const e={title:o.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:o.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return o.dataset.date&&(e.date=o.dataset.date),o.dataset.status&&(e.status=o.dataset.status),o.dataset.entryId&&(e._entryId=o.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...n.length?{items:n}:{}});n.length&&(this._dmCtx={instance:s,items:n})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(n=>{const t=n.dataset.revealMode||"stagger",s=n.dataset.revealAnimation||"slide-up",o=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,a=parseInt(n.dataset.revealDelay,10)||0,f=n.dataset.revealDirection==="rtl",v=Array.from(n.children),i={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};v.forEach((u,h)=>{u.style.opacity="0",u.style.transform=i[s]||"",u.style.transition=`opacity ${o}ms ease, transform ${o}ms ease`;const b=f?v.length-1-h:h;u.style.transitionDelay=t==="stagger"?`${a+b*e}ms`:`${a}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const u=new IntersectionObserver(h=>{h.forEach(b=>{b.isIntersecting&&(b.target.offsetWidth,b.target.style.opacity="1",b.target.style.transform="none",u.unobserve(b.target))})},{threshold:.1});v.forEach(h=>u.observe(h))}))}),w.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),w.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const n=this.dataset.soTarget,t=document.getElementById(n);if(!t)return;const s=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",s.setContent(t),s.open()})})}if(typeof $.setup=="function"){const n=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const s=P(t.dataset.config);Object.assign(n,s)}catch{}}),Object.keys(n).length>0){const t={};for(const[s,o]of Object.entries(n)){const e=o?.events?.click,{confirm:a,toast:f,alert:v,prompt:i,...u}=e||{};a||f||v||i?($(s).on("click",async function(b){if(b.preventDefault(),a&&!await E.confirm(a))return;let l=null;if(!(i&&(l=await E.prompt(i,{inputPlaceholder:u.promptPlaceholder||"",inputValue:u.promptDefault||""}),l===null))){if(u.target){const d=$(u.target);u.toggleClass&&d.toggleClass(u.toggleClass),u.addClass&&d.addClass(u.addClass),u.removeClass&&d.removeClass(u.removeClass),l!==null&&(u.setText&&d.text(l),u.setVal&&d.val(l),u.setAttr&&d.attr(u.setAttr,l))}u.href&&(window.location.href=u.href),f&&E.toast(f,{type:u.toastType||"success"}),v&&E.alert(v)}}),Object.keys(u).length&&(t[s]={...o,events:{...o.events,click:u}})):t[s]=o}$.setup(t)}}w.length&&j(w.get(0))}),window.wireCTAButtons=j;function j(p){p.querySelectorAll(".dm-cta-trigger").forEach(c=>{c.__ctaWired||(c.__ctaWired=!0,c.addEventListener("click",async()=>{const x=c.dataset.action,y=c.dataset.entry,L=c.dataset.confirm;let w=S.get("auth_token");if(!w){E.toast("Please log in to perform this action.",{type:"warning"});return}if(L&&!await E.confirm(L))return;const n=Array.from(c.childNodes).map(s=>s.cloneNode(!0));c.disabled=!0,c.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${x}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(c.dataset.scope?{entryId:y,scope:c.dataset.scope}:{entryId:y})});try{let s=await t(w);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const a=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(a.ok){const{token:f}=await a.json();S.set("auth_token",f),w=f,s=await t(w)}}}const o=await s.json().catch(()=>({}));if(!s.ok)throw new Error(o.error||o.message||`Error ${s.status}`);E.toast(o.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{c.disabled=!1,c.textContent="",n.forEach(s=>c.appendChild(s)),Domma.icons.scan(c)}}))})}(function(){const c=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!c.length)return;const x=S.get("auth_token");function y(w,n){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(n){s.appendChild(document.createTextNode("Please "));const o=document.createElement("a");o.href="/login",o.textContent="sign in",s.appendChild(o),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=w;return t.appendChild(s),t}function L(w,n){const t=document.createElement("template");t.innerHTML=n||"",w.replaceWith(t.content)}c.forEach(async w=>{const n=w.dataset.collectionAttrs;if(!n)return;if(!x){w.replaceChildren(y("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:n})});try{let s=x,o=await t(s);if(o.status===401){const a=S.get("auth_refresh_token");if(a){const f=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:a})});if(f.ok){const{token:v}=await f.json();S.set("auth_token",v),s=v,o=await t(s)}}}if(!o.ok){const{error:a}=await o.json().catch(()=>({}));w.replaceChildren(y(a||"Unable to load entries.",!1));return}const{html:e}=await o.json();L(w,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{w.replaceChildren(y("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),j(document.body)},100)})(),(function(){const c=document.querySelectorAll("[data-collection-table]");!c.length||typeof T>"u"||!T.create||c.forEach(x=>{let y;try{y=P(x.dataset.payload)}catch{return}const{columns:L,rows:w,search:n,sortable:t,exportable:s,pageSize:o,empty:e,ctaConfig:a,slug:f,exportCfg:v}=y;if(!L?.length)return;if(a){const h=L.findIndex(b=>b.key==="_cta");h!==-1&&(L[h]={key:"_cta",title:"",render:(b,l)=>{const d=document.createElement("button");if(d.className=`btn btn-${a.style||"primary"} dm-cta-trigger`,d.dataset.action=a.action||"",a.scope&&(d.dataset.scope=a.scope),d.dataset.entry=l._entryId||"",a.confirm&&(d.dataset.confirm=a.confirm),a.icon){const m=document.createElement("span");m.dataset.icon=a.icon,d.appendChild(m),d.appendChild(document.createTextNode(" "))}return d.appendChild(document.createTextNode(a.label||"Run")),d}})}const i="col-table-"+Math.random().toString(36).slice(2,7),u=document.createElement("div");u.id=i,x.replaceChildren(u),T.create("#"+i,{data:w,columns:L,search:n,sortable:t,exportable:s,pageSize:o,emptyMessage:e}),a&&j(u),x._dmTable={columns:L,rows:w,slug:f,exportCfg:v,render(h){T.create("#"+i,{data:h,columns:L,search:n,sortable:t,exportable:s,pageSize:o,emptyMessage:e}),a&&j(u)}}})})(),(function(){const c=document.querySelectorAll("[data-form-inline]");if(!c.length||typeof F>"u")return;function x(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function y(t,s){const o={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),f=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":a?"chooser":e.type,v={...e.formConfig||{}};v.span==="full"&&s&&(v.span=s);const i={type:f,required:x(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...v}};e.minLength!==void 0&&(i.minLength=e.minLength),e.maxLength!==void 0&&(i.maxLength=e.maxLength),e.min!==void 0&&(i.min=e.min),e.max!==void 0&&(i.max=e.max),a&&(e.variant&&(i.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(i.multiple=!0),e.density&&(i.density=e.density),e.columns&&(i.columns=e.columns),e.accent&&(i.accent=e.accent),e.accentStyle&&(i.accentStyle=e.accentStyle),e.glow&&(i.glow=!0),e.glowColour&&(i.glowColour=e.glowColour),e.shadow&&(i.shadow=e.shadow),e.shadowColour&&(i.shadowColour=e.shadowColour)),o[e.name]=i}),o}function L(t){const s={};return(t||[]).forEach(o=>{if(!(!o.name||o.type==="page-break"||o.type==="spacer")&&(o.type==="select"||o.type==="multiselect")&&o.required){const e=(o.options||[])[0];e&&(s[o.name]=typeof e=="object"?e.value:e)}}),s}function w(t,s){(s||[]).forEach(o=>{if(o.type!=="date"||!o.name)return;const e=t.querySelector(`[name="${o.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(t,s,o){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=o?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}c.forEach(t=>{let s;try{s=P(t.dataset.formInline)}catch{return}const o=s.fields||[],e=s.settings||{},a=Number(e.columns)===3?3:2,f=e.layout||"grid",v=o.some(d=>d.type==="page-break"),i=async d=>{if(t.dataset.triggerBlocked==="true"){const m=t._formLogicRuntime,g=m&&m.submitBlock?m.submitBlock().reasons:[];n(t,g.join(" ")||"This form cannot be submitted yet.",!0);const C=new Error("Blocked by a form trigger");throw C.formSubmitFailed=!0,C}try{const m=t.querySelector(".fb-form-honeypot"),g=m?.querySelector('input[type="text"]')||null,C=m?.querySelector('[name="_t"]')||null,M=Object.assign({},d);delete M._t,m?.dataset.hpName&&delete M[m.dataset.hpName],g!==null&&(M._hp=g.value),C!==null&&(M._t=C.value);const D=await H.post(`/api/forms/submit/${s.slug}`,M);if(D&&D.error){n(t,D.error,!0);const z=new Error(D.error);throw z.formSubmitFailed=!0,z}if(D?.redirect){window.location.href=D.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);n(t,D?.message||e.successMessage||"Thank you for your submission.",!1)}catch(m){throw m.formSubmitFailed||n(t,m.message||"Submission failed. Please try again.",!0),m}},u=Date.now();function h(d){const m=d.querySelector("form");if(!m||m.querySelector(".fb-form-honeypot"))return;const g=document.createElement("div");g.className="fb-form-honeypot",g.setAttribute("aria-hidden","true");const C=document.createElement("input");C.name=m.querySelector('[name="website"]')?"_website":"website",g.dataset.hpName=C.name,C.type="text",C.tabIndex=-1,C.autocomplete="url",C.placeholder="https://",g.appendChild(C);const M=document.createElement("input");M.name="_t",M.type="hidden",M.value=u,g.appendChild(M),m.appendChild(g)}function b(d){if(!window.FormLogicEngine||!o.some(g=>g.logic||Array.isArray(g.triggers)&&g.triggers.length))return null;const m=new window.FormLogicEngine.FormLogicRuntime(s,t,d?{baseValues:d}:void 0);if(m.init(),t._formLogicRuntime=m,t._formLogicObserved)return m;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const g=new MutationObserver(function(C){for(const M of C)for(const D of M.removedNodes)if(D===t||D.nodeType===1&&D.contains&&D.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),g.disconnect();return}});g.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=g}return m}let l=!1;if(t.addEventListener("dm-form-end",d=>{const m=d.detail?.validation;if(m&&!m.valid){G(t,m.missing),K(m);return}l||(l=!0,i(d.detail?.values||{}).catch(()=>{}).finally(()=>{l=!1}))}),v&&F.wizard){const d=re(o,s.title),m=d.map(I=>({title:I.title,description:I.description,fields:y(I.fields,a)})),g=d.map(I=>I.fields);let C=0,M=null,D=null;const z=I=>{const r=window.FormLogicEngine;if(!r||!r.validateFields)return;const A=r.validateFields(t,g[C]||[]);A.valid||(I.preventDefault(),I.stopImmediatePropagation(),G(t,A.missing),K(A))},B=()=>{const I=g[C]||o;le(t,e),Q(t,e,I),w(t,I),U(t,I),e.honeypot!==!1&&h(t),M&&M.destroy(),M=b(D?.getStepData?D.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(r=>r.addEventListener("click",z,!0))};D=F.wizard(t,{schema:{steps:m},layout:f,columns:a,finishText:e.submitText||"Finish",onSubmit:i,onStepChange:I=>{C=I,setTimeout(B,0)}}),t.addEventListener("dm-form-trigger",I=>{if(I.detail?.type!=="goto-step"||!D?.goToStep)return;const r=Number(I.detail.action.step);!Number.isFinite(r)||r<0||r>=m.length||r!==C&&D.goToStep(r)}),Promise.resolve(D).then(B)}else if(F.render){const d=F.render(t,y(o,a),L(o),{submitText:e.submitText||"Submit",layout:f,columns:a,onSubmit:i});Promise.resolve(d).then(function(){ce(t,e,f),Q(t,e,o),w(t,o),U(t,o),e.honeypot!==!1&&h(t),b()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();function de(p,c){const x=document.body,y=x.classList,L=new Set((x.dataset.railSite||"").split(" ").filter(Boolean)),w=()=>window.matchMedia("(min-width: 993px)").matches;p.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(a=>{const f=a.textContent.trim();f&&(a.setAttribute("title",f),a.querySelector("svg, [data-icon]")||(a.dataset.initial=f.charAt(0).toUpperCase()))});const n=document.createElement("button");n.type="button",n.className="dm-nav-collapse-toggle";const t=()=>{const a=y.contains("dm-vnav-collapsed");n.setAttribute("aria-pressed",String(a)),n.setAttribute("aria-label",a?"Expand menu":"Collapse menu"),n.title=n.getAttribute("aria-label");const f=c?"chevrons-left":"chevrons-right",v=c?"chevrons-right":"chevrons-left";n.innerHTML=`<span data-icon="${a?f:v}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(n)},s=a=>{y.toggle("dm-vnav-collapsed",a),S.set("nav_collapsed",a),t()};n.addEventListener("click",()=>s(!y.contains("dm-vnav-collapsed"))),t();const o=p.querySelector(".navbar-container")||p;o.insertBefore(n,o.firstChild?.nextSibling||null);const e=a=>{y.toggle("dm-vnav-autohide",a),y.toggle("dm-vnav-collapsible",!a&&L.has("collapsible")),a?y.remove("dm-vnav-collapsed"):L.has("collapsible")&&S.get("nav_collapsed")===!0&&y.add("dm-vnav-collapsed"),p.classList.remove("dm-nav-revealed"),t()};p.addEventListener("pointerdown",a=>{y.contains("dm-vnav-autohide")&&a.pointerType!=="mouse"&&!p.classList.contains("dm-nav-revealed")&&(p.classList.add("dm-nav-revealed"),a.preventDefault())}),document.addEventListener("pointerdown",a=>{p.contains(a.target)||p.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const a=y.contains("dm-vnav-autohide"),f=y.contains("dm-vnav-collapsed"),v=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:f?"Expand menu":"Collapse to icons",icon:f?"maximize":"minimize",disabled:!w()||a||!L.has("collapsible"),action:()=>s(!f)},{label:a?"Keep on screen":"Hide when not in use",icon:a?"eye":"eye-off",disabled:!w(),action:()=>{S.set("nav_autohide",!a),e(!a)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!v,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(L.has("autohide")),y.toggle("dm-vnav-collapsed",!L.has("autohide")&&L.has("start-collapsed")),t()}}]}})}function me(p){p.classList.add("dm-nav-scroll-hide");let c=window.scrollY,x=!1;window.addEventListener("scroll",()=>{x||(x=!0,requestAnimationFrame(()=>{x=!1;const y=window.scrollY,L=p.matches(":focus-within")||p.querySelector(".navbar-dropdown.open, .navbar-collapse.show");y>c&&y>p.offsetHeight&&!L?p.classList.add("dm-nav-scrolled-away"):y<c&&p.classList.remove("dm-nav-scrolled-away"),c=y}))},{passive:!0})}function ue(p){let c={};try{c=JSON.parse(p.dataset.contents||"{}")}catch{}const x=p.closest(".site-main"),y=document.querySelector(".site-content"),L=new Set(String(c.exclude||"").split(",").map(i=>i.trim().toLowerCase()).filter(Boolean)),w=i=>!i.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),n=i=>(y?[...y.querySelectorAll(i)]:[]).filter(w).filter(u=>!L.has(u.textContent.trim().toLowerCase())),t=c.headings==="h2"?n("h2"):c.headings==="h3"?n("h3"):c.headings==="h2h3"?n("h2, h3"):n("h2").length?n("h2"):n("h3");if(!t.length){x?.classList.add("no-sidebar-items");return}const s=new Set([...document.querySelectorAll("[id]")].map(i=>i.id)),o=document.createElement("nav");o.className="dm-contents",o.setAttribute("aria-label",c.title||"Page contents"),c.hover&&(o.dataset.menuHover=c.hover),c.selected&&(o.dataset.menuActive=c.selected),c.accent&&o.style.setProperty("--dm-menu-highlight",c.accent.startsWith("#")?c.accent:`var(--dm-${c.accent})`),c.font&&(o.style.fontFamily=c.font),c.fontSize&&(o.style.fontSize=c.fontSize),c.fontWeight&&(o.style.fontWeight=c.fontWeight);const e=document.createElement("div");e.className="dm-contents-head";const a=document.createElement("p");a.className="dm-contents-title",a.textContent=c.title||"",e.appendChild(a),o.appendChild(e);const f=document.createElement("ol");f.className="dm-contents-list"+(c.numbered?" is-numbered":"");const v=[];for(const i of t){if(!i.id){const b=(i.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let l=b;for(let d=2;s.has(l);d++)l=`${b}-${d}`;s.add(l),i.id=l}const u=document.createElement("li");u.className=`dm-contents-item dm-contents-${i.tagName.toLowerCase()}`;const h=document.createElement("a");h.href=`#${i.id}`,h.textContent=i.textContent.trim(),u.appendChild(h),f.appendChild(u),v.push([i,h])}if(o.appendChild(f),p.replaceChildren(o),c.scrollSpy!==!1&&"IntersectionObserver"in window){const i=new Map,u=()=>{const b=v.find(([l])=>i.get(l))||null;v.forEach(([,l])=>{const d=b&&l===b[1];l.classList.toggle("is-active",!!d),d?l.setAttribute("aria-current","location"):l.removeAttribute("aria-current")})},h=new IntersectionObserver(b=>{b.forEach(l=>i.set(l.target,l.isIntersecting)),u()},{rootMargin:"-80px 0px -60% 0px"});v.forEach(([b])=>h.observe(b))}if(x?.classList.contains("contents-collapsible")){const i=document.createElement("button");i.type="button",i.className="dm-contents-toggle";const u=()=>{const h=x.classList.contains("contents-collapsed");i.setAttribute("aria-expanded",String(!h)),i.setAttribute("aria-label",h?"Show the contents":"Hide the contents"),i.title=i.getAttribute("aria-label"),i.innerHTML=`<span data-icon="${h?"list":"x"}"></span>`,window.Domma?.icons&&Domma.icons.scan(i)};i.addEventListener("click",()=>{S.set("contents_collapsed",x.classList.toggle("contents-collapsed")),u()}),u(),e.insertBefore(i,e.firstChild)}if(x?.classList.contains("contents-floating")&&c.movable){o.classList.add("is-movable");const i=S.get("contents_position");i&&Number.isFinite(i.x)&&Object.assign(p.style,{left:`${i.x}px`,top:`${i.y}px`,right:"auto",bottom:"auto"}),e.addEventListener("pointerdown",u=>{if(u.target.closest("button"))return;const h=p.getBoundingClientRect(),b=u.clientX-h.left,l=u.clientY-h.top,d=g=>{const C=Math.max(0,Math.min(window.innerWidth-h.width,g.clientX-b)),M=Math.max(0,Math.min(window.innerHeight-40,g.clientY-l));Object.assign(p.style,{left:`${C}px`,top:`${M}px`,right:"auto",bottom:"auto"})},m=()=>{document.removeEventListener("pointermove",d),S.set("contents_position",{x:parseInt(p.style.left,10),y:parseInt(p.style.top,10)})};document.addEventListener("pointermove",d),document.addEventListener("pointerup",m,{once:!0})})}window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const i=x?.classList.contains("contents-collapsible"),u=x?.classList.contains("contents-collapsed"),h=v.find(([,b])=>b.classList.contains("is-active"));return[{header:"Contents"},...i?[{label:u?"Show the contents":"Collapse to a button",icon:u?"list":"minimize",action:()=>p.querySelector(".dm-contents-toggle")?.click()}]:[],{label:"Copy a link to this section",icon:"link",disabled:!h,action:async()=>{const b=`${location.origin}${location.pathname}#${h[0].id}`;try{await _.copyToClipboard(b),E.toast("Link copied.",{type:"success"})}catch{E.toast("Could not copy the link.",{type:"error"})}}},{label:"Back to the top",icon:"arrow-up",action:()=>window.scrollTo({top:0,behavior:"smooth"})}]}}),x?.classList.contains("contents-autohide")&&(p.addEventListener("pointerdown",i=>{i.pointerType!=="mouse"&&!p.classList.contains("is-revealed")&&(p.classList.add("is-revealed"),i.preventDefault())}),document.addEventListener("pointerdown",i=>{p.contains(i.target)||p.classList.remove("is-revealed")}))}
|
|
1
|
+
import{decodeBase64Json as P}from"/public/js/utf8-base64.mjs";import{makeBadgeEl as Y,applyColour as J,applyPill as te,applyFloat as oe,applyHighlight as R,applyItemHighlight as ne,itemHighlightAttrs as ae,isCurrentItem as X,menuAlign as se,applyClasses as O,cssClasses as W}from"/public/js/menu-decor.mjs?v=20261009-hover-darken";import{initFloatingMenus as ie}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as U,markInvalidFields as G,showValidationPopup as K}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as re}from"/public/js/form-steps.mjs";import{applyFormClasses as Q,applySubmitButtons as ce,applyWizardButtons as le}from"/public/js/form-submit.mjs";$(()=>{const p=window.__CMS_NAV__||{},c=window.__CMS_SITE__||{};if(c.autoTheme?.enabled){let t=function(e){const a=(e||"07:00").split(":");return+a[0]*60+(+a[1]||0)},s=function(){const e=new Date,a=e.getHours()*60+e.getMinutes();return a>=t(n.dayStart)&&a<t(n.nightStart)?n.dayTheme:n.nightTheme},o=function(e){const a=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(a.theme);for(const f of[...document.body.classList])f.startsWith("dm-custom-")&&document.body.classList.remove(f);a.custom&&document.body.classList.add(a.custom)};const n=c.autoTheme;o(s()),setInterval(()=>o(s()),6e4)}const x=$("#site-navbar");if(x.length&&p.brand){let s=function(l,d=0){return Array.isArray(l)?l.filter(m=>!(m&&(m.type==="spacer"||m.type==="theme-switcher"))).filter(m=>!(m&&m.type==="separator"&&d===0)).map(m=>m&&m.type==="separator"?{divider:!0}:Array.isArray(m?.items)?{...m,items:s(m.items,d+1)}:m):l},o=function(l){return Array.isArray(l)?l.filter(d=>!(d&&(d.type==="separator"||d.type==="spacer"||d.type==="theme-switcher"))):[]};const n={...p.brand},t=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let l="";n.logo?l+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(l+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(l+=`<span class="navbar-brand-text${t}">${n.text}</span>`),n.tagline&&(l+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=l}else t&&n.text&&(n.html=`<span class="navbar-brand-text${t}">${n.text}</span>`);const e=p.position==="floating",a=p.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:n,items:s(p.items||[]),variant:p.variant||"dark",position:e?"static":p.position||"sticky",collapsible:!0,appearOnHover:!!p.appearOnHover}),Domma.icons.scan("#site-navbar");const f=x.get(0);f.classList.add(`dm-nav-align-${se(p)||"centre"}`),a&&x.get(0).classList.add("dm-nav-vertical",p.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left");const v=p.dock||{};a&&!e&&de(f,p.side==="right"),!a&&v.hideOnScroll&&me(f),R(f,p),O(f,p.class),e&&(oe(x.get(0),p),ie(x.get(0).parentNode||document));const i=f.querySelector(".navbar-toggle"),u=f.querySelector(".navbar-collapse");if(i&&u){let l=null;const d=()=>{u.classList.contains("show")&&i.click()},m=()=>{l&&(l.remove(),l=null),document.body.classList.remove("dm-drawer-open")},g=()=>{l||(l=document.createElement("div"),l.className="dm-navbar-backdrop",l.addEventListener("click",d),document.body.appendChild(l),document.body.classList.add("dm-drawer-open"))};i.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?g():m()})}),u.addEventListener("click",C=>{C.target.closest("a")&&requestAnimationFrame(m)}),document.addEventListener("keydown",C=>{C.key==="Escape"&&u.classList.contains("show")&&d()})}const h=f.querySelector(".navbar-nav");if(h){const l=Array.from(h.children);let d=0;for(const m of p.items||[])if(!(m&&m.type==="separator")){if(m&&m.type==="spacer"){const g=document.createElement("li"),C=["xs","sm","md","lg","xl","flex"].includes(m.size)?m.size:"md";g.className=`dm-menu-spacer dm-menu-spacer--${C}`,g.setAttribute("aria-hidden","true"),h.insertBefore(g,l[d]||null);continue}if(m&&m.type==="theme-switcher"){const g=document.createElement("li");g.className="dm-menu-theme-switcher";const C=document.createElement("span");C.dataset.themeSwitcher="menu",C.dataset.position="inline",g.appendChild(C),h.insertBefore(g,l[d]||null);continue}d++}window.CMSThemeSwitcher?.scan(h)}const b=o(p.items||[]);f.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(l=>{const d=b[parseInt(l.dataset.index,10)];if(!d)return;const m=l.dataset.subindex!=null,g=m&&Array.isArray(d.items)?d.items[parseInt(l.dataset.subindex,10)]:d;if(!g)return;g.colour&&J(l,g.colour),g.pill&&!m&&te(l,g.pill),ne(l,g),O(l.closest("li"),g.class);const C=Y(g.badge);C&&l.appendChild(C),X(g.url,location.pathname)&&(l.classList.add("active"),l.setAttribute("aria-current","page"))})}const y=$("#site-footer");if(y.length){let e=function(r){return String(r??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},a=function(r){return e(r).replace(/'/g,"'")},f=function(r){if(r&&r.type==="separator")return'<li class="footer-sep"><hr></li>';if(r&&r.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md"}" aria-hidden="true"></li>`;if(r&&r.type==="theme-switcher")return'<li class="dm-menu-theme-switcher"><span data-theme-switcher="menu" data-position="inline"></span></li>';const A=a(r.url||"#"),k=e(r.text||""),q=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(f).join("")}</ul>`:"",N=ae(r),Z=[N.hover&&` data-menu-item-hover="${a(N.hover)}"`,N.active&&` data-menu-item-active="${a(N.active)}"`].filter(Boolean).join(""),ee=N.accent?` style="--dm-menu-highlight:${a(N.accent)}"`:"",V=W(r.class).join(" ");return`<li${V?` class="${a(V)}"`:""}><a href="${A}"${Z}${ee}>${k}</a>${q}</li>`},v=function(){if(!c.footer)return"";const r=Object.keys(t).filter(k=>n[k]);if(!r.length)return"";const A=W(c.footer.socialClass).join(" ");return`<div class="footer-social">${r.map(k=>{const{label:q,svg:N}=t[k];return`<a href="${n[k]}" target="_blank" rel="noopener noreferrer" aria-label="${q}" class="footer-social-link${A?` ${a(A)}`:""}">${N}</a>`}).join("")}</div>`},b=function(r){if(!r||r.type==="separator"||r.type==="spacer")return"";if(r.type==="theme-switcher")return`<li class="cms-footer-col">${f(r).replace(/^<li[^>]*>|<\/li>$/g,"")}</li>`;const A=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(f).join("")}</ul>`:"",k=h(r)?`<span class="cms-footer-col-title">${e(r.text||"")}</span>`:`<a class="cms-footer-col-title" href="${a(r.url||"#")}">${e(r.text||"")}</a>`,q=["cms-footer-col",...W(r.class)].join(" ");return`<li class="${a(q)}">${k}${A}</li>`},d=function(r,A,k=!1){return(r||[]).forEach(q=>{q&&(q.type==="separator"||q.type==="spacer"||q.type==="theme-switcher")||(k&&h(q)||A.push(q),Array.isArray(q.items)&&q.items.length&&d(q.items,A))}),A};const n=c.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const o=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""},i=["columns","row"].includes(c.footer?.layout)?c.footer.layout:"auto",u=i==="columns"||i==="auto"&&o.primary.some(r=>Array.isArray(r?.items)&&r.items.length),h=r=>u&&!r.url&&Array.isArray(r.items)&&r.items.length>0;if(u){const r=p.brand||{},A=r.text||c.title||"",k=r.logo?`<img src="${a(r.logo)}" class="cms-footer-brand-logo" alt="">`:r.icon?'<span class="cms-footer-brand-icon"></span>':"",q=String(c.footer?.blurb||"").trim();s='<div class="footer-inner footer-inner--columns container"><div class="cms-footer-top">',s+=`<div class="cms-footer-brand">${A||k?`<a class="cms-footer-brand-name" href="${a(r.url||"/")}">${k}<span>${e(A)}</span></a>`:""}${q?`<p class="cms-footer-blurb">${e(q)}</p>`:""}${v()}</div>`,o.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary footer-nav--columns" aria-label="Footer"><ul>${o.primary.map(b).join("")}</ul></nav>`),s+='</div><div class="cms-footer-bottom">',o.copyright&&(s+=`<p class="cms-footer-copyright">${e(o.copyright)}</p>`),o.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal" aria-label="Legal"><ul>${o.legal.map(f).join("")}</ul></nav>`),s+="</div>"}else o.copyright&&(s+=`<p>${e(o.copyright)}</p>`),o.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${o.primary.map(f).join("")}</ul></nav>`),o.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${o.legal.map(f).join("")}</ul></nav>`),s+=v();s+="</div>",y.html(s),window.CMSThemeSwitcher?.scan(y.get(0));const l=y.get(0).querySelector(".cms-footer-brand-icon");l&&p.brand?.icon&&l.setAttribute("data-icon",p.brand.icon),O(y.get(0),c.footer?.class);const m=[...d(o.primary,[],!0),...d(o.legal,[])];y.get(0).querySelectorAll(".footer-nav a").forEach((r,A)=>{const k=m[A];if(!k)return;k.colour&&J(r,k.colour);const q=Y(k.badge);q&&r.appendChild(q),X(k.url,location.pathname)&&(r.classList.add("is-active"),r.setAttribute("aria-current","page"))}),R(y.get(0).querySelector(".footer-nav--primary"),{highlight:o.primaryHighlight}),R(y.get(0).querySelector(".footer-nav--legal"),{highlight:o.legalHighlight}),O(y.get(0).querySelector(".footer-nav--primary"),o.primaryClass),O(y.get(0).querySelector(".footer-nav--legal"),o.legalClass);const C=c.footer?.showMotionToggle!==!1,M=S.get("reduced_motion"),D=c.footer?.motionDefault,z=M!=null?!!M:D==="on"?!0:D==="off"?!1:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),B=c.footer?.motionControl==="checkbox",I=y.get(0).querySelector(".cms-footer-bottom")||y.get(0).querySelector(".footer-inner");if(C&&I){const r=document.createElement("input");r.type="checkbox",r.className=B?"footer-motion-checkbox":"form-switch-input",r.id="dm-motion-switch",r.checked=z,r.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const A=document.createElement("span");A.className=B?"footer-motion-label":"form-switch-label",A.textContent="Reduce motion";const k=document.createElement("label");k.className=B?"footer-motion-check":"form-switch footer-motion-switch",k.title="Reduce motion",k.appendChild(r),k.appendChild(A),I.appendChild(k)}}const L=document.getElementById("site-sidebar");L&&ue(L),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const w=$(".page-body");if(w.length){w.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),w.find(".tabs").each(function(){Domma.elements.tabs(this)}),w.find(".carousel").each(function(){const n={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(n.animationDuration=t)}this.dataset.animationEasing&&(n.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=n),this._dmCarousel=Domma.elements.carousel(this,n)}),w.find(".dm-countdown").each(function(){const n={autoStart:!0},t=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),o=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=o?new Date(+o[1],+o[2]-1,+o[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?n.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(n.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const a=/^dd:/i.test(t);n.format=a?"hh:mm:ss":t||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const f=this,v=u=>String(u).padStart(2,"0"),i=u=>{const h=Math.max(0,Math.floor(u/1e3)),b=f.querySelector(".dm-timer-time");b&&(b.textContent=`${v(Math.floor(h/86400))}:${v(Math.floor(h%86400/3600))}:${v(Math.floor(h%3600/60))}:${v(h%60)}`)};a&&(n.onTick=i),Domma.elements.timer(this,n),a&&i(n.duration||0)}),w.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),w.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(o=>{const e={title:o.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:o.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return o.dataset.date&&(e.date=o.dataset.date),o.dataset.status&&(e.status=o.dataset.status),o.dataset.entryId&&(e._entryId=o.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...n.length?{items:n}:{}});n.length&&(this._dmCtx={instance:s,items:n})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(n=>{const t=n.dataset.revealMode||"stagger",s=n.dataset.revealAnimation||"slide-up",o=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,a=parseInt(n.dataset.revealDelay,10)||0,f=n.dataset.revealDirection==="rtl",v=Array.from(n.children),i={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};v.forEach((u,h)=>{u.style.opacity="0",u.style.transform=i[s]||"",u.style.transition=`opacity ${o}ms ease, transform ${o}ms ease`;const b=f?v.length-1-h:h;u.style.transitionDelay=t==="stagger"?`${a+b*e}ms`:`${a}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const u=new IntersectionObserver(h=>{h.forEach(b=>{b.isIntersecting&&(b.target.offsetWidth,b.target.style.opacity="1",b.target.style.transform="none",u.unobserve(b.target))})},{threshold:.1});v.forEach(h=>u.observe(h))}))}),w.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),w.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const n=this.dataset.soTarget,t=document.getElementById(n);if(!t)return;const s=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",s.setContent(t),s.open()})})}if(typeof $.setup=="function"){const n=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const s=P(t.dataset.config);Object.assign(n,s)}catch{}}),Object.keys(n).length>0){const t={};for(const[s,o]of Object.entries(n)){const e=o?.events?.click,{confirm:a,toast:f,alert:v,prompt:i,...u}=e||{};a||f||v||i?($(s).on("click",async function(b){if(b.preventDefault(),a&&!await E.confirm(a))return;let l=null;if(!(i&&(l=await E.prompt(i,{inputPlaceholder:u.promptPlaceholder||"",inputValue:u.promptDefault||""}),l===null))){if(u.target){const d=$(u.target);u.toggleClass&&d.toggleClass(u.toggleClass),u.addClass&&d.addClass(u.addClass),u.removeClass&&d.removeClass(u.removeClass),l!==null&&(u.setText&&d.text(l),u.setVal&&d.val(l),u.setAttr&&d.attr(u.setAttr,l))}u.href&&(window.location.href=u.href),f&&E.toast(f,{type:u.toastType||"success"}),v&&E.alert(v)}}),Object.keys(u).length&&(t[s]={...o,events:{...o.events,click:u}})):t[s]=o}$.setup(t)}}w.length&&j(w.get(0))}),window.wireCTAButtons=j;function j(p){p.querySelectorAll(".dm-cta-trigger").forEach(c=>{c.__ctaWired||(c.__ctaWired=!0,c.addEventListener("click",async()=>{const x=c.dataset.action,y=c.dataset.entry,L=c.dataset.confirm;let w=S.get("auth_token");if(!w){E.toast("Please log in to perform this action.",{type:"warning"});return}if(L&&!await E.confirm(L))return;const n=Array.from(c.childNodes).map(s=>s.cloneNode(!0));c.disabled=!0,c.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${x}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(c.dataset.scope?{entryId:y,scope:c.dataset.scope}:{entryId:y})});try{let s=await t(w);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const a=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(a.ok){const{token:f}=await a.json();S.set("auth_token",f),w=f,s=await t(w)}}}const o=await s.json().catch(()=>({}));if(!s.ok||o.success===!1)throw new Error(o.error||o.message||`Error ${s.status}`);E.toast(o.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{c.disabled=!1,c.textContent="",n.forEach(s=>c.appendChild(s)),Domma.icons.scan(c)}}))})}(function(){const c=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!c.length)return;const x=S.get("auth_token");function y(w,n){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(n){s.appendChild(document.createTextNode("Please "));const o=document.createElement("a");o.href="/login",o.textContent="sign in",s.appendChild(o),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=w;return t.appendChild(s),t}function L(w,n){const t=document.createElement("template");t.innerHTML=n||"",w.replaceWith(t.content)}c.forEach(async w=>{const n=w.dataset.collectionAttrs;if(!n)return;if(!x){w.replaceChildren(y("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:n})});try{let s=x,o=await t(s);if(o.status===401){const a=S.get("auth_refresh_token");if(a){const f=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:a})});if(f.ok){const{token:v}=await f.json();S.set("auth_token",v),s=v,o=await t(s)}}}if(!o.ok){const{error:a}=await o.json().catch(()=>({}));w.replaceChildren(y(a||"Unable to load entries.",!1));return}const{html:e}=await o.json();L(w,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{w.replaceChildren(y("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),j(document.body)},100)})(),(function(){const c=document.querySelectorAll("[data-collection-table]");!c.length||typeof T>"u"||!T.create||c.forEach(x=>{let y;try{y=P(x.dataset.payload)}catch{return}const{columns:L,rows:w,search:n,sortable:t,exportable:s,pageSize:o,empty:e,ctaConfig:a,slug:f,exportCfg:v}=y;if(!L?.length)return;if(a){const h=L.findIndex(b=>b.key==="_cta");h!==-1&&(L[h]={key:"_cta",title:"",render:(b,l)=>{const d=document.createElement("button");if(d.className=`btn btn-${a.style||"primary"} dm-cta-trigger`,d.dataset.action=a.action||"",a.scope&&(d.dataset.scope=a.scope),d.dataset.entry=l._entryId||"",a.confirm&&(d.dataset.confirm=a.confirm),a.icon){const m=document.createElement("span");m.dataset.icon=a.icon,d.appendChild(m),d.appendChild(document.createTextNode(" "))}return d.appendChild(document.createTextNode(a.label||"Run")),d}})}const i="col-table-"+Math.random().toString(36).slice(2,7),u=document.createElement("div");u.id=i,x.replaceChildren(u),T.create("#"+i,{data:w,columns:L,search:n,sortable:t,exportable:s,pageSize:o,emptyMessage:e}),a&&j(u),x._dmTable={columns:L,rows:w,slug:f,exportCfg:v,render(h){T.create("#"+i,{data:h,columns:L,search:n,sortable:t,exportable:s,pageSize:o,emptyMessage:e}),a&&j(u)}}})})(),(function(){const c=document.querySelectorAll("[data-form-inline]");if(!c.length||typeof F>"u")return;function x(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function y(t,s){const o={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),f=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":a?"chooser":e.type,v={...e.formConfig||{}};v.span==="full"&&s&&(v.span=s);const i={type:f,required:x(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...v}};e.minLength!==void 0&&(i.minLength=e.minLength),e.maxLength!==void 0&&(i.maxLength=e.maxLength),e.min!==void 0&&(i.min=e.min),e.max!==void 0&&(i.max=e.max),a&&(e.variant&&(i.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(i.multiple=!0),e.density&&(i.density=e.density),e.columns&&(i.columns=e.columns),e.accent&&(i.accent=e.accent),e.accentStyle&&(i.accentStyle=e.accentStyle),e.glow&&(i.glow=!0),e.glowColour&&(i.glowColour=e.glowColour),e.shadow&&(i.shadow=e.shadow),e.shadowColour&&(i.shadowColour=e.shadowColour)),o[e.name]=i}),o}function L(t){const s={};return(t||[]).forEach(o=>{if(!(!o.name||o.type==="page-break"||o.type==="spacer")&&(o.type==="select"||o.type==="multiselect")&&o.required){const e=(o.options||[])[0];e&&(s[o.name]=typeof e=="object"?e.value:e)}}),s}function w(t,s){(s||[]).forEach(o=>{if(o.type!=="date"||!o.name)return;const e=t.querySelector(`[name="${o.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(t,s,o){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=o?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}c.forEach(t=>{let s;try{s=P(t.dataset.formInline)}catch{return}const o=s.fields||[],e=s.settings||{},a=Number(e.columns)===3?3:2,f=e.layout||"grid",v=o.some(d=>d.type==="page-break"),i=async d=>{if(t.dataset.triggerBlocked==="true"){const m=t._formLogicRuntime,g=m&&m.submitBlock?m.submitBlock().reasons:[];n(t,g.join(" ")||"This form cannot be submitted yet.",!0);const C=new Error("Blocked by a form trigger");throw C.formSubmitFailed=!0,C}try{const m=t.querySelector(".fb-form-honeypot"),g=m?.querySelector('input[type="text"]')||null,C=m?.querySelector('[name="_t"]')||null,M=Object.assign({},d);delete M._t,m?.dataset.hpName&&delete M[m.dataset.hpName],g!==null&&(M._hp=g.value),C!==null&&(M._t=C.value);const D=await H.post(`/api/forms/submit/${s.slug}`,M);if(D&&D.error){n(t,D.error,!0);const z=new Error(D.error);throw z.formSubmitFailed=!0,z}if(D?.redirect){window.location.href=D.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);n(t,D?.message||e.successMessage||"Thank you for your submission.",!1)}catch(m){throw m.formSubmitFailed||n(t,m.message||"Submission failed. Please try again.",!0),m}},u=Date.now();function h(d){const m=d.querySelector("form");if(!m||m.querySelector(".fb-form-honeypot"))return;const g=document.createElement("div");g.className="fb-form-honeypot",g.setAttribute("aria-hidden","true");const C=document.createElement("input");C.name=m.querySelector('[name="website"]')?"_website":"website",g.dataset.hpName=C.name,C.type="text",C.tabIndex=-1,C.autocomplete="url",C.placeholder="https://",g.appendChild(C);const M=document.createElement("input");M.name="_t",M.type="hidden",M.value=u,g.appendChild(M),m.appendChild(g)}function b(d){if(!window.FormLogicEngine||!o.some(g=>g.logic||Array.isArray(g.triggers)&&g.triggers.length))return null;const m=new window.FormLogicEngine.FormLogicRuntime(s,t,d?{baseValues:d}:void 0);if(m.init(),t._formLogicRuntime=m,t._formLogicObserved)return m;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const g=new MutationObserver(function(C){for(const M of C)for(const D of M.removedNodes)if(D===t||D.nodeType===1&&D.contains&&D.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),g.disconnect();return}});g.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=g}return m}let l=!1;if(t.addEventListener("dm-form-end",d=>{const m=d.detail?.validation;if(m&&!m.valid){G(t,m.missing),K(m);return}l||(l=!0,i(d.detail?.values||{}).catch(()=>{}).finally(()=>{l=!1}))}),v&&F.wizard){const d=re(o,s.title),m=d.map(I=>({title:I.title,description:I.description,fields:y(I.fields,a)})),g=d.map(I=>I.fields);let C=0,M=null,D=null;const z=I=>{const r=window.FormLogicEngine;if(!r||!r.validateFields)return;const A=r.validateFields(t,g[C]||[]);A.valid||(I.preventDefault(),I.stopImmediatePropagation(),G(t,A.missing),K(A))},B=()=>{const I=g[C]||o;le(t,e),Q(t,e,I),w(t,I),U(t,I),e.honeypot!==!1&&h(t),M&&M.destroy(),M=b(D?.getStepData?D.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(r=>r.addEventListener("click",z,!0))};D=F.wizard(t,{schema:{steps:m},layout:f,columns:a,finishText:e.submitText||"Finish",onSubmit:i,onStepChange:I=>{C=I,setTimeout(B,0)}}),t.addEventListener("dm-form-trigger",I=>{if(I.detail?.type!=="goto-step"||!D?.goToStep)return;const r=Number(I.detail.action.step);!Number.isFinite(r)||r<0||r>=m.length||r!==C&&D.goToStep(r)}),Promise.resolve(D).then(B)}else if(F.render){const d=F.render(t,y(o,a),L(o),{submitText:e.submitText||"Submit",layout:f,columns:a,onSubmit:i});Promise.resolve(d).then(function(){ce(t,e,f),Q(t,e,o),w(t,o),U(t,o),e.honeypot!==!1&&h(t),b()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();function de(p,c){const x=document.body,y=x.classList,L=new Set((x.dataset.railSite||"").split(" ").filter(Boolean)),w=()=>window.matchMedia("(min-width: 993px)").matches;p.querySelectorAll(".navbar-link, .navbar-dropdown-toggle").forEach(a=>{const f=a.textContent.trim();f&&(a.setAttribute("title",f),a.querySelector("svg, [data-icon]")||(a.dataset.initial=f.charAt(0).toUpperCase()))});const n=document.createElement("button");n.type="button",n.className="dm-nav-collapse-toggle";const t=()=>{const a=y.contains("dm-vnav-collapsed");n.setAttribute("aria-pressed",String(a)),n.setAttribute("aria-label",a?"Expand menu":"Collapse menu"),n.title=n.getAttribute("aria-label");const f=c?"chevrons-left":"chevrons-right",v=c?"chevrons-right":"chevrons-left";n.innerHTML=`<span data-icon="${a?f:v}"></span>`,window.Domma&&Domma.icons&&Domma.icons.scan(n)},s=a=>{y.toggle("dm-vnav-collapsed",a),S.set("nav_collapsed",a),t()};n.addEventListener("click",()=>s(!y.contains("dm-vnav-collapsed"))),t();const o=p.querySelector(".navbar-container")||p;o.insertBefore(n,o.firstChild?.nextSibling||null);const e=a=>{y.toggle("dm-vnav-autohide",a),y.toggle("dm-vnav-collapsible",!a&&L.has("collapsible")),a?y.remove("dm-vnav-collapsed"):L.has("collapsible")&&S.get("nav_collapsed")===!0&&y.add("dm-vnav-collapsed"),p.classList.remove("dm-nav-revealed"),t()};p.addEventListener("pointerdown",a=>{y.contains("dm-vnav-autohide")&&a.pointerType!=="mouse"&&!p.classList.contains("dm-nav-revealed")&&(p.classList.add("dm-nav-revealed"),a.preventDefault())}),document.addEventListener("pointerdown",a=>{p.contains(a.target)||p.classList.remove("dm-nav-revealed")}),window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const a=y.contains("dm-vnav-autohide"),f=y.contains("dm-vnav-collapsed"),v=S.has("nav_autohide")||S.has("nav_collapsed");return[{header:"Menu"},{label:f?"Expand menu":"Collapse to icons",icon:f?"maximize":"minimize",disabled:!w()||a||!L.has("collapsible"),action:()=>s(!f)},{label:a?"Keep on screen":"Hide when not in use",icon:a?"eye":"eye-off",disabled:!w(),action:()=>{S.set("nav_autohide",!a),e(!a)}},{type:"divider"},{label:"Reset to the site's setting",icon:"refresh",disabled:!v,action:()=>{S.remove("nav_autohide"),S.remove("nav_collapsed"),e(L.has("autohide")),y.toggle("dm-vnav-collapsed",!L.has("autohide")&&L.has("start-collapsed")),t()}}]}})}function me(p){p.classList.add("dm-nav-scroll-hide");let c=window.scrollY,x=!1;window.addEventListener("scroll",()=>{x||(x=!0,requestAnimationFrame(()=>{x=!1;const y=window.scrollY,L=p.matches(":focus-within")||p.querySelector(".navbar-dropdown.open, .navbar-collapse.show");y>c&&y>p.offsetHeight&&!L?p.classList.add("dm-nav-scrolled-away"):y<c&&p.classList.remove("dm-nav-scrolled-away"),c=y}))},{passive:!0})}function ue(p){let c={};try{c=JSON.parse(p.dataset.contents||"{}")}catch{}const x=p.closest(".site-main"),y=document.querySelector(".site-content"),L=new Set(String(c.exclude||"").split(",").map(i=>i.trim().toLowerCase()).filter(Boolean)),w=i=>!i.closest(".hero, .card, .accordion, .tabs, figure, #site-sidebar"),n=i=>(y?[...y.querySelectorAll(i)]:[]).filter(w).filter(u=>!L.has(u.textContent.trim().toLowerCase())),t=c.headings==="h2"?n("h2"):c.headings==="h3"?n("h3"):c.headings==="h2h3"?n("h2, h3"):n("h2").length?n("h2"):n("h3");if(!t.length){x?.classList.add("no-sidebar-items");return}const s=new Set([...document.querySelectorAll("[id]")].map(i=>i.id)),o=document.createElement("nav");o.className="dm-contents",o.setAttribute("aria-label",c.title||"Page contents"),c.hover&&(o.dataset.menuHover=c.hover),c.selected&&(o.dataset.menuActive=c.selected),c.accent&&o.style.setProperty("--dm-menu-highlight",c.accent.startsWith("#")?c.accent:`var(--dm-${c.accent})`),c.font&&(o.style.fontFamily=c.font),c.fontSize&&(o.style.fontSize=c.fontSize),c.fontWeight&&(o.style.fontWeight=c.fontWeight);const e=document.createElement("div");e.className="dm-contents-head";const a=document.createElement("p");a.className="dm-contents-title",a.textContent=c.title||"",e.appendChild(a),o.appendChild(e);const f=document.createElement("ol");f.className="dm-contents-list"+(c.numbered?" is-numbered":"");const v=[];for(const i of t){if(!i.id){const b=(i.textContent||"").toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"section";let l=b;for(let d=2;s.has(l);d++)l=`${b}-${d}`;s.add(l),i.id=l}const u=document.createElement("li");u.className=`dm-contents-item dm-contents-${i.tagName.toLowerCase()}`;const h=document.createElement("a");h.href=`#${i.id}`,h.textContent=i.textContent.trim(),u.appendChild(h),f.appendChild(u),v.push([i,h])}if(o.appendChild(f),p.replaceChildren(o),c.scrollSpy!==!1&&"IntersectionObserver"in window){const i=new Map,u=()=>{const b=v.find(([l])=>i.get(l))||null;v.forEach(([,l])=>{const d=b&&l===b[1];l.classList.toggle("is-active",!!d),d?l.setAttribute("aria-current","location"):l.removeAttribute("aria-current")})},h=new IntersectionObserver(b=>{b.forEach(l=>i.set(l.target,l.isIntersecting)),u()},{rootMargin:"-80px 0px -60% 0px"});v.forEach(([b])=>h.observe(b))}if(x?.classList.contains("contents-collapsible")){const i=document.createElement("button");i.type="button",i.className="dm-contents-toggle";const u=()=>{const h=x.classList.contains("contents-collapsed");i.setAttribute("aria-expanded",String(!h)),i.setAttribute("aria-label",h?"Show the contents":"Hide the contents"),i.title=i.getAttribute("aria-label"),i.innerHTML=`<span data-icon="${h?"list":"x"}"></span>`,window.Domma?.icons&&Domma.icons.scan(i)};i.addEventListener("click",()=>{S.set("contents_collapsed",x.classList.toggle("contents-collapsed")),u()}),u(),e.insertBefore(i,e.firstChild)}if(x?.classList.contains("contents-floating")&&c.movable){o.classList.add("is-movable");const i=S.get("contents_position");i&&Number.isFinite(i.x)&&Object.assign(p.style,{left:`${i.x}px`,top:`${i.y}px`,right:"auto",bottom:"auto"}),e.addEventListener("pointerdown",u=>{if(u.target.closest("button"))return;const h=p.getBoundingClientRect(),b=u.clientX-h.left,l=u.clientY-h.top,d=g=>{const C=Math.max(0,Math.min(window.innerWidth-h.width,g.clientX-b)),M=Math.max(0,Math.min(window.innerHeight-40,g.clientY-l));Object.assign(p.style,{left:`${C}px`,top:`${M}px`,right:"auto",bottom:"auto"})},m=()=>{document.removeEventListener("pointermove",d),S.set("contents_position",{x:parseInt(p.style.left,10),y:parseInt(p.style.top,10)})};document.addEventListener("pointermove",d),document.addEventListener("pointerup",m,{once:!0})})}window.E&&typeof E.contextMenu=="function"&&E.contextMenu(p,{items:()=>{const i=x?.classList.contains("contents-collapsible"),u=x?.classList.contains("contents-collapsed"),h=v.find(([,b])=>b.classList.contains("is-active"));return[{header:"Contents"},...i?[{label:u?"Show the contents":"Collapse to a button",icon:u?"list":"minimize",action:()=>p.querySelector(".dm-contents-toggle")?.click()}]:[],{label:"Copy a link to this section",icon:"link",disabled:!h,action:async()=>{const b=`${location.origin}${location.pathname}#${h[0].id}`;try{await _.copyToClipboard(b),E.toast("Link copied.",{type:"success"})}catch{E.toast("Could not copy the link.",{type:"error"})}}},{label:"Back to the top",icon:"arrow-up",action:()=>window.scrollTo({top:0,behavior:"smooth"})}]}}),x?.classList.contains("contents-autohide")&&(p.addEventListener("pointerdown",i=>{i.pointerType!=="mouse"&&!p.classList.contains("is-revealed")&&(p.classList.add("is-revealed"),i.preventDefault())}),document.addEventListener("pointerdown",i=>{p.contains(i.target)||p.classList.remove("is-revealed")}))}
|
|
@@ -139,7 +139,10 @@ export async function actionsRoutes(fastify, opts = {}) {
|
|
|
139
139
|
// Static sub-route declared before parameterised :slug for radix-tree priority
|
|
140
140
|
fastify.get('/actions/collection/:collectionSlug', canRead, async (request, reply) => {
|
|
141
141
|
try {
|
|
142
|
-
|
|
142
|
+
// canRun: whether this person is under the action's "Who can run it", so the
|
|
143
|
+
// entries screen offers only the actions that will run (the execute route checks).
|
|
144
|
+
const list = await listActionsForCollection(request.params.collectionSlug);
|
|
145
|
+
return list.map(a => ({...a, canRun: canRunAction(request.user, a)}));
|
|
143
146
|
} catch (err) {
|
|
144
147
|
return reply.status(503).send({ error: err.message });
|
|
145
148
|
}
|
|
@@ -186,9 +189,22 @@ export async function actionsRoutes(fastify, opts = {}) {
|
|
|
186
189
|
const { entryId } = request.body || {};
|
|
187
190
|
if (!entryId) return reply.status(400).send({ error: 'entryId is required' });
|
|
188
191
|
|
|
192
|
+
// The action's own "Who can run it" applies in the admin too: holding the actions
|
|
193
|
+
// permission lets you see and edit actions, not run every one of them.
|
|
194
|
+
let action;
|
|
195
|
+
try {
|
|
196
|
+
action = await getAction(request.params.slug);
|
|
197
|
+
} catch (err) {
|
|
198
|
+
return reply.status(503).send({ error: err.message });
|
|
199
|
+
}
|
|
200
|
+
if (!action) return reply.status(404).send({ error: 'Action not found' });
|
|
201
|
+
if (!canRunAction(request.user, action)) {
|
|
202
|
+
return reply.status(403).send({ error: 'Your role is not one that may run this action.' });
|
|
203
|
+
}
|
|
204
|
+
|
|
189
205
|
try {
|
|
190
206
|
const result = await executeAction(
|
|
191
|
-
|
|
207
|
+
action.slug,
|
|
192
208
|
entryId,
|
|
193
209
|
{ user: request.user || null }
|
|
194
210
|
);
|
|
@@ -277,7 +293,20 @@ export async function actionsRoutes(fastify, opts = {}) {
|
|
|
277
293
|
}
|
|
278
294
|
|
|
279
295
|
try {
|
|
280
|
-
|
|
296
|
+
const result = await executeAction(action.slug, entryId, { user, scope });
|
|
297
|
+
// A step failed: say so with a failure status, so the page's button does not
|
|
298
|
+
// report success. The step's own error stays in the log - it can carry detail
|
|
299
|
+
// (a mail server's reply, a webhook address) a visitor should not see.
|
|
300
|
+
if (result?.success === false) {
|
|
301
|
+
const failed = result.results?.find(r => !r.success);
|
|
302
|
+
request.log.warn({action: action.slug, entryId, step: failed?.type, error: failed?.error},
|
|
303
|
+
'action did not finish');
|
|
304
|
+
return reply.status(422).send({
|
|
305
|
+
error: 'That did not finish - something went wrong part-way through. Please try again later.',
|
|
306
|
+
stepsCompleted: result.stepsCompleted
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
return result;
|
|
281
310
|
} catch (err) {
|
|
282
311
|
return reply.status(executeErrorStatus(err)).send({ error: err.message });
|
|
283
312
|
}
|
|
@@ -410,7 +410,7 @@ export async function renderPage(page, opts = {}) {
|
|
|
410
410
|
? `window.__CMS_CTXMENUS__ = ${JSON.stringify(ctxMenus).replace(/<\/script>/gi, '<\\/script>')};`
|
|
411
411
|
: '';
|
|
412
412
|
const ctxMenusModule = ctxMenus.length
|
|
413
|
-
? '<script src="/public/js/context-menus.js?v=
|
|
413
|
+
? '<script src="/public/js/context-menus.js?v=20261012-run-action" type="module"></script>'
|
|
414
414
|
: '';
|
|
415
415
|
|
|
416
416
|
const vars = {
|
|
@@ -1159,7 +1159,7 @@ export async function renderBlogPage(templatePath, data = {}, seoMeta = {}) {
|
|
|
1159
1159
|
? `window.__CMS_CTXMENUS__ = ${JSON.stringify(ctxMenus).replace(/<\/script>/gi, '<\\/script>')};`
|
|
1160
1160
|
: '';
|
|
1161
1161
|
const ctxMenusModule = ctxMenus.length
|
|
1162
|
-
? '<script src="/public/js/context-menus.js?v=
|
|
1162
|
+
? '<script src="/public/js/context-menus.js?v=20261012-run-action" type="module"></script>'
|
|
1163
1163
|
: '';
|
|
1164
1164
|
|
|
1165
1165
|
const vars = {
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
</script>
|
|
174
174
|
|
|
175
175
|
<!-- Site initialisation -->
|
|
176
|
-
<script src="/public/js/site.js?v=
|
|
176
|
+
<script src="/public/js/site.js?v=20261012-action-results" type="module"></script>
|
|
177
177
|
<script src="/public/js/collection-context.js?v=20261010-utf8-payloads" type="module"></script>
|
|
178
178
|
{{ctxMenusModule}}
|
|
179
179
|
|