domma-cms 0.118.0 → 0.119.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/js/templates/docs/api-forms.html +5 -0
- package/admin/js/templates/form-editor.html +11 -0
- package/admin/js/views/form-editor.js +7 -7
- package/package.json +1 -1
- package/public/js/css-classes.mjs +1 -0
- package/public/js/form-submit.mjs +1 -1
- package/public/js/forms.js +2 -2
- package/public/js/menu-decor.mjs +1 -1
- package/public/js/site.js +1 -1
- package/server/routes/api/forms.js +3 -3
- package/server/services/forms.js +2 -2
- package/server/templates/page.html +2 -2
|
@@ -143,6 +143,11 @@
|
|
|
143
143
|
<code>url</code> must be a path, <code>#anchor</code>, <code>?query</code> or an <code>http(s):</code>,
|
|
144
144
|
<code>mailto:</code> or <code>tel:</code> address - create and update answer <code>400</code> otherwise. Leave
|
|
145
145
|
either key out for the default button.</p>
|
|
146
|
+
<p>Designer classes (optional): <code>settings.class</code> goes on the <code><form></code>,
|
|
147
|
+
<code>settings.submitClass</code> on the submit button (and Finish on a multi-step form), and a field's own
|
|
148
|
+
<code>class</code> on its wrapper (<code>[data-field="name"]</code>). Each is CSS class names separated by spaces -
|
|
149
|
+
letters, digits, hyphens and underscores, not starting with a digit; create and update answer <code>400</code>
|
|
150
|
+
otherwise.</p>
|
|
146
151
|
<p>The create and update responses carry a <code>warnings</code> array when the form and its target collection
|
|
147
152
|
disagree - the collection is missing, requires a field the form does not collect, or lacks a field the form
|
|
148
153
|
sends. Saving still succeeds.</p>
|
|
@@ -149,6 +149,11 @@
|
|
|
149
149
|
</select>
|
|
150
150
|
<p class="form-hint text-muted" style="margin-top:.3rem;font-size:.8rem;">A grid form lays out in two
|
|
151
151
|
or three columns. Use a field's Column Span to make one field wider than the rest.</p>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="mb-3" style="margin-top:1rem">
|
|
154
|
+
<label class="form-label" for="setting-form-class">CSS classes <span data-help-title="CSS classes" data-help="Your own class names, separated by spaces, added to the form element so you can style it in Custom CSS. Each field has its own CSS classes box too, and the submit button has one under Submit Button."></span></label>
|
|
155
|
+
<input id="setting-form-class" type="text" class="form-input" placeholder="contact-form is-compact" autocomplete="off" spellcheck="false">
|
|
156
|
+
<p class="form-hint text-muted" style="margin-top:.3rem;font-size:.8rem;">Letters, digits, hyphens and underscores; no dots.</p>
|
|
152
157
|
</div>
|
|
153
158
|
</div>
|
|
154
159
|
</div>
|
|
@@ -204,6 +209,12 @@
|
|
|
204
209
|
</select>
|
|
205
210
|
</div>
|
|
206
211
|
</div>
|
|
212
|
+
<div class="row">
|
|
213
|
+
<div class="col-12 mb-3">
|
|
214
|
+
<label class="form-label" for="setting-submit-class">CSS classes <span data-help-title="Submit button CSS classes" data-help="Your own class names, separated by spaces, added to the submit button - and to Finish on a multi-step form - on top of the style chosen above. Style them in Custom CSS."></span></label>
|
|
215
|
+
<input id="setting-submit-class" type="text" class="form-input" placeholder="cta-button" autocomplete="off" spellcheck="false">
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
207
218
|
<div class="row">
|
|
208
219
|
<div class="col-6 mb-3">
|
|
209
220
|
<label class="form-label">Icon before the text <span data-help-title="Button icons" data-help="An icon either side of the button's text - a paper plane after Send, say. Type an icon's name or browse for one; leave both empty for text only. On a multi-step form the icons go on the Finish button, not on Next. If a trigger ends the form early, its Finish keeps them."></span></label>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{apiRequest as ie}from"/admin/js/api.js";import{makeIconInput as
|
|
2
|
-
`).filter(
|
|
3
|
-
`).filter(b=>b.trim()).map(b=>{const[k,...m]=b.split(":");return{value:k.trim(),label:m.join(":").trim()||k.trim()}});n.cascade={sourceField:f,mapping:y,defaultOptions:h},a=!0}}return a?n:void 0}function _(){w=w.map((e,t)=>nn(t))}function ln(e){const t=e.firstElementChild;if(!t||t.querySelector(".fb-drag-grip"))return;const o=document.createElement("span");o.className="fb-drag-grip",o.setAttribute("data-icon","grip-vertical"),o.setAttribute("data-icon-size","16"),o.title="Drag to reorder",t.insertBefore(o,t.firstChild),window.I?.scan?.(t)}function X(e){const t=e.find("#fields-list").get(0),o=e.find("#fields-empty-msg").get(0);if(t){if(Array.from(t.querySelectorAll(".fb-field-card")).forEach(n=>n.remove()),w.length===0){o&&(o.style.display=""),ce?.(t),ze();return}o&&(o.style.display="none"),w.forEach((n,a)=>{const l=n.type==="page-break"?on(n,a,e):n.type==="spacer"?sn(n,a,e):rn(n,a,e);ln(l),t.appendChild(l)}),ce?.(t),ze()}}function on(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent="- Page Break -",l.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:color-mix(in srgb, var(--dm-text-muted) 20%, transparent);color:var(--dm-text-muted);white-space:nowrap;flex-shrink:0;font-style:italic;";const i=document.createElement("span");i.textContent=e.label||"Untitled Step",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text-muted);";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit step",B(c,"more-horizontal"),c.addEventListener("click",y=>{y.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove page break",B(s,"x"),s.addEventListener("click",async y=>{y.stopPropagation(),await E.confirm("Remove this page break?")&&(_(),w.splice(t,1),X(o))}),r.appendChild(s),a.appendChild(l),a.appendChild(i),a.appendChild(r),a.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=document.createElement("div");d.className="fb-field-body",d.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border);display:none;";const p=D([j("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),j("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),f=p.querySelector(`#fb-pb-label-${t}`);return f&&f.addEventListener("input",()=>{i.textContent=f.value||"Untitled Step"}),d.appendChild(p),n.appendChild(a),n.appendChild(d),n}function sn(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--dm-border);border-radius:6px;margin-bottom:.5rem;background:transparent;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const l=document.createElement("div");l.style.cssText="flex:1;height:1px;background:var(--dm-border);";const i=document.createElement("span");i.textContent="Spacer",i.style.cssText="font-size:.7rem;color:var(--dm-text-muted);white-space:nowrap;padding:0 .4rem;font-style:italic;";const r=document.createElement("div");r.style.cssText="flex:1;height:1px;background:var(--dm-border);";const c=document.createElement("div");c.style.cssText="display:flex;gap:.25rem;flex-shrink:0;";const s=document.createElement("button");return s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove spacer",B(s,"x"),s.addEventListener("click",async d=>{d.stopPropagation(),_(),w.splice(t,1),X(o)}),c.appendChild(s),a.appendChild(l),a.appendChild(i),a.appendChild(r),a.appendChild(c),n.appendChild(a),n}function rn(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);box-shadow:var(--dm-shadow-sm);";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;background:var(--dm-card-header-bg);cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=ut(e.type),l.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:color-mix(in srgb, var(--dm-primary) 14%, transparent);color:var(--dm-primary);white-space:nowrap;flex-shrink:0;";const i=document.createElement("span");i.textContent=e.label||"(unlabelled)",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit field",B(c,"more-horizontal"),c.addEventListener("click",p=>{p.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");if(s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove field",B(s,"x"),s.addEventListener("click",async p=>{p.stopPropagation(),await E.confirm("Remove this field?")&&(_(),w.splice(t,1),X(o))}),r.appendChild(s),a.appendChild(l),a.appendChild(i),e.required){const p=document.createElement("span");p.textContent="required",p.style.cssText="font-size:.7rem;color:var(--dm-danger);flex-shrink:0;",a.appendChild(p)}if(mt(e.logic)){const p=document.createElement("span");B(p,"zap"),p.title="Has conditional logic",p.style.cssText="font-size:.75rem;color:var(--dm-primary);flex-shrink:0;",a.appendChild(p)}a.appendChild(r),a.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=cn(e,t,i);return d.style.display="none",n.appendChild(a),n.appendChild(d),n}function cn(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:1rem .9rem;border-top:1px solid var(--dm-border);";const a=D([j("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),j("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),l=D([Bn("Type",`fb-type-${t}`,rt,e.type||"string"),Ge("Required",`fb-required-${t}`,e.required||!1)]),i=D([j("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field")]),r=D([j("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field"),j("Tooltip",`fb-tooltip-${t}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),c=e.formConfig?.span,s=D([j("Column Span",`fb-span-${t}`,"number",c&&c!=="full"?String(c):"1","Columns to span (grid only)"),Ge("Full Width",`fb-fullwidth-${t}`,c==="full")]);s.classList.add("fb-grid-row"),s.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(a),n.appendChild(l),n.appendChild(i),n.appendChild(r),n.appendChild(s);const d=n.querySelector(`#fb-label-${t}`),p=n.querySelector(`#fb-name-${t}`);d&&d.addEventListener("input",()=>{o&&(o.textContent=d.value||"(unlabelled)"),p&&!p.dataset.manuallyEdited&&(p.value=dt(d.value))}),p&&p.addEventListener("input",()=>{p.dataset.manuallyEdited="1"});const f=n.querySelector(`#fb-type-${t}`);f&&f.addEventListener("change",()=>{const h=n.closest(".fb-field-card");if(h){const m=h.querySelector("span");m&&(m.textContent=ut(f.value))}const b=n.querySelector(".fb-field-extras");b&&b.remove();const k=$t(f.value,e,t);k&&n.appendChild(k)});const y=$t(e.type,e,t);return y&&n.appendChild(y),n.appendChild(fn(e,t)),n.appendChild(Cn(e,t)),n}const ye=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],Re=new Set(["is_empty","is_not_empty"]),ft={equals:"includes",not_equals:"does not include",contains:"any value contains",not_contains:"no value contains",starts_with:"any value starts with",ends_with:"any value ends with",greater_than:"any value is greater than",less_than:"any value is less than",is_empty:"nothing selected",is_not_empty:"something selected",in:"includes one of (comma sep)",not_in:"includes none of (comma sep)",matches_regex:"any value matches regex"};function Me(e){return!!e&&(e.type==="checkbox-group"||!!e.multiple)}function ve(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--dm-text-muted);margin:0 0 .7rem;text-transform:uppercase;letter-spacing:.06em;",t}function xe(e,t,o,n,a){const l=document.createElement("div");l.className="fb-logic-cond-row",l.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const i=document.createElement("span");i.textContent="When",i.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const r=document.createElement("select");r.className="form-select fb-logic-cond-field",r.style.cssText="flex:1 1 140px;min-width:140px;",t.forEach(h=>{const b=document.createElement("option");b.value=h.value,b.textContent=h.label,e&&h.value===e.field&&(b.selected=!0),r.appendChild(b)});const c=document.createElement("select");c.className="form-select fb-logic-cond-op",c.style.cssText="flex:1 1 160px;min-width:140px;",ye.forEach(h=>{const b=document.createElement("option");b.value=h.value,b.textContent=h.label,e&&h.value===e.operator&&(b.selected=!0),c.appendChild(b)});const s=()=>{const h=t.find(b=>b.value===r.value);Array.from(c.options).forEach(b=>{const k=ye.find(m=>m.value===b.value);b.textContent=h?.multi&&ft[b.value]||k?.label||b.value})};s(),r.addEventListener("change",s);const d=document.createElement("input");d.type="text",d.className="form-input fb-logic-cond-val",d.placeholder="value",d.style.cssText="flex:1 1 120px;min-width:100px;",d.value=e?.value||"",e&&Re.has(e.operator)&&(d.style.display="none"),c.addEventListener("change",()=>{d.style.display=Re.has(c.value)?"none":""});const p=document.createElement("span");B(p,"arrow-right"),p.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const f=document.createElement("select");f.className=`form-select ${n}`,f.style.cssText="flex:1 1 140px;min-width:120px;",o.forEach(h=>{const b=document.createElement("option");b.value=h.value,b.textContent=h.label,h.value===a&&(b.selected=!0),f.appendChild(b)});const y=document.createElement("button");return y.type="button",y.className="btn btn-xs btn-ghost",y.style.cssText="line-height:1;opacity:.6;",B(y,"x"),y.style.flexShrink="0",y.addEventListener("click",()=>l.remove()),l.appendChild(i),l.appendChild(r),l.appendChild(c),l.appendChild(d),l.appendChild(p),l.appendChild(f),l.appendChild(y),l}function dn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(ve("Visibility"));const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const l=document.createElement("span");l.textContent="Default:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-vis-default",i.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(m=>{const x=document.createElement("option");x.value=m.value,x.textContent=m.label,m.value===(e.default||"visible")&&(x.selected=!0),i.appendChild(x)}),a.appendChild(l),a.appendChild(i),n.appendChild(a);const r=document.createElement("div");r.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const c=document.createElement("span");c.textContent="Transition:",c.style.cssText="font-size:.8rem;flex-shrink:0;";const s=document.createElement("select");s.className="form-select fb-logic-vis-transition",s.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(m=>{const x=document.createElement("option");x.value=m.value,x.textContent=m.label,m.value===(e.transition||"none")&&(x.selected=!0),s.appendChild(x)}),r.appendChild(c),r.appendChild(s),n.appendChild(r);const d=document.createElement("div");d.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const p=document.createElement("span");p.textContent="Speed:",p.style.cssText="font-size:.8rem;flex-shrink:0;";const f=document.createElement("select");f.className="form-select fb-logic-vis-duration",f.style.cssText="max-width:240px;",[{value:"",label:"Default"},{value:"120",label:"Very fast (120ms)"},{value:"200",label:"Fast (200ms)"},{value:"350",label:"Medium (350ms)"},{value:"600",label:"Slow (600ms)"},{value:"1000",label:"Very slow (1s)"}].forEach(m=>{const x=document.createElement("option");x.value=m.value,x.textContent=m.label,m.value===String(e.duration??"")&&(x.selected=!0),f.appendChild(x)}),d.appendChild(p),d.appendChild(f),n.appendChild(d);const y=()=>{d.style.display=s.value==="none"?"none":""};y(),s.addEventListener("change",y);const h=document.createElement("div");h.className="fb-logic-vis-rules";const b=o.map(m=>({value:m.name,label:m.label||m.name,multi:Me(m)})),k=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(m=>{const x=(m.when?.all||m.when?.any||[])[0],N=m.then==="hidden"?"hidden":"visible";b.length>0&&h.appendChild(xe(x,b,k,"fb-logic-vis-then",N))}),n.appendChild(h),b.length>0){const m=document.createElement("button");m.type="button",m.className="btn btn-xs btn-ghost",m.style.cssText="font-size:.73rem;margin-top:.35rem;",re(m,"plus","Add visibility rule"),m.addEventListener("click",()=>h.appendChild(xe(null,b,k,"fb-logic-vis-then","visible"))),n.appendChild(m)}return n}function un(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(ve("Conditional Requirement"));const a=document.createElement("label");a.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8rem;cursor:pointer;margin-bottom:.65rem;";const l=document.createElement("input");l.type="checkbox",l.className="fb-logic-req-default",l.checked=e.default===!0,a.appendChild(l),a.appendChild(document.createTextNode("Required by default")),n.appendChild(a);const i=document.createElement("div");i.className="fb-logic-req-rules";const r=o.map(s=>({value:s.name,label:s.label||s.name,multi:Me(s)})),c=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(s=>{const d=(s.when?.all||s.when?.any||[])[0],p=s.then===!0?"true":"false";r.length>0&&i.appendChild(xe(d,r,c,"fb-logic-req-then",p))}),n.appendChild(i),r.length>0){const s=document.createElement("button");s.type="button",s.className="btn btn-xs btn-ghost",s.style.cssText="font-size:.73rem;margin-top:.35rem;",re(s,"plus","Add requirement rule"),s.addEventListener("click",()=>i.appendChild(xe(null,r,c,"fb-logic-req-then","true"))),n.appendChild(s)}return n}function ht(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const o=document.createElement("select");o.className="form-select fb-logic-val-type",o.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===(e?.type||"regex")&&(c.selected=!0),o.appendChild(c)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;";const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-val-flags",a.placeholder="flags",a.value=e?.flags||"",a.style.cssText="flex:0 0 55px;",e?.type==="match"&&(a.style.display="none"),o.addEventListener("change",()=>{a.style.display=o.value==="match"?"none":"",n.placeholder=o.value==="match"?"field name":"pattern"});const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-message",l.placeholder="Error message",l.value=e?.message||"",l.style.cssText="flex:4;";const i=document.createElement("button");return i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="line-height:1;opacity:.6;",B(i,"x"),i.style.flexShrink="0",i.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(a),t.appendChild(l),t.appendChild(i),t}function pn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(ve("Custom Validation"));const a=document.createElement("div");a.className="fb-logic-val-rules",(e||[]).forEach(i=>a.appendChild(ht(i))),n.appendChild(a);const l=document.createElement("button");return l.type="button",l.className="btn btn-xs btn-ghost",l.style.cssText="font-size:.73rem;margin-top:.35rem;",re(l,"plus","Add validation rule"),l.addEventListener("click",()=>a.appendChild(ht(null))),n.appendChild(l),n}function mn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(ve("Cascade Options")),n.lastChild.appendChild(Ie("Make this field's options depend on another field. When the source field changes, the options here are replaced by the mapping entry for its value; if nothing matches, the default options below are shown."));const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const l=document.createElement("span");l.textContent="Source field:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-cascade-source",i.style.cssText="flex:1;";const r=document.createElement("option");r.value="",r.textContent="- none -",i.appendChild(r),o.forEach(f=>{const y=document.createElement("option");y.value=f.name,y.textContent=f.label||f.name,f.name===e.sourceField&&(y.selected=!0),i.appendChild(y)}),a.appendChild(l),a.appendChild(i),n.appendChild(a);const c=document.createElement("p");c.textContent='Mapping JSON - {"value":[{"value":"...","label":"..."}]}',c.appendChild(Ie(`Each key is a value of the source field; its list becomes this field's options when that value is picked. Example: {"uk":[{"value":"london","label":"London"}]} shows London when the source is "uk".`)),c.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const s=document.createElement("textarea");s.className="form-input fb-logic-cascade-mapping",s.rows=4,s.style.cssText="font-family:monospace;",s.placeholder='{"uk": [{"value": "london", "label": "London"}]}',s.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(c),n.appendChild(s);const d=document.createElement("p");d.textContent="Default options (one per line: value:Label)",d.appendChild(Ie("Shown before the source field has a value, or when its value has no mapping entry.")),d.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const p=document.createElement("textarea");return p.className="form-input fb-logic-cascade-defaults",p.rows=3,p.style.cssText="font-family:monospace;",p.placeholder=`option1:Option 1
|
|
4
|
-
option2:Option 2`,p.value=(e.defaultOptions||[]).map(
|
|
5
|
-
`),n.appendChild(d),n.appendChild(p),n}function fn(e,t){const o=e.logic||{},n=w.filter((p,f)=>f!==t&&p.type!=="page-break"&&p.type!=="spacer"),a=document.createElement("div");a.className="fb-field-logic",a.style.cssText="margin-top:.75rem;border-top:1px solid var(--dm-border);padding-top:.5rem;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const i=document.createElement("span");i.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted);",i.textContent="\u26A1 Conditional Logic";const r=mt(o),c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",B(c,r?"chevron-down":"chevron-right",12);const s=document.createElement("div");s.className="fb-logic-body",s.style.cssText="padding:.25rem 0 .25rem;"+(r?"":"display:none;"),l.addEventListener("click",()=>{const p=s.style.display==="none";s.style.display=p?"":"none",B(c,p?"chevron-down":"chevron-right",12)}),l.appendChild(i),l.appendChild(c),a.appendChild(l),s.appendChild(dn(o.visibility||{},t,n)),s.appendChild(un(o.requirement||{},t,n)),s.appendChild(pn(o.validation||[],t,n));const d=document.getElementById(`fb-type-${t}`)?.value||e.type;return Fe.has(d)&&s.appendChild(mn(o.cascade||{},t,n)),a.appendChild(s),a}const de=[{value:"banner",label:"Show a banner",kind:"state",params:["message","level","position","dismissible"],placeholder:"e.g. You must be 18 or over to continue."},{value:"toast",label:"Show a toast",kind:"event",params:["message","level"],placeholder:"e.g. Thanks - carry on."},{value:"hide-fields",label:"Hide fields",kind:"state",params:["target"]},{value:"disable-fields",label:"Disable fields",kind:"state",params:["target"]},{value:"require-fields",label:"Make fields required",kind:"state",params:["target"]},{value:"block-submit",label:"Block submission",kind:"state",params:["message"],messageLabel:"Reason, shown under the button",placeholder:'Blank: "This form cannot be submitted yet."'},{value:"end-form",label:"End the form here",kind:"state",params:["message","finish","finishLabel","doneMessage","record"],messageLabel:"Message shown in place of the rest",placeholder:"e.g. Sorry - you must be 18 or over to apply."},{value:"goto-step",label:"Jump to a wizard step",kind:"event",params:["step"]},{value:"redirect",label:"Redirect after submit",kind:"event",params:["url"]},{value:"celebrate",label:"Celebrate",kind:"event",params:["theme","intensity"]},{value:"run-action",label:"Run a CMS action",kind:"event",params:["slug"]},{value:"notify",label:"Notify the admins",kind:"event",params:["message","level"],messageLabel:"Notification title",placeholder:"Blank: titled after the form",noOnce:!0,kindText:"when the form is submitted"}],Ce=[{value:"info",label:"Info"},{value:"success",label:"Success"},{value:"warning",label:"Warning"},{value:"error",label:"Error"}],bt=[{value:"field-below",label:"Below this field"},{value:"field-above",label:"Above this field"},{value:"form-top",label:"Top of the form"}],gt=[{value:"rest",label:"The rest of the form"},{value:"all",label:"Every other field"},{value:"listed",label:"Chosen fields"}],yt=[{value:"auto",label:"Whatever is in season"},{value:"christmas",label:"Christmas"},{value:"halloween",label:"Halloween"},{value:"valentines",label:"Valentine's Day"},{value:"guy-fawkes",label:"Guy Fawkes Night"},{value:"st-patricks",label:"St Patrick's Day"},{value:"st-andrews",label:"St Andrew's Day"},{value:"st-davids",label:"St David's Day"},{value:"st-georges",label:"St George's Day"}];function vt(e,t=!1){const o=(i,r)=>({value:i.name,label:`${i.label||i.name}${r?" (this field)":""}`,multi:Me(i)}),n=i=>i&&i.type!=="page-break"&&i.type!=="spacer"&&i.name,a=w.filter((i,r)=>r!==e&&n(i)).map(i=>o(i,!1)),l=w[e];return t&&n(l)?[o(l,!0),...a]:a}function J(e,t,o){const n=document.createElement("select");return n.className=`form-select ${e}`,t.forEach(a=>{const l=document.createElement("option");l.value=a.value,l.textContent=a.label,a.value===o&&(l.selected=!0),n.appendChild(l)}),n}function ae(e,t,o){const n=document.createElement("input");return n.type="text",n.className=`form-input ${e}`,n.value=t==null?"":String(t),o&&(n.placeholder=o),n}function De(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-remove",t&&(o.title=t,o.setAttribute("aria-label",t)),B(o,"x"),o.addEventListener("click",n=>{n.stopPropagation(),e()}),o}function P(e,t,{full:o=!1,hint:n=""}={}){const a=document.createElement("label");a.className=`fb-trig-f${o?" fb-trig-f--full":""}`;const l=document.createElement("span");if(l.className="fb-trig-f-label",l.textContent=e,a.appendChild(l),a.appendChild(t),n){const i=document.createElement("span");i.className="fb-trig-f-hint",i.textContent=n,a.appendChild(i)}return a}function ue(e,t,o,n){const a=document.createElement("label");a.className="fb-trig-check",n&&(a.title=n);const l=document.createElement("input");return l.type="checkbox",l.className=`form-check ${e}`,l.checked=!!t,a.appendChild(l),a.appendChild(document.createTextNode(o)),a}function xt(e,t){const o=document.createElement("div");o.className="fb-trig-cond-row";const n=J("fb-trig-cond-field",t,e?.field),a=J("fb-trig-cond-op",ye,e?.operator),l=ae("fb-trig-cond-val",e?.value,"value"),i=()=>{const c=t.find(s=>s.value===n.value);Array.from(a.options).forEach(s=>{const d=ye.find(p=>p.value===s.value);s.textContent=c?.multi&&ft[s.value]||d?.label||s.value})},r=()=>{l.hidden=Re.has(a.value)};return i(),r(),n.addEventListener("change",i),a.addEventListener("change",r),o.appendChild(n),o.appendChild(a),o.appendChild(l),o.appendChild(De(()=>o.remove(),"Remove condition")),o}const Ct=["banner","toast","block-submit","end-form"],Et=["password","file","image","signature"],hn="Put an answer in with {{field_name}} - e.g. Hello {{name}}. Pick one from Insert field.";function bn(){try{_()}catch{}return w.filter(e=>e&&e.name&&e.type!=="page-break"&&e.type!=="spacer"&&!Et.includes(e.type))}function wt(e,t,o){const n=ae(e,t,o),a=document.createElement("span");a.className="fb-token-row";const l=document.createElement("select");l.className="form-input fb-token-pick",l.title="Insert an answer into the message",l.setAttribute("aria-label","Insert a field's answer into the message");const i=()=>{l.replaceChildren(new Option("Insert field",""));for(const r of bn())l.appendChild(new Option(`${r.label||r.name} ({{${r.name}}})`,r.name))};return i(),l.addEventListener("focus",i),l.addEventListener("mousedown",i),l.addEventListener("change",()=>{const r=l.value;if(l.value="",!r)return;const c=`{{${r}}}`,s=n.selectionStart??n.value.length,d=n.selectionEnd??s;n.value=n.value.slice(0,s)+c+n.value.slice(d),n.focus(),n.setSelectionRange(s+c.length,s+c.length),n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}),a.append(n,l),a}function gn(e){const t=window.FormLogicEngine;if(!t?.triggerTokens)return[];const o=new Map((e||[]).filter(a=>a&&a.name).map(a=>[a.name,a])),n=new Set;for(const a of e||[])for(const l of a?.triggers||[])for(const i of[...l.then||[],...l.otherwise||[]])if(Ct.includes(i?.type))for(const r of[...t.triggerTokens(i.message),...t.triggerTokens(i.doneMessage)]){const c=o.get(r);(!c||Et.includes(c.type))&&n.add(r)}return[...n]}function kt(e,t){const o=document.createElement("div");o.className="fb-trig-params";const n=de.find(c=>c.value===(e.type||"banner"));if(!n)return o;const a=document.createElement("div");a.className="fb-trig-grid";const l=document.createElement("div");l.className="fb-trig-opts";const i=[];for(const c of n.params)switch(c){case"message":a.appendChild(Ct.includes(n.value)?P(n.messageLabel||"Message",wt("fb-trig-p-message",e.message,n.placeholder||""),{full:!0,hint:hn}):P(n.messageLabel||"Message",ae("fb-trig-p-message",e.message,n.placeholder||""),{full:!0}));break;case"finish":l.appendChild(ue("fb-trig-p-finish-on",e.finish!==!1,"Let the visitor finish (send the answers given so far)",'Untick to stop the form dead: the submit button is disabled and nothing is sent, so nothing is saved and "Notify the admins" cannot fire.'));break;case"finishLabel":{const s=P("Button text",ae("fb-trig-p-finish",e.finishLabel,"Finish"));i.push(s),a.appendChild(s);break}case"doneMessage":{const s=P("Closing message",wt("fb-trig-p-done",e.doneMessage,"Blank: the form's own success message"));i.push(s),a.appendChild(s);break}case"record":{const s=ue("fb-trig-p-record",e.record!==!1,"Save the answers given so far",`Untick to keep nothing: no submission is stored and the form's email, webhook and actions do not run. A "Notify the admins" action still fires.`);i.push(s),l.appendChild(s);break}case"level":a.appendChild(P(n.value==="notify"?"Severity":"Level",J("fb-trig-p-level",Ce,e.level||"info")));break;case"position":a.appendChild(P("Where",J("fb-trig-p-position",bt,e.position||"field-below")));break;case"dismissible":l.appendChild(ue("fb-trig-p-dismissible",e.dismissible!==!1,"The visitor can dismiss it"));break;case"target":{const s=J("fb-trig-p-target",gt,e.target||(e.fields?.length?"listed":"rest")),d=document.createElement("select");d.className="form-select fb-trig-p-fields",d.multiple=!0,d.size=4;const p=new Set(e.fields||[]);vt(t).forEach(h=>{const b=document.createElement("option");b.value=h.value,b.textContent=h.label,p.has(h.value)&&(b.selected=!0),d.appendChild(b)});const f=P("Fields",d,{hint:"Ctrl/Cmd-click to pick several"}),y=()=>{f.hidden=s.value!=="listed"};y(),s.addEventListener("change",y),a.appendChild(P("Which fields",s)),a.appendChild(f);break}case"step":{const s=ae("fb-trig-p-step",e.step,"0");s.type="number",s.min="0",a.appendChild(P("Step",s,{hint:"Counting from 0"}));break}case"url":a.appendChild(P("Send them to",ae("fb-trig-p-url",e.url,"/thank-you"),{full:!0}));break;case"theme":a.appendChild(P("Theme",J("fb-trig-p-theme",yt,e.theme||"auto")));break;case"intensity":a.appendChild(P("Intensity",J("fb-trig-p-intensity",[{value:"low",label:"Low"},{value:"medium",label:"Medium"},{value:"high",label:"High"}],e.intensity||"medium")));break;case"slug":{const s=[{value:"",label:fe.length?"Choose an action":"No actions available"}].concat(fe.map(d=>({value:d.slug,label:d.title||d.slug})));a.appendChild(P("Action",J("fb-trig-p-slug",s,e.slug||""),{full:!0}));break}default:break}n.kind==="event"&&!n.noOnce&&l.appendChild(ue("fb-trig-p-once",!!e.once,"Only once","Fire the first time only, rather than every time the answer swings back."));const r=l.querySelector(".fb-trig-p-finish-on");if(r){const c=()=>i.forEach(s=>{s.hidden=!r.checked});c(),r.addEventListener("change",c)}return a.children.length&&o.appendChild(a),l.children.length&&o.appendChild(l),o}function yn(e){return e?.kindText?e.kindText:e?.kind==="event"?"once, when it becomes true":"while it is true"}const vn=(e,t=48)=>e.length>t?`${e.slice(0,t-1)}\u2026`:e,le=(e,t)=>e.find(o=>o.value===t)?.label||t;function xn(e){if(!e)return"";const t=[],o=a=>a?`"${vn(a)}"`:"",n=()=>e.target==="listed"?e.fields?.length?e.fields.join(", "):"no fields chosen":le(gt,e.target||"rest").toLowerCase();switch(e.type){case"banner":t.push(o(e.message)||"No message yet",le(Ce,e.level||"info"),le(bt,e.position||"field-below").toLowerCase());break;case"toast":t.push(o(e.message)||"No message yet",le(Ce,e.level||"info"));break;case"hide-fields":case"disable-fields":case"require-fields":t.push(n());break;case"block-submit":t.push(o(e.message)||"the standard reason");break;case"end-form":t.push(o(e.message)||"no message"),e.finish===!1?t.push("submit disabled"):t.push(`button "${e.finishLabel||"Finish"}"`,e.record===!1?"saves nothing":"saves the answers");break;case"goto-step":t.push(Number.isFinite(e.step)?`step ${e.step}`:"no step yet");break;case"redirect":t.push(e.url||"no address yet");break;case"celebrate":t.push(le(yt,e.theme||"auto"),`${e.intensity||"medium"} intensity`);break;case"run-action":t.push(e.slug?fe.find(a=>a.slug===e.slug)?.title||e.slug:"no action chosen");break;case"notify":t.push(o(e.message)||"titled after the form",le(Ce,e.level||"info"));break;default:break}return e.once&&t.push("only once"),t.filter(Boolean).join(" \xB7 ")}function _e(e,t,{open:o=!1}={}){const n=document.createElement("div");n.className="fb-trig-action-row";const a=document.createElement("div");a.className="fb-trig-action-head",a.tabIndex=0,a.setAttribute("role","button");const l=document.createElement("span");l.className="fb-trig-chevron";const i=document.createElement("span");i.className="fb-trig-action-main";const r=document.createElement("strong"),c=document.createElement("small");c.className="fb-trig-action-summary",i.append(r,c);const s=document.createElement("span");s.className="fb-trig-kind",a.append(l,i,s,De(()=>n.remove(),"Remove action"));const d=document.createElement("div");d.className="fb-trig-action-body";const p=J("fb-trig-action-type",de,e.type||"banner");d.appendChild(P("Action",p,{full:!0})),d.appendChild(kt(e,t));const f=()=>{const h=de.find(b=>b.value===p.value);r.textContent=h?.label||p.value,s.textContent=yn(h),s.classList.toggle("fb-trig-kind--event",h?.kind==="event"),c.textContent=xn(Lt(n))},y=h=>{d.hidden=!h,n.classList.toggle("is-open",h),a.setAttribute("aria-expanded",String(h)),B(l,h?"chevron-down":"chevron-right",12)};return a.addEventListener("click",()=>y(d.hidden)),a.addEventListener("keydown",h=>{h.target!==a||h.key!=="Enter"&&h.key!==" "||(h.preventDefault(),y(d.hidden))}),p.addEventListener("change",()=>{const h=kt({type:p.value},t);d.replaceChild(h,d.querySelector(".fb-trig-params")),f(),window.I?.scan?.()}),d.addEventListener("input",f),d.addEventListener("change",f),n.append(a,d),y(o),f(),n}function St(e,t,o){const n=document.createElement("section");n.className=`fb-trig-sec fb-trig-sec--${e}`;const a=document.createElement("div");a.className="fb-trig-sec-head";const l=document.createElement("span");if(l.className="fb-trig-sec-title",l.textContent=t,a.appendChild(l),o){const i=document.createElement("span");i.className="fb-trig-sec-hint",i.textContent=o,a.appendChild(i)}return n.appendChild(a),n}function Pe(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-add",re(o,"plus",e,12),o.addEventListener("click",t),o}function Tt(e,t,o,n){const l=St(e,t,e==="then"?"What happens while the answers match.":"What happens while they do not. Leave empty for nothing.");l.classList.add("fb-trig-branch"),l.dataset.branch=e;const i=document.createElement("div");return i.className="fb-trig-action-list",(o||[]).forEach(r=>i.appendChild(_e(r,n))),l.appendChild(i),l.appendChild(Pe("Add action",()=>{i.appendChild(_e({type:"banner"},n,{open:!0})),window.I?.scan?.()})),l}function Nt(e,t,o){const n=vt(t,!0),a=document.createElement("div");a.className="fb-trig-card",a.dataset.triggerId=e.id||`trg-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;const l=document.createElement("div");l.className="fb-trig-card-head";const i=document.createElement("span");i.className="fb-trig-card-title",i.textContent=`Trigger ${o+1}`,l.appendChild(i);const r=ue("fb-trig-enabled",e.enabled!==!1,"Enabled","Untick to keep the trigger but switch it off.");if(l.appendChild(r),l.appendChild(De(()=>a.remove(),"Remove trigger")),a.appendChild(l),!n.length){const p=document.createElement("p");return p.className="fb-trig-empty",p.textContent="Give this field a name first - a trigger tests an answer, and it needs something to test.",a.appendChild(p),a}const c=St("when","When");c.querySelector(".fb-trig-sec-head").appendChild(J("fb-trig-match",[{value:"all",label:"all of these are true"},{value:"any",label:"any of these is true"}],Array.isArray(e.when?.any)?"any":"all"));const s=document.createElement("div");s.className="fb-trig-cond-list";const d=e.when?.all||e.when?.any||[];return(d.length?d:[{}]).forEach(p=>s.appendChild(xt(p,n))),c.appendChild(s),c.appendChild(Pe("Add condition",()=>{s.appendChild(xt({},n)),window.I?.scan?.()})),a.appendChild(c),a.appendChild(Tt("then","Then",e.then,t)),a.appendChild(Tt("otherwise","Otherwise",e.otherwise,t)),a}function Cn(e,t){const o=Array.isArray(e.triggers)?e.triggers:[],n=document.createElement("div");n.className="fb-field-triggers";const a=document.createElement("div");a.className="fb-trig-panel-head";const l=document.createElement("span");l.className="fb-trig-panel-title",l.textContent=`\u{1F3AF} Triggers${o.length?` (${o.length})`:""}`;const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",B(i,o.length?"chevron-down":"chevron-right",12);const r=document.createElement("div");r.className="fb-triggers-body",r.hidden=!o.length,a.addEventListener("click",()=>{r.hidden=!r.hidden,B(i,r.hidden?"chevron-right":"chevron-down",12)});const c=document.createElement("p");c.className="fb-trig-blurb",c.textContent="Do something to the form when the answers meet a condition - show a banner or toast, hide, disable or require other fields, refuse the submit, end the form early, notify the admins, jump to a step, or celebrate.",r.appendChild(c);const s=document.createElement("div");return s.className="fb-trig-list",o.forEach((d,p)=>s.appendChild(Nt(d,t,p))),r.appendChild(s),r.appendChild(Pe("Add trigger",()=>{const d=Nt({enabled:!0,then:[]},t,s.children.length);s.appendChild(d),d.querySelector('.fb-trig-branch[data-branch="then"] .fb-trig-action-list')?.appendChild(_e({type:"banner"},t,{open:!0})),window.I?.scan?.()})),a.appendChild(l),a.appendChild(i),n.appendChild(a),n.appendChild(r),n}function Lt(e){const t=e.querySelector(".fb-trig-action-type")?.value,o=de.find(l=>l.value===t);if(!o)return null;const n={type:t},a=l=>e.querySelector(l)?.value?.trim()||"";for(const l of o.params)switch(l){case"message":n.message=a(".fb-trig-p-message");break;case"finishLabel":{const i=a(".fb-trig-p-finish");i&&(n.finishLabel=i);break}case"doneMessage":{const i=a(".fb-trig-p-done");i&&(n.doneMessage=i);break}case"finish":e.querySelector(".fb-trig-p-finish-on")?.checked||(n.finish=!1);break;case"record":e.querySelector(".fb-trig-p-record")?.checked||(n.record=!1);break;case"level":n.level=a(".fb-trig-p-level")||"info";break;case"position":n.position=a(".fb-trig-p-position")||"field-below";break;case"dismissible":n.dismissible=!!e.querySelector(".fb-trig-p-dismissible")?.checked;break;case"target":{const i=a(".fb-trig-p-target")||"rest";n.target=i,i==="listed"&&(n.fields=Array.from(e.querySelectorAll(".fb-trig-p-fields option")).filter(r=>r.selected).map(r=>r.value));break}case"step":{const i=parseInt(a(".fb-trig-p-step"),10);Number.isFinite(i)&&(n.step=i);break}case"url":n.url=a(".fb-trig-p-url");break;case"theme":n.theme=a(".fb-trig-p-theme")||"auto";break;case"intensity":n.intensity=a(".fb-trig-p-intensity")||"medium";break;case"slug":n.slug=a(".fb-trig-p-slug");break;default:break}return o.kind==="event"&&!o.noOnce&&e.querySelector(".fb-trig-p-once")?.checked&&(n.once=!0),n}function En(e){const t=Lt(e);if(!t)return null;const o=de.find(l=>l.value===t.type),n=t.type,a=["block-submit","end-form","notify"].includes(o.value);return o.params.includes("message")&&!t.message&&!a?(delete t.message,null):(a&&!t.message&&delete t.message,n==="redirect"&&!t.url||n==="run-action"&&!t.slug?null:t)}function wn(e){const o=document.querySelector(`.fb-field-card[data-index="${e}"]`)?.querySelector(".fb-field-triggers");if(!o)return;const n=[];return o.querySelectorAll(".fb-trig-card").forEach(a=>{const l=Array.from(a.querySelectorAll(".fb-trig-cond-row")).map(p=>{const f=p.querySelector(".fb-trig-cond-field")?.value,y=p.querySelector(".fb-trig-cond-op")?.value;if(!f||!y)return null;const h=p.querySelector(".fb-trig-cond-val")?.value??"";return{field:f,operator:y,value:h}}).filter(Boolean);if(!l.length)return;const i=p=>Array.from(a.querySelectorAll(`.fb-trig-branch[data-branch="${p}"] .fb-trig-action-row`)).map(En).filter(Boolean),r=i("then"),c=i("otherwise");if(!r.length&&!c.length)return;const s=a.querySelector(".fb-trig-match")?.value==="any"?"any":"all",d={id:a.dataset.triggerId,enabled:!!a.querySelector(".fb-trig-enabled")?.checked,when:{[s]:l}};r.length&&(d.then=r),c.length&&(d.otherwise=c),n.push(d)}),n.length?n:void 0}function $t(e,t,o){const n=document.createElement("div");return n.className="fb-field-extras",e==="chooser"?(n.appendChild(Tn(t,o)),n.appendChild(Ln(t.options||[],o))):(Fe.has(e)&&n.appendChild(Fn(t.options||[],o)),e==="textarea"&&n.appendChild(D([j("Rows",`fb-rows-${o}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(D([j("Min Length",`fb-minlength-${o}`,"number",t.minLength||"",""),j("Max Length",`fb-maxlength-${o}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(D([j("Min",`fb-min-${o}`,"number",t.min??"",""),j("Max",`fb-max-${o}`,"number",t.max??"","")]))),qt.includes(e)&&n.appendChild(Sn(t,o)),n.children.length?n:null}const qt=["string","email","tel","number","url","date","time","password","select","textarea"],At=[{key:"reveal",label:"Show / hide button",types:["password"],hint:"Show / hide lets the visitor see what they typed."},{key:"clear",label:"Clear button",types:["string","email","tel","url","textarea"],hint:"Clear adds an x that empties the field."},{key:"stepper",label:"- / + buttons",types:["number"],hint:"The - and + buttons step the number within its min, max and step."},{key:"counter",label:"Character counter",types:["string","textarea"],hint:"The counter shows how many characters are used, against Max Length if one is set."}];function kn(e){return e?typeof e=="string"?{icon:"",text:e}:{icon:e.icon||"",text:e.icon?"":e.text??""}:{icon:"",text:""}}function Sn(e,t){const o=document.createElement("div");o.className="fb-addons";const n=(i,r)=>{const c=kn(e.formConfig?.[i]),s=document.createElement("div");s.style.flex="1";const d=document.createElement("span");d.className="form-label",d.style.fontSize=".8rem",d.textContent=r;const p=$e("Icon, e.g. search",c.icon);p.input.id=`fb-${i}-icon-${t}`,p.input.setAttribute("aria-label",`${r}: icon`);const f=document.createElement("input");return f.type="text",f.className="form-input",f.id=`fb-${i}-text-${t}`,f.value=c.text,f.placeholder="or text, e.g. \xA3 or kg",f.maxLength=24,f.setAttribute("aria-label",`${r}: text`),f.style.marginTop=".35rem",p.input.addEventListener("input",()=>{p.input.value.trim()&&(f.value="")}),f.addEventListener("input",()=>{f.value.trim()&&(p.input.value="")}),s.append(d,p.el,f),s};o.appendChild(D([n("prefix","Before the field"),n("suffix","After the field")]));const a=document.createElement("p");a.className="form-hint text-muted",a.style.cssText="font-size:.73rem;margin:-.4rem 0 .75rem;",a.textContent="An icon or a short text joined to the start or end of the input, like \xA3 before a price or kg after a weight. Leave both empty for none.",o.appendChild(a);const l=At.filter(i=>i.types.includes(e.type));if(l.length){o.appendChild(D(l.map(r=>Ge(r.label,`fb-extra-${r.key}-${t}`,!!e.formConfig?.[r.key]))));const i=document.createElement("p");i.className="form-hint text-muted",i.style.cssText="font-size:.73rem;margin:-.4rem 0 .75rem;",i.textContent=l.map(r=>r.hint).join(" "),o.appendChild(i)}return o}function Bt(e){const t=document.createElement("div");t.className="fb-chooser-section",t.style.cssText="border:1px solid var(--dm-border); border-radius:6px; margin-top:.5rem; overflow:hidden;";const o=document.createElement("div");o.style.cssText="padding:.4rem .6rem; background:color-mix(in srgb, var(--dm-background) 60%, transparent); font-weight:600; font-size:.82rem; border-bottom:1px solid var(--dm-border);",o.textContent=e,t.appendChild(o);const n=document.createElement("div");return n.className="fb-chooser-section-body",n.style.cssText="padding:.55rem .6rem; display:flex; flex-direction:column; gap:.45rem;",t.appendChild(n),{wrap:t,body:n}}function Ee(e,t,o,n,a){const l=document.createElement("div");l.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem";const r=document.createElement("select");if(r.id=e,r.className="form-input",n.forEach(([c,s])=>{const d=document.createElement("option");d.value=c,d.textContent=s,String(c)===String(o)&&(d.selected=!0),r.appendChild(d)}),l.appendChild(i),l.appendChild(r),a){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=a,c.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(c)}return l}function Ft(e,t,o,n){const a=document.createElement("div");a.style.flex="1";const l=document.createElement("label");l.style.cssText="display:inline-flex;align-items:center;gap:.4rem;font-size:.82rem;";const i=document.createElement("input");if(i.id=e,i.type="checkbox",i.checked=!!o,l.appendChild(i),l.appendChild(document.createTextNode(" "+t)),a.appendChild(l),n){const r=document.createElement("p");r.className="form-hint text-muted",r.textContent=n,r.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(r)}return a}function je(e,t,o,n,a){const l=document.createElement("div");l.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem",l.appendChild(i);const r=document.createElement("div");r.style.cssText="display:flex;gap:.4rem;align-items:stretch;";const c=document.createElement("input");c.id=e,c.type="text",c.className="form-input",c.value=o||"",n&&(c.placeholder=n),c.style.flex="1";const s=document.createElement("input");s.type="color",s.title="Pick a colour",s.style.cssText="width:36px;height:auto;padding:0;border:1px solid var(--dm-border);border-radius:4px;cursor:pointer;";const d=String(c.value).match(/^#[0-9a-fA-F]{3,8}$/);if(s.value=d?c.value:"#000000",s.addEventListener("input",()=>{c.value=s.value,c.dispatchEvent(new Event("input",{bubbles:!0}))}),r.appendChild(c),r.appendChild(s),l.appendChild(r),a){const p=document.createElement("p");p.className="form-hint text-muted",p.textContent=a,p.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(p)}return l}function Tn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const n=Bt("Layout");n.body.appendChild(D([Ee(`fb-chooser-variant-${t}`,"Variant",e.variant||"card",[["card","Card - rich tiles"],["chip","Chip - compact pills"]],"Card supports description and grid columns; chips wrap."),Ft(`fb-chooser-multiple-${t}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),n.body.appendChild(D([Ee(`fb-chooser-density-${t}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),j("Columns",`fb-chooser-columns-${t}`,"number",e.columns||3,"Card grid (1-6). Ignored for chips.")])),o.appendChild(n.wrap);const a=Bt("Visual");return a.body.appendChild(D([je(`fb-chooser-accent-${t}`,"Accent",e.accent||"","primary / success / #ec4899","Selected highlight colour - semantic name or any CSS colour."),Ee(`fb-chooser-accent-style-${t}`,"Accent style",e.accentStyle||"border",[["border","Border (default)"],["solid","Solid"],["glow","Glow"],["overlay","Overlay"],["underline","Underline"]],"Visual treatment of the selected state.")])),a.body.appendChild(D([Ft(`fb-chooser-glow-${t}`,"Glow on selected",!!e.glow,"Soft outer glow."),je(`fb-chooser-glow-colour-${t}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),a.body.appendChild(D([Ee(`fb-chooser-shadow-${t}`,"Shadow",e.shadow||"none",[["none","None"],["sm","Small"],["md","Medium"],["lg","Large"],["xl","Extra Large"]],"Drop shadow on every option."),je(`fb-chooser-shadow-colour-${t}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),o.appendChild(a.wrap),o}function Nn(e,t,o,n){const a=document.createElement("div");a.className="fb-chooser-option-row",a.dataset.optIdx=String(o),a.style.cssText="border:1px solid var(--dm-border); border-radius:4px; padding:.5rem; background:var(--dm-background-alt); display:flex; flex-direction:column; gap:.35rem;";const l=document.createElement("div");l.style.cssText="display:flex; gap:.4rem; align-items:center;";const i=document.createElement("div");i.style.cssText="display:flex; flex-direction:column; gap:1px;";const r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",r.title="Move up",B(r,"arrow-up"),r.addEventListener("click",z=>{z.preventDefault(),It(t,o,-1,n)});const c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",c.title="Move down",B(c,"arrow-down"),c.addEventListener("click",z=>{z.preventDefault(),It(t,o,1,n)}),i.appendChild(r),i.appendChild(c),l.appendChild(i);const s=document.createElement("input");s.type="text",s.className="form-input fb-chooser-opt-value",s.placeholder="value",s.value=e.value||"",s.style.flex="1",l.appendChild(s);const d=document.createElement("input");d.type="text",d.className="form-input fb-chooser-opt-label",d.placeholder="label (visible to users)",d.value=e.label||"",d.style.flex="2",l.appendChild(d);const p=document.createElement("button");p.type="button",p.className="btn btn-xs btn-ghost",p.style.cssText="line-height:1;opacity:.6;",p.title="Remove option",B(p,"x"),p.addEventListener("click",z=>{z.preventDefault(),An(t,o,n)}),l.appendChild(p),a.appendChild(l);const f=document.createElement("div");f.style.cssText="display:flex; gap:.4rem;";const y=$e("icon name (optional)",e.icon||"");y.input.classList.add("fb-chooser-opt-icon"),y.el.style.flex="1",f.appendChild(y.el);const h=document.createElement("input");h.type="text",h.className="form-input fb-chooser-opt-description",h.placeholder="description (card + comfortable only)",h.value=e.description||"",h.style.flex="2",f.appendChild(h),a.appendChild(f);const b=document.createElement("div");b.style.cssText="display:flex; gap:.4rem;";const k=document.createElement("input");k.type="text",k.className="form-input fb-chooser-opt-tooltip",k.placeholder="tooltip (hover hint)",k.value=e.tooltip||"",k.style.flex="2",b.appendChild(k);const m=document.createElement("input");m.type="text",m.className="form-input fb-chooser-opt-badge-text",m.placeholder="badge text",m.value=e.badge?.text||"",m.style.flex="1",b.appendChild(m);const x=document.createElement("select");x.className="form-input fb-chooser-opt-badge-type",x.style.flex="1",[["","no badge"],["primary","primary"],["success","success"],["info","info"],["warning","warning"],["danger","danger"]].forEach(([z,Q])=>{const W=document.createElement("option");W.value=z,W.textContent=Q,(e.badge?.type||"")===z&&(W.selected=!0),x.appendChild(W)}),b.appendChild(x),a.appendChild(b);const N=document.createElement("div");N.style.cssText="display:flex; gap:1rem; font-size:.8rem;";const L=document.createElement("label");L.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const I=document.createElement("input");I.type="checkbox",I.className="fb-chooser-opt-recommended",I.checked=!!e.recommended,L.appendChild(I),L.appendChild(document.createTextNode(" Recommended")),N.appendChild(L);const O=document.createElement("label");O.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const V=document.createElement("input");return V.type="checkbox",V.className="fb-chooser-opt-disabled",V.checked=!!e.disabled,O.appendChild(V),O.appendChild(document.createTextNode(" Disabled")),N.appendChild(O),a.appendChild(N),a}function Ln(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem;";const n=document.createElement("div");n.style.cssText="display:flex; align-items:center; justify-content:space-between; margin-bottom:.4rem;";const a=document.createElement("p");a.textContent="Options",a.style.cssText="font-size:.85rem;font-weight:600;margin:0;",n.appendChild(a);const l=document.createElement("button");l.type="button",l.className="btn btn-xs btn-ghost",re(l,"plus","Add option"),n.appendChild(l),o.appendChild(n);const i=document.createElement("div");i.className="fb-chooser-options-list",i.id=`fb-chooser-options-${t}`,i.style.cssText="display:flex; flex-direction:column; gap:.4rem;",o.appendChild(i);const r=()=>{i.replaceChildren();const c=$n(t);(c.length?c:e||[]).forEach((d,p)=>{i.appendChild(Nn(d,t,p,r))})};return l.addEventListener("click",c=>{c.preventDefault(),qn(t,r)}),r(),o}function $n(e){const t=w[e];return!t||!Array.isArray(t.options)?[]:t.options}function Ve(e){return w[e]?(Array.isArray(w[e].options)||(w[e].options=[]),w[e].options):[]}function qn(e,t){we(e),Ve(e).push({value:"new",label:"New option"}),t()}function An(e,t,o){we(e),Ve(e).splice(t,1),o()}function It(e,t,o,n){we(e);const a=Ve(e),l=t+o;if(l<0||l>=a.length)return;const[i]=a.splice(t,1);a.splice(l,0,i),n()}function we(e){const t=document.getElementById(`fb-chooser-options-${e}`);if(!t)return;const o=t.querySelectorAll(".fb-chooser-option-row"),n=[];o.forEach(a=>{const l={value:a.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:a.querySelector(".fb-chooser-opt-label")?.value.trim()||""},i=a.querySelector(".fb-chooser-opt-icon")?.value.trim();i&&(l.icon=i);const r=a.querySelector(".fb-chooser-opt-description")?.value.trim();r&&(l.description=r);const c=a.querySelector(".fb-chooser-opt-tooltip")?.value.trim();c&&(l.tooltip=c);const s=a.querySelector(".fb-chooser-opt-badge-text")?.value.trim(),d=a.querySelector(".fb-chooser-opt-badge-type")?.value;(s||d)&&(l.badge={},s&&(l.badge.text=s),d&&(l.badge.type=d)),a.querySelector(".fb-chooser-opt-recommended")?.checked&&(l.recommended=!0),a.querySelector(".fb-chooser-opt-disabled")?.checked&&(l.disabled=!0),n.push(l)}),w[e]&&(w[e].options=n)}function D(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.85rem;margin-bottom:.75rem;",e.forEach(o=>{o&&t.appendChild(o)}),t}function j(e,t,o,n,a){const l=document.createElement("div");l.style.flex="1";const i=document.createElement("label");i.htmlFor=t,i.className="form-label",i.textContent=e,i.style.fontSize=".8rem";const r=document.createElement("input");if(r.id=t,r.type=o||"text",r.className="form-input",r.value=n??"",l.appendChild(i),l.appendChild(r),a){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=a,c.style.cssText="font-size:.73rem;margin-top:.35rem;",l.appendChild(c)}return l}function Bn(e,t,o,n){const a=document.createElement("div");a.style.flex="1";const l=document.createElement("label");l.htmlFor=t,l.className="form-label",l.textContent=e,l.style.fontSize=".8rem";const i=document.createElement("select");return i.id=t,i.className="form-select",o.forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===n&&(c.selected=!0),i.appendChild(c)}),a.appendChild(l),a.appendChild(i),a}function Ge(e,t,o){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const a=document.createElement("label");a.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const l=document.createElement("input");return l.id=t,l.type="checkbox",l.checked=o,a.appendChild(l),a.appendChild(document.createTextNode(e)),n.appendChild(a),n}function Fn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.4rem;";const n=document.createElement("p");n.textContent="Options (one per line: value or value:Label)",n.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const a=document.createElement("textarea");return a.id=`fb-options-${t}`,a.className="form-input",a.rows=4,a.placeholder=`yes:Yes
|
|
1
|
+
import{apiRequest as ie}from"/admin/js/api.js";import{makeIconInput as Ae}from"/admin/js/lib/shortcode-modal.js";import{enhancePickerFields as lt}from"/public/js/forms.js";import{buildWizardSteps as Ut}from"/public/js/form-steps.mjs";import{applyFormClasses as at,applySubmitButtons as Jt,applyWizardButtons as Kt,buttonSettingsProblems as Yt,formClassProblems as Xt,resolveSubmitAlign as ot}from"/public/js/form-submit.mjs";import{addBannerAction as Be}from"../lib/plugin-chrome.js";import{helpPopovers as Qt}from"../lib/help-popover.js";import{openMenuAt as it,sidebarCount as Zt}from"../lib/tool-kit.js";import{draftKey as se,draftOf as en,duplicateField as tn,fieldTitle as Fe,fingerprint as st,leavingEditor as rt,moveField as ct,restoreDraft as nn,snapshotOf as Ie}from"../lib/form-editor-arrange.js";import{fmtDateTime as ln}from"../lib/dates.js";const dt=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"chooser",label:"Chooser (visual options)"},{value:"icon",label:"Icon (icon picker)"},{value:"image",label:"Image (media library)"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"password",label:"Password"},{value:"file",label:"File upload"},{value:"hidden",label:"Hidden field"}],Oe=new Set(["select","radio","checkbox-group","chooser"]);let w=[],he=[],B=null,be=null,ne=null,ge={};function I(e,t,o=14){e.textContent="";const n=document.createElement("span");return n.setAttribute("data-icon",t),n.setAttribute("data-icon-size",String(o)),n.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;",e.appendChild(n),window.I?.scan?.(e),e}function re(e,t,o,n=14){return I(e,t,n),e.appendChild(document.createTextNode(" "+o)),e}function ze(e){const t=document.createElement("span");return t.setAttribute("data-icon","help-circle"),t.setAttribute("data-icon-size","12"),t.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;margin-left:.3rem;opacity:.55;cursor:help;",t.title=e,window.I?.scan?.(t),requestAnimationFrame(()=>{try{t.parentNode&&typeof E<"u"&&E.tooltip&&(t.removeAttribute("title"),E.tooltip(t,{content:e,position:"top"}))}catch{}}),t}let ye=null,ut=null,Re=null,ce=null;function Me(){Re?.(),clearTimeout(ut),ut=setTimeout(()=>{ye&&ye()},350)}function pt(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function mt(e){return dt.find(t=>t.value===e)?.label||e}function ft(e){return(e||[]).some(t=>t.logic||Array.isArray(t.triggers)&&t.triggers.length)}function ht(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function an(e){const t={...w[e]};if(t.type==="spacer")return t;if(t.type==="page-break"){const b=document.getElementById(`fb-pb-label-${e}`),k=document.getElementById(`fb-pb-desc-${e}`);return b&&(t.label=b.value.trim()||t.label),k&&(t.description=k.value.trim()),t}const o=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),l=document.getElementById(`fb-type-${e}`),a=document.getElementById(`fb-required-${e}`),i=document.getElementById(`fb-placeholder-${e}`),r=document.getElementById(`fb-helper-${e}`),c=document.getElementById(`fb-tooltip-${e}`);o&&(t.label=o.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),l&&(t.type=l.value||t.type),a&&(t.required=a.checked),i&&(t.placeholder=i.value.trim()),r&&(t.helper=r.value.trim()),c&&(t.tooltip=c.value.trim());const s=document.getElementById(`fb-class-${e}`);if(s){const b=s.value.trim();b?t.class=b:delete t.class}if(t.type==="chooser"){const b=document.getElementById(`fb-chooser-variant-${e}`)?.value;b&&(t.variant=b);const k=document.getElementById(`fb-chooser-multiple-${e}`);k&&(t.multiple=k.checked);const $=document.getElementById(`fb-chooser-density-${e}`)?.value;$&&(t.density=$);const q=document.getElementById(`fb-chooser-columns-${e}`)?.value;q!==""&&q!==void 0&&(t.columns=parseInt(q,10)||3);const z=document.getElementById(`fb-chooser-accent-${e}`)?.value.trim();z?t.accent=z:delete t.accent;const _=document.getElementById(`fb-chooser-accent-style-${e}`)?.value;_?t.accentStyle=_:delete t.accentStyle;const P=document.getElementById(`fb-chooser-glow-${e}`);P&&(t.glow=P.checked);const Z=document.getElementById(`fb-chooser-glow-colour-${e}`)?.value.trim();Z?t.glowColour=Z:delete t.glowColour;const W=document.getElementById(`fb-chooser-shadow-${e}`)?.value;W&&W!=="none"?t.shadow=W:delete t.shadow;const pe=document.getElementById(`fb-chooser-shadow-colour-${e}`)?.value.trim();pe?t.shadowColour=pe:delete t.shadowColour,ke(e),w[e]&&Array.isArray(w[e].options)&&(t.options=w[e].options)}else if(Oe.has(t.type)){["variant","density","columns","accent","accentStyle","glow","glowColour","shadow","shadowColour"].forEach(k=>delete t[k]),t.type!=="checkbox-group"&&t.type!=="multiselect"&&delete t.multiple;const b=document.getElementById(`fb-options-${e}`);b&&(t.options=b.value.split(`
|
|
2
|
+
`).filter(k=>k.trim()).map(k=>{const[$,...q]=k.split(":");return{value:$.trim(),label:q.join(":").trim()||$.trim()}}))}for(const b of["prefix","suffix"]){const k=document.getElementById(`fb-${b}-icon-${e}`),$=document.getElementById(`fb-${b}-text-${e}`),q={...t.formConfig||{}};if(k||$){const z=k?.value.trim()||"",_=$?.value.trim()||"";z&&/^[a-z0-9-]+$/i.test(z)?q[b]={icon:z}:_?q[b]={text:_.slice(0,24)}:delete q[b]}else Bt.includes(t.type)||delete q[b];t.formConfig=Object.keys(q).length?q:void 0}{const b={...t.formConfig||{}};for(const k of Ft){const $=document.getElementById(`fb-extra-${k.key}-${e}`);$&&k.types.includes(t.type)?$.checked?b[k.key]=!0:delete b[k.key]:k.types.includes(t.type)||delete b[k.key]}t.formConfig=Object.keys(b).length?b:void 0}if(t.type==="textarea"){const b=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);b>0&&(t.formConfig={...t.formConfig||{},rows:b})}const u=document.getElementById(`fb-span-${e}`),p=document.getElementById(`fb-fullwidth-${e}`);if(u||p){const b={...t.formConfig||{}};if(p?.checked)b.span="full";else{const k=parseInt(u?.value,10);k>1?b.span=k:delete b.span}t.formConfig=Object.keys(b).length?b:void 0}const m=document.getElementById(`fb-minlength-${e}`)?.value;m&&(t.minLength=parseInt(m,10));const y=document.getElementById(`fb-maxlength-${e}`)?.value;y&&(t.maxLength=parseInt(y,10));const h=document.getElementById(`fb-min-${e}`)?.value;h!==""&&h!==void 0&&(t.min=parseFloat(h));const f=document.getElementById(`fb-max-${e}`)?.value;f!==""&&f!==void 0&&(t.max=parseFloat(f));const T=on(e);T?t.logic=T:delete t.logic;const x=Sn(e);return x?t.triggers=x:delete t.triggers,t}function on(e){const t=document.querySelector(`.fb-field-card[data-index="${e}"]`);if(!t)return;const o=t.querySelector(".fb-field-logic");if(!o)return;const n={};let l=!1;const a=o.querySelector('[data-logic-section="visibility"]');if(a){const s=a.querySelector(".fb-logic-vis-default"),u=a.querySelector(".fb-logic-vis-transition"),p=Array.from(a.querySelectorAll(".fb-logic-cond-row")).map(f=>{const T=f.querySelector(".fb-logic-cond-field"),x=f.querySelector(".fb-logic-cond-op"),b=f.querySelector(".fb-logic-cond-val"),k=f.querySelector(".fb-logic-vis-then");return T?.value?{when:{all:[{field:T.value,operator:x.value,value:b.value}]},then:k.value}:null}).filter(Boolean),m=s?.value||"visible",y=u?.value||"none",h=parseInt(a.querySelector(".fb-logic-vis-duration")?.value||"",10);(m!=="visible"||p.length>0||y!=="none")&&(n.visibility={default:m,conditions:p},y!=="none"&&(n.visibility.transition=y),y!=="none"&&Number.isFinite(h)&&(n.visibility.duration=h),l=!0)}const i=o.querySelector('[data-logic-section="requirement"]');if(i){const s=i.querySelector(".fb-logic-req-default"),u=Array.from(i.querySelectorAll(".fb-logic-cond-row")).map(p=>{const m=p.querySelector(".fb-logic-cond-field"),y=p.querySelector(".fb-logic-cond-op"),h=p.querySelector(".fb-logic-cond-val"),f=p.querySelector(".fb-logic-req-then");return m?.value?{when:{all:[{field:m.value,operator:y.value,value:h.value}]},then:f.value==="true"}:null}).filter(Boolean);u.length>0&&(n.requirement={default:s?.checked===!0,conditions:u},l=!0)}const r=o.querySelector('[data-logic-section="validation"]');if(r){const s=Array.from(r.querySelectorAll(".fb-logic-val-rule")).map(u=>{const p=u.querySelector(".fb-logic-val-type"),m=u.querySelector(".fb-logic-val-pattern"),y=u.querySelector(".fb-logic-val-flags"),h=u.querySelector(".fb-logic-val-message");if(!m?.value.trim())return null;const f=p?.value||"regex",T={type:f,message:h?.value.trim()||"Invalid value."};return f==="regex"?(T.pattern=m.value.trim(),y?.value.trim()&&(T.flags=y.value.trim())):T.field=m.value.trim(),T}).filter(Boolean);s.length>0&&(n.validation=s,l=!0)}const c=o.querySelector('[data-logic-section="cascade"]');if(c){const s=c.querySelector(".fb-logic-cascade-source"),u=c.querySelector(".fb-logic-cascade-mapping"),p=c.querySelector(".fb-logic-cascade-defaults"),m=s?.value?.trim();if(m){let y={};try{y=JSON.parse(u?.value||"{}")}catch{}const h=(p?.value||"").split(`
|
|
3
|
+
`).filter(f=>f.trim()).map(f=>{const[T,...x]=f.split(":");return{value:T.trim(),label:x.join(":").trim()||T.trim()}});n.cascade={sourceField:m,mapping:y,defaultOptions:h},l=!0}}return l?n:void 0}function j(){w=w.map((e,t)=>an(t))}function sn(e){const t=e.firstElementChild;if(!t||t.querySelector(".fb-drag-grip"))return;const o=document.createElement("span");o.className="fb-drag-grip",o.setAttribute("data-icon","grip-vertical"),o.setAttribute("data-icon-size","16"),o.title="Drag to reorder",t.insertBefore(o,t.firstChild),window.I?.scan?.(t)}function X(e){const t=e.find("#fields-list").get(0),o=e.find("#fields-empty-msg").get(0);if(t){if(Array.from(t.querySelectorAll(".fb-field-card")).forEach(n=>n.remove()),w.length===0){o&&(o.style.display=""),ce?.(t),Me();return}o&&(o.style.display="none"),w.forEach((n,l)=>{const a=n.type==="page-break"?rn(n,l,e):n.type==="spacer"?cn(n,l,e):dn(n,l,e);sn(a),t.appendChild(a)}),ce?.(t),Me()}}function rn(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent="- Page Break -",a.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:color-mix(in srgb, var(--dm-text-muted) 20%, transparent);color:var(--dm-text-muted);white-space:nowrap;flex-shrink:0;font-style:italic;";const i=document.createElement("span");i.textContent=e.label||"Untitled Step",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text-muted);";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit step",I(c,"more-horizontal"),c.addEventListener("click",y=>{y.stopPropagation(),u.style.display=u.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove page break",I(s,"x"),s.addEventListener("click",async y=>{y.stopPropagation(),await E.confirm("Remove this page break?")&&(j(),w.splice(t,1),X(o))}),r.appendChild(s),l.appendChild(a),l.appendChild(i),l.appendChild(r),l.addEventListener("click",()=>{u.style.display=u.style.display==="none"?"":"none"});const u=document.createElement("div");u.className="fb-field-body",u.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border);display:none;";const p=D([V("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),V("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),m=p.querySelector(`#fb-pb-label-${t}`);return m&&m.addEventListener("input",()=>{i.textContent=m.value||"Untitled Step"}),u.appendChild(p),n.appendChild(l),n.appendChild(u),n}function cn(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--dm-border);border-radius:6px;margin-bottom:.5rem;background:transparent;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const a=document.createElement("div");a.style.cssText="flex:1;height:1px;background:var(--dm-border);";const i=document.createElement("span");i.textContent="Spacer",i.style.cssText="font-size:.7rem;color:var(--dm-text-muted);white-space:nowrap;padding:0 .4rem;font-style:italic;";const r=document.createElement("div");r.style.cssText="flex:1;height:1px;background:var(--dm-border);";const c=document.createElement("div");c.style.cssText="display:flex;gap:.25rem;flex-shrink:0;";const s=document.createElement("button");return s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove spacer",I(s,"x"),s.addEventListener("click",async u=>{u.stopPropagation(),j(),w.splice(t,1),X(o)}),c.appendChild(s),l.appendChild(a),l.appendChild(i),l.appendChild(r),l.appendChild(c),n.appendChild(l),n}function dn(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);box-shadow:var(--dm-shadow-sm);";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;background:var(--dm-card-header-bg);cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent=mt(e.type),a.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:color-mix(in srgb, var(--dm-primary) 14%, transparent);color:var(--dm-primary);white-space:nowrap;flex-shrink:0;";const i=document.createElement("span");i.textContent=e.label||"(unlabelled)",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit field",I(c,"more-horizontal"),c.addEventListener("click",p=>{p.stopPropagation(),u.style.display=u.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");if(s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove field",I(s,"x"),s.addEventListener("click",async p=>{p.stopPropagation(),await E.confirm("Remove this field?")&&(j(),w.splice(t,1),X(o))}),r.appendChild(s),l.appendChild(a),l.appendChild(i),e.required){const p=document.createElement("span");p.textContent="required",p.style.cssText="font-size:.7rem;color:var(--dm-danger);flex-shrink:0;",l.appendChild(p)}if(ht(e.logic)){const p=document.createElement("span");I(p,"zap"),p.title="Has conditional logic",p.style.cssText="font-size:.75rem;color:var(--dm-primary);flex-shrink:0;",l.appendChild(p)}l.appendChild(r),l.addEventListener("click",()=>{u.style.display=u.style.display==="none"?"":"none"});const u=un(e,t,i);return u.style.display="none",n.appendChild(l),n.appendChild(u),n}function un(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:1rem .9rem;border-top:1px solid var(--dm-border);";const l=D([V("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),V("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),a=D([In("Type",`fb-type-${t}`,dt,e.type||"string"),He("Required",`fb-required-${t}`,e.required||!1)]),i=D([V("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field")]),r=D([V("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field"),V("Tooltip",`fb-tooltip-${t}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),c=D([V("CSS classes",`fb-class-${t}`,"text",e.class||"","Your own class names, separated by spaces, on the field's wrapper - style them in Custom CSS")]),s=e.formConfig?.span,u=D([V("Column Span",`fb-span-${t}`,"number",s&&s!=="full"?String(s):"1","Columns to span (grid only)"),He("Full Width",`fb-fullwidth-${t}`,s==="full")]);u.classList.add("fb-grid-row"),u.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(l),n.appendChild(a),n.appendChild(i),n.appendChild(r),n.appendChild(c),n.appendChild(u);const p=n.querySelector(`#fb-label-${t}`),m=n.querySelector(`#fb-name-${t}`);p&&p.addEventListener("input",()=>{o&&(o.textContent=p.value||"(unlabelled)"),m&&!m.dataset.manuallyEdited&&(m.value=pt(p.value))}),m&&m.addEventListener("input",()=>{m.dataset.manuallyEdited="1"});const y=n.querySelector(`#fb-type-${t}`);y&&y.addEventListener("change",()=>{const f=n.closest(".fb-field-card");if(f){const b=f.querySelector("span");b&&(b.textContent=mt(y.value))}const T=n.querySelector(".fb-field-extras");T&&T.remove();const x=At(y.value,e,t);x&&n.appendChild(x)});const h=At(e.type,e,t);return h&&n.appendChild(h),n.appendChild(bn(e,t)),n.appendChild(wn(e,t)),n}const ve=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],De=new Set(["is_empty","is_not_empty"]),bt={equals:"includes",not_equals:"does not include",contains:"any value contains",not_contains:"no value contains",starts_with:"any value starts with",ends_with:"any value ends with",greater_than:"any value is greater than",less_than:"any value is less than",is_empty:"nothing selected",is_not_empty:"something selected",in:"includes one of (comma sep)",not_in:"includes none of (comma sep)",matches_regex:"any value matches regex"};function _e(e){return!!e&&(e.type==="checkbox-group"||!!e.multiple)}function xe(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--dm-text-muted);margin:0 0 .7rem;text-transform:uppercase;letter-spacing:.06em;",t}function Ce(e,t,o,n,l){const a=document.createElement("div");a.className="fb-logic-cond-row",a.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const i=document.createElement("span");i.textContent="When",i.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const r=document.createElement("select");r.className="form-select fb-logic-cond-field",r.style.cssText="flex:1 1 140px;min-width:140px;",t.forEach(h=>{const f=document.createElement("option");f.value=h.value,f.textContent=h.label,e&&h.value===e.field&&(f.selected=!0),r.appendChild(f)});const c=document.createElement("select");c.className="form-select fb-logic-cond-op",c.style.cssText="flex:1 1 160px;min-width:140px;",ve.forEach(h=>{const f=document.createElement("option");f.value=h.value,f.textContent=h.label,e&&h.value===e.operator&&(f.selected=!0),c.appendChild(f)});const s=()=>{const h=t.find(f=>f.value===r.value);Array.from(c.options).forEach(f=>{const T=ve.find(x=>x.value===f.value);f.textContent=h?.multi&&bt[f.value]||T?.label||f.value})};s(),r.addEventListener("change",s);const u=document.createElement("input");u.type="text",u.className="form-input fb-logic-cond-val",u.placeholder="value",u.style.cssText="flex:1 1 120px;min-width:100px;",u.value=e?.value||"",e&&De.has(e.operator)&&(u.style.display="none"),c.addEventListener("change",()=>{u.style.display=De.has(c.value)?"none":""});const p=document.createElement("span");I(p,"arrow-right"),p.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const m=document.createElement("select");m.className=`form-select ${n}`,m.style.cssText="flex:1 1 140px;min-width:120px;",o.forEach(h=>{const f=document.createElement("option");f.value=h.value,f.textContent=h.label,h.value===l&&(f.selected=!0),m.appendChild(f)});const y=document.createElement("button");return y.type="button",y.className="btn btn-xs btn-ghost",y.style.cssText="line-height:1;opacity:.6;",I(y,"x"),y.style.flexShrink="0",y.addEventListener("click",()=>a.remove()),a.appendChild(i),a.appendChild(r),a.appendChild(c),a.appendChild(u),a.appendChild(p),a.appendChild(m),a.appendChild(y),a}function pn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(xe("Visibility"));const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const a=document.createElement("span");a.textContent="Default:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-vis-default",i.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(x=>{const b=document.createElement("option");b.value=x.value,b.textContent=x.label,x.value===(e.default||"visible")&&(b.selected=!0),i.appendChild(b)}),l.appendChild(a),l.appendChild(i),n.appendChild(l);const r=document.createElement("div");r.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const c=document.createElement("span");c.textContent="Transition:",c.style.cssText="font-size:.8rem;flex-shrink:0;";const s=document.createElement("select");s.className="form-select fb-logic-vis-transition",s.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(x=>{const b=document.createElement("option");b.value=x.value,b.textContent=x.label,x.value===(e.transition||"none")&&(b.selected=!0),s.appendChild(b)}),r.appendChild(c),r.appendChild(s),n.appendChild(r);const u=document.createElement("div");u.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const p=document.createElement("span");p.textContent="Speed:",p.style.cssText="font-size:.8rem;flex-shrink:0;";const m=document.createElement("select");m.className="form-select fb-logic-vis-duration",m.style.cssText="max-width:240px;",[{value:"",label:"Default"},{value:"120",label:"Very fast (120ms)"},{value:"200",label:"Fast (200ms)"},{value:"350",label:"Medium (350ms)"},{value:"600",label:"Slow (600ms)"},{value:"1000",label:"Very slow (1s)"}].forEach(x=>{const b=document.createElement("option");b.value=x.value,b.textContent=x.label,x.value===String(e.duration??"")&&(b.selected=!0),m.appendChild(b)}),u.appendChild(p),u.appendChild(m),n.appendChild(u);const y=()=>{u.style.display=s.value==="none"?"none":""};y(),s.addEventListener("change",y);const h=document.createElement("div");h.className="fb-logic-vis-rules";const f=o.map(x=>({value:x.name,label:x.label||x.name,multi:_e(x)})),T=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(x=>{const b=(x.when?.all||x.when?.any||[])[0],k=x.then==="hidden"?"hidden":"visible";f.length>0&&h.appendChild(Ce(b,f,T,"fb-logic-vis-then",k))}),n.appendChild(h),f.length>0){const x=document.createElement("button");x.type="button",x.className="btn btn-xs btn-ghost",x.style.cssText="font-size:.73rem;margin-top:.35rem;",re(x,"plus","Add visibility rule"),x.addEventListener("click",()=>h.appendChild(Ce(null,f,T,"fb-logic-vis-then","visible"))),n.appendChild(x)}return n}function mn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(xe("Conditional Requirement"));const l=document.createElement("label");l.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8rem;cursor:pointer;margin-bottom:.65rem;";const a=document.createElement("input");a.type="checkbox",a.className="fb-logic-req-default",a.checked=e.default===!0,l.appendChild(a),l.appendChild(document.createTextNode("Required by default")),n.appendChild(l);const i=document.createElement("div");i.className="fb-logic-req-rules";const r=o.map(s=>({value:s.name,label:s.label||s.name,multi:_e(s)})),c=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(s=>{const u=(s.when?.all||s.when?.any||[])[0],p=s.then===!0?"true":"false";r.length>0&&i.appendChild(Ce(u,r,c,"fb-logic-req-then",p))}),n.appendChild(i),r.length>0){const s=document.createElement("button");s.type="button",s.className="btn btn-xs btn-ghost",s.style.cssText="font-size:.73rem;margin-top:.35rem;",re(s,"plus","Add requirement rule"),s.addEventListener("click",()=>i.appendChild(Ce(null,r,c,"fb-logic-req-then","true"))),n.appendChild(s)}return n}function gt(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const o=document.createElement("select");o.className="form-select fb-logic-val-type",o.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===(e?.type||"regex")&&(c.selected=!0),o.appendChild(c)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;";const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-flags",l.placeholder="flags",l.value=e?.flags||"",l.style.cssText="flex:0 0 55px;",e?.type==="match"&&(l.style.display="none"),o.addEventListener("change",()=>{l.style.display=o.value==="match"?"none":"",n.placeholder=o.value==="match"?"field name":"pattern"});const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-val-message",a.placeholder="Error message",a.value=e?.message||"",a.style.cssText="flex:4;";const i=document.createElement("button");return i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="line-height:1;opacity:.6;",I(i,"x"),i.style.flexShrink="0",i.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(l),t.appendChild(a),t.appendChild(i),t}function fn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(xe("Custom Validation"));const l=document.createElement("div");l.className="fb-logic-val-rules",(e||[]).forEach(i=>l.appendChild(gt(i))),n.appendChild(l);const a=document.createElement("button");return a.type="button",a.className="btn btn-xs btn-ghost",a.style.cssText="font-size:.73rem;margin-top:.35rem;",re(a,"plus","Add validation rule"),a.addEventListener("click",()=>l.appendChild(gt(null))),n.appendChild(a),n}function hn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(xe("Cascade Options")),n.lastChild.appendChild(ze("Make this field's options depend on another field. When the source field changes, the options here are replaced by the mapping entry for its value; if nothing matches, the default options below are shown."));const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const a=document.createElement("span");a.textContent="Source field:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-cascade-source",i.style.cssText="flex:1;";const r=document.createElement("option");r.value="",r.textContent="- none -",i.appendChild(r),o.forEach(m=>{const y=document.createElement("option");y.value=m.name,y.textContent=m.label||m.name,m.name===e.sourceField&&(y.selected=!0),i.appendChild(y)}),l.appendChild(a),l.appendChild(i),n.appendChild(l);const c=document.createElement("p");c.textContent='Mapping JSON - {"value":[{"value":"...","label":"..."}]}',c.appendChild(ze(`Each key is a value of the source field; its list becomes this field's options when that value is picked. Example: {"uk":[{"value":"london","label":"London"}]} shows London when the source is "uk".`)),c.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const s=document.createElement("textarea");s.className="form-input fb-logic-cascade-mapping",s.rows=4,s.style.cssText="font-family:monospace;",s.placeholder='{"uk": [{"value": "london", "label": "London"}]}',s.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(c),n.appendChild(s);const u=document.createElement("p");u.textContent="Default options (one per line: value:Label)",u.appendChild(ze("Shown before the source field has a value, or when its value has no mapping entry.")),u.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const p=document.createElement("textarea");return p.className="form-input fb-logic-cascade-defaults",p.rows=3,p.style.cssText="font-family:monospace;",p.placeholder=`option1:Option 1
|
|
4
|
+
option2:Option 2`,p.value=(e.defaultOptions||[]).map(m=>{const y=typeof m=="string"?m:m.value??"",h=typeof m=="string"?m:m.label??y;return y===h?y:`${y}:${h}`}).join(`
|
|
5
|
+
`),n.appendChild(u),n.appendChild(p),n}function bn(e,t){const o=e.logic||{},n=w.filter((p,m)=>m!==t&&p.type!=="page-break"&&p.type!=="spacer"),l=document.createElement("div");l.className="fb-field-logic",l.style.cssText="margin-top:.75rem;border-top:1px solid var(--dm-border);padding-top:.5rem;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const i=document.createElement("span");i.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted);",i.textContent="\u26A1 Conditional Logic";const r=ht(o),c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",I(c,r?"chevron-down":"chevron-right",12);const s=document.createElement("div");s.className="fb-logic-body",s.style.cssText="padding:.25rem 0 .25rem;"+(r?"":"display:none;"),a.addEventListener("click",()=>{const p=s.style.display==="none";s.style.display=p?"":"none",I(c,p?"chevron-down":"chevron-right",12)}),a.appendChild(i),a.appendChild(c),l.appendChild(a),s.appendChild(pn(o.visibility||{},t,n)),s.appendChild(mn(o.requirement||{},t,n)),s.appendChild(fn(o.validation||[],t,n));const u=document.getElementById(`fb-type-${t}`)?.value||e.type;return Oe.has(u)&&s.appendChild(hn(o.cascade||{},t,n)),l.appendChild(s),l}const de=[{value:"banner",label:"Show a banner",kind:"state",params:["message","level","position","dismissible"],placeholder:"e.g. You must be 18 or over to continue."},{value:"toast",label:"Show a toast",kind:"event",params:["message","level"],placeholder:"e.g. Thanks - carry on."},{value:"hide-fields",label:"Hide fields",kind:"state",params:["target"]},{value:"disable-fields",label:"Disable fields",kind:"state",params:["target"]},{value:"require-fields",label:"Make fields required",kind:"state",params:["target"]},{value:"block-submit",label:"Block submission",kind:"state",params:["message"],messageLabel:"Reason, shown under the button",placeholder:'Blank: "This form cannot be submitted yet."'},{value:"end-form",label:"End the form here",kind:"state",params:["message","finish","finishLabel","doneMessage","record"],messageLabel:"Message shown in place of the rest",placeholder:"e.g. Sorry - you must be 18 or over to apply."},{value:"goto-step",label:"Jump to a wizard step",kind:"event",params:["step"]},{value:"redirect",label:"Redirect after submit",kind:"event",params:["url"]},{value:"celebrate",label:"Celebrate",kind:"event",params:["theme","intensity"]},{value:"run-action",label:"Run a CMS action",kind:"event",params:["slug"]},{value:"notify",label:"Notify the admins",kind:"event",params:["message","level"],messageLabel:"Notification title",placeholder:"Blank: titled after the form",noOnce:!0,kindText:"when the form is submitted"}],Ee=[{value:"info",label:"Info"},{value:"success",label:"Success"},{value:"warning",label:"Warning"},{value:"error",label:"Error"}],yt=[{value:"field-below",label:"Below this field"},{value:"field-above",label:"Above this field"},{value:"form-top",label:"Top of the form"}],vt=[{value:"rest",label:"The rest of the form"},{value:"all",label:"Every other field"},{value:"listed",label:"Chosen fields"}],xt=[{value:"auto",label:"Whatever is in season"},{value:"christmas",label:"Christmas"},{value:"halloween",label:"Halloween"},{value:"valentines",label:"Valentine's Day"},{value:"guy-fawkes",label:"Guy Fawkes Night"},{value:"st-patricks",label:"St Patrick's Day"},{value:"st-andrews",label:"St Andrew's Day"},{value:"st-davids",label:"St David's Day"},{value:"st-georges",label:"St George's Day"}];function Ct(e,t=!1){const o=(i,r)=>({value:i.name,label:`${i.label||i.name}${r?" (this field)":""}`,multi:_e(i)}),n=i=>i&&i.type!=="page-break"&&i.type!=="spacer"&&i.name,l=w.filter((i,r)=>r!==e&&n(i)).map(i=>o(i,!1)),a=w[e];return t&&n(a)?[o(a,!0),...l]:l}function J(e,t,o){const n=document.createElement("select");return n.className=`form-select ${e}`,t.forEach(l=>{const a=document.createElement("option");a.value=l.value,a.textContent=l.label,l.value===o&&(a.selected=!0),n.appendChild(a)}),n}function le(e,t,o){const n=document.createElement("input");return n.type="text",n.className=`form-input ${e}`,n.value=t==null?"":String(t),o&&(n.placeholder=o),n}function Pe(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-remove",t&&(o.title=t,o.setAttribute("aria-label",t)),I(o,"x"),o.addEventListener("click",n=>{n.stopPropagation(),e()}),o}function G(e,t,{full:o=!1,hint:n=""}={}){const l=document.createElement("label");l.className=`fb-trig-f${o?" fb-trig-f--full":""}`;const a=document.createElement("span");if(a.className="fb-trig-f-label",a.textContent=e,l.appendChild(a),l.appendChild(t),n){const i=document.createElement("span");i.className="fb-trig-f-hint",i.textContent=n,l.appendChild(i)}return l}function ue(e,t,o,n){const l=document.createElement("label");l.className="fb-trig-check",n&&(l.title=n);const a=document.createElement("input");return a.type="checkbox",a.className=`form-check ${e}`,a.checked=!!t,l.appendChild(a),l.appendChild(document.createTextNode(o)),l}function Et(e,t){const o=document.createElement("div");o.className="fb-trig-cond-row";const n=J("fb-trig-cond-field",t,e?.field),l=J("fb-trig-cond-op",ve,e?.operator),a=le("fb-trig-cond-val",e?.value,"value"),i=()=>{const c=t.find(s=>s.value===n.value);Array.from(l.options).forEach(s=>{const u=ve.find(p=>p.value===s.value);s.textContent=c?.multi&&bt[s.value]||u?.label||s.value})},r=()=>{a.hidden=De.has(l.value)};return i(),r(),n.addEventListener("change",i),l.addEventListener("change",r),o.appendChild(n),o.appendChild(l),o.appendChild(a),o.appendChild(Pe(()=>o.remove(),"Remove condition")),o}const wt=["banner","toast","block-submit","end-form"],kt=["password","file","image","signature"],gn="Put an answer in with {{field_name}} - e.g. Hello {{name}}. Pick one from Insert field.";function yn(){try{j()}catch{}return w.filter(e=>e&&e.name&&e.type!=="page-break"&&e.type!=="spacer"&&!kt.includes(e.type))}function St(e,t,o){const n=le(e,t,o),l=document.createElement("span");l.className="fb-token-row";const a=document.createElement("select");a.className="form-input fb-token-pick",a.title="Insert an answer into the message",a.setAttribute("aria-label","Insert a field's answer into the message");const i=()=>{a.replaceChildren(new Option("Insert field",""));for(const r of yn())a.appendChild(new Option(`${r.label||r.name} ({{${r.name}}})`,r.name))};return i(),a.addEventListener("focus",i),a.addEventListener("mousedown",i),a.addEventListener("change",()=>{const r=a.value;if(a.value="",!r)return;const c=`{{${r}}}`,s=n.selectionStart??n.value.length,u=n.selectionEnd??s;n.value=n.value.slice(0,s)+c+n.value.slice(u),n.focus(),n.setSelectionRange(s+c.length,s+c.length),n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}),l.append(n,a),l}function vn(e){const t=window.FormLogicEngine;if(!t?.triggerTokens)return[];const o=new Map((e||[]).filter(l=>l&&l.name).map(l=>[l.name,l])),n=new Set;for(const l of e||[])for(const a of l?.triggers||[])for(const i of[...a.then||[],...a.otherwise||[]])if(wt.includes(i?.type))for(const r of[...t.triggerTokens(i.message),...t.triggerTokens(i.doneMessage)]){const c=o.get(r);(!c||kt.includes(c.type))&&n.add(r)}return[...n]}function Tt(e,t){const o=document.createElement("div");o.className="fb-trig-params";const n=de.find(c=>c.value===(e.type||"banner"));if(!n)return o;const l=document.createElement("div");l.className="fb-trig-grid";const a=document.createElement("div");a.className="fb-trig-opts";const i=[];for(const c of n.params)switch(c){case"message":l.appendChild(wt.includes(n.value)?G(n.messageLabel||"Message",St("fb-trig-p-message",e.message,n.placeholder||""),{full:!0,hint:gn}):G(n.messageLabel||"Message",le("fb-trig-p-message",e.message,n.placeholder||""),{full:!0}));break;case"finish":a.appendChild(ue("fb-trig-p-finish-on",e.finish!==!1,"Let the visitor finish (send the answers given so far)",'Untick to stop the form dead: the submit button is disabled and nothing is sent, so nothing is saved and "Notify the admins" cannot fire.'));break;case"finishLabel":{const s=G("Button text",le("fb-trig-p-finish",e.finishLabel,"Finish"));i.push(s),l.appendChild(s);break}case"doneMessage":{const s=G("Closing message",St("fb-trig-p-done",e.doneMessage,"Blank: the form's own success message"));i.push(s),l.appendChild(s);break}case"record":{const s=ue("fb-trig-p-record",e.record!==!1,"Save the answers given so far",`Untick to keep nothing: no submission is stored and the form's email, webhook and actions do not run. A "Notify the admins" action still fires.`);i.push(s),a.appendChild(s);break}case"level":l.appendChild(G(n.value==="notify"?"Severity":"Level",J("fb-trig-p-level",Ee,e.level||"info")));break;case"position":l.appendChild(G("Where",J("fb-trig-p-position",yt,e.position||"field-below")));break;case"dismissible":a.appendChild(ue("fb-trig-p-dismissible",e.dismissible!==!1,"The visitor can dismiss it"));break;case"target":{const s=J("fb-trig-p-target",vt,e.target||(e.fields?.length?"listed":"rest")),u=document.createElement("select");u.className="form-select fb-trig-p-fields",u.multiple=!0,u.size=4;const p=new Set(e.fields||[]);Ct(t).forEach(h=>{const f=document.createElement("option");f.value=h.value,f.textContent=h.label,p.has(h.value)&&(f.selected=!0),u.appendChild(f)});const m=G("Fields",u,{hint:"Ctrl/Cmd-click to pick several"}),y=()=>{m.hidden=s.value!=="listed"};y(),s.addEventListener("change",y),l.appendChild(G("Which fields",s)),l.appendChild(m);break}case"step":{const s=le("fb-trig-p-step",e.step,"0");s.type="number",s.min="0",l.appendChild(G("Step",s,{hint:"Counting from 0"}));break}case"url":l.appendChild(G("Send them to",le("fb-trig-p-url",e.url,"/thank-you"),{full:!0}));break;case"theme":l.appendChild(G("Theme",J("fb-trig-p-theme",xt,e.theme||"auto")));break;case"intensity":l.appendChild(G("Intensity",J("fb-trig-p-intensity",[{value:"low",label:"Low"},{value:"medium",label:"Medium"},{value:"high",label:"High"}],e.intensity||"medium")));break;case"slug":{const s=[{value:"",label:he.length?"Choose an action":"No actions available"}].concat(he.map(u=>({value:u.slug,label:u.title||u.slug})));l.appendChild(G("Action",J("fb-trig-p-slug",s,e.slug||""),{full:!0}));break}default:break}n.kind==="event"&&!n.noOnce&&a.appendChild(ue("fb-trig-p-once",!!e.once,"Only once","Fire the first time only, rather than every time the answer swings back."));const r=a.querySelector(".fb-trig-p-finish-on");if(r){const c=()=>i.forEach(s=>{s.hidden=!r.checked});c(),r.addEventListener("change",c)}return l.children.length&&o.appendChild(l),a.children.length&&o.appendChild(a),o}function xn(e){return e?.kindText?e.kindText:e?.kind==="event"?"once, when it becomes true":"while it is true"}const Cn=(e,t=48)=>e.length>t?`${e.slice(0,t-1)}\u2026`:e,ae=(e,t)=>e.find(o=>o.value===t)?.label||t;function En(e){if(!e)return"";const t=[],o=l=>l?`"${Cn(l)}"`:"",n=()=>e.target==="listed"?e.fields?.length?e.fields.join(", "):"no fields chosen":ae(vt,e.target||"rest").toLowerCase();switch(e.type){case"banner":t.push(o(e.message)||"No message yet",ae(Ee,e.level||"info"),ae(yt,e.position||"field-below").toLowerCase());break;case"toast":t.push(o(e.message)||"No message yet",ae(Ee,e.level||"info"));break;case"hide-fields":case"disable-fields":case"require-fields":t.push(n());break;case"block-submit":t.push(o(e.message)||"the standard reason");break;case"end-form":t.push(o(e.message)||"no message"),e.finish===!1?t.push("submit disabled"):t.push(`button "${e.finishLabel||"Finish"}"`,e.record===!1?"saves nothing":"saves the answers");break;case"goto-step":t.push(Number.isFinite(e.step)?`step ${e.step}`:"no step yet");break;case"redirect":t.push(e.url||"no address yet");break;case"celebrate":t.push(ae(xt,e.theme||"auto"),`${e.intensity||"medium"} intensity`);break;case"run-action":t.push(e.slug?he.find(l=>l.slug===e.slug)?.title||e.slug:"no action chosen");break;case"notify":t.push(o(e.message)||"titled after the form",ae(Ee,e.level||"info"));break;default:break}return e.once&&t.push("only once"),t.filter(Boolean).join(" \xB7 ")}function je(e,t,{open:o=!1}={}){const n=document.createElement("div");n.className="fb-trig-action-row";const l=document.createElement("div");l.className="fb-trig-action-head",l.tabIndex=0,l.setAttribute("role","button");const a=document.createElement("span");a.className="fb-trig-chevron";const i=document.createElement("span");i.className="fb-trig-action-main";const r=document.createElement("strong"),c=document.createElement("small");c.className="fb-trig-action-summary",i.append(r,c);const s=document.createElement("span");s.className="fb-trig-kind",l.append(a,i,s,Pe(()=>n.remove(),"Remove action"));const u=document.createElement("div");u.className="fb-trig-action-body";const p=J("fb-trig-action-type",de,e.type||"banner");u.appendChild(G("Action",p,{full:!0})),u.appendChild(Tt(e,t));const m=()=>{const h=de.find(f=>f.value===p.value);r.textContent=h?.label||p.value,s.textContent=xn(h),s.classList.toggle("fb-trig-kind--event",h?.kind==="event"),c.textContent=En(qt(n))},y=h=>{u.hidden=!h,n.classList.toggle("is-open",h),l.setAttribute("aria-expanded",String(h)),I(a,h?"chevron-down":"chevron-right",12)};return l.addEventListener("click",()=>y(u.hidden)),l.addEventListener("keydown",h=>{h.target!==l||h.key!=="Enter"&&h.key!==" "||(h.preventDefault(),y(u.hidden))}),p.addEventListener("change",()=>{const h=Tt({type:p.value},t);u.replaceChild(h,u.querySelector(".fb-trig-params")),m(),window.I?.scan?.()}),u.addEventListener("input",m),u.addEventListener("change",m),n.append(l,u),y(o),m(),n}function Nt(e,t,o){const n=document.createElement("section");n.className=`fb-trig-sec fb-trig-sec--${e}`;const l=document.createElement("div");l.className="fb-trig-sec-head";const a=document.createElement("span");if(a.className="fb-trig-sec-title",a.textContent=t,l.appendChild(a),o){const i=document.createElement("span");i.className="fb-trig-sec-hint",i.textContent=o,l.appendChild(i)}return n.appendChild(l),n}function Ve(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-add",re(o,"plus",e,12),o.addEventListener("click",t),o}function Lt(e,t,o,n){const a=Nt(e,t,e==="then"?"What happens while the answers match.":"What happens while they do not. Leave empty for nothing.");a.classList.add("fb-trig-branch"),a.dataset.branch=e;const i=document.createElement("div");return i.className="fb-trig-action-list",(o||[]).forEach(r=>i.appendChild(je(r,n))),a.appendChild(i),a.appendChild(Ve("Add action",()=>{i.appendChild(je({type:"banner"},n,{open:!0})),window.I?.scan?.()})),a}function $t(e,t,o){const n=Ct(t,!0),l=document.createElement("div");l.className="fb-trig-card",l.dataset.triggerId=e.id||`trg-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;const a=document.createElement("div");a.className="fb-trig-card-head";const i=document.createElement("span");i.className="fb-trig-card-title",i.textContent=`Trigger ${o+1}`,a.appendChild(i);const r=ue("fb-trig-enabled",e.enabled!==!1,"Enabled","Untick to keep the trigger but switch it off.");if(a.appendChild(r),a.appendChild(Pe(()=>l.remove(),"Remove trigger")),l.appendChild(a),!n.length){const p=document.createElement("p");return p.className="fb-trig-empty",p.textContent="Give this field a name first - a trigger tests an answer, and it needs something to test.",l.appendChild(p),l}const c=Nt("when","When");c.querySelector(".fb-trig-sec-head").appendChild(J("fb-trig-match",[{value:"all",label:"all of these are true"},{value:"any",label:"any of these is true"}],Array.isArray(e.when?.any)?"any":"all"));const s=document.createElement("div");s.className="fb-trig-cond-list";const u=e.when?.all||e.when?.any||[];return(u.length?u:[{}]).forEach(p=>s.appendChild(Et(p,n))),c.appendChild(s),c.appendChild(Ve("Add condition",()=>{s.appendChild(Et({},n)),window.I?.scan?.()})),l.appendChild(c),l.appendChild(Lt("then","Then",e.then,t)),l.appendChild(Lt("otherwise","Otherwise",e.otherwise,t)),l}function wn(e,t){const o=Array.isArray(e.triggers)?e.triggers:[],n=document.createElement("div");n.className="fb-field-triggers";const l=document.createElement("div");l.className="fb-trig-panel-head";const a=document.createElement("span");a.className="fb-trig-panel-title",a.textContent=`\u{1F3AF} Triggers${o.length?` (${o.length})`:""}`;const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",I(i,o.length?"chevron-down":"chevron-right",12);const r=document.createElement("div");r.className="fb-triggers-body",r.hidden=!o.length,l.addEventListener("click",()=>{r.hidden=!r.hidden,I(i,r.hidden?"chevron-right":"chevron-down",12)});const c=document.createElement("p");c.className="fb-trig-blurb",c.textContent="Do something to the form when the answers meet a condition - show a banner or toast, hide, disable or require other fields, refuse the submit, end the form early, notify the admins, jump to a step, or celebrate.",r.appendChild(c);const s=document.createElement("div");return s.className="fb-trig-list",o.forEach((u,p)=>s.appendChild($t(u,t,p))),r.appendChild(s),r.appendChild(Ve("Add trigger",()=>{const u=$t({enabled:!0,then:[]},t,s.children.length);s.appendChild(u),u.querySelector('.fb-trig-branch[data-branch="then"] .fb-trig-action-list')?.appendChild(je({type:"banner"},t,{open:!0})),window.I?.scan?.()})),l.appendChild(a),l.appendChild(i),n.appendChild(l),n.appendChild(r),n}function qt(e){const t=e.querySelector(".fb-trig-action-type")?.value,o=de.find(a=>a.value===t);if(!o)return null;const n={type:t},l=a=>e.querySelector(a)?.value?.trim()||"";for(const a of o.params)switch(a){case"message":n.message=l(".fb-trig-p-message");break;case"finishLabel":{const i=l(".fb-trig-p-finish");i&&(n.finishLabel=i);break}case"doneMessage":{const i=l(".fb-trig-p-done");i&&(n.doneMessage=i);break}case"finish":e.querySelector(".fb-trig-p-finish-on")?.checked||(n.finish=!1);break;case"record":e.querySelector(".fb-trig-p-record")?.checked||(n.record=!1);break;case"level":n.level=l(".fb-trig-p-level")||"info";break;case"position":n.position=l(".fb-trig-p-position")||"field-below";break;case"dismissible":n.dismissible=!!e.querySelector(".fb-trig-p-dismissible")?.checked;break;case"target":{const i=l(".fb-trig-p-target")||"rest";n.target=i,i==="listed"&&(n.fields=Array.from(e.querySelectorAll(".fb-trig-p-fields option")).filter(r=>r.selected).map(r=>r.value));break}case"step":{const i=parseInt(l(".fb-trig-p-step"),10);Number.isFinite(i)&&(n.step=i);break}case"url":n.url=l(".fb-trig-p-url");break;case"theme":n.theme=l(".fb-trig-p-theme")||"auto";break;case"intensity":n.intensity=l(".fb-trig-p-intensity")||"medium";break;case"slug":n.slug=l(".fb-trig-p-slug");break;default:break}return o.kind==="event"&&!o.noOnce&&e.querySelector(".fb-trig-p-once")?.checked&&(n.once=!0),n}function kn(e){const t=qt(e);if(!t)return null;const o=de.find(a=>a.value===t.type),n=t.type,l=["block-submit","end-form","notify"].includes(o.value);return o.params.includes("message")&&!t.message&&!l?(delete t.message,null):(l&&!t.message&&delete t.message,n==="redirect"&&!t.url||n==="run-action"&&!t.slug?null:t)}function Sn(e){const o=document.querySelector(`.fb-field-card[data-index="${e}"]`)?.querySelector(".fb-field-triggers");if(!o)return;const n=[];return o.querySelectorAll(".fb-trig-card").forEach(l=>{const a=Array.from(l.querySelectorAll(".fb-trig-cond-row")).map(p=>{const m=p.querySelector(".fb-trig-cond-field")?.value,y=p.querySelector(".fb-trig-cond-op")?.value;if(!m||!y)return null;const h=p.querySelector(".fb-trig-cond-val")?.value??"";return{field:m,operator:y,value:h}}).filter(Boolean);if(!a.length)return;const i=p=>Array.from(l.querySelectorAll(`.fb-trig-branch[data-branch="${p}"] .fb-trig-action-row`)).map(kn).filter(Boolean),r=i("then"),c=i("otherwise");if(!r.length&&!c.length)return;const s=l.querySelector(".fb-trig-match")?.value==="any"?"any":"all",u={id:l.dataset.triggerId,enabled:!!l.querySelector(".fb-trig-enabled")?.checked,when:{[s]:a}};r.length&&(u.then=r),c.length&&(u.otherwise=c),n.push(u)}),n.length?n:void 0}function At(e,t,o){const n=document.createElement("div");return n.className="fb-field-extras",e==="chooser"?(n.appendChild(Ln(t,o)),n.appendChild(qn(t.options||[],o))):(Oe.has(e)&&n.appendChild(On(t.options||[],o)),e==="textarea"&&n.appendChild(D([V("Rows",`fb-rows-${o}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(D([V("Min Length",`fb-minlength-${o}`,"number",t.minLength||"",""),V("Max Length",`fb-maxlength-${o}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(D([V("Min",`fb-min-${o}`,"number",t.min??"",""),V("Max",`fb-max-${o}`,"number",t.max??"","")]))),Bt.includes(e)&&n.appendChild(Nn(t,o)),n.children.length?n:null}const Bt=["string","email","tel","number","url","date","time","password","select","textarea"],Ft=[{key:"reveal",label:"Show / hide button",types:["password"],hint:"Show / hide lets the visitor see what they typed."},{key:"clear",label:"Clear button",types:["string","email","tel","url","textarea"],hint:"Clear adds an x that empties the field."},{key:"stepper",label:"- / + buttons",types:["number"],hint:"The - and + buttons step the number within its min, max and step."},{key:"counter",label:"Character counter",types:["string","textarea"],hint:"The counter shows how many characters are used, against Max Length if one is set."}];function Tn(e){return e?typeof e=="string"?{icon:"",text:e}:{icon:e.icon||"",text:e.icon?"":e.text??""}:{icon:"",text:""}}function Nn(e,t){const o=document.createElement("div");o.className="fb-addons";const n=(i,r)=>{const c=Tn(e.formConfig?.[i]),s=document.createElement("div");s.style.flex="1";const u=document.createElement("span");u.className="form-label",u.style.fontSize=".8rem",u.textContent=r;const p=Ae("Icon, e.g. search",c.icon);p.input.id=`fb-${i}-icon-${t}`,p.input.setAttribute("aria-label",`${r}: icon`);const m=document.createElement("input");return m.type="text",m.className="form-input",m.id=`fb-${i}-text-${t}`,m.value=c.text,m.placeholder="or text, e.g. \xA3 or kg",m.maxLength=24,m.setAttribute("aria-label",`${r}: text`),m.style.marginTop=".35rem",p.input.addEventListener("input",()=>{p.input.value.trim()&&(m.value="")}),m.addEventListener("input",()=>{m.value.trim()&&(p.input.value="")}),s.append(u,p.el,m),s};o.appendChild(D([n("prefix","Before the field"),n("suffix","After the field")]));const l=document.createElement("p");l.className="form-hint text-muted",l.style.cssText="font-size:.73rem;margin:-.4rem 0 .75rem;",l.textContent="An icon or a short text joined to the start or end of the input, like \xA3 before a price or kg after a weight. Leave both empty for none.",o.appendChild(l);const a=Ft.filter(i=>i.types.includes(e.type));if(a.length){o.appendChild(D(a.map(r=>He(r.label,`fb-extra-${r.key}-${t}`,!!e.formConfig?.[r.key]))));const i=document.createElement("p");i.className="form-hint text-muted",i.style.cssText="font-size:.73rem;margin:-.4rem 0 .75rem;",i.textContent=a.map(r=>r.hint).join(" "),o.appendChild(i)}return o}function It(e){const t=document.createElement("div");t.className="fb-chooser-section",t.style.cssText="border:1px solid var(--dm-border); border-radius:6px; margin-top:.5rem; overflow:hidden;";const o=document.createElement("div");o.style.cssText="padding:.4rem .6rem; background:color-mix(in srgb, var(--dm-background) 60%, transparent); font-weight:600; font-size:.82rem; border-bottom:1px solid var(--dm-border);",o.textContent=e,t.appendChild(o);const n=document.createElement("div");return n.className="fb-chooser-section-body",n.style.cssText="padding:.55rem .6rem; display:flex; flex-direction:column; gap:.45rem;",t.appendChild(n),{wrap:t,body:n}}function we(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem";const r=document.createElement("select");if(r.id=e,r.className="form-input",n.forEach(([c,s])=>{const u=document.createElement("option");u.value=c,u.textContent=s,String(c)===String(o)&&(u.selected=!0),r.appendChild(u)}),a.appendChild(i),a.appendChild(r),l){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=l,c.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(c)}return a}function Ot(e,t,o,n){const l=document.createElement("div");l.style.flex="1";const a=document.createElement("label");a.style.cssText="display:inline-flex;align-items:center;gap:.4rem;font-size:.82rem;";const i=document.createElement("input");if(i.id=e,i.type="checkbox",i.checked=!!o,a.appendChild(i),a.appendChild(document.createTextNode(" "+t)),l.appendChild(a),n){const r=document.createElement("p");r.className="form-hint text-muted",r.textContent=n,r.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(r)}return l}function Ge(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem",a.appendChild(i);const r=document.createElement("div");r.style.cssText="display:flex;gap:.4rem;align-items:stretch;";const c=document.createElement("input");c.id=e,c.type="text",c.className="form-input",c.value=o||"",n&&(c.placeholder=n),c.style.flex="1";const s=document.createElement("input");s.type="color",s.title="Pick a colour",s.style.cssText="width:36px;height:auto;padding:0;border:1px solid var(--dm-border);border-radius:4px;cursor:pointer;";const u=String(c.value).match(/^#[0-9a-fA-F]{3,8}$/);if(s.value=u?c.value:"#000000",s.addEventListener("input",()=>{c.value=s.value,c.dispatchEvent(new Event("input",{bubbles:!0}))}),r.appendChild(c),r.appendChild(s),a.appendChild(r),l){const p=document.createElement("p");p.className="form-hint text-muted",p.textContent=l,p.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(p)}return a}function Ln(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const n=It("Layout");n.body.appendChild(D([we(`fb-chooser-variant-${t}`,"Variant",e.variant||"card",[["card","Card - rich tiles"],["chip","Chip - compact pills"]],"Card supports description and grid columns; chips wrap."),Ot(`fb-chooser-multiple-${t}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),n.body.appendChild(D([we(`fb-chooser-density-${t}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),V("Columns",`fb-chooser-columns-${t}`,"number",e.columns||3,"Card grid (1-6). Ignored for chips.")])),o.appendChild(n.wrap);const l=It("Visual");return l.body.appendChild(D([Ge(`fb-chooser-accent-${t}`,"Accent",e.accent||"","primary / success / #ec4899","Selected highlight colour - semantic name or any CSS colour."),we(`fb-chooser-accent-style-${t}`,"Accent style",e.accentStyle||"border",[["border","Border (default)"],["solid","Solid"],["glow","Glow"],["overlay","Overlay"],["underline","Underline"]],"Visual treatment of the selected state.")])),l.body.appendChild(D([Ot(`fb-chooser-glow-${t}`,"Glow on selected",!!e.glow,"Soft outer glow."),Ge(`fb-chooser-glow-colour-${t}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),l.body.appendChild(D([we(`fb-chooser-shadow-${t}`,"Shadow",e.shadow||"none",[["none","None"],["sm","Small"],["md","Medium"],["lg","Large"],["xl","Extra Large"]],"Drop shadow on every option."),Ge(`fb-chooser-shadow-colour-${t}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),o.appendChild(l.wrap),o}function $n(e,t,o,n){const l=document.createElement("div");l.className="fb-chooser-option-row",l.dataset.optIdx=String(o),l.style.cssText="border:1px solid var(--dm-border); border-radius:4px; padding:.5rem; background:var(--dm-background-alt); display:flex; flex-direction:column; gap:.35rem;";const a=document.createElement("div");a.style.cssText="display:flex; gap:.4rem; align-items:center;";const i=document.createElement("div");i.style.cssText="display:flex; flex-direction:column; gap:1px;";const r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",r.title="Move up",I(r,"arrow-up"),r.addEventListener("click",P=>{P.preventDefault(),zt(t,o,-1,n)});const c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",c.title="Move down",I(c,"arrow-down"),c.addEventListener("click",P=>{P.preventDefault(),zt(t,o,1,n)}),i.appendChild(r),i.appendChild(c),a.appendChild(i);const s=document.createElement("input");s.type="text",s.className="form-input fb-chooser-opt-value",s.placeholder="value",s.value=e.value||"",s.style.flex="1",a.appendChild(s);const u=document.createElement("input");u.type="text",u.className="form-input fb-chooser-opt-label",u.placeholder="label (visible to users)",u.value=e.label||"",u.style.flex="2",a.appendChild(u);const p=document.createElement("button");p.type="button",p.className="btn btn-xs btn-ghost",p.style.cssText="line-height:1;opacity:.6;",p.title="Remove option",I(p,"x"),p.addEventListener("click",P=>{P.preventDefault(),Fn(t,o,n)}),a.appendChild(p),l.appendChild(a);const m=document.createElement("div");m.style.cssText="display:flex; gap:.4rem;";const y=Ae("icon name (optional)",e.icon||"");y.input.classList.add("fb-chooser-opt-icon"),y.el.style.flex="1",m.appendChild(y.el);const h=document.createElement("input");h.type="text",h.className="form-input fb-chooser-opt-description",h.placeholder="description (card + comfortable only)",h.value=e.description||"",h.style.flex="2",m.appendChild(h),l.appendChild(m);const f=document.createElement("div");f.style.cssText="display:flex; gap:.4rem;";const T=document.createElement("input");T.type="text",T.className="form-input fb-chooser-opt-tooltip",T.placeholder="tooltip (hover hint)",T.value=e.tooltip||"",T.style.flex="2",f.appendChild(T);const x=document.createElement("input");x.type="text",x.className="form-input fb-chooser-opt-badge-text",x.placeholder="badge text",x.value=e.badge?.text||"",x.style.flex="1",f.appendChild(x);const b=document.createElement("select");b.className="form-input fb-chooser-opt-badge-type",b.style.flex="1",[["","no badge"],["primary","primary"],["success","success"],["info","info"],["warning","warning"],["danger","danger"]].forEach(([P,Z])=>{const W=document.createElement("option");W.value=P,W.textContent=Z,(e.badge?.type||"")===P&&(W.selected=!0),b.appendChild(W)}),f.appendChild(b),l.appendChild(f);const k=document.createElement("div");k.style.cssText="display:flex; gap:1rem; font-size:.8rem;";const $=document.createElement("label");$.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const q=document.createElement("input");q.type="checkbox",q.className="fb-chooser-opt-recommended",q.checked=!!e.recommended,$.appendChild(q),$.appendChild(document.createTextNode(" Recommended")),k.appendChild($);const z=document.createElement("label");z.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const _=document.createElement("input");return _.type="checkbox",_.className="fb-chooser-opt-disabled",_.checked=!!e.disabled,z.appendChild(_),z.appendChild(document.createTextNode(" Disabled")),k.appendChild(z),l.appendChild(k),l}function qn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem;";const n=document.createElement("div");n.style.cssText="display:flex; align-items:center; justify-content:space-between; margin-bottom:.4rem;";const l=document.createElement("p");l.textContent="Options",l.style.cssText="font-size:.85rem;font-weight:600;margin:0;",n.appendChild(l);const a=document.createElement("button");a.type="button",a.className="btn btn-xs btn-ghost",re(a,"plus","Add option"),n.appendChild(a),o.appendChild(n);const i=document.createElement("div");i.className="fb-chooser-options-list",i.id=`fb-chooser-options-${t}`,i.style.cssText="display:flex; flex-direction:column; gap:.4rem;",o.appendChild(i);const r=()=>{i.replaceChildren();const c=An(t);(c.length?c:e||[]).forEach((u,p)=>{i.appendChild($n(u,t,p,r))})};return a.addEventListener("click",c=>{c.preventDefault(),Bn(t,r)}),r(),o}function An(e){const t=w[e];return!t||!Array.isArray(t.options)?[]:t.options}function We(e){return w[e]?(Array.isArray(w[e].options)||(w[e].options=[]),w[e].options):[]}function Bn(e,t){ke(e),We(e).push({value:"new",label:"New option"}),t()}function Fn(e,t,o){ke(e),We(e).splice(t,1),o()}function zt(e,t,o,n){ke(e);const l=We(e),a=t+o;if(a<0||a>=l.length)return;const[i]=l.splice(t,1);l.splice(a,0,i),n()}function ke(e){const t=document.getElementById(`fb-chooser-options-${e}`);if(!t)return;const o=t.querySelectorAll(".fb-chooser-option-row"),n=[];o.forEach(l=>{const a={value:l.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:l.querySelector(".fb-chooser-opt-label")?.value.trim()||""},i=l.querySelector(".fb-chooser-opt-icon")?.value.trim();i&&(a.icon=i);const r=l.querySelector(".fb-chooser-opt-description")?.value.trim();r&&(a.description=r);const c=l.querySelector(".fb-chooser-opt-tooltip")?.value.trim();c&&(a.tooltip=c);const s=l.querySelector(".fb-chooser-opt-badge-text")?.value.trim(),u=l.querySelector(".fb-chooser-opt-badge-type")?.value;(s||u)&&(a.badge={},s&&(a.badge.text=s),u&&(a.badge.type=u)),l.querySelector(".fb-chooser-opt-recommended")?.checked&&(a.recommended=!0),l.querySelector(".fb-chooser-opt-disabled")?.checked&&(a.disabled=!0),n.push(a)}),w[e]&&(w[e].options=n)}function D(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.85rem;margin-bottom:.75rem;",e.forEach(o=>{o&&t.appendChild(o)}),t}function V(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=t,i.className="form-label",i.textContent=e,i.style.fontSize=".8rem";const r=document.createElement("input");if(r.id=t,r.type=o||"text",r.className="form-input",r.value=n??"",a.appendChild(i),a.appendChild(r),l){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=l,c.style.cssText="font-size:.73rem;margin-top:.35rem;",a.appendChild(c)}return a}function In(e,t,o,n){const l=document.createElement("div");l.style.flex="1";const a=document.createElement("label");a.htmlFor=t,a.className="form-label",a.textContent=e,a.style.fontSize=".8rem";const i=document.createElement("select");return i.id=t,i.className="form-select",o.forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===n&&(c.selected=!0),i.appendChild(c)}),l.appendChild(a),l.appendChild(i),l}function He(e,t,o){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const l=document.createElement("label");l.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const a=document.createElement("input");return a.id=t,a.type="checkbox",a.checked=o,l.appendChild(a),l.appendChild(document.createTextNode(e)),n.appendChild(l),n}function On(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.4rem;";const n=document.createElement("p");n.textContent="Options (one per line: value or value:Label)",n.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const l=document.createElement("textarea");return l.id=`fb-options-${t}`,l.className="form-input",l.rows=4,l.placeholder=`yes:Yes
|
|
6
6
|
no:No
|
|
7
|
-
maybe:Maybe`,
|
|
8
|
-
`),a.style.fontFamily="monospace",o.appendChild(n),o.appendChild(a),o}function ke(e){return parseInt(e,10)===3?3:2}const In=[["#setting-submit-icon-start-slot","setting-submit-icon-start"],["#setting-submit-icon-end-slot","setting-submit-icon-end"],["#setting-second-icon-start-slot","setting-second-icon-start"],["#setting-second-icon-end-slot","setting-second-icon-end"]];function On(e){In.forEach(([t,o])=>{const n=e.find(t).get(0);if(!n||n.querySelector(`#${o}`))return;const a=$e("none","");a.input.id=o,a.input.classList.add("form-input"),n.appendChild(a.el)})}function Ot(e){const t=e.find("#setting-second-kind").val()||"",o=e.find("#second-button-group").get(0);o&&(o.style.display=t?"":"none");const n=e.find("#second-url-group").get(0);n&&(n.style.display=t==="link"?"":"none");const a=e.find("#setting-second-label").get(0);a&&(a.placeholder=t==="link"?"Cancel":"Clear form")}function zn(e){const t=l=>String(e.find(l).val()||"").trim(),o={},n={style:t("#setting-submit-style")||"primary",size:t("#setting-submit-size"),iconStart:t("#setting-submit-icon-start"),iconEnd:t("#setting-submit-icon-end")};(n.style!=="primary"||n.size||n.iconStart||n.iconEnd)&&(o.submitButton=n);const a=t("#setting-second-kind");return(a==="reset"||a==="link")&&(o.secondaryButton={kind:a,label:t("#setting-second-label"),...a==="link"?{url:t("#setting-second-url")}:{},style:t("#setting-second-style")||"secondary",iconStart:t("#setting-second-icon-start"),iconEnd:t("#setting-second-icon-end"),first:t("#setting-second-order")==="first",stack:t("#setting-second-arrange")==="stack"}),o}function zt(e,t){const o=t&&t.submitButton||{},n=t&&t.secondaryButton||{};e.find("#setting-submit-style").val(o.style||"primary"),e.find("#setting-submit-size").val(o.size||""),e.find("#setting-submit-icon-start").val(o.iconStart||""),e.find("#setting-submit-icon-end").val(o.iconEnd||""),e.find("#setting-second-kind").val(n.kind==="reset"||n.kind==="link"?n.kind:""),e.find("#setting-second-label").val(n.label||""),e.find("#setting-second-url").val(n.url||""),e.find("#setting-second-style").val(n.style||"secondary"),e.find("#setting-second-icon-start").val(n.iconStart||""),e.find("#setting-second-icon-end").val(n.iconEnd||""),e.find("#setting-second-order").val(n.first?"first":"after"),e.find("#setting-second-arrange").val(n.stack?"stack":"row"),Ot(e)}function Se(e){const t=e.find("#field-project").val()||"";return _(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},meta:{...be||{},project:t||null},fields:w,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"grid",columns:ke(e.find("#setting-columns").val()),submitAlign:e.find("#setting-submit-align").val()||"",...zn(e),honeypot:e.find("#setting-honeypot").prop("checked"),rateLimitPerMinute:parseInt(e.find("#setting-rate-limit").val(),10)||3,successRedirect:e.find("#setting-success-redirect").val().trim()||null,actionSlug:e.find("#action-cms-slug").val()||null},actions:{email:{enabled:e.find("#action-email-enabled").prop("checked"),recipients:e.find("#action-email-recipients").val().trim(),subjectPrefix:e.find("#action-email-subject-prefix").val().trim()},webhook:{enabled:e.find("#action-webhook-enabled").prop("checked"),url:e.find("#action-webhook-url").val().trim(),method:e.find("#action-webhook-method").val()},...he!==null&&{collection:he}}}}function Rt(e,t){const o={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const a={...n.formConfig||{}};a.span==="full"&&t&&(a.span=t);const l=n.type==="chooser"||!!(n.variant&&["select","radio","checkbox-group"].includes(n.type)),r={type:n.type==="checkbox"?"boolean":n.type==="date"||n.type==="icon"||n.type==="image"?"string":l?"chooser":n.type,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{helperText:n.helper},...n.tooltip&&{tooltip:n.tooltip},...a}};l&&(n.variant&&(r.variant=n.variant),(n.multiple||n.type==="checkbox-group")&&(r.multiple=!0),n.density&&(r.density=n.density),n.columns&&(r.columns=n.columns),n.accent&&(r.accent=n.accent),n.accentStyle&&(r.accentStyle=n.accentStyle),n.glow&&(r.glow=!0),n.glowColour&&(r.glowColour=n.glowColour),n.shadow&&(r.shadow=n.shadow),n.shadowColour&&(r.shadowColour=n.shadowColour)),o[n.name]=r}),o}function Mt(e,t){const o=typeof e=="string"?document.querySelector(e):e;o&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const a=o.querySelector(`[name="${n.name}"]`);a&&a.type!=="date"&&(a.type="date")})}function Dt(e,t){const o=e?.querySelector?.(".dm-plugin-banner-name .dm-plugin-banner-sep");if(o){for(;o.nextSibling;)o.nextSibling.remove();o.after(document.createTextNode(String(t||"")))}}const Rn=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");let G=null,_t=0,Pt=!1;const Te=e=>String(e||"").split("?")[0].replace(/\/$/,"");function Mn(){Pt||!window.R?.use||(Pt=!0,R.use((e,t,o)=>!G||!it(t?.path,e?.path)||G.path!==Te(t?.path)||(G.flush(),!G.dirty())?o():E.confirm("You have unsaved changes to this form. Leave anyway? They are kept as a draft for your next visit to it.").then(n=>{n?o():history.replaceState(null,"",`#${t.path}`)})),M.subscribe("router:afterChange",({to:e,from:t}={})=>{if(G&&G.path===Te(t?.path)&&it(t?.path,e?.path)){const o=G;G=null,o.dispose()}}))}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){if(Mn(),G){const u=G;G=null,u.dispose()}const t=Te(location.hash.replace(/^#/,"")),o=++_t,n=()=>o!==_t||!e.get(0)?.isConnected||Te(location.hash.replace(/^#/,""))!==t;w=[],A=null,he=null,On(e),e.find("#setting-second-kind").get(0)?.addEventListener("change",()=>Ot(e));const a=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);A=a?a[1]:null;let l=null;const i=E.loader(e.get(0),{type:"dots"});if(A)try{if(l=await ie(`/forms/${A}`),n()){i.destroy();return}w=l.fields||[],he=l.actions?.collection??null}catch{if(n()){i.destroy();return}E.toast("Could not load form.",{type:"error"})}be={};try{const u=await ie("/projects").catch(()=>[]);if(n()){i.destroy();return}const v=e.find("#field-project").get(0);v&&(Array.isArray(u)?u:[]).forEach(g=>{const C=document.createElement("option");C.value=g.slug,C.textContent=g.name||g.slug,v.appendChild(C)})}catch{}if(i.destroy(),Dt(e.get(0),l?l.title||l.slug:"New form"),A||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(dt(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),l){e.find("#field-title").val(l.title),e.find("#field-slug").val(l.slug),e.find("#field-description").val(l.description||""),e.find("#field-bundled").prop("checked",!!l.bundled),be=l.meta||{},e.find("#field-project").val(l.meta?.project||"");const u=l.settings||{};e.find("#setting-submit-text").val(u.submitText||"Submit"),e.find("#setting-success-message").val(u.successMessage||""),e.find("#setting-layout").val(u.layout||"grid"),e.find("#setting-columns").val(ke(u.columns)),e.find("#setting-submit-align").val(at(u,u.layout||"grid")),zt(e,u),e.find("#columns-group").get(0).style.display=(u.layout||"grid")==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",u.honeypot!==!1),e.find("#setting-rate-limit").val(u.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(u.successRedirect||"");const v=l.actions?.email||{};e.find("#action-email-enabled").prop("checked",v.enabled||!1),e.find("#action-email-recipients").val(v.recipients||""),e.find("#action-email-subject-prefix").val(v.subjectPrefix||"");const g=l.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",g.enabled||!1),e.find("#action-webhook-url").val(g.url||""),e.find("#action-webhook-method").val(g.method||"POST")}const r=l?.settings?.actionSlug||"";try{const u=await ie("/actions").catch(()=>[]);if(n())return;const v=e.find("#action-cms-slug").get(0);if(fe=Array.isArray(u)?u:[],(Array.isArray(u)?u:[]).forEach(g=>{const C=document.createElement("option");C.value=g.slug,C.textContent=g.title||g.slug,g.slug===r&&(C.selected=!0),v.appendChild(C)}),!u.length){const g=document.createElement("option");g.value="",g.textContent="No actions available",g.disabled=!0,v.appendChild(g)}}catch{}const c=u=>{e.find("#columns-group").get(0).style.display=u?"":"none",document.querySelectorAll(".fb-grid-row").forEach(v=>{v.style.display=u?"flex":"none"})};e.find("#setting-layout").get(0)?.addEventListener("change",function(){c(this.value==="grid")}),c(e.find("#setting-layout").val()==="grid"),X(e);const s=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",u=>{u.stopPropagation(),s.style.display=s.style.display==="none"?"":"none"}),ne&&document.removeEventListener("click",ne),ne=()=>{s&&(s.style.display="none")},document.addEventListener("click",ne),e.find("#add-field-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),_();const u=w.length;w.push({name:`field_${u+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),X(e);const v=e.find("#fields-list").get(0)?.lastElementChild;if(v){const g=v.querySelector(".fb-field-body");g&&(g.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),_(),w.push({type:"spacer"}),X(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),_();const u=w.filter(v=>v.type==="page-break").length+2;w.push({type:"page-break",label:`Step ${u}`,description:""}),X(e)}),ge=()=>{const u=Se(e),v=e.find("#preview-container").get(0);if(!v)return;const g=e.find("#preview-test-result").get(0),C=e.find("#preview-test-badge").get(0);g&&(g.style.display="none",g.textContent=""),C&&(C.style.display=A?"":"none"),e.find("#preview-card").get(0).style.display="",v.textContent="";const T=document.createElement("div");T.id="fb-preview-form",v.appendChild(T);const H=A?async q=>{g&&(g.style.display="none",g.textContent="");try{const $=await fetch(`/api/forms/submit/${A}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(q)}),Y=await $.json();if(!$.ok)throw new Error(Y.error||"Submission failed.");g&&(g.textContent=Y.message||u.settings?.successMessage||"Submitted successfully.",g.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-success) 12%, transparent);color:var(--dm-success);"),E.toast("Test submission stored.",{type:"success"})}catch($){g&&(g.textContent=$.message,g.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-danger) 12%, transparent);color:var(--dm-danger);"),E.toast($.message,{type:"error"})}return!1}:()=>!1,pe=u.fields.some(q=>q.type==="page-break");if(T.addEventListener("click",q=>{const $=q.target.closest?.("a.fb-secondary-btn");$&&(q.preventDefault(),E.toast(`Cancel takes the visitor to ${$.getAttribute("href")}`,{type:"info"}))}),T.addEventListener("dm-form-end",q=>{const $=q.detail?.validation;if($&&!$.valid){E.toast(`Still to answer: ${$.missing.map(Y=>Y.label).concat($.errors).join(", ")}`,{type:"warning"});return}H(q.detail?.values||{})}),typeof F<"u"){const q=ke(u.settings?.columns),$=u.settings?.layout||"grid";if(pe&&F.wizard){const Y=Ht(u.fields,u.title),me=Y.map(te=>({title:te.title,description:te.description,fields:Rt(te.fields,q)}));let U=0,Z=null,Le=null;const et=te=>{const tt=(Y[U]||{}).fields||[];Jt(T,u.settings),Mt("#fb-preview-form",tt),nt(T,tt),te&&window.FormLogicEngine&&pt(u.fields)&&(Z?.destroy?.(),Z=new window.FormLogicEngine.FormLogicRuntime({fields:u.fields},T,{baseValues:Le?.getStepData?Le.getStepData():{}}),Z.init())};Le=F.wizard("#fb-preview-form",{schema:{steps:me},layout:$,columns:q,finishText:u.settings?.submitText||"Finish",onStepChange:te=>{U=te,queueMicrotask(()=>et(!0))},onSubmit:H}),et(!1)}else if(F.render){const Y=Rt(u.fields,q),me={};u.fields.forEach(U=>{if(!(!U.name||U.type==="page-break"||U.type==="spacer")&&(U.type==="select"||U.type==="multiselect")&&U.required){const Z=(U.options||[])[0];Z&&(me[U.name]=typeof Z=="object"?Z.value:Z)}}),F.render("#fb-preview-form",Y,me,{submitText:u.settings?.submitText||"Submit",layout:$,columns:q,onSubmit:H}),Ut(T,u.settings,$),Mt("#fb-preview-form",u.fields),nt(T,u.fields)}window.FormLogicEngine&&pt(u.fields)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:u.fields},T).init()})}else{const q=document.createElement("p");q.textContent=`${u.fields.filter($=>$.type!=="page-break").length} field(s): ${u.fields.filter($=>$.type!=="page-break").map($=>$.label).join(", ")}`,q.style.cssText="color:var(--dm-text-muted);font-style:italic;",T.appendChild(q)}},ge();const d=e.find("#editor-tabs").get(0),p=e.find("#preview-card").get(0),f=u=>{p&&p.contains(u.target)||ze()};d&&(d.addEventListener("input",f),d.addEventListener("change",f));const y=e.get(0),h=[],b=u=>(h.push(u),u);let k=!1;const m=M.observable(!1),x=M.observable(!1);let N=A,L=Se(e),I=Be(L),O=L;const V=()=>{k||!y.isConnected||(O=Se(e),m.value=Be(O)!==I)};let z=null;Oe=()=>{clearTimeout(z),z=setTimeout(V,150)},b(()=>{clearTimeout(z),Oe=null,ce=null});const Q=u=>{const v=u.settings||{};e.find("#field-title").val(u.title||""),e.find("#field-slug").val(u.slug||""),e.find("#field-description").val(u.description||""),e.find("#field-bundled").prop("checked",!!u.bundled),be={...u.meta||{}},e.find("#field-project").val(u.meta?.project||""),e.find("#setting-submit-text").val(v.submitText||"Submit"),e.find("#setting-success-message").val(v.successMessage||""),e.find("#setting-layout").val(v.layout||"grid"),e.find("#setting-columns").val(ke(v.columns)),e.find("#setting-submit-align").val(at(v,v.layout||"grid")),zt(e,v),e.find("#setting-honeypot").prop("checked",v.honeypot!==!1),e.find("#setting-rate-limit").val(v.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(v.successRedirect||""),e.find("#action-cms-slug").val(v.actionSlug||"");const g=u.actions?.email||{};e.find("#action-email-enabled").prop("checked",!!g.enabled),e.find("#action-email-recipients").val(g.recipients||""),e.find("#action-email-subject-prefix").val(g.subjectPrefix||"");const C=u.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",!!C.enabled),e.find("#action-webhook-url").val(C.url||""),e.find("#action-webhook-method").val(C.method||"POST"),w=JSON.parse(JSON.stringify(u.fields||[])),c((v.layout||"grid")==="grid"),X(e)};async function W(){if(x.peek()||k)return;const u=Se(e);if(!u.title){E.toast("Please enter a form title (Form Details).",{type:"error"});return}const v=Kt(u.settings);if(v.length){E.toast(`${v[0]} (Settings > Submit Button)`,{type:"error"});return}const g=gn(u.fields);g.length&&E.toast(`Some trigger messages use ${g.map(T=>`{{${T}}}`).join(", ")}, which will show as blank: no field has that name, or it is a password, file or image.`,{type:"warning",duration:9e3}),x.value=!0;const C=A;try{A?(await ie(`/forms/${A}`,{method:"PUT",body:JSON.stringify(u)}),E.toast("Form saved.",{type:"success"})):(A=(await ie("/forms",{method:"POST",body:JSON.stringify(u)})).slug,E.toast("Form created.",{type:"success"})),N=A,L=u,I=Be(u),O=u,m.value=!1;for(const T of new Set([se(C),se(A)]))try{S.remove?S.remove(T):S.set(T,null)}catch{}Dt(y,u.title),Xt("#/forms"),C||R.navigate(`/forms/edit/${A}`)}catch(T){C||(A=null),E.toast(T.message||"Failed to save form.",{type:"error"})}finally{x.value=!1}}async function jt(){m.peek()&&(!await E.confirm("Discard the changes you have not saved?")||k||(Q(L),V(),Xe()))}const We=y.querySelector(".fex-bar");if(We){const u=M.applyBindings({dirty:m,saving:x},We,{methods:{save:W,discard:jt}});b(()=>u.dispose())}b(Yt(y,{position:"bottom"})),qe(e,{id:"form-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>W()}),qe(e,{id:"form-editor-back",icon:"arrow-left",title:"All forms",onClick:()=>{location.hash="#/forms"}}),A&&qe(e,{id:"form-editor-subs",icon:"list",title:"Submissions",onClick:()=>{location.hash=`#/forms/${encodeURIComponent(A)}/submissions`}});const He=u=>{n()||!(u.ctrlKey||u.metaKey)||String(u.key).toLowerCase()!=="s"||(u.preventDefault(),u.stopImmediatePropagation(),W())};document.addEventListener("keydown",He,!0),b(()=>document.removeEventListener("keydown",He,!0));const K=e.find("#fields-list").get(0),Vt=u=>u?.closest?.(".fb-field-card"),Ue=u=>Number(u?.dataset.index),Je=u=>u?.querySelector(":scope > .fb-field-body"),Ke=u=>{const v=Je(u);v&&(v.style.display=v.style.display==="none"?"":"none")},oe=(u,v)=>{w=u,X(e),v!=null&&K?.querySelectorAll(".fb-field-card")[v]?.focus()},Gt=async u=>{try{await navigator.clipboard.writeText(u),E.toast(`Copied "${u}".`,{type:"success"})}catch{E.toast(`Copy failed - the name is ${u}.`,{type:"info"})}},Wt=u=>{const v=Vt(u),g=Ue(v);_();const C=w[g];if(!C)return[];const T=C.type!=="spacer"&&C.type!=="page-break",H=Je(v),pe=H&&H.style.display!=="none";return[{header:Ae(C)},...H?[{label:pe?"Close":"Edit",icon:pe?"chevron-up":"edit",action:()=>Ke(v)}]:[],...T?[{label:"Logic & triggers",icon:"zap",action:()=>{H&&(H.style.display=""),(H?.querySelector(".fb-field-logic")||H)?.scrollIntoView({block:"center",behavior:"smooth"})}}]:[],{label:"Duplicate",icon:"copy",action:()=>{_(),oe(Zt(w,g),g+1)}},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:g===0,action:()=>{_(),oe(st(w,g,-1),g-1)}},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:g>=w.length-1,action:()=>{_(),oe(st(w,g,1),g+1)}},...T&&C.name?[{label:"Copy field name",icon:"clipboard",action:()=>Gt(C.name)}]:[],{type:"divider"},{label:"Delete\u2026",icon:"trash",danger:!0,action:async()=>{if(C.type!=="spacer"&&!await E.confirm(`Remove "${Rn(Ae(C))}"?`))return;_();const q=[...w];q.splice(g,1),oe(q,Math.min(g,q.length-1))}}]};if(K&&typeof E.sortable=="function"){const u=E.sortable(K,{items:".fb-field-card",handle:".fb-drag-grip",key:null,onSort:({from:v,to:g})=>{_();const C=[...w],[T]=C.splice(v,1);C.splice(g,0,T),oe(C,g)}});b(()=>u.destroy())}let Ye=null;if(K&&E.contextMenu&&(Ye=E.contextMenu(K,{cursor:"glyph",match:".fb-field-card > :first-child",inherit:!1,density:"compact",items:u=>Wt(u)}),b(()=>Ye?.destroy?.())),ce=u=>{for(const v of u.querySelectorAll(".fb-field-card")){v.tabIndex=0;const g=v.firstElementChild;if(!g||g.querySelector(".fex-kebab"))continue;const C=document.createElement("button");C.type="button",C.className="fex-kebab",C.textContent="\u22EE",C.title="Actions",_(),C.setAttribute("aria-label",`Actions for ${Ae(w[Ue(v)])}`),C.addEventListener("click",T=>{T.stopPropagation(),lt(C)}),g.appendChild(C)}},K){ce(K);const u=v=>{const g=v.target?.classList?.contains("fb-field-card")?v.target:null;g&&(v.key==="F10"&&v.shiftKey?(v.preventDefault(),lt(g.firstElementChild)):v.key==="Enter"&&(v.preventDefault(),Ke(g)))};K.addEventListener("keydown",u),b(()=>K.removeEventListener("keydown",u))}const Xe=()=>{try{const u=se(N);S.remove?S.remove(u):S.set(u,null)}catch{}},Qe=u=>{if(!m.peek()||!u){Xe();return}try{S.set(se(N),{data:Qt(u),base:ot(I),at:new Date().toISOString()})}catch{}},Ze=u=>{V(),m.peek()&&(Qe(O),u.preventDefault(),u.returnValue="")};window.addEventListener("beforeunload",Ze),b(()=>window.removeEventListener("beforeunload",Ze)),b(()=>{ne&&(document.removeEventListener("click",ne),ne=null)}),G={path:t,dirty:()=>m.peek(),flush:()=>{clearTimeout(z),V()},dispose(){k||(Qe(O),k=!0,h.splice(0).reverse().forEach(u=>{try{u?.()}catch{}}))}};const Ne=se(A);let ee=null;try{ee=S.get(Ne)}catch{}if(ee?.data){try{S.remove?S.remove(Ne):S.set(Ne,null)}catch{}const u=ee.base&&ee.base!==ot(I),v=ee.at?` (${tn(ee.at)})`:"";await E.confirm(`You left unsaved changes to this form${v}.${u?" The saved form has changed since then.":""} Pick up where you left off?`)&&!k&&(Q(en(ee.data,L)),V())}}};
|
|
7
|
+
maybe:Maybe`,l.value=(e||[]).map(a=>{const i=typeof a=="string"?a:a.value??"",r=typeof a=="string"?a:a.label??i;return i===r?i:`${i}:${r}`}).join(`
|
|
8
|
+
`),l.style.fontFamily="monospace",o.appendChild(n),o.appendChild(l),o}function Se(e){return parseInt(e,10)===3?3:2}const zn=[["#setting-submit-icon-start-slot","setting-submit-icon-start"],["#setting-submit-icon-end-slot","setting-submit-icon-end"],["#setting-second-icon-start-slot","setting-second-icon-start"],["#setting-second-icon-end-slot","setting-second-icon-end"]];function Rn(e){zn.forEach(([t,o])=>{const n=e.find(t).get(0);if(!n||n.querySelector(`#${o}`))return;const l=Ae("none","");l.input.id=o,l.input.classList.add("form-input"),n.appendChild(l.el)})}function Rt(e){const t=e.find("#setting-second-kind").val()||"",o=e.find("#second-button-group").get(0);o&&(o.style.display=t?"":"none");const n=e.find("#second-url-group").get(0);n&&(n.style.display=t==="link"?"":"none");const l=e.find("#setting-second-label").get(0);l&&(l.placeholder=t==="link"?"Cancel":"Clear form")}function Mn(e){const t=a=>String(e.find(a).val()||"").trim(),o={},n={style:t("#setting-submit-style")||"primary",size:t("#setting-submit-size"),iconStart:t("#setting-submit-icon-start"),iconEnd:t("#setting-submit-icon-end")};(n.style!=="primary"||n.size||n.iconStart||n.iconEnd)&&(o.submitButton=n);const l=t("#setting-second-kind");return(l==="reset"||l==="link")&&(o.secondaryButton={kind:l,label:t("#setting-second-label"),...l==="link"?{url:t("#setting-second-url")}:{},style:t("#setting-second-style")||"secondary",iconStart:t("#setting-second-icon-start"),iconEnd:t("#setting-second-icon-end"),first:t("#setting-second-order")==="first",stack:t("#setting-second-arrange")==="stack"}),o}function Mt(e,t){const o=t&&t.submitButton||{},n=t&&t.secondaryButton||{};e.find("#setting-submit-style").val(o.style||"primary"),e.find("#setting-submit-size").val(o.size||""),e.find("#setting-submit-icon-start").val(o.iconStart||""),e.find("#setting-submit-icon-end").val(o.iconEnd||""),e.find("#setting-second-kind").val(n.kind==="reset"||n.kind==="link"?n.kind:""),e.find("#setting-second-label").val(n.label||""),e.find("#setting-second-url").val(n.url||""),e.find("#setting-second-style").val(n.style||"secondary"),e.find("#setting-second-icon-start").val(n.iconStart||""),e.find("#setting-second-icon-end").val(n.iconEnd||""),e.find("#setting-second-order").val(n.first?"first":"after"),e.find("#setting-second-arrange").val(n.stack?"stack":"row"),Rt(e)}function Te(e){const t=e.find("#field-project").val()||"";return j(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},meta:{...ge||{},project:t||null},fields:w,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"grid",columns:Se(e.find("#setting-columns").val()),submitAlign:e.find("#setting-submit-align").val()||"",...Mn(e),...e.find("#setting-form-class").val().trim()&&{class:e.find("#setting-form-class").val().trim()},...e.find("#setting-submit-class").val().trim()&&{submitClass:e.find("#setting-submit-class").val().trim()},honeypot:e.find("#setting-honeypot").prop("checked"),rateLimitPerMinute:parseInt(e.find("#setting-rate-limit").val(),10)||3,successRedirect:e.find("#setting-success-redirect").val().trim()||null,actionSlug:e.find("#action-cms-slug").val()||null},actions:{email:{enabled:e.find("#action-email-enabled").prop("checked"),recipients:e.find("#action-email-recipients").val().trim(),subjectPrefix:e.find("#action-email-subject-prefix").val().trim()},webhook:{enabled:e.find("#action-webhook-enabled").prop("checked"),url:e.find("#action-webhook-url").val().trim(),method:e.find("#action-webhook-method").val()},...be!==null&&{collection:be}}}}function Dt(e,t){const o={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const l={...n.formConfig||{}};l.span==="full"&&t&&(l.span=t);const a=n.type==="chooser"||!!(n.variant&&["select","radio","checkbox-group"].includes(n.type)),r={type:n.type==="checkbox"?"boolean":n.type==="date"||n.type==="icon"||n.type==="image"?"string":a?"chooser":n.type,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{helperText:n.helper},...n.tooltip&&{tooltip:n.tooltip},...l}};a&&(n.variant&&(r.variant=n.variant),(n.multiple||n.type==="checkbox-group")&&(r.multiple=!0),n.density&&(r.density=n.density),n.columns&&(r.columns=n.columns),n.accent&&(r.accent=n.accent),n.accentStyle&&(r.accentStyle=n.accentStyle),n.glow&&(r.glow=!0),n.glowColour&&(r.glowColour=n.glowColour),n.shadow&&(r.shadow=n.shadow),n.shadowColour&&(r.shadowColour=n.shadowColour)),o[n.name]=r}),o}function _t(e,t){const o=typeof e=="string"?document.querySelector(e):e;o&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const l=o.querySelector(`[name="${n.name}"]`);l&&l.type!=="date"&&(l.type="date")})}function Pt(e,t){const o=e?.querySelector?.(".dm-plugin-banner-name .dm-plugin-banner-sep");if(o){for(;o.nextSibling;)o.nextSibling.remove();o.after(document.createTextNode(String(t||"")))}}const Dn=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");let H=null,jt=0,Vt=!1;const Ne=e=>String(e||"").split("?")[0].replace(/\/$/,"");function _n(){Vt||!window.R?.use||(Vt=!0,R.use((e,t,o)=>!H||!rt(t?.path,e?.path)||H.path!==Ne(t?.path)||(H.flush(),!H.dirty())?o():E.confirm("You have unsaved changes to this form. Leave anyway? They are kept as a draft for your next visit to it.").then(n=>{n?o():history.replaceState(null,"",`#${t.path}`)})),M.subscribe("router:afterChange",({to:e,from:t}={})=>{if(H&&H.path===Ne(t?.path)&&rt(t?.path,e?.path)){const o=H;H=null,o.dispose()}}))}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){if(_n(),H){const d=H;H=null,d.dispose()}const t=Ne(location.hash.replace(/^#/,"")),o=++jt,n=()=>o!==jt||!e.get(0)?.isConnected||Ne(location.hash.replace(/^#/,""))!==t;w=[],B=null,be=null,Rn(e),e.find("#setting-second-kind").get(0)?.addEventListener("change",()=>Rt(e));const l=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);B=l?l[1]:null;let a=null;const i=E.loader(e.get(0),{type:"dots"});if(B)try{if(a=await ie(`/forms/${B}`),n()){i.destroy();return}w=a.fields||[],be=a.actions?.collection??null}catch{if(n()){i.destroy();return}E.toast("Could not load form.",{type:"error"})}ge={};try{const d=await ie("/projects").catch(()=>[]);if(n()){i.destroy();return}const g=e.find("#field-project").get(0);g&&(Array.isArray(d)?d:[]).forEach(v=>{const C=document.createElement("option");C.value=v.slug,C.textContent=v.name||v.slug,g.appendChild(C)})}catch{}if(i.destroy(),Pt(e.get(0),a?a.title||a.slug:"New form"),B||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(pt(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),a){e.find("#field-title").val(a.title),e.find("#field-slug").val(a.slug),e.find("#field-description").val(a.description||""),e.find("#field-bundled").prop("checked",!!a.bundled),ge=a.meta||{},e.find("#field-project").val(a.meta?.project||"");const d=a.settings||{};e.find("#setting-submit-text").val(d.submitText||"Submit"),e.find("#setting-success-message").val(d.successMessage||""),e.find("#setting-layout").val(d.layout||"grid"),e.find("#setting-columns").val(Se(d.columns)),e.find("#setting-submit-align").val(ot(d,d.layout||"grid")),Mt(e,d),e.find("#setting-form-class").val(d.class||""),e.find("#setting-submit-class").val(d.submitClass||""),e.find("#columns-group").get(0).style.display=(d.layout||"grid")==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",d.honeypot!==!1),e.find("#setting-rate-limit").val(d.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(d.successRedirect||"");const g=a.actions?.email||{};e.find("#action-email-enabled").prop("checked",g.enabled||!1),e.find("#action-email-recipients").val(g.recipients||""),e.find("#action-email-subject-prefix").val(g.subjectPrefix||"");const v=a.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",v.enabled||!1),e.find("#action-webhook-url").val(v.url||""),e.find("#action-webhook-method").val(v.method||"POST")}const r=a?.settings?.actionSlug||"";try{const d=await ie("/actions").catch(()=>[]);if(n())return;const g=e.find("#action-cms-slug").get(0);if(he=Array.isArray(d)?d:[],(Array.isArray(d)?d:[]).forEach(v=>{const C=document.createElement("option");C.value=v.slug,C.textContent=v.title||v.slug,v.slug===r&&(C.selected=!0),g.appendChild(C)}),!d.length){const v=document.createElement("option");v.value="",v.textContent="No actions available",v.disabled=!0,g.appendChild(v)}}catch{}const c=d=>{e.find("#columns-group").get(0).style.display=d?"":"none",document.querySelectorAll(".fb-grid-row").forEach(g=>{g.style.display=d?"flex":"none"})};e.find("#setting-layout").get(0)?.addEventListener("change",function(){c(this.value==="grid")}),c(e.find("#setting-layout").val()==="grid"),X(e);const s=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",d=>{d.stopPropagation(),s.style.display=s.style.display==="none"?"":"none"}),ne&&document.removeEventListener("click",ne),ne=()=>{s&&(s.style.display="none")},document.addEventListener("click",ne),e.find("#add-field-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),j();const d=w.length;w.push({name:`field_${d+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),X(e);const g=e.find("#fields-list").get(0)?.lastElementChild;if(g){const v=g.querySelector(".fb-field-body");v&&(v.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),j(),w.push({type:"spacer"}),X(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),j();const d=w.filter(g=>g.type==="page-break").length+2;w.push({type:"page-break",label:`Step ${d}`,description:""}),X(e)}),ye=()=>{const d=Te(e),g=e.find("#preview-container").get(0);if(!g)return;const v=e.find("#preview-test-result").get(0),C=e.find("#preview-test-badge").get(0);v&&(v.style.display="none",v.textContent=""),C&&(C.style.display=B?"":"none"),e.find("#preview-card").get(0).style.display="",g.textContent="";const N=document.createElement("div");N.id="fb-preview-form",g.appendChild(N);const O=B?async A=>{v&&(v.style.display="none",v.textContent="");try{const L=await fetch(`/api/forms/submit/${B}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(A)}),Y=await L.json();if(!L.ok)throw new Error(Y.error||"Submission failed.");v&&(v.textContent=Y.message||d.settings?.successMessage||"Submitted successfully.",v.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-success) 12%, transparent);color:var(--dm-success);"),E.toast("Test submission stored.",{type:"success"})}catch(L){v&&(v.textContent=L.message,v.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-danger) 12%, transparent);color:var(--dm-danger);"),E.toast(L.message,{type:"error"})}return!1}:()=>!1,me=d.fields.some(A=>A.type==="page-break");if(N.addEventListener("click",A=>{const L=A.target.closest?.("a.fb-secondary-btn");L&&(A.preventDefault(),E.toast(`Cancel takes the visitor to ${L.getAttribute("href")}`,{type:"info"}))}),N.addEventListener("dm-form-end",A=>{const L=A.detail?.validation;if(L&&!L.valid){E.toast(`Still to answer: ${L.missing.map(Y=>Y.label).concat(L.errors).join(", ")}`,{type:"warning"});return}O(A.detail?.values||{})}),typeof F<"u"){const A=Se(d.settings?.columns),L=d.settings?.layout||"grid";if(me&&F.wizard){const Y=Ut(d.fields,d.title),fe=Y.map(te=>({title:te.title,description:te.description,fields:Dt(te.fields,A)}));let U=0,Q=null,$e=null;const nt=te=>{const qe=(Y[U]||{}).fields||[];Kt(N,d.settings),at(N,d.settings,qe),_t("#fb-preview-form",qe),lt(N,qe),te&&window.FormLogicEngine&&ft(d.fields)&&(Q?.destroy?.(),Q=new window.FormLogicEngine.FormLogicRuntime({fields:d.fields},N,{baseValues:$e?.getStepData?$e.getStepData():{}}),Q.init())};$e=F.wizard("#fb-preview-form",{schema:{steps:fe},layout:L,columns:A,finishText:d.settings?.submitText||"Finish",onStepChange:te=>{U=te,queueMicrotask(()=>nt(!0))},onSubmit:O}),nt(!1)}else if(F.render){const Y=Dt(d.fields,A),fe={};d.fields.forEach(U=>{if(!(!U.name||U.type==="page-break"||U.type==="spacer")&&(U.type==="select"||U.type==="multiselect")&&U.required){const Q=(U.options||[])[0];Q&&(fe[U.name]=typeof Q=="object"?Q.value:Q)}}),F.render("#fb-preview-form",Y,fe,{submitText:d.settings?.submitText||"Submit",layout:L,columns:A,onSubmit:O}),Jt(N,d.settings,L),at(N,d.settings,d.fields),_t("#fb-preview-form",d.fields),lt(N,d.fields)}window.FormLogicEngine&&ft(d.fields)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:d.fields},N).init()})}else{const A=document.createElement("p");A.textContent=`${d.fields.filter(L=>L.type!=="page-break").length} field(s): ${d.fields.filter(L=>L.type!=="page-break").map(L=>L.label).join(", ")}`,A.style.cssText="color:var(--dm-text-muted);font-style:italic;",N.appendChild(A)}},ye();const u=e.find("#editor-tabs").get(0),p=e.find("#preview-card").get(0),m=d=>{p&&p.contains(d.target)||Me()};u&&(u.addEventListener("input",m),u.addEventListener("change",m));const y=e.get(0),h=[],f=d=>(h.push(d),d);let T=!1;const x=M.observable(!1),b=M.observable(!1);let k=B,$=Te(e),q=Ie($),z=$;const _=()=>{T||!y.isConnected||(z=Te(e),x.value=Ie(z)!==q)};let P=null;Re=()=>{clearTimeout(P),P=setTimeout(_,150)},f(()=>{clearTimeout(P),Re=null,ce=null});const Z=d=>{const g=d.settings||{};e.find("#field-title").val(d.title||""),e.find("#field-slug").val(d.slug||""),e.find("#field-description").val(d.description||""),e.find("#field-bundled").prop("checked",!!d.bundled),ge={...d.meta||{}},e.find("#field-project").val(d.meta?.project||""),e.find("#setting-submit-text").val(g.submitText||"Submit"),e.find("#setting-success-message").val(g.successMessage||""),e.find("#setting-layout").val(g.layout||"grid"),e.find("#setting-columns").val(Se(g.columns)),e.find("#setting-submit-align").val(ot(g,g.layout||"grid")),Mt(e,g),e.find("#setting-form-class").val(g.class||""),e.find("#setting-submit-class").val(g.submitClass||""),e.find("#setting-honeypot").prop("checked",g.honeypot!==!1),e.find("#setting-rate-limit").val(g.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(g.successRedirect||""),e.find("#action-cms-slug").val(g.actionSlug||"");const v=d.actions?.email||{};e.find("#action-email-enabled").prop("checked",!!v.enabled),e.find("#action-email-recipients").val(v.recipients||""),e.find("#action-email-subject-prefix").val(v.subjectPrefix||"");const C=d.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",!!C.enabled),e.find("#action-webhook-url").val(C.url||""),e.find("#action-webhook-method").val(C.method||"POST"),w=JSON.parse(JSON.stringify(d.fields||[])),c((g.layout||"grid")==="grid"),X(e)};async function W(){if(b.peek()||T)return;const d=Te(e);if(!d.title){E.toast("Please enter a form title (Form Details).",{type:"error"});return}const g=Yt(d.settings);if(g.length){E.toast(`${g[0]} (Settings > Submit Button)`,{type:"error"});return}const v=Xt(d.settings,d.fields);if(v.length){E.toast(v[0],{type:"error"});return}const C=vn(d.fields);C.length&&E.toast(`Some trigger messages use ${C.map(O=>`{{${O}}}`).join(", ")}, which will show as blank: no field has that name, or it is a password, file or image.`,{type:"warning",duration:9e3}),b.value=!0;const N=B;try{B?(await ie(`/forms/${B}`,{method:"PUT",body:JSON.stringify(d)}),E.toast("Form saved.",{type:"success"})):(B=(await ie("/forms",{method:"POST",body:JSON.stringify(d)})).slug,E.toast("Form created.",{type:"success"})),k=B,$=d,q=Ie(d),z=d,x.value=!1;for(const O of new Set([se(N),se(B)]))try{S.remove?S.remove(O):S.set(O,null)}catch{}Pt(y,d.title),Zt("#/forms"),N||R.navigate(`/forms/edit/${B}`)}catch(O){N||(B=null),E.toast(O.message||"Failed to save form.",{type:"error"})}finally{b.value=!1}}async function pe(){x.peek()&&(!await E.confirm("Discard the changes you have not saved?")||T||(Z($),_(),Ze()))}const Ue=y.querySelector(".fex-bar");if(Ue){const d=M.applyBindings({dirty:x,saving:b},Ue,{methods:{save:W,discard:pe}});f(()=>d.dispose())}f(Qt(y,{position:"bottom"})),Be(e,{id:"form-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>W()}),Be(e,{id:"form-editor-back",icon:"arrow-left",title:"All forms",onClick:()=>{location.hash="#/forms"}}),B&&Be(e,{id:"form-editor-subs",icon:"list",title:"Submissions",onClick:()=>{location.hash=`#/forms/${encodeURIComponent(B)}/submissions`}});const Je=d=>{n()||!(d.ctrlKey||d.metaKey)||String(d.key).toLowerCase()!=="s"||(d.preventDefault(),d.stopImmediatePropagation(),W())};document.addEventListener("keydown",Je,!0),f(()=>document.removeEventListener("keydown",Je,!0));const K=e.find("#fields-list").get(0),Gt=d=>d?.closest?.(".fb-field-card"),Ke=d=>Number(d?.dataset.index),Ye=d=>d?.querySelector(":scope > .fb-field-body"),Xe=d=>{const g=Ye(d);g&&(g.style.display=g.style.display==="none"?"":"none")},oe=(d,g)=>{w=d,X(e),g!=null&&K?.querySelectorAll(".fb-field-card")[g]?.focus()},Wt=async d=>{try{await navigator.clipboard.writeText(d),E.toast(`Copied "${d}".`,{type:"success"})}catch{E.toast(`Copy failed - the name is ${d}.`,{type:"info"})}},Ht=d=>{const g=Gt(d),v=Ke(g);j();const C=w[v];if(!C)return[];const N=C.type!=="spacer"&&C.type!=="page-break",O=Ye(g),me=O&&O.style.display!=="none";return[{header:Fe(C)},...O?[{label:me?"Close":"Edit",icon:me?"chevron-up":"edit",action:()=>Xe(g)}]:[],...N?[{label:"Logic & triggers",icon:"zap",action:()=>{O&&(O.style.display=""),(O?.querySelector(".fb-field-logic")||O)?.scrollIntoView({block:"center",behavior:"smooth"})}}]:[],{label:"Duplicate",icon:"copy",action:()=>{j(),oe(tn(w,v),v+1)}},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:v===0,action:()=>{j(),oe(ct(w,v,-1),v-1)}},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:v>=w.length-1,action:()=>{j(),oe(ct(w,v,1),v+1)}},...N&&C.name?[{label:"Copy field name",icon:"clipboard",action:()=>Wt(C.name)}]:[],{type:"divider"},{label:"Delete\u2026",icon:"trash",danger:!0,action:async()=>{if(C.type!=="spacer"&&!await E.confirm(`Remove "${Dn(Fe(C))}"?`))return;j();const A=[...w];A.splice(v,1),oe(A,Math.min(v,A.length-1))}}]};if(K&&typeof E.sortable=="function"){const d=E.sortable(K,{items:".fb-field-card",handle:".fb-drag-grip",key:null,onSort:({from:g,to:v})=>{j();const C=[...w],[N]=C.splice(g,1);C.splice(v,0,N),oe(C,v)}});f(()=>d.destroy())}let Qe=null;if(K&&E.contextMenu&&(Qe=E.contextMenu(K,{cursor:"glyph",match:".fb-field-card > :first-child",inherit:!1,density:"compact",items:d=>Ht(d)}),f(()=>Qe?.destroy?.())),ce=d=>{for(const g of d.querySelectorAll(".fb-field-card")){g.tabIndex=0;const v=g.firstElementChild;if(!v||v.querySelector(".fex-kebab"))continue;const C=document.createElement("button");C.type="button",C.className="fex-kebab",C.textContent="\u22EE",C.title="Actions",j(),C.setAttribute("aria-label",`Actions for ${Fe(w[Ke(g)])}`),C.addEventListener("click",N=>{N.stopPropagation(),it(C)}),v.appendChild(C)}},K){ce(K);const d=g=>{const v=g.target?.classList?.contains("fb-field-card")?g.target:null;v&&(g.key==="F10"&&g.shiftKey?(g.preventDefault(),it(v.firstElementChild)):g.key==="Enter"&&(g.preventDefault(),Xe(v)))};K.addEventListener("keydown",d),f(()=>K.removeEventListener("keydown",d))}const Ze=()=>{try{const d=se(k);S.remove?S.remove(d):S.set(d,null)}catch{}},et=d=>{if(!x.peek()||!d){Ze();return}try{S.set(se(k),{data:en(d),base:st(q),at:new Date().toISOString()})}catch{}},tt=d=>{_(),x.peek()&&(et(z),d.preventDefault(),d.returnValue="")};window.addEventListener("beforeunload",tt),f(()=>window.removeEventListener("beforeunload",tt)),f(()=>{ne&&(document.removeEventListener("click",ne),ne=null)}),H={path:t,dirty:()=>x.peek(),flush:()=>{clearTimeout(P),_()},dispose(){T||(et(z),T=!0,h.splice(0).reverse().forEach(d=>{try{d?.()}catch{}}))}};const Le=se(B);let ee=null;try{ee=S.get(Le)}catch{}if(ee?.data){try{S.remove?S.remove(Le):S.set(Le,null)}catch{}const d=ee.base&&ee.base!==st(q),g=ee.at?` (${ln(ee.at)})`:"";await E.confirm(`You left unsaved changes to this form${g}.${d?" The saved form has changed since then.":""} Pick up where you left off?`)&&!T&&(Z(nn(ee.data,$)),_())}}};
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CSS_CLASS_RE=/^-?[_a-zA-Z][_a-zA-Z0-9-]*$/,CSS_CLASS_MAX=20,CSS_CLASS_MAX_LEN=64;function r(s){return typeof s!="string"?[]:s.split(/[\s,]+/).map(t=>t.replace(/^\./,"")).filter(Boolean)}export function cssClasses(s){const t=[];for(const n of r(s))if(n.length<=64&&CSS_CLASS_RE.test(n)&&!t.includes(n)&&t.push(n),t.length>=20)break;return t}export function cssClassProblems(s){if(s==null||s==="")return[];if(typeof s!="string")return["must be a string of class names"];const t=r(s),n=t.filter(o=>o.length>64||!CSS_CLASS_RE.test(o)),e=[];return n.length&&e.push(`not a valid class name: ${n.join(", ")}`),t.length>20&&e.push("at most 20 classes"),e}export function normaliseCssClasses(s){return cssClasses(s).join(" ")}export function applyClasses(s,t){if(!s)return!1;const n=cssClasses(t);return n.length&&s.classList.add(...n),n.length>0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SUBMIT_ALIGNS=["left","center","right","full"];export function resolveSubmitAlign(e,t){const n=e||{};return SUBMIT_ALIGNS.includes(n.submitAlign)?n.submitAlign:t==="grid"&&n.submitSpan==="full"?"left":""}export function submitWrapperClasses(e,t){const n=resolveSubmitAlign(e,t);if(!n)return[];const r=["fb-submit",`fb-submit--${n}`];return t==="grid"&&r.push("col-span-full"),r}export function applySubmitPosition(e,t,n){const r=e&&e.querySelector?e.querySelector(".form-buttons"):null;return r?(submitWrapperClasses(t,n).forEach(
|
|
1
|
+
import{applyClasses as u,cssClasses as b,cssClassProblems as a}from"./css-classes.mjs";export const SUBMIT_ALIGNS=["left","center","right","full"];export function resolveSubmitAlign(e,t){const n=e||{};return SUBMIT_ALIGNS.includes(n.submitAlign)?n.submitAlign:t==="grid"&&n.submitSpan==="full"?"left":""}export function submitWrapperClasses(e,t){const n=resolveSubmitAlign(e,t);if(!n)return[];const r=["fb-submit",`fb-submit--${n}`];return t==="grid"&&r.push("col-span-full"),r}export function applySubmitPosition(e,t,n){const r=e&&e.querySelector?e.querySelector(".form-buttons"):null;return r?(submitWrapperClasses(t,n).forEach(s=>r.classList.add(s)),r):null}export const BUTTON_STYLES=["primary","secondary","success","danger","warning","info","outline","outline-success","outline-danger","outline-warning","outline-info","ghost"],BUTTON_SIZES=["sm","lg"],SECONDARY_KINDS=["reset","link"];const y={sm:14,"":16,lg:20},m=/^[a-z0-9][a-z0-9-]{0,63}$/i;export function isIconName(e){return typeof e=="string"&&m.test(e)}export function isSafeButtonUrl(e){if(typeof e!="string")return!1;const t=e.trim();if(!t||t.length>2048||/[\u0000-\u0020\u007f-\u009f\u2028\u2029\\]/.test(t))return!1;const n=/^([a-z][a-z0-9+.-]*):/i.exec(t);return n?["http","https","mailto","tel"].includes(n[1].toLowerCase()):!0}export function resolveSubmitButton(e){const t=e&&e.submitButton&&typeof e.submitButton=="object"?e.submitButton:{};return{style:BUTTON_STYLES.includes(t.style)?t.style:"primary",size:BUTTON_SIZES.includes(t.size)?t.size:"",iconStart:isIconName(t.iconStart)?t.iconStart:"",iconEnd:isIconName(t.iconEnd)?t.iconEnd:""}}export function resolveSecondaryButton(e){const t=e&&e.secondaryButton;if(!t||typeof t!="object"||!SECONDARY_KINDS.includes(t.kind)||t.kind==="link"&&!isSafeButtonUrl(t.url))return null;const n=typeof t.label=="string"&&t.label.trim()?t.label.trim().slice(0,80):t.kind==="reset"?"Clear form":"Cancel";return{kind:t.kind,label:n,url:t.kind==="link"?t.url.trim():"",style:BUTTON_STYLES.includes(t.style)?t.style:"secondary",iconStart:isIconName(t.iconStart)?t.iconStart:"",iconEnd:isIconName(t.iconEnd)?t.iconEnd:"",first:t.first===!0,stack:t.stack===!0}}export function buttonClasses(e,t){const n=["btn","btn-"+(BUTTON_STYLES.includes(e)?e:"primary")];return BUTTON_SIZES.includes(t)&&n.push("btn-"+t),n}export function escapeHtml(e){return String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}export function buttonInnerHtml(e,t,n){const r=y[BUTTON_SIZES.includes(n)?n:""],s=(i,o)=>isIconName(i)?`<span class="fb-btn-icon fb-btn-icon--${o}" data-icon="${i}" data-icon-size="${r}" aria-hidden="true"></span>`:"",c=t||{};return s(c.iconStart,"start")+`<span class="fb-btn-label">${escapeHtml(e)}</span>`+s(c.iconEnd,"end")}export function secondaryButtonHtml(e,t){if(!e||!SECONDARY_KINDS.includes(e.kind))return"";const n=buttonClasses(e.style,t).concat("fb-btn","fb-secondary-btn","fb-secondary-btn--"+e.kind).join(" "),r=buttonInnerHtml(e.label,e,t);return e.kind==="reset"?`<button type="reset" class="${n}">${r}</button>`:isSafeButtonUrl(e.url)?`<a class="${n}" href="${escapeHtml(e.url.trim())}">${r}</a>`:""}export function pairWrapperClasses(e){const t=resolveSecondaryButton(e);return t?t.stack?["fb-submit--pair","fb-submit--stack"]:["fb-submit--pair"]:[]}function l(e){if(typeof window>"u"||!e)return;const t=window.Domma&&window.Domma.icons||window.I;t&&typeof t.scan=="function"&&t.scan(e)}export function decorateButton(e,t){return!e||!t||(t.style&&t.style!=="primary"&&BUTTON_STYLES.includes(t.style)&&(e.classList.remove("btn-primary"),e.classList.add("btn-"+t.style)),BUTTON_SIZES.includes(t.size)&&e.classList.add("btn-"+t.size),(isIconName(t.iconStart)||isIconName(t.iconEnd))&&e.tagName!=="INPUT"&&!e.querySelector(".fb-btn-label")&&(e.innerHTML=buttonInnerHtml(e.textContent.trim(),t,t.size),e.classList.add("fb-btn"))),e}export function applySubmitButtons(e,t,n){const r=applySubmitPosition(e,t,n);if(!r){const o=e&&e.querySelector?e.querySelector('button[type="submit"]'):null;return o&&(decorateButton(o,resolveSubmitButton(t)),l(o)),null}const s=r.querySelector('button[type="submit"], input[type="submit"]');if(!s)return r;const c=resolveSubmitButton(t);decorateButton(s,c);const i=resolveSecondaryButton(t);if(i&&!r.querySelector(".fb-secondary-btn")){const o=r.ownerDocument.createElement("template");o.innerHTML=secondaryButtonHtml(i,c.size);const f=o.content.firstElementChild;f&&(s.parentNode.insertBefore(f,i.first?s:s.nextSibling),pairWrapperClasses(t).forEach(p=>r.classList.add(p)),i.kind==="reset"&&wireFormReset(s.form||r.closest("form")))}return l(r),r}export function applyWizardButtons(e,t){const n=e&&e.querySelector?e.querySelector(".wizard-nav"):null;if(!n)return null;const r=resolveSubmitButton(t),s=n.querySelector(".wizard-prev");s&&r.size&&s.classList.add("btn-"+r.size);const c=n.querySelector(".wizard-next");c&&decorateButton(c,{style:r.style,size:r.size,iconStart:"",iconEnd:""});const i=n.querySelector(".wizard-submit");return i&&decorateButton(i,r),l(n),n}const S='input:not([type="hidden"]):not([type="submit"]):not([type="reset"]):not([type="button"]), select, textarea';function d(e){return Array.from(e.querySelectorAll(S)).filter(t=>!(t.closest&&t.closest(".fb-form-honeypot")))}export function formHasAnswers(e){return d(e).some(t=>t.type==="checkbox"||t.type==="radio"?t.checked!==t.defaultChecked:t.tagName==="SELECT"?Array.from(t.options).some(n=>n.selected!==n.defaultSelected):t.value!==t.defaultValue)}function h(e){d(e).forEach(t=>{t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0}))}),e.querySelectorAll(".fb-field-invalid").forEach(t=>t.classList.remove("fb-field-invalid")),e.querySelectorAll("[data-error-for]").forEach(t=>{t.textContent="",t.style.display="none",t.parentElement&&t.parentElement.classList.remove("has-error")})}export function wireFormReset(e){if(!e||e.__fbResetWired)return;e.__fbResetWired=!0;let t=!1;e.addEventListener("reset",n=>{const r=typeof window<"u"?window.E:null;if(!t&&r&&typeof r.confirm=="function"&&formHasAnswers(e)){n.preventDefault(),Promise.resolve(r.confirm("Clear everything you have entered in this form?")).then(s=>{s&&(t=!0,e.reset(),t=!1)});return}setTimeout(()=>h(e),0)})}export function buttonSettingsProblems(e){const t=e&&e.secondaryButton;return!t||typeof t!="object"||t.kind!=="link"?[]:typeof t.url!="string"||!t.url.trim()?["The Cancel button needs an address to go to."]:isSafeButtonUrl(t.url)?[]:["The Cancel button's address must be a page on this site (/contact) or a full http(s), mailto or tel address."]}export function publicButtonSettings(e){if(!e||typeof e!="object")return e;const t=e.secondaryButton;if(t&&typeof t=="object"&&t.kind==="link"&&!isSafeButtonUrl(t.url)){const{secondaryButton:n,...r}=e;return r}return e}export function formClassProblems(e,t){const n=[],r=e&&typeof e=="object"?e:{};for(const s of a(r.class))n.push(`Form CSS classes: ${s}.`);for(const s of a(r.submitClass))n.push(`Submit button CSS classes: ${s}.`);for(const s of Array.isArray(t)?t:[])if(!(!s||typeof s!="object"))for(const c of a(s.class))n.push(`CSS classes on "${s.label||s.name||s.type}": ${c}.`);return n}export function applyFormClasses(e,t,n){if(!e||!e.querySelector)return null;const r=t&&typeof t=="object"?t:{},s=e.matches&&e.matches("form")?e:e.querySelector("form");s&&u(s,r.class);const c=e;r.submitClass&&c.querySelectorAll('button[type="submit"], input[type="submit"], .wizard-submit').forEach(o=>u(o,r.submitClass));const i=new Map;for(const o of Array.isArray(n)?n:[])o&&o.name&&b(o.class).length&&i.set(o.name,o.class);return i.size&&c.querySelectorAll("[data-field]").forEach(o=>{i.has(o.dataset.field)&&u(o,i.get(o.dataset.field))}),s}
|
package/public/js/forms.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{buildWizardSteps as
|
|
2
|
-
`).replace(/<[^>]+>/g,""))}function j(n){return String(n).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function F(n,o){let t=!1;n.addEventListener("dm-form-end",function(e){const r=e.detail&&e.detail.validation;if(r&&!r.valid){markInvalidFields(n,r.missing),showValidationPopup(r);return}t||(t=!0,n.classList.add("fb-form-loading"),Promise.resolve(o(e.detail&&e.detail.values||{})).catch(function(){}).finally(function(){t=!1,n.classList.remove("fb-form-loading")}))})}function C(n,o,t){const e=n.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const r=document.createElement("div");r.className=t==="success"?"fb-form-success":"fb-form-error",r.textContent=o,n.appendChild(r)}function A(n,o){if(n._formLogicRuntime=o,n._formLogicObserver&&(n._formLogicObserver.disconnect(),n._formLogicObserver=null),!n.parentNode||typeof MutationObserver>"u"||n._formLogicObserved)return;n._formLogicObserved=!0;const t=new MutationObserver(function(e){for(const r of e)for(const i of r.removedNodes)if(i===n||i.nodeType===1&&i.contains&&i.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1}),n._formLogicObserver=t}function Y(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function B(n,o){const t={};return n.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const r=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),i=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":r?"chooser":e.type,c={...e.formConfig||{}};c.span==="full"&&o&&(c.span=o);const s={type:i,label:e.label||e.name,required:Y(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...c}};e.minLength!==void 0&&(s.minLength=e.minLength),e.maxLength!==void 0&&(s.maxLength=e.maxLength),e.min!==void 0&&(s.min=e.min),e.max!==void 0&&(s.max=e.max),r&&(e.variant&&(s.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(s.multiple=!0),e.density&&(s.density=e.density),e.columns&&(s.columns=e.columns),e.accent&&(s.accent=e.accent),e.accentStyle&&(s.accentStyle=e.accentStyle),e.glow&&(s.glow=!0),e.glowColour&&(s.glowColour=e.glowColour),e.shadow&&(s.shadow=e.shadow),e.shadowColour&&(s.shadowColour=e.shadowColour)),t[e.name]=s}),t}function $(n){const o={};return n.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function R(n,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=n.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}const O="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function z(n){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const r=document.createElement("strong");r.textContent=n;const i=document.createElement("button");i.type="button",i.textContent="\xD7",i.setAttribute("aria-label","Close"),i.style.cssText=O+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(r),e.appendChild(i),t.appendChild(e);const c=document.createElement("div");c.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(c),o.appendChild(t);const s=l=>{l.key==="Escape"&&a()};function a(){document.removeEventListener("keydown",s),o.remove()}return i.addEventListener("click",a),o.addEventListener("click",l=>{l.target===o&&a()}),document.addEventListener("keydown",s),document.body.appendChild(o),{body:c,close:a}}function G(n){const{body:o,close:t}=z("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const r=document.createElement("div");r.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(r);const i=window.I&&typeof I.list=="function"?I.list():[],c=i.map(s=>{const a=document.createElement("button");a.type="button",a.title=s,a.dataset.iconName=s,a.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const l=document.createElement("span");return l.setAttribute("data-icon",s),l.setAttribute("data-icon-size","18"),a.appendChild(l),a.addEventListener("mouseenter",()=>{a.style.borderColor="var(--dm-border)"}),a.addEventListener("mouseleave",()=>{a.style.borderColor="transparent"}),a.addEventListener("click",()=>{t(),n(s)}),r.appendChild(a),a});if(!i.length){const s=document.createElement("p");s.textContent="Icon engine unavailable - type an icon name into the field instead.",r.appendChild(s)}window.I?.scan?.(r),e.addEventListener("input",()=>{const s=e.value.trim().toLowerCase();c.forEach(a=>{a.style.display=!s||a.dataset.iconName.includes(s)?"":"none"})}),e.focus()}async function Q(){const n=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!n)return{error:"auth"};const o=r=>fetch("/api/media",{headers:{Authorization:"Bearer "+r}});let t;try{if(t=await o(n),t.status===401&&S.get("auth_refresh_token")){const r=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(r.ok){const{token:i}=await r.json();S.set("auth_token",i),t=await o(i)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(r=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(r.name||r.url||""))}}function X(n){const{body:o,close:t}=z("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),Q().then(({files:r,error:i})=>{if(i){e.textContent=i==="auth"?"Sign in with media access to browse the library - or paste an image URL into the field.":"Could not load the media library - paste an image URL into the field instead.";return}if(!r.length){e.textContent="No images in the media library yet.";return}e.remove();const c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",r.forEach(s=>{const a=document.createElement("button");a.type="button",a.title=s.name||s.url,a.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const l=document.createElement("img");l.src=s.url,l.alt=s.name||"",l.loading="lazy",l.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const m=document.createElement("span");m.textContent=s.name||s.url,m.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",a.appendChild(l),a.appendChild(m),a.addEventListener("click",()=>{t(),n(s.url)}),c.appendChild(a)}),o.appendChild(c)})}function P(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function D(n){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",n.parentNode.insertBefore(o,n),o.appendChild(n),n.style.flex="1",n.style.minWidth="0",o}function M(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=O,o}function Z(n){if(!window.I||typeof I.list!="function")return;const o=D(n),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const i=n.value.trim();if(!i)return;const c=document.createElement("span");c.setAttribute("data-icon",i),c.setAttribute("data-icon-size","16"),t.appendChild(c),window.I?.scan?.(t)};n.addEventListener("input",e),e();const r=M("Browse");r.addEventListener("click",()=>G(i=>{P(n,i),e()})),o.appendChild(t),o.appendChild(r)}function ee(n){const o=D(n),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const i=n.value.trim();t.style.display=i?"":"none",i&&(t.src=i)};n.addEventListener("input",e),e();const r=M("Browse");r.addEventListener("click",()=>X(i=>{P(n,i),e()})),o.appendChild(t),o.appendChild(r)}export function enhancePickerFields(n,o){const t=typeof n=="string"?document.querySelector(n):n;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const r=t.querySelector('[name="'+e.name+'"]');!r||r.dataset.pickerEnhanced||(r.dataset.pickerEnhanced="1",e.type==="icon"?Z(r):ee(r))})}function q(n,o){const t=document.createElement("div");t.className="fb-form-honeypot",t.setAttribute("aria-hidden","true");const e=document.createElement("input");e.name=n.querySelector('[name="website"]')?"_website":"website",t.dataset.hpName=e.name,e.type="text",e.tabIndex=-1,e.autocomplete="url",e.placeholder="https://",t.appendChild(e);const r=document.createElement("input");r.name="_t",r.type="hidden",r.value=o||Date.now(),t.appendChild(r),n.appendChild(t)}function V(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let r=0;o.forEach(function(i){if(i.type==="spacer"){const c=document.createElement("div");c.className="fb-spacer";const s=e[r];if(s)t.insertBefore(c,s);else{const a=t.querySelector('[type="submit"]');a?t.insertBefore(c,a):t.appendChild(c)}}else i.type!=="page-break"&&r++})}function L(n,o){!n||!o||n.querySelectorAll('input[type="file"]').forEach(function(t){t.name&&t.files&&t.files.length&&o.set(t.name,Array.from(t.files))})}function x(n,o,t,e,r,i){const c=r||e,s=c.querySelector(".fb-form-honeypot"),a=s?.querySelector('input[type="text"]')?.value||"",l=s?.querySelector('[name="_t"]')?.value||"",m=Object.assign({},o);delete m._t,s?.dataset.hpName&&delete m[s.dataset.hpName];const d=new Map(i||[]);L(c,d);const u=d.size>0;let p,b;if(u){const h=new FormData;for(const[g,v]of Object.entries(m))v!=null&&(d.has(g)||h.append(g,typeof v=="object"?JSON.stringify(v):String(v)));for(const[g,v]of d)for(const w of v)h.append(g,w,w.name);h.append("_hp",a),h.append("_t",l),p=h,b={}}else{const h=Object.assign({},m,{_hp:a,_t:l});p=JSON.stringify(h),b={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:b,body:p}).then(h=>h.json().then(g=>({ok:h.ok,body:g}))).then(h=>{h.ok&&h.body.ok?(e.textContent="",C(e,h.body.message||t.successMessage||"Thank you.","success")):C(e,h.body.error||"Something went wrong.","error")}).catch(()=>{C(e,"Unable to submit. Please check your connection.","error")})}function te(n,o,t,e,r){const i=document.createElement("form");i.noValidate=!0,o.forEach(function(a){const l=document.createElement("div");l.className="form-group",l.style.marginBottom="1.25rem";const m=document.createElement("label");if(m.className="form-label",m.textContent=a.label||a.name,a.required){const u=document.createElement("span");u.textContent=" *",u.style.color="var(--dm-danger)",m.appendChild(u)}let d;a.type==="textarea"?(d=document.createElement("textarea"),d.rows=a.formConfig?.rows||4,d.className="form-input"):a.type==="select"?(d=document.createElement("select"),d.className="form-input",(a.options||[]).forEach(function(u){const p=document.createElement("option");p.value=typeof u=="string"?u:u.value??"",p.textContent=typeof u=="string"?u:u.label||p.value,d.appendChild(p)})):(d=document.createElement("input"),d.type=a.type==="icon"||a.type==="image"?"text":a.type||"text",d.className="form-input",a.placeholder&&(d.placeholder=a.placeholder),a.type==="file"&&(a.file?.accept&&(d.accept=a.file.accept),a.multiple&&(d.multiple=!0))),d.name=a.name,d.required=a.required||!1,l.appendChild(m),l.appendChild(d),i.appendChild(l)}),t.honeypot&&q(i);const c=document.createElement("button");if(c.type="submit",c.className="btn btn-primary",c.textContent=t.submitText||"Submit",H(t,"stacked").length||U(t)){const a=document.createElement("div");a.className="form-group form-buttons",a.appendChild(c),i.appendChild(a)}else i.appendChild(c);if(i.addEventListener("submit",function(a){a.preventDefault();const l={};if(o.forEach(function(m){const d=i.querySelector('[name="'+m.name+'"]');d&&(l[m.name]=d.value)}),window.FormLogicEngine&&r){const m=window.FormLogicEngine,d=[],u=[];if(o.forEach(function(p){if(m.evaluateFieldVisibility(p,l)==="hidden"){delete l[p.name];return}const h=m.evaluateFieldRequirement(p,l),g=l[p.name];h&&(!g||!String(g).trim())&&d.push(p.label||p.name);const v=m.validateField(p,g||"",l);v.length&&u.push(v[0].message)}),d.length||u.length){const p=[];d.length&&p.push("Required: "+d.join(", ")),u.length&&p.push(u.join("; ")),C(n,p.join(". "),"error");return}}if(n.dataset.triggerBlocked==="true"){const m=n._formLogicRuntime,d=m&&m.submitBlock?m.submitBlock().reasons:[];C(n,d.join(" ")||"This form cannot be submitted yet.","error");return}n.classList.add("fb-form-loading"),c.disabled=!0,x(e,l,t,n,i).finally(function(){n.classList.remove("fb-form-loading"),c.disabled=!1})}),n.appendChild(i),N(i,t,"stacked"),enhancePickerFields(n,o),F(n,function(a){return x(e,a,t,n,i)}),window.FormLogicEngine&&r&&T(o)){const a=new window.FormLogicEngine.FormLogicRuntime(r,n);a.init(),n._formLogicRuntime=a}}function ne(n){const o=n.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],r=t.settings||{},i=document.createElement("div");i.className="fb-form-wrapper",n.appendChild(i);const c=e.some(s=>s.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const s=Number(r.columns)===3?3:2,a=r.layout||"grid";if(c&&Domma.forms.wizard){const l=W(e,t.title),m=l.map(f=>f.fields),d=l.map(function(f){return{title:f.title,description:f.description,fields:B(f.fields,s)}});let u=0,p=null,b=null;const h=Date.now(),g=new Map,v=function(f){const y=window.FormLogicEngine;if(!y||!y.validateFields)return;const k=y.validateFields(i,m[u]||[]);k.valid||(f.preventDefault(),f.stopImmediatePropagation(),markInvalidFields(i,k.missing),showValidationPopup(k))},w=function(){const f=m[u]||e;if(J(i,r),R(i,f),enhancePickerFields(i,f),f.some(y=>y.type==="spacer")&&V(i,f),r.honeypot){const y=i.querySelector("form");y&&q(y,h)}window.FormLogicEngine&&T(e)&&(p&&p.destroy(),p=new window.FormLogicEngine.FormLogicRuntime(t,i,{baseValues:b&&b.getStepData?b.getStepData():{}}),p.init(),A(i,p)),i.querySelectorAll(".wizard-next, .wizard-submit").forEach(y=>y.addEventListener("click",v,!0))};b=Domma.forms.wizard(i,{schema:{steps:d},layout:a,columns:s,finishText:r.submitText||"Finish",onStepChange:function(f){L(i,g),u=f,setTimeout(w,0)},onSubmit:function(f){return L(i,g),x(o,f,r,i,null,g)}}),F(i,function(f){return L(i,g),x(o,f,r,i,null,g)}),i.addEventListener("dm-form-trigger",function(f){if(!f.detail||f.detail.type!=="goto-step"||!b||!b.goToStep)return;const y=Number(f.detail.action.step);!isFinite(y)||y<0||y>=d.length||y!==u&&b.goToStep(y)}),Promise.resolve(b).then(w)}else if(Domma.forms.render){const l=B(e,s),m=$(e);F(i,function(u){return x(o,u,r,i,null)});const d=Domma.forms.render(i,l,m,{submitText:r.submitText||"Submit",layout:a,columns:s,onSubmit:function(u){return x(o,u,r,i,null)}});Promise.resolve(d).then(function(){if(N(i,r,a),R(i,e),enhancePickerFields(i,e),window.FormLogicEngine&&T(e)){const u=new window.FormLogicEngine.FormLogicRuntime(t,i);u.init(),A(i,u)}if(e.some(u=>u.type==="spacer")&&V(i,e),r.honeypot){const u=i.querySelector("form");u&&q(u)}})}}else te(i,e.filter(s=>s.type!=="page-break"&&s.type!=="spacer"),r,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",n.appendChild(e),console.warn("[forms]",t.message)})}
|
|
1
|
+
import{buildWizardSteps as J}from"/public/js/form-steps.mjs";import{applyFormClasses as T,applySubmitButtons as _,applyWizardButtons as U,resolveSecondaryButton as H,submitWrapperClasses as K}from"/public/js/form-submit.mjs";const j=document.querySelectorAll("[data-form]");j.length&&j.forEach(oe);function F(n){return(n||[]).some(o=>o.logic||Array.isArray(o.triggers)&&o.triggers.length)}function Y(n,o){const t=n.querySelector('[name="'+o+'"], [name="'+o+'[]"]')||n.querySelector('[data-chooser-field="'+o+'"]');if(!t)return null;const e=t.closest("form")||n;let i=t;for(;i.parentNode&&i.parentNode!==e;)i=i.parentNode;return i}export function markInvalidFields(n,o){n.querySelectorAll(".fb-field-invalid").forEach(e=>e.classList.remove("fb-field-invalid"));let t=null;(o||[]).forEach(function(e){const i=Y(n,e.name);i&&(i.classList.add("fb-field-invalid"),t||(t=i))}),t&&t.scrollIntoView&&t.scrollIntoView({behavior:"smooth",block:"center"})}export function showValidationPopup(n){const o=(n.missing||[]).map(e=>"<strong>"+A(e.label)+"</strong> is required.").concat((n.errors||[]).map(A)),t=o.join("<br>");if(typeof E<"u"&&E.alert){E.alert(t,{title:"Please complete this step"});return}window.alert(o.join(`
|
|
2
|
+
`).replace(/<[^>]+>/g,""))}function A(n){return String(n).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function q(n,o){let t=!1;n.addEventListener("dm-form-end",function(e){const i=e.detail&&e.detail.validation;if(i&&!i.valid){markInvalidFields(n,i.missing),showValidationPopup(i);return}t||(t=!0,n.classList.add("fb-form-loading"),Promise.resolve(o(e.detail&&e.detail.values||{})).catch(function(){}).finally(function(){t=!1,n.classList.remove("fb-form-loading")}))})}function C(n,o,t){const e=n.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const i=document.createElement("div");i.className=t==="success"?"fb-form-success":"fb-form-error",i.textContent=o,n.appendChild(i)}function B(n,o){if(n._formLogicRuntime=o,n._formLogicObserver&&(n._formLogicObserver.disconnect(),n._formLogicObserver=null),!n.parentNode||typeof MutationObserver>"u"||n._formLogicObserved)return;n._formLogicObserved=!0;const t=new MutationObserver(function(e){for(const i of e)for(const r of i.removedNodes)if(r===n||r.nodeType===1&&r.contains&&r.contains(n)){n._formLogicRuntime&&n._formLogicRuntime.destroy(),t.disconnect();return}});t.observe(n.parentNode,{childList:!0,subtree:!1}),n._formLogicObserver=t}function $(n){const o=n&&n.logic;return!!(o&&(o.visibility||o.requirement))}function R(n,o){const t={};return n.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),r=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,l={...e.formConfig||{}};l.span==="full"&&o&&(l.span=o);const s={type:r,label:e.label||e.name,required:$(e)?!1:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...l}};e.minLength!==void 0&&(s.minLength=e.minLength),e.maxLength!==void 0&&(s.maxLength=e.maxLength),e.min!==void 0&&(s.min=e.min),e.max!==void 0&&(s.max=e.max),i&&(e.variant&&(s.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(s.multiple=!0),e.density&&(s.density=e.density),e.columns&&(s.columns=e.columns),e.accent&&(s.accent=e.accent),e.accentStyle&&(s.accentStyle=e.accentStyle),e.glow&&(s.glow=!0),e.glowColour&&(s.glowColour=e.glowColour),e.shadow&&(s.shadow=e.shadow),e.shadowColour&&(s.shadowColour=e.shadowColour)),t[e.name]=s}),t}function G(n){const o={};return n.forEach(function(t){if(!(!t.name||t.type==="page-break"||t.type==="spacer")&&(t.type==="select"||t.type==="multiselect")&&t.required){const e=(t.options||[])[0];e&&(o[t.name]=typeof e=="object"?e.value:e)}}),o}function O(n,o){(o||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=n.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}const z="padding:.45rem .7rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:transparent;color:inherit;cursor:pointer;font:inherit;font-size:.85em;flex-shrink:0;line-height:1.2;";function P(n){const o=document.createElement("div");o.style.cssText="position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:20px;";const t=document.createElement("div");t.style.cssText="background:var(--dm-surface-overlay,var(--dm-surface));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:10px;width:100%;max-width:560px;max-height:75vh;display:flex;flex-direction:column;gap:.6rem;padding:1rem;box-shadow:var(--dm-shadow-lg,0 12px 40px rgba(0,0,0,.35));";const e=document.createElement("div");e.style.cssText="display:flex;align-items:center;justify-content:space-between;gap:.5rem;";const i=document.createElement("strong");i.textContent=n;const r=document.createElement("button");r.type="button",r.textContent="\xD7",r.setAttribute("aria-label","Close"),r.style.cssText=z+"font-size:1rem;padding:.15rem .55rem;",e.appendChild(i),e.appendChild(r),t.appendChild(e);const l=document.createElement("div");l.style.cssText="display:flex;flex-direction:column;gap:.6rem;overflow:hidden;min-height:0;",t.appendChild(l),o.appendChild(t);const s=c=>{c.key==="Escape"&&a()};function a(){document.removeEventListener("keydown",s),o.remove()}return r.addEventListener("click",a),o.addEventListener("click",c=>{c.target===o&&a()}),document.addEventListener("keydown",s),document.body.appendChild(o),{body:l,close:a}}function Q(n){const{body:o,close:t}=P("Choose an icon"),e=document.createElement("input");e.type="text",e.placeholder="Search icons\u2026",e.className="form-input",e.style.cssText="padding:.45rem .6rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);background:var(--dm-input-bg,transparent);color:var(--dm-text);",o.appendChild(e);const i=document.createElement("div");i.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(46px,1fr));gap:4px;overflow-y:auto;min-height:0;",o.appendChild(i);const r=window.I&&typeof I.list=="function"?I.list():[],l=r.map(s=>{const a=document.createElement("button");a.type="button",a.title=s,a.dataset.iconName=s,a.style.cssText="display:flex;align-items:center;justify-content:center;padding:.55rem 0;border:1px solid transparent;border-radius:6px;background:transparent;color:inherit;cursor:pointer;";const c=document.createElement("span");return c.setAttribute("data-icon",s),c.setAttribute("data-icon-size","18"),a.appendChild(c),a.addEventListener("mouseenter",()=>{a.style.borderColor="var(--dm-border)"}),a.addEventListener("mouseleave",()=>{a.style.borderColor="transparent"}),a.addEventListener("click",()=>{t(),n(s)}),i.appendChild(a),a});if(!r.length){const s=document.createElement("p");s.textContent="Icon engine unavailable - type an icon name into the field instead.",i.appendChild(s)}window.I?.scan?.(i),e.addEventListener("input",()=>{const s=e.value.trim().toLowerCase();l.forEach(a=>{a.style.display=!s||a.dataset.iconName.includes(s)?"":"none"})}),e.focus()}async function X(){const n=typeof S<"u"&&S.get?S.get("auth_token"):null;if(!n)return{error:"auth"};const o=i=>fetch("/api/media",{headers:{Authorization:"Bearer "+i}});let t;try{if(t=await o(n),t.status===401&&S.get("auth_refresh_token")){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:S.get("auth_refresh_token")})});if(i.ok){const{token:r}=await i.json();S.set("auth_token",r),t=await o(r)}}}catch{return{error:"load"}}if(!t.ok)return{error:t.status===401||t.status===403?"auth":"load"};const e=await t.json().catch(()=>[]);return{files:(Array.isArray(e)?e:[]).filter(i=>/\.(png|jpe?g|gif|webp|svg|avif)$/i.test(i.name||i.url||""))}}function Z(n){const{body:o,close:t}=P("Choose an image"),e=document.createElement("p");e.textContent="Loading media library\u2026",e.style.cssText="margin:0;font-size:.85em;color:var(--dm-text-muted);",o.appendChild(e),X().then(({files:i,error:r})=>{if(r){e.textContent=r==="auth"?"Sign in with media access to browse the library - or paste an image URL into the field.":"Could not load the media library - paste an image URL into the field instead.";return}if(!i.length){e.textContent="No images in the media library yet.";return}e.remove();const l=document.createElement("div");l.style.cssText="display:grid;grid-template-columns:repeat(auto-fill,minmax(104px,1fr));gap:8px;overflow-y:auto;min-height:0;",i.forEach(s=>{const a=document.createElement("button");a.type="button",a.title=s.name||s.url,a.style.cssText="display:flex;flex-direction:column;gap:.25rem;padding:.35rem;border:1px solid var(--dm-border);border-radius:8px;background:transparent;color:inherit;cursor:pointer;min-width:0;";const c=document.createElement("img");c.src=s.url,c.alt=s.name||"",c.loading="lazy",c.style.cssText="width:100%;height:72px;object-fit:cover;border-radius:5px;";const m=document.createElement("span");m.textContent=s.name||s.url,m.style.cssText="font-size:.68em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;",a.appendChild(c),a.appendChild(m),a.addEventListener("click",()=>{t(),n(s.url)}),l.appendChild(a)}),o.appendChild(l)})}function D(n,o){n.value=o,n.dispatchEvent(new Event("input",{bubbles:!0})),n.dispatchEvent(new Event("change",{bubbles:!0}))}function M(n){const o=document.createElement("div");return o.style.cssText="display:flex;align-items:center;gap:.5rem;",n.parentNode.insertBefore(o,n),o.appendChild(n),n.style.flex="1",n.style.minWidth="0",o}function V(n){const o=document.createElement("button");return o.type="button",o.textContent=n,o.style.cssText=z,o}function ee(n){if(!window.I||typeof I.list!="function")return;const o=M(n),t=document.createElement("span");t.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;flex-shrink:0;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);";const e=()=>{t.textContent="";const r=n.value.trim();if(!r)return;const l=document.createElement("span");l.setAttribute("data-icon",r),l.setAttribute("data-icon-size","16"),t.appendChild(l),window.I?.scan?.(t)};n.addEventListener("input",e),e();const i=V("Browse");i.addEventListener("click",()=>Q(r=>{D(n,r),e()})),o.appendChild(t),o.appendChild(i)}function te(n){const o=M(n),t=document.createElement("img");t.alt="",t.style.cssText="width:2rem;height:2rem;flex-shrink:0;object-fit:cover;border:1px solid var(--dm-border);border-radius:var(--dm-radius-md,6px);display:none;";const e=()=>{const r=n.value.trim();t.style.display=r?"":"none",r&&(t.src=r)};n.addEventListener("input",e),e();const i=V("Browse");i.addEventListener("click",()=>Z(r=>{D(n,r),e()})),o.appendChild(t),o.appendChild(i)}export function enhancePickerFields(n,o){const t=typeof n=="string"?document.querySelector(n):n;t&&(o||[]).forEach(function(e){if(!e.name||e.type!=="icon"&&e.type!=="image")return;const i=t.querySelector('[name="'+e.name+'"]');!i||i.dataset.pickerEnhanced||(i.dataset.pickerEnhanced="1",e.type==="icon"?ee(i):te(i))})}function N(n,o){const t=document.createElement("div");t.className="fb-form-honeypot",t.setAttribute("aria-hidden","true");const e=document.createElement("input");e.name=n.querySelector('[name="website"]')?"_website":"website",t.dataset.hpName=e.name,e.type="text",e.tabIndex=-1,e.autocomplete="url",e.placeholder="https://",t.appendChild(e);const i=document.createElement("input");i.name="_t",i.type="hidden",i.value=o||Date.now(),t.appendChild(i),n.appendChild(t)}function W(n,o){const t=n.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let i=0;o.forEach(function(r){if(r.type==="spacer"){const l=document.createElement("div");l.className="fb-spacer";const s=e[i];if(s)t.insertBefore(l,s);else{const a=t.querySelector('[type="submit"]');a?t.insertBefore(l,a):t.appendChild(l)}}else r.type!=="page-break"&&i++})}function L(n,o){!n||!o||n.querySelectorAll('input[type="file"]').forEach(function(t){t.name&&t.files&&t.files.length&&o.set(t.name,Array.from(t.files))})}function x(n,o,t,e,i,r){const l=i||e,s=l.querySelector(".fb-form-honeypot"),a=s?.querySelector('input[type="text"]')?.value||"",c=s?.querySelector('[name="_t"]')?.value||"",m=Object.assign({},o);delete m._t,s?.dataset.hpName&&delete m[s.dataset.hpName];const d=new Map(r||[]);L(l,d);const u=d.size>0;let p,b;if(u){const h=new FormData;for(const[g,v]of Object.entries(m))v!=null&&(d.has(g)||h.append(g,typeof v=="object"?JSON.stringify(v):String(v)));for(const[g,v]of d)for(const w of v)h.append(g,w,w.name);h.append("_hp",a),h.append("_t",c),p=h,b={}}else{const h=Object.assign({},m,{_hp:a,_t:c});p=JSON.stringify(h),b={"Content-Type":"application/json"}}return fetch("/api/forms/submit/"+n,{method:"POST",headers:b,body:p}).then(h=>h.json().then(g=>({ok:h.ok,body:g}))).then(h=>{h.ok&&h.body.ok?(e.textContent="",C(e,h.body.message||t.successMessage||"Thank you.","success")):C(e,h.body.error||"Something went wrong.","error")}).catch(()=>{C(e,"Unable to submit. Please check your connection.","error")})}function ne(n,o,t,e,i){const r=document.createElement("form");r.noValidate=!0,o.forEach(function(a){const c=document.createElement("div");c.className="form-group",c.style.marginBottom="1.25rem",a.name&&(c.dataset.field=a.name);const m=document.createElement("label");if(m.className="form-label",m.textContent=a.label||a.name,a.required){const u=document.createElement("span");u.textContent=" *",u.style.color="var(--dm-danger)",m.appendChild(u)}let d;a.type==="textarea"?(d=document.createElement("textarea"),d.rows=a.formConfig?.rows||4,d.className="form-input"):a.type==="select"?(d=document.createElement("select"),d.className="form-input",(a.options||[]).forEach(function(u){const p=document.createElement("option");p.value=typeof u=="string"?u:u.value??"",p.textContent=typeof u=="string"?u:u.label||p.value,d.appendChild(p)})):(d=document.createElement("input"),d.type=a.type==="icon"||a.type==="image"?"text":a.type||"text",d.className="form-input",a.placeholder&&(d.placeholder=a.placeholder),a.type==="file"&&(a.file?.accept&&(d.accept=a.file.accept),a.multiple&&(d.multiple=!0))),d.name=a.name,d.required=a.required||!1,c.appendChild(m),c.appendChild(d),r.appendChild(c)}),t.honeypot&&N(r);const l=document.createElement("button");if(l.type="submit",l.className="btn btn-primary",l.textContent=t.submitText||"Submit",K(t,"stacked").length||H(t)){const a=document.createElement("div");a.className="form-group form-buttons",a.appendChild(l),r.appendChild(a)}else r.appendChild(l);if(r.addEventListener("submit",function(a){a.preventDefault();const c={};if(o.forEach(function(m){const d=r.querySelector('[name="'+m.name+'"]');d&&(c[m.name]=d.value)}),window.FormLogicEngine&&i){const m=window.FormLogicEngine,d=[],u=[];if(o.forEach(function(p){if(m.evaluateFieldVisibility(p,c)==="hidden"){delete c[p.name];return}const h=m.evaluateFieldRequirement(p,c),g=c[p.name];h&&(!g||!String(g).trim())&&d.push(p.label||p.name);const v=m.validateField(p,g||"",c);v.length&&u.push(v[0].message)}),d.length||u.length){const p=[];d.length&&p.push("Required: "+d.join(", ")),u.length&&p.push(u.join("; ")),C(n,p.join(". "),"error");return}}if(n.dataset.triggerBlocked==="true"){const m=n._formLogicRuntime,d=m&&m.submitBlock?m.submitBlock().reasons:[];C(n,d.join(" ")||"This form cannot be submitted yet.","error");return}n.classList.add("fb-form-loading"),l.disabled=!0,x(e,c,t,n,r).finally(function(){n.classList.remove("fb-form-loading"),l.disabled=!1})}),n.appendChild(r),_(r,t,"stacked"),T(r,t,o),enhancePickerFields(n,o),q(n,function(a){return x(e,a,t,n,r)}),window.FormLogicEngine&&i&&F(o)){const a=new window.FormLogicEngine.FormLogicRuntime(i,n);a.init(),n._formLogicRuntime=a}}function oe(n){const o=n.getAttribute("data-form");o&&fetch("/api/forms/"+o+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+o);return t.json()}).then(t=>{const e=t.fields||[],i=t.settings||{},r=document.createElement("div");r.className="fb-form-wrapper",n.appendChild(r);const l=e.some(s=>s.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const s=Number(i.columns)===3?3:2,a=i.layout||"grid";if(l&&Domma.forms.wizard){const c=J(e,t.title),m=c.map(f=>f.fields),d=c.map(function(f){return{title:f.title,description:f.description,fields:R(f.fields,s)}});let u=0,p=null,b=null;const h=Date.now(),g=new Map,v=function(f){const y=window.FormLogicEngine;if(!y||!y.validateFields)return;const k=y.validateFields(r,m[u]||[]);k.valid||(f.preventDefault(),f.stopImmediatePropagation(),markInvalidFields(r,k.missing),showValidationPopup(k))},w=function(){const f=m[u]||e;if(U(r,i),T(r,i,f),O(r,f),enhancePickerFields(r,f),f.some(y=>y.type==="spacer")&&W(r,f),i.honeypot){const y=r.querySelector("form");y&&N(y,h)}window.FormLogicEngine&&F(e)&&(p&&p.destroy(),p=new window.FormLogicEngine.FormLogicRuntime(t,r,{baseValues:b&&b.getStepData?b.getStepData():{}}),p.init(),B(r,p)),r.querySelectorAll(".wizard-next, .wizard-submit").forEach(y=>y.addEventListener("click",v,!0))};b=Domma.forms.wizard(r,{schema:{steps:d},layout:a,columns:s,finishText:i.submitText||"Finish",onStepChange:function(f){L(r,g),u=f,setTimeout(w,0)},onSubmit:function(f){return L(r,g),x(o,f,i,r,null,g)}}),q(r,function(f){return L(r,g),x(o,f,i,r,null,g)}),r.addEventListener("dm-form-trigger",function(f){if(!f.detail||f.detail.type!=="goto-step"||!b||!b.goToStep)return;const y=Number(f.detail.action.step);!isFinite(y)||y<0||y>=d.length||y!==u&&b.goToStep(y)}),Promise.resolve(b).then(w)}else if(Domma.forms.render){const c=R(e,s),m=G(e);q(r,function(u){return x(o,u,i,r,null)});const d=Domma.forms.render(r,c,m,{submitText:i.submitText||"Submit",layout:a,columns:s,onSubmit:function(u){return x(o,u,i,r,null)}});Promise.resolve(d).then(function(){if(_(r,i,a),T(r,i,e),O(r,e),enhancePickerFields(r,e),window.FormLogicEngine&&F(e)){const u=new window.FormLogicEngine.FormLogicRuntime(t,r);u.init(),B(r,u)}if(e.some(u=>u.type==="spacer")&&W(r,e),i.honeypot){const u=r.querySelector("form");u&&N(u)}})}}else ne(r,e.filter(s=>s.type!=="page-break"&&s.type!=="spacer"),i,o,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:var(--dm-danger);font-style:italic;",n.appendChild(e),console.warn("[forms]",t.message)})}
|
package/public/js/menu-decor.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PRESET_COLOUR_VARS={primary:"--dm-primary",success:"--dm-success",danger:"--dm-danger",warning:"--dm-warning",info:"--dm-info",neutral:"--dm-text-muted"},PRESET_COLOUR_FALLBACKS={primary:"#0d6efd",success:"#198754",danger:"#dc3545",warning:"#ffc107",info:"#0dcaf0",neutral:"#6c757d"};const
|
|
1
|
+
export const PRESET_COLOUR_VARS={primary:"--dm-primary",success:"--dm-success",danger:"--dm-danger",warning:"--dm-warning",info:"--dm-info",neutral:"--dm-text-muted"},PRESET_COLOUR_FALLBACKS={primary:"#0d6efd",success:"#198754",danger:"#dc3545",warning:"#ffc107",info:"#0dcaf0",neutral:"#6c757d"};const l=/^#[0-9a-fA-F]{6}$/;export function colourToCss(t){return typeof t!="string"?"":PRESET_COLOUR_VARS[t]?`var(${PRESET_COLOUR_VARS[t]}, ${PRESET_COLOUR_FALLBACKS[t]})`:l.test(t)?t:""}export const FLOAT_ANCHORS=["TL","TR","BL","BR","L","R"],FLOAT_DEFAULTS={anchor:"TL",offsetX:16,offsetY:16,zIndex:150},FLOAT_SHADOWS={none:"none",sm:"var(--dm-shadow-sm)",md:"var(--dm-shadow-md)",lg:"var(--dm-shadow-lg)",xl:"var(--dm-shadow-xl)"};function s(t,e,o,r){const n=Number(t);return Number.isFinite(n)?Math.min(r,Math.max(o,Math.round(n))):e}function f(t){const e=[];if(t.radius!=null&&t.radius!==""&&e.push(`border-radius:${s(t.radius,8,0,48)}px`),t.shadow!=null&&t.shadow!==""&&Object.prototype.hasOwnProperty.call(FLOAT_SHADOWS,t.shadow)&&e.push(`box-shadow:${FLOAT_SHADOWS[t.shadow]}`),t.accent&&colourToCss(t.accent)){const o=colourToCss(t.accent);e.push(`--dm-menu-accent:${o}`,`border-color:${o}`)}return t.opacity!=null&&t.opacity!==""&&e.push(`--dm-menu-panel-opacity:${s(t.opacity,100,20,100)/100}`),e}export function floatToCss(t){if(!t||t.position!=="floating")return"";const e=t.float&&typeof t.float=="object"&&!Array.isArray(t.float)?t.float:{},o=FLOAT_ANCHORS.includes(e.anchor)?e.anchor:FLOAT_DEFAULTS.anchor,r=s(e.offsetX,FLOAT_DEFAULTS.offsetX,0,4e3),n=s(e.offsetY,FLOAT_DEFAULTS.offsetY,0,4e3),a=["position:fixed",`z-index:${s(e.zIndex,FLOAT_DEFAULTS.zIndex,0,2147483647)}`];return o==="L"||o==="R"?(a.push("top:50%","transform:translateY(-50%)"),a.push(o==="L"?`left:${r}px`:`right:${r}px`)):(a.push(o[0]==="T"?`top:${n}px`:`bottom:${n}px`),a.push(o[1]==="L"?`left:${r}px`:`right:${r}px`)),e.width!=null&&e.width!==""&&a.push(`width:${s(e.width,260,120,600)}px`),a.push(`max-height:calc(100vh - ${o==="L"||o==="R"?32:n*2}px)`),a.push(...f(e)),a.join(";")}export const FLOAT_FLAGS=["collapsible","collapsed","movable","resizable"];export function floatBehaviour(t){const e={collapsible:!1,collapsed:!1,movable:!1,resizable:!1,chrome:!1,title:""};if(!t||t.position!=="floating")return e;const o=t.float&&typeof t.float=="object"&&!Array.isArray(t.float)?t.float:{},r={collapsible:!!o.collapsible,collapsed:!!o.collapsible&&!!o.collapsed,movable:!!o.movable,resizable:!!o.resizable},n=r.collapsible||r.movable,i=typeof o.title=="string"&&o.title!==""?o.title:t.name||"";return{...r,chrome:n,title:n?i:""}}export function applyFloat(t,e){const o=floatToCss(e);if(!t||!o)return!1;t.style.cssText+=";"+o,t.classList.add("dm-menu-floating"),e.slug&&!t.hasAttribute("data-menu")&&t.setAttribute("data-menu",e.slug),e.float?.anchor&&t.setAttribute("data-float-anchor",e.float.anchor);const r=floatBehaviour(e);for(const n of FLOAT_FLAGS)n!=="collapsed"&&r[n]&&t.setAttribute(`data-float-${n}`,"1");return r.collapsed&&t.setAttribute("data-float-collapsed","1"),r.title&&t.setAttribute("data-float-title",r.title),!0}export function makeBadgeEl(t){if(!t||t.text==null||t.text==="")return null;const e=document.createElement("span");e.className="dm-menu-badge",e.textContent=String(t.text);const o=t.variant?colourToCss(t.variant):"";return o&&(e.style.background=o,e.style.color="var(--dm-text-inverse, #fff)"),e}export function applyColour(t,e){const o=colourToCss(e);o&&(t.style.color=o)}export function applyPill(t,e){if(!e)return;t.classList.add("dm-nav-pill");const o=e.variant?colourToCss(e.variant):"";e.style==="outline"?(t.classList.add("dm-nav-pill--outline"),o&&(t.style.borderColor=o,t.style.color=o)):o&&(t.style.background=o,t.style.color="#fff")}export const MENU_ALIGN=["left","centre","right","spread"];export function menuAlign(t){const e=t&&t.align;return MENU_ALIGN.includes(e)?e:""}export const HIGHLIGHT_HOVER=["none","colour","underline","overline","background","uppercase","grow","breathe","glow"],HIGHLIGHT_ACTIVE=["none","bold","underline","overline","background","darken","pill"],HIGHLIGHT_HOVER_LABELS={none:"None - no change on hover",colour:"Colour change",underline:"Underline",overline:"Overline",background:"Background tint",uppercase:"Uppercase",grow:"Grow",breathe:"Breathe",glow:"Glow"},HIGHLIGHT_ACTIVE_LABELS={none:"None - not marked at all",bold:"Bold",underline:"Underline",overline:"Overline",background:"Background tint",darken:"Darkened",pill:"Filled pill"},LEGACY_STYLE_HOVER={none:"none",underline:"underline",overline:"overline",transform:"uppercase","text-transform":"uppercase",breathe:"breathe"},LEGACY_STYLE_ACTIVE={none:"none",darken:"darken",background:"background","background-color":"background",underline:"underline",overline:"overline"};export function legacyStyleHighlight(t){const e=t&&typeof t=="object"&&!Array.isArray(t)?t:{};return{hover:LEGACY_STYLE_HOVER[e.hover]||"",active:LEGACY_STYLE_ACTIVE[e.active]||""}}export function highlightAttrs(t){const e=t&&t.highlight&&typeof t.highlight=="object"&&!Array.isArray(t.highlight)?t.highlight:{},o=legacyStyleHighlight(t&&t.style);return{hover:HIGHLIGHT_HOVER.includes(e.hover)?e.hover:o.hover,active:HIGHLIGHT_ACTIVE.includes(e.active)?e.active:o.active,accent:e.accent?colourToCss(e.accent):""}}export function applyHighlight(t,e){if(!t)return!1;const{hover:o,active:r,accent:n}=highlightAttrs(e);return o&&t.setAttribute("data-menu-hover",o),r&&t.setAttribute("data-menu-active",r),n&&t.style.setProperty("--dm-menu-highlight",n),!!(o||r||n)}export function itemHighlightAttrs(t){const e=t&&t.highlight&&typeof t.highlight=="object"&&!Array.isArray(t.highlight)?t.highlight:{};return{hover:HIGHLIGHT_HOVER.includes(e.hover)?e.hover:"",active:HIGHLIGHT_ACTIVE.includes(e.active)?e.active:"",accent:e.accent?colourToCss(e.accent):""}}export function applyItemHighlight(t,e){if(!t)return!1;const{hover:o,active:r,accent:n}=itemHighlightAttrs(e);return o&&t.setAttribute("data-menu-item-hover",o),r&&t.setAttribute("data-menu-item-active",r),n&&t.style.setProperty("--dm-menu-highlight",n),!!(o||r||n)}function c(t){if(typeof t!="string"||!t)return"";const e=t.split("#")[0].split("?")[0];return e.startsWith("/")?e.length>1&&e.endsWith("/")?e.slice(0,-1):e:""}export function isCurrentItem(t,e){const o=c(t),r=c(e);return!!o&&!!r&&o===r}export{CSS_CLASS_RE,CSS_CLASS_MAX,CSS_CLASS_MAX_LEN,cssClasses,cssClassProblems,normaliseCssClasses,applyClasses}from"./css-classes.mjs";
|
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{makeBadgeEl as O,applyColour as B,applyPill as J,applyFloat as W,applyHighlight as z,applyItemHighlight as X,itemHighlightAttrs as G,isCurrentItem as j,menuAlign as Y,applyClasses as M,cssClasses as U}from"/public/js/menu-decor.mjs?v=20261009-menu-classes";import{initFloatingMenus as K}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as R,markInvalidFields as P,showValidationPopup as V}from"/public/js/forms.js?v=20260927-submit-btn";import{buildWizardSteps as Q}from"/public/js/form-steps.mjs";import{applySubmitButtons as Z,applyWizardButtons as ee}from"/public/js/form-submit.mjs";$(()=>{const x=window.__CMS_NAV__||{},y=window.__CMS_SITE__||{};if(y.autoTheme?.enabled){let t=function(e){const i=(e||"07:00").split(":");return+i[0]*60+(+i[1]||0)},s=function(){const e=new Date,i=e.getHours()*60+e.getMinutes();return i>=t(n.dayStart)&&i<t(n.nightStart)?n.dayTheme:n.nightTheme},a=function(e){const i=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(i.theme);for(const p of[...document.body.classList])p.startsWith("dm-custom-")&&document.body.classList.remove(p);i.custom&&document.body.classList.add(i.custom)};const n=y.autoTheme;a(s()),setInterval(()=>a(s()),6e4)}const _=$("#site-navbar");if(_.length&&x.brand){let s=function(c,h=0){return Array.isArray(c)?c.filter(r=>!(r&&r.type==="spacer")).filter(r=>!(r&&r.type==="separator"&&h===0)).map(r=>r&&r.type==="separator"?{divider:!0}:Array.isArray(r?.items)?{...r,items:s(r.items,h+1)}:r):c},a=function(c){return Array.isArray(c)?c.filter(h=>!(h&&(h.type==="separator"||h.type==="spacer"))):[]};const n={...x.brand},t=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let c="";n.logo?c+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(c+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(c+=`<span class="navbar-brand-text${t}">${n.text}</span>`),n.tagline&&(c+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=c}else t&&n.text&&(n.html=`<span class="navbar-brand-text${t}">${n.text}</span>`);const e=x.position==="floating",i=x.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:n,items:s(x.items||[]),variant:x.variant||"dark",position:e?"static":x.position||"sticky",collapsible:!0,appearOnHover:!!x.appearOnHover}),Domma.icons.scan("#site-navbar");const p=_.get(0);p.classList.add(`dm-nav-align-${Y(x)||"centre"}`),i&&_.get(0).classList.add("dm-nav-vertical",x.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),z(p,x),M(p,x.class),e&&(W(_.get(0),x),K(_.get(0).parentNode||document));const g=p.querySelector(".navbar-toggle"),u=p.querySelector(".navbar-collapse");if(g&&u){let c=null;const h=()=>{u.classList.contains("show")&&g.click()},r=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},o=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",h),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};g.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?o():r()})}),u.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(r)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&u.classList.contains("show")&&h()})}const m=p.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let h=0;for(const r of x.items||[])if(!(r&&r.type==="separator")){if(r&&r.type==="spacer"){const o=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md";o.className=`dm-menu-spacer dm-menu-spacer--${l}`,o.setAttribute("aria-hidden","true"),m.insertBefore(o,c[h]||null);continue}h++}}const b=a(x.items||[]);p.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const h=b[parseInt(c.dataset.index,10)];if(!h)return;const r=c.dataset.subindex!=null,o=r&&Array.isArray(h.items)?h.items[parseInt(c.dataset.subindex,10)]:h;if(!o)return;o.colour&&B(c,o.colour),o.pill&&!r&&J(c,o.pill),X(c,o),M(c.closest("li"),o.class);const l=O(o.badge);l&&c.appendChild(l),j(o.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const C=$("#site-footer");if(C.length){let e=function(o){return String(o??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},i=function(o){return e(o).replace(/'/g,"'")},p=function(o){if(o&&o.type==="separator")return'<li class="footer-sep"><hr></li>';if(o&&o.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(o.size)?o.size:"md"}" aria-hidden="true"></li>`;const l=i(o.url||"#"),d=e(o.text||""),w=Array.isArray(o.items)&&o.items.length?`<ul>${o.items.map(p).join("")}</ul>`:"",v=G(o),D=[v.hover&&` data-menu-item-hover="${i(v.hover)}"`,v.active&&` data-menu-item-active="${i(v.active)}"`].filter(Boolean).join(""),q=v.accent?` style="--dm-menu-highlight:${i(v.accent)}"`:"",k=U(o.class).join(" ");return`<li${k?` class="${i(k)}"`:""}><a href="${l}"${D}${q}>${d}</a>${w}</li>`},g=function(o,l){return(o||[]).forEach(d=>{d&&(d.type==="separator"||d.type==="spacer")||(l.push(d),Array.isArray(d.items)&&d.items.length&&g(d.items,l))}),l};const n=y.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const a=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(a.copyright&&(s+=`<p>${e(a.copyright)}</p>`),a.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${a.primary.map(p).join("")}</ul></nav>`),a.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${a.legal.map(p).join("")}</ul></nav>`),y.footer){const o=Object.keys(t).filter(l=>n[l]);o.length&&(s+='<div class="footer-social">',o.forEach(l=>{const{label:d,svg:w}=t[l];s+=`<a href="${n[l]}" target="_blank" rel="noopener noreferrer" aria-label="${d}" class="footer-social-link">${w}</a>`}),s+="</div>")}s+="</div>",C.html(s);const u=[...g(a.primary,[]),...g(a.legal,[])];C.get(0).querySelectorAll(".footer-nav a").forEach((o,l)=>{const d=u[l];if(!d)return;d.colour&&B(o,d.colour);const w=O(d.badge);w&&o.appendChild(w),j(d.url,location.pathname)&&(o.classList.add("is-active"),o.setAttribute("aria-current","page"))}),z(C.get(0).querySelector(".footer-nav--primary"),{highlight:a.primaryHighlight}),z(C.get(0).querySelector(".footer-nav--legal"),{highlight:a.legalHighlight}),M(C.get(0).querySelector(".footer-nav--primary"),a.primaryClass),M(C.get(0).querySelector(".footer-nav--legal"),a.legalClass);const b=y.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),h=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),r=C.get(0).querySelector(".footer-inner");if(b&&r){const o=document.createElement("input");o.type="checkbox",o.className="form-switch-input",o.id="dm-motion-switch",o.checked=h,o.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const l=document.createElement("span");l.className="form-switch-label",l.textContent="Reduce motion";const d=document.createElement("label");d.className="form-switch footer-motion-switch",d.title="Reduce motion",d.appendChild(o),d.appendChild(l),r.appendChild(d)}}$("#site-sidebar").length&&Domma.elements.sidebar("#site-sidebar",{autoGenerate:!0,selector:"h2, h3",collapsible:!1,push:!0,contentSelector:".site-content"}),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const f=$(".page-body");if(f.length){f.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),f.find(".tabs").each(function(){Domma.elements.tabs(this)}),f.find(".carousel").each(function(){const n={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(n.animationDuration=t)}this.dataset.animationEasing&&(n.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=n),this._dmCarousel=Domma.elements.carousel(this,n)}),f.find(".dm-countdown").each(function(){const n={autoStart:!0},t=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),a=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=a?new Date(+a[1],+a[2]-1,+a[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?n.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(n.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const i=/^dd:/i.test(t);n.format=i?"hh:mm:ss":t||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const p=this,g=m=>String(m).padStart(2,"0"),u=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=p.querySelector(".dm-timer-time");c&&(c.textContent=`${g(Math.floor(b/86400))}:${g(Math.floor(b%86400/3600))}:${g(Math.floor(b%3600/60))}:${g(b%60)}`)};i&&(n.onTick=u),Domma.elements.timer(this,n),i&&u(n.duration||0)}),f.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),f.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(a=>{const e={title:a.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:a.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return a.dataset.date&&(e.date=a.dataset.date),a.dataset.status&&(e.status=a.dataset.status),a.dataset.entryId&&(e._entryId=a.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...n.length?{items:n}:{}});n.length&&(this._dmCtx={instance:s,items:n})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(n=>{const t=n.dataset.revealMode||"stagger",s=n.dataset.revealAnimation||"slide-up",a=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,i=parseInt(n.dataset.revealDelay,10)||0,p=n.dataset.revealDirection==="rtl",g=Array.from(n.children),u={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};g.forEach((m,b)=>{m.style.opacity="0",m.style.transform=u[s]||"",m.style.transition=`opacity ${a}ms ease, transform ${a}ms ease`;const c=p?g.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${i+c*e}ms`:`${i}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});g.forEach(b=>m.observe(b))}))}),f.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),f.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const n=this.dataset.soTarget,t=document.getElementById(n);if(!t)return;const s=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",s.setContent(t),s.open()})})}if(typeof $.setup=="function"){const n=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const s=atob(t.dataset.config),a=JSON.parse(s);Object.assign(n,a)}catch{}}),Object.keys(n).length>0){const t={};for(const[s,a]of Object.entries(n)){const e=a?.events?.click,{confirm:i,toast:p,alert:g,prompt:u,...m}=e||{};i||p||g||u?($(s).on("click",async function(c){if(c.preventDefault(),i&&!await E.confirm(i))return;let h=null;if(!(u&&(h=await E.prompt(u,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),h===null))){if(m.target){const r=$(m.target);m.toggleClass&&r.toggleClass(m.toggleClass),m.addClass&&r.addClass(m.addClass),m.removeClass&&r.removeClass(m.removeClass),h!==null&&(m.setText&&r.text(h),m.setVal&&r.val(h),m.setAttr&&r.attr(m.setAttr,h))}m.href&&(window.location.href=m.href),p&&E.toast(p,{type:m.toastType||"success"}),g&&E.alert(g)}}),Object.keys(m).length&&(t[s]={...a,events:{...a.events,click:m}})):t[s]=a}$.setup(t)}}f.length&&I(f.get(0))}),window.wireCTAButtons=I;function I(x){x.querySelectorAll(".dm-cta-trigger").forEach(y=>{y.__ctaWired||(y.__ctaWired=!0,y.addEventListener("click",async()=>{const _=y.dataset.action,C=y.dataset.entry,A=y.dataset.confirm;let f=S.get("auth_token");if(!f){E.toast("Please log in to perform this action.",{type:"warning"});return}if(A&&!await E.confirm(A))return;const n=Array.from(y.childNodes).map(s=>s.cloneNode(!0));y.disabled=!0,y.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${_}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(y.dataset.scope?{entryId:C,scope:y.dataset.scope}:{entryId:C})});try{let s=await t(f);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(i.ok){const{token:p}=await i.json();S.set("auth_token",p),f=p,s=await t(f)}}}const a=await s.json().catch(()=>({}));if(!s.ok)throw new Error(a.error||a.message||`Error ${s.status}`);E.toast(a.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{y.disabled=!1,y.textContent="",n.forEach(s=>y.appendChild(s)),Domma.icons.scan(y)}}))})}(function(){const y=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!y.length)return;const _=S.get("auth_token");function C(f,n){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(n){s.appendChild(document.createTextNode("Please "));const a=document.createElement("a");a.href="/login",a.textContent="sign in",s.appendChild(a),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=f;return t.appendChild(s),t}function A(f,n){const t=document.createElement("template");t.innerHTML=n||"",f.replaceWith(t.content)}y.forEach(async f=>{const n=f.dataset.collectionAttrs;if(!n)return;if(!_){f.replaceChildren(C("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:n})});try{let s=_,a=await t(s);if(a.status===401){const i=S.get("auth_refresh_token");if(i){const p=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:i})});if(p.ok){const{token:g}=await p.json();S.set("auth_token",g),s=g,a=await t(s)}}}if(!a.ok){const{error:i}=await a.json().catch(()=>({}));f.replaceChildren(C(i||"Unable to load entries.",!1));return}const{html:e}=await a.json();A(f,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{f.replaceChildren(C("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const y=document.querySelectorAll("[data-collection-table]");!y.length||typeof T>"u"||!T.create||y.forEach(_=>{let C;try{C=JSON.parse(atob(_.dataset.payload))}catch{return}const{columns:A,rows:f,search:n,sortable:t,exportable:s,pageSize:a,empty:e,ctaConfig:i,slug:p,exportCfg:g}=C;if(!A?.length)return;if(i){const b=A.findIndex(c=>c.key==="_cta");b!==-1&&(A[b]={key:"_cta",title:"",render:(c,h)=>{const r=document.createElement("button");if(r.className=`btn btn-${i.style||"primary"} dm-cta-trigger`,r.dataset.action=i.action||"",i.scope&&(r.dataset.scope=i.scope),r.dataset.entry=h._entryId||"",i.confirm&&(r.dataset.confirm=i.confirm),i.icon){const o=document.createElement("span");o.dataset.icon=i.icon,r.appendChild(o),r.appendChild(document.createTextNode(" "))}return r.appendChild(document.createTextNode(i.label||"Run")),r}})}const u="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=u,_.replaceChildren(m),T.create("#"+u,{data:f,columns:A,search:n,sortable:t,exportable:s,pageSize:a,emptyMessage:e}),i&&I(m),_._dmTable={columns:A,rows:f,slug:p,exportCfg:g,render(b){T.create("#"+u,{data:b,columns:A,search:n,sortable:t,exportable:s,pageSize:a,emptyMessage:e}),i&&I(m)}}})})(),(function(){const y=document.querySelectorAll("[data-form-inline]");if(!y.length||typeof F>"u")return;function _(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function C(t,s){const a={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),p=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,g={...e.formConfig||{}};g.span==="full"&&s&&(g.span=s);const u={type:p,required:_(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...g}};e.minLength!==void 0&&(u.minLength=e.minLength),e.maxLength!==void 0&&(u.maxLength=e.maxLength),e.min!==void 0&&(u.min=e.min),e.max!==void 0&&(u.max=e.max),i&&(e.variant&&(u.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(u.multiple=!0),e.density&&(u.density=e.density),e.columns&&(u.columns=e.columns),e.accent&&(u.accent=e.accent),e.accentStyle&&(u.accentStyle=e.accentStyle),e.glow&&(u.glow=!0),e.glowColour&&(u.glowColour=e.glowColour),e.shadow&&(u.shadow=e.shadow),e.shadowColour&&(u.shadowColour=e.shadowColour)),a[e.name]=u}),a}function A(t){const s={};return(t||[]).forEach(a=>{if(!(!a.name||a.type==="page-break"||a.type==="spacer")&&(a.type==="select"||a.type==="multiselect")&&a.required){const e=(a.options||[])[0];e&&(s[a.name]=typeof e=="object"?e.value:e)}}),s}function f(t,s){(s||[]).forEach(a=>{if(a.type!=="date"||!a.name)return;const e=t.querySelector(`[name="${a.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(t,s,a){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=a?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}y.forEach(t=>{let s;try{s=JSON.parse(atob(t.dataset.formInline))}catch{return}const a=s.fields||[],e=s.settings||{},i=Number(e.columns)===3?3:2,p=e.layout||"grid",g=a.some(r=>r.type==="page-break"),u=async r=>{if(t.dataset.triggerBlocked==="true"){const o=t._formLogicRuntime,l=o&&o.submitBlock?o.submitBlock().reasons:[];n(t,l.join(" ")||"This form cannot be submitted yet.",!0);const d=new Error("Blocked by a form trigger");throw d.formSubmitFailed=!0,d}try{const o=t.querySelector(".fb-form-honeypot"),l=o?.querySelector('input[type="text"]')||null,d=o?.querySelector('[name="_t"]')||null,w=Object.assign({},r);delete w._t,o?.dataset.hpName&&delete w[o.dataset.hpName],l!==null&&(w._hp=l.value),d!==null&&(w._t=d.value);const v=await H.post(`/api/forms/submit/${s.slug}`,w);if(v&&v.error){n(t,v.error,!0);const D=new Error(v.error);throw D.formSubmitFailed=!0,D}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);n(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(o){throw o.formSubmitFailed||n(t,o.message||"Submission failed. Please try again.",!0),o}},m=Date.now();function b(r){const o=r.querySelector("form");if(!o||o.querySelector(".fb-form-honeypot"))return;const l=document.createElement("div");l.className="fb-form-honeypot",l.setAttribute("aria-hidden","true");const d=document.createElement("input");d.name=o.querySelector('[name="website"]')?"_website":"website",l.dataset.hpName=d.name,d.type="text",d.tabIndex=-1,d.autocomplete="url",d.placeholder="https://",l.appendChild(d);const w=document.createElement("input");w.name="_t",w.type="hidden",w.value=m,l.appendChild(w),o.appendChild(l)}function c(r){if(!window.FormLogicEngine||!a.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const o=new window.FormLogicEngine.FormLogicRuntime(s,t,r?{baseValues:r}:void 0);if(o.init(),t._formLogicRuntime=o,t._formLogicObserved)return o;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(d){for(const w of d)for(const v of w.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=l}return o}let h=!1;if(t.addEventListener("dm-form-end",r=>{const o=r.detail?.validation;if(o&&!o.valid){P(t,o.missing),V(o);return}h||(h=!0,u(r.detail?.values||{}).catch(()=>{}).finally(()=>{h=!1}))}),g&&F.wizard){const r=Q(a,s.title),o=r.map(k=>({title:k.title,description:k.description,fields:C(k.fields,i)})),l=r.map(k=>k.fields);let d=0,w=null,v=null;const D=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const N=L.validateFields(t,l[d]||[]);N.valid||(k.preventDefault(),k.stopImmediatePropagation(),P(t,N.missing),V(N))},q=()=>{const k=l[d]||a;ee(t,e),f(t,k),R(t,k),e.honeypot!==!1&&b(t),w&&w.destroy(),w=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",D,!0))};v=F.wizard(t,{schema:{steps:o},layout:p,columns:i,finishText:e.submitText||"Finish",onSubmit:u,onStepChange:k=>{d=k,setTimeout(q,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=o.length||L!==d&&v.goToStep(L)}),Promise.resolve(v).then(q)}else if(F.render){const r=F.render(t,C(a,i),A(a),{submitText:e.submitText||"Submit",layout:p,columns:i,onSubmit:u});Promise.resolve(r).then(function(){Z(t,e,p),f(t,a),R(t,a),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
1
|
+
import{makeBadgeEl as O,applyColour as B,applyPill as W,applyFloat as X,applyHighlight as z,applyItemHighlight as G,itemHighlightAttrs as Y,isCurrentItem as j,menuAlign as U,applyClasses as M,cssClasses as K}from"/public/js/menu-decor.mjs?v=20261009-menu-classes";import{initFloatingMenus as Q}from"/public/js/menu-float.js?v=20260829-float-panel";import{enhancePickerFields as R,markInvalidFields as P,showValidationPopup as V}from"/public/js/forms.js?v=20261009-form-classes";import{buildWizardSteps as Z}from"/public/js/form-steps.mjs";import{applyFormClasses as J,applySubmitButtons as ee,applyWizardButtons as te}from"/public/js/form-submit.mjs";$(()=>{const x=window.__CMS_NAV__||{},y=window.__CMS_SITE__||{};if(y.autoTheme?.enabled){let t=function(e){const i=(e||"07:00").split(":");return+i[0]*60+(+i[1]||0)},s=function(){const e=new Date,i=e.getHours()*60+e.getMinutes();return i>=t(n.dayStart)&&i<t(n.nightStart)?n.dayTheme:n.nightTheme},a=function(e){const i=n.apply&&n.apply[e]||{theme:e,custom:""};Domma.theme.set(i.theme);for(const p of[...document.body.classList])p.startsWith("dm-custom-")&&document.body.classList.remove(p);i.custom&&document.body.classList.add(i.custom)};const n=y.autoTheme;a(s()),setInterval(()=>a(s()),6e4)}const _=$("#site-navbar");if(_.length&&x.brand){let s=function(c,h=0){return Array.isArray(c)?c.filter(r=>!(r&&r.type==="spacer")).filter(r=>!(r&&r.type==="separator"&&h===0)).map(r=>r&&r.type==="separator"?{divider:!0}:Array.isArray(r?.items)?{...r,items:s(r.items,h+1)}:r):c},a=function(c){return Array.isArray(c)?c.filter(h=>!(h&&(h.type==="separator"||h.type==="spacer"))):[]};const n={...x.brand},t=n.size&&n.size!=="md"?` navbar-brand-${n.size}`:"";if(n.logo||n.icon||n.tagline){let c="";n.logo?c+=`<img src="${n.logo}" class="navbar-brand-logo" alt="${n.text||""}">`:n.icon&&(c+=`<span data-icon="${n.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),n.text&&(c+=`<span class="navbar-brand-text${t}">${n.text}</span>`),n.tagline&&(c+=`<small class="navbar-brand-tagline">${n.tagline}</small>`),n.html=c}else t&&n.text&&(n.html=`<span class="navbar-brand-text${t}">${n.text}</span>`);const e=x.position==="floating",i=x.orientation==="vertical";Domma.elements.navbar("#site-navbar",{brand:n,items:s(x.items||[]),variant:x.variant||"dark",position:e?"static":x.position||"sticky",collapsible:!0,appearOnHover:!!x.appearOnHover}),Domma.icons.scan("#site-navbar");const p=_.get(0);p.classList.add(`dm-nav-align-${U(x)||"centre"}`),i&&_.get(0).classList.add("dm-nav-vertical",x.side==="right"?"dm-nav-vertical-right":"dm-nav-vertical-left"),z(p,x),M(p,x.class),e&&(X(_.get(0),x),Q(_.get(0).parentNode||document));const g=p.querySelector(".navbar-toggle"),u=p.querySelector(".navbar-collapse");if(g&&u){let c=null;const h=()=>{u.classList.contains("show")&&g.click()},r=()=>{c&&(c.remove(),c=null),document.body.classList.remove("dm-drawer-open")},o=()=>{c||(c=document.createElement("div"),c.className="dm-navbar-backdrop",c.addEventListener("click",h),document.body.appendChild(c),document.body.classList.add("dm-drawer-open"))};g.addEventListener("click",()=>{requestAnimationFrame(()=>{u.classList.contains("show")?o():r()})}),u.addEventListener("click",l=>{l.target.closest("a")&&requestAnimationFrame(r)}),document.addEventListener("keydown",l=>{l.key==="Escape"&&u.classList.contains("show")&&h()})}const m=p.querySelector(".navbar-nav");if(m){const c=Array.from(m.children);let h=0;for(const r of x.items||[])if(!(r&&r.type==="separator")){if(r&&r.type==="spacer"){const o=document.createElement("li"),l=["xs","sm","md","lg","xl","flex"].includes(r.size)?r.size:"md";o.className=`dm-menu-spacer dm-menu-spacer--${l}`,o.setAttribute("aria-hidden","true"),m.insertBefore(o,c[h]||null);continue}h++}}const b=a(x.items||[]);p.querySelectorAll(".navbar-link[data-index], .navbar-dropdown-item[data-index]").forEach(c=>{const h=b[parseInt(c.dataset.index,10)];if(!h)return;const r=c.dataset.subindex!=null,o=r&&Array.isArray(h.items)?h.items[parseInt(c.dataset.subindex,10)]:h;if(!o)return;o.colour&&B(c,o.colour),o.pill&&!r&&W(c,o.pill),G(c,o),M(c.closest("li"),o.class);const l=O(o.badge);l&&c.appendChild(l),j(o.url,location.pathname)&&(c.classList.add("active"),c.setAttribute("aria-current","page"))})}const C=$("#site-footer");if(C.length){let e=function(o){return String(o??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},i=function(o){return e(o).replace(/'/g,"'")},p=function(o){if(o&&o.type==="separator")return'<li class="footer-sep"><hr></li>';if(o&&o.type==="spacer")return`<li class="dm-menu-spacer dm-menu-spacer--${["xs","sm","md","lg","xl","flex"].includes(o.size)?o.size:"md"}" aria-hidden="true"></li>`;const l=i(o.url||"#"),d=e(o.text||""),w=Array.isArray(o.items)&&o.items.length?`<ul>${o.items.map(p).join("")}</ul>`:"",v=Y(o),D=[v.hover&&` data-menu-item-hover="${i(v.hover)}"`,v.active&&` data-menu-item-active="${i(v.active)}"`].filter(Boolean).join(""),q=v.accent?` style="--dm-menu-highlight:${i(v.accent)}"`:"",k=K(o.class).join(" ");return`<li${k?` class="${i(k)}"`:""}><a href="${l}"${D}${q}>${d}</a>${w}</li>`},g=function(o,l){return(o||[]).forEach(d=>{d&&(d.type==="separator"||d.type==="spacer")||(l.push(d),Array.isArray(d.items)&&d.items.length&&g(d.items,l))}),l};const n=y.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let s='<div class="footer-inner container">';const a=window.__CMS_FOOTER__||{primary:[],legal:[],copyright:""};if(a.copyright&&(s+=`<p>${e(a.copyright)}</p>`),a.primary.length&&(s+=`<nav class="footer-nav footer-nav--primary"><ul>${a.primary.map(p).join("")}</ul></nav>`),a.legal.length&&(s+=`<nav class="footer-nav footer-nav--legal"><ul>${a.legal.map(p).join("")}</ul></nav>`),y.footer){const o=Object.keys(t).filter(l=>n[l]);o.length&&(s+='<div class="footer-social">',o.forEach(l=>{const{label:d,svg:w}=t[l];s+=`<a href="${n[l]}" target="_blank" rel="noopener noreferrer" aria-label="${d}" class="footer-social-link">${w}</a>`}),s+="</div>")}s+="</div>",C.html(s);const u=[...g(a.primary,[]),...g(a.legal,[])];C.get(0).querySelectorAll(".footer-nav a").forEach((o,l)=>{const d=u[l];if(!d)return;d.colour&&B(o,d.colour);const w=O(d.badge);w&&o.appendChild(w),j(d.url,location.pathname)&&(o.classList.add("is-active"),o.setAttribute("aria-current","page"))}),z(C.get(0).querySelector(".footer-nav--primary"),{highlight:a.primaryHighlight}),z(C.get(0).querySelector(".footer-nav--legal"),{highlight:a.legalHighlight}),M(C.get(0).querySelector(".footer-nav--primary"),a.primaryClass),M(C.get(0).querySelector(".footer-nav--legal"),a.legalClass);const b=y.footer?.showMotionToggle!==!1,c=S.get("reduced_motion"),h=c!==null?!!c:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),r=C.get(0).querySelector(".footer-inner");if(b&&r){const o=document.createElement("input");o.type="checkbox",o.className="form-switch-input",o.id="dm-motion-switch",o.checked=h,o.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const l=document.createElement("span");l.className="form-switch-label",l.textContent="Reduce motion";const d=document.createElement("label");d.className="form-switch footer-motion-switch",d.title="Reduce motion",d.appendChild(o),d.appendChild(l),r.appendChild(d)}}$("#site-sidebar").length&&Domma.elements.sidebar("#site-sidebar",{autoGenerate:!0,selector:"h2, h3",collapsible:!1,push:!0,contentSelector:".site-content"}),Domma.icons.scan(),Domma.syntax?.scan&&Domma.syntax.scan();const f=$(".page-body");if(f.length){f.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),f.find(".tabs").each(function(){Domma.elements.tabs(this)}),f.find(".carousel").each(function(){const n={autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"};if(this.dataset.animationDuration){const t=parseInt(this.dataset.animationDuration,10);Number.isFinite(t)&&(n.animationDuration=t)}this.dataset.animationEasing&&(n.animationEasing=this.dataset.animationEasing),this.dataset.ctx&&(this._dmCtxSlides=Array.from(this.querySelectorAll(".carousel-slide")).map(t=>t.cloneNode(!0)),this._dmCarouselOpts=n),this._dmCarousel=Domma.elements.carousel(this,n)}),f.find(".dm-countdown").each(function(){const n={autoStart:!0},t=String(this.dataset.format||"").trim(),s=String(this.dataset.to||"").trim(),a=/^(\d{4})-(\d{2})-(\d{2})$/.exec(s),e=a?new Date(+a[1],+a[2]-1,+a[3]).getTime():s?new Date(s).getTime():NaN;Number.isFinite(e)?n.duration=Math.max(0,e-Date.now()):this.dataset.duration&&(n.duration=(parseInt(this.dataset.duration,10)||0)*1e3);const i=/^dd:/i.test(t);n.format=i?"hh:mm:ss":t||(n.duration>=36e5?"hh:mm:ss":"mm:ss");const p=this,g=m=>String(m).padStart(2,"0"),u=m=>{const b=Math.max(0,Math.floor(m/1e3)),c=p.querySelector(".dm-timer-time");c&&(c.textContent=`${g(Math.floor(b/86400))}:${g(Math.floor(b%86400/3600))}:${g(Math.floor(b%3600/60))}:${g(b%60)}`)};i&&(n.onTick=u),Domma.elements.timer(this,n),i&&u(n.duration||0)}),f.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),f.find(".dm-progression").each(function(){const n=Array.from(this.querySelectorAll(".dm-progression-item")).map(a=>{const e={title:a.querySelector(".dm-progression-item-title")?.textContent?.trim()||"",description:a.querySelector(".dm-progression-item-body")?.innerHTML?.trim()||""};return a.dataset.date&&(e.date=a.dataset.date),a.dataset.status&&(e.status=a.dataset.status),a.dataset.entryId&&(e._entryId=a.dataset.entryId),e}),t=this.dataset.layout==="centred"?"centered":this.dataset.layout||"vertical",s=Domma.elements.progression(this,{layout:t,theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0,allowHtml:!0,...n.length?{items:n}:{}});n.length&&(this._dmCtx={instance:s,items:n})});try{Domma.effects.reveal(".page-body .hero",{animation:"slide-up",duration:480,threshold:.06,stagger:60,once:!1})}catch{}document.querySelectorAll(".page-body .row[data-reveal]").forEach(n=>{const t=n.dataset.revealMode||"stagger",s=n.dataset.revealAnimation||"slide-up",a=parseInt(n.dataset.revealDuration,10)||400,e=parseInt(n.dataset.revealStagger,10)||60,i=parseInt(n.dataset.revealDelay,10)||0,p=n.dataset.revealDirection==="rtl",g=Array.from(n.children),u={"slide-up":"translateY(30px)","slide-down":"translateY(-30px)","slide-left":"translateX(30px)","slide-right":"translateX(-30px)",zoom:"scale(0.85)",flip:"perspective(600px) rotateX(15deg)"};g.forEach((m,b)=>{m.style.opacity="0",m.style.transform=u[s]||"",m.style.transition=`opacity ${a}ms ease, transform ${a}ms ease`;const c=p?g.length-1-b:b;m.style.transitionDelay=t==="stagger"?`${i+c*e}ms`:`${i}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const m=new IntersectionObserver(b=>{b.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",m.unobserve(c.target))})},{threshold:.1});g.forEach(b=>m.observe(b))}))}),f.find(".card[data-collapsible]").each(function(){const n=this.querySelector(".card-header");n&&n.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),f.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const n=this.dataset.soTarget,t=document.getElementById(n);if(!t)return;const s=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",s.setContent(t),s.open()})})}if(typeof $.setup=="function"){const n=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const s=atob(t.dataset.config),a=JSON.parse(s);Object.assign(n,a)}catch{}}),Object.keys(n).length>0){const t={};for(const[s,a]of Object.entries(n)){const e=a?.events?.click,{confirm:i,toast:p,alert:g,prompt:u,...m}=e||{};i||p||g||u?($(s).on("click",async function(c){if(c.preventDefault(),i&&!await E.confirm(i))return;let h=null;if(!(u&&(h=await E.prompt(u,{inputPlaceholder:m.promptPlaceholder||"",inputValue:m.promptDefault||""}),h===null))){if(m.target){const r=$(m.target);m.toggleClass&&r.toggleClass(m.toggleClass),m.addClass&&r.addClass(m.addClass),m.removeClass&&r.removeClass(m.removeClass),h!==null&&(m.setText&&r.text(h),m.setVal&&r.val(h),m.setAttr&&r.attr(m.setAttr,h))}m.href&&(window.location.href=m.href),p&&E.toast(p,{type:m.toastType||"success"}),g&&E.alert(g)}}),Object.keys(m).length&&(t[s]={...a,events:{...a.events,click:m}})):t[s]=a}$.setup(t)}}f.length&&I(f.get(0))}),window.wireCTAButtons=I;function I(x){x.querySelectorAll(".dm-cta-trigger").forEach(y=>{y.__ctaWired||(y.__ctaWired=!0,y.addEventListener("click",async()=>{const _=y.dataset.action,C=y.dataset.entry,A=y.dataset.confirm;let f=S.get("auth_token");if(!f){E.toast("Please log in to perform this action.",{type:"warning"});return}if(A&&!await E.confirm(A))return;const n=Array.from(y.childNodes).map(s=>s.cloneNode(!0));y.disabled=!0,y.textContent="Running\u2026";const t=s=>fetch(`/api/actions/${_}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify(y.dataset.scope?{entryId:C,scope:y.dataset.scope}:{entryId:C})});try{let s=await t(f);if(s.status===401){const e=S.get("auth_refresh_token");if(e){const i=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:e})});if(i.ok){const{token:p}=await i.json();S.set("auth_token",p),f=p,s=await t(f)}}}const a=await s.json().catch(()=>({}));if(!s.ok)throw new Error(a.error||a.message||`Error ${s.status}`);E.toast(a.message||"Action completed.",{type:"success"})}catch(s){E.toast(s.message||"Action failed.",{type:"error"})}finally{y.disabled=!1,y.textContent="",n.forEach(s=>y.appendChild(s)),Domma.icons.scan(y)}}))})}(function(){const y=document.querySelectorAll('.dm-collection-hydrate[data-collection-scope="mine"]');if(!y.length)return;const _=S.get("auth_token");function C(f,n){const t=document.createElement("div");t.className="dm-collection-display dm-collection-empty";const s=document.createElement("p");if(n){s.appendChild(document.createTextNode("Please "));const a=document.createElement("a");a.href="/login",a.textContent="sign in",s.appendChild(a),s.appendChild(document.createTextNode(" to view your entries."))}else s.textContent=f;return t.appendChild(s),t}function A(f,n){const t=document.createElement("template");t.innerHTML=n||"",f.replaceWith(t.content)}y.forEach(async f=>{const n=f.dataset.collectionAttrs;if(!n)return;if(!_){f.replaceChildren(C("",!0));return}const t=s=>fetch("/api/collections/render-scope",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({attrs:n})});try{let s=_,a=await t(s);if(a.status===401){const i=S.get("auth_refresh_token");if(i){const p=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:i})});if(p.ok){const{token:g}=await p.json();S.set("auth_token",g),s=g,a=await t(s)}}}if(!a.ok){const{error:i}=await a.json().catch(()=>({}));f.replaceChildren(C(i||"Unable to load entries.",!1));return}const{html:e}=await a.json();A(f,e),window.DommaCollectionBrowser?.hydrate&&window.DommaCollectionBrowser.hydrate(document)}catch{f.replaceChildren(C("Unable to load entries.",!1))}}),setTimeout(()=>{typeof Domma<"u"&&Domma.icons?.scan&&Domma.icons.scan(),typeof Domma<"u"&&Domma.syntax?.scan&&Domma.syntax.scan(),I(document.body)},100)})(),(function(){const y=document.querySelectorAll("[data-collection-table]");!y.length||typeof T>"u"||!T.create||y.forEach(_=>{let C;try{C=JSON.parse(atob(_.dataset.payload))}catch{return}const{columns:A,rows:f,search:n,sortable:t,exportable:s,pageSize:a,empty:e,ctaConfig:i,slug:p,exportCfg:g}=C;if(!A?.length)return;if(i){const b=A.findIndex(c=>c.key==="_cta");b!==-1&&(A[b]={key:"_cta",title:"",render:(c,h)=>{const r=document.createElement("button");if(r.className=`btn btn-${i.style||"primary"} dm-cta-trigger`,r.dataset.action=i.action||"",i.scope&&(r.dataset.scope=i.scope),r.dataset.entry=h._entryId||"",i.confirm&&(r.dataset.confirm=i.confirm),i.icon){const o=document.createElement("span");o.dataset.icon=i.icon,r.appendChild(o),r.appendChild(document.createTextNode(" "))}return r.appendChild(document.createTextNode(i.label||"Run")),r}})}const u="col-table-"+Math.random().toString(36).slice(2,7),m=document.createElement("div");m.id=u,_.replaceChildren(m),T.create("#"+u,{data:f,columns:A,search:n,sortable:t,exportable:s,pageSize:a,emptyMessage:e}),i&&I(m),_._dmTable={columns:A,rows:f,slug:p,exportCfg:g,render(b){T.create("#"+u,{data:b,columns:A,search:n,sortable:t,exportable:s,pageSize:a,emptyMessage:e}),i&&I(m)}}})})(),(function(){const y=document.querySelectorAll("[data-form-inline]");if(!y.length||typeof F>"u")return;function _(t){const s=t&&t.logic;return!!(s&&(s.visibility||s.requirement))}function C(t,s){const a={};return(t||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const i=e.type==="chooser"||!!(e.variant&&["select","radio","checkbox-group"].includes(e.type)),p=e.type==="checkbox"?"boolean":e.type==="date"||e.type==="icon"||e.type==="image"?"string":i?"chooser":e.type,g={...e.formConfig||{}};g.span==="full"&&s&&(g.span=s);const u={type:p,required:_(e)?!1:e.required,label:e.label,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...e.tooltip&&{tooltip:e.tooltip},...g}};e.minLength!==void 0&&(u.minLength=e.minLength),e.maxLength!==void 0&&(u.maxLength=e.maxLength),e.min!==void 0&&(u.min=e.min),e.max!==void 0&&(u.max=e.max),i&&(e.variant&&(u.variant=e.variant),(e.multiple||e.type==="checkbox-group")&&(u.multiple=!0),e.density&&(u.density=e.density),e.columns&&(u.columns=e.columns),e.accent&&(u.accent=e.accent),e.accentStyle&&(u.accentStyle=e.accentStyle),e.glow&&(u.glow=!0),e.glowColour&&(u.glowColour=e.glowColour),e.shadow&&(u.shadow=e.shadow),e.shadowColour&&(u.shadowColour=e.shadowColour)),a[e.name]=u}),a}function A(t){const s={};return(t||[]).forEach(a=>{if(!(!a.name||a.type==="page-break"||a.type==="spacer")&&(a.type==="select"||a.type==="multiselect")&&a.required){const e=(a.options||[])[0];e&&(s[a.name]=typeof e=="object"?e.value:e)}}),s}function f(t,s){(s||[]).forEach(a=>{if(a.type!=="date"||!a.name)return;const e=t.querySelector(`[name="${a.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function n(t,s,a){let e=t.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",t.appendChild(e)),e.textContent=s,e.style.cssText=a?"color:var(--dm-danger);margin-top:.75rem;":"color:var(--dm-success);margin-top:.75rem;"}y.forEach(t=>{let s;try{s=JSON.parse(atob(t.dataset.formInline))}catch{return}const a=s.fields||[],e=s.settings||{},i=Number(e.columns)===3?3:2,p=e.layout||"grid",g=a.some(r=>r.type==="page-break"),u=async r=>{if(t.dataset.triggerBlocked==="true"){const o=t._formLogicRuntime,l=o&&o.submitBlock?o.submitBlock().reasons:[];n(t,l.join(" ")||"This form cannot be submitted yet.",!0);const d=new Error("Blocked by a form trigger");throw d.formSubmitFailed=!0,d}try{const o=t.querySelector(".fb-form-honeypot"),l=o?.querySelector('input[type="text"]')||null,d=o?.querySelector('[name="_t"]')||null,w=Object.assign({},r);delete w._t,o?.dataset.hpName&&delete w[o.dataset.hpName],l!==null&&(w._hp=l.value),d!==null&&(w._t=d.value);const v=await H.post(`/api/forms/submit/${s.slug}`,w);if(v&&v.error){n(t,v.error,!0);const D=new Error(v.error);throw D.formSubmitFailed=!0,D}if(v?.redirect){window.location.href=v.redirect;return}for(;t.firstChild;)t.removeChild(t.firstChild);n(t,v?.message||e.successMessage||"Thank you for your submission.",!1)}catch(o){throw o.formSubmitFailed||n(t,o.message||"Submission failed. Please try again.",!0),o}},m=Date.now();function b(r){const o=r.querySelector("form");if(!o||o.querySelector(".fb-form-honeypot"))return;const l=document.createElement("div");l.className="fb-form-honeypot",l.setAttribute("aria-hidden","true");const d=document.createElement("input");d.name=o.querySelector('[name="website"]')?"_website":"website",l.dataset.hpName=d.name,d.type="text",d.tabIndex=-1,d.autocomplete="url",d.placeholder="https://",l.appendChild(d);const w=document.createElement("input");w.name="_t",w.type="hidden",w.value=m,l.appendChild(w),o.appendChild(l)}function c(r){if(!window.FormLogicEngine||!a.some(l=>l.logic||Array.isArray(l.triggers)&&l.triggers.length))return null;const o=new window.FormLogicEngine.FormLogicRuntime(s,t,r?{baseValues:r}:void 0);if(o.init(),t._formLogicRuntime=o,t._formLogicObserved)return o;if(t._formLogicObserved=!0,t.parentNode&&typeof MutationObserver<"u"){const l=new MutationObserver(function(d){for(const w of d)for(const v of w.removedNodes)if(v===t||v.nodeType===1&&v.contains&&v.contains(t)){t._formLogicRuntime&&t._formLogicRuntime.destroy(),l.disconnect();return}});l.observe(t.parentNode,{childList:!0,subtree:!1}),t._formLogicObserver=l}return o}let h=!1;if(t.addEventListener("dm-form-end",r=>{const o=r.detail?.validation;if(o&&!o.valid){P(t,o.missing),V(o);return}h||(h=!0,u(r.detail?.values||{}).catch(()=>{}).finally(()=>{h=!1}))}),g&&F.wizard){const r=Z(a,s.title),o=r.map(k=>({title:k.title,description:k.description,fields:C(k.fields,i)})),l=r.map(k=>k.fields);let d=0,w=null,v=null;const D=k=>{const L=window.FormLogicEngine;if(!L||!L.validateFields)return;const N=L.validateFields(t,l[d]||[]);N.valid||(k.preventDefault(),k.stopImmediatePropagation(),P(t,N.missing),V(N))},q=()=>{const k=l[d]||a;te(t,e),J(t,e,k),f(t,k),R(t,k),e.honeypot!==!1&&b(t),w&&w.destroy(),w=c(v?.getStepData?v.getStepData():void 0),t.querySelectorAll(".wizard-next, .wizard-submit").forEach(L=>L.addEventListener("click",D,!0))};v=F.wizard(t,{schema:{steps:o},layout:p,columns:i,finishText:e.submitText||"Finish",onSubmit:u,onStepChange:k=>{d=k,setTimeout(q,0)}}),t.addEventListener("dm-form-trigger",k=>{if(k.detail?.type!=="goto-step"||!v?.goToStep)return;const L=Number(k.detail.action.step);!Number.isFinite(L)||L<0||L>=o.length||L!==d&&v.goToStep(L)}),Promise.resolve(v).then(q)}else if(F.render){const r=F.render(t,C(a,i),A(a),{submitText:e.submitText||"Submit",layout:p,columns:i,onSubmit:u});Promise.resolve(r).then(function(){ee(t,e,p),J(t,e,a),f(t,a),R(t,a),e.honeypot!==!1&&b(t),c()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
@@ -26,7 +26,7 @@ import path from 'path';
|
|
|
26
26
|
import {deleteForm, ensureCollectionForForm, ensureFormsDir, listForms, readForm, slugify, writeForm} from '../../services/forms.js';
|
|
27
27
|
import {executeAction} from '../../services/actions.js';
|
|
28
28
|
// The same rules the browser draws the buttons by (a Cancel link must be safe).
|
|
29
|
-
import {buttonSettingsProblems, publicButtonSettings} from '../../../public/js/form-submit.mjs';
|
|
29
|
+
import {buttonSettingsProblems, formClassProblems, publicButtonSettings} from '../../../public/js/form-submit.mjs';
|
|
30
30
|
import {createTransport, sendFormEmail} from '../../services/email.js';
|
|
31
31
|
import {formActionFailed, formTriggerNotice} from '../../services/notification-sources.js';
|
|
32
32
|
import {
|
|
@@ -429,7 +429,7 @@ export async function formsRoutes(fastify) {
|
|
|
429
429
|
|
|
430
430
|
const now = new Date().toISOString();
|
|
431
431
|
const body = request.body || {};
|
|
432
|
-
const buttonProblems = buttonSettingsProblems(body.settings);
|
|
432
|
+
const buttonProblems = [...buttonSettingsProblems(body.settings), ...formClassProblems(body.settings, body.fields)];
|
|
433
433
|
if (buttonProblems.length) return reply.status(400).send({ error: buttonProblems[0] });
|
|
434
434
|
const form = {
|
|
435
435
|
slug,
|
|
@@ -527,7 +527,7 @@ export async function formsRoutes(fastify) {
|
|
|
527
527
|
const body = request.body || {};
|
|
528
528
|
// Only a Cancel link's address can do harm; refuse it rather than
|
|
529
529
|
// store something the page will not draw.
|
|
530
|
-
const buttonProblems = buttonSettingsProblems(body.settings);
|
|
530
|
+
const buttonProblems = [...buttonSettingsProblems(body.settings), ...formClassProblems(body.settings, body.fields)];
|
|
531
531
|
if (buttonProblems.length) return reply.status(400).send({ error: buttonProblems[0] });
|
|
532
532
|
const updated = {
|
|
533
533
|
...existing,
|
package/server/services/forms.js
CHANGED
|
@@ -7,7 +7,7 @@ import fs from 'fs/promises';
|
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import {fileURLToPath} from 'url';
|
|
9
9
|
import * as cache from './cache/index.js';
|
|
10
|
-
import {buttonSettingsProblems} from '../../public/js/form-submit.mjs';
|
|
10
|
+
import {buttonSettingsProblems, formClassProblems} from '../../public/js/form-submit.mjs';
|
|
11
11
|
|
|
12
12
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
const ROOT = path.resolve(__dirname, '..', '..');
|
|
@@ -134,7 +134,7 @@ export async function createForm(data) {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
// A Cancel link to javascript: and the like (public/js/form-submit.mjs).
|
|
137
|
-
const buttonProblems = buttonSettingsProblems(settings);
|
|
137
|
+
const buttonProblems = [...buttonSettingsProblems(settings), ...formClassProblems(settings, fields)];
|
|
138
138
|
if (buttonProblems.length) throw new Error(buttonProblems[0]);
|
|
139
139
|
|
|
140
140
|
// Throw if a form with this slug already exists
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
</script>
|
|
138
138
|
|
|
139
139
|
<!-- Site initialisation -->
|
|
140
|
-
<script src="/public/js/site.js?v=20261009-
|
|
140
|
+
<script src="/public/js/site.js?v=20261009-form-classes" type="module"></script>
|
|
141
141
|
<script src="/public/js/collection-context.js?v=20260927-ctx" type="module"></script>
|
|
142
142
|
{{ctxMenusModule}}
|
|
143
143
|
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
|
|
153
153
|
<!-- Core Forms (logic engine must load before renderer) -->
|
|
154
154
|
<script src="/public/js/form-logic-engine.js?v=20260927-submit-btn"></script>
|
|
155
|
-
<script src="/public/js/forms.js?v=
|
|
155
|
+
<script src="/public/js/forms.js?v=20261009-form-classes" type="module"></script>
|
|
156
156
|
|
|
157
157
|
<!-- Core effects runtime -->
|
|
158
158
|
<script src="/public/js/effects.js?v=20261003-characters"></script>
|