domma-cms 0.114.0 → 0.114.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{makeBadgeEl as M,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 w=window.__CMS_NAV__||{},g=window.__CMS_SITE__||{};if(g.autoTheme?.enabled){let t=function(e){const s=(e||"07:00").split(":");return+s[0]*60+(+s[1]||0)},n=function(){const e=new Date,s=e.getHours()*60+e.getMinutes();return s>=t(o.dayStart)&&s<t(o.nightStart)?o.dayTheme:o.nightTheme},i=function(e){const s=o.apply&&o.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 o=g.autoTheme;i(n()),setInterval(()=>i(n()),6e4)}const _=$("#site-navbar");if(_.length&&w.brand){let n=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:n(r.items,h+1)}:r):c},i=function(c){return Array.isArray(c)?c.filter(h=>!(h&&(h.type==="separator"||h.type==="spacer"))):[]};const o={...w.brand},t=o.size&&o.size!=="md"?` navbar-brand-${o.size}`:"";if(o.logo||o.icon||o.tagline){let c="";o.logo?c+=`<img src="${o.logo}" class="navbar-brand-logo" alt="${o.text||""}">`:o.icon&&(c+=`<span data-icon="${o.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),o.text&&(c+=`<span class="navbar-brand-text${t}">${o.text}</span>`),o.tagline&&(c+=`<small class="navbar-brand-tagline">${o.tagline}</small>`),o.html=c}else t&&o.text&&(o.html=`<span class="navbar-brand-text${t}">${o.text}</span>`);const e=w.position==="floating",s=w.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:o,items:n(w.items||[]),variant:w.variant||"dark",position:e?"static":w.position||"sticky",collapsible:!0,appearOnHover:!!w.appearOnHover}),Domma.icons.scan("#site-navbar");const p=_.get(0);p.classList.add(`dm-nav-align-${G(w)||"centre"}`),s&&_.get(0).classList.add("dm-nav-vertical",w.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),N(p,w),e&&(J(_.get(0),w),Y(_.get(0).parentNode||document));const y=p.querySelector(".navbar-toggle"),u=p.querySelector(".navbar-collapse");if(y&&u){let c=null;const h=()=>{u.classList.contains("show")&&y.click()},r=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},a=()=>{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"))};y.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?a():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 w.items||[])if(!(r&&r.type==="separator")){if(r&&r.type==="spacer"){const a=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md";a.className=`dm-menu-spacer dm-menu-spacer--${l}`,a.setAttribute("aria-hidden","true"),m.insertBefore(a,c[h]||null);continue}h++}}const x=i(w.items||[]);p.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const h=x[parseInt(c.dataset.index,10)];if(!h)return;const r=c.dataset.subindex!=null,a=r&&Array.isArray(h.items)?h.items[parseInt(c.dataset.subindex,10)]:h;if(!a)return;a.colour&&O(c,a.colour),a.pill&&!r&&V(c,a.pill),W(c,a);const l=M(a.badge);l&&c.appendChild(l),B(a.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const C=$("#site-footer");if(C.length){let e=function(a){return String(a??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},s=function(a){return e(a).replace(/'/g,"'")},p=function(a){if(a&&a.type==="separator")return'<li class="footer-sep"><hr></li>';if(a&&a.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(a.size)?a.size:"md"}" aria-hidden="true"></li>`;const l=s(a.url||"#"),d=e(a.text||""),b=Array.isArray(a.items)&&a.items.length?`<ul>${a.items.map(p).join("")}</ul>`:"",v=X(a),I=[v.hover&&` data-menu-item-hover="${s(v.hover)}"`,v.active&&` data-menu-item-active="${s(v.active)}"`].filter(Boolean).join(""),q=v.accent?` style="--dm-menu-highlight:${s(v.accent)}"`:"";return`<li><a href="${l}"${I}${q}>${d}</a>${b}</li>`},y=function(a,l){return(a||[]).forEach(d=>{d&&(d.type==="separator"||d.type==="spacer")||(l.push(d),Array.isArray(d.items)&&d.items.length&&y(d.items,l))}),l};const o=g.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 n='<div class="footer-inner container">';const i=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(i.copyright&&(n+=`<p>${e(i.copyright)}</p>`),i.primary.length&&(n+=`<nav class="footer-nav footer-nav--primary"><ul>${i.primary.map(p).join("")}</ul></nav>`),i.legal.length&&(n+=`<nav class="footer-nav footer-nav--legal"><ul>${i.legal.map(p).join("")}</ul></nav>`),g.footer){const a=Object.keys(t).filter(l=>o[l]);a.length&&(n+='<div class="footer-social">',a.forEach(l=>{const{label:d,svg:b}=t[l];n+=`<a href="${o[l]}" target="_blank" rel="noopener noreferrer" aria-label="${d}" class="footer-social-link">${b}</a>`}),n+="</div>")}n+="</div>",C.html(n);const u=[...y(i.primary,[]),...y(i.legal,[])];C.get(0).querySelectorAll(".footer-nav a").forEach((a,l)=>{const d=u[l];if(!d)return;d.colour&&O(a,d.colour);const b=M(d.badge);b&&a.appendChild(b),B(d.url,location.pathname)&&(a.classList.add("is-active"),a.setAttribute("aria-current","page"))}),N(C.get(0).querySelector(".footer-nav--primary"),{highlight:i.primaryHighlight}),N(C.get(0).querySelector(".footer-nav--legal"),{highlight:i.legalHighlight});const x=g.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(x&&r){const a=document.createElement("input");a.type="checkbox",a.className="form-switch-input",a.id="dm-motion-switch",a.checked=h,a.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(a),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 o={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)&&(o.animationDuration=t)}this.dataset.animationEasing&&(o.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=o),this._dmCarousel=Domma.elements.carousel(this,o)}),f.find(".dm-countdown").each(function(){const o={autoStart:!0};this.dataset.to&&(o.targetDate=new Date(this.dataset.to)),this.dataset.duration&&(o.duration=parseInt(this.dataset.duration,10)),this.dataset.format&&(o.format=this.dataset.format),Domma.elements.timer(this,o)}),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 o=Array.from(this.querySelectorAll(".dm-progression-item")).map(i=>{const e={title:i.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:i.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return i.dataset.date&&(e.date=i.dataset.date),i.dataset.status&&(e.status=i.dataset.status),i.dataset.entryId&&(e._entryId=i.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",n=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...o.length?{items:o}:{}});o.length&&(this._dmCtx={instance:n,items:o})});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(o=>{const t=o.dataset.revealMode||"stagger",n=o.dataset.revealAnimation||"slide-up",i=parseInt(o.dataset.revealDuration,10)||400,e=parseInt(o.dataset.revealStagger,10)||60,s=parseInt(o.dataset.revealDelay,10)||0,p=o.dataset.revealDirection==="rtl",y=Array.from(o.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)"};y.forEach((m,x)=>{m.style.opacity="0",m.style.transform=u[n]||"",m.style.transition=`opacity ${i}ms ease, transform ${i}ms ease`;const c=p?y.length-1-x:x;m.style.transitionDelay=t==="stagger"?`${s+c*e}ms`:`${s}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(x=>{x.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});y.forEach(x=>m.observe(x))}))}),f.find(".card[data-collapsible]").each(function(){const o=this.querySelector(".card-header");o&&o.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),f.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const o=this.dataset.soTarget,t=document.getElementById(o);if(!t)return;const n=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",n.setContent(t),n.open()})})}if(typeof $.setup=="function"){const o=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const n=atob(t.dataset.config),i=JSON.parse(n);Object.assign(o,i)}catch{}}),Object.keys(o).length>0){const t={};for(const[n,i]of Object.entries(o)){const e=i?.events?.click,{confirm:s,toast:p,alert:y,prompt:u,...m}=e||{};s||p||y||u?($(n).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"}),y&&E.alert(y)}}),Object.keys(m).length&&(t[n]={...i,events:{...i.events,click:m}})):t[n]=i}$.setup(t)}}f.length&&D(f.get(0))}),window.wireCTAButtons=D;function D(w){w.querySelectorAll(".dm-cta-trigger").forEach(g=>{g.__ctaWired||(g.__ctaWired=!0,g.addEventListener("click",async()=>{const _=g.dataset.action,C=g.dataset.entry,A=g.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 o=Array.from(g.childNodes).map(n=>n.cloneNode(!0));g.disabled=!0,g.textContent="Running\u2026";const t=n=>fetch(`/api/actions/${_}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify(g.dataset.scope?{entryId:C,scope:g.dataset.scope}:{entryId:C})});try{let n=await t(f);if(n.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,n=await t(f)}}}const i=await n.json().catch(()=>({}));if(!n.ok)throw new Error(i.error||i.message||`Error ${n.status}`);E.toast(i.message||"Action completed.",{type:"success"})}catch(n){E.toast(n.message||"Action failed.",{type:"error"})}finally{g.disabled=!1,g.textContent="",o.forEach(n=>g.appendChild(n)),Domma.icons.scan(g)}}))})}(function(){const g=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!g.length)return;const _=S.get("auth_token");function C(f,o){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const n=document.createElement("p");if(o){n.appendChild(document.createTextNode("Please "));const i=document.createElement("a");i.href="/login",i.textContent="sign in",n.appendChild(i),n.appendChild(document.createTextNode(" to view your entries."))}else n.textContent=f;return t.appendChild(n),t}function A(f,o){const t=document.createElement("template");t.innerHTML=o||"",f.replaceWith(t.content)}g.forEach(async f=>{const o=f.dataset.collectionAttrs;if(!o)return;if(!_){f.replaceChildren(C("",!0));return}const t=n=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({attrs:o})});try{let n=_,i=await t(n);if(i.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:y}=await p.json();S.set("auth_token",y),n=y,i=await t(n)}}}if(!i.ok){const{error:s}=await i.json().catch(()=>({}));f.replaceChildren(C(s||"Unable to load entries.",!1));return}const{html:e}=await i.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(),D(document.body)},100)})(),(function(){const g=document.querySelectorAll("[data-collection-table]");!g.length||typeof T>"u"||!T.create||g.forEach(_=>{let C;try{C=JSON.parse(atob(_.dataset.payload))}catch{return}const{columns:A,rows:f,search:o,sortable:t,exportable:n,pageSize:i,empty:e,ctaConfig:s,slug:p,exportCfg:y}=C;if(!A?.length)return;if(s){const x=A.findIndex(c=>c.key==="_cta");x!==-1&&(A[x]={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 a=document.createElement("span");a.dataset.icon=s.icon,r.appendChild(a),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:o,sortable:t,exportable:n,pageSize:i,emptyMessage:e}),s&&D(m),_._dmTable={columns:A,rows:f,slug:p,exportCfg:y,render(x){T.create("#"+u,{data:x,columns:A,search:o,sortable:t,exportable:n,pageSize:i,emptyMessage:e}),s&&D(m)}}})})(),(function(){const g=document.querySelectorAll("[data-form-inline]");if(!g.length||typeof F>"u")return;function _(t){const n=t&&t.logic;return!!(n&&(n.visibility||n.requirement))}function C(t,n){const i={};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,y={...e.formConfig||{}};y.span==="full"&&n&&(y.span=n);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},...y}};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)),i[e.name]=u}),i}function A(t){const n={};return(t||[]).forEach(i=>{if(!(!i.name||i.type==="page-break"||i.type==="spacer")&&(i.type==="select"||i.type==="multiselect")&&i.required){const e=(i.options||[])[0];e&&(n[i.name]=typeof e=="object"?e.value:e)}}),n}function f(t,n){(n||[]).forEach(i=>{if(i.type!=="date"||!i.name)return;const e=t.querySelector(`[name="${i.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function o(t,n,i){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=n,e.style.cssText=i?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}g.forEach(t=>{let n;try{n=JSON.parse(atob(t.dataset.formInline))}catch{return}const i=n.fields||[],e=n.settings||{},s=Number(e.columns)===3?3:2,p=e.layout||"grid",y=i.some(r=>r.type==="page-break"),u=async r=>{if(t.dataset.triggerBlocked==="true"){const a=t._formLogicRuntime,l=a&&a.submitBlock?a.submitBlock().reasons:[];o(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 a=t.querySelector(".fb-form-honeypot"),l=a?.querySelector('input[type="text"]')||null,d=a?.querySelector('[name="_t"]')||null,b=Object.assign({},r);delete b._t,a?.dataset.hpName&&delete b[a.dataset.hpName],l!==null&&(b._hp=l.value),d!==null&&(b._t=d.value);const v=await H.post(`/api/forms/submit/${n.slug}`,b);if(v&&v.error){o(t,v.error,!0);const I=new Error(v.error);throw I.formSubmitFailed=!0,I}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);o(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(a){throw a.formSubmitFailed||o(t,a.message||"Submission failed. Please try again.",!0),a}},m=Date.now();function x(r){const a=r.querySelector("form");if(!a||a.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=a.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 b=document.createElement("input");b.name="_t",b.type="hidden",b.value=m,l.appendChild(b),a.appendChild(l)}function c(r){if(!window.FormLogicEngine||!i.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const a=new window.FormLogicEngine.FormLogicRuntime(n,t,r?{baseValues:r}:void 0);if(a.init(),t._formLogicRuntime=a,t._formLogicObserved)return a;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(d){for(const b of d)for(const v of b.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 a}let h=!1;if(t.addEventListener("dm-form-end",r=>{const a=r.detail?.validation;if(a&&!a.valid){R(t,a.missing),P(a);return}h||(h=!0,u(r.detail?.values||{}).catch(()=>{}).finally(()=>{h=!1}))}),y&&F.wizard){const r=U(i,n.title),a=r.map(k=>({title:k.title,description:k.description,fields:C(k.fields,s)})),l=r.map(k=>k.fields);let d=0,b=null,v=null;const I=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const z=L.validateFields(t,l[d]||[]);z.valid||(k.preventDefault(),k.stopImmediatePropagation(),R(t,z.missing),P(z))},q=()=>{const k=l[d]||i;Q(t,e),f(t,k),j(t,k),e.honeypot!==!1&&x(t),b&&b.destroy(),b=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",I,!0))};v=F.wizard(t,{schema:{steps:a},layout:p,columns:s,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>=a.length||L!==d&&v.goToStep(L)}),Promise.resolve(v).then(q)}else if(F.render){const r=F.render(t,C(i,s),A(i),{submitText:e.submitText||"Submit",layout:p,columns:s,onSubmit:u});Promise.resolve(r).then(function(){K(t,e,p),f(t,i),j(t,i),e.honeypot!==!1&&x(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
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,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},s=function(n){return e(n).replace(/'/g,"'")},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()})})();
|
package/server/server.js
CHANGED
|
@@ -31,6 +31,7 @@ import {refreshComponentTagAllowlist} from './services/markdown.js';
|
|
|
31
31
|
import * as cache from './services/cache/index.js';
|
|
32
32
|
import {parseTrustProxy} from './services/network.js';
|
|
33
33
|
import {rateLimitOptions} from './services/rate-limit.js';
|
|
34
|
+
import {frameSources} from './services/embedCsp.js';
|
|
34
35
|
|
|
35
36
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
36
37
|
const ROOT = path.resolve(__dirname, '..');
|
|
@@ -122,6 +123,8 @@ await app.register(helmet, {
|
|
|
122
123
|
imgSrc: ["'self'", 'data:', 'blob:'],
|
|
123
124
|
fontSrc: ["'self'", 'data:', 'https://fonts.gstatic.com'],
|
|
124
125
|
connectSrc: ["'self'", 'https://cdn.jsdelivr.net'],
|
|
126
|
+
// [embed] players and config/embeds.json hosts - without this, default-src blocked them all.
|
|
127
|
+
frameSrc: frameSources((() => { try { return getConfig('embeds')?.allowedHosts; } catch { return []; } })()),
|
|
125
128
|
upgradeInsecureRequests: null, // prevent browsers forcing HTTPS on HTTP deployments
|
|
126
129
|
}
|
|
127
130
|
},
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frame-src the Content-Security-Policy needs for [embed].
|
|
3
|
+
*
|
|
4
|
+
* The CSP had no frame-src, so it fell back to default-src 'self' and the
|
|
5
|
+
* browser blocked every embedded player - YouTube and Vimeo included, which the
|
|
6
|
+
* [embed] shortcode documents as always allowed. The page rendered the iframe
|
|
7
|
+
* and the visitor saw a blocked frame.
|
|
8
|
+
*
|
|
9
|
+
* So: 'self' (the [demo] shortcode frames the site's own pages), the two players
|
|
10
|
+
* [embed] rewrites links to (youtube-nocookie.com, player.vimeo.com), and every
|
|
11
|
+
* host in config/embeds.json `allowedHosts` - the same list the renderer and the
|
|
12
|
+
* sanitiser already enforce (server.js passes getConfig('embeds'), as the
|
|
13
|
+
* renderer reads it). Read at boot: a change to embeds.json needs a restart to
|
|
14
|
+
* reach the header.
|
|
15
|
+
*/
|
|
16
|
+
/** The players [embed] always uses. */
|
|
17
|
+
// youtube.com too: the HTML sanitiser lets its iframes through, so the policy must agree.
|
|
18
|
+
export const ALWAYS_FRAMED = ['https://www.youtube-nocookie.com', 'https://www.youtube.com', 'https://youtube.com', 'https://player.vimeo.com'];
|
|
19
|
+
|
|
20
|
+
/** A bare hostname, or nothing: a host in embeds.json must never smuggle in a scheme, path or wildcard. */
|
|
21
|
+
const HOST_RE = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {string[]} allowedHosts - config/embeds.json allowedHosts
|
|
25
|
+
* @returns {string[]} frame-src sources
|
|
26
|
+
*/
|
|
27
|
+
export function frameSources(allowedHosts = []) {
|
|
28
|
+
const extra = (Array.isArray(allowedHosts) ? allowedHosts : [])
|
|
29
|
+
.map(h => String(h).trim().toLowerCase())
|
|
30
|
+
.filter(h => HOST_RE.test(h))
|
|
31
|
+
.map(h => `https://${h}`);
|
|
32
|
+
return [...new Set(["'self'", ...ALWAYS_FRAMED, ...extra])];
|
|
33
|
+
}
|
|
@@ -694,7 +694,7 @@ function renderCollectionAccordion(entries, titleField, bodyField, multiple, emp
|
|
|
694
694
|
* @param {string} opts.titleField - entry data field used as item title
|
|
695
695
|
* @param {string} [opts.dateField] - optional field surfaced as data-date
|
|
696
696
|
* @param {string} [opts.statusField]- optional field surfaced as data-status
|
|
697
|
-
* @param {string} [opts.iconField] - optional field surfaced as data-icon
|
|
697
|
+
* @param {string} [opts.iconField] - optional field surfaced as data-event-icon
|
|
698
698
|
* @param {string} [opts.bodyField] - optional Markdown body field
|
|
699
699
|
* @param {string} opts.layout - vertical | centred | horizontal
|
|
700
700
|
* @param {string} opts.theme - minimal | corporate | modern
|
|
@@ -712,7 +712,9 @@ function renderCollectionTimeline(entries, opts, ctxOpts = {}) {
|
|
|
712
712
|
const title = escapeHtmlText(String(e.data?.[titleField] ?? e.id ?? '(untitled)'));
|
|
713
713
|
const date = dateField && e.data?.[dateField] != null ? ` data-date="${escapeAttr(String(e.data[dateField]))}"` : '';
|
|
714
714
|
const status = statusField && e.data?.[statusField] != null ? ` data-status="${escapeAttr(String(e.data[statusField]))}"` : '';
|
|
715
|
-
|
|
715
|
+
// data-event-icon, never data-icon: the icon scanner turns ANY [data-icon] element into an
|
|
716
|
+
// icon, replacing its children - which wiped each item's title and body before site.js read them.
|
|
717
|
+
const icon = iconField && e.data?.[iconField] != null ? ` data-event-icon="${escapeAttr(String(e.data[iconField]))}"` : '';
|
|
716
718
|
const bodyHtml = bodyField
|
|
717
719
|
? marked.parse(String(e.data?.[bodyField] ?? ''))
|
|
718
720
|
: '';
|
|
@@ -3178,7 +3180,8 @@ function processTimelineBlocks(markdown) {
|
|
|
3178
3180
|
const title = escapeAttr(ia.title || '');
|
|
3179
3181
|
const date = ia.date ? ` data-date="${escapeAttr(ia.date)}"` : '';
|
|
3180
3182
|
const status = ia.status ? ` data-status="${escapeAttr(ia.status)}"` : '';
|
|
3181
|
-
|
|
3183
|
+
// data-event-icon, never data-icon - see renderCollectionTimeline: the icon scanner would empty the item.
|
|
3184
|
+
const icon = ia.icon ? ` data-event-icon="${escapeAttr(ia.icon)}"` : '';
|
|
3182
3185
|
const descHtml = marked.parse(processCardBlocks(processGridBlocks(processInlineShortcodes(restore(itemBody.trim())))));
|
|
3183
3186
|
return `<div class="dm-progression-item"${date}${status}${icon}><div class="dm-progression-item-title">${title}</div><div class="dm-progression-item-body">${descHtml}</div></div>`;
|
|
3184
3187
|
}
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
</script>
|
|
137
137
|
|
|
138
138
|
<!-- Site initialisation -->
|
|
139
|
-
<script src="/public/js/site.js?v=
|
|
139
|
+
<script src="/public/js/site.js?v=20261004-countdown" type="module"></script>
|
|
140
140
|
<script src="/public/js/collection-context.js?v=20260927-ctx" type="module"></script>
|
|
141
141
|
{{ctxMenusModule}}
|
|
142
142
|
|