domma-cms 0.117.0 → 0.119.0

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.
@@ -1,25 +1,25 @@
1
- import{api as C}from"../api.js";import{colourToCss as wt,HIGHLIGHT_HOVER as tt,HIGHLIGHT_ACTIVE as nt,HIGHLIGHT_HOVER_LABELS as ot,HIGHLIGHT_ACTIVE_LABELS as at}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{openIconPicker as kt}from"../lib/card-builder.js";import{sortableMenuRows as St}from"../lib/menu-drag.js";import{placeTools as $t,ensureLockedTools as xt,isLockedUrl as Et,groupKeyFor as At,slugify as Lt,GROUP_ICON as _t,TOOLS_FOLDER_KEY as Ct}from"../lib/sidebar-grouping.js";import{flatten as it,nest as Ht,uid as Ee}from"../lib/menu-rows.js";import{addBannerAction as Be}from"../lib/plugin-chrome.js";import{helpPopovers as It}from"../lib/help-popover.js";import{onceClosed as Rt,openMenuAt as ze,sidebarCount as Tt}from"../lib/tool-kit.js";import{addChild as jt,bindingFrom as Dt,duplicateRow as Nt,indentRow as Ot,insertBelow as Pt,isStructural as oe,menuFromForm as Ft,menuProblems as st,moveRow as lt,outdentRow as Bt,siblingsOf as zt,snapshot as Ae}from"../lib/menu-editor-arrange.js";import{fmtDateTime as Mt}from"../lib/dates.js";const Kt=760,Wt="admin-sidebar",qt=/^\/menus\/(new|edit\/[^?#]+)(\?.*)?$/;function y(t){return String(t||"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}const Le=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function Ut(t,d){let s=0,l=d.find(i=>i.id===t);for(;l&&l.parentId;)s++,l=d.find(i=>i.id===l.parentId);return s}function rt(t){const d=new Set,s=new Set,l=i=>{for(const g of t.filter(k=>k.parentId===i))!g.type&&Et(g.url)&&!s.has(g.url)&&(s.add(g.url),d.add(g.id)),l(g.id)};return l(null),d}const Me='<button type="button" class="btn btn-sm btn-ghost mex-kebab" aria-label="Actions" title="Actions (right-click, or Shift+F10)">\u22EE</button>';function Gt(t,d,s=!1){const l=s?rt(d):new Set,i=[];function g(k){for(const f of d.filter(N=>N.parentId===k)){const _=`style="margin-left:${Ut(f.id,d)*28}px"`;if(f.type==="separator"){i.push(`
1
+ import{api as j}from"../api.js";import{colourToCss as kt,HIGHLIGHT_HOVER as st,HIGHLIGHT_ACTIVE as lt,HIGHLIGHT_HOVER_LABELS as it,HIGHLIGHT_ACTIVE_LABELS as rt,cssClassProblems as ct,normaliseCssClasses as St}from"/public/js/menu-decor.mjs?v=20261009-menu-classes";import{openIconPicker as $t}from"../lib/card-builder.js";import{sortableMenuRows as xt}from"../lib/menu-drag.js";import{placeTools as Et,ensureLockedTools as At,isLockedUrl as Ct,groupKeyFor as Lt,slugify as _t,GROUP_ICON as It,TOOLS_FOLDER_KEY as Ht}from"../lib/sidebar-grouping.js";import{flatten as dt,nest as Rt,uid as _e}from"../lib/menu-rows.js";import{addBannerAction as We}from"../lib/plugin-chrome.js";import{helpPopovers as Tt}from"../lib/help-popover.js";import{onceClosed as jt,openMenuAt as qe,sidebarCount as Dt}from"../lib/tool-kit.js";import{addChild as Nt,bindingFrom as Ot,duplicateRow as Pt,indentRow as Ft,insertBelow as Bt,isStructural as ne,menuFromForm as zt,menuProblems as Mt,moveRow as ut,outdentRow as Kt,siblingsOf as Wt,snapshot as Ie}from"../lib/menu-editor-arrange.js";import{fmtDateTime as qt}from"../lib/dates.js";const Ut=760,Gt="admin-sidebar",Vt=/^\/menus\/(new|edit\/[^?#]+)(\?.*)?$/;function b(t){return String(t||"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}const He=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function Yt(t,c){let l=0,i=c.find(s=>s.id===t);for(;i&&i.parentId;)l++,i=c.find(s=>s.id===i.parentId);return l}function mt(t){const c=new Set,l=new Set,i=s=>{for(const g of t.filter(w=>w.parentId===s))!g.type&&Ct(g.url)&&!l.has(g.url)&&(l.add(g.url),c.add(g.id)),i(g.id)};return i(null),c}const Ue='<button type="button" class="btn btn-sm btn-ghost mex-kebab" aria-label="Actions" title="Actions (right-click, or Shift+F10)">\u22EE</button>';function Xt(t,c,l=!1){const i=l?mt(c):new Set,s=[];function g(w){for(const f of c.filter(P=>P.parentId===w)){const _=`style="margin-left:${Yt(f.id,c)*28}px"`;if(f.type==="separator"){s.push(`
2
2
  <div class="menu-tree-row menu-tree-row--separator" data-id="${f.id}" tabindex="0" ${_}>
3
3
  <span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
4
4
  <span class="me-sep-line"><span class="me-sep-label">Separator</span></span>
5
- ${Me}
6
- </div>`);continue}if(f.type==="spacer"){const ee=["xs","sm","md","lg","xl","flex"].map(O=>`<option value="${O}"${(f.size||"md")===O?" selected":""}>${O==="flex"?"flexible":O}</option>`).join("");i.push(`
5
+ ${Ue}
6
+ </div>`);continue}if(f.type==="spacer"){const te=["xs","sm","md","lg","xl","flex"].map(F=>`<option value="${F}"${(f.size||"md")===F?" selected":""}>${F==="flex"?"flexible":F}</option>`).join("");s.push(`
7
7
  <div class="menu-tree-row menu-tree-row--spacer" data-id="${f.id}" tabindex="0" ${_}>
8
8
  <span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
9
9
  <span class="me-spacer-line">
10
10
  <span class="me-spacer-label">Spacer</span>
11
- <select class="form-input me-spacer-size" title="Spacer size - flexible fills the leftover room" aria-label="Spacer size">${ee}</select>
11
+ <select class="form-input me-spacer-size" title="Spacer size - flexible fills the leftover room" aria-label="Spacer size">${te}</select>
12
12
  </span>
13
- ${Me}
14
- </div>`);continue}const V=f.badge&&(f.badge.text||f.badge.countFrom)?`<span class="dm-menu-badge">${y(String(f.badge.text||"#"))}</span>`:"",A=f.tool,h=A&&(A.persisted||f.touched),B=A?A.orphan?' <span class="badge badge-secondary me-tool-badge" title="A placeholder for a Tool that is not enabled - it returns here when it is">Not enabled</span>':` <span class="badge badge-secondary me-tool-badge" title="${h?"A Tool, placed here by this menu":"A Tool in its default place - move or edit it to place it here"}">${y(A.source||"Tool")}${h?"":" \xB7 default"}</span>`:"",ae=l.has(f.id),Z=wt(f.colour),z=Z?` style="color:${y(Z)}"`:"",ie=ae?'<button type="button" class="btn btn-sm btn-ghost" disabled title="Always shown - it can be moved, not hidden" aria-label="Always shown"><span data-icon="lock"></span></button>':`<button type="button" class="btn btn-sm btn-ghost me-hidden ${f.hidden?"active":""}" title="${f.hidden?"Hidden - click to show":"Hide"}" aria-label="${f.hidden?"Show":"Hide"}" aria-pressed="${f.hidden?"true":"false"}"><span data-icon="${f.hidden?"eye-off":"eye"}"></span></button>`;i.push(`
13
+ ${Ue}
14
+ </div>`);continue}const Y=f.badge&&(f.badge.text||f.badge.countFrom)?`<span class="dm-menu-badge">${b(String(f.badge.text||"#"))}</span>`:"",A=f.tool,h=A&&(A.persisted||f.touched),K=A?A.orphan?' <span class="badge badge-secondary me-tool-badge" title="A placeholder for a Tool that is not enabled - it returns here when it is">Not enabled</span>':` <span class="badge badge-secondary me-tool-badge" title="${h?"A Tool, placed here by this menu":"A Tool in its default place - move or edit it to place it here"}">${b(A.source||"Tool")}${h?"":" \xB7 default"}</span>`:"",oe=i.has(f.id),ee=kt(f.colour),W=ee?` style="color:${b(ee)}"`:"",ae=oe?'<button type="button" class="btn btn-sm btn-ghost" disabled title="Always shown - it can be moved, not hidden" aria-label="Always shown"><span data-icon="lock"></span></button>':`<button type="button" class="btn btn-sm btn-ghost me-hidden ${f.hidden?"active":""}" title="${f.hidden?"Hidden - click to show":"Hide"}" aria-label="${f.hidden?"Show":"Hide"}" aria-pressed="${f.hidden?"true":"false"}"><span data-icon="${f.hidden?"eye-off":"eye"}"></span></button>`;s.push(`
15
15
  <div class="menu-tree-row menu-tree-row--slim${f.hidden?" menu-tree-row--hidden":""}${A?" menu-tree-row--tool":""}${A&&!h?" menu-tree-row--default":""}" data-id="${f.id}" tabindex="0" ${_}>
16
16
  <span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
17
- <span class="me-row-label${!f.text&&!A?" mex-untitled":""}"${z}>${y(f.text||A?.label||"(no label - click to add one)")}${V}${B}</span>
18
- <span class="me-row-url">${y(f.url||"")}</span>
19
- ${ie}
17
+ <span class="me-row-label${!f.text&&!A?" mex-untitled":""}"${W}>${b(f.text||A?.label||"(no label - click to add one)")}${Y}${K}</span>
18
+ <span class="me-row-url">${b(f.url||"")}</span>
19
+ ${ae}
20
20
  <button type="button" class="btn btn-sm btn-ghost me-edit" title="Edit" aria-label="Edit"><span data-icon="edit"></span></button>
21
- ${Me}
22
- </div>`),g(f.id)}}g(null),t.innerHTML=i.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(t)}function $(t,d={},...s){const l=document.createElement(t);Object.assign(l,d);for(const i of s)i!=null&&l.append(i);return l}function T(t,d,s){const l=$("label",{className:"form-field"},$("span",{className:"form-label",textContent:t}),d);return s&&l.append($("small",{className:"form-hint",textContent:s,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),l}function Vt(t,d){const s=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(d||[]).map(i=>[i.name,`${i.label||i.name} and above`]),...(d||[]).filter(i=>i.level!==0).map(i=>[`=${i.name}`,`${i.label||i.name} only`]),["private","Private - super-admin only"]];t&&!s.some(([i])=>i===t)&&s.push([t,`${t} (custom)`]);const l=Q(s,t||"");return l.name="visibility",l}function Q(t,d){const s=$("select",{className:"form-select"});return t.forEach(([l,i])=>s.add(new Option(i,l))),s.value=d??"",s}function _e(t,d){const s=typeof d=="string"&&d.startsWith("#"),l=Q([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],s?"__custom__":d||""),i=$("input",{type:"color",className:"form-input me-colour-hex",value:s?d:"#000000"});i.style.display=s?"":"none",l.addEventListener("change",()=>{i.style.display=l.value==="__custom__"?"":"none"});const g=T(t,l);return g.append(i),g._read=()=>l.value==="__custom__"?i.value:l.value,g}function Yt(t,d){const s=$("input",{className:"form-input me-icon",name:"icon",value:d||""}),l=$("span",{className:"me-icon-preview"});d&&l.setAttribute("data-icon",d);const i=$("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),g=k=>{k?l.setAttribute("data-icon",k):l.removeAttribute("data-icon"),Domma.icons.scan(l.parentNode||l)};return i.addEventListener("click",()=>kt(k=>{s.value=k,g(k)})),s.addEventListener("input",()=>g(s.value.trim())),T(t,$("div",{className:"me-icon-field"},s,i,l))}function Ce(...t){return $("div",{className:"me-field-grid"},...t)}async function Xt(t,d,s,l,i){const g=t.text||t.tool?.label||"",k=r=>$("h4",{className:"me-form-section",textContent:r}),f=T("Label",$("input",{className:"form-input",name:"text",value:t.text||""}),"The text shown for this item."),N=$("input",{className:"form-input",name:"url",value:t.url||""}),_=T("URL",N,t.tool||t.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(t.tool||t.locked)&&(N.readOnly=!0);const V=Yt("Icon",t.icon||""),A=Vt(t.visibility||"",l),h=T("Visibility",A,t.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');t.locked&&(A.disabled=!0);const B=Q([["","- no permission gate -"],...(d||[]).map(r=>[r.key,r.label||r.key])],t.permission||"");B.name="permission";const ae=T("Permission",B,t.tool||t.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(t.tool||t.locked)&&(B.disabled=!0);const Z=T("Badge text",$("input",{className:"form-input",name:"badgeText",value:t.badge?.text||""})),z=Q([["","- none -"],...(s||[]).map(r=>[r.slug,r.title||r.slug])],t.badge?.countFrom||"");z.name="badgeCount";const ie=T("Badge count from",z,"Show a live count of this collection\u2019s entries as the badge."),ee=_e("Badge colour",t.badge?.variant||""),O=Q([["link","Link"],["pill","Pill"]],t.pill?"pill":"link");O.name="renderAs";const He=T("Render as",O,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),K=T("Pill style",Q([["filled","Filled"],["outline","Outline"]],t.pill?.style||"filled"));K.querySelector("select").name="pillStyle";const me=_e("Pill colour",t.pill?.variant||""),se=$("div",{className:"me-pill-wrap"},Ce(K,me));se.style.display=t.pill?"":"none",O.addEventListener("change",()=>{se.style.display=O.value==="pill"?"":"none"});const m=_e("Text colour",t.colour||""),j=Q([["","- use the menu default -"],...tt.map(r=>[r,ot[r]||r])],t.highlight?.hover||"");j.name="hlHover";const le=T("Hover effect",j,"Overrides the menu-wide hover effect for this item only."),pe=Q([["","- use the menu default -"],...nt.map(r=>[r,at[r]||r])],t.highlight?.active||"");pe.name="hlActive";const be=T("When selected",pe,"How this item is marked when it points at the page being viewed."),P=_e("Highlight colour",t.highlight?.accent||""),x=$("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),W=$("div",{className:"me-item-form"},k("Link"),f,_,V,k("Access"),Ce(h,ae),k("Badge"),Ce(Z,ee),ie,k("Appearance"),He,se,m,k("Highlighting"),Ce(le,be),P,x),b=E.slideover({title:g?`Edit ${Le(g)}`:"Edit menu item",size:"lg",position:"right"});b.element.appendChild(W);const Y=()=>JSON.stringify([...W.querySelectorAll("input, select, textarea")].map(r=>r.type==="checkbox"?r.checked:r.value)),te=Y();let q=!1,re=!1;Rt(b);const ye=b.close.bind(b);b.close=async r=>{if(!q&&r!==!0&&Y()!==te){if(re)return;re=!0;const U=await E.confirm("Discard the changes to this item?");if(re=!1,!U)return}return q=!0,ye()},W.addEventListener("keydown",r=>{(r.ctrlKey||r.metaKey)&&r.key==="Enter"&&(r.preventDefault(),x.click())}),b.open();const fe=b.element.closest(".dm-slideover")||b.element.querySelector(".dm-slideover")||b.element;fe.style.setProperty("width",Kt+"px","important"),fe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(W);const L=r=>W.querySelector(`[name="${r}"]`)?.value||"";x.addEventListener("click",()=>{t.text=L("text"),t.icon=L("icon"),t.locked||(t.visibility=L("visibility")),!t.tool&&!t.locked?(t.url=L("url"),t.permission=L("permission")):t.touched=!0;const r=L("badgeText"),U=L("badgeCount"),ne=ee._read();if(t.badge=r||U?{...r&&{text:r},...U&&{countFrom:U},...ne&&{variant:ne}}:null,L("renderAs")==="pill"){const he=me._read();t.pill={style:L("pillStyle")||"filled",...he&&{variant:he}}}else t.pill=null;t.colour=m._read();const ce=L("hlHover"),de=L("hlActive"),ue=P._read();t.highlight=ce||de||ue?{...ce&&{hover:ce},...de&&{active:de},...ue&&{accent:ue}}:null,q=!0,b.close(!0),i()})}let F=null,ct=!1;function Jt(){ct||!window.R?.use||(ct=!0,R.use((t,d,s)=>{const l=d?.path||"";return!(qt.test(l)&&(t?.path||"")!==l)||!F?.dirty()?s():E.confirm(`You have unsaved changes to the menu "${Le(F.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(g=>{g?s():history.replaceState(null,"",`#${l}`)})}),M.subscribe("router:afterChange",({to:t}={})=>{if(F&&(t?.path||"")!==F.path){const d=F;F=null,d.dispose()}}))}function dt(t,d){const s=t.querySelector(".dm-plugin-banner-name"),l=s?.querySelector(".dm-plugin-banner-sep");if(!(!s||!l)){for(;l.nextSibling;)l.nextSibling.remove();s.appendChild(document.createTextNode(d))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(t){if(Jt(),F){const e=F;F=null,e.dispose()}const d=[],s=e=>(d.push(e),e);let l=!1;const i=t.get(0).querySelector(".mex")||t.get(0),g=()=>!l&&i.isConnected,k=location.hash.replace(/^#/,""),f=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),N=f?decodeURIComponent(f[1]):null,_=!N,V=`menu-editor.draft.${N||"new"}`,A=E.loader(t.get(0),{type:"dots"});let h,B,ae,Z,z,ie,ee;try{if(_)h={slug:"",name:"",description:"",items:[]};else try{h=await C.menus.get(N)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[B,ae,Z,z,ie,ee]=await Promise.all([C.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),C.collections.list().catch(()=>[]),C.get("/collections/roles/entries?limit=100").catch(()=>null),C.menuLocations.registry().catch(()=>[]),C.pages.list().catch(()=>[])])}finally{A.destroy()}if(!i.isConnected)return;const He=(Array.isArray(z)?z:z?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,n)=>n.level-e.level),K=!_&&N===Wt;let me=[];if(K&&(me=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!i.isConnected))return;const se=e=>it(K?xt($t(e||[],me,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let m=se(h.items);const j=M.observable(!1),le=M.observable(!1),pe=M.observable(""),be=M.observable(0);let P="";const x=i.querySelector("#me-items-list");function W(){Gt(x,m,K),be.value=m.filter(e=>!oe(e)).length}const b=()=>{W(),G()},Y=()=>K?rt(m):new Set,te=e=>m.find(n=>n.id===e);function q(e){requestAnimationFrame(()=>x.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function re(e){const n=v=>m.find(c=>!c.type&&!c.url&&!c.tool&&(c.key||"").toLowerCase()===v)||m.find(c=>!c.type&&!c.url&&!c.tool&&!c.key&&(c.text||"").toLowerCase()===v);let a=n(String(e.tool.folder||"").toLowerCase())||n(Ct);const p=String(e.tool.group||"").trim();if(a&&p){const v=At(a.key||Lt(a.text),p),c=u=>u!==e&&!u.type&&!u.url&&!u.tool;let w=m.find(u=>c(u)&&(u.key||"").toLowerCase()===v)||m.find(u=>c(u)&&u.parentId===a.id&&(!u.key||u.key.toLowerCase()===v)&&(u.text||"").toLowerCase()===p.toLowerCase());w||([w]=it([{text:p,key:v,icon:_t,synthesised:!0}],a.id),m.push(w)),a=w}e.parentId=a?a.id:null,m.splice(m.indexOf(e),1),m.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const ye=e=>!Y().has(e.id)&&!(e.tool&&!e.tool.orphan);async function fe(e){const n=te(e);if(!n||!ye(n))return;const a=u=>{let J=u;for(;J;){if(J.id===e)return!0;J=m.find(D=>D.id===J.parentId)}return!1},p=m.filter(u=>u.id!==e&&a(u));if(p.length&&!await E.confirm(`Remove "${Le(n.text||n.type||"this item")}" and the ${p.length} item${p.length===1?"":"s"} beneath it?`))return;const v=Y(),c=p.filter(u=>u.tool),w=p.filter(u=>!u.tool&&v.has(u.id));m=m.filter(u=>!a(u)||c.includes(u)||w.includes(u));for(const u of w)u.parentId=n.parentId??null;for(const u of c)u.tool.orphan?u.parentId=n.parentId??null:re(u);b()}function L(e){const n=te(e);!n||oe(n)||Y().has(e)||(n.hidden=!n.hidden,n.touched=!0,b())}function r(e){const n=te(e);!n||oe(n)||(n.locked=K&&Y().has(n.id),Xt(n,ae.resources||[],Z,He,()=>{b(),q(e)}))}function U(e){const n={id:Ee(),parentId:null,...e==="separator"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};m.push(n),b(),oe(n)?q(n.id):r(n.id)}const ne=e=>n=>{e(n)&&(b(),q(n))},ce=ne(e=>lt(m,e,-1)),de=ne(e=>lt(m,e,1)),ue=ne(e=>Ot(m,e)),he=ne(e=>Bt(m,e));function ut(e){const n=te(e);if(!n)return[];const a=oe(n),p=Y().has(e),v=zt(m,e),c=v.findIndex(D=>D.id===e),w=n.tool,u=w&&(w.persisted||n.touched),J=D=>()=>{const ge=Pt(m,e,D,Ee());b(),ge&&!oe(ge)?r(ge.id):ge&&q(ge.id)};return[{header:a?n.type==="separator"?"Separator":"Spacer":n.text||w?.label||"(untitled)"},...a?[]:[{label:"Edit\u2026",icon:"edit",action:()=>r(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:J("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:a,action:()=>{const D=jt(m,e,Ee());b(),D&&r(D.id)}},{label:"Add separator below",icon:"minus",action:J("separator")},{label:"Add spacer below",icon:"move",action:J("spacer")},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:c<=0,action:()=>ce(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:c<0||c>=v.length-1,action:()=>de(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:c<=0||oe(v[c-1]),action:()=>ue(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:n.parentId==null,action:()=>he(e)},{type:"divider"},...a?[]:[{label:n.hidden?"Show":"Hide",icon:n.hidden?"eye":"eye-off",disabled:p,action:()=>L(e)}],{label:"Duplicate",icon:"copy",disabled:!!w,action:()=>{const D=Nt(m,e,Ee);b(),D&&q(D.id)}},...w&&!w.orphan&&u?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{re(n),b()}}]:[],{label:p?"Remove - always in the sidebar":w&&!w.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!ye(n),action:()=>fe(e)}]}const mt=E.contextMenu(x,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>ut(e.dataset.id)});s(()=>mt?.destroy?.());const pt=St(x,()=>m,b,{items:".menu-tree-row",handle:".menu-tree-grip"});s(()=>pt?.destroy());const Ke=e=>{const n=e.target.closest(".menu-tree-row");if(!n)return;const a=n.dataset.id;if(e.target.closest(".mex-kebab")){ze(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){L(a);return}if(e.target.closest(".me-edit")){r(a);return}e.target.closest("select, .menu-tree-grip, button")||r(a)},We=e=>{const n=e.target.closest(".menu-tree-row");if(!n||e.target!==n){n&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),ze(n));return}const a=n.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ze(n);else if(e.key==="Enter")e.preventDefault(),r(a);else if(e.key==="Delete")e.preventDefault(),fe(a);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),ce(a);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),de(a);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),ue(a);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),he(a);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const p=[...x.querySelectorAll(".menu-tree-row")],v=p.indexOf(n)+(e.key==="ArrowDown"?1:-1);p[v]&&(e.preventDefault(),p[v].focus())}},qe=e=>{if(!e.target.matches(".me-spacer-size"))return;const n=te(e.target.closest(".menu-tree-row")?.dataset.id);n&&(n.size=e.target.value,G())};x.addEventListener("click",Ke),x.addEventListener("keydown",We),x.addEventListener("change",qe),s(()=>{x.removeEventListener("click",Ke),x.removeEventListener("keydown",We),x.removeEventListener("change",qe)});const o=e=>t.find(e),we=o("#me-float-accent"),Ie=o("#me-float-accent-hex"),Re=()=>{Ie.get(0).style.display=we.val()==="__custom__"?"":"none"},ft=()=>we.val()==="__custom__"?Ie.val():we.val(),ke=o("#me-highlight-accent"),Te=o("#me-highlight-accent-hex"),Ue=()=>{Te.get(0).style.display=ke.val()==="__custom__"?"":"none"},ht=()=>ke.val()==="__custom__"?Te.val():ke.val(),Ge=()=>{const e=o("#me-position").val()==="floating";o(".dm-float-field").each(function(){this.style.display=e?"":"none"}),e&&Re();const n=o("#me-orientation").val()==="vertical";o(".dm-vertical-field").each(function(){this.style.display=n?"":"none"});const a=!!(o("#me-float-collapsible").get(0)||{}).checked;o(".dm-float-collapsed-field").each(function(){this.style.display=e&&a?"":"none"})},Ve=(e,n,a,p)=>{const v=o(e).get(0);v&&(v.innerHTML="",v.add(new Option(p,"")),n.forEach(c=>v.add(new Option(a[c]||c,c))))};Ve("#me-highlight-hover",tt,ot,"- theme default -"),Ve("#me-highlight-active",nt,at,"- theme default -");const je=o("#me-bind-slot"),De=o("#me-bind-projects"),Se=o("#me-bind-pages");je.html('<option value="">- not bound -</option>'+(ie||[]).map(e=>`<option value="${y(e.slot)}">${y(e.label||e.slot)} (${y(e.slot)})</option>`).join("")),De.html(B.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join("")),o("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ee.map(e=>{const n=e.urlPath||e.url||"";return n?`<option value="${y(n)}">${y(e.title||n)} - ${y(n)}</option>`:""}).join(""));const Ye=()=>Dt({slot:je.val(),projects:Array.from(De.get(0).selectedOptions).map(e=>e.value),pagesText:Se.val()});function Ne(){const e=Ye(),n=o("#me-bind-summary");if(!e){n.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const a=[];e.projects.length&&a.push(`pages in ${e.projects.map(c=>`<code>${y(c)}</code>`).join(", ")}`),e.pages.length&&a.push(`pages matching ${e.pages.map(c=>`<code>${y(c)}</code>`).join(", ")}`);const p=e.pages.filter(c=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(c)),v=p.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${p.map(c=>`<code>${y(c)}</code>`).join(", ")}</div>`:"";n.html(a.length?`Takes over the <code>${y(e.slot)}</code> slot on ${a.join(" and ")}.${v}`:`<span class="text-warning">Slot <code>${y(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:vt}=await import("../lib/project-context.js");if(!g())return;const gt=_?vt():null;o("#me-project").html('<option value="">- none -</option>'+B.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join(""));function Oe(e){m=se(e.items),o("#me-variant").val(e.variant||""),o("#me-position").val(e.position||"");const n=o("#me-appearOnHover").get(0);n&&(n.checked=e.appearOnHover===!0),o("#me-float-anchor").val(e.float?.anchor||"TL"),o("#me-float-offsetX").val(e.float?.offsetX??""),o("#me-float-offsetY").val(e.float?.offsetY??""),o("#me-float-width").val(e.float?.width??""),o("#me-float-radius").val(e.float?.radius??""),o("#me-float-shadow").val(e.float?.shadow||""),o("#me-float-opacity").val(e.float?.opacity??""),o("#me-float-title").val(e.float?.title||"");for(const[c,w]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const u=o(c).get(0);u&&(u.checked=w===!0)}const a=e.float?.accent||"";we.val(a.startsWith("#")?"__custom__":a),a.startsWith("#")&&Ie.val(a),Re(),o("#me-orientation").val(e.orientation||""),o("#me-align").val(e.align||""),o("#me-side").val(e.side||"left"),o("#me-highlight-hover").val(e.highlight?.hover||""),o("#me-highlight-active").val(e.highlight?.active||"");const p=e.highlight?.accent||"";ke.val(p.startsWith("#")?"__custom__":p),p.startsWith("#")&&Te.val(p),Ue(),o("#me-fontFamily").val(e.style?.fontFamily||""),o("#me-fontSize").val(e.style?.fontSize||""),o("#me-fontWeight").val(e.style?.fontWeight||""),o("#me-letterSpacing").val(e.style?.letterSpacing||""),o("#me-iconSize").val(e.style?.iconSize||""),je.val(e.binding?.slot||"");const v=new Set(e.binding?.projects||[]);Array.from(De.get(0).options).forEach(c=>{c.selected=v.has(c.value)}),Se.val((e.binding?.pages||[]).join(`
23
- `)),o("#me-slug").val(e.slug||""),o("#me-name").val(e.name||""),o("#me-description").val(e.description||""),o("#me-project").val(e.meta?.project||gt||""),Ge(),Ne(),W()}const ve=e=>!!(o(e).get(0)||{}).checked;function $e(){const e={variant:o("#me-variant").val(),position:o("#me-position").val(),appearOnHover:ve("#me-appearOnHover"),floatAnchor:o("#me-float-anchor").val(),floatOffsetX:o("#me-float-offsetX").val(),floatOffsetY:o("#me-float-offsetY").val(),floatWidth:o("#me-float-width").val(),floatRadius:o("#me-float-radius").val(),floatShadow:o("#me-float-shadow").val(),floatAccent:ft(),floatOpacity:o("#me-float-opacity").val(),floatTitle:o("#me-float-title").val(),floatCollapsible:ve("#me-float-collapsible"),floatCollapsed:ve("#me-float-collapsed"),floatMovable:ve("#me-float-movable"),floatResizable:ve("#me-float-resizable"),highlightHover:o("#me-highlight-hover").val(),highlightActive:o("#me-highlight-active").val(),highlightAccent:ht(),orientation:o("#me-orientation").val(),align:o("#me-align").val(),side:o("#me-side").val(),fontFamily:o("#me-fontFamily").val(),fontSize:o("#me-fontSize").val(),fontWeight:o("#me-fontWeight").val(),letterSpacing:o("#me-letterSpacing").val(),iconSize:o("#me-iconSize").val()},n={slug:o("#me-slug").val(),name:o("#me-name").val(),description:o("#me-description").val(),project:o("#me-project").val()};return Ft(e,n,Ye(),Ht(m),h.meta||{})}let Xe=!1,Pe=null;function G(){if(!P)return;const e=$e();Pe=e,j.value=Ae(e)!==P,pe.value=j.peek()||Xe?st(e).join(" "):""}const xe=e=>{e.target.closest("#me-items-list")||(e.target.matches("#me-position, #me-orientation, #me-float-collapsible")&&Ge(),e.target.matches("#me-float-accent")&&Re(),e.target.matches("#me-highlight-accent")&&Ue(),e.target.closest("#me-binding")&&Ne(),G())};i.addEventListener("input",xe),i.addEventListener("change",xe),s(()=>{i.removeEventListener("input",xe),i.removeEventListener("change",xe)}),o("#me-bind-page-add").on("click",()=>{const e=o("#me-bind-page-pick").val();if(!e)return;const n=Se.val().split(`
24
- `).map(a=>a.trim()).filter(Boolean);n.includes(e)||n.push(e),Se.val(n.join(`
25
- `)),Ne(),G()}),Oe(h),P=Ae($e()),G();const Je=()=>{try{S.remove?S.remove(V):S.set(V,null)}catch{}};async function Fe(){if(le.peek())return;const e=$e(),n=st(e);if(n.length){Xe=!0,G(),E.toast(n.join(" "),{type:"warning",duration:7e3});return}le.value=!0;try{if(_)await C.menus.create(e);else if(e.slug!==h.slug){await C.menus.create(e);const a=await C.menuLocations.get();let p=!1;for(const[v,c]of Object.entries(a))c===h.slug&&(a[v]=e.slug,p=!0);p&&await C.menuLocations.save(a),await C.menus.remove(h.slug)}else await C.menus.update(h.slug,e);if(P=Ae(e),j.value=!1,Je(),Tt("#/menus"),E.toast("Saved.",{type:"success"}),_||e.slug!==h.slug)location.hash="#/menus/edit/"+encodeURIComponent(e.slug);else{h={...h,...e};for(const a of m)a.tool&&a.touched&&(a.tool={...a.tool,persisted:!0});W(),P=Ae($e()),G(),dt(t.get(0),e.name||e.slug)}if(K)try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}catch(a){E.toast(`Save failed: ${a.message||a}`,{type:"error"})}finally{le.value=!1}}async function bt(){!j.peek()||!await E.confirm("Throw away the changes you have not saved?")||(Oe(h),G())}E.tabs(o("#me-tabs").get(0));const yt=M.applyBindings({dirty:j,saving:le,problems:pe,itemCount:be},i,{methods:{save:()=>Fe(),discard:()=>bt(),addItem:()=>U("item"),addSeparator:()=>U("separator"),addSpacer:()=>U("spacer")}});s(()=>yt.dispose()),s(It(i,{position:"bottom"})),dt(t.get(0),_?"New menu":h.name||h.slug),Be(t,{id:"menu-editor-back",icon:"arrow-left",title:"All menus",onClick:()=>{location.hash="#/menus"}}),Be(t,{id:"menu-editor-locations",icon:"map-pin",title:"Menu locations",onClick:()=>{location.hash="#/menu-locations"}}),Be(t,{id:"menu-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>Fe()});const Qe=e=>{if(!(!(e.ctrlKey||e.metaKey)||e.key!=="s")){if(e.preventDefault(),e.stopImmediatePropagation(),document.querySelector(".me-item-form")?.offsetParent){E.toast("Apply the item first (Ctrl+Enter), then Save.",{type:"info"});return}Fe()}};document.addEventListener("keydown",Qe,!0),s(()=>document.removeEventListener("keydown",Qe,!0));const Ze=()=>{if(!(!j.peek()||!Pe))try{S.set(V,{menu:Pe,base:P,at:new Date().toISOString()})}catch{}},et=e=>{j.peek()&&(Ze(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",et),s(()=>window.removeEventListener("beforeunload",et)),F={path:k,dirty:()=>j.peek(),name:()=>o("#me-name").val()||h.name||h.slug||"new menu",dispose(){l=!0,Ze(),d.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(i);let X=null;try{X=S.get(V)}catch{}if(X?.menu){Je();const e=X.base&&X.base!==P,n=X.at?` (${Mt(X.at)})`:"",a=_?"the new menu you started":`the menu "${Le(h.name||h.slug)}"`,p=e?`You left unsaved changes to ${a}${n}, but the saved menu has changed since. Restore your version anyway?`:`You left unsaved changes to ${a}${n}. Restore them?`;await E.confirm(p)&&g()&&(Oe({...X.menu,meta:{...h.meta||{},...X.menu.meta||{}}}),G())}}};
21
+ ${Ue}
22
+ </div>`),g(f.id)}}g(null),t.innerHTML=s.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(t)}function y(t,c={},...l){const i=document.createElement(t);Object.assign(i,c);for(const s of l)s!=null&&i.append(s);return i}function T(t,c,l){const i=y("label",{className:"form-field"},y("span",{className:"form-label",textContent:t}),c);return l&&i.append(y("small",{className:"form-hint",textContent:l,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),i}function Jt(t,c){const l=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(c||[]).map(s=>[s.name,`${s.label||s.name} and above`]),...(c||[]).filter(s=>s.level!==0).map(s=>[`=${s.name}`,`${s.label||s.name} only`]),["private","Private - super-admin only"]];t&&!l.some(([s])=>s===t)&&l.push([t,`${t} (custom)`]);const i=Z(l,t||"");return i.name="visibility",i}function Z(t,c){const l=y("select",{className:"form-select"});return t.forEach(([i,s])=>l.add(new Option(s,i))),l.value=c??"",l}function Re(t,c){const l=typeof c=="string"&&c.startsWith("#"),i=Z([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],l?"__custom__":c||""),s=y("input",{type:"color",className:"form-input me-colour-hex",value:l?c:"#000000"});s.style.display=l?"":"none",i.addEventListener("change",()=>{s.style.display=i.value==="__custom__"?"":"none"});const g=T(t,i);return g.append(s),g._read=()=>i.value==="__custom__"?s.value:i.value,g}function Qt(t,c){const l=y("input",{className:"form-input me-icon",name:"icon",value:c||""}),i=y("span",{className:"me-icon-preview"});c&&i.setAttribute("data-icon",c);const s=y("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),g=w=>{w?i.setAttribute("data-icon",w):i.removeAttribute("data-icon"),Domma.icons.scan(i.parentNode||i)};return s.addEventListener("click",()=>$t(w=>{l.value=w,g(w)})),l.addEventListener("input",()=>g(l.value.trim())),T(t,y("div",{className:"me-icon-field"},l,s,i))}function Te(...t){return y("div",{className:"me-field-grid"},...t)}async function Zt(t,c,l,i,s){const g=t.text||t.tool?.label||"",w=u=>y("h4",{className:"me-form-section",textContent:u}),f=T("Label",y("input",{className:"form-input",name:"text",value:t.text||""}),"The text shown for this item."),P=y("input",{className:"form-input",name:"url",value:t.url||""}),_=T("URL",P,t.tool||t.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(t.tool||t.locked)&&(P.readOnly=!0);const Y=Qt("Icon",t.icon||""),A=Jt(t.visibility||"",i),h=T("Visibility",A,t.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');t.locked&&(A.disabled=!0);const K=Z([["","- no permission gate -"],...(c||[]).map(u=>[u.key,u.label||u.key])],t.permission||"");K.name="permission";const oe=T("Permission",K,t.tool||t.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(t.tool||t.locked)&&(K.disabled=!0);const ee=T("Badge text",y("input",{className:"form-input",name:"badgeText",value:t.badge?.text||""})),W=Z([["","- none -"],...(l||[]).map(u=>[u.slug,u.title||u.slug])],t.badge?.countFrom||"");W.name="badgeCount";const ae=T("Badge count from",W,"Show a live count of this collection\u2019s entries as the badge."),te=Re("Badge colour",t.badge?.variant||""),F=Z([["link","Link"],["pill","Pill"]],t.pill?"pill":"link");F.name="renderAs";const je=T("Render as",F,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),q=T("Pill style",Z([["filled","Filled"],["outline","Outline"]],t.pill?.style||"filled"));q.querySelector("select").name="pillStyle";const me=Re("Pill colour",t.pill?.variant||""),se=y("div",{className:"me-pill-wrap"},Te(q,me));se.style.display=t.pill?"":"none",F.addEventListener("change",()=>{se.style.display=F.value==="pill"?"":"none"});const m=Re("Text colour",t.colour||""),D=Z([["","- use the menu default -"],...st.map(u=>[u,it[u]||u])],t.highlight?.hover||"");D.name="hlHover";const le=T("Hover effect",D,"Overrides the menu-wide hover effect for this item only."),pe=Z([["","- use the menu default -"],...lt.map(u=>[u,rt[u]||u])],t.highlight?.active||"");pe.name="hlActive";const Se=T("When selected",pe,"How this item is marked when it points at the page being viewed."),B=Re("Highlight colour",t.highlight?.accent||""),C=y("input",{className:"form-input",name:"class",value:t.class||"",placeholder:"nav-cta push-right",autocomplete:"off",spellcheck:!1}),ie=T("CSS classes",C,"Your own class names, separated by spaces, added to this item's <li> - target the link with .your-class > a. Style them in Custom CSS."),L=y("small",{className:"text-danger",style:"display:none;margin-top:.25rem"});ie.append(L);const U=y("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),N=y("div",{className:"me-item-form"},w("Link"),f,_,Y,w("Access"),Te(h,oe),w("Badge"),Te(ee,te),ae,w("Appearance"),je,se,m,w("Highlighting"),Te(le,Se),B,w("Styling"),ie,U),x=E.slideover({title:g?`Edit ${He(g)}`:"Edit menu item",size:"lg",position:"right"});x.element.appendChild(N);const fe=()=>JSON.stringify([...N.querySelectorAll("input, select, textarea")].map(u=>u.type==="checkbox"?u.checked:u.value)),$e=fe();let re=!1,ce=!1;jt(x);const G=x.close.bind(x);x.close=async u=>{if(!re&&u!==!0&&fe()!==$e){if(ce)return;ce=!0;const X=await E.confirm("Discard the changes to this item?");if(ce=!1,!X)return}return re=!0,G()},N.addEventListener("keydown",u=>{(u.ctrlKey||u.metaKey)&&u.key==="Enter"&&(u.preventDefault(),U.click())}),x.open();const de=x.element.closest(".dm-slideover")||x.element.querySelector(".dm-slideover")||x.element;de.style.setProperty("width",Ut+"px","important"),de.style.setProperty("max-width","95vw","important"),Domma.icons.scan(N);const k=u=>N.querySelector(`[name="${u}"]`)?.value||"";U.addEventListener("click",()=>{const u=ct(k("class"));if(u.length){L.textContent=u.join("; "),L.style.display="block",C.focus();return}t.class=St(k("class")),t.text=k("text"),t.icon=k("icon"),t.locked||(t.visibility=k("visibility")),!t.tool&&!t.locked?(t.url=k("url"),t.permission=k("permission")):t.touched=!0;const X=k("badgeText"),ue=k("badgeCount"),he=te._read();if(t.badge=X||ue?{...X&&{text:X},...ue&&{countFrom:ue},...he&&{variant:he}}:null,k("renderAs")==="pill"){const ye=me._read();t.pill={style:k("pillStyle")||"filled",...ye&&{variant:ye}}}else t.pill=null;t.colour=m._read();const ve=k("hlHover"),ge=k("hlActive"),be=B._read();t.highlight=ve||ge||be?{...ve&&{hover:ve},...ge&&{active:ge},...be&&{accent:be}}:null,re=!0,x.close(!0),s()})}let z=null,pt=!1;function en(){pt||!window.R?.use||(pt=!0,R.use((t,c,l)=>{const i=c?.path||"";return!(Vt.test(i)&&(t?.path||"")!==i)||!z?.dirty()?l():E.confirm(`You have unsaved changes to the menu "${He(z.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(g=>{g?l():history.replaceState(null,"",`#${i}`)})}),M.subscribe("router:afterChange",({to:t}={})=>{if(z&&(t?.path||"")!==z.path){const c=z;z=null,c.dispose()}}))}function ft(t,c){const l=t.querySelector(".dm-plugin-banner-name"),i=l?.querySelector(".dm-plugin-banner-sep");if(!(!l||!i)){for(;i.nextSibling;)i.nextSibling.remove();l.appendChild(document.createTextNode(c))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(t){if(en(),z){const e=z;z=null,e.dispose()}const c=[],l=e=>(c.push(e),e);let i=!1;const s=t.get(0).querySelector(".mex")||t.get(0),g=()=>!i&&s.isConnected,w=location.hash.replace(/^#/,""),f=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),P=f?decodeURIComponent(f[1]):null,_=!P,Y=`menu-editor.draft.${P||"new"}`,A=E.loader(t.get(0),{type:"dots"});let h,K,oe,ee,W,ae,te;try{if(_)h={slug:"",name:"",description:"",items:[]};else try{h=await j.menus.get(P)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[K,oe,ee,W,ae,te]=await Promise.all([j.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),j.collections.list().catch(()=>[]),j.get("/collections/roles/entries?limit=100").catch(()=>null),j.menuLocations.registry().catch(()=>[]),j.pages.list().catch(()=>[])])}finally{A.destroy()}if(!s.isConnected)return;const je=(Array.isArray(W)?W:W?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,n)=>n.level-e.level),q=!_&&P===Gt;let me=[];if(q&&(me=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!s.isConnected))return;const se=e=>dt(q?At(Et(e||[],me,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let m=se(h.items);const D=M.observable(!1),le=M.observable(!1),pe=M.observable(""),Se=M.observable(0);let B="";const C=s.querySelector("#me-items-list");function ie(){Xt(C,m,q),Se.value=m.filter(e=>!ne(e)).length}const L=()=>{ie(),V()},U=()=>q?mt(m):new Set,N=e=>m.find(n=>n.id===e);function x(e){requestAnimationFrame(()=>C.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function fe(e){const n=v=>m.find(r=>!r.type&&!r.url&&!r.tool&&(r.key||"").toLowerCase()===v)||m.find(r=>!r.type&&!r.url&&!r.tool&&!r.key&&(r.text||"").toLowerCase()===v);let a=n(String(e.tool.folder||"").toLowerCase())||n(Ht);const p=String(e.tool.group||"").trim();if(a&&p){const v=Lt(a.key||_t(a.text),p),r=d=>d!==e&&!d.type&&!d.url&&!d.tool;let $=m.find(d=>r(d)&&(d.key||"").toLowerCase()===v)||m.find(d=>r(d)&&d.parentId===a.id&&(!d.key||d.key.toLowerCase()===v)&&(d.text||"").toLowerCase()===p.toLowerCase());$||([$]=dt([{text:p,key:v,icon:It,synthesised:!0}],a.id),m.push($)),a=$}e.parentId=a?a.id:null,m.splice(m.indexOf(e),1),m.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const $e=e=>!U().has(e.id)&&!(e.tool&&!e.tool.orphan);async function re(e){const n=N(e);if(!n||!$e(n))return;const a=d=>{let Q=d;for(;Q;){if(Q.id===e)return!0;Q=m.find(O=>O.id===Q.parentId)}return!1},p=m.filter(d=>d.id!==e&&a(d));if(p.length&&!await E.confirm(`Remove "${He(n.text||n.type||"this item")}" and the ${p.length} item${p.length===1?"":"s"} beneath it?`))return;const v=U(),r=p.filter(d=>d.tool),$=p.filter(d=>!d.tool&&v.has(d.id));m=m.filter(d=>!a(d)||r.includes(d)||$.includes(d));for(const d of $)d.parentId=n.parentId??null;for(const d of r)d.tool.orphan?d.parentId=n.parentId??null:fe(d);L()}function ce(e){const n=N(e);!n||ne(n)||U().has(e)||(n.hidden=!n.hidden,n.touched=!0,L())}function G(e){const n=N(e);!n||ne(n)||(n.locked=q&&U().has(n.id),Zt(n,oe.resources||[],ee,je,()=>{L(),x(e)}))}function de(e){const n={id:_e(),parentId:null,...e==="separator"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};m.push(n),L(),ne(n)?x(n.id):G(n.id)}const k=e=>n=>{e(n)&&(L(),x(n))},u=k(e=>ut(m,e,-1)),X=k(e=>ut(m,e,1)),ue=k(e=>Ft(m,e)),he=k(e=>Kt(m,e));function ve(e){const n=N(e);if(!n)return[];const a=ne(n),p=U().has(e),v=Wt(m,e),r=v.findIndex(O=>O.id===e),$=n.tool,d=$&&($.persisted||n.touched),Q=O=>()=>{const ke=Bt(m,e,O,_e());L(),ke&&!ne(ke)?G(ke.id):ke&&x(ke.id)};return[{header:a?n.type==="separator"?"Separator":"Spacer":n.text||$?.label||"(untitled)"},...a?[]:[{label:"Edit\u2026",icon:"edit",action:()=>G(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:Q("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:a,action:()=>{const O=Nt(m,e,_e());L(),O&&G(O.id)}},{label:"Add separator below",icon:"minus",action:Q("separator")},{label:"Add spacer below",icon:"move",action:Q("spacer")},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:r<=0,action:()=>u(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:r<0||r>=v.length-1,action:()=>X(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:r<=0||ne(v[r-1]),action:()=>ue(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:n.parentId==null,action:()=>he(e)},{type:"divider"},...a?[]:[{label:n.hidden?"Show":"Hide",icon:n.hidden?"eye":"eye-off",disabled:p,action:()=>ce(e)}],{label:"Duplicate",icon:"copy",disabled:!!$,action:()=>{const O=Pt(m,e,_e);L(),O&&x(O.id)}},...$&&!$.orphan&&d?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{fe(n),L()}}]:[],{label:p?"Remove - always in the sidebar":$&&!$.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!$e(n),action:()=>re(e)}]}const ge=E.contextMenu(C,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>ve(e.dataset.id)});l(()=>ge?.destroy?.());const be=xt(C,()=>m,L,{items:".menu-tree-row",handle:".menu-tree-grip"});l(()=>be?.destroy());const ye=e=>{const n=e.target.closest(".menu-tree-row");if(!n)return;const a=n.dataset.id;if(e.target.closest(".mex-kebab")){qe(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){ce(a);return}if(e.target.closest(".me-edit")){G(a);return}e.target.closest("select, .menu-tree-grip, button")||G(a)},Ge=e=>{const n=e.target.closest(".menu-tree-row");if(!n||e.target!==n){n&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),qe(n));return}const a=n.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),qe(n);else if(e.key==="Enter")e.preventDefault(),G(a);else if(e.key==="Delete")e.preventDefault(),re(a);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),u(a);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),X(a);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),ue(a);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),he(a);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const p=[...C.querySelectorAll(".menu-tree-row")],v=p.indexOf(n)+(e.key==="ArrowDown"?1:-1);p[v]&&(e.preventDefault(),p[v].focus())}},Ve=e=>{if(!e.target.matches(".me-spacer-size"))return;const n=N(e.target.closest(".menu-tree-row")?.dataset.id);n&&(n.size=e.target.value,V())};C.addEventListener("click",ye),C.addEventListener("keydown",Ge),C.addEventListener("change",Ve),l(()=>{C.removeEventListener("click",ye),C.removeEventListener("keydown",Ge),C.removeEventListener("change",Ve)});const o=e=>t.find(e),xe=o("#me-float-accent"),De=o("#me-float-accent-hex"),Ne=()=>{De.get(0).style.display=xe.val()==="__custom__"?"":"none"},ht=()=>xe.val()==="__custom__"?De.val():xe.val(),Ee=o("#me-highlight-accent"),Oe=o("#me-highlight-accent-hex"),Ye=()=>{Oe.get(0).style.display=Ee.val()==="__custom__"?"":"none"},vt=()=>Ee.val()==="__custom__"?Oe.val():Ee.val(),Xe=()=>{const e=o("#me-position").val()==="floating";o(".dm-float-field").each(function(){this.style.display=e?"":"none"}),e&&Ne();const n=o("#me-orientation").val()==="vertical";o(".dm-vertical-field").each(function(){this.style.display=n?"":"none"});const a=!!(o("#me-float-collapsible").get(0)||{}).checked;o(".dm-float-collapsed-field").each(function(){this.style.display=e&&a?"":"none"})},Je=(e,n,a,p)=>{const v=o(e).get(0);v&&(v.innerHTML="",v.add(new Option(p,"")),n.forEach(r=>v.add(new Option(a[r]||r,r))))};Je("#me-highlight-hover",st,it,"- theme default -"),Je("#me-highlight-active",lt,rt,"- theme default -");const Pe=o("#me-bind-slot"),Fe=o("#me-bind-projects"),Ae=o("#me-bind-pages");Pe.html('<option value="">- not bound -</option>'+(ae||[]).map(e=>`<option value="${b(e.slot)}">${b(e.label||e.slot)} (${b(e.slot)})</option>`).join("")),Fe.html(K.map(e=>`<option value="${b(e.slug)}">${b(e.name||e.slug)}</option>`).join("")),o("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+te.map(e=>{const n=e.urlPath||e.url||"";return n?`<option value="${b(n)}">${b(e.title||n)} - ${b(n)}</option>`:""}).join(""));const Qe=()=>Ot({slot:Pe.val(),projects:Array.from(Fe.get(0).selectedOptions).map(e=>e.value),pagesText:Ae.val()});function Be(){const e=Qe(),n=o("#me-bind-summary");if(!e){n.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const a=[];e.projects.length&&a.push(`pages in ${e.projects.map(r=>`<code>${b(r)}</code>`).join(", ")}`),e.pages.length&&a.push(`pages matching ${e.pages.map(r=>`<code>${b(r)}</code>`).join(", ")}`);const p=e.pages.filter(r=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(r)),v=p.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${p.map(r=>`<code>${b(r)}</code>`).join(", ")}</div>`:"";n.html(a.length?`Takes over the <code>${b(e.slot)}</code> slot on ${a.join(" and ")}.${v}`:`<span class="text-warning">Slot <code>${b(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:gt}=await import("../lib/project-context.js");if(!g())return;const bt=_?gt():null;o("#me-project").html('<option value="">- none -</option>'+K.map(e=>`<option value="${b(e.slug)}">${b(e.name||e.slug)}</option>`).join(""));function ze(e){m=se(e.items),o("#me-variant").val(e.variant||""),o("#me-position").val(e.position||"");const n=o("#me-appearOnHover").get(0);n&&(n.checked=e.appearOnHover===!0),o("#me-float-anchor").val(e.float?.anchor||"TL"),o("#me-float-offsetX").val(e.float?.offsetX??""),o("#me-float-offsetY").val(e.float?.offsetY??""),o("#me-float-width").val(e.float?.width??""),o("#me-float-radius").val(e.float?.radius??""),o("#me-float-shadow").val(e.float?.shadow||""),o("#me-float-opacity").val(e.float?.opacity??""),o("#me-float-title").val(e.float?.title||"");for(const[r,$]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const d=o(r).get(0);d&&(d.checked=$===!0)}const a=e.float?.accent||"";xe.val(a.startsWith("#")?"__custom__":a),a.startsWith("#")&&De.val(a),Ne(),o("#me-orientation").val(e.orientation||""),o("#me-align").val(e.align||""),o("#me-side").val(e.side||"left"),o("#me-class").val(e.class||""),o("#me-highlight-hover").val(e.highlight?.hover||""),o("#me-highlight-active").val(e.highlight?.active||"");const p=e.highlight?.accent||"";Ee.val(p.startsWith("#")?"__custom__":p),p.startsWith("#")&&Oe.val(p),Ye(),o("#me-fontFamily").val(e.style?.fontFamily||""),o("#me-fontSize").val(e.style?.fontSize||""),o("#me-fontWeight").val(e.style?.fontWeight||""),o("#me-letterSpacing").val(e.style?.letterSpacing||""),o("#me-iconSize").val(e.style?.iconSize||""),Pe.val(e.binding?.slot||"");const v=new Set(e.binding?.projects||[]);Array.from(Fe.get(0).options).forEach(r=>{r.selected=v.has(r.value)}),Ae.val((e.binding?.pages||[]).join(`
23
+ `)),o("#me-slug").val(e.slug||""),o("#me-name").val(e.name||""),o("#me-description").val(e.description||""),o("#me-project").val(e.meta?.project||bt||""),Xe(),Be(),ie()}const we=e=>!!(o(e).get(0)||{}).checked;function Ce(){const e={variant:o("#me-variant").val(),position:o("#me-position").val(),appearOnHover:we("#me-appearOnHover"),floatAnchor:o("#me-float-anchor").val(),floatOffsetX:o("#me-float-offsetX").val(),floatOffsetY:o("#me-float-offsetY").val(),floatWidth:o("#me-float-width").val(),floatRadius:o("#me-float-radius").val(),floatShadow:o("#me-float-shadow").val(),floatAccent:ht(),floatOpacity:o("#me-float-opacity").val(),floatTitle:o("#me-float-title").val(),floatCollapsible:we("#me-float-collapsible"),floatCollapsed:we("#me-float-collapsed"),floatMovable:we("#me-float-movable"),floatResizable:we("#me-float-resizable"),highlightHover:o("#me-highlight-hover").val(),highlightActive:o("#me-highlight-active").val(),highlightAccent:vt(),class:o("#me-class").val(),orientation:o("#me-orientation").val(),align:o("#me-align").val(),side:o("#me-side").val(),fontFamily:o("#me-fontFamily").val(),fontSize:o("#me-fontSize").val(),fontWeight:o("#me-fontWeight").val(),letterSpacing:o("#me-letterSpacing").val(),iconSize:o("#me-iconSize").val()},n={slug:o("#me-slug").val(),name:o("#me-name").val(),description:o("#me-description").val(),project:o("#me-project").val()};return zt(e,n,Qe(),Rt(m),h.meta||{})}const Ze=e=>[...Mt(e),...ct(e.class).map(n=>`CSS classes: ${n} (Behaviour tab).`)];let et=!1,Me=null;function V(){if(!B)return;const e=Ce();Me=e,D.value=Ie(e)!==B,pe.value=D.peek()||et?Ze(e).join(" "):""}const Le=e=>{e.target.closest("#me-items-list")||(e.target.matches("#me-position, #me-orientation, #me-float-collapsible")&&Xe(),e.target.matches("#me-float-accent")&&Ne(),e.target.matches("#me-highlight-accent")&&Ye(),e.target.closest("#me-binding")&&Be(),V())};s.addEventListener("input",Le),s.addEventListener("change",Le),l(()=>{s.removeEventListener("input",Le),s.removeEventListener("change",Le)}),o("#me-bind-page-add").on("click",()=>{const e=o("#me-bind-page-pick").val();if(!e)return;const n=Ae.val().split(`
24
+ `).map(a=>a.trim()).filter(Boolean);n.includes(e)||n.push(e),Ae.val(n.join(`
25
+ `)),Be(),V()}),ze(h),B=Ie(Ce()),V();const tt=()=>{try{S.remove?S.remove(Y):S.set(Y,null)}catch{}};async function Ke(){if(le.peek())return;const e=Ce(),n=Ze(e);if(n.length){et=!0,V(),E.toast(n.join(" "),{type:"warning",duration:7e3});return}le.value=!0;try{if(_)await j.menus.create(e);else if(e.slug!==h.slug){await j.menus.create(e);const a=await j.menuLocations.get();let p=!1;for(const[v,r]of Object.entries(a))r===h.slug&&(a[v]=e.slug,p=!0);p&&await j.menuLocations.save(a),await j.menus.remove(h.slug)}else await j.menus.update(h.slug,e);if(B=Ie(e),D.value=!1,tt(),Dt("#/menus"),E.toast("Saved.",{type:"success"}),_||e.slug!==h.slug)location.hash="#/menus/edit/"+encodeURIComponent(e.slug);else{h={...h,...e};for(const a of m)a.tool&&a.touched&&(a.tool={...a.tool,persisted:!0});ie(),B=Ie(Ce()),V(),ft(t.get(0),e.name||e.slug)}if(q)try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}catch(a){E.toast(`Save failed: ${a.message||a}`,{type:"error"})}finally{le.value=!1}}async function yt(){!D.peek()||!await E.confirm("Throw away the changes you have not saved?")||(ze(h),V())}E.tabs(o("#me-tabs").get(0));const wt=M.applyBindings({dirty:D,saving:le,problems:pe,itemCount:Se},s,{methods:{save:()=>Ke(),discard:()=>yt(),addItem:()=>de("item"),addSeparator:()=>de("separator"),addSpacer:()=>de("spacer")}});l(()=>wt.dispose()),l(Tt(s,{position:"bottom"})),ft(t.get(0),_?"New menu":h.name||h.slug),We(t,{id:"menu-editor-back",icon:"arrow-left",title:"All menus",onClick:()=>{location.hash="#/menus"}}),We(t,{id:"menu-editor-locations",icon:"map-pin",title:"Menu locations",onClick:()=>{location.hash="#/menu-locations"}}),We(t,{id:"menu-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>Ke()});const nt=e=>{if(!(!(e.ctrlKey||e.metaKey)||e.key!=="s")){if(e.preventDefault(),e.stopImmediatePropagation(),document.querySelector(".me-item-form")?.offsetParent){E.toast("Apply the item first (Ctrl+Enter), then Save.",{type:"info"});return}Ke()}};document.addEventListener("keydown",nt,!0),l(()=>document.removeEventListener("keydown",nt,!0));const ot=()=>{if(!(!D.peek()||!Me))try{S.set(Y,{menu:Me,base:B,at:new Date().toISOString()})}catch{}},at=e=>{D.peek()&&(ot(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",at),l(()=>window.removeEventListener("beforeunload",at)),z={path:w,dirty:()=>D.peek(),name:()=>o("#me-name").val()||h.name||h.slug||"new menu",dispose(){i=!0,ot(),c.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(s);let J=null;try{J=S.get(Y)}catch{}if(J?.menu){tt();const e=J.base&&J.base!==B,n=J.at?` (${qt(J.at)})`:"",a=_?"the new menu you started":`the menu "${He(h.name||h.slug)}"`,p=e?`You left unsaved changes to ${a}${n}, but the saved menu has changed since. Restore your version anyway?`:`You left unsaved changes to ${a}${n}. Restore them?`;await E.confirm(p)&&g()&&(ze({...J.menu,meta:{...h.meta||{},...J.menu.meta||{}}}),V())}}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domma-cms",
3
- "version": "0.117.0",
3
+ "version": "0.119.0",
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",
@@ -0,0 +1 @@
1
+ export const CSS_CLASS_RE=/^-?[_a-zA-Z][_a-zA-Z0-9-]*$/,CSS_CLASS_MAX=20,CSS_CLASS_MAX_LEN=64;function r(s){return typeof s!="string"?[]:s.split(/[\s,]+/).map(t=>t.replace(/^\./,"")).filter(Boolean)}export function cssClasses(s){const t=[];for(const n of r(s))if(n.length<=64&&CSS_CLASS_RE.test(n)&&!t.includes(n)&&t.push(n),t.length>=20)break;return t}export function cssClassProblems(s){if(s==null||s==="")return[];if(typeof s!="string")return["must be a string of class names"];const t=r(s),n=t.filter(o=>o.length>64||!CSS_CLASS_RE.test(o)),e=[];return n.length&&e.push(`not a valid class name: ${n.join(", ")}`),t.length>20&&e.push("at most 20 classes"),e}export function normaliseCssClasses(s){return cssClasses(s).join(" ")}export function applyClasses(s,t){if(!s)return!1;const n=cssClasses(t);return n.length&&s.classList.add(...n),n.length>0}
@@ -1 +1 @@
1
- export const SUBMIT_ALIGNS=["left","center","right","full"];export function resolveSubmitAlign(e,t){const n=e||{};return SUBMIT_ALIGNS.includes(n.submitAlign)?n.submitAlign:t==="grid"&&n.submitSpan==="full"?"left":""}export function submitWrapperClasses(e,t){const n=resolveSubmitAlign(e,t);if(!n)return[];const r=["fb-submit",`fb-submit--${n}`];return t==="grid"&&r.push("col-span-full"),r}export function applySubmitPosition(e,t,n){const r=e&&e.querySelector?e.querySelector(".form-buttons"):null;return r?(submitWrapperClasses(t,n).forEach(i=>r.classList.add(i)),r):null}export const BUTTON_STYLES=["primary","secondary","success","danger","warning","info","outline","outline-success","outline-danger","outline-warning","outline-info","ghost"],BUTTON_SIZES=["sm","lg"],SECONDARY_KINDS=["reset","link"];const d={sm:14,"":16,lg:20},p=/^[a-z0-9][a-z0-9-]{0,63}$/i;export function isIconName(e){return typeof e=="string"&&p.test(e)}export function isSafeButtonUrl(e){if(typeof e!="string")return!1;const t=e.trim();if(!t||t.length>2048||/[\u0000-\u0020\u007f-\u009f\u2028\u2029\\]/.test(t))return!1;const n=/^([a-z][a-z0-9+.-]*):/i.exec(t);return n?["http","https","mailto","tel"].includes(n[1].toLowerCase()):!0}export function resolveSubmitButton(e){const t=e&&e.submitButton&&typeof e.submitButton=="object"?e.submitButton:{};return{style:BUTTON_STYLES.includes(t.style)?t.style:"primary",size:BUTTON_SIZES.includes(t.size)?t.size:"",iconStart:isIconName(t.iconStart)?t.iconStart:"",iconEnd:isIconName(t.iconEnd)?t.iconEnd:""}}export function resolveSecondaryButton(e){const t=e&&e.secondaryButton;if(!t||typeof t!="object"||!SECONDARY_KINDS.includes(t.kind)||t.kind==="link"&&!isSafeButtonUrl(t.url))return null;const n=typeof t.label=="string"&&t.label.trim()?t.label.trim().slice(0,80):t.kind==="reset"?"Clear form":"Cancel";return{kind:t.kind,label:n,url:t.kind==="link"?t.url.trim():"",style:BUTTON_STYLES.includes(t.style)?t.style:"secondary",iconStart:isIconName(t.iconStart)?t.iconStart:"",iconEnd:isIconName(t.iconEnd)?t.iconEnd:"",first:t.first===!0,stack:t.stack===!0}}export function buttonClasses(e,t){const n=["btn","btn-"+(BUTTON_STYLES.includes(e)?e:"primary")];return BUTTON_SIZES.includes(t)&&n.push("btn-"+t),n}export function escapeHtml(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}export function buttonInnerHtml(e,t,n){const r=d[BUTTON_SIZES.includes(n)?n:""],i=(o,u)=>isIconName(o)?`<span class="fb-btn-icon fb-btn-icon--${u}" data-icon="${o}" data-icon-size="${r}" aria-hidden="true"></span>`:"",s=t||{};return i(s.iconStart,"start")+`<span class="fb-btn-label">${escapeHtml(e)}</span>`+i(s.iconEnd,"end")}export function secondaryButtonHtml(e,t){if(!e||!SECONDARY_KINDS.includes(e.kind))return"";const n=buttonClasses(e.style,t).concat("fb-btn","fb-secondary-btn","fb-secondary-btn--"+e.kind).join(" "),r=buttonInnerHtml(e.label,e,t);return e.kind==="reset"?`<button type="reset" class="${n}">${r}</button>`:isSafeButtonUrl(e.url)?`<a class="${n}" href="${escapeHtml(e.url.trim())}">${r}</a>`:""}export function pairWrapperClasses(e){const t=resolveSecondaryButton(e);return t?t.stack?["fb-submit--pair","fb-submit--stack"]:["fb-submit--pair"]:[]}function c(e){if(typeof window>"u"||!e)return;const t=window.Domma&&window.Domma.icons||window.I;t&&typeof t.scan=="function"&&t.scan(e)}export function decorateButton(e,t){return!e||!t||(t.style&&t.style!=="primary"&&BUTTON_STYLES.includes(t.style)&&(e.classList.remove("btn-primary"),e.classList.add("btn-"+t.style)),BUTTON_SIZES.includes(t.size)&&e.classList.add("btn-"+t.size),(isIconName(t.iconStart)||isIconName(t.iconEnd))&&e.tagName!=="INPUT"&&!e.querySelector(".fb-btn-label")&&(e.innerHTML=buttonInnerHtml(e.textContent.trim(),t,t.size),e.classList.add("fb-btn"))),e}export function applySubmitButtons(e,t,n){const r=applySubmitPosition(e,t,n);if(!r){const u=e&&e.querySelector?e.querySelector('button[type="submit"]'):null;return u&&(decorateButton(u,resolveSubmitButton(t)),c(u)),null}const i=r.querySelector('button[type="submit"], input[type="submit"]');if(!i)return r;const s=resolveSubmitButton(t);decorateButton(i,s);const o=resolveSecondaryButton(t);if(o&&!r.querySelector(".fb-secondary-btn")){const u=r.ownerDocument.createElement("template");u.innerHTML=secondaryButtonHtml(o,s.size);const l=u.content.firstElementChild;l&&(i.parentNode.insertBefore(l,o.first?i:i.nextSibling),pairWrapperClasses(t).forEach(f=>r.classList.add(f)),o.kind==="reset"&&wireFormReset(i.form||r.closest("form")))}return c(r),r}export function applyWizardButtons(e,t){const n=e&&e.querySelector?e.querySelector(".wizard-nav"):null;if(!n)return null;const r=resolveSubmitButton(t),i=n.querySelector(".wizard-prev");i&&r.size&&i.classList.add("btn-"+r.size);const s=n.querySelector(".wizard-next");s&&decorateButton(s,{style:r.style,size:r.size,iconStart:"",iconEnd:""});const o=n.querySelector(".wizard-submit");return o&&decorateButton(o,r),c(n),n}const b='input:not([type="hidden"]):not([type="submit"]):not([type="reset"]):not([type="button"]), select, textarea';function a(e){return Array.from(e.querySelectorAll(b)).filter(t=>!(t.closest&&t.closest(".fb-form-honeypot")))}export function formHasAnswers(e){return a(e).some(t=>t.type==="checkbox"||t.type==="radio"?t.checked!==t.defaultChecked:t.tagName==="SELECT"?Array.from(t.options).some(n=>n.selected!==n.defaultSelected):t.value!==t.defaultValue)}function y(e){a(e).forEach(t=>{t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0}))}),e.querySelectorAll(".fb-field-invalid").forEach(t=>t.classList.remove("fb-field-invalid")),e.querySelectorAll("[data-error-for]").forEach(t=>{t.textContent="",t.style.display="none",t.parentElement&&t.parentElement.classList.remove("has-error")})}export function wireFormReset(e){if(!e||e.__fbResetWired)return;e.__fbResetWired=!0;let t=!1;e.addEventListener("reset",n=>{const r=typeof window<"u"?window.E:null;if(!t&&r&&typeof r.confirm=="function"&&formHasAnswers(e)){n.preventDefault(),Promise.resolve(r.confirm("Clear everything you have entered in this form?")).then(i=>{i&&(t=!0,e.reset(),t=!1)});return}setTimeout(()=>y(e),0)})}export function buttonSettingsProblems(e){const t=e&&e.secondaryButton;return!t||typeof t!="object"||t.kind!=="link"?[]:typeof t.url!="string"||!t.url.trim()?["The Cancel button needs an address to go to."]:isSafeButtonUrl(t.url)?[]:["The Cancel button's address must be a page on this site (/contact) or a full http(s), mailto or tel address."]}export function publicButtonSettings(e){if(!e||typeof e!="object")return e;const t=e.secondaryButton;if(t&&typeof t=="object"&&t.kind==="link"&&!isSafeButtonUrl(t.url)){const{secondaryButton:n,...r}=e;return r}return e}
1
+ import{applyClasses as u,cssClasses as b,cssClassProblems as a}from"./css-classes.mjs";export const SUBMIT_ALIGNS=["left","center","right","full"];export function resolveSubmitAlign(e,t){const n=e||{};return SUBMIT_ALIGNS.includes(n.submitAlign)?n.submitAlign:t==="grid"&&n.submitSpan==="full"?"left":""}export function submitWrapperClasses(e,t){const n=resolveSubmitAlign(e,t);if(!n)return[];const r=["fb-submit",`fb-submit--${n}`];return t==="grid"&&r.push("col-span-full"),r}export function applySubmitPosition(e,t,n){const r=e&&e.querySelector?e.querySelector(".form-buttons"):null;return r?(submitWrapperClasses(t,n).forEach(s=>r.classList.add(s)),r):null}export const BUTTON_STYLES=["primary","secondary","success","danger","warning","info","outline","outline-success","outline-danger","outline-warning","outline-info","ghost"],BUTTON_SIZES=["sm","lg"],SECONDARY_KINDS=["reset","link"];const y={sm:14,"":16,lg:20},m=/^[a-z0-9][a-z0-9-]{0,63}$/i;export function isIconName(e){return typeof e=="string"&&m.test(e)}export function isSafeButtonUrl(e){if(typeof e!="string")return!1;const t=e.trim();if(!t||t.length>2048||/[\u0000-\u0020\u007f-\u009f\u2028\u2029\\]/.test(t))return!1;const n=/^([a-z][a-z0-9+.-]*):/i.exec(t);return n?["http","https","mailto","tel"].includes(n[1].toLowerCase()):!0}export function resolveSubmitButton(e){const t=e&&e.submitButton&&typeof e.submitButton=="object"?e.submitButton:{};return{style:BUTTON_STYLES.includes(t.style)?t.style:"primary",size:BUTTON_SIZES.includes(t.size)?t.size:"",iconStart:isIconName(t.iconStart)?t.iconStart:"",iconEnd:isIconName(t.iconEnd)?t.iconEnd:""}}export function resolveSecondaryButton(e){const t=e&&e.secondaryButton;if(!t||typeof t!="object"||!SECONDARY_KINDS.includes(t.kind)||t.kind==="link"&&!isSafeButtonUrl(t.url))return null;const n=typeof t.label=="string"&&t.label.trim()?t.label.trim().slice(0,80):t.kind==="reset"?"Clear form":"Cancel";return{kind:t.kind,label:n,url:t.kind==="link"?t.url.trim():"",style:BUTTON_STYLES.includes(t.style)?t.style:"secondary",iconStart:isIconName(t.iconStart)?t.iconStart:"",iconEnd:isIconName(t.iconEnd)?t.iconEnd:"",first:t.first===!0,stack:t.stack===!0}}export function buttonClasses(e,t){const n=["btn","btn-"+(BUTTON_STYLES.includes(e)?e:"primary")];return BUTTON_SIZES.includes(t)&&n.push("btn-"+t),n}export function escapeHtml(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}export function buttonInnerHtml(e,t,n){const r=y[BUTTON_SIZES.includes(n)?n:""],s=(i,o)=>isIconName(i)?`<span class="fb-btn-icon fb-btn-icon--${o}" data-icon="${i}" data-icon-size="${r}" aria-hidden="true"></span>`:"",c=t||{};return s(c.iconStart,"start")+`<span class="fb-btn-label">${escapeHtml(e)}</span>`+s(c.iconEnd,"end")}export function secondaryButtonHtml(e,t){if(!e||!SECONDARY_KINDS.includes(e.kind))return"";const n=buttonClasses(e.style,t).concat("fb-btn","fb-secondary-btn","fb-secondary-btn--"+e.kind).join(" "),r=buttonInnerHtml(e.label,e,t);return e.kind==="reset"?`<button type="reset" class="${n}">${r}</button>`:isSafeButtonUrl(e.url)?`<a class="${n}" href="${escapeHtml(e.url.trim())}">${r}</a>`:""}export function pairWrapperClasses(e){const t=resolveSecondaryButton(e);return t?t.stack?["fb-submit--pair","fb-submit--stack"]:["fb-submit--pair"]:[]}function l(e){if(typeof window>"u"||!e)return;const t=window.Domma&&window.Domma.icons||window.I;t&&typeof t.scan=="function"&&t.scan(e)}export function decorateButton(e,t){return!e||!t||(t.style&&t.style!=="primary"&&BUTTON_STYLES.includes(t.style)&&(e.classList.remove("btn-primary"),e.classList.add("btn-"+t.style)),BUTTON_SIZES.includes(t.size)&&e.classList.add("btn-"+t.size),(isIconName(t.iconStart)||isIconName(t.iconEnd))&&e.tagName!=="INPUT"&&!e.querySelector(".fb-btn-label")&&(e.innerHTML=buttonInnerHtml(e.textContent.trim(),t,t.size),e.classList.add("fb-btn"))),e}export function applySubmitButtons(e,t,n){const r=applySubmitPosition(e,t,n);if(!r){const o=e&&e.querySelector?e.querySelector('button[type="submit"]'):null;return o&&(decorateButton(o,resolveSubmitButton(t)),l(o)),null}const s=r.querySelector('button[type="submit"], input[type="submit"]');if(!s)return r;const c=resolveSubmitButton(t);decorateButton(s,c);const i=resolveSecondaryButton(t);if(i&&!r.querySelector(".fb-secondary-btn")){const o=r.ownerDocument.createElement("template");o.innerHTML=secondaryButtonHtml(i,c.size);const f=o.content.firstElementChild;f&&(s.parentNode.insertBefore(f,i.first?s:s.nextSibling),pairWrapperClasses(t).forEach(p=>r.classList.add(p)),i.kind==="reset"&&wireFormReset(s.form||r.closest("form")))}return l(r),r}export function applyWizardButtons(e,t){const n=e&&e.querySelector?e.querySelector(".wizard-nav"):null;if(!n)return null;const r=resolveSubmitButton(t),s=n.querySelector(".wizard-prev");s&&r.size&&s.classList.add("btn-"+r.size);const c=n.querySelector(".wizard-next");c&&decorateButton(c,{style:r.style,size:r.size,iconStart:"",iconEnd:""});const i=n.querySelector(".wizard-submit");return i&&decorateButton(i,r),l(n),n}const S='input:not([type="hidden"]):not([type="submit"]):not([type="reset"]):not([type="button"]), select, textarea';function d(e){return Array.from(e.querySelectorAll(S)).filter(t=>!(t.closest&&t.closest(".fb-form-honeypot")))}export function formHasAnswers(e){return d(e).some(t=>t.type==="checkbox"||t.type==="radio"?t.checked!==t.defaultChecked:t.tagName==="SELECT"?Array.from(t.options).some(n=>n.selected!==n.defaultSelected):t.value!==t.defaultValue)}function h(e){d(e).forEach(t=>{t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0}))}),e.querySelectorAll(".fb-field-invalid").forEach(t=>t.classList.remove("fb-field-invalid")),e.querySelectorAll("[data-error-for]").forEach(t=>{t.textContent="",t.style.display="none",t.parentElement&&t.parentElement.classList.remove("has-error")})}export function wireFormReset(e){if(!e||e.__fbResetWired)return;e.__fbResetWired=!0;let t=!1;e.addEventListener("reset",n=>{const r=typeof window<"u"?window.E:null;if(!t&&r&&typeof r.confirm=="function"&&formHasAnswers(e)){n.preventDefault(),Promise.resolve(r.confirm("Clear everything you have entered in this form?")).then(s=>{s&&(t=!0,e.reset(),t=!1)});return}setTimeout(()=>h(e),0)})}export function buttonSettingsProblems(e){const t=e&&e.secondaryButton;return!t||typeof t!="object"||t.kind!=="link"?[]:typeof t.url!="string"||!t.url.trim()?["The Cancel button needs an address to go to."]:isSafeButtonUrl(t.url)?[]:["The Cancel button's address must be a page on this site (/contact) or a full http(s), mailto or tel address."]}export function publicButtonSettings(e){if(!e||typeof e!="object")return e;const t=e.secondaryButton;if(t&&typeof t=="object"&&t.kind==="link"&&!isSafeButtonUrl(t.url)){const{secondaryButton:n,...r}=e;return r}return e}export function formClassProblems(e,t){const n=[],r=e&&typeof e=="object"?e:{};for(const s of a(r.class))n.push(`Form CSS classes: ${s}.`);for(const s of a(r.submitClass))n.push(`Submit button CSS classes: ${s}.`);for(const s of Array.isArray(t)?t:[])if(!(!s||typeof s!="object"))for(const c of a(s.class))n.push(`CSS classes on "${s.label||s.name||s.type}": ${c}.`);return n}export function applyFormClasses(e,t,n){if(!e||!e.querySelector)return null;const r=t&&typeof t=="object"?t:{},s=e.matches&&e.matches("form")?e:e.querySelector("form");s&&u(s,r.class);const c=e;r.submitClass&&c.querySelectorAll('button[type="submit"], input[type="submit"], .wizard-submit').forEach(o=>u(o,r.submitClass));const i=new Map;for(const o of Array.isArray(n)?n:[])o&&o.name&&b(o.class).length&&i.set(o.name,o.class);return i.size&&c.querySelectorAll("[data-field]").forEach(o=>{i.has(o.dataset.field)&&u(o,i.get(o.dataset.field))}),s}
@@ -1,2 +1,2 @@
1
- import{buildWizardSteps as W}from"/public/js/form-steps.mjs";import{applySubmitButtons as N,applyWizardButtons as J,resolveSecondaryButton as U,submitWrapperClasses as H}from"/public/js/form-submit.mjs";const _=document.querySelectorAll("[data-form]");_.length&&_.forEach(ne);function T(n){return(n||[]).some(o=>o.logic||Array.isArray(o.triggers)&&o.triggers.length)}function K(n,o){const t=n.querySelector('[name="'+o+'"], [name="'+o+'[]"]')||n.querySelector('[data-chooser-field="'+o+'"]');if(!t)return null;const e=t.closest("form")||n;let r=t;for(;r.parentNode&&r.parentNode!==e;)r=r.parentNode;return r}export function markInvalidFields(n,o){n.querySelectorAll(".fb-field-invalid").forEach(e=>e.classList.remove("fb-field-invalid"));let t=null;(o||[]).forEach(function(e){const r=K(n,e.name);r&&(r.classList.add("fb-field-invalid"),t||(t=r))}),t&&t.scrollIntoView&&t.scrollIntoView({behavior:"smooth",block:"center"})}export function showValidationPopup(n){const o=(n.missing||[]).map(e=>"<strong>"+j(e.label)+"</strong> is required.").concat((n.errors||[]).map(j)),t=o.join("<br>");if(typeof E<"u"&&E.alert){E.alert(t,{title:"Please complete this step"});return}window.alert(o.join(`
2
- `).replace(/<[^>]+>/g,""))}function j(n){return String(n).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function F(n,o){let t=!1;n.addEventListener("dm-form-end",function(e){const r=e.detail&&e.detail.validation;if(r&&!r.valid){markInvalidFields(n,r.missing),showValidationPopup(r);return}t||(t=!0,n.classList.add("fb-form-loading"),Promise.resolve(o(e.detail&&e.detail.values||{})).catch(function(){}).finally(function(){t=!1,n.classList.remove("fb-form-loading")}))})}function C(n,o,t){const e=n.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const r=document.createElement("div");r.className=t==="success"?"fb-form-success":"fb-form-error",r.textContent=o,n.appendChild(r)}function A(n,o){if(n._formLogicRuntime=o,n._formLogicObserver&&(n._formLogicObserver.disconnect(),n._formLogicObserver=null),!n.parentNode||typeof MutationObserver>"u"||n._formLogicObserved)return;n._formLogicObserved=!0;const t=new MutationObserver(function(e){for(const r of e)for(const i of r.removedNodes)if(i===n||i.nodeType===1&&i.contains&&i.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1}),n._formLogicObserver=t}function Y(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function B(n,o){const t={};return n.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const r=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),i=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":r?"chooser":e.type,c={...e.formConfig||{}};c.span==="full"&&o&&(c.span=o);const s={type:i,label:e.label||e.name,required:Y(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...c}};e.minLength!==void 0&&(s.minLength=e.minLength),e.maxLength!==void 0&&(s.maxLength=e.maxLength),e.min!==void 0&&(s.min=e.min),e.max!==void 0&&(s.max=e.max),r&&(e.variant&&(s.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(s.multiple=!0),e.density&&(s.density=e.density),e.columns&&(s.columns=e.columns),e.accent&&(s.accent=e.accent),e.accentStyle&&(s.accentStyle=e.accentStyle),e.glow&&(s.glow=!0),e.glowColour&&(s.glowColour=e.glowColour),e.shadow&&(s.shadow=e.shadow),e.shadowColour&&(s.shadowColour=e.shadowColour)),t[e.name]=s}),t}function $(n){const o={};return n.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function R(n,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=n.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}const O="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function z(n){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const r=document.createElement("strong");r.textContent=n;const i=document.createElement("button");i.type="button",i.textContent="\xD7",i.setAttribute("aria-label","Close"),i.style.cssText=O+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(r),e.appendChild(i),t.appendChild(e);const c=document.createElement("div");c.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(c),o.appendChild(t);const s=l=>{l.key==="Escape"&&a()};function a(){document.removeEventListener("keydown",s),o.remove()}return i.addEventListener("click",a),o.addEventListener("click",l=>{l.target===o&&a()}),document.addEventListener("keydown",s),document.body.appendChild(o),{body:c,close:a}}function G(n){const{body:o,close:t}=z("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const r=document.createElement("div");r.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(r);const i=window.I&&typeof I.list=="function"?I.list():[],c=i.map(s=>{const a=document.createElement("button");a.type="button",a.title=s,a.dataset.iconName=s,a.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const l=document.createElement("span");return l.setAttribute("data-icon",s),l.setAttribute("data-icon-size","18"),a.appendChild(l),a.addEventListener("mouseenter",()=>{a.style.borderColor="var(--dm-border)"}),a.addEventListener("mouseleave",()=>{a.style.borderColor="transparent"}),a.addEventListener("click",()=>{t(),n(s)}),r.appendChild(a),a});if(!i.length){const s=document.createElement("p");s.textContent="Icon engine unavailable - type an icon name into the field instead.",r.appendChild(s)}window.I?.scan?.(r),e.addEventListener("input",()=>{const s=e.value.trim().toLowerCase();c.forEach(a=>{a.style.display=!s||a.dataset.iconName.includes(s)?"":"none"})}),e.focus()}async function Q(){const n=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!n)return{error:"auth"};const o=r=>fetch("/api/media",{headers:{Authorization:"Bearer "+r}});let t;try{if(t=await o(n),t.status===401&&S.get("auth_refresh_token")){const r=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(r.ok){const{token:i}=await r.json();S.set("auth_token",i),t=await o(i)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(r=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(r.name||r.url||""))}}function X(n){const{body:o,close:t}=z("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),Q().then(({files:r,error:i})=>{if(i){e.textContent=i==="auth"?"Sign in with media access to browse the library - or paste an image URL into the field.":"Could not load the media library - paste an image URL into the field instead.";return}if(!r.length){e.textContent="No images in the media library yet.";return}e.remove();const c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",r.forEach(s=>{const a=document.createElement("button");a.type="button",a.title=s.name||s.url,a.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const l=document.createElement("img");l.src=s.url,l.alt=s.name||"",l.loading="lazy",l.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const m=document.createElement("span");m.textContent=s.name||s.url,m.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",a.appendChild(l),a.appendChild(m),a.addEventListener("click",()=>{t(),n(s.url)}),c.appendChild(a)}),o.appendChild(c)})}function P(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function D(n){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",n.parentNode.insertBefore(o,n),o.appendChild(n),n.style.flex="1",n.style.minWidth="0",o}function M(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=O,o}function Z(n){if(!window.I||typeof I.list!="function")return;const o=D(n),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const i=n.value.trim();if(!i)return;const c=document.createElement("span");c.setAttribute("data-icon",i),c.setAttribute("data-icon-size","16"),t.appendChild(c),window.I?.scan?.(t)};n.addEventListener("input",e),e();const r=M("Browse");r.addEventListener("click",()=>G(i=>{P(n,i),e()})),o.appendChild(t),o.appendChild(r)}function ee(n){const o=D(n),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const i=n.value.trim();t.style.display=i?"":"none",i&&(t.src=i)};n.addEventListener("input",e),e();const r=M("Browse");r.addEventListener("click",()=>X(i=>{P(n,i),e()})),o.appendChild(t),o.appendChild(r)}export function enhancePickerFields(n,o){const t=typeof n=="string"?document.querySelector(n):n;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const r=t.querySelector('[name="'+e.name+'"]');!r||r.dataset.pickerEnhanced||(r.dataset.pickerEnhanced="1",e.type==="icon"?Z(r):ee(r))})}function q(n,o){const t=document.createElement("div");t.className="fb-form-honeypot",t.setAttribute("aria-hidden","true");const e=document.createElement("input");e.name=n.querySelector('[name="website"]')?"_website":"website",t.dataset.hpName=e.name,e.type="text",e.tabIndex=-1,e.autocomplete="url",e.placeholder="https://",t.appendChild(e);const r=document.createElement("input");r.name="_t",r.type="hidden",r.value=o||Date.now(),t.appendChild(r),n.appendChild(t)}function V(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let r=0;o.forEach(function(i){if(i.type==="spacer"){const c=document.createElement("div");c.className="fb-spacer";const s=e[r];if(s)t.insertBefore(c,s);else{const a=t.querySelector('[type="submit"]');a?t.insertBefore(c,a):t.appendChild(c)}}else i.type!=="page-break"&&r++})}function L(n,o){!n||!o||n.querySelectorAll('input[type="file"]').forEach(function(t){t.name&&t.files&&t.files.length&&o.set(t.name,Array.from(t.files))})}function x(n,o,t,e,r,i){const c=r||e,s=c.querySelector(".fb-form-honeypot"),a=s?.querySelector('input[type="text"]')?.value||"",l=s?.querySelector('[name="_t"]')?.value||"",m=Object.assign({},o);delete m._t,s?.dataset.hpName&&delete m[s.dataset.hpName];const d=new Map(i||[]);L(c,d);const u=d.size>0;let p,b;if(u){const h=new FormData;for(const[g,v]of Object.entries(m))v!=null&&(d.has(g)||h.append(g,typeof v=="object"?JSON.stringify(v):String(v)));for(const[g,v]of d)for(const w of v)h.append(g,w,w.name);h.append("_hp",a),h.append("_t",l),p=h,b={}}else{const h=Object.assign({},m,{_hp:a,_t:l});p=JSON.stringify(h),b={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:b,body:p}).then(h=>h.json().then(g=>({ok:h.ok,body:g}))).then(h=>{h.ok&&h.body.ok?(e.textContent="",C(e,h.body.message||t.successMessage||"Thank you.","success")):C(e,h.body.error||"Something went wrong.","error")}).catch(()=>{C(e,"Unable to submit. Please check your connection.","error")})}function te(n,o,t,e,r){const i=document.createElement("form");i.noValidate=!0,o.forEach(function(a){const l=document.createElement("div");l.className="form-group",l.style.marginBottom="1.25rem";const m=document.createElement("label");if(m.className="form-label",m.textContent=a.label||a.name,a.required){const u=document.createElement("span");u.textContent=" *",u.style.color="var(--dm-danger)",m.appendChild(u)}let d;a.type==="textarea"?(d=document.createElement("textarea"),d.rows=a.formConfig?.rows||4,d.className="form-input"):a.type==="select"?(d=document.createElement("select"),d.className="form-input",(a.options||[]).forEach(function(u){const p=document.createElement("option");p.value=typeof u=="string"?u:u.value??"",p.textContent=typeof u=="string"?u:u.label||p.value,d.appendChild(p)})):(d=document.createElement("input"),d.type=a.type==="icon"||a.type==="image"?"text":a.type||"text",d.className="form-input",a.placeholder&&(d.placeholder=a.placeholder),a.type==="file"&&(a.file?.accept&&(d.accept=a.file.accept),a.multiple&&(d.multiple=!0))),d.name=a.name,d.required=a.required||!1,l.appendChild(m),l.appendChild(d),i.appendChild(l)}),t.honeypot&&q(i);const c=document.createElement("button");if(c.type="submit",c.className="btn btn-primary",c.textContent=t.submitText||"Submit",H(t,"stacked").length||U(t)){const a=document.createElement("div");a.className="form-group form-buttons",a.appendChild(c),i.appendChild(a)}else i.appendChild(c);if(i.addEventListener("submit",function(a){a.preventDefault();const l={};if(o.forEach(function(m){const d=i.querySelector('[name="'+m.name+'"]');d&&(l[m.name]=d.value)}),window.FormLogicEngine&&r){const m=window.FormLogicEngine,d=[],u=[];if(o.forEach(function(p){if(m.evaluateFieldVisibility(p,l)==="hidden"){delete l[p.name];return}const h=m.evaluateFieldRequirement(p,l),g=l[p.name];h&&(!g||!String(g).trim())&&d.push(p.label||p.name);const v=m.validateField(p,g||"",l);v.length&&u.push(v[0].message)}),d.length||u.length){const p=[];d.length&&p.push("Required: "+d.join(", ")),u.length&&p.push(u.join("; ")),C(n,p.join(". "),"error");return}}if(n.dataset.triggerBlocked==="true"){const m=n._formLogicRuntime,d=m&&m.submitBlock?m.submitBlock().reasons:[];C(n,d.join(" ")||"This form cannot be submitted yet.","error");return}n.classList.add("fb-form-loading"),c.disabled=!0,x(e,l,t,n,i).finally(function(){n.classList.remove("fb-form-loading"),c.disabled=!1})}),n.appendChild(i),N(i,t,"stacked"),enhancePickerFields(n,o),F(n,function(a){return x(e,a,t,n,i)}),window.FormLogicEngine&&r&&T(o)){const a=new window.FormLogicEngine.FormLogicRuntime(r,n);a.init(),n._formLogicRuntime=a}}function ne(n){const o=n.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],r=t.settings||{},i=document.createElement("div");i.className="fb-form-wrapper",n.appendChild(i);const c=e.some(s=>s.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const s=Number(r.columns)===3?3:2,a=r.layout||"grid";if(c&&Domma.forms.wizard){const l=W(e,t.title),m=l.map(f=>f.fields),d=l.map(function(f){return{title:f.title,description:f.description,fields:B(f.fields,s)}});let u=0,p=null,b=null;const h=Date.now(),g=new Map,v=function(f){const y=window.FormLogicEngine;if(!y||!y.validateFields)return;const k=y.validateFields(i,m[u]||[]);k.valid||(f.preventDefault(),f.stopImmediatePropagation(),markInvalidFields(i,k.missing),showValidationPopup(k))},w=function(){const f=m[u]||e;if(J(i,r),R(i,f),enhancePickerFields(i,f),f.some(y=>y.type==="spacer")&&V(i,f),r.honeypot){const y=i.querySelector("form");y&&q(y,h)}window.FormLogicEngine&&T(e)&&(p&&p.destroy(),p=new window.FormLogicEngine.FormLogicRuntime(t,i,{baseValues:b&&b.getStepData?b.getStepData():{}}),p.init(),A(i,p)),i.querySelectorAll(".wizard-next, .wizard-submit").forEach(y=>y.addEventListener("click",v,!0))};b=Domma.forms.wizard(i,{schema:{steps:d},layout:a,columns:s,finishText:r.submitText||"Finish",onStepChange:function(f){L(i,g),u=f,setTimeout(w,0)},onSubmit:function(f){return L(i,g),x(o,f,r,i,null,g)}}),F(i,function(f){return L(i,g),x(o,f,r,i,null,g)}),i.addEventListener("dm-form-trigger",function(f){if(!f.detail||f.detail.type!=="goto-step"||!b||!b.goToStep)return;const y=Number(f.detail.action.step);!isFinite(y)||y<0||y>=d.length||y!==u&&b.goToStep(y)}),Promise.resolve(b).then(w)}else if(Domma.forms.render){const l=B(e,s),m=$(e);F(i,function(u){return x(o,u,r,i,null)});const d=Domma.forms.render(i,l,m,{submitText:r.submitText||"Submit",layout:a,columns:s,onSubmit:function(u){return x(o,u,r,i,null)}});Promise.resolve(d).then(function(){if(N(i,r,a),R(i,e),enhancePickerFields(i,e),window.FormLogicEngine&&T(e)){const u=new window.FormLogicEngine.FormLogicRuntime(t,i);u.init(),A(i,u)}if(e.some(u=>u.type==="spacer")&&V(i,e),r.honeypot){const u=i.querySelector("form");u&&q(u)}})}}else te(i,e.filter(s=>s.type!=="page-break"&&s.type!=="spacer"),r,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",n.appendChild(e),console.warn("[forms]",t.message)})}
1
+ import{buildWizardSteps as J}from"/public/js/form-steps.mjs";import{applyFormClasses as T,applySubmitButtons as _,applyWizardButtons as U,resolveSecondaryButton as H,submitWrapperClasses as K}from"/public/js/form-submit.mjs";const j=document.querySelectorAll("[data-form]");j.length&&j.forEach(oe);function F(n){return(n||[]).some(o=>o.logic||Array.isArray(o.triggers)&&o.triggers.length)}function Y(n,o){const t=n.querySelector('[name="'+o+'"], [name="'+o+'[]"]')||n.querySelector('[data-chooser-field="'+o+'"]');if(!t)return null;const e=t.closest("form")||n;let i=t;for(;i.parentNode&&i.parentNode!==e;)i=i.parentNode;return i}export function markInvalidFields(n,o){n.querySelectorAll(".fb-field-invalid").forEach(e=>e.classList.remove("fb-field-invalid"));let t=null;(o||[]).forEach(function(e){const i=Y(n,e.name);i&&(i.classList.add("fb-field-invalid"),t||(t=i))}),t&&t.scrollIntoView&&t.scrollIntoView({behavior:"smooth",block:"center"})}export function showValidationPopup(n){const o=(n.missing||[]).map(e=>"<strong>"+A(e.label)+"</strong> is required.").concat((n.errors||[]).map(A)),t=o.join("<br>");if(typeof E<"u"&&E.alert){E.alert(t,{title:"Please complete this step"});return}window.alert(o.join(`
2
+ `).replace(/<[^>]+>/g,""))}function A(n){return String(n).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function q(n,o){let t=!1;n.addEventListener("dm-form-end",function(e){const i=e.detail&&e.detail.validation;if(i&&!i.valid){markInvalidFields(n,i.missing),showValidationPopup(i);return}t||(t=!0,n.classList.add("fb-form-loading"),Promise.resolve(o(e.detail&&e.detail.values||{})).catch(function(){}).finally(function(){t=!1,n.classList.remove("fb-form-loading")}))})}function C(n,o,t){const e=n.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const i=document.createElement("div");i.className=t==="success"?"fb-form-success":"fb-form-error",i.textContent=o,n.appendChild(i)}function B(n,o){if(n._formLogicRuntime=o,n._formLogicObserver&&(n._formLogicObserver.disconnect(),n._formLogicObserver=null),!n.parentNode||typeof MutationObserver>"u"||n._formLogicObserved)return;n._formLogicObserved=!0;const t=new MutationObserver(function(e){for(const i of e)for(const r of i.removedNodes)if(r===n||r.nodeType===1&&r.contains&&r.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1}),n._formLogicObserver=t}function $(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function R(n,o){const t={};return n.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,l={...e.formConfig||{}};l.span==="full"&&o&&(l.span=o);const s={type:r,label:e.label||e.name,required:$(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...l}};e.minLength!==void 0&&(s.minLength=e.minLength),e.maxLength!==void 0&&(s.maxLength=e.maxLength),e.min!==void 0&&(s.min=e.min),e.max!==void 0&&(s.max=e.max),i&&(e.variant&&(s.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(s.multiple=!0),e.density&&(s.density=e.density),e.columns&&(s.columns=e.columns),e.accent&&(s.accent=e.accent),e.accentStyle&&(s.accentStyle=e.accentStyle),e.glow&&(s.glow=!0),e.glowColour&&(s.glowColour=e.glowColour),e.shadow&&(s.shadow=e.shadow),e.shadowColour&&(s.shadowColour=e.shadowColour)),t[e.name]=s}),t}function G(n){const o={};return n.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function O(n,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=n.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}const z="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function P(n){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const i=document.createElement("strong");i.textContent=n;const r=document.createElement("button");r.type="button",r.textContent="\xD7",r.setAttribute("aria-label","Close"),r.style.cssText=z+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(i),e.appendChild(r),t.appendChild(e);const l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(l),o.appendChild(t);const s=c=>{c.key==="Escape"&&a()};function a(){document.removeEventListener("keydown",s),o.remove()}return r.addEventListener("click",a),o.addEventListener("click",c=>{c.target===o&&a()}),document.addEventListener("keydown",s),document.body.appendChild(o),{body:l,close:a}}function Q(n){const{body:o,close:t}=P("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const i=document.createElement("div");i.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(i);const r=window.I&&typeof I.list=="function"?I.list():[],l=r.map(s=>{const a=document.createElement("button");a.type="button",a.title=s,a.dataset.iconName=s,a.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const c=document.createElement("span");return c.setAttribute("data-icon",s),c.setAttribute("data-icon-size","18"),a.appendChild(c),a.addEventListener("mouseenter",()=>{a.style.borderColor="var(--dm-border)"}),a.addEventListener("mouseleave",()=>{a.style.borderColor="transparent"}),a.addEventListener("click",()=>{t(),n(s)}),i.appendChild(a),a});if(!r.length){const s=document.createElement("p");s.textContent="Icon engine unavailable - type an icon name into the field instead.",i.appendChild(s)}window.I?.scan?.(i),e.addEventListener("input",()=>{const s=e.value.trim().toLowerCase();l.forEach(a=>{a.style.display=!s||a.dataset.iconName.includes(s)?"":"none"})}),e.focus()}async function X(){const n=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!n)return{error:"auth"};const o=i=>fetch("/api/media",{headers:{Authorization:"Bearer "+i}});let t;try{if(t=await o(n),t.status===401&&S.get("auth_refresh_token")){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(i.ok){const{token:r}=await i.json();S.set("auth_token",r),t=await o(r)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(i=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(i.name||i.url||""))}}function Z(n){const{body:o,close:t}=P("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),X().then(({files:i,error:r})=>{if(r){e.textContent=r==="auth"?"Sign in with media access to browse the library - or paste an image URL into the field.":"Could not load the media library - paste an image URL into the field instead.";return}if(!i.length){e.textContent="No images in the media library yet.";return}e.remove();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",i.forEach(s=>{const a=document.createElement("button");a.type="button",a.title=s.name||s.url,a.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const c=document.createElement("img");c.src=s.url,c.alt=s.name||"",c.loading="lazy",c.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const m=document.createElement("span");m.textContent=s.name||s.url,m.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",a.appendChild(c),a.appendChild(m),a.addEventListener("click",()=>{t(),n(s.url)}),l.appendChild(a)}),o.appendChild(l)})}function D(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function M(n){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",n.parentNode.insertBefore(o,n),o.appendChild(n),n.style.flex="1",n.style.minWidth="0",o}function V(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=z,o}function ee(n){if(!window.I||typeof I.list!="function")return;const o=M(n),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const r=n.value.trim();if(!r)return;const l=document.createElement("span");l.setAttribute("data-icon",r),l.setAttribute("data-icon-size","16"),t.appendChild(l),window.I?.scan?.(t)};n.addEventListener("input",e),e();const i=V("Browse");i.addEventListener("click",()=>Q(r=>{D(n,r),e()})),o.appendChild(t),o.appendChild(i)}function te(n){const o=M(n),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const r=n.value.trim();t.style.display=r?"":"none",r&&(t.src=r)};n.addEventListener("input",e),e();const i=V("Browse");i.addEventListener("click",()=>Z(r=>{D(n,r),e()})),o.appendChild(t),o.appendChild(i)}export function enhancePickerFields(n,o){const t=typeof n=="string"?document.querySelector(n):n;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const i=t.querySelector('[name="'+e.name+'"]');!i||i.dataset.pickerEnhanced||(i.dataset.pickerEnhanced="1",e.type==="icon"?ee(i):te(i))})}function N(n,o){const t=document.createElement("div");t.className="fb-form-honeypot",t.setAttribute("aria-hidden","true");const e=document.createElement("input");e.name=n.querySelector('[name="website"]')?"_website":"website",t.dataset.hpName=e.name,e.type="text",e.tabIndex=-1,e.autocomplete="url",e.placeholder="https://",t.appendChild(e);const i=document.createElement("input");i.name="_t",i.type="hidden",i.value=o||Date.now(),t.appendChild(i),n.appendChild(t)}function W(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let i=0;o.forEach(function(r){if(r.type==="spacer"){const l=document.createElement("div");l.className="fb-spacer";const s=e[i];if(s)t.insertBefore(l,s);else{const a=t.querySelector('[type="submit"]');a?t.insertBefore(l,a):t.appendChild(l)}}else r.type!=="page-break"&&i++})}function L(n,o){!n||!o||n.querySelectorAll('input[type="file"]').forEach(function(t){t.name&&t.files&&t.files.length&&o.set(t.name,Array.from(t.files))})}function x(n,o,t,e,i,r){const l=i||e,s=l.querySelector(".fb-form-honeypot"),a=s?.querySelector('input[type="text"]')?.value||"",c=s?.querySelector('[name="_t"]')?.value||"",m=Object.assign({},o);delete m._t,s?.dataset.hpName&&delete m[s.dataset.hpName];const d=new Map(r||[]);L(l,d);const u=d.size>0;let p,b;if(u){const h=new FormData;for(const[g,v]of Object.entries(m))v!=null&&(d.has(g)||h.append(g,typeof v=="object"?JSON.stringify(v):String(v)));for(const[g,v]of d)for(const w of v)h.append(g,w,w.name);h.append("_hp",a),h.append("_t",c),p=h,b={}}else{const h=Object.assign({},m,{_hp:a,_t:c});p=JSON.stringify(h),b={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:b,body:p}).then(h=>h.json().then(g=>({ok:h.ok,body:g}))).then(h=>{h.ok&&h.body.ok?(e.textContent="",C(e,h.body.message||t.successMessage||"Thank you.","success")):C(e,h.body.error||"Something went wrong.","error")}).catch(()=>{C(e,"Unable to submit. Please check your connection.","error")})}function ne(n,o,t,e,i){const r=document.createElement("form");r.noValidate=!0,o.forEach(function(a){const c=document.createElement("div");c.className="form-group",c.style.marginBottom="1.25rem",a.name&&(c.dataset.field=a.name);const m=document.createElement("label");if(m.className="form-label",m.textContent=a.label||a.name,a.required){const u=document.createElement("span");u.textContent=" *",u.style.color="var(--dm-danger)",m.appendChild(u)}let d;a.type==="textarea"?(d=document.createElement("textarea"),d.rows=a.formConfig?.rows||4,d.className="form-input"):a.type==="select"?(d=document.createElement("select"),d.className="form-input",(a.options||[]).forEach(function(u){const p=document.createElement("option");p.value=typeof u=="string"?u:u.value??"",p.textContent=typeof u=="string"?u:u.label||p.value,d.appendChild(p)})):(d=document.createElement("input"),d.type=a.type==="icon"||a.type==="image"?"text":a.type||"text",d.className="form-input",a.placeholder&&(d.placeholder=a.placeholder),a.type==="file"&&(a.file?.accept&&(d.accept=a.file.accept),a.multiple&&(d.multiple=!0))),d.name=a.name,d.required=a.required||!1,c.appendChild(m),c.appendChild(d),r.appendChild(c)}),t.honeypot&&N(r);const l=document.createElement("button");if(l.type="submit",l.className="btn btn-primary",l.textContent=t.submitText||"Submit",K(t,"stacked").length||H(t)){const a=document.createElement("div");a.className="form-group form-buttons",a.appendChild(l),r.appendChild(a)}else r.appendChild(l);if(r.addEventListener("submit",function(a){a.preventDefault();const c={};if(o.forEach(function(m){const d=r.querySelector('[name="'+m.name+'"]');d&&(c[m.name]=d.value)}),window.FormLogicEngine&&i){const m=window.FormLogicEngine,d=[],u=[];if(o.forEach(function(p){if(m.evaluateFieldVisibility(p,c)==="hidden"){delete c[p.name];return}const h=m.evaluateFieldRequirement(p,c),g=c[p.name];h&&(!g||!String(g).trim())&&d.push(p.label||p.name);const v=m.validateField(p,g||"",c);v.length&&u.push(v[0].message)}),d.length||u.length){const p=[];d.length&&p.push("Required: "+d.join(", ")),u.length&&p.push(u.join("; ")),C(n,p.join(". "),"error");return}}if(n.dataset.triggerBlocked==="true"){const m=n._formLogicRuntime,d=m&&m.submitBlock?m.submitBlock().reasons:[];C(n,d.join(" ")||"This form cannot be submitted yet.","error");return}n.classList.add("fb-form-loading"),l.disabled=!0,x(e,c,t,n,r).finally(function(){n.classList.remove("fb-form-loading"),l.disabled=!1})}),n.appendChild(r),_(r,t,"stacked"),T(r,t,o),enhancePickerFields(n,o),q(n,function(a){return x(e,a,t,n,r)}),window.FormLogicEngine&&i&&F(o)){const a=new window.FormLogicEngine.FormLogicRuntime(i,n);a.init(),n._formLogicRuntime=a}}function oe(n){const o=n.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],i=t.settings||{},r=document.createElement("div");r.className="fb-form-wrapper",n.appendChild(r);const l=e.some(s=>s.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const s=Number(i.columns)===3?3:2,a=i.layout||"grid";if(l&&Domma.forms.wizard){const c=J(e,t.title),m=c.map(f=>f.fields),d=c.map(function(f){return{title:f.title,description:f.description,fields:R(f.fields,s)}});let u=0,p=null,b=null;const h=Date.now(),g=new Map,v=function(f){const y=window.FormLogicEngine;if(!y||!y.validateFields)return;const k=y.validateFields(r,m[u]||[]);k.valid||(f.preventDefault(),f.stopImmediatePropagation(),markInvalidFields(r,k.missing),showValidationPopup(k))},w=function(){const f=m[u]||e;if(U(r,i),T(r,i,f),O(r,f),enhancePickerFields(r,f),f.some(y=>y.type==="spacer")&&W(r,f),i.honeypot){const y=r.querySelector("form");y&&N(y,h)}window.FormLogicEngine&&F(e)&&(p&&p.destroy(),p=new window.FormLogicEngine.FormLogicRuntime(t,r,{baseValues:b&&b.getStepData?b.getStepData():{}}),p.init(),B(r,p)),r.querySelectorAll(".wizard-next, .wizard-submit").forEach(y=>y.addEventListener("click",v,!0))};b=Domma.forms.wizard(r,{schema:{steps:d},layout:a,columns:s,finishText:i.submitText||"Finish",onStepChange:function(f){L(r,g),u=f,setTimeout(w,0)},onSubmit:function(f){return L(r,g),x(o,f,i,r,null,g)}}),q(r,function(f){return L(r,g),x(o,f,i,r,null,g)}),r.addEventListener("dm-form-trigger",function(f){if(!f.detail||f.detail.type!=="goto-step"||!b||!b.goToStep)return;const y=Number(f.detail.action.step);!isFinite(y)||y<0||y>=d.length||y!==u&&b.goToStep(y)}),Promise.resolve(b).then(w)}else if(Domma.forms.render){const c=R(e,s),m=G(e);q(r,function(u){return x(o,u,i,r,null)});const d=Domma.forms.render(r,c,m,{submitText:i.submitText||"Submit",layout:a,columns:s,onSubmit:function(u){return x(o,u,i,r,null)}});Promise.resolve(d).then(function(){if(_(r,i,a),T(r,i,e),O(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&F(e)){const u=new window.FormLogicEngine.FormLogicRuntime(t,r);u.init(),B(r,u)}if(e.some(u=>u.type==="spacer")&&W(r,e),i.honeypot){const u=r.querySelector("form");u&&N(u)}})}}else ne(r,e.filter(s=>s.type!=="page-break"&&s.type!=="spacer"),i,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",n.appendChild(e),console.warn("[forms]",t.message)})}
@@ -1 +1 @@
1
- export const PRESET_COLOUR_VARS={primary:"--dm-primary",success:"--dm-success",danger:"--dm-danger",warning:"--dm-warning",info:"--dm-info",neutral:"--dm-text-muted"},PRESET_COLOUR_FALLBACKS={primary:"#0d6efd",success:"#198754",danger:"#dc3545",warning:"#ffc107",info:"#0dcaf0",neutral:"#6c757d"};const l=/^#[0-9a-fA-F]{6}$/;export function colourToCss(t){return typeof t!="string"?"":PRESET_COLOUR_VARS[t]?`var(${PRESET_COLOUR_VARS[t]}, ${PRESET_COLOUR_FALLBACKS[t]})`:l.test(t)?t:""}export const FLOAT_ANCHORS=["TL","TR","BL","BR","L","R"],FLOAT_DEFAULTS={anchor:"TL",offsetX:16,offsetY:16,zIndex:150},FLOAT_SHADOWS={none:"none",sm:"var(--dm-shadow-sm)",md:"var(--dm-shadow-md)",lg:"var(--dm-shadow-lg)",xl:"var(--dm-shadow-xl)"};function i(t,e,o,r){const n=Number(t);return Number.isFinite(n)?Math.min(r,Math.max(o,Math.round(n))):e}function d(t){const e=[];if(t.radius!=null&&t.radius!==""&&e.push(`border-radius:${i(t.radius,8,0,48)}px`),t.shadow!=null&&t.shadow!==""&&Object.prototype.hasOwnProperty.call(FLOAT_SHADOWS,t.shadow)&&e.push(`box-shadow:${FLOAT_SHADOWS[t.shadow]}`),t.accent&&colourToCss(t.accent)){const o=colourToCss(t.accent);e.push(`--dm-menu-accent:${o}`,`border-color:${o}`)}return t.opacity!=null&&t.opacity!==""&&e.push(`--dm-menu-panel-opacity:${i(t.opacity,100,20,100)/100}`),e}export function floatToCss(t){if(!t||t.position!=="floating")return"";const e=t.float&&typeof t.float=="object"&&!Array.isArray(t.float)?t.float:{},o=FLOAT_ANCHORS.includes(e.anchor)?e.anchor:FLOAT_DEFAULTS.anchor,r=i(e.offsetX,FLOAT_DEFAULTS.offsetX,0,4e3),n=i(e.offsetY,FLOAT_DEFAULTS.offsetY,0,4e3),a=["position:fixed",`z-index:${i(e.zIndex,FLOAT_DEFAULTS.zIndex,0,2147483647)}`];return o==="L"||o==="R"?(a.push("top:50%","transform:translateY(-50%)"),a.push(o==="L"?`left:${r}px`:`right:${r}px`)):(a.push(o[0]==="T"?`top:${n}px`:`bottom:${n}px`),a.push(o[1]==="L"?`left:${r}px`:`right:${r}px`)),e.width!=null&&e.width!==""&&a.push(`width:${i(e.width,260,120,600)}px`),a.push(`max-height:calc(100vh - ${o==="L"||o==="R"?32:n*2}px)`),a.push(...d(e)),a.join(";")}export const FLOAT_FLAGS=["collapsible","collapsed","movable","resizable"];export function floatBehaviour(t){const e={collapsible:!1,collapsed:!1,movable:!1,resizable:!1,chrome:!1,title:""};if(!t||t.position!=="floating")return e;const o=t.float&&typeof t.float=="object"&&!Array.isArray(t.float)?t.float:{},r={collapsible:!!o.collapsible,collapsed:!!o.collapsible&&!!o.collapsed,movable:!!o.movable,resizable:!!o.resizable},n=r.collapsible||r.movable,s=typeof o.title=="string"&&o.title!==""?o.title:t.name||"";return{...r,chrome:n,title:n?s:""}}export function applyFloat(t,e){const o=floatToCss(e);if(!t||!o)return!1;t.style.cssText+=";"+o,t.classList.add("dm-menu-floating"),e.slug&&!t.hasAttribute("data-menu")&&t.setAttribute("data-menu",e.slug),e.float?.anchor&&t.setAttribute("data-float-anchor",e.float.anchor);const r=floatBehaviour(e);for(const n of FLOAT_FLAGS)n!=="collapsed"&&r[n]&&t.setAttribute(`data-float-${n}`,"1");return r.collapsed&&t.setAttribute("data-float-collapsed","1"),r.title&&t.setAttribute("data-float-title",r.title),!0}export function makeBadgeEl(t){if(!t||t.text==null||t.text==="")return null;const e=document.createElement("span");e.className="dm-menu-badge",e.textContent=String(t.text);const o=t.variant?colourToCss(t.variant):"";return o&&(e.style.background=o,e.style.color="var(--dm-text-inverse, #fff)"),e}export function applyColour(t,e){const o=colourToCss(e);o&&(t.style.color=o)}export function applyPill(t,e){if(!e)return;t.classList.add("dm-nav-pill");const o=e.variant?colourToCss(e.variant):"";e.style==="outline"?(t.classList.add("dm-nav-pill--outline"),o&&(t.style.borderColor=o,t.style.color=o)):o&&(t.style.background=o,t.style.color="#fff")}export const MENU_ALIGN=["left","centre","right","spread"];export function menuAlign(t){const e=t&&t.align;return MENU_ALIGN.includes(e)?e:""}export const HIGHLIGHT_HOVER=["none","colour","underline","overline","background","uppercase","grow","breathe","glow"],HIGHLIGHT_ACTIVE=["none","bold","underline","overline","background","darken","pill"],HIGHLIGHT_HOVER_LABELS={none:"None - no change on hover",colour:"Colour change",underline:"Underline",overline:"Overline",background:"Background tint",uppercase:"Uppercase",grow:"Grow",breathe:"Breathe",glow:"Glow"},HIGHLIGHT_ACTIVE_LABELS={none:"None - not marked at all",bold:"Bold",underline:"Underline",overline:"Overline",background:"Background tint",darken:"Darkened",pill:"Filled pill"},LEGACY_STYLE_HOVER={none:"none",underline:"underline",overline:"overline",transform:"uppercase","text-transform":"uppercase",breathe:"breathe"},LEGACY_STYLE_ACTIVE={none:"none",darken:"darken",background:"background","background-color":"background",underline:"underline",overline:"overline"};export function legacyStyleHighlight(t){const e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};return{hover:LEGACY_STYLE_HOVER[e.hover]||"",active:LEGACY_STYLE_ACTIVE[e.active]||""}}export function highlightAttrs(t){const e=t&&t.highlight&&typeof t.highlight=="object"&&!Array.isArray(t.highlight)?t.highlight:{},o=legacyStyleHighlight(t&&t.style);return{hover:HIGHLIGHT_HOVER.includes(e.hover)?e.hover:o.hover,active:HIGHLIGHT_ACTIVE.includes(e.active)?e.active:o.active,accent:e.accent?colourToCss(e.accent):""}}export function applyHighlight(t,e){if(!t)return!1;const{hover:o,active:r,accent:n}=highlightAttrs(e);return o&&t.setAttribute("data-menu-hover",o),r&&t.setAttribute("data-menu-active",r),n&&t.style.setProperty("--dm-menu-highlight",n),!!(o||r||n)}export function itemHighlightAttrs(t){const e=t&&t.highlight&&typeof t.highlight=="object"&&!Array.isArray(t.highlight)?t.highlight:{};return{hover:HIGHLIGHT_HOVER.includes(e.hover)?e.hover:"",active:HIGHLIGHT_ACTIVE.includes(e.active)?e.active:"",accent:e.accent?colourToCss(e.accent):""}}export function applyItemHighlight(t,e){if(!t)return!1;const{hover:o,active:r,accent:n}=itemHighlightAttrs(e);return o&&t.setAttribute("data-menu-item-hover",o),r&&t.setAttribute("data-menu-item-active",r),n&&t.style.setProperty("--dm-menu-highlight",n),!!(o||r||n)}function c(t){if(typeof t!="string"||!t)return"";const e=t.split("#")[0].split("?")[0];return e.startsWith("/")?e.length>1&&e.endsWith("/")?e.slice(0,-1):e:""}export function isCurrentItem(t,e){const o=c(t),r=c(e);return!!o&&!!r&&o===r}
1
+ export const PRESET_COLOUR_VARS={primary:"--dm-primary",success:"--dm-success",danger:"--dm-danger",warning:"--dm-warning",info:"--dm-info",neutral:"--dm-text-muted"},PRESET_COLOUR_FALLBACKS={primary:"#0d6efd",success:"#198754",danger:"#dc3545",warning:"#ffc107",info:"#0dcaf0",neutral:"#6c757d"};const l=/^#[0-9a-fA-F]{6}$/;export function colourToCss(t){return typeof t!="string"?"":PRESET_COLOUR_VARS[t]?`var(${PRESET_COLOUR_VARS[t]}, ${PRESET_COLOUR_FALLBACKS[t]})`:l.test(t)?t:""}export const FLOAT_ANCHORS=["TL","TR","BL","BR","L","R"],FLOAT_DEFAULTS={anchor:"TL",offsetX:16,offsetY:16,zIndex:150},FLOAT_SHADOWS={none:"none",sm:"var(--dm-shadow-sm)",md:"var(--dm-shadow-md)",lg:"var(--dm-shadow-lg)",xl:"var(--dm-shadow-xl)"};function s(t,e,o,r){const n=Number(t);return Number.isFinite(n)?Math.min(r,Math.max(o,Math.round(n))):e}function f(t){const e=[];if(t.radius!=null&&t.radius!==""&&e.push(`border-radius:${s(t.radius,8,0,48)}px`),t.shadow!=null&&t.shadow!==""&&Object.prototype.hasOwnProperty.call(FLOAT_SHADOWS,t.shadow)&&e.push(`box-shadow:${FLOAT_SHADOWS[t.shadow]}`),t.accent&&colourToCss(t.accent)){const o=colourToCss(t.accent);e.push(`--dm-menu-accent:${o}`,`border-color:${o}`)}return t.opacity!=null&&t.opacity!==""&&e.push(`--dm-menu-panel-opacity:${s(t.opacity,100,20,100)/100}`),e}export function floatToCss(t){if(!t||t.position!=="floating")return"";const e=t.float&&typeof t.float=="object"&&!Array.isArray(t.float)?t.float:{},o=FLOAT_ANCHORS.includes(e.anchor)?e.anchor:FLOAT_DEFAULTS.anchor,r=s(e.offsetX,FLOAT_DEFAULTS.offsetX,0,4e3),n=s(e.offsetY,FLOAT_DEFAULTS.offsetY,0,4e3),a=["position:fixed",`z-index:${s(e.zIndex,FLOAT_DEFAULTS.zIndex,0,2147483647)}`];return o==="L"||o==="R"?(a.push("top:50%","transform:translateY(-50%)"),a.push(o==="L"?`left:${r}px`:`right:${r}px`)):(a.push(o[0]==="T"?`top:${n}px`:`bottom:${n}px`),a.push(o[1]==="L"?`left:${r}px`:`right:${r}px`)),e.width!=null&&e.width!==""&&a.push(`width:${s(e.width,260,120,600)}px`),a.push(`max-height:calc(100vh - ${o==="L"||o==="R"?32:n*2}px)`),a.push(...f(e)),a.join(";")}export const FLOAT_FLAGS=["collapsible","collapsed","movable","resizable"];export function floatBehaviour(t){const e={collapsible:!1,collapsed:!1,movable:!1,resizable:!1,chrome:!1,title:""};if(!t||t.position!=="floating")return e;const o=t.float&&typeof t.float=="object"&&!Array.isArray(t.float)?t.float:{},r={collapsible:!!o.collapsible,collapsed:!!o.collapsible&&!!o.collapsed,movable:!!o.movable,resizable:!!o.resizable},n=r.collapsible||r.movable,i=typeof o.title=="string"&&o.title!==""?o.title:t.name||"";return{...r,chrome:n,title:n?i:""}}export function applyFloat(t,e){const o=floatToCss(e);if(!t||!o)return!1;t.style.cssText+=";"+o,t.classList.add("dm-menu-floating"),e.slug&&!t.hasAttribute("data-menu")&&t.setAttribute("data-menu",e.slug),e.float?.anchor&&t.setAttribute("data-float-anchor",e.float.anchor);const r=floatBehaviour(e);for(const n of FLOAT_FLAGS)n!=="collapsed"&&r[n]&&t.setAttribute(`data-float-${n}`,"1");return r.collapsed&&t.setAttribute("data-float-collapsed","1"),r.title&&t.setAttribute("data-float-title",r.title),!0}export function makeBadgeEl(t){if(!t||t.text==null||t.text==="")return null;const e=document.createElement("span");e.className="dm-menu-badge",e.textContent=String(t.text);const o=t.variant?colourToCss(t.variant):"";return o&&(e.style.background=o,e.style.color="var(--dm-text-inverse, #fff)"),e}export function applyColour(t,e){const o=colourToCss(e);o&&(t.style.color=o)}export function applyPill(t,e){if(!e)return;t.classList.add("dm-nav-pill");const o=e.variant?colourToCss(e.variant):"";e.style==="outline"?(t.classList.add("dm-nav-pill--outline"),o&&(t.style.borderColor=o,t.style.color=o)):o&&(t.style.background=o,t.style.color="#fff")}export const MENU_ALIGN=["left","centre","right","spread"];export function menuAlign(t){const e=t&&t.align;return MENU_ALIGN.includes(e)?e:""}export const HIGHLIGHT_HOVER=["none","colour","underline","overline","background","uppercase","grow","breathe","glow"],HIGHLIGHT_ACTIVE=["none","bold","underline","overline","background","darken","pill"],HIGHLIGHT_HOVER_LABELS={none:"None - no change on hover",colour:"Colour change",underline:"Underline",overline:"Overline",background:"Background tint",uppercase:"Uppercase",grow:"Grow",breathe:"Breathe",glow:"Glow"},HIGHLIGHT_ACTIVE_LABELS={none:"None - not marked at all",bold:"Bold",underline:"Underline",overline:"Overline",background:"Background tint",darken:"Darkened",pill:"Filled pill"},LEGACY_STYLE_HOVER={none:"none",underline:"underline",overline:"overline",transform:"uppercase","text-transform":"uppercase",breathe:"breathe"},LEGACY_STYLE_ACTIVE={none:"none",darken:"darken",background:"background","background-color":"background",underline:"underline",overline:"overline"};export function legacyStyleHighlight(t){const e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};return{hover:LEGACY_STYLE_HOVER[e.hover]||"",active:LEGACY_STYLE_ACTIVE[e.active]||""}}export function highlightAttrs(t){const e=t&&t.highlight&&typeof t.highlight=="object"&&!Array.isArray(t.highlight)?t.highlight:{},o=legacyStyleHighlight(t&&t.style);return{hover:HIGHLIGHT_HOVER.includes(e.hover)?e.hover:o.hover,active:HIGHLIGHT_ACTIVE.includes(e.active)?e.active:o.active,accent:e.accent?colourToCss(e.accent):""}}export function applyHighlight(t,e){if(!t)return!1;const{hover:o,active:r,accent:n}=highlightAttrs(e);return o&&t.setAttribute("data-menu-hover",o),r&&t.setAttribute("data-menu-active",r),n&&t.style.setProperty("--dm-menu-highlight",n),!!(o||r||n)}export function itemHighlightAttrs(t){const e=t&&t.highlight&&typeof t.highlight=="object"&&!Array.isArray(t.highlight)?t.highlight:{};return{hover:HIGHLIGHT_HOVER.includes(e.hover)?e.hover:"",active:HIGHLIGHT_ACTIVE.includes(e.active)?e.active:"",accent:e.accent?colourToCss(e.accent):""}}export function applyItemHighlight(t,e){if(!t)return!1;const{hover:o,active:r,accent:n}=itemHighlightAttrs(e);return o&&t.setAttribute("data-menu-item-hover",o),r&&t.setAttribute("data-menu-item-active",r),n&&t.style.setProperty("--dm-menu-highlight",n),!!(o||r||n)}function c(t){if(typeof t!="string"||!t)return"";const e=t.split("#")[0].split("?")[0];return e.startsWith("/")?e.length>1&&e.endsWith("/")?e.slice(0,-1):e:""}export function isCurrentItem(t,e){const o=c(t),r=c(e);return!!o&&!!r&&o===r}export{CSS_CLASS_RE,CSS_CLASS_MAX,CSS_CLASS_MAX_LEN,cssClasses,cssClassProblems,normaliseCssClasses,applyClasses}from"./css-classes.mjs";
package/public/js/site.js CHANGED
@@ -1 +1 @@
1
- import{makeBadgeEl as z,applyColour as O,applyPill as V,applyFloat as J,applyHighlight as N,applyItemHighlight as W,itemHighlightAttrs as X,isCurrentItem as B,menuAlign as G}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{initFloatingMenus as Y}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as j,markInvalidFields as R,showValidationPopup as P}from"/public/js/forms.js?v=20260927-submit-btn";import{buildWizardSteps as U}from"/public/js/form-steps.mjs";import{applySubmitButtons as K,applyWizardButtons as Q}from"/public/js/form-submit.mjs";$(()=>{const C=window.__CMS_NAV__||{},y=window.__CMS_SITE__||{};if(y.autoTheme?.enabled){let t=function(e){const s=(e||"07:00").split(":");return+s[0]*60+(+s[1]||0)},i=function(){const e=new Date,s=e.getHours()*60+e.getMinutes();return s>=t(a.dayStart)&&s<t(a.nightStart)?a.dayTheme:a.nightTheme},o=function(e){const s=a.apply&&a.apply[e]||{theme:e,custom:""};Domma.theme.set(s.theme);for(const p of[...document.body.classList])p.startsWith("dm-custom-")&&document.body.classList.remove(p);s.custom&&document.body.classList.add(s.custom)};const a=y.autoTheme;o(i()),setInterval(()=>o(i()),6e4)}const _=$("#site-navbar");if(_.length&&C.brand){let i=function(c,h=0){return Array.isArray(c)?c.filter(r=>!(r&&r.type==="spacer")).filter(r=>!(r&&r.type==="separator"&&h===0)).map(r=>r&&r.type==="separator"?{divider:!0}:Array.isArray(r?.items)?{...r,items:i(r.items,h+1)}:r):c},o=function(c){return Array.isArray(c)?c.filter(h=>!(h&&(h.type==="separator"||h.type==="spacer"))):[]};const a={...C.brand},t=a.size&&a.size!=="md"?` navbar-brand-${a.size}`:"";if(a.logo||a.icon||a.tagline){let c="";a.logo?c+=`<img src="${a.logo}" class="navbar-brand-logo" alt="${a.text||""}">`:a.icon&&(c+=`<span data-icon="${a.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),a.text&&(c+=`<span class="navbar-brand-text${t}">${a.text}</span>`),a.tagline&&(c+=`<small class="navbar-brand-tagline">${a.tagline}</small>`),a.html=c}else t&&a.text&&(a.html=`<span class="navbar-brand-text${t}">${a.text}</span>`);const e=C.position==="floating",s=C.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:a,items:i(C.items||[]),variant:C.variant||"dark",position:e?"static":C.position||"sticky",collapsible:!0,appearOnHover:!!C.appearOnHover}),Domma.icons.scan("#site-navbar");const p=_.get(0);p.classList.add(`dm-nav-align-${G(C)||"centre"}`),s&&_.get(0).classList.add("dm-nav-vertical",C.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),N(p,C),e&&(J(_.get(0),C),Y(_.get(0).parentNode||document));const g=p.querySelector(".navbar-toggle"),u=p.querySelector(".navbar-collapse");if(g&&u){let c=null;const h=()=>{u.classList.contains("show")&&g.click()},r=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},n=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",h),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};g.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?n():r()})}),u.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(r)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&u.classList.contains("show")&&h()})}const m=p.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let h=0;for(const r of C.items||[])if(!(r&&r.type==="separator")){if(r&&r.type==="spacer"){const n=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md";n.className=`dm-menu-spacer dm-menu-spacer--${l}`,n.setAttribute("aria-hidden","true"),m.insertBefore(n,c[h]||null);continue}h++}}const b=o(C.items||[]);p.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const h=b[parseInt(c.dataset.index,10)];if(!h)return;const r=c.dataset.subindex!=null,n=r&&Array.isArray(h.items)?h.items[parseInt(c.dataset.subindex,10)]:h;if(!n)return;n.colour&&O(c,n.colour),n.pill&&!r&&V(c,n.pill),W(c,n);const l=z(n.badge);l&&c.appendChild(l),B(n.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const x=$("#site-footer");if(x.length){let e=function(n){return String(n??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},s=function(n){return e(n).replace(/'/g,"&#39;")},p=function(n){if(n&&n.type==="separator")return'<li class="footer-sep"><hr></li>';if(n&&n.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(n.size)?n.size:"md"}" aria-hidden="true"></li>`;const l=s(n.url||"#"),d=e(n.text||""),w=Array.isArray(n.items)&&n.items.length?`<ul>${n.items.map(p).join("")}</ul>`:"",v=X(n),D=[v.hover&&` data-menu-item-hover="${s(v.hover)}"`,v.active&&` data-menu-item-active="${s(v.active)}"`].filter(Boolean).join(""),M=v.accent?` style="--dm-menu-highlight:${s(v.accent)}"`:"";return`<li><a href="${l}"${D}${M}>${d}</a>${w}</li>`},g=function(n,l){return(n||[]).forEach(d=>{d&&(d.type==="separator"||d.type==="spacer")||(l.push(d),Array.isArray(d.items)&&d.items.length&&g(d.items,l))}),l};const a=y.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 i='<div class="footer-inner container">';const o=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(o.copyright&&(i+=`<p>${e(o.copyright)}</p>`),o.primary.length&&(i+=`<nav class="footer-nav footer-nav--primary"><ul>${o.primary.map(p).join("")}</ul></nav>`),o.legal.length&&(i+=`<nav class="footer-nav footer-nav--legal"><ul>${o.legal.map(p).join("")}</ul></nav>`),y.footer){const n=Object.keys(t).filter(l=>a[l]);n.length&&(i+='<div class="footer-social">',n.forEach(l=>{const{label:d,svg:w}=t[l];i+=`<a href="${a[l]}" target="_blank" rel="noopener noreferrer" aria-label="${d}" class="footer-social-link">${w}</a>`}),i+="</div>")}i+="</div>",x.html(i);const u=[...g(o.primary,[]),...g(o.legal,[])];x.get(0).querySelectorAll(".footer-nav a").forEach((n,l)=>{const d=u[l];if(!d)return;d.colour&&O(n,d.colour);const w=z(d.badge);w&&n.appendChild(w),B(d.url,location.pathname)&&(n.classList.add("is-active"),n.setAttribute("aria-current","page"))}),N(x.get(0).querySelector(".footer-nav--primary"),{highlight:o.primaryHighlight}),N(x.get(0).querySelector(".footer-nav--legal"),{highlight:o.legalHighlight});const b=y.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),h=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),r=x.get(0).querySelector(".footer-inner");if(b&&r){const n=document.createElement("input");n.type="checkbox",n.className="form-switch-input",n.id="dm-motion-switch",n.checked=h,n.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const l=document.createElement("span");l.className="form-switch-label",l.textContent="Reduce motion";const d=document.createElement("label");d.className="form-switch footer-motion-switch",d.title="Reduce motion",d.appendChild(n),d.appendChild(l),r.appendChild(d)}}$("#site-sidebar").length&&Domma.elements.sidebar("#site-sidebar",{autoGenerate:!0,selector:"h2, h3",collapsible:!1,push:!0,contentSelector:".site-content"}),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const f=$(".page-body");if(f.length){f.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),f.find(".tabs").each(function(){Domma.elements.tabs(this)}),f.find(".carousel").each(function(){const a={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)&&(a.animationDuration=t)}this.dataset.animationEasing&&(a.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=a),this._dmCarousel=Domma.elements.carousel(this,a)}),f.find(".dm-countdown").each(function(){const a={autoStart:!0},t=String(this.dataset.format||"").trim(),i=String(this.dataset.to||"").trim(),o=/^(\d{4})-(\d{2})-(\d{2})$/.exec(i),e=o?new Date(+o[1],+o[2]-1,+o[3]).getTime():i?new Date(i).getTime():NaN;Number.isFinite(e)?a.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(a.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const s=/^dd:/i.test(t);a.format=s?"hh:mm:ss":t||(a.duration>=36e5?"hh:mm:ss":"mm:ss");const p=this,g=m=>String(m).padStart(2,"0"),u=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=p.querySelector(".dm-timer-time");c&&(c.textContent=`${g(Math.floor(b/86400))}:${g(Math.floor(b%86400/3600))}:${g(Math.floor(b%3600/60))}:${g(b%60)}`)};s&&(a.onTick=u),Domma.elements.timer(this,a),s&&u(a.duration||0)}),f.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),f.find(".dm-progression").each(function(){const a=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",i=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...a.length?{items:a}:{}});a.length&&(this._dmCtx={instance:i,items:a})});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(a=>{const t=a.dataset.revealMode||"stagger",i=a.dataset.revealAnimation||"slide-up",o=parseInt(a.dataset.revealDuration,10)||400,e=parseInt(a.dataset.revealStagger,10)||60,s=parseInt(a.dataset.revealDelay,10)||0,p=a.dataset.revealDirection==="rtl",g=Array.from(a.children),u={"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)"};g.forEach((m,b)=>{m.style.opacity="0",m.style.transform=u[i]||"",m.style.transition=`opacity ${o}ms ease, transform ${o}ms ease`;const c=p?g.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${s+c*e}ms`:`${s}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});g.forEach(b=>m.observe(b))}))}),f.find(".card[data-collapsible]").each(function(){const a=this.querySelector(".card-header");a&&a.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),f.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const a=this.dataset.soTarget,t=document.getElementById(a);if(!t)return;const i=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",i.setContent(t),i.open()})})}if(typeof $.setup=="function"){const a=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const i=atob(t.dataset.config),o=JSON.parse(i);Object.assign(a,o)}catch{}}),Object.keys(a).length>0){const t={};for(const[i,o]of Object.entries(a)){const e=o?.events?.click,{confirm:s,toast:p,alert:g,prompt:u,...m}=e||{};s||p||g||u?($(i).on("click",async function(c){if(c.preventDefault(),s&&!await E.confirm(s))return;let h=null;if(!(u&&(h=await E.prompt(u,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),h===null))){if(m.target){const r=$(m.target);m.toggleClass&&r.toggleClass(m.toggleClass),m.addClass&&r.addClass(m.addClass),m.removeClass&&r.removeClass(m.removeClass),h!==null&&(m.setText&&r.text(h),m.setVal&&r.val(h),m.setAttr&&r.attr(m.setAttr,h))}m.href&&(window.location.href=m.href),p&&E.toast(p,{type:m.toastType||"success"}),g&&E.alert(g)}}),Object.keys(m).length&&(t[i]={...o,events:{...o.events,click:m}})):t[i]=o}$.setup(t)}}f.length&&I(f.get(0))}),window.wireCTAButtons=I;function I(C){C.querySelectorAll(".dm-cta-trigger").forEach(y=>{y.__ctaWired||(y.__ctaWired=!0,y.addEventListener("click",async()=>{const _=y.dataset.action,x=y.dataset.entry,A=y.dataset.confirm;let f=S.get("auth_token");if(!f){E.toast("Please log in to perform this action.",{type:"warning"});return}if(A&&!await E.confirm(A))return;const a=Array.from(y.childNodes).map(i=>i.cloneNode(!0));y.disabled=!0,y.textContent="Running\u2026";const t=i=>fetch(`/api/actions/${_}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`},body:JSON.stringify(y.dataset.scope?{entryId:x,scope:y.dataset.scope}:{entryId:x})});try{let i=await t(f);if(i.status===401){const e=S.get("auth_refresh_token");if(e){const s=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(s.ok){const{token:p}=await s.json();S.set("auth_token",p),f=p,i=await t(f)}}}const o=await i.json().catch(()=>({}));if(!i.ok)throw new Error(o.error||o.message||`Error ${i.status}`);E.toast(o.message||"Action completed.",{type:"success"})}catch(i){E.toast(i.message||"Action failed.",{type:"error"})}finally{y.disabled=!1,y.textContent="",a.forEach(i=>y.appendChild(i)),Domma.icons.scan(y)}}))})}(function(){const y=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!y.length)return;const _=S.get("auth_token");function x(f,a){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const i=document.createElement("p");if(a){i.appendChild(document.createTextNode("Please "));const o=document.createElement("a");o.href="/login",o.textContent="sign in",i.appendChild(o),i.appendChild(document.createTextNode(" to view your entries."))}else i.textContent=f;return t.appendChild(i),t}function A(f,a){const t=document.createElement("template");t.innerHTML=a||"",f.replaceWith(t.content)}y.forEach(async f=>{const a=f.dataset.collectionAttrs;if(!a)return;if(!_){f.replaceChildren(x("",!0));return}const t=i=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`},body:JSON.stringify({attrs:a})});try{let i=_,o=await t(i);if(o.status===401){const s=S.get("auth_refresh_token");if(s){const p=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:s})});if(p.ok){const{token:g}=await p.json();S.set("auth_token",g),i=g,o=await t(i)}}}if(!o.ok){const{error:s}=await o.json().catch(()=>({}));f.replaceChildren(x(s||"Unable to load entries.",!1));return}const{html:e}=await o.json();A(f,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{f.replaceChildren(x("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const y=document.querySelectorAll("[data-collection-table]");!y.length||typeof T>"u"||!T.create||y.forEach(_=>{let x;try{x=JSON.parse(atob(_.dataset.payload))}catch{return}const{columns:A,rows:f,search:a,sortable:t,exportable:i,pageSize:o,empty:e,ctaConfig:s,slug:p,exportCfg:g}=x;if(!A?.length)return;if(s){const b=A.findIndex(c=>c.key==="_cta");b!==-1&&(A[b]={key:"_cta",title:"",render:(c,h)=>{const r=document.createElement("button");if(r.className=`btn btn-${s.style||"primary"} dm-cta-trigger`,r.dataset.action=s.action||"",s.scope&&(r.dataset.scope=s.scope),r.dataset.entry=h._entryId||"",s.confirm&&(r.dataset.confirm=s.confirm),s.icon){const n=document.createElement("span");n.dataset.icon=s.icon,r.appendChild(n),r.appendChild(document.createTextNode(" "))}return r.appendChild(document.createTextNode(s.label||"Run")),r}})}const u="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=u,_.replaceChildren(m),T.create("#"+u,{data:f,columns:A,search:a,sortable:t,exportable:i,pageSize:o,emptyMessage:e}),s&&I(m),_._dmTable={columns:A,rows:f,slug:p,exportCfg:g,render(b){T.create("#"+u,{data:b,columns:A,search:a,sortable:t,exportable:i,pageSize:o,emptyMessage:e}),s&&I(m)}}})})(),(function(){const y=document.querySelectorAll("[data-form-inline]");if(!y.length||typeof F>"u")return;function _(t){const i=t&&t.logic;return!!(i&&(i.visibility||i.requirement))}function x(t,i){const o={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const s=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),p=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":s?"chooser":e.type,g={...e.formConfig||{}};g.span==="full"&&i&&(g.span=i);const u={type:p,required:_(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},...g}};e.minLength!==void 0&&(u.minLength=e.minLength),e.maxLength!==void 0&&(u.maxLength=e.maxLength),e.min!==void 0&&(u.min=e.min),e.max!==void 0&&(u.max=e.max),s&&(e.variant&&(u.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(u.multiple=!0),e.density&&(u.density=e.density),e.columns&&(u.columns=e.columns),e.accent&&(u.accent=e.accent),e.accentStyle&&(u.accentStyle=e.accentStyle),e.glow&&(u.glow=!0),e.glowColour&&(u.glowColour=e.glowColour),e.shadow&&(u.shadow=e.shadow),e.shadowColour&&(u.shadowColour=e.shadowColour)),o[e.name]=u}),o}function A(t){const i={};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&&(i[o.name]=typeof e=="object"?e.value:e)}}),i}function f(t,i){(i||[]).forEach(o=>{if(o.type!=="date"||!o.name)return;const e=t.querySelector(`[name="${o.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function a(t,i,o){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=i,e.style.cssText=o?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}y.forEach(t=>{let i;try{i=JSON.parse(atob(t.dataset.formInline))}catch{return}const o=i.fields||[],e=i.settings||{},s=Number(e.columns)===3?3:2,p=e.layout||"grid",g=o.some(r=>r.type==="page-break"),u=async r=>{if(t.dataset.triggerBlocked==="true"){const n=t._formLogicRuntime,l=n&&n.submitBlock?n.submitBlock().reasons:[];a(t,l.join(" ")||"This form cannot be submitted yet.",!0);const d=new Error("Blocked by a form trigger");throw d.formSubmitFailed=!0,d}try{const n=t.querySelector(".fb-form-honeypot"),l=n?.querySelector('input[type="text"]')||null,d=n?.querySelector('[name="_t"]')||null,w=Object.assign({},r);delete w._t,n?.dataset.hpName&&delete w[n.dataset.hpName],l!==null&&(w._hp=l.value),d!==null&&(w._t=d.value);const v=await H.post(`/api/forms/submit/${i.slug}`,w);if(v&&v.error){a(t,v.error,!0);const D=new Error(v.error);throw D.formSubmitFailed=!0,D}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);a(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(n){throw n.formSubmitFailed||a(t,n.message||"Submission failed. Please try again.",!0),n}},m=Date.now();function b(r){const n=r.querySelector("form");if(!n||n.querySelector(".fb-form-honeypot"))return;const l=document.createElement("div");l.className="fb-form-honeypot",l.setAttribute("aria-hidden","true");const d=document.createElement("input");d.name=n.querySelector('[name="website"]')?"_website":"website",l.dataset.hpName=d.name,d.type="text",d.tabIndex=-1,d.autocomplete="url",d.placeholder="https://",l.appendChild(d);const w=document.createElement("input");w.name="_t",w.type="hidden",w.value=m,l.appendChild(w),n.appendChild(l)}function c(r){if(!window.FormLogicEngine||!o.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const n=new window.FormLogicEngine.FormLogicRuntime(i,t,r?{baseValues:r}:void 0);if(n.init(),t._formLogicRuntime=n,t._formLogicObserved)return n;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(d){for(const w of d)for(const v of w.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=l}return n}let h=!1;if(t.addEventListener("dm-form-end",r=>{const n=r.detail?.validation;if(n&&!n.valid){R(t,n.missing),P(n);return}h||(h=!0,u(r.detail?.values||{}).catch(()=>{}).finally(()=>{h=!1}))}),g&&F.wizard){const r=U(o,i.title),n=r.map(k=>({title:k.title,description:k.description,fields:x(k.fields,s)})),l=r.map(k=>k.fields);let d=0,w=null,v=null;const D=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const q=L.validateFields(t,l[d]||[]);q.valid||(k.preventDefault(),k.stopImmediatePropagation(),R(t,q.missing),P(q))},M=()=>{const k=l[d]||o;Q(t,e),f(t,k),j(t,k),e.honeypot!==!1&&b(t),w&&w.destroy(),w=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",D,!0))};v=F.wizard(t,{schema:{steps:n},layout:p,columns:s,finishText:e.submitText||"Finish",onSubmit:u,onStepChange:k=>{d=k,setTimeout(M,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=n.length||L!==d&&v.goToStep(L)}),Promise.resolve(v).then(M)}else if(F.render){const r=F.render(t,x(o,s),A(o),{submitText:e.submitText||"Submit",layout:p,columns:s,onSubmit:u});Promise.resolve(r).then(function(){K(t,e,p),f(t,o),j(t,o),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
1
+ import{makeBadgeEl as O,applyColour as B,applyPill as W,applyFloat as X,applyHighlight as z,applyItemHighlight as G,itemHighlightAttrs as Y,isCurrentItem as j,menuAlign as U,applyClasses as M,cssClasses as K}from"/public/js/menu-decor.mjs?v=20261009-menu-classes";import{initFloatingMenus as Q}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as R,markInvalidFields as P,showValidationPopup as V}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as Z}from"/public/js/form-steps.mjs";import{applyFormClasses as J,applySubmitButtons as ee,applyWizardButtons as te}from"/public/js/form-submit.mjs";$(()=>{const x=window.__CMS_NAV__||{},y=window.__CMS_SITE__||{};if(y.autoTheme?.enabled){let t=function(e){const i=(e||"07:00").split(":");return+i[0]*60+(+i[1]||0)},s=function(){const e=new Date,i=e.getHours()*60+e.getMinutes();return i>=t(n.dayStart)&&i<t(n.nightStart)?n.dayTheme:n.nightTheme},a=function(e){const i=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(i.theme);for(const p of[...document.body.classList])p.startsWith("dm-custom-")&&document.body.classList.remove(p);i.custom&&document.body.classList.add(i.custom)};const n=y.autoTheme;a(s()),setInterval(()=>a(s()),6e4)}const _=$("#site-navbar");if(_.length&&x.brand){let s=function(c,h=0){return Array.isArray(c)?c.filter(r=>!(r&&r.type==="spacer")).filter(r=>!(r&&r.type==="separator"&&h===0)).map(r=>r&&r.type==="separator"?{divider:!0}:Array.isArray(r?.items)?{...r,items:s(r.items,h+1)}:r):c},a=function(c){return Array.isArray(c)?c.filter(h=>!(h&&(h.type==="separator"||h.type==="spacer"))):[]};const n={...x.brand},t=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let c="";n.logo?c+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(c+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(c+=`<span class="navbar-brand-text${t}">${n.text}</span>`),n.tagline&&(c+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=c}else t&&n.text&&(n.html=`<span class="navbar-brand-text${t}">${n.text}</span>`);const e=x.position==="floating",i=x.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:n,items:s(x.items||[]),variant:x.variant||"dark",position:e?"static":x.position||"sticky",collapsible:!0,appearOnHover:!!x.appearOnHover}),Domma.icons.scan("#site-navbar");const p=_.get(0);p.classList.add(`dm-nav-align-${U(x)||"centre"}`),i&&_.get(0).classList.add("dm-nav-vertical",x.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),z(p,x),M(p,x.class),e&&(X(_.get(0),x),Q(_.get(0).parentNode||document));const g=p.querySelector(".navbar-toggle"),u=p.querySelector(".navbar-collapse");if(g&&u){let c=null;const h=()=>{u.classList.contains("show")&&g.click()},r=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},o=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",h),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};g.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?o():r()})}),u.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(r)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&u.classList.contains("show")&&h()})}const m=p.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let h=0;for(const r of x.items||[])if(!(r&&r.type==="separator")){if(r&&r.type==="spacer"){const o=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md";o.className=`dm-menu-spacer dm-menu-spacer--${l}`,o.setAttribute("aria-hidden","true"),m.insertBefore(o,c[h]||null);continue}h++}}const b=a(x.items||[]);p.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const h=b[parseInt(c.dataset.index,10)];if(!h)return;const r=c.dataset.subindex!=null,o=r&&Array.isArray(h.items)?h.items[parseInt(c.dataset.subindex,10)]:h;if(!o)return;o.colour&&B(c,o.colour),o.pill&&!r&&W(c,o.pill),G(c,o),M(c.closest("li"),o.class);const l=O(o.badge);l&&c.appendChild(l),j(o.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const C=$("#site-footer");if(C.length){let e=function(o){return String(o??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")},i=function(o){return e(o).replace(/'/g,"&#39;")},p=function(o){if(o&&o.type==="separator")return'<li class="footer-sep"><hr></li>';if(o&&o.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(o.size)?o.size:"md"}" aria-hidden="true"></li>`;const l=i(o.url||"#"),d=e(o.text||""),w=Array.isArray(o.items)&&o.items.length?`<ul>${o.items.map(p).join("")}</ul>`:"",v=Y(o),D=[v.hover&&` data-menu-item-hover="${i(v.hover)}"`,v.active&&` data-menu-item-active="${i(v.active)}"`].filter(Boolean).join(""),q=v.accent?` style="--dm-menu-highlight:${i(v.accent)}"`:"",k=K(o.class).join(" ");return`<li${k?` class="${i(k)}"`:""}><a href="${l}"${D}${q}>${d}</a>${w}</li>`},g=function(o,l){return(o||[]).forEach(d=>{d&&(d.type==="separator"||d.type==="spacer")||(l.push(d),Array.isArray(d.items)&&d.items.length&&g(d.items,l))}),l};const n=y.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 a=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(a.copyright&&(s+=`<p>${e(a.copyright)}</p>`),a.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${a.primary.map(p).join("")}</ul></nav>`),a.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${a.legal.map(p).join("")}</ul></nav>`),y.footer){const o=Object.keys(t).filter(l=>n[l]);o.length&&(s+='<div class="footer-social">',o.forEach(l=>{const{label:d,svg:w}=t[l];s+=`<a href="${n[l]}" target="_blank" rel="noopener noreferrer" aria-label="${d}" class="footer-social-link">${w}</a>`}),s+="</div>")}s+="</div>",C.html(s);const u=[...g(a.primary,[]),...g(a.legal,[])];C.get(0).querySelectorAll(".footer-nav a").forEach((o,l)=>{const d=u[l];if(!d)return;d.colour&&B(o,d.colour);const w=O(d.badge);w&&o.appendChild(w),j(d.url,location.pathname)&&(o.classList.add("is-active"),o.setAttribute("aria-current","page"))}),z(C.get(0).querySelector(".footer-nav--primary"),{highlight:a.primaryHighlight}),z(C.get(0).querySelector(".footer-nav--legal"),{highlight:a.legalHighlight}),M(C.get(0).querySelector(".footer-nav--primary"),a.primaryClass),M(C.get(0).querySelector(".footer-nav--legal"),a.legalClass);const b=y.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),h=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),r=C.get(0).querySelector(".footer-inner");if(b&&r){const o=document.createElement("input");o.type="checkbox",o.className="form-switch-input",o.id="dm-motion-switch",o.checked=h,o.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const l=document.createElement("span");l.className="form-switch-label",l.textContent="Reduce motion";const d=document.createElement("label");d.className="form-switch footer-motion-switch",d.title="Reduce motion",d.appendChild(o),d.appendChild(l),r.appendChild(d)}}$("#site-sidebar").length&&Domma.elements.sidebar("#site-sidebar",{autoGenerate:!0,selector:"h2, h3",collapsible:!1,push:!0,contentSelector:".site-content"}),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const f=$(".page-body");if(f.length){f.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),f.find(".tabs").each(function(){Domma.elements.tabs(this)}),f.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)}),f.find(".dm-countdown").each(function(){const n={autoStart:!0},t=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),a=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=a?new Date(+a[1],+a[2]-1,+a[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 i=/^dd:/i.test(t);n.format=i?"hh:mm:ss":t||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const p=this,g=m=>String(m).padStart(2,"0"),u=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=p.querySelector(".dm-timer-time");c&&(c.textContent=`${g(Math.floor(b/86400))}:${g(Math.floor(b%86400/3600))}:${g(Math.floor(b%3600/60))}:${g(b%60)}`)};i&&(n.onTick=u),Domma.elements.timer(this,n),i&&u(n.duration||0)}),f.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),f.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(a=>{const e={title:a.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:a.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return a.dataset.date&&(e.date=a.dataset.date),a.dataset.status&&(e.status=a.dataset.status),a.dataset.entryId&&(e._entryId=a.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",a=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,i=parseInt(n.dataset.revealDelay,10)||0,p=n.dataset.revealDirection==="rtl",g=Array.from(n.children),u={"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)"};g.forEach((m,b)=>{m.style.opacity="0",m.style.transform=u[s]||"",m.style.transition=`opacity ${a}ms ease, transform ${a}ms ease`;const c=p?g.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${i+c*e}ms`:`${i}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});g.forEach(b=>m.observe(b))}))}),f.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),f.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=atob(t.dataset.config),a=JSON.parse(s);Object.assign(n,a)}catch{}}),Object.keys(n).length>0){const t={};for(const[s,a]of Object.entries(n)){const e=a?.events?.click,{confirm:i,toast:p,alert:g,prompt:u,...m}=e||{};i||p||g||u?($(s).on("click",async function(c){if(c.preventDefault(),i&&!await E.confirm(i))return;let h=null;if(!(u&&(h=await E.prompt(u,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),h===null))){if(m.target){const r=$(m.target);m.toggleClass&&r.toggleClass(m.toggleClass),m.addClass&&r.addClass(m.addClass),m.removeClass&&r.removeClass(m.removeClass),h!==null&&(m.setText&&r.text(h),m.setVal&&r.val(h),m.setAttr&&r.attr(m.setAttr,h))}m.href&&(window.location.href=m.href),p&&E.toast(p,{type:m.toastType||"success"}),g&&E.alert(g)}}),Object.keys(m).length&&(t[s]={...a,events:{...a.events,click:m}})):t[s]=a}$.setup(t)}}f.length&&I(f.get(0))}),window.wireCTAButtons=I;function I(x){x.querySelectorAll(".dm-cta-trigger").forEach(y=>{y.__ctaWired||(y.__ctaWired=!0,y.addEventListener("click",async()=>{const _=y.dataset.action,C=y.dataset.entry,A=y.dataset.confirm;let f=S.get("auth_token");if(!f){E.toast("Please log in to perform this action.",{type:"warning"});return}if(A&&!await E.confirm(A))return;const n=Array.from(y.childNodes).map(s=>s.cloneNode(!0));y.disabled=!0,y.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${_}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(y.dataset.scope?{entryId:C,scope:y.dataset.scope}:{entryId:C})});try{let s=await t(f);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(i.ok){const{token:p}=await i.json();S.set("auth_token",p),f=p,s=await t(f)}}}const a=await s.json().catch(()=>({}));if(!s.ok)throw new Error(a.error||a.message||`Error ${s.status}`);E.toast(a.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{y.disabled=!1,y.textContent="",n.forEach(s=>y.appendChild(s)),Domma.icons.scan(y)}}))})}(function(){const y=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!y.length)return;const _=S.get("auth_token");function C(f,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 a=document.createElement("a");a.href="/login",a.textContent="sign in",s.appendChild(a),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=f;return t.appendChild(s),t}function A(f,n){const t=document.createElement("template");t.innerHTML=n||"",f.replaceWith(t.content)}y.forEach(async f=>{const n=f.dataset.collectionAttrs;if(!n)return;if(!_){f.replaceChildren(C("",!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=_,a=await t(s);if(a.status===401){const i=S.get("auth_refresh_token");if(i){const p=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:i})});if(p.ok){const{token:g}=await p.json();S.set("auth_token",g),s=g,a=await t(s)}}}if(!a.ok){const{error:i}=await a.json().catch(()=>({}));f.replaceChildren(C(i||"Unable to load entries.",!1));return}const{html:e}=await a.json();A(f,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{f.replaceChildren(C("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const y=document.querySelectorAll("[data-collection-table]");!y.length||typeof T>"u"||!T.create||y.forEach(_=>{let C;try{C=JSON.parse(atob(_.dataset.payload))}catch{return}const{columns:A,rows:f,search:n,sortable:t,exportable:s,pageSize:a,empty:e,ctaConfig:i,slug:p,exportCfg:g}=C;if(!A?.length)return;if(i){const b=A.findIndex(c=>c.key==="_cta");b!==-1&&(A[b]={key:"_cta",title:"",render:(c,h)=>{const r=document.createElement("button");if(r.className=`btn btn-${i.style||"primary"} dm-cta-trigger`,r.dataset.action=i.action||"",i.scope&&(r.dataset.scope=i.scope),r.dataset.entry=h._entryId||"",i.confirm&&(r.dataset.confirm=i.confirm),i.icon){const o=document.createElement("span");o.dataset.icon=i.icon,r.appendChild(o),r.appendChild(document.createTextNode(" "))}return r.appendChild(document.createTextNode(i.label||"Run")),r}})}const u="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=u,_.replaceChildren(m),T.create("#"+u,{data:f,columns:A,search:n,sortable:t,exportable:s,pageSize:a,emptyMessage:e}),i&&I(m),_._dmTable={columns:A,rows:f,slug:p,exportCfg:g,render(b){T.create("#"+u,{data:b,columns:A,search:n,sortable:t,exportable:s,pageSize:a,emptyMessage:e}),i&&I(m)}}})})(),(function(){const y=document.querySelectorAll("[data-form-inline]");if(!y.length||typeof F>"u")return;function _(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function C(t,s){const a={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),p=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,g={...e.formConfig||{}};g.span==="full"&&s&&(g.span=s);const u={type:p,required:_(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},...g}};e.minLength!==void 0&&(u.minLength=e.minLength),e.maxLength!==void 0&&(u.maxLength=e.maxLength),e.min!==void 0&&(u.min=e.min),e.max!==void 0&&(u.max=e.max),i&&(e.variant&&(u.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(u.multiple=!0),e.density&&(u.density=e.density),e.columns&&(u.columns=e.columns),e.accent&&(u.accent=e.accent),e.accentStyle&&(u.accentStyle=e.accentStyle),e.glow&&(u.glow=!0),e.glowColour&&(u.glowColour=e.glowColour),e.shadow&&(u.shadow=e.shadow),e.shadowColour&&(u.shadowColour=e.shadowColour)),a[e.name]=u}),a}function A(t){const s={};return(t||[]).forEach(a=>{if(!(!a.name||a.type==="page-break"||a.type==="spacer")&&(a.type==="select"||a.type==="multiselect")&&a.required){const e=(a.options||[])[0];e&&(s[a.name]=typeof e=="object"?e.value:e)}}),s}function f(t,s){(s||[]).forEach(a=>{if(a.type!=="date"||!a.name)return;const e=t.querySelector(`[name="${a.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(t,s,a){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=a?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}y.forEach(t=>{let s;try{s=JSON.parse(atob(t.dataset.formInline))}catch{return}const a=s.fields||[],e=s.settings||{},i=Number(e.columns)===3?3:2,p=e.layout||"grid",g=a.some(r=>r.type==="page-break"),u=async r=>{if(t.dataset.triggerBlocked==="true"){const o=t._formLogicRuntime,l=o&&o.submitBlock?o.submitBlock().reasons:[];n(t,l.join(" ")||"This form cannot be submitted yet.",!0);const d=new Error("Blocked by a form trigger");throw d.formSubmitFailed=!0,d}try{const o=t.querySelector(".fb-form-honeypot"),l=o?.querySelector('input[type="text"]')||null,d=o?.querySelector('[name="_t"]')||null,w=Object.assign({},r);delete w._t,o?.dataset.hpName&&delete w[o.dataset.hpName],l!==null&&(w._hp=l.value),d!==null&&(w._t=d.value);const v=await H.post(`/api/forms/submit/${s.slug}`,w);if(v&&v.error){n(t,v.error,!0);const D=new Error(v.error);throw D.formSubmitFailed=!0,D}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);n(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(o){throw o.formSubmitFailed||n(t,o.message||"Submission failed. Please try again.",!0),o}},m=Date.now();function b(r){const o=r.querySelector("form");if(!o||o.querySelector(".fb-form-honeypot"))return;const l=document.createElement("div");l.className="fb-form-honeypot",l.setAttribute("aria-hidden","true");const d=document.createElement("input");d.name=o.querySelector('[name="website"]')?"_website":"website",l.dataset.hpName=d.name,d.type="text",d.tabIndex=-1,d.autocomplete="url",d.placeholder="https://",l.appendChild(d);const w=document.createElement("input");w.name="_t",w.type="hidden",w.value=m,l.appendChild(w),o.appendChild(l)}function c(r){if(!window.FormLogicEngine||!a.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const o=new window.FormLogicEngine.FormLogicRuntime(s,t,r?{baseValues:r}:void 0);if(o.init(),t._formLogicRuntime=o,t._formLogicObserved)return o;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(d){for(const w of d)for(const v of w.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=l}return o}let h=!1;if(t.addEventListener("dm-form-end",r=>{const o=r.detail?.validation;if(o&&!o.valid){P(t,o.missing),V(o);return}h||(h=!0,u(r.detail?.values||{}).catch(()=>{}).finally(()=>{h=!1}))}),g&&F.wizard){const r=Z(a,s.title),o=r.map(k=>({title:k.title,description:k.description,fields:C(k.fields,i)})),l=r.map(k=>k.fields);let d=0,w=null,v=null;const D=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const N=L.validateFields(t,l[d]||[]);N.valid||(k.preventDefault(),k.stopImmediatePropagation(),P(t,N.missing),V(N))},q=()=>{const k=l[d]||a;te(t,e),J(t,e,k),f(t,k),R(t,k),e.honeypot!==!1&&b(t),w&&w.destroy(),w=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",D,!0))};v=F.wizard(t,{schema:{steps:o},layout:p,columns:i,finishText:e.submitText||"Finish",onSubmit:u,onStepChange:k=>{d=k,setTimeout(q,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=o.length||L!==d&&v.goToStep(L)}),Promise.resolve(v).then(q)}else if(F.render){const r=F.render(t,C(a,i),A(a),{submitText:e.submitText||"Submit",layout:p,columns:i,onSubmit:u});Promise.resolve(r).then(function(){ee(t,e,p),J(t,e,a),f(t,a),R(t,a),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();