domma-cms 0.80.0 → 0.81.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.
- package/CLAUDE.md +6 -1
- package/admin/index.html +2 -2
- package/admin/js/lib/action-editor-arrange.js +1 -1
- package/admin/js/templates/action-editor.html +1 -0
- package/admin/js/templates/docs/usage-actions.html +5 -0
- package/admin/js/templates/form-editor.html +72 -0
- package/admin/js/views/form-editor.js +7 -7
- package/package.json +1 -1
- package/public/css/forms.css +1 -1
- package/public/js/form-logic-engine.js +1 -1
- package/public/js/forms.js +2 -2
- package/public/js/site.js +1 -1
- package/server/routes/api/forms.js +36 -10
- package/server/services/actions.js +28 -0
- package/server/services/collections.js +10 -4
- package/server/services/notification-sources.js +40 -0
- package/server/templates/page.html +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(l,f){typeof module<"u"&&module.exports?module.exports=f():l.FormLogicEngine=f()})(typeof globalThis<"u"?globalThis:this,function(){"use strict";function l(e){return e===""||e===null||e===void 0?"":String(e)}function f(e){const n=parseFloat(e);return isNaN(n)?null:n}function d(e){return e==null?!0:typeof e=="string"?e.trim()==="":Array.isArray(e)?e.length===0:!1}const M={not_equals:"equals",not_contains:"contains",not_in:"in"};function v(e,n){const t=l(n),r=l(e.value);switch(e.operator){case"equals":return t===r;case"not_equals":return t!==r;case"contains":return t.toLowerCase().includes(r.toLowerCase());case"not_contains":return!t.toLowerCase().includes(r.toLowerCase());case"starts_with":return t.toLowerCase().startsWith(r.toLowerCase());case"ends_with":return t.toLowerCase().endsWith(r.toLowerCase());case"greater_than":{const i=f(n),s=f(e.value);return i!==null&&s!==null&&i>s}case"less_than":{const i=f(n),s=f(e.value);return i!==null&&s!==null&&i<s}case"is_empty":return d(n);case"is_not_empty":return!d(n);case"in":return(Array.isArray(e.value)?e.value.map(l):String(e.value).split(",").map(s=>s.trim())).includes(t);case"not_in":return!(Array.isArray(e.value)?e.value.map(l):String(e.value).split(",").map(s=>s.trim())).includes(t);case"matches_regex":try{const i=e.flags||"";return new RegExp(e.value,i).test(t)}catch(i){return typeof console<"u"&&console.warn&&console.warn('[FormLogicEngine] Invalid regex in condition for field "'+e.field+'": '+e.value,i&&i.message),!1}default:return!0}}function g(e,n){if(!e||!e.field||!e.operator)return!0;const t=n[e.field];if(!Array.isArray(t))return v(e,t);if(e.operator==="is_empty")return d(t);if(e.operator==="is_not_empty")return!d(t);const r=M[e.operator];if(r){const i=Object.assign({},e,{operator:r});return!t.some(s=>v(i,s))}return t.some(i=>v(e,i))}function p(e,n){return e?Array.isArray(e.all)?e.all.every(t=>t.all||t.any?p(t,n):g(t,n)):Array.isArray(e.any)?e.any.some(t=>t.all||t.any?p(t,n):g(t,n)):e.field&&e.operator?g(e,n):!0:!0}function w(e,n){const t=e.logic;if(!t||!t.visibility)return"visible";const r=t.visibility,i=r.conditions||[];for(const s of i)if(s.when&&p(s.when,n))return s.then==="hidden"?"hidden":"visible";return r.default==="hidden"?"hidden":"visible"}function y(e,n){const t=e.logic;if(!t||!t.requirement)return e.required||!1;const r=t.requirement,i=r.conditions||[];for(const s of i)if(s.when&&p(s.when,n))return s.then===!0;return r.default===!0}function q(e,n,t){const r=e.logic;if(!r||!Array.isArray(r.validation))return[];const i=[];for(const s of r.validation)switch(s.type){case"regex":{if(!d(n))try{new RegExp(s.pattern||"",s.flags||"").test(l(n))||i.push({message:s.message||"Invalid format."})}catch{}break}case"match":{const a=t[s.field];!d(n)&&l(n)!==l(a)&&i.push({message:s.message||"Fields do not match."});break}}return i}function x(e,n){const t=e.logic;if(!t||!t.cascade||!t.cascade.sourceField)return null;const r=t.cascade,i=r.mapping||{},s=n[r.sourceField];if(Array.isArray(s)){const c=new Set,u=[];return s.forEach(function(m){const _=l(m);Object.prototype.hasOwnProperty.call(i,_)&&(i[_]||[]).forEach(function(S){const I=l(S&&S.value);c.has(I)||(c.add(I),u.push(S))})}),u.length?u:r.defaultOptions||null}const a=l(s);return Object.prototype.hasOwnProperty.call(i,a)?i[a]||[]:r.defaultOptions||null}const R={fade:250,slide:300,scale:200};function k(e,n){const t=Number(n);return!isFinite(t)||t<0||t>5e3?R[e]||250:Math.round(t)}function O(e,n,t){const r=k(n,t);if(n==="fade")e.style.transition="opacity "+r+"ms ease",e.style.opacity="1",requestAnimationFrame(function(){e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.opacity=""},r+10)});else if(n==="slide"){const i=Math.round(r*.67);e.style.overflow="hidden",e.style.maxHeight=e.scrollHeight+"px",e.style.transition="max-height "+r+"ms ease, opacity "+i+"ms ease",requestAnimationFrame(function(){e.style.maxHeight="0",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},r+20)})}else n==="scale"&&(e.style.transition="opacity "+r+"ms ease, transform "+r+"ms ease",e.style.transform="scale(1)",e.style.opacity="1",requestAnimationFrame(function(){e.style.transform="scale(0.95)",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.transform="",e.style.opacity=""},r+20)}))}function V(e,n,t){const r=k(n,t);if(e.classList.remove("fb-field-hidden"),n==="fade")e.style.opacity="0",e.style.transition="opacity "+r+"ms ease",requestAnimationFrame(function(){e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.opacity=""},r+10)});else if(n==="slide"){const i=Math.round(r*.67);e.style.overflow="hidden",e.style.maxHeight="0",e.style.opacity="0",e.style.transition="max-height "+r+"ms ease, opacity "+i+"ms ease",requestAnimationFrame(function(){e.style.maxHeight=e.scrollHeight+"px",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},r+20)})}else n==="scale"&&(e.style.transform="scale(0.95)",e.style.opacity="0",e.style.transition="opacity "+r+"ms ease, transform "+r+"ms ease",requestAnimationFrame(function(){e.style.transform="scale(1)",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.transform="",e.style.opacity=""},r+20)}))}const C={banner:"state","disable-fields":"state","hide-fields":"state","require-fields":"state","block-submit":"state",toast:"event",celebrate:"event","goto-step":"event",redirect:"event","run-action":"event"},B=["block-submit","hide-fields","disable-fields","require-fields","redirect","run-action"];function T(e){return!!e&&!!e.name&&e.type!=="page-break"&&e.type!=="spacer"}function b(e,n,t){const r=(t||[]).filter(T),i=e.target||(e.fields&&e.fields.length?"listed":"rest");if(i==="listed"){const a=new Set(e.fields||[]);return r.filter(c=>a.has(c.name)&&c.name!==n.name).map(c=>c.name)}if(i==="all")return r.filter(a=>a.name!==n.name).map(a=>a.name);const s=r.findIndex(a=>a.name===n.name);return s===-1?[]:r.slice(s+1).map(a=>a.name)}function A(e,n){for(const t of n)e.includes(t)||e.push(t)}function H(e,n,t,r,i){if(!n||!n.type)return;const s=C[n.type];if(s){if(s==="event"){e.events.push({key:i,type:n.type,field:t.name,action:n});return}switch(n.type){case"banner":e.banners.push({key:i,field:t.name,message:n.message||"",level:n.level||"info",position:n.position||"field-below",dismissible:n.dismissible!==!1});break;case"hide-fields":A(e.hidden,b(n,t,r));break;case"disable-fields":A(e.disabled,b(n,t,r));break;case"require-fields":A(e.required,b(n,t,r));break;case"block-submit":e.blocks.push({key:i,message:n.message||"This form cannot be submitted yet."});break;default:break}}}function F(e,n){const t={active:[],banners:[],hidden:[],disabled:[],required:[],blocks:[],events:[]};return(e||[]).forEach(r=>{!T(r)||!Array.isArray(r.triggers)||r.triggers.forEach((i,s)=>{if(!i||i.enabled===!1)return;const a=i.id||`${r.name}::${s}`,c=p(i.when,n),u=`${a}:${c?"then":"else"}`,m=c?i.then:i.otherwise;!Array.isArray(m)||!m.length||(t.active.push(u),m.forEach(_=>H(t,_,r,e,u)))})}),t.required=t.required.filter(r=>!t.hidden.includes(r)),t}function N(e){return(e||[]).some(n=>Array.isArray(n&&n.triggers)&&n.triggers.length>0)}function o(e,n,t){this._form=e,this._wrapper=n,this._fields=(e.fields||[]).filter(r=>r.type!=="page-break"),this._listeners=[],this._depMap=new Map,this._initialEval=!1,this._baseValues=t&&t.baseValues||null,this._hasTriggers=N(this._fields),this._triggerState=null,this._triggerPrev=new Set,this._triggerFired=new Set,this._triggerApplied={hidden:[],disabled:[],required:[]},this._banners=new Map,this._dismissed=new Set}function h(e,n,t){const r=t||"",i=n||"";return r+'[name="'+e+'"]'+i+", "+r+'[name="'+e+'[]"]'+i}function W(e){return String(e||"").replace(/\[\]$/,"")}o.prototype._fieldInputs=function(e){return this._wrapper.querySelectorAll(h(e))},o.prototype._fieldInput=function(e){return this._wrapper.querySelector(h(e))},o.prototype._buildDepMap=function(){this._depMap.clear();const e=this;e._fields.forEach(function(n){const t=n.logic;if(!t)return;function r(i){if(!i)return;(i.all||i.any||[]).forEach(function(a){a.field?(e._depMap.has(a.field)||e._depMap.set(a.field,new Set),e._depMap.get(a.field).add(n.name)):r(a)})}if(t.visibility&&(t.visibility.conditions||[]).forEach(function(i){r(i.when)}),t.requirement&&(t.requirement.conditions||[]).forEach(function(i){r(i.when)}),t.cascade&&t.cascade.sourceField){const i=t.cascade.sourceField;e._depMap.has(i)||e._depMap.set(i,new Set),e._depMap.get(i).add(n.name)}})};function L(e,n){const t={};return(n||[]).forEach(function(r){if(!r||!r.name)return;const i=e.querySelectorAll(h(r.name));if(!i.length)return;const s=i[0];if(s.type==="radio"){const a=e.querySelector(h(r.name,":checked"));t[r.name]=a?a.value:""}else if(s.type==="checkbox")if(i.length>1||/\[\]$/.test(s.name||"")){const a=[];i.forEach(function(c){c.checked&&a.push(c.value)}),t[r.name]=a}else t[r.name]=s.checked?s.value||"true":"";else t[r.name]=s.value}),t}function D(e,n){const t=L(e,n),r=[],i=[];return(n||[]).forEach(function(s){if(!s||!s.name||w(s,t)==="hidden")return;const a=t[s.name],c=Array.isArray(a)?a.length===0:!String(a??"").trim();if(y(s,t)&&c){r.push({name:s.name,label:s.label||s.name});return}if(c)return;const u=q(s,a,t);u.length&&i.push(u[0].message)}),{valid:r.length===0&&i.length===0,missing:r,errors:i,values:t}}return o.prototype._getValues=function(){const e=this._baseValues?Object.assign({},this._baseValues):{};return this._fields.forEach(function(n){const t=this._fieldInputs(n.name);if(!t.length)return;const r=t[0];if(r.type==="radio"){const i=this._wrapper.querySelector(h(n.name,":checked"));e[n.name]=i?i.value:""}else if(r.type==="checkbox")if(t.length>1||/\[\]$/.test(r.name||"")){const i=[];t.forEach(function(s){s.checked&&i.push(s.value)}),e[n.name]=i}else e[n.name]=r.checked?r.value||"true":"";else e[n.name]=r.value},this),e},o.prototype._applyVisibility=function(e,n){const r=w(e,n)==="hidden",i=this._findFieldWrapper(e.name);if(!i)return;i.setAttribute("aria-hidden",String(r));const s=this._initialEval?"none":e.logic?.visibility?.transition||"none";if(s==="none"){i.classList.toggle("fb-field-hidden",r);return}const a=e.logic?.visibility?.duration;i.style.transition="",r?O(i,s,a):V(i,s,a)},o.prototype._applyRequirement=function(e,n){const t=y(e,n),r=this._fieldInput(e.name);if(!r)return;if(/\[\]$/.test(r.name||"")||r.closest&&r.closest(".domma-chooser")){const s=this._findFieldWrapper(e.name);r.removeAttribute("required"),s&&(s.setAttribute("aria-required",String(t)),s.classList.toggle("fb-field-required",t));return}t?r.setAttribute("required",""):r.removeAttribute("required");const i=this._findFieldWrapper(e.name);i&&(i.setAttribute("aria-required",String(t)),i.classList.toggle("fb-field-required",t))},o.prototype._applyCascade=function(e,n){const t=x(e,n);if(t===null)return;const r=this._wrapper.querySelector(h(e.name,"","select"));if(!r)return;const i=r.value;r.textContent="",t.forEach(function(s){const a=document.createElement("option");a.value=s.value,a.textContent=s.label||s.value,s.value===i&&(a.selected=!0),r.appendChild(a)})},o.prototype._applyValidation=function(e,n){const t=this._fieldInput(e.name);if(!t)return;const r=q(e,n[e.name],n);let i=t.parentNode.querySelector(".fb-validation-error");r.length?(i||(i=document.createElement("div"),i.className="fb-validation-error",t.parentNode.appendChild(i)),i.textContent=r[0].message):i&&i.remove()},o.prototype._findFieldWrapper=function(e){const n=this._fieldInput(e);if(!n)return null;const t=n.closest("form")||this._wrapper;let r=n;for(;r.parentNode&&r.parentNode!==t;)r=r.parentNode;return r},o.prototype.evaluate=function(e){const n=this._getValues(),t=this;let r;if(e&&this._depMap.has(e)){const i=this._depMap.get(e);r=this._fields.filter(function(s){return i.has(s.name)})}else r=this._fields;r.forEach(function(i){i.logic&&(t._applyVisibility(i,n),t._applyRequirement(i,n),t._applyCascade(i,n))}),this._applyTriggers(n)},o.prototype.init=function(){this._buildDepMap();const e=this;this._wrapper.querySelectorAll("input, select, textarea").forEach(function(r){const i=W(r.getAttribute("name"));if(!i)return;const s=function(){e.evaluate(i)};r.addEventListener("input",s),r.addEventListener("change",s),e._listeners.push({el:r,event:"input",fn:s}),e._listeners.push({el:r,event:"change",fn:s});const a=e._fields.find(function(c){return c.name===i});if(a&&a.logic&&Array.isArray(a.logic.validation)&&a.logic.validation.length){const c=function(){const u=e._getValues();e._applyValidation(a,u)};r.addEventListener("blur",c),e._listeners.push({el:r,event:"blur",fn:c})}}),this._wrapper.querySelectorAll("[data-chooser-field]").forEach(function(r){const i=r.getAttribute("data-chooser-field");if(!i)return;const s=function(){setTimeout(function(){e.evaluate(i)},0)};r.addEventListener("click",s),e._listeners.push({el:r,event:"click",fn:s})}),this._initialEval=!0,this.evaluate(),this._initialEval=!1},o.prototype.destroy=function(){this._listeners.forEach(function(e){e.el.removeEventListener(e.event,e.fn)}),this._listeners=[],this._banners.forEach(function(e){e&&e.parentNode&&e.parentNode.removeChild(e)}),this._banners.clear()},o.prototype._applyTriggers=function(e){if(!this._hasTriggers)return;const n=F(this._fields,e);this._triggerState=n;const t=this._triggerApplied||{hidden:[],disabled:[],required:[]};t.hidden.forEach(r=>{n.hidden.indexOf(r)===-1&&this._setTriggerHidden(r,!1)}),n.hidden.forEach(r=>this._setTriggerHidden(r,!0)),t.disabled.forEach(r=>{n.disabled.indexOf(r)===-1&&this._setTriggerDisabled(r,!1)}),n.disabled.forEach(r=>this._setTriggerDisabled(r,!0)),t.required.forEach(r=>{n.required.indexOf(r)===-1&&this._restoreRequired(r,e)}),n.required.forEach(r=>this._setTriggerRequired(r,!0)),this._triggerApplied={hidden:n.hidden.slice(),disabled:n.disabled.slice(),required:n.required.slice()},this._syncBanners(n.banners),this._syncSubmitBlock(n.blocks),this._fireTriggerEvents(n)},o.prototype._setTriggerHidden=function(e,n){const t=this._findFieldWrapper(e);t&&(t.classList.toggle("fb-field-trigger-hidden",n),t.setAttribute("aria-hidden",String(n||t.classList.contains("fb-field-hidden"))))},o.prototype._setTriggerDisabled=function(e,n){const t=this._findFieldWrapper(e);t&&t.classList.toggle("fb-field-disabled",n),this._fieldInputs(e).forEach(function(i){i.disabled=n});const r=this._wrapper.querySelector('[data-chooser-field="'+e+'"]');r&&(r.classList.toggle("fb-field-disabled",n),r.querySelectorAll('button, [role="radio"], [role="checkbox"]').forEach(function(i){n?i.setAttribute("aria-disabled","true"):i.removeAttribute("aria-disabled")}))},o.prototype._setTriggerRequired=function(e,n){const t=this._fieldInput(e),r=this._findFieldWrapper(e);if(r&&(r.setAttribute("aria-required",String(n)),r.classList.toggle("fb-field-required",n)),!!t){if(/\[\]$/.test(t.name||"")||t.closest&&t.closest(".domma-chooser")){t.removeAttribute("required");return}n?t.setAttribute("required",""):t.removeAttribute("required")}},o.prototype._restoreRequired=function(e,n){const t=this._fields.find(function(r){return r.name===e});t&&this._setTriggerRequired(e,y(t,n))},o.prototype._syncBanners=function(e){const n=new Map;e.forEach(function(t){n.set(t.key,t)}),this._banners.forEach(function(t,r){n.has(r)||(t.parentNode&&t.parentNode.removeChild(t),this._banners.delete(r))},this),this._dismissed.forEach(function(t){n.has(t)||this._dismissed.delete(t)},this),n.forEach(function(t,r){if(this._banners.has(r)){const a=this._banners.get(r).querySelector(".fb-trigger-banner-text");a&&a.textContent!==t.message&&(a.textContent=t.message);return}if(this._dismissed.has(r))return;const i=this._buildBanner(t,r);i&&this._banners.set(r,i)},this)},o.prototype._buildBanner=function(e,n){if(typeof document>"u"||!e.message)return null;const t=document.createElement("div");t.className="fb-trigger-banner fb-trigger-banner--"+(e.level||"info"),t.setAttribute("role",e.level==="error"?"alert":"status"),t.dataset.triggerKey=n;const r=document.createElement("span");if(r.className="fb-trigger-banner-text",r.textContent=e.message,t.appendChild(r),e.dismissible){const a=document.createElement("button");a.type="button",a.className="fb-trigger-banner-close",a.setAttribute("aria-label","Dismiss"),a.textContent="\xD7";const c=this;a.addEventListener("click",function(){c._dismissed.add(n),t.parentNode&&t.parentNode.removeChild(t),c._banners.delete(n)}),t.appendChild(a)}const i=this._findFieldWrapper(e.field),s=this._wrapper.querySelector("form")||this._wrapper;return e.position==="form-top"?s.insertBefore(t,s.firstChild):i&&i.parentNode?e.position==="field-above"?i.parentNode.insertBefore(t,i):i.parentNode.insertBefore(t,i.nextSibling):s.appendChild(t),t},o.prototype._syncSubmitBlock=function(e){const n=this._wrapper.querySelector("form")||this._wrapper,t=n.querySelector('button[type="submit"], input[type="submit"], .fb-form-submit'),r=e.length>0;this._wrapper.dataset.triggerBlocked=r?"true":"false",t&&(t.disabled=r,t.setAttribute("aria-disabled",String(r)));let i=n.querySelector(".fb-trigger-block-note");if(!r){i&&i.parentNode&&i.parentNode.removeChild(i);return}i||(i=document.createElement("p"),i.className="fb-trigger-block-note",i.setAttribute("role","status"),(t&&t.parentNode?t.parentNode:n).appendChild(i)),i.textContent=e.map(function(s){return s.message}).join(" ")},o.prototype._fireTriggerEvents=function(e){const n=new Set(e.active),t=this;e.events.forEach(function(r){t._triggerPrev.has(r.key)||r.action.once&&t._triggerFired.has(r.key)||t._initialEval&&r.action.onLoad!==!0||(t._triggerFired.add(r.key),t._runTriggerEvent(r))}),this._triggerPrev=n},o.prototype._runTriggerEvent=function(e){const n=e.action;switch(n.type){case"toast":typeof E<"u"&&E&&typeof E.toast=="function"&&E.toast(n.message||"",{type:n.level||"info",duration:Number(n.duration)||4e3});break;case"celebrate":this._celebrate(n);break;default:break}typeof CustomEvent<"u"&&this._wrapper.dispatchEvent&&this._wrapper.dispatchEvent(new CustomEvent("dm-form-trigger",{bubbles:!0,detail:{type:n.type,field:e.field,action:n}}))},o.prototype._celebrate=function(e){typeof window>"u"||typeof document>"u"||window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches||import("/public/js/celebrations/index.js").then(function(n){const t=n.CelebrationsEffect;let r=e.theme||"auto";if(r==="auto"&&(r=t.getCurrentTheme(),!r))return;const i=new t({theme:r,intensity:e.intensity||"medium",enabled:!0,zIndex:999});i.init().then(function(){i.start()})}).catch(function(){})},o.prototype.submitBlock=function(){const e=this._triggerState&&this._triggerState.blocks||[];return{blocked:e.length>0,reasons:e.map(function(n){return n.message})}},{evaluateCondition:g,evaluateConditionGroup:p,evaluateFieldVisibility:w,evaluateFieldRequirement:y,validateField:q,collectValues:L,validateFields:D,getCascadeOptions:x,resolveTriggerState:F,resolveTriggerTargets:b,hasTriggers:N,TRIGGER_ACTION_KINDS:C,SERVER_TRIGGER_ACTIONS:B,FormLogicRuntime:o}});
|
|
1
|
+
(function(u,f){typeof module<"u"&&module.exports?module.exports=f():u.FormLogicEngine=f()})(typeof globalThis<"u"?globalThis:this,function(){"use strict";function u(e){return e===""||e===null||e===void 0?"":String(e)}function f(e){const i=parseFloat(e);return isNaN(i)?null:i}function p(e){return e==null?!0:typeof e=="string"?e.trim()==="":Array.isArray(e)?e.length===0:!1}const O={not_equals:"equals",not_contains:"contains",not_in:"in"};function w(e,i){const t=u(i),n=u(e.value);switch(e.operator){case"equals":return t===n;case"not_equals":return t!==n;case"contains":return t.toLowerCase().includes(n.toLowerCase());case"not_contains":return!t.toLowerCase().includes(n.toLowerCase());case"starts_with":return t.toLowerCase().startsWith(n.toLowerCase());case"ends_with":return t.toLowerCase().endsWith(n.toLowerCase());case"greater_than":{const r=f(i),s=f(e.value);return r!==null&&s!==null&&r>s}case"less_than":{const r=f(i),s=f(e.value);return r!==null&&s!==null&&r<s}case"is_empty":return p(i);case"is_not_empty":return!p(i);case"in":return(Array.isArray(e.value)?e.value.map(u):String(e.value).split(",").map(s=>s.trim())).includes(t);case"not_in":return!(Array.isArray(e.value)?e.value.map(u):String(e.value).split(",").map(s=>s.trim())).includes(t);case"matches_regex":try{const r=e.flags||"";return new RegExp(e.value,r).test(t)}catch(r){return typeof console<"u"&&console.warn&&console.warn('[FormLogicEngine] Invalid regex in condition for field "'+e.field+'": '+e.value,r&&r.message),!1}default:return!0}}function b(e,i){if(!e||!e.field||!e.operator)return!0;const t=i[e.field];if(!Array.isArray(t))return w(e,t);if(e.operator==="is_empty")return p(t);if(e.operator==="is_not_empty")return!p(t);const n=O[e.operator];if(n){const r=Object.assign({},e,{operator:n});return!t.some(s=>w(r,s))}return t.some(r=>w(e,r))}function h(e,i){return e?Array.isArray(e.all)?e.all.every(t=>t.all||t.any?h(t,i):b(t,i)):Array.isArray(e.any)?e.any.some(t=>t.all||t.any?h(t,i):b(t,i)):e.field&&e.operator?b(e,i):!0:!0}function q(e,i){const t=e.logic;if(!t||!t.visibility)return"visible";const n=t.visibility,r=n.conditions||[];for(const s of r)if(s.when&&h(s.when,i))return s.then==="hidden"?"hidden":"visible";return n.default==="hidden"?"hidden":"visible"}function _(e,i){const t=e.logic;if(!t||!t.requirement)return e.required||!1;const n=t.requirement,r=n.conditions||[];for(const s of r)if(s.when&&h(s.when,i))return s.then===!0;return n.default===!0}function A(e,i,t){const n=e.logic;if(!n||!Array.isArray(n.validation))return[];const r=[];for(const s of n.validation)switch(s.type){case"regex":{if(!p(i))try{new RegExp(s.pattern||"",s.flags||"").test(u(i))||r.push({message:s.message||"Invalid format."})}catch{}break}case"match":{const a=t[s.field];!p(i)&&u(i)!==u(a)&&r.push({message:s.message||"Fields do not match."});break}}return r}function S(e,i){const t=e.logic;if(!t||!t.cascade||!t.cascade.sourceField)return null;const n=t.cascade,r=n.mapping||{},s=i[n.sourceField];if(Array.isArray(s)){const o=new Set,l=[];return s.forEach(function(g){const d=u(g);Object.prototype.hasOwnProperty.call(r,d)&&(r[d]||[]).forEach(function(x){const B=u(x&&x.value);o.has(B)||(o.add(B),l.push(x))})}),l.length?l:n.defaultOptions||null}const a=u(s);return Object.prototype.hasOwnProperty.call(r,a)?r[a]||[]:n.defaultOptions||null}const V={fade:250,slide:300,scale:200};function C(e,i){const t=Number(i);return!isFinite(t)||t<0||t>5e3?V[e]||250:Math.round(t)}function W(e,i,t){const n=C(i,t);if(i==="fade")e.style.transition="opacity "+n+"ms ease",e.style.opacity="1",requestAnimationFrame(function(){e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.opacity=""},n+10)});else if(i==="slide"){const r=Math.round(n*.67);e.style.overflow="hidden",e.style.maxHeight=e.scrollHeight+"px",e.style.transition="max-height "+n+"ms ease, opacity "+r+"ms ease",requestAnimationFrame(function(){e.style.maxHeight="0",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},n+20)})}else i==="scale"&&(e.style.transition="opacity "+n+"ms ease, transform "+n+"ms ease",e.style.transform="scale(1)",e.style.opacity="1",requestAnimationFrame(function(){e.style.transform="scale(0.95)",e.style.opacity="0",setTimeout(function(){e.classList.add("fb-field-hidden"),e.style.transition="",e.style.transform="",e.style.opacity=""},n+20)}))}function D(e,i,t){const n=C(i,t);if(e.classList.remove("fb-field-hidden"),i==="fade")e.style.opacity="0",e.style.transition="opacity "+n+"ms ease",requestAnimationFrame(function(){e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.opacity=""},n+10)});else if(i==="slide"){const r=Math.round(n*.67);e.style.overflow="hidden",e.style.maxHeight="0",e.style.opacity="0",e.style.transition="max-height "+n+"ms ease, opacity "+r+"ms ease",requestAnimationFrame(function(){e.style.maxHeight=e.scrollHeight+"px",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.maxHeight="",e.style.opacity="",e.style.overflow=""},n+20)})}else i==="scale"&&(e.style.transform="scale(0.95)",e.style.opacity="0",e.style.transition="opacity "+n+"ms ease, transform "+n+"ms ease",requestAnimationFrame(function(){e.style.transform="scale(1)",e.style.opacity="1",setTimeout(function(){e.style.transition="",e.style.transform="",e.style.opacity=""},n+20)}))}const T={banner:"state","disable-fields":"state","hide-fields":"state","require-fields":"state","block-submit":"state","end-form":"state",toast:"event",celebrate:"event","goto-step":"event",redirect:"event","run-action":"event",notify:"event"},H=["block-submit","hide-fields","disable-fields","require-fields","end-form","redirect","run-action","notify"];function k(e){return!!e&&!!e.name&&e.type!=="page-break"&&e.type!=="spacer"}function y(e,i,t){const n=(t||[]).filter(k),r=e.target||(e.fields&&e.fields.length?"listed":"rest");if(r==="listed"){const a=new Set(e.fields||[]);return n.filter(o=>a.has(o.name)&&o.name!==i.name).map(o=>o.name)}if(r==="all")return n.filter(a=>a.name!==i.name).map(a=>a.name);const s=n.findIndex(a=>a.name===i.name);return s===-1?[]:n.slice(s+1).map(a=>a.name)}function v(e,i){for(const t of i)e.includes(t)||e.push(t)}function P(e,i,t,n,r){if(!i||!i.type)return;const s=T[i.type];if(s){if(s==="event"){e.events.push({key:r,type:i.type,field:t.name,action:i});return}switch(i.type){case"banner":e.banners.push({key:r,field:t.name,message:i.message||"",level:i.level||"info",position:i.position||"field-below",dismissible:i.dismissible!==!1});break;case"hide-fields":v(e.hidden,y(i,t,n));break;case"disable-fields":v(e.disabled,y(i,t,n));break;case"require-fields":v(e.required,y(i,t,n));break;case"block-submit":e.blocks.push({key:r,message:i.message||"This form cannot be submitted yet."});break;case"end-form":v(e.masked,y({target:"rest"},t,n)),e.ends.push({key:r,field:t.name,message:i.message||"",finishLabel:i.finishLabel||"Finish",doneMessage:i.doneMessage||"",record:i.record!==!1,finish:i.finish!==!1}),i.finish===!1&&e.blocks.push({key:r,quiet:!0,message:i.message||"This form cannot be submitted."});break;default:break}}}function N(e,i){const t={active:[],banners:[],hidden:[],disabled:[],required:[],blocks:[],events:[],masked:[],ends:[]};return(e||[]).forEach(n=>{!k(n)||!Array.isArray(n.triggers)||n.triggers.forEach((r,s)=>{if(!r||r.enabled===!1)return;const a=r.id||`${n.name}::${s}`,o=h(r.when,i),l=`${a}:${o?"then":"else"}`,g=o?r.then:r.otherwise;!Array.isArray(g)||!g.length||(t.active.push(l),g.forEach(d=>P(t,d,n,e,l)))})}),t.required=t.required.filter(n=>!t.hidden.includes(n)&&!t.masked.includes(n)),t}function F(e){return(e||[]).some(i=>Array.isArray(i&&i.triggers)&&i.triggers.length>0)}function c(e,i,t){this._form=e,this._wrapper=i,this._fields=(e.fields||[]).filter(n=>n.type!=="page-break"),this._listeners=[],this._depMap=new Map,this._initialEval=!1,this._baseValues=t&&t.baseValues||null,this._hasTriggers=F(this._fields),this._triggerState=null,this._triggerPrev=new Set,this._triggerFired=new Set,this._triggerApplied={hidden:[],disabled:[],required:[],masked:[]},this._banners=new Map,this._dismissed=new Set,this._end=null}function m(e,i,t){const n=t||"",r=i||"";return n+'[name="'+e+'"]'+r+", "+n+'[name="'+e+'[]"]'+r}function $(e){return String(e||"").replace(/\[\]$/,"")}c.prototype._fieldInputs=function(e){return this._wrapper.querySelectorAll(m(e))},c.prototype._fieldInput=function(e){return this._wrapper.querySelector(m(e))},c.prototype._buildDepMap=function(){this._depMap.clear();const e=this;e._fields.forEach(function(i){const t=i.logic;if(!t)return;function n(r){if(!r)return;(r.all||r.any||[]).forEach(function(a){a.field?(e._depMap.has(a.field)||e._depMap.set(a.field,new Set),e._depMap.get(a.field).add(i.name)):n(a)})}if(t.visibility&&(t.visibility.conditions||[]).forEach(function(r){n(r.when)}),t.requirement&&(t.requirement.conditions||[]).forEach(function(r){n(r.when)}),t.cascade&&t.cascade.sourceField){const r=t.cascade.sourceField;e._depMap.has(r)||e._depMap.set(r,new Set),e._depMap.get(r).add(i.name)}})};function L(e,i){const t={};return(i||[]).forEach(function(n){if(!n||!n.name)return;const r=e.querySelectorAll(m(n.name));if(!r.length)return;const s=r[0];if(s.type==="radio"){const a=e.querySelector(m(n.name,":checked"));t[n.name]=a?a.value:""}else if(s.type==="checkbox")if(r.length>1||/\[\]$/.test(s.name||"")){const a=[];r.forEach(function(o){o.checked&&a.push(o.value)}),t[n.name]=a}else t[n.name]=s.checked?s.value||"true":"";else t[n.name]=s.value}),t}function I(e,i){const t=L(e,i),n=[],r=[];return(i||[]).forEach(function(s){if(!s||!s.name||q(s,t)==="hidden")return;const a=t[s.name],o=Array.isArray(a)?a.length===0:!String(a??"").trim();if(_(s,t)&&o){n.push({name:s.name,label:s.label||s.name});return}if(o)return;const l=A(s,a,t);l.length&&r.push(l[0].message)}),{valid:n.length===0&&r.length===0,missing:n,errors:r,values:t}}c.prototype._getValues=function(){const e=this._baseValues?Object.assign({},this._baseValues):{};return this._fields.forEach(function(i){const t=this._fieldInputs(i.name);if(!t.length)return;const n=t[0];if(n.type==="radio"){const r=this._wrapper.querySelector(m(i.name,":checked"));e[i.name]=r?r.value:""}else if(n.type==="checkbox")if(t.length>1||/\[\]$/.test(n.name||"")){const r=[];t.forEach(function(s){s.checked&&r.push(s.value)}),e[i.name]=r}else e[i.name]=n.checked?n.value||"true":"";else e[i.name]=n.value},this),e},c.prototype._applyVisibility=function(e,i){const n=q(e,i)==="hidden",r=this._findFieldWrapper(e.name);if(!r)return;r.setAttribute("aria-hidden",String(n));const s=this._initialEval?"none":e.logic?.visibility?.transition||"none";if(s==="none"){r.classList.toggle("fb-field-hidden",n);return}const a=e.logic?.visibility?.duration;r.style.transition="",n?W(r,s,a):D(r,s,a)},c.prototype._applyRequirement=function(e,i){const t=_(e,i),n=this._fieldInput(e.name);if(!n)return;if(/\[\]$/.test(n.name||"")||n.closest&&n.closest(".domma-chooser")){const s=this._findFieldWrapper(e.name);n.removeAttribute("required"),s&&(s.setAttribute("aria-required",String(t)),s.classList.toggle("fb-field-required",t));return}t?n.setAttribute("required",""):n.removeAttribute("required");const r=this._findFieldWrapper(e.name);r&&(r.setAttribute("aria-required",String(t)),r.classList.toggle("fb-field-required",t))},c.prototype._applyCascade=function(e,i){const t=S(e,i);if(t===null)return;const n=this._wrapper.querySelector(m(e.name,"","select"));if(!n)return;const r=n.value;n.textContent="",t.forEach(function(s){const a=document.createElement("option");a.value=s.value,a.textContent=s.label||s.value,s.value===r&&(a.selected=!0),n.appendChild(a)})},c.prototype._applyValidation=function(e,i){const t=this._fieldInput(e.name);if(!t)return;const n=A(e,i[e.name],i);let r=t.parentNode.querySelector(".fb-validation-error");n.length?(r||(r=document.createElement("div"),r.className="fb-validation-error",t.parentNode.appendChild(r)),r.textContent=n[0].message):r&&r.remove()},c.prototype._findFieldWrapper=function(e){const i=this._fieldInput(e);if(!i)return null;const t=i.closest("form")||this._wrapper;let n=i;for(;n.parentNode&&n.parentNode!==t;)n=n.parentNode;return n},c.prototype.evaluate=function(e){const i=this._getValues(),t=this;let n;if(e&&this._depMap.has(e)){const r=this._depMap.get(e);n=this._fields.filter(function(s){return r.has(s.name)})}else n=this._fields;n.forEach(function(r){r.logic&&(t._applyVisibility(r,i),t._applyRequirement(r,i),t._applyCascade(r,i))}),this._applyTriggers(i)},c.prototype.init=function(){this._buildDepMap();const e=this;if(this._wrapper.querySelectorAll("input, select, textarea").forEach(function(n){const r=$(n.getAttribute("name"));if(!r)return;const s=function(){e.evaluate(r)};n.addEventListener("input",s),n.addEventListener("change",s),e._listeners.push({el:n,event:"input",fn:s}),e._listeners.push({el:n,event:"change",fn:s});const a=e._fields.find(function(o){return o.name===r});if(a&&a.logic&&Array.isArray(a.logic.validation)&&a.logic.validation.length){const o=function(){const l=e._getValues();e._applyValidation(a,l)};n.addEventListener("blur",o),e._listeners.push({el:n,event:"blur",fn:o})}}),this._wrapper.querySelectorAll("[data-chooser-field]").forEach(function(n){const r=n.getAttribute("data-chooser-field");if(!r)return;const s=function(){setTimeout(function(){e.evaluate(r)},0)};n.addEventListener("click",s),e._listeners.push({el:n,event:"click",fn:s})}),this._hasTriggers){const n=function(r){if(e._end&&!(r.type==="click"&&!(r.target&&r.target.closest&&r.target.closest(z)))){if(!e._end.spec.finish){r.preventDefault(),r.stopImmediatePropagation();return}e._wrapper.dataset.triggerBlocked!=="true"&&(r.preventDefault(),r.stopImmediatePropagation(),e._finishEnded())}};this._wrapper.addEventListener("click",n,!0),this._wrapper.addEventListener("submit",n,!0),this._listeners.push({el:this._wrapper,event:"click",fn:n,capture:!0}),this._listeners.push({el:this._wrapper,event:"submit",fn:n,capture:!0})}this._initialEval=!0,this.evaluate(),this._initialEval=!1},c.prototype.destroy=function(){this._listeners.forEach(function(e){e.el.removeEventListener(e.event,e.fn,!!e.capture)}),this._listeners=[],this._banners.forEach(function(e){e&&e.parentNode&&e.parentNode.removeChild(e)}),this._banners.clear(),this._syncEnd([])},c.prototype._applyTriggers=function(e){if(!this._hasTriggers)return;const i=N(this._fields,e);this._triggerState=i;const t=this._triggerApplied||{hidden:[],disabled:[],required:[]};t.hidden.forEach(n=>{i.hidden.indexOf(n)===-1&&this._setTriggerHidden(n,!1)}),i.hidden.forEach(n=>this._setTriggerHidden(n,!0)),t.disabled.forEach(n=>{i.disabled.indexOf(n)===-1&&this._setTriggerDisabled(n,!1)}),i.disabled.forEach(n=>this._setTriggerDisabled(n,!0)),t.required.forEach(n=>{i.required.indexOf(n)===-1&&this._restoreRequired(n,e)}),i.required.forEach(n=>this._setTriggerRequired(n,!0)),(t.masked||[]).forEach(n=>{i.masked.indexOf(n)===-1&&this._setTriggerMasked(n,!1)}),i.masked.forEach(n=>this._setTriggerMasked(n,!0)),this._triggerApplied={hidden:i.hidden.slice(),disabled:i.disabled.slice(),required:i.required.slice(),masked:i.masked.slice()},this._syncBanners(i.banners),this._syncSubmitBlock(i.blocks),this._syncEnd(i.ends),this._fireTriggerEvents(i)},c.prototype._setTriggerHidden=function(e,i){const t=this._findFieldWrapper(e);t&&(t.classList.toggle("fb-field-trigger-hidden",i),t.setAttribute("aria-hidden",String(i||t.classList.contains("fb-field-hidden"))))},c.prototype._setTriggerMasked=function(e,i){const t=this._findFieldWrapper(e);t&&(t.classList.toggle("fb-field-trigger-masked",i),t.setAttribute("aria-hidden",String(i||t.classList.contains("fb-field-hidden")||t.classList.contains("fb-field-trigger-hidden"))))},c.prototype._setTriggerDisabled=function(e,i){const t=this._findFieldWrapper(e);t&&t.classList.toggle("fb-field-disabled",i),this._fieldInputs(e).forEach(function(r){r.disabled=i});const n=this._wrapper.querySelector('[data-chooser-field="'+e+'"]');n&&(n.classList.toggle("fb-field-disabled",i),n.querySelectorAll('button, [role="radio"], [role="checkbox"]').forEach(function(r){i?r.setAttribute("aria-disabled","true"):r.removeAttribute("aria-disabled")}))},c.prototype._setTriggerRequired=function(e,i){const t=this._fieldInput(e),n=this._findFieldWrapper(e);if(n&&(n.setAttribute("aria-required",String(i)),n.classList.toggle("fb-field-required",i)),!!t){if(/\[\]$/.test(t.name||"")||t.closest&&t.closest(".domma-chooser")){t.removeAttribute("required");return}i?t.setAttribute("required",""):t.removeAttribute("required")}},c.prototype._restoreRequired=function(e,i){const t=this._fields.find(function(n){return n.name===e});t&&this._setTriggerRequired(e,_(t,i))},c.prototype._syncBanners=function(e){const i=new Map;e.forEach(function(t){i.set(t.key,t)}),this._banners.forEach(function(t,n){i.has(n)||(t.parentNode&&t.parentNode.removeChild(t),this._banners.delete(n))},this),this._dismissed.forEach(function(t){i.has(t)||this._dismissed.delete(t)},this),i.forEach(function(t,n){if(this._banners.has(n)){const a=this._banners.get(n).querySelector(".fb-trigger-banner-text");a&&a.textContent!==t.message&&(a.textContent=t.message);return}if(this._dismissed.has(n))return;const r=this._buildBanner(t,n);r&&this._banners.set(n,r)},this)},c.prototype._buildBanner=function(e,i){if(typeof document>"u"||!e.message)return null;const t=document.createElement("div");t.className="fb-trigger-banner fb-trigger-banner--"+(e.level||"info"),t.setAttribute("role",e.level==="error"?"alert":"status"),t.dataset.triggerKey=i;const n=document.createElement("span");if(n.className="fb-trigger-banner-text",n.textContent=e.message,t.appendChild(n),e.dismissible){const a=document.createElement("button");a.type="button",a.className="fb-trigger-banner-close",a.setAttribute("aria-label","Dismiss"),a.textContent="\xD7";const o=this;a.addEventListener("click",function(){o._dismissed.add(i),t.parentNode&&t.parentNode.removeChild(t),o._banners.delete(i)}),t.appendChild(a)}const r=this._findFieldWrapper(e.field),s=this._wrapper.querySelector("form")||this._wrapper;return e.position==="form-top"?s.insertBefore(t,s.firstChild):r&&r.parentNode?e.position==="field-above"?r.parentNode.insertBefore(t,r):r.parentNode.insertBefore(t,r.nextSibling):s.appendChild(t),t},c.prototype._syncSubmitBlock=function(e){const i=this._wrapper.querySelector("form")||this._wrapper,t=i.querySelector('button[type="submit"], input[type="submit"], .fb-form-submit'),n=e.length>0;this._wrapper.dataset.triggerBlocked=n?"true":"false",t&&(t.disabled=n,t.setAttribute("aria-disabled",String(n)));let r=i.querySelector(".fb-trigger-block-note");const s=e.filter(function(a){return!a.quiet}).map(function(a){return a.message});if(!s.length){r&&r.parentNode&&r.parentNode.removeChild(r);return}r||(r=document.createElement("p"),r.className="fb-trigger-block-note",r.setAttribute("role","status"),(t&&t.parentNode?t.parentNode:i).appendChild(r)),r.textContent=s.join(" ")};const z='button[type="submit"], input[type="submit"], .fb-form-submit, .wizard-next, .wizard-submit';c.prototype._primaryButton=function(){return this._wrapper.querySelector(".wizard-next, .wizard-submit")||this._wrapper.querySelector('button[type="submit"], input[type="submit"], .fb-form-submit')};function M(e){return!!(e.matches&&e.matches(".wizard-next, .wizard-submit"))}function R(e,i){e.tagName==="INPUT"?e.value=i:e.textContent=i}return c.prototype._syncEnd=function(e){const i=e&&e.length?e[0]:null,t=this._end;if(t&&(!i||t.spec.key!==i.key)&&(t.panel&&t.panel.parentNode&&t.panel.parentNode.removeChild(t.panel),t.button&&t.button.isConnected&&(t.spec.finish?R(t.button,t.label):M(t.button)&&(t.button.disabled=!1)),this._end=null),this._wrapper.dataset.triggerEnded=i?"true":"false",!i||typeof document>"u")return;if(this._end){const a=this._end.panel&&this._end.panel.querySelector(".fb-trigger-end-text");a&&a.textContent!==i.message&&(a.textContent=i.message),this._end.spec=i;return}let n=null;if(i.message){n=document.createElement("div"),n.className="fb-trigger-end",n.setAttribute("role","status"),n.dataset.triggerKey=i.key;const a=document.createElement("div");a.className="fb-trigger-end-text",a.textContent=i.message,n.appendChild(a);const o=this._findFieldWrapper(i.field);o&&o.parentNode?o.parentNode.insertBefore(n,o.nextSibling):(this._wrapper.querySelector("form")||this._wrapper).appendChild(n)}const r=this._primaryButton();let s="";r&&i.finish?(s=r.tagName==="INPUT"?r.value:r.textContent,R(r,i.finishLabel)):r&&M(r)&&(r.disabled=!0),this._end={spec:i,panel:n,button:r,label:s}},c.prototype._finishEnded=function(){const e=this._triggerState||{},i=new Set([].concat(e.masked||[],e.hidden||[],e.disabled||[])),t=this,n=this._fields.filter(function(a){return k(a)&&!i.has(a.name)&&t._fieldInput(a.name)}),r=this._getValues();(e.masked||[]).forEach(function(a){delete r[a]});const s=I(this._wrapper,n);(e.required||[]).forEach(function(a){const o=n.find(function(d){return d.name===a});if(!o)return;const l=r[a];(Array.isArray(l)?l.length===0:!String(l??"").trim())&&!s.missing.some(function(d){return d.name===a})&&(s.missing.push({name:a,label:o.label||a}),s.valid=!1)}),this._wrapper.dispatchEvent(new CustomEvent("dm-form-end",{bubbles:!0,detail:{values:r,validation:s,end:this._end?this._end.spec:null}}))},c.prototype._fireTriggerEvents=function(e){const i=new Set(e.active),t=this;e.events.forEach(function(n){t._triggerPrev.has(n.key)||n.action.once&&t._triggerFired.has(n.key)||t._initialEval&&n.action.onLoad!==!0||(t._triggerFired.add(n.key),t._runTriggerEvent(n))}),this._triggerPrev=i},c.prototype._runTriggerEvent=function(e){const i=e.action;switch(i.type){case"toast":typeof E<"u"&&E&&typeof E.toast=="function"&&E.toast(i.message||"",{type:i.level||"info",duration:Number(i.duration)||4e3});break;case"celebrate":this._celebrate(i);break;default:break}typeof CustomEvent<"u"&&this._wrapper.dispatchEvent&&this._wrapper.dispatchEvent(new CustomEvent("dm-form-trigger",{bubbles:!0,detail:{type:i.type,field:e.field,action:i}}))},c.prototype._celebrate=function(e){typeof window>"u"||typeof document>"u"||window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches||import("/public/js/celebrations/index.js").then(function(i){const t=i.CelebrationsEffect;let n=e.theme||"auto";if(n==="auto"&&(n=t.getCurrentTheme(),!n))return;const r=new t({theme:n,intensity:e.intensity||"medium",enabled:!0,zIndex:999});r.init().then(function(){r.start()})}).catch(function(){})},c.prototype.submitBlock=function(){const e=this._triggerState&&this._triggerState.blocks||[];return{blocked:e.length>0,reasons:e.map(function(i){return i.message})}},{evaluateCondition:b,evaluateConditionGroup:h,evaluateFieldVisibility:q,evaluateFieldRequirement:_,validateField:A,collectValues:L,validateFields:I,getCascadeOptions:S,resolveTriggerState:N,resolveTriggerTargets:y,hasTriggers:F,TRIGGER_ACTION_KINDS:T,SERVER_TRIGGER_ACTIONS:H,FormLogicRuntime:c}});
|
package/public/js/forms.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{buildWizardSteps as
|
|
2
|
-
`).replace(/<[^>]+>/g,""))}function N(n){return String(n).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function w(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 _(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 a of i.removedNodes)if(a===n||a.nodeType===1&&a.contains&&a.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1}),n._formLogicObserver=t}function W(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function j(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)),a=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,u={...e.formConfig||{}};u.span==="full"&&o&&(u.span=o);const r={type:a,label:e.label||e.name,required:W(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...u}};e.minLength!==void 0&&(r.minLength=e.minLength),e.maxLength!==void 0&&(r.maxLength=e.maxLength),e.min!==void 0&&(r.min=e.min),e.max!==void 0&&(r.max=e.max),i&&(e.variant&&(r.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(r.multiple=!0),e.density&&(r.density=e.density),e.columns&&(r.columns=e.columns),e.accent&&(r.accent=e.accent),e.accentStyle&&(r.accentStyle=e.accentStyle),e.glow&&(r.glow=!0),e.glowColour&&(r.glowColour=e.glowColour),e.shadow&&(r.shadow=e.shadow),e.shadowColour&&(r.shadowColour=e.shadowColour)),t[e.name]=r}),t}function J(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 A(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 R="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 O(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 a=document.createElement("button");a.type="button",a.textContent="\xD7",a.setAttribute("aria-label","Close"),a.style.cssText=R+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(i),e.appendChild(a),t.appendChild(e);const u=document.createElement("div");u.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(u),o.appendChild(t);const r=l=>{l.key==="Escape"&&s()};function s(){document.removeEventListener("keydown",r),o.remove()}return a.addEventListener("click",s),o.addEventListener("click",l=>{l.target===o&&s()}),document.addEventListener("keydown",r),document.body.appendChild(o),{body:u,close:s}}function U(n){const{body:o,close:t}=O("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 a=window.I&&typeof I.list=="function"?I.list():[],u=a.map(r=>{const s=document.createElement("button");s.type="button",s.title=r,s.dataset.iconName=r,s.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",r),l.setAttribute("data-icon-size","18"),s.appendChild(l),s.addEventListener("mouseenter",()=>{s.style.borderColor="var(--dm-border)"}),s.addEventListener("mouseleave",()=>{s.style.borderColor="transparent"}),s.addEventListener("click",()=>{t(),n(r)}),i.appendChild(s),s});if(!a.length){const r=document.createElement("p");r.textContent="Icon engine unavailable - type an icon name into the field instead.",i.appendChild(r)}window.I?.scan?.(i),e.addEventListener("input",()=>{const r=e.value.trim().toLowerCase();u.forEach(s=>{s.style.display=!r||s.dataset.iconName.includes(r)?"":"none"})}),e.focus()}async function H(){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:a}=await i.json();S.set("auth_token",a),t=await o(a)}}}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 K(n){const{body:o,close:t}=O("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),H().then(({files:i,error:a})=>{if(a){e.textContent=a==="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 u=document.createElement("div");u.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",i.forEach(r=>{const s=document.createElement("button");s.type="button",s.title=r.name||r.url,s.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=r.url,l.alt=r.name||"",l.loading="lazy",l.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const c=document.createElement("span");c.textContent=r.name||r.url,c.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",s.appendChild(l),s.appendChild(c),s.addEventListener("click",()=>{t(),n(r.url)}),u.appendChild(s)}),o.appendChild(u)})}function B(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function z(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 P(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=R,o}function Y(n){if(!window.I||typeof I.list!="function")return;const o=z(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 a=n.value.trim();if(!a)return;const u=document.createElement("span");u.setAttribute("data-icon",a),u.setAttribute("data-icon-size","16"),t.appendChild(u),window.I?.scan?.(t)};n.addEventListener("input",e),e();const i=P("Browse");i.addEventListener("click",()=>U(a=>{B(n,a),e()})),o.appendChild(t),o.appendChild(i)}function $(n){const o=z(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 a=n.value.trim();t.style.display=a?"":"none",a&&(t.src=a)};n.addEventListener("input",e),e();const i=P("Browse");i.addEventListener("click",()=>K(a=>{B(n,a),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"?Y(i):$(i))})}function k(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 D(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let i=0;o.forEach(function(a){if(a.type==="spacer"){const u=document.createElement("div");u.className="fb-spacer";const r=e[i];if(r)t.insertBefore(u,r);else{const s=t.querySelector('[type="submit"]');s?t.insertBefore(u,s):t.appendChild(u)}}else a.type!=="page-break"&&i++})}function T(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 q(n,o,t,e,i,a){const u=i||e,r=u.querySelector(".fb-form-honeypot"),s=r?.querySelector('input[type="text"]')?.value||"",l=r?.querySelector('[name="_t"]')?.value||"",c=Object.assign({},o);delete c._t,r?.dataset.hpName&&delete c[r.dataset.hpName];const m=new Map(a||[]);T(u,m);const d=m.size>0;let b,g;if(d){const p=new FormData;for(const[y,v]of Object.entries(c))v!=null&&(m.has(y)||p.append(y,typeof v=="object"?JSON.stringify(v):String(v)));for(const[y,v]of m)for(const x of v)p.append(y,x,x.name);p.append("_hp",s),p.append("_t",l),b=p,g={}}else{const p=Object.assign({},c,{_hp:s,_t:l});b=JSON.stringify(p),g={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:g,body:b}).then(p=>p.json().then(y=>({ok:p.ok,body:y}))).then(p=>{p.ok&&p.body.ok?(e.textContent="",w(e,p.body.message||t.successMessage||"Thank you.","success")):w(e,p.body.error||"Something went wrong.","error")}).catch(()=>{w(e,"Unable to submit. Please check your connection.","error")})}function G(n,o,t,e,i){const a=document.createElement("form");a.noValidate=!0,o.forEach(function(r){const s=document.createElement("div");s.className="form-group",s.style.marginBottom="1.25rem";const l=document.createElement("label");if(l.className="form-label",l.textContent=r.label||r.name,r.required){const m=document.createElement("span");m.textContent=" *",m.style.color="var(--dm-danger)",l.appendChild(m)}let c;r.type==="textarea"?(c=document.createElement("textarea"),c.rows=r.formConfig?.rows||4,c.className="form-input"):r.type==="select"?(c=document.createElement("select"),c.className="form-input",(r.options||[]).forEach(function(m){const d=document.createElement("option");d.value=typeof m=="string"?m:m.value??"",d.textContent=typeof m=="string"?m:m.label||d.value,c.appendChild(d)})):(c=document.createElement("input"),c.type=r.type==="icon"||r.type==="image"?"text":r.type||"text",c.className="form-input",r.placeholder&&(c.placeholder=r.placeholder),r.type==="file"&&(r.file?.accept&&(c.accept=r.file.accept),r.multiple&&(c.multiple=!0))),c.name=r.name,c.required=r.required||!1,s.appendChild(l),s.appendChild(c),a.appendChild(s)}),t.honeypot&&k(a);const u=document.createElement("button");if(u.type="submit",u.className="btn btn-primary",u.textContent=t.submitText||"Submit",a.appendChild(u),a.addEventListener("submit",function(r){r.preventDefault();const s={};if(o.forEach(function(l){const c=a.querySelector('[name="'+l.name+'"]');c&&(s[l.name]=c.value)}),window.FormLogicEngine&&i){const l=window.FormLogicEngine,c=[],m=[];if(o.forEach(function(d){if(l.evaluateFieldVisibility(d,s)==="hidden"){delete s[d.name];return}const g=l.evaluateFieldRequirement(d,s),p=s[d.name];g&&(!p||!String(p).trim())&&c.push(d.label||d.name);const y=l.validateField(d,p||"",s);y.length&&m.push(y[0].message)}),c.length||m.length){const d=[];c.length&&d.push("Required: "+c.join(", ")),m.length&&d.push(m.join("; ")),w(n,d.join(". "),"error");return}}if(n.dataset.triggerBlocked==="true"){const l=n._formLogicRuntime,c=l&&l.submitBlock?l.submitBlock().reasons:[];w(n,c.join(" ")||"This form cannot be submitted yet.","error");return}n.classList.add("fb-form-loading"),u.disabled=!0,q(e,s,t,n,a).finally(function(){n.classList.remove("fb-form-loading"),u.disabled=!1})}),n.appendChild(a),enhancePickerFields(n,o),window.FormLogicEngine&&i&&L(o)){const r=new window.FormLogicEngine.FormLogicRuntime(i,n);r.init(),n._formLogicRuntime=r}}function Q(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||{},a=document.createElement("div");a.className="fb-form-wrapper",n.appendChild(a);const u=e.some(r=>r.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const r=Number(i.columns)===3?3:2,s=i.layout||"grid";if(u&&Domma.forms.wizard){const l=M(e,t.title),c=l.map(f=>f.fields),m=l.map(function(f){return{title:f.title,description:f.description,fields:j(f.fields,r)}});let d=0,b=null,g=null;const p=Date.now(),y=new Map,v=function(f){const h=window.FormLogicEngine;if(!h||!h.validateFields)return;const C=h.validateFields(a,c[d]||[]);C.valid||(f.preventDefault(),f.stopImmediatePropagation(),markInvalidFields(a,C.missing),showValidationPopup(C))},x=function(){const f=c[d]||e;if(A(a,f),enhancePickerFields(a,f),f.some(h=>h.type==="spacer")&&D(a,f),i.honeypot){const h=a.querySelector("form");h&&k(h,p)}window.FormLogicEngine&&L(e)&&(b&&b.destroy(),b=new window.FormLogicEngine.FormLogicRuntime(t,a,{baseValues:g&&g.getStepData?g.getStepData():{}}),b.init(),_(a,b)),a.querySelectorAll(".wizard-next, .wizard-submit").forEach(h=>h.addEventListener("click",v,!0))};g=Domma.forms.wizard(a,{schema:{steps:m},layout:s,columns:r,finishText:i.submitText||"Finish",onStepChange:function(f){T(a,y),d=f,setTimeout(x,0)},onSubmit:function(f){return T(a,y),q(o,f,i,a,null,y)}}),a.addEventListener("dm-form-trigger",function(f){if(!f.detail||f.detail.type!=="goto-step"||!g||!g.goToStep)return;const h=Number(f.detail.action.step);!isFinite(h)||h<0||h>=m.length||h!==d&&g.goToStep(h)}),Promise.resolve(g).then(x)}else if(Domma.forms.render){const l=j(e,r),c=J(e),m=Domma.forms.render(a,l,c,{submitText:i.submitText||"Submit",layout:s,columns:r,onSubmit:function(d){return q(o,d,i,a,null)}});Promise.resolve(m).then(function(){if(A(a,e),enhancePickerFields(a,e),window.FormLogicEngine&&L(e)){const d=new window.FormLogicEngine.FormLogicRuntime(t,a);d.init(),_(a,d)}if(e.some(d=>d.type==="spacer")&&D(a,e),s==="grid"&&i.submitSpan==="full"){const d=a.querySelector(".form-buttons");d&&d.classList.add("col-span-full")}if(i.honeypot){const d=a.querySelector("form");d&&k(d)}})}}else G(a,e.filter(r=>r.type!=="page-break"&&r.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
|
+
import{buildWizardSteps as V}from"/public/js/form-steps.mjs";const N=document.querySelectorAll("[data-form]");N.length&&N.forEach(X);function T(n){return(n||[]).some(o=>o.logic||Array.isArray(o.triggers)&&o.triggers.length)}function W(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=W(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>"+_(e.label)+"</strong> is required.").concat((n.errors||[]).map(_)),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 _(n){return String(n).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function q(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 j(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 a of r.removedNodes)if(a===n||a.nodeType===1&&a.contains&&a.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1}),n._formLogicObserver=t}function J(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function A(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)),a=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":r?"chooser":e.type,u={...e.formConfig||{}};u.span==="full"&&o&&(u.span=o);const i={type:a,label:e.label||e.name,required:J(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...u}};e.minLength!==void 0&&(i.minLength=e.minLength),e.maxLength!==void 0&&(i.maxLength=e.maxLength),e.min!==void 0&&(i.min=e.min),e.max!==void 0&&(i.max=e.max),r&&(e.variant&&(i.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(i.multiple=!0),e.density&&(i.density=e.density),e.columns&&(i.columns=e.columns),e.accent&&(i.accent=e.accent),e.accentStyle&&(i.accentStyle=e.accentStyle),e.glow&&(i.glow=!0),e.glowColour&&(i.glowColour=e.glowColour),e.shadow&&(i.shadow=e.shadow),e.shadowColour&&(i.shadowColour=e.shadowColour)),t[e.name]=i}),t}function U(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 B(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 a=document.createElement("button");a.type="button",a.textContent="\xD7",a.setAttribute("aria-label","Close"),a.style.cssText=O+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(r),e.appendChild(a),t.appendChild(e);const u=document.createElement("div");u.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(u),o.appendChild(t);const i=d=>{d.key==="Escape"&&s()};function s(){document.removeEventListener("keydown",i),o.remove()}return a.addEventListener("click",s),o.addEventListener("click",d=>{d.target===o&&s()}),document.addEventListener("keydown",i),document.body.appendChild(o),{body:u,close:s}}function H(n){const{body:o,close:t}=B("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 a=window.I&&typeof I.list=="function"?I.list():[],u=a.map(i=>{const s=document.createElement("button");s.type="button",s.title=i,s.dataset.iconName=i,s.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 d=document.createElement("span");return d.setAttribute("data-icon",i),d.setAttribute("data-icon-size","18"),s.appendChild(d),s.addEventListener("mouseenter",()=>{s.style.borderColor="var(--dm-border)"}),s.addEventListener("mouseleave",()=>{s.style.borderColor="transparent"}),s.addEventListener("click",()=>{t(),n(i)}),r.appendChild(s),s});if(!a.length){const i=document.createElement("p");i.textContent="Icon engine unavailable - type an icon name into the field instead.",r.appendChild(i)}window.I?.scan?.(r),e.addEventListener("input",()=>{const i=e.value.trim().toLowerCase();u.forEach(s=>{s.style.display=!i||s.dataset.iconName.includes(i)?"":"none"})}),e.focus()}async function K(){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:a}=await r.json();S.set("auth_token",a),t=await o(a)}}}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 Y(n){const{body:o,close:t}=B("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),K().then(({files:r,error:a})=>{if(a){e.textContent=a==="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 u=document.createElement("div");u.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",r.forEach(i=>{const s=document.createElement("button");s.type="button",s.title=i.name||i.url,s.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 d=document.createElement("img");d.src=i.url,d.alt=i.name||"",d.loading="lazy",d.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const c=document.createElement("span");c.textContent=i.name||i.url,c.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",s.appendChild(d),s.appendChild(c),s.addEventListener("click",()=>{t(),n(i.url)}),u.appendChild(s)}),o.appendChild(u)})}function z(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function P(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 D(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=O,o}function $(n){if(!window.I||typeof I.list!="function")return;const o=P(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 a=n.value.trim();if(!a)return;const u=document.createElement("span");u.setAttribute("data-icon",a),u.setAttribute("data-icon-size","16"),t.appendChild(u),window.I?.scan?.(t)};n.addEventListener("input",e),e();const r=D("Browse");r.addEventListener("click",()=>H(a=>{z(n,a),e()})),o.appendChild(t),o.appendChild(r)}function G(n){const o=P(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 a=n.value.trim();t.style.display=a?"":"none",a&&(t.src=a)};n.addEventListener("input",e),e();const r=D("Browse");r.addEventListener("click",()=>Y(a=>{z(n,a),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"?$(r):G(r))})}function F(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 M(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let r=0;o.forEach(function(a){if(a.type==="spacer"){const u=document.createElement("div");u.className="fb-spacer";const i=e[r];if(i)t.insertBefore(u,i);else{const s=t.querySelector('[type="submit"]');s?t.insertBefore(u,s):t.appendChild(u)}}else a.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,a){const u=r||e,i=u.querySelector(".fb-form-honeypot"),s=i?.querySelector('input[type="text"]')?.value||"",d=i?.querySelector('[name="_t"]')?.value||"",c=Object.assign({},o);delete c._t,i?.dataset.hpName&&delete c[i.dataset.hpName];const m=new Map(a||[]);L(u,m);const l=m.size>0;let b,y;if(l){const f=new FormData;for(const[g,v]of Object.entries(c))v!=null&&(m.has(g)||f.append(g,typeof v=="object"?JSON.stringify(v):String(v)));for(const[g,v]of m)for(const w of v)f.append(g,w,w.name);f.append("_hp",s),f.append("_t",d),b=f,y={}}else{const f=Object.assign({},c,{_hp:s,_t:d});b=JSON.stringify(f),y={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:y,body:b}).then(f=>f.json().then(g=>({ok:f.ok,body:g}))).then(f=>{f.ok&&f.body.ok?(e.textContent="",C(e,f.body.message||t.successMessage||"Thank you.","success")):C(e,f.body.error||"Something went wrong.","error")}).catch(()=>{C(e,"Unable to submit. Please check your connection.","error")})}function Q(n,o,t,e,r){const a=document.createElement("form");a.noValidate=!0,o.forEach(function(i){const s=document.createElement("div");s.className="form-group",s.style.marginBottom="1.25rem";const d=document.createElement("label");if(d.className="form-label",d.textContent=i.label||i.name,i.required){const m=document.createElement("span");m.textContent=" *",m.style.color="var(--dm-danger)",d.appendChild(m)}let c;i.type==="textarea"?(c=document.createElement("textarea"),c.rows=i.formConfig?.rows||4,c.className="form-input"):i.type==="select"?(c=document.createElement("select"),c.className="form-input",(i.options||[]).forEach(function(m){const l=document.createElement("option");l.value=typeof m=="string"?m:m.value??"",l.textContent=typeof m=="string"?m:m.label||l.value,c.appendChild(l)})):(c=document.createElement("input"),c.type=i.type==="icon"||i.type==="image"?"text":i.type||"text",c.className="form-input",i.placeholder&&(c.placeholder=i.placeholder),i.type==="file"&&(i.file?.accept&&(c.accept=i.file.accept),i.multiple&&(c.multiple=!0))),c.name=i.name,c.required=i.required||!1,s.appendChild(d),s.appendChild(c),a.appendChild(s)}),t.honeypot&&F(a);const u=document.createElement("button");if(u.type="submit",u.className="btn btn-primary",u.textContent=t.submitText||"Submit",a.appendChild(u),a.addEventListener("submit",function(i){i.preventDefault();const s={};if(o.forEach(function(d){const c=a.querySelector('[name="'+d.name+'"]');c&&(s[d.name]=c.value)}),window.FormLogicEngine&&r){const d=window.FormLogicEngine,c=[],m=[];if(o.forEach(function(l){if(d.evaluateFieldVisibility(l,s)==="hidden"){delete s[l.name];return}const y=d.evaluateFieldRequirement(l,s),f=s[l.name];y&&(!f||!String(f).trim())&&c.push(l.label||l.name);const g=d.validateField(l,f||"",s);g.length&&m.push(g[0].message)}),c.length||m.length){const l=[];c.length&&l.push("Required: "+c.join(", ")),m.length&&l.push(m.join("; ")),C(n,l.join(". "),"error");return}}if(n.dataset.triggerBlocked==="true"){const d=n._formLogicRuntime,c=d&&d.submitBlock?d.submitBlock().reasons:[];C(n,c.join(" ")||"This form cannot be submitted yet.","error");return}n.classList.add("fb-form-loading"),u.disabled=!0,x(e,s,t,n,a).finally(function(){n.classList.remove("fb-form-loading"),u.disabled=!1})}),n.appendChild(a),enhancePickerFields(n,o),q(n,function(i){return x(e,i,t,n,a)}),window.FormLogicEngine&&r&&T(o)){const i=new window.FormLogicEngine.FormLogicRuntime(r,n);i.init(),n._formLogicRuntime=i}}function X(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||{},a=document.createElement("div");a.className="fb-form-wrapper",n.appendChild(a);const u=e.some(i=>i.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const i=Number(r.columns)===3?3:2,s=r.layout||"grid";if(u&&Domma.forms.wizard){const d=V(e,t.title),c=d.map(p=>p.fields),m=d.map(function(p){return{title:p.title,description:p.description,fields:A(p.fields,i)}});let l=0,b=null,y=null;const f=Date.now(),g=new Map,v=function(p){const h=window.FormLogicEngine;if(!h||!h.validateFields)return;const k=h.validateFields(a,c[l]||[]);k.valid||(p.preventDefault(),p.stopImmediatePropagation(),markInvalidFields(a,k.missing),showValidationPopup(k))},w=function(){const p=c[l]||e;if(R(a,p),enhancePickerFields(a,p),p.some(h=>h.type==="spacer")&&M(a,p),r.honeypot){const h=a.querySelector("form");h&&F(h,f)}window.FormLogicEngine&&T(e)&&(b&&b.destroy(),b=new window.FormLogicEngine.FormLogicRuntime(t,a,{baseValues:y&&y.getStepData?y.getStepData():{}}),b.init(),j(a,b)),a.querySelectorAll(".wizard-next, .wizard-submit").forEach(h=>h.addEventListener("click",v,!0))};y=Domma.forms.wizard(a,{schema:{steps:m},layout:s,columns:i,finishText:r.submitText||"Finish",onStepChange:function(p){L(a,g),l=p,setTimeout(w,0)},onSubmit:function(p){return L(a,g),x(o,p,r,a,null,g)}}),q(a,function(p){return L(a,g),x(o,p,r,a,null,g)}),a.addEventListener("dm-form-trigger",function(p){if(!p.detail||p.detail.type!=="goto-step"||!y||!y.goToStep)return;const h=Number(p.detail.action.step);!isFinite(h)||h<0||h>=m.length||h!==l&&y.goToStep(h)}),Promise.resolve(y).then(w)}else if(Domma.forms.render){const d=A(e,i),c=U(e);q(a,function(l){return x(o,l,r,a,null)});const m=Domma.forms.render(a,d,c,{submitText:r.submitText||"Submit",layout:s,columns:i,onSubmit:function(l){return x(o,l,r,a,null)}});Promise.resolve(m).then(function(){if(R(a,e),enhancePickerFields(a,e),window.FormLogicEngine&&T(e)){const l=new window.FormLogicEngine.FormLogicRuntime(t,a);l.init(),j(a,l)}if(e.some(l=>l.type==="spacer")&&M(a,e),s==="grid"&&r.submitSpan==="full"){const l=a.querySelector(".form-buttons");l&&l.classList.add("col-span-full")}if(r.honeypot){const l=a.querySelector("form");l&&F(l)}})}}else Q(a,e.filter(i=>i.type!=="page-break"&&i.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)})}
|
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{makeBadgeEl as N,applyColour as M,applyPill as B,applyFloat as R,applyHighlight as z,applyItemHighlight as P,itemHighlightAttrs as V,isCurrentItem as O,menuAlign as J}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{initFloatingMenus as W}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as j,markInvalidFields as G,showValidationPopup as X}from"/public/js/forms.js?v=20260821-wizard-grid";import{buildWizardSteps as Y}from"/public/js/form-steps.mjs";$(()=>{const b=window.__CMS_NAV__||{},g=window.__CMS_SITE__||{};if(g.autoTheme?.enabled){let t=function(e){const c=(e||"07:00").split(":");return+c[0]*60+(+c[1]||0)},o=function(){const e=new Date,c=e.getHours()*60+e.getMinutes();return c>=t(a.dayStart)&&c<t(a.nightStart)?a.dayTheme:a.nightTheme},n=function(e){const c=a.apply&&a.apply[e]||{theme:e,custom:""};Domma.theme.set(c.theme);for(const p of[...document.body.classList])p.startsWith("dm-custom-")&&document.body.classList.remove(p);c.custom&&document.body.classList.add(c.custom)};const a=g.autoTheme;n(o()),setInterval(()=>n(o()),6e4)}const k=$("#site-navbar");if(k.length&&b.brand){let o=function(i,d=0){return Array.isArray(i)?i.filter(s=>!(s&&s.type==="spacer")).filter(s=>!(s&&s.type==="separator"&&d===0)).map(s=>s&&s.type==="separator"?{divider:!0}:Array.isArray(s?.items)?{...s,items:o(s.items,d+1)}:s):i},n=function(i){return Array.isArray(i)?i.filter(d=>!(d&&(d.type==="separator"||d.type==="spacer"))):[]};const a={...b.brand},t=a.size&&a.size!=="md"?` navbar-brand-${a.size}`:"";if(a.logo||a.icon||a.tagline){let i="";a.logo?i+=`<img src="${a.logo}" class="navbar-brand-logo" alt="${a.text||""}">`:a.icon&&(i+=`<span data-icon="${a.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),a.text&&(i+=`<span class="navbar-brand-text${t}">${a.text}</span>`),a.tagline&&(i+=`<small class="navbar-brand-tagline">${a.tagline}</small>`),a.html=i}else t&&a.text&&(a.html=`<span class="navbar-brand-text${t}">${a.text}</span>`);const e=b.position==="floating",c=b.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:a,items:o(b.items||[]),variant:b.variant||"dark",position:e?"static":b.position||"sticky",collapsible:!0,appearOnHover:!!b.appearOnHover}),Domma.icons.scan("#site-navbar");const p=k.get(0);p.classList.add(`dm-nav-align-${J(b)||"centre"}`),c&&k.get(0).classList.add("dm-nav-vertical",b.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),z(p,b),e&&(R(k.get(0),b),W(k.get(0).parentNode||document));const y=p.querySelector(".navbar-toggle"),h=p.querySelector(".navbar-collapse");if(y&&h){let i=null;const d=()=>{h.classList.contains("show")&&y.click()},s=()=>{i&&(i.remove(),i=null),document.body.classList.remove("dm-drawer-open")},r=()=>{i||(i=document.createElement("div"),i.className="dm-navbar-backdrop",i.addEventListener("click",d),document.body.appendChild(i),document.body.classList.add("dm-drawer-open"))};y.addEventListener("click",()=>{requestAnimationFrame(()=>{h.classList.contains("show")?r():s()})}),h.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(s)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&h.classList.contains("show")&&d()})}const u=p.querySelector(".navbar-nav");if(u){const i=Array.from(u.children);let d=0;for(const s of b.items||[])if(!(s&&s.type==="separator")){if(s&&s.type==="spacer"){const r=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(s.size)?s.size:"md";r.className=`dm-menu-spacer dm-menu-spacer--${l}`,r.setAttribute("aria-hidden","true"),u.insertBefore(r,i[d]||null);continue}d++}}const w=n(b.items||[]);p.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(i=>{const d=w[parseInt(i.dataset.index,10)];if(!d)return;const s=i.dataset.subindex!=null,r=s&&Array.isArray(d.items)?d.items[parseInt(i.dataset.subindex,10)]:d;if(!r)return;r.colour&&M(i,r.colour),r.pill&&!s&&B(i,r.pill),P(i,r);const l=N(r.badge);l&&i.appendChild(l),O(r.url,location.pathname)&&(i.classList.add("active"),i.setAttribute("aria-current","page"))})}const C=$("#site-footer");if(C.length){let e=function(r){return String(r??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},c=function(r){return e(r).replace(/'/g,"'")},p=function(r){if(r&&r.type==="separator")return'<li class="footer-sep"><hr></li>';if(r&&r.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md"}" aria-hidden="true"></li>`;const l=c(r.url||"#"),m=e(r.text||""),v=Array.isArray(r.items)&&r.items.length?`<ul>${r.items.map(p).join("")}</ul>`:"",L=V(r),I=[L.hover&&` data-menu-item-hover="${c(L.hover)}"`,L.active&&` data-menu-item-active="${c(L.active)}"`].filter(Boolean).join(""),x=L.accent?` style="--dm-menu-highlight:${c(L.accent)}"`:"";return`<li><a href="${l}"${I}${x}>${m}</a>${v}</li>`},y=function(r,l){return(r||[]).forEach(m=>{m&&(m.type==="separator"||m.type==="spacer")||(l.push(m),Array.isArray(m.items)&&m.items.length&&y(m.items,l))}),l};const a=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 o='<div class="footer-inner container">';const n=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(n.copyright&&(o+=`<p>${e(n.copyright)}</p>`),n.primary.length&&(o+=`<nav class="footer-nav footer-nav--primary"><ul>${n.primary.map(p).join("")}</ul></nav>`),n.legal.length&&(o+=`<nav class="footer-nav footer-nav--legal"><ul>${n.legal.map(p).join("")}</ul></nav>`),g.footer){const r=Object.keys(t).filter(l=>a[l]);r.length&&(o+='<div class="footer-social">',r.forEach(l=>{const{label:m,svg:v}=t[l];o+=`<a href="${a[l]}" target="_blank" rel="noopener noreferrer" aria-label="${m}" class="footer-social-link">${v}</a>`}),o+="</div>")}o+="</div>",C.html(o);const h=[...y(n.primary,[]),...y(n.legal,[])];C.get(0).querySelectorAll(".footer-nav a").forEach((r,l)=>{const m=h[l];if(!m)return;m.colour&&M(r,m.colour);const v=N(m.badge);v&&r.appendChild(v),O(m.url,location.pathname)&&(r.classList.add("is-active"),r.setAttribute("aria-current","page"))}),z(C.get(0).querySelector(".footer-nav--primary"),{highlight:n.primaryHighlight}),z(C.get(0).querySelector(".footer-nav--legal"),{highlight:n.legalHighlight});const w=g.footer?.showMotionToggle!==!1,i=S.get("reduced_motion"),d=i!==null?!!i:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),s=C.get(0).querySelector(".footer-inner");if(w&&s){const r=document.createElement("input");r.type="checkbox",r.className="form-switch-input",r.id="dm-motion-switch",r.checked=d,r.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 m=document.createElement("label");m.className="form-switch footer-motion-switch",m.title="Reduce motion",m.appendChild(r),m.appendChild(l),s.appendChild(m)}}$("#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};this.dataset.to&&(a.targetDate=new Date(this.dataset.to)),this.dataset.duration&&(a.duration=parseInt(this.dataset.duration,10)),this.dataset.format&&(a.format=this.dataset.format),Domma.elements.timer(this,a)}),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(n=>{const e={title:n.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:n.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return n.dataset.date&&(e.date=n.dataset.date),n.dataset.status&&(e.status=n.dataset.status),n.dataset.entryId&&(e._entryId=n.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",o=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:o,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",o=a.dataset.revealAnimation||"slide-up",n=parseInt(a.dataset.revealDuration,10)||400,e=parseInt(a.dataset.revealStagger,10)||60,c=parseInt(a.dataset.revealDelay,10)||0,p=a.dataset.revealDirection==="rtl",y=Array.from(a.children),h={"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((u,w)=>{u.style.opacity="0",u.style.transform=h[o]||"",u.style.transition=`opacity ${n}ms ease, transform ${n}ms ease`;const i=p?y.length-1-w:w;u.style.transitionDelay=t==="stagger"?`${c+i*e}ms`:`${c}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const u=new IntersectionObserver(w=>{w.forEach(i=>{i.isIntersecting&&(i.target.offsetWidth,i.target.style.opacity="1",i.target.style.transform="none",u.unobserve(i.target))})},{threshold:.1});y.forEach(w=>u.observe(w))}))}),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 o=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",o.setContent(t),o.open()})})}if(typeof $.setup=="function"){const a=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const o=atob(t.dataset.config),n=JSON.parse(o);Object.assign(a,n)}catch{}}),Object.keys(a).length>0){const t={};for(const[o,n]of Object.entries(a)){const e=n?.events?.click,{confirm:c,toast:p,alert:y,prompt:h,...u}=e||{};c||p||y||h?($(o).on("click",async function(i){if(i.preventDefault(),c&&!await E.confirm(c))return;let d=null;if(!(h&&(d=await E.prompt(h,{inputPlaceholder:u.promptPlaceholder||"",inputValue:u.promptDefault||""}),d===null))){if(u.target){const s=$(u.target);u.toggleClass&&s.toggleClass(u.toggleClass),u.addClass&&s.addClass(u.addClass),u.removeClass&&s.removeClass(u.removeClass),d!==null&&(u.setText&&s.text(d),u.setVal&&s.val(d),u.setAttr&&s.attr(u.setAttr,d))}u.href&&(window.location.href=u.href),p&&E.toast(p,{type:u.toastType||"success"}),y&&E.alert(y)}}),Object.keys(u).length&&(t[o]={...n,events:{...n.events,click:u}})):t[o]=n}$.setup(t)}}f.length&&D(f.get(0))});function D(b){b.querySelectorAll(".dm-cta-trigger").forEach(g=>{g.__ctaWired||(g.__ctaWired=!0,g.addEventListener("click",async()=>{const k=g.dataset.action,C=g.dataset.entry,_=g.dataset.confirm;let f=S.get("auth_token");if(!f){E.toast("Please log in to perform this action.",{type:"warning"});return}if(_&&!await E.confirm(_))return;const a=Array.from(g.childNodes).map(o=>o.cloneNode(!0));g.disabled=!0,g.textContent="Running\u2026";const t=o=>fetch(`/api/actions/${k}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({entryId:C})});try{let o=await t(f);if(o.status===401){const e=S.get("auth_refresh_token");if(e){const c=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(c.ok){const{token:p}=await c.json();S.set("auth_token",p),f=p,o=await t(f)}}}const n=await o.json().catch(()=>({}));if(!o.ok)throw new Error(n.error||n.message||`Error ${o.status}`);E.toast(n.message||"Action completed.",{type:"success"})}catch(o){E.toast(o.message||"Action failed.",{type:"error"})}finally{g.disabled=!1,g.textContent="",a.forEach(o=>g.appendChild(o)),Domma.icons.scan(g)}}))})}(function(){const g=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!g.length)return;const k=S.get("auth_token");function C(f,a){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const o=document.createElement("p");if(a){o.appendChild(document.createTextNode("Please "));const n=document.createElement("a");n.href="/login",n.textContent="sign in",o.appendChild(n),o.appendChild(document.createTextNode(" to view your entries."))}else o.textContent=f;return t.appendChild(o),t}function _(f,a){const t=document.createElement("template");t.innerHTML=a||"",f.replaceWith(t.content)}g.forEach(async f=>{const a=f.dataset.collectionAttrs;if(!a)return;if(!k){f.replaceChildren(C("",!0));return}const t=o=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({attrs:a})});try{let o=k,n=await t(o);if(n.status===401){const c=S.get("auth_refresh_token");if(c){const p=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:c})});if(p.ok){const{token:y}=await p.json();S.set("auth_token",y),o=y,n=await t(o)}}}if(!n.ok){const{error:c}=await n.json().catch(()=>({}));f.replaceChildren(C(c||"Unable to load entries.",!1));return}const{html:e}=await n.json();_(f,e)}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(k=>{let C;try{C=JSON.parse(atob(k.dataset.payload))}catch{return}const{columns:_,rows:f,search:a,sortable:t,exportable:o,pageSize:n,empty:e,ctaConfig:c,slug:p,exportCfg:y}=C;if(!_?.length)return;if(c){const w=_.findIndex(i=>i.key==="_cta");w!==-1&&(_[w]={key:"_cta",title:"",render:(i,d)=>{const s=document.createElement("button");if(s.className=`btn btn-${c.style||"primary"} dm-cta-trigger`,s.dataset.action=c.action||"",s.dataset.entry=d._entryId||"",c.confirm&&(s.dataset.confirm=c.confirm),c.icon){const r=document.createElement("span");r.dataset.icon=c.icon,s.appendChild(r),s.appendChild(document.createTextNode(" "))}return s.appendChild(document.createTextNode(c.label||"Run")),s}})}const h="col-table-"+Math.random().toString(36).slice(2,7),u=document.createElement("div");u.id=h,k.replaceChildren(u),T.create("#"+h,{data:f,columns:_,search:a,sortable:t,exportable:o,pageSize:n,emptyMessage:e}),c&&D(u),k._dmTable={columns:_,rows:f,slug:p,exportCfg:y,render(w){T.create("#"+h,{data:w,columns:_,search:a,sortable:t,exportable:o,pageSize:n,emptyMessage:e}),c&&D(u)}}})})(),(function(){const g=document.querySelectorAll("[data-form-inline]");if(!g.length||typeof F>"u")return;function k(t){const o=t&&t.logic;return!!(o&&(o.visibility||o.requirement))}function C(t,o){const n={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const c=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":c?"chooser":e.type,y={...e.formConfig||{}};y.span==="full"&&o&&(y.span=o);const h={type:p,required:k(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...y}};c&&(e.variant&&(h.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(h.multiple=!0),e.density&&(h.density=e.density),e.columns&&(h.columns=e.columns),e.accent&&(h.accent=e.accent),e.accentStyle&&(h.accentStyle=e.accentStyle),e.glow&&(h.glow=!0),e.glowColour&&(h.glowColour=e.glowColour),e.shadow&&(h.shadow=e.shadow),e.shadowColour&&(h.shadowColour=e.shadowColour)),n[e.name]=h}),n}function _(t){const o={};return(t||[]).forEach(n=>{if(!(!n.name||n.type==="page-break"||n.type==="spacer")&&(n.type==="select"||n.type==="multiselect")&&n.required){const e=(n.options||[])[0];e&&(o[n.name]=typeof e=="object"?e.value:e)}}),o}function f(t,o){(o||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const e=t.querySelector(`[name="${n.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function a(t,o,n){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=o,e.style.cssText=n?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}g.forEach(t=>{let o;try{o=JSON.parse(atob(t.dataset.formInline))}catch{return}const n=o.fields||[],e=o.settings||{},c=Number(e.columns)===3?3:2,p=e.layout||"grid",y=n.some(d=>d.type==="page-break"),h=async d=>{if(t.dataset.triggerBlocked==="true"){const s=t._formLogicRuntime,r=s&&s.submitBlock?s.submitBlock().reasons:[];a(t,r.join(" ")||"This form cannot be submitted yet.",!0);const l=new Error("Blocked by a form trigger");throw l.formSubmitFailed=!0,l}try{const s=t.querySelector(".fb-form-honeypot"),r=s?.querySelector('input[type="text"]')||null,l=s?.querySelector('[name="_t"]')||null,m=Object.assign({},d);delete m._t,s?.dataset.hpName&&delete m[s.dataset.hpName],r!==null&&(m._hp=r.value),l!==null&&(m._t=l.value);const v=await H.post(`/api/forms/submit/${o.slug}`,m);if(v&&v.error){a(t,v.error,!0);const L=new Error(v.error);throw L.formSubmitFailed=!0,L}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(s){throw s.formSubmitFailed||a(t,s.message||"Submission failed. Please try again.",!0),s}},u=Date.now();function w(d){const s=d.querySelector("form");if(!s||s.querySelector(".fb-form-honeypot"))return;const r=document.createElement("div");r.className="fb-form-honeypot",r.setAttribute("aria-hidden","true");const l=document.createElement("input");l.name=s.querySelector('[name="website"]')?"_website":"website",r.dataset.hpName=l.name,l.type="text",l.tabIndex=-1,l.autocomplete="url",l.placeholder="https://",r.appendChild(l);const m=document.createElement("input");m.name="_t",m.type="hidden",m.value=u,r.appendChild(m),s.appendChild(r)}function i(d){if(!window.FormLogicEngine||!n.some(r=>r.logic||Array.isArray(r.triggers)&&r.triggers.length))return null;const s=new window.FormLogicEngine.FormLogicRuntime(o,t,d?{baseValues:d}:void 0);if(s.init(),t._formLogicRuntime=s,t._formLogicObserved)return s;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const r=new MutationObserver(function(l){for(const m of l)for(const v of m.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),r.disconnect();return}});r.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=r}return s}if(y&&F.wizard){const d=Y(n,o.title),s=d.map(x=>({title:x.title,description:x.description,fields:C(x.fields,c)})),r=d.map(x=>x.fields);let l=0,m=null,v=null;const L=x=>{const A=window.FormLogicEngine;if(!A||!A.validateFields)return;const q=A.validateFields(t,r[l]||[]);q.valid||(x.preventDefault(),x.stopImmediatePropagation(),G(t,q.missing),X(q))},I=()=>{const x=r[l]||n;f(t,x),j(t,x),e.honeypot!==!1&&w(t),m&&m.destroy(),m=i(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(A=>A.addEventListener("click",L,!0))};v=F.wizard(t,{schema:{steps:s},layout:p,columns:c,finishText:e.submitText||"Finish",onSubmit:h,onStepChange:x=>{l=x,setTimeout(I,0)}}),t.addEventListener("dm-form-trigger",x=>{if(x.detail?.type!=="goto-step"||!v?.goToStep)return;const A=Number(x.detail.action.step);!Number.isFinite(A)||A<0||A>=s.length||A!==l&&v.goToStep(A)}),Promise.resolve(v).then(I)}else if(F.render){const d=F.render(t,C(n,c),_(n),{submitText:e.submitText||"Submit",layout:p,columns:c,onSubmit:h});Promise.resolve(d).then(function(){if(p==="grid"&&e.submitSpan==="full"){const s=t.querySelector(".form-buttons");s&&s.classList.add("col-span-full")}f(t,n),j(t,n),e.honeypot!==!1&&w(t),i()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
1
|
+
import{makeBadgeEl as M,applyColour as O,applyPill as V,applyFloat as J,applyHighlight as N,applyItemHighlight as W,itemHighlightAttrs as G,isCurrentItem as j,menuAlign as X}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 B,markInvalidFields as R,showValidationPopup as P}from"/public/js/forms.js?v=20260926-form-end";import{buildWizardSteps as U}from"/public/js/form-steps.mjs";$(()=>{const w=window.__CMS_NAV__||{},g=window.__CMS_SITE__||{};if(g.autoTheme?.enabled){let e=function(t){const c=(t||"07:00").split(":");return+c[0]*60+(+c[1]||0)},n=function(){const t=new Date,c=t.getHours()*60+t.getMinutes();return c>=e(o.dayStart)&&c<e(o.nightStart)?o.dayTheme:o.nightTheme},r=function(t){const c=o.apply&&o.apply[t]||{theme:t,custom:""};Domma.theme.set(c.theme);for(const u of[...document.body.classList])u.startsWith("dm-custom-")&&document.body.classList.remove(u);c.custom&&document.body.classList.add(c.custom)};const o=g.autoTheme;r(n()),setInterval(()=>r(n()),6e4)}const _=$("#site-navbar");if(_.length&&w.brand){let n=function(i,h=0){return Array.isArray(i)?i.filter(s=>!(s&&s.type==="spacer")).filter(s=>!(s&&s.type==="separator"&&h===0)).map(s=>s&&s.type==="separator"?{divider:!0}:Array.isArray(s?.items)?{...s,items:n(s.items,h+1)}:s):i},r=function(i){return Array.isArray(i)?i.filter(h=>!(h&&(h.type==="separator"||h.type==="spacer"))):[]};const o={...w.brand},e=o.size&&o.size!=="md"?` navbar-brand-${o.size}`:"";if(o.logo||o.icon||o.tagline){let i="";o.logo?i+=`<img src="${o.logo}" class="navbar-brand-logo" alt="${o.text||""}">`:o.icon&&(i+=`<span data-icon="${o.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),o.text&&(i+=`<span class="navbar-brand-text${e}">${o.text}</span>`),o.tagline&&(i+=`<small class="navbar-brand-tagline">${o.tagline}</small>`),o.html=i}else e&&o.text&&(o.html=`<span class="navbar-brand-text${e}">${o.text}</span>`);const t=w.position==="floating",c=w.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:o,items:n(w.items||[]),variant:w.variant||"dark",position:t?"static":w.position||"sticky",collapsible:!0,appearOnHover:!!w.appearOnHover}),Domma.icons.scan("#site-navbar");const u=_.get(0);u.classList.add(`dm-nav-align-${X(w)||"centre"}`),c&&_.get(0).classList.add("dm-nav-vertical",w.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),N(u,w),t&&(J(_.get(0),w),Y(_.get(0).parentNode||document));const y=u.querySelector(".navbar-toggle"),p=u.querySelector(".navbar-collapse");if(y&&p){let i=null;const h=()=>{p.classList.contains("show")&&y.click()},s=()=>{i&&(i.remove(),i=null),document.body.classList.remove("dm-drawer-open")},a=()=>{i||(i=document.createElement("div"),i.className="dm-navbar-backdrop",i.addEventListener("click",h),document.body.appendChild(i),document.body.classList.add("dm-drawer-open"))};y.addEventListener("click",()=>{requestAnimationFrame(()=>{p.classList.contains("show")?a():s()})}),p.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(s)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&p.classList.contains("show")&&h()})}const m=u.querySelector(".navbar-nav");if(m){const i=Array.from(m.children);let h=0;for(const s of w.items||[])if(!(s&&s.type==="separator")){if(s&&s.type==="spacer"){const a=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(s.size)?s.size:"md";a.className=`dm-menu-spacer dm-menu-spacer--${l}`,a.setAttribute("aria-hidden","true"),m.insertBefore(a,i[h]||null);continue}h++}}const C=r(w.items||[]);u.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(i=>{const h=C[parseInt(i.dataset.index,10)];if(!h)return;const s=i.dataset.subindex!=null,a=s&&Array.isArray(h.items)?h.items[parseInt(i.dataset.subindex,10)]:h;if(!a)return;a.colour&&O(i,a.colour),a.pill&&!s&&V(i,a.pill),W(i,a);const l=M(a.badge);l&&i.appendChild(l),j(a.url,location.pathname)&&(i.classList.add("active"),i.setAttribute("aria-current","page"))})}const x=$("#site-footer");if(x.length){let t=function(a){return String(a??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},c=function(a){return t(a).replace(/'/g,"'")},u=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=c(a.url||"#"),d=t(a.text||""),b=Array.isArray(a.items)&&a.items.length?`<ul>${a.items.map(u).join("")}</ul>`:"",v=G(a),I=[v.hover&&` data-menu-item-hover="${c(v.hover)}"`,v.active&&` data-menu-item-active="${c(v.active)}"`].filter(Boolean).join(""),D=v.accent?` style="--dm-menu-highlight:${c(v.accent)}"`:"";return`<li><a href="${l}"${I}${D}>${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||{},e={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 r=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(r.copyright&&(n+=`<p>${t(r.copyright)}</p>`),r.primary.length&&(n+=`<nav class="footer-nav footer-nav--primary"><ul>${r.primary.map(u).join("")}</ul></nav>`),r.legal.length&&(n+=`<nav class="footer-nav footer-nav--legal"><ul>${r.legal.map(u).join("")}</ul></nav>`),g.footer){const a=Object.keys(e).filter(l=>o[l]);a.length&&(n+='<div class="footer-social">',a.forEach(l=>{const{label:d,svg:b}=e[l];n+=`<a href="${o[l]}" target="_blank" rel="noopener noreferrer" aria-label="${d}" class="footer-social-link">${b}</a>`}),n+="</div>")}n+="</div>",x.html(n);const p=[...y(r.primary,[]),...y(r.legal,[])];x.get(0).querySelectorAll(".footer-nav a").forEach((a,l)=>{const d=p[l];if(!d)return;d.colour&&O(a,d.colour);const b=M(d.badge);b&&a.appendChild(b),j(d.url,location.pathname)&&(a.classList.add("is-active"),a.setAttribute("aria-current","page"))}),N(x.get(0).querySelector(".footer-nav--primary"),{highlight:r.primaryHighlight}),N(x.get(0).querySelector(".footer-nav--legal"),{highlight:r.legalHighlight});const C=g.footer?.showMotionToggle!==!1,i=S.get("reduced_motion"),h=i!==null?!!i:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),s=x.get(0).querySelector(".footer-inner");if(C&&s){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),s.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 e=parseInt(this.dataset.animationDuration,10);Number.isFinite(e)&&(o.animationDuration=e)}this.dataset.animationEasing&&(o.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(e=>e.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(r=>{const t={title:r.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:r.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return r.dataset.date&&(t.date=r.dataset.date),r.dataset.status&&(t.status=r.dataset.status),r.dataset.entryId&&(t._entryId=r.dataset.entryId),t}),e=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",n=Domma.elements.progression(this,{layout:e,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 e=o.dataset.revealMode||"stagger",n=o.dataset.revealAnimation||"slide-up",r=parseInt(o.dataset.revealDuration,10)||400,t=parseInt(o.dataset.revealStagger,10)||60,c=parseInt(o.dataset.revealDelay,10)||0,u=o.dataset.revealDirection==="rtl",y=Array.from(o.children),p={"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,C)=>{m.style.opacity="0",m.style.transform=p[n]||"",m.style.transition=`opacity ${r}ms ease, transform ${r}ms ease`;const i=u?y.length-1-C:C;m.style.transitionDelay=e==="stagger"?`${c+i*t}ms`:`${c}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(C=>{C.forEach(i=>{i.isIntersecting&&(i.target.offsetWidth,i.target.style.opacity="1",i.target.style.transform="none",m.unobserve(i.target))})},{threshold:.1});y.forEach(C=>m.observe(C))}))}),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,e=document.getElementById(o);if(!e)return;const n=E.slideover({title:e.dataset.soTitle||"",size:e.dataset.soSize||"md",position:e.dataset.soPosition||"right"});e.style.display="",n.setContent(e),n.open()})})}if(typeof $.setup=="function"){const o=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(e=>{try{const n=atob(e.dataset.config),r=JSON.parse(n);Object.assign(o,r)}catch{}}),Object.keys(o).length>0){const e={};for(const[n,r]of Object.entries(o)){const t=r?.events?.click,{confirm:c,toast:u,alert:y,prompt:p,...m}=t||{};c||u||y||p?($(n).on("click",async function(i){if(i.preventDefault(),c&&!await E.confirm(c))return;let h=null;if(!(p&&(h=await E.prompt(p,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),h===null))){if(m.target){const s=$(m.target);m.toggleClass&&s.toggleClass(m.toggleClass),m.addClass&&s.addClass(m.addClass),m.removeClass&&s.removeClass(m.removeClass),h!==null&&(m.setText&&s.text(h),m.setVal&&s.val(h),m.setAttr&&s.attr(m.setAttr,h))}m.href&&(window.location.href=m.href),u&&E.toast(u,{type:m.toastType||"success"}),y&&E.alert(y)}}),Object.keys(m).length&&(e[n]={...r,events:{...r.events,click:m}})):e[n]=r}$.setup(e)}}f.length&&q(f.get(0))});function q(w){w.querySelectorAll(".dm-cta-trigger").forEach(g=>{g.__ctaWired||(g.__ctaWired=!0,g.addEventListener("click",async()=>{const _=g.dataset.action,x=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 e=n=>fetch(`/api/actions/${_}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({entryId:x})});try{let n=await e(f);if(n.status===401){const t=S.get("auth_refresh_token");if(t){const c=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:t})});if(c.ok){const{token:u}=await c.json();S.set("auth_token",u),f=u,n=await e(f)}}}const r=await n.json().catch(()=>({}));if(!n.ok)throw new Error(r.error||r.message||`Error ${n.status}`);E.toast(r.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 x(f,o){const e=document.createElement("div");e.className="dm-collection-display dm-collection-empty";const n=document.createElement("p");if(o){n.appendChild(document.createTextNode("Please "));const r=document.createElement("a");r.href="/login",r.textContent="sign in",n.appendChild(r),n.appendChild(document.createTextNode(" to view your entries."))}else n.textContent=f;return e.appendChild(n),e}function A(f,o){const e=document.createElement("template");e.innerHTML=o||"",f.replaceWith(e.content)}g.forEach(async f=>{const o=f.dataset.collectionAttrs;if(!o)return;if(!_){f.replaceChildren(x("",!0));return}const e=n=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify({attrs:o})});try{let n=_,r=await e(n);if(r.status===401){const c=S.get("auth_refresh_token");if(c){const u=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:c})});if(u.ok){const{token:y}=await u.json();S.set("auth_token",y),n=y,r=await e(n)}}}if(!r.ok){const{error:c}=await r.json().catch(()=>({}));f.replaceChildren(x(c||"Unable to load entries.",!1));return}const{html:t}=await r.json();A(f,t)}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(),q(document.body)},100)})(),(function(){const g=document.querySelectorAll("[data-collection-table]");!g.length||typeof T>"u"||!T.create||g.forEach(_=>{let x;try{x=JSON.parse(atob(_.dataset.payload))}catch{return}const{columns:A,rows:f,search:o,sortable:e,exportable:n,pageSize:r,empty:t,ctaConfig:c,slug:u,exportCfg:y}=x;if(!A?.length)return;if(c){const C=A.findIndex(i=>i.key==="_cta");C!==-1&&(A[C]={key:"_cta",title:"",render:(i,h)=>{const s=document.createElement("button");if(s.className=`btn btn-${c.style||"primary"} dm-cta-trigger`,s.dataset.action=c.action||"",s.dataset.entry=h._entryId||"",c.confirm&&(s.dataset.confirm=c.confirm),c.icon){const a=document.createElement("span");a.dataset.icon=c.icon,s.appendChild(a),s.appendChild(document.createTextNode(" "))}return s.appendChild(document.createTextNode(c.label||"Run")),s}})}const p="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=p,_.replaceChildren(m),T.create("#"+p,{data:f,columns:A,search:o,sortable:e,exportable:n,pageSize:r,emptyMessage:t}),c&&q(m),_._dmTable={columns:A,rows:f,slug:u,exportCfg:y,render(C){T.create("#"+p,{data:C,columns:A,search:o,sortable:e,exportable:n,pageSize:r,emptyMessage:t}),c&&q(m)}}})})(),(function(){const g=document.querySelectorAll("[data-form-inline]");if(!g.length||typeof F>"u")return;function _(e){const n=e&&e.logic;return!!(n&&(n.visibility||n.requirement))}function x(e,n){const r={};return(e||[]).forEach(t=>{if(t.type==="page-break"||t.type==="spacer"||!t.name)return;const c=t.type==="chooser"||!!(t.variant&&["select","radio","checkbox-group"].includes(t.type)),u=t.type==="checkbox"?"boolean":t.type==="date"||t.type==="icon"||t.type==="image"?"string":c?"chooser":t.type,y={...t.formConfig||{}};y.span==="full"&&n&&(y.span=n);const p={type:u,required:_(t)?!1:t.required,label:t.label,options:t.options,formConfig:{...t.placeholder&&{placeholder:t.placeholder},...t.helper&&{hint:t.helper},...y}};c&&(t.variant&&(p.variant=t.variant),(t.multiple||t.type==="checkbox-group")&&(p.multiple=!0),t.density&&(p.density=t.density),t.columns&&(p.columns=t.columns),t.accent&&(p.accent=t.accent),t.accentStyle&&(p.accentStyle=t.accentStyle),t.glow&&(p.glow=!0),t.glowColour&&(p.glowColour=t.glowColour),t.shadow&&(p.shadow=t.shadow),t.shadowColour&&(p.shadowColour=t.shadowColour)),r[t.name]=p}),r}function A(e){const n={};return(e||[]).forEach(r=>{if(!(!r.name||r.type==="page-break"||r.type==="spacer")&&(r.type==="select"||r.type==="multiselect")&&r.required){const t=(r.options||[])[0];t&&(n[r.name]=typeof t=="object"?t.value:t)}}),n}function f(e,n){(n||[]).forEach(r=>{if(r.type!=="date"||!r.name)return;const t=e.querySelector(`[name="${r.name}"]`);t&&t.type!=="date"&&(t.type="date")})}function o(e,n,r){let t=e.querySelector(".cms-form-message");t||(t=document.createElement("p"),t.className="cms-form-message",e.appendChild(t)),t.textContent=n,t.style.cssText=r?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}g.forEach(e=>{let n;try{n=JSON.parse(atob(e.dataset.formInline))}catch{return}const r=n.fields||[],t=n.settings||{},c=Number(t.columns)===3?3:2,u=t.layout||"grid",y=r.some(s=>s.type==="page-break"),p=async s=>{if(e.dataset.triggerBlocked==="true"){const a=e._formLogicRuntime,l=a&&a.submitBlock?a.submitBlock().reasons:[];o(e,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=e.querySelector(".fb-form-honeypot"),l=a?.querySelector('input[type="text"]')||null,d=a?.querySelector('[name="_t"]')||null,b=Object.assign({},s);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(e,v.error,!0);const I=new Error(v.error);throw I.formSubmitFailed=!0,I}if(v?.redirect){window.location.href=v.redirect;return}for(;e.firstChild;)e.removeChild(e.firstChild);o(e,v?.message||t.successMessage||"Thank you for your submission.",!1)}catch(a){throw a.formSubmitFailed||o(e,a.message||"Submission failed. Please try again.",!0),a}},m=Date.now();function C(s){const a=s.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 i(s){if(!window.FormLogicEngine||!r.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const a=new window.FormLogicEngine.FormLogicRuntime(n,e,s?{baseValues:s}:void 0);if(a.init(),e._formLogicRuntime=a,e._formLogicObserved)return a;if(e._formLogicObserved=!0,e.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(d){for(const b of d)for(const v of b.removedNodes)if(v===e||v.nodeType===1&&v.contains&&v.contains(e)){e._formLogicRuntime&&e._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(e.parentNode,{childList:!0,subtree:!1}),e._formLogicObserver=l}return a}let h=!1;if(e.addEventListener("dm-form-end",s=>{const a=s.detail?.validation;if(a&&!a.valid){R(e,a.missing),P(a);return}h||(h=!0,p(s.detail?.values||{}).catch(()=>{}).finally(()=>{h=!1}))}),y&&F.wizard){const s=U(r,n.title),a=s.map(k=>({title:k.title,description:k.description,fields:x(k.fields,c)})),l=s.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(e,l[d]||[]);z.valid||(k.preventDefault(),k.stopImmediatePropagation(),R(e,z.missing),P(z))},D=()=>{const k=l[d]||r;f(e,k),B(e,k),t.honeypot!==!1&&C(e),b&&b.destroy(),b=i(v?.getStepData?v.getStepData():void 0),e.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",I,!0))};v=F.wizard(e,{schema:{steps:a},layout:u,columns:c,finishText:t.submitText||"Finish",onSubmit:p,onStepChange:k=>{d=k,setTimeout(D,0)}}),e.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(D)}else if(F.render){const s=F.render(e,x(r,c),A(r),{submitText:t.submitText||"Submit",layout:u,columns:c,onSubmit:p});Promise.resolve(s).then(function(){if(u==="grid"&&t.submitSpan==="full"){const a=e.querySelector(".form-buttons");a&&a.classList.add("col-span-full")}f(e,r),B(e,r),t.honeypot!==!1&&C(e),i()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
@@ -25,7 +25,7 @@ import path from 'path';
|
|
|
25
25
|
import {deleteForm, ensureCollectionForForm, ensureFormsDir, listForms, readForm, slugify, writeForm} from '../../services/forms.js';
|
|
26
26
|
import {executeAction} from '../../services/actions.js';
|
|
27
27
|
import {createTransport, sendFormEmail} from '../../services/email.js';
|
|
28
|
-
import {formActionFailed} from '../../services/notification-sources.js';
|
|
28
|
+
import {formActionFailed, formTriggerNotice} from '../../services/notification-sources.js';
|
|
29
29
|
import {
|
|
30
30
|
clearEntries,
|
|
31
31
|
createCollection,
|
|
@@ -798,9 +798,15 @@ export async function formsRoutes(fastify) {
|
|
|
798
798
|
// Hidden and disabled are the same thing to a submission: the visitor
|
|
799
799
|
// was given no way to answer, so the answer is not theirs and is not
|
|
800
800
|
// required. A value posted for one anyway is dropped below.
|
|
801
|
-
const triggerOff = new Set([...triggerState.hidden, ...triggerState.disabled]);
|
|
801
|
+
const triggerOff = new Set([...triggerState.hidden, ...triggerState.disabled, ...triggerState.masked]);
|
|
802
802
|
const triggerRequired = new Set(triggerState.required);
|
|
803
803
|
|
|
804
|
+
// An end-form in force: the answers so far ARE the submission, and the
|
|
805
|
+
// masked rest is neither asked for nor kept. `record: false` keeps
|
|
806
|
+
// nothing at all - the trigger's notification is the only trace.
|
|
807
|
+
const ended = triggerState.ends[0] || null;
|
|
808
|
+
const record = !ended || ended.record;
|
|
809
|
+
|
|
804
810
|
// Evaluate conditional logic
|
|
805
811
|
const missingFields = [];
|
|
806
812
|
const validationErrors = [];
|
|
@@ -842,9 +848,13 @@ export async function formsRoutes(fastify) {
|
|
|
842
848
|
|
|
843
849
|
// Build submission data - only include visible fields
|
|
844
850
|
const data = {};
|
|
851
|
+
const excused = [];
|
|
845
852
|
for (const field of form.fields || []) {
|
|
846
853
|
if (field.type === 'page-break' || field.type === 'spacer') continue;
|
|
847
|
-
|
|
854
|
+
// The collection mirrors the form's static `required`, so a field
|
|
855
|
+
// the form excused (hidden, disabled, masked) would still be
|
|
856
|
+
// refused there - the form's own pass above is the one that knows.
|
|
857
|
+
if (!visibleFieldNames.has(field.name)) { excused.push(field.name); continue; }
|
|
848
858
|
const val = body[field.name];
|
|
849
859
|
if (val !== undefined) {
|
|
850
860
|
data[field.name] = typeof val === 'string' ? val.trim() : val;
|
|
@@ -863,7 +873,8 @@ export async function formsRoutes(fastify) {
|
|
|
863
873
|
const collectionAction = form.actions?.collection;
|
|
864
874
|
const targetSlug = (collectionAction?.enabled && collectionAction.slug) ? collectionAction.slug : slug;
|
|
865
875
|
let entry = null;
|
|
866
|
-
|
|
876
|
+
// An end-form set not to record stores nothing (see `record` above).
|
|
877
|
+
if (record) try {
|
|
867
878
|
let col = await getCollection(targetSlug);
|
|
868
879
|
if (!col) {
|
|
869
880
|
// The backing collection was never created (a form pointing at a
|
|
@@ -876,7 +887,9 @@ export async function formsRoutes(fastify) {
|
|
|
876
887
|
if (col) {
|
|
877
888
|
entry = await createEntry(targetSlug, data, {
|
|
878
889
|
source: `form:${slug}`,
|
|
879
|
-
createdBy: submittingUser?.id || null
|
|
890
|
+
createdBy: submittingUser?.id || null,
|
|
891
|
+
excused,
|
|
892
|
+
outcome: ended ? {type: 'ended', trigger: ended.key, field: ended.field} : null
|
|
880
893
|
});
|
|
881
894
|
} else {
|
|
882
895
|
// Could not resolve or provision a target - e.g. collection
|
|
@@ -898,9 +911,10 @@ export async function formsRoutes(fastify) {
|
|
|
898
911
|
return reply.status(400).send({ error: msg });
|
|
899
912
|
}
|
|
900
913
|
|
|
901
|
-
// Email action
|
|
914
|
+
// Email action - like the webhook and the form's action, it reports a
|
|
915
|
+
// stored submission, so an unrecorded end has nothing for it to say.
|
|
902
916
|
const emailAction = form.actions?.email;
|
|
903
|
-
if (emailAction?.enabled && emailAction.recipients) {
|
|
917
|
+
if (record && emailAction?.enabled && emailAction.recipients) {
|
|
904
918
|
try {
|
|
905
919
|
const smtp = getConfig('site').smtp || {};
|
|
906
920
|
const transport = await createTransport(smtp);
|
|
@@ -921,7 +935,7 @@ export async function formsRoutes(fastify) {
|
|
|
921
935
|
|
|
922
936
|
// Webhook action
|
|
923
937
|
const webhookAction = form.actions?.webhook;
|
|
924
|
-
if (webhookAction?.enabled && webhookAction.url) {
|
|
938
|
+
if (record && webhookAction?.enabled && webhookAction.url) {
|
|
925
939
|
try {
|
|
926
940
|
await fetch(webhookAction.url, {
|
|
927
941
|
method: webhookAction.method || 'POST',
|
|
@@ -959,6 +973,15 @@ export async function formsRoutes(fastify) {
|
|
|
959
973
|
fastify.log.warn(`[forms] Trigger action "${event.action.slug}" failed for form "${slug}": ${err.message}`);
|
|
960
974
|
formActionFailed(slug, form.title, `action "${event.action.slug}"`, err.message);
|
|
961
975
|
}
|
|
976
|
+
} else if (event.type === 'notify') {
|
|
977
|
+
// Never throws; a switched-off source or the hourly cap just
|
|
978
|
+
// means nothing is raised.
|
|
979
|
+
const owner = (form.fields || []).find(f => f.name === event.field);
|
|
980
|
+
await formTriggerNotice({
|
|
981
|
+
slug, formTitle: form.title, action: event.action,
|
|
982
|
+
field: owner?.label || event.field, answer: formValues[event.field],
|
|
983
|
+
ended: !!ended, recorded: !!entry
|
|
984
|
+
});
|
|
962
985
|
} else if (event.type === 'redirect' && event.action.url && !triggerRedirect) {
|
|
963
986
|
// First one wins - two triggers redirecting at once is an
|
|
964
987
|
// authoring mistake, not a case to resolve cleverly.
|
|
@@ -966,7 +989,9 @@ export async function formsRoutes(fastify) {
|
|
|
966
989
|
}
|
|
967
990
|
}
|
|
968
991
|
|
|
969
|
-
|
|
992
|
+
// An unrecorded end is not a submission anyone keeps, so nothing that
|
|
993
|
+
// listens for submissions (plugins, the "Form submitted" notice) hears it.
|
|
994
|
+
if (record) hooks.emit('form:submitted', {slug, entryId: entry?.id || null, data, formTitle: form.title, ended: !!ended});
|
|
970
995
|
|
|
971
996
|
// Template interpolation for successRedirect. A trigger's redirect is
|
|
972
997
|
// the more specific instruction, so it wins over the form's default.
|
|
@@ -978,7 +1003,8 @@ export async function formsRoutes(fastify) {
|
|
|
978
1003
|
return {
|
|
979
1004
|
ok: true,
|
|
980
1005
|
entryId: entry?.id || null,
|
|
981
|
-
|
|
1006
|
+
ended: !!ended,
|
|
1007
|
+
message: ended?.doneMessage || settings.successMessage || 'Thank you for your submission.',
|
|
982
1008
|
redirect: redirect
|
|
983
1009
|
};
|
|
984
1010
|
});
|
|
@@ -225,6 +225,34 @@ async function executeStep(step, collection, entry, context) {
|
|
|
225
225
|
return { to };
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
/*
|
|
229
|
+
* notify - raise a notification in the admin (the bell, and desktop
|
|
230
|
+
* notifications for those who switched them on). Goes to whoever the
|
|
231
|
+
* "Actions" source is set to reach in Notifications' settings.
|
|
232
|
+
*
|
|
233
|
+
* Config (all template-interpolated):
|
|
234
|
+
* title {string} required
|
|
235
|
+
* body {string} optional
|
|
236
|
+
* severity {string} optional - info | success | warning | critical
|
|
237
|
+
* link {string} optional - an admin route (#/…) or http(s) URL
|
|
238
|
+
*
|
|
239
|
+
* Returns: { raised: boolean } - false when the source is switched off
|
|
240
|
+
* or over its hourly cap, which is not a failure of the action.
|
|
241
|
+
*/
|
|
242
|
+
case 'notify': {
|
|
243
|
+
const title = interpolate(cfg.title || '', context).trim();
|
|
244
|
+
if (!title) throw new Error('notify: title is required');
|
|
245
|
+
const { notify } = await import('./notify.js');
|
|
246
|
+
const raised = await notify({
|
|
247
|
+
source: 'core:actions',
|
|
248
|
+
title,
|
|
249
|
+
body: interpolate(cfg.body || '', context),
|
|
250
|
+
severity: interpolate(cfg.severity || 'info', context).trim(),
|
|
251
|
+
link: interpolate(cfg.link || '', context).trim() || null
|
|
252
|
+
});
|
|
253
|
+
return { raised: !!raised };
|
|
254
|
+
}
|
|
255
|
+
|
|
228
256
|
default:
|
|
229
257
|
throw new Error(`Unknown step type: "${step.type}"`);
|
|
230
258
|
}
|
|
@@ -260,11 +260,15 @@ export async function deleteCollection(slug) {
|
|
|
260
260
|
*
|
|
261
261
|
* @param {object} schema
|
|
262
262
|
* @param {object} data
|
|
263
|
+
* @param {Iterable<string>} [excused] - fields whose `required` does not apply to this
|
|
264
|
+
* write: a form submission the form itself excused from answering them
|
|
263
265
|
* @returns {{ valid: boolean, errors: string[] }}
|
|
264
266
|
*/
|
|
265
|
-
export function validateEntryData(schema, data) {
|
|
267
|
+
export function validateEntryData(schema, data, excused = []) {
|
|
266
268
|
const errors = [];
|
|
269
|
+
const skip = new Set(excused);
|
|
267
270
|
for (const field of (schema.fields || [])) {
|
|
271
|
+
if (skip.has(field.name)) continue;
|
|
268
272
|
const val = data[field.name];
|
|
269
273
|
const isEmpty = val === undefined || val === null || val === '';
|
|
270
274
|
if (field.required && isEmpty) {
|
|
@@ -383,15 +387,17 @@ export async function getEntry(slug, entryId) {
|
|
|
383
387
|
* @param {object} [meta]
|
|
384
388
|
* @param {string} [meta.createdBy]
|
|
385
389
|
* @param {string} [meta.source] - 'admin' | 'api' | 'import' | 'form:{slug}'
|
|
390
|
+
* @param {string[]} [meta.excused] - required fields this write may leave empty (see validateEntryData)
|
|
391
|
+
* @param {object} [meta.outcome] - how a form submission ended, stored as meta.outcome
|
|
386
392
|
* @returns {Promise<object>} Created entry
|
|
387
393
|
* @throws {Error} If validation fails or collection not found
|
|
388
394
|
*/
|
|
389
|
-
export async function createEntry(slug, data, { createdBy = null, source = 'admin' } = {}) {
|
|
395
|
+
export async function createEntry(slug, data, { createdBy = null, source = 'admin', excused = [], outcome = null } = {}) {
|
|
390
396
|
const schema = await getCollection(slug);
|
|
391
397
|
if (!schema) throw new Error(`Collection "${slug}" not found`);
|
|
392
398
|
data = typedEntryData(schema, data);
|
|
393
399
|
|
|
394
|
-
const { valid, errors } = validateEntryData(schema, data);
|
|
400
|
+
const { valid, errors } = validateEntryData(schema, data, excused);
|
|
395
401
|
if (!valid) throw new Error(`Validation failed: ${errors.join('; ')}`);
|
|
396
402
|
|
|
397
403
|
const refErrors = await validateReferences(schema, data);
|
|
@@ -401,7 +407,7 @@ export async function createEntry(slug, data, { createdBy = null, source = 'admi
|
|
|
401
407
|
const entry = {
|
|
402
408
|
id: uuidv4(),
|
|
403
409
|
data,
|
|
404
|
-
meta: { createdAt: now, updatedAt: now, createdBy, source }
|
|
410
|
+
meta: { createdAt: now, updatedAt: now, createdBy, source, ...(outcome && {outcome}) }
|
|
405
411
|
};
|
|
406
412
|
|
|
407
413
|
const adapter = await getAdapter(slug);
|