domma-cms 0.14.8 → 0.14.10
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/index.html
CHANGED
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
<!-- Admin CSS -->
|
|
19
19
|
<link rel="stylesheet" href="/admin/css/admin.css?v=20260422-2">
|
|
20
|
+
|
|
21
|
+
<!-- Forms CSS — needed for conditional logic preview (.fb-field-hidden, etc.) -->
|
|
22
|
+
<link rel="stylesheet" href="/public/css/forms.css">
|
|
20
23
|
</head>
|
|
21
24
|
<body class="dm-cloaked dm-theme-charcoal-dark dashboard-layout">
|
|
22
25
|
|
|
@@ -70,6 +73,9 @@
|
|
|
70
73
|
<!-- Marked - Markdown parser for page editor preview -->
|
|
71
74
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
72
75
|
|
|
76
|
+
<!-- Form Logic Engine — needed for conditional logic preview -->
|
|
77
|
+
<script src="/public/js/form-logic-engine.js"></script>
|
|
78
|
+
|
|
73
79
|
<!-- Admin App (ES module entry) -->
|
|
74
80
|
<script type="module" src="/admin/js/app.js"></script>
|
|
75
81
|
</body>
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
</div>
|
|
131
131
|
<div class="mb-3">
|
|
132
132
|
<label class="form-label">Layout</label>
|
|
133
|
-
<select id="setting-layout" class="form-
|
|
133
|
+
<select id="setting-layout" class="form-select">
|
|
134
134
|
<option value="stacked">Stacked</option>
|
|
135
135
|
<option value="inline">Inline</option>
|
|
136
136
|
<option value="grid">Grid</option>
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
<input id="setting-columns" type="number" class="form-input" min="1" max="6" value="2">
|
|
142
142
|
<div class="mt-3">
|
|
143
143
|
<label class="form-label">Submit Button Span</label>
|
|
144
|
-
<select id="setting-submit-span" class="form-
|
|
144
|
+
<select id="setting-submit-span" class="form-select">
|
|
145
145
|
<option value="">Auto (1 column)</option>
|
|
146
146
|
<option value="full">Full width</option>
|
|
147
147
|
</select>
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
</div>
|
|
195
195
|
<div>
|
|
196
196
|
<label class="form-label">Method</label>
|
|
197
|
-
<select id="action-webhook-method" class="form-
|
|
197
|
+
<select id="action-webhook-method" class="form-select">
|
|
198
198
|
<option value="POST">POST</option>
|
|
199
199
|
<option value="PUT">PUT</option>
|
|
200
200
|
</select>
|
|
@@ -208,7 +208,7 @@
|
|
|
208
208
|
<div class="card-body">
|
|
209
209
|
<div class="mb-3">
|
|
210
210
|
<label class="form-label">Action on Submit</label>
|
|
211
|
-
<select id="action-cms-slug" class="form-
|
|
211
|
+
<select id="action-cms-slug" class="form-select">
|
|
212
212
|
<option value="">— None —</option>
|
|
213
213
|
</select>
|
|
214
214
|
<p class="form-hint text-muted" style="margin-top:.3rem;font-size:.8rem;">
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{apiRequest as
|
|
2
|
-
`).filter(
|
|
3
|
-
`).filter(g=>g.trim()).map(g=>{const[h,...w]=g.split(":");return{value:h.trim(),label:w.join(":").trim()||h.trim()}});n.cascade={sourceField:u,mapping:s,defaultOptions:f},a=!0}}return a?n:void 0}function y(){b=b.map((e,t)=>D(t))}function v(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()),b.length===0){o&&(o.style.display="");return}o&&(o.style.display="none"),b.forEach((n,a)=>{const l=n.type==="page-break"?W(n,a,e):n.type==="spacer"?Y(n,a,e):G(n,a,e);t.appendChild(l)})}}function W(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--border-color,#444);border-radius:6px;overflow:hidden;margin-bottom:.5rem;background:var(--card-bg,rgba(255,255,255,.02));";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="\u2014 Page Break \u2014",l.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:rgba(120,120,120,.2);color:var(--text-muted,#888);white-space:nowrap;flex-shrink:0;font-style:italic;";const r=document.createElement("span");r.textContent=e.label||"Untitled Step",r.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-muted,#888);";const i=document.createElement("div");if(i.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.title="Move up",s.textContent="\u2191",s.addEventListener("click",f=>{f.stopPropagation(),y(),[b[t-1],b[t]]=[b[t],b[t-1]],v(o)}),i.appendChild(s)}if(t<b.length-1){const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.title="Move down",s.textContent="\u2193",s.addEventListener("click",f=>{f.stopPropagation(),y(),[b[t],b[t+1]]=[b[t+1],b[t]],v(o)}),i.appendChild(s)}const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Edit step",p.textContent="\u22EF",p.addEventListener("click",s=>{s.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),i.appendChild(p);const d=document.createElement("button");d.className="btn btn-xs btn-danger",d.title="Remove page break",d.textContent="\u2715",d.addEventListener("click",async s=>{s.stopPropagation(),await E.confirm("Remove this page break?")&&(y(),b.splice(t,1),v(o))}),i.appendChild(d),a.appendChild(l),a.appendChild(r),a.appendChild(i),a.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=document.createElement("div");m.className="fb-field-body",m.style.cssText="padding:.8rem;border-top:1px dashed var(--border-color,#444);display:none;";const c=k([C("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),C("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),u=c.querySelector(`#fb-pb-label-${t}`);return u&&u.addEventListener("input",()=>{r.textContent=u.value||"Untitled Step"}),m.appendChild(c),n.appendChild(a),n.appendChild(m),n}function Y(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--border-color,#444);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(--border-color,#444);";const r=document.createElement("span");r.textContent="Spacer",r.style.cssText="font-size:.7rem;color:var(--text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const i=document.createElement("div");i.style.cssText="flex:1;height:1px;background:var(--border-color,#444);";const p=document.createElement("div");if(p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;",t>0){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move up",m.textContent="\u2191",m.addEventListener("click",c=>{c.stopPropagation(),y(),[b[t-1],b[t]]=[b[t],b[t-1]],v(o)}),p.appendChild(m)}if(t<b.length-1){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move down",m.textContent="\u2193",m.addEventListener("click",c=>{c.stopPropagation(),y(),[b[t],b[t+1]]=[b[t+1],b[t]],v(o)}),p.appendChild(m)}const d=document.createElement("button");return d.className="btn btn-xs btn-danger",d.title="Remove spacer",d.textContent="\u2715",d.addEventListener("click",async m=>{m.stopPropagation(),y(),b.splice(t,1),v(o)}),p.appendChild(d),a.appendChild(l),a.appendChild(r),a.appendChild(i),a.appendChild(p),n.appendChild(a),n}function G(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--border-color,#333);border-radius:6px;overflow:hidden;margin-bottom:.5rem;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;background:var(--card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=P(e.type),l.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:var(--primary-soft,rgba(99,102,241,.15));color:var(--primary,#6366f1);white-space:nowrap;flex-shrink:0;";const r=document.createElement("span");r.textContent=e.label||"(unlabelled)",r.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const i=document.createElement("div");if(i.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Move up",c.textContent="\u2191",c.addEventListener("click",u=>{u.stopPropagation(),y(),[b[t-1],b[t]]=[b[t],b[t-1]],v(o)}),i.appendChild(c)}if(t<b.length-1){const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Move down",c.textContent="\u2193",c.addEventListener("click",u=>{u.stopPropagation(),y(),[b[t],b[t+1]]=[b[t+1],b[t]],v(o)}),i.appendChild(c)}const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Edit field",p.textContent="\u22EF",p.addEventListener("click",c=>{c.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),i.appendChild(p);const d=document.createElement("button");if(d.className="btn btn-xs btn-danger",d.title="Remove field",d.textContent="\u2715",d.addEventListener("click",async c=>{c.stopPropagation(),await E.confirm("Remove this field?")&&(y(),b.splice(t,1),v(o))}),i.appendChild(d),a.appendChild(l),a.appendChild(r),e.required){const c=document.createElement("span");c.textContent="required",c.style.cssText="font-size:.7rem;color:var(--danger,#ef4444);flex-shrink:0;",a.appendChild(c)}if(M(e.logic)){const c=document.createElement("span");c.textContent="\u26A1",c.title="Has conditional logic",c.style.cssText="font-size:.75rem;color:var(--primary,#6366f1);flex-shrink:0;",a.appendChild(c)}a.appendChild(i),a.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=K(e,t,r);return m.style.display="none",n.appendChild(a),n.appendChild(m),n}function K(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:.8rem;border-top:1px solid var(--border-color,#333);";const a=k([C("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),C("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),l=k([le("Type",`fb-type-${t}`,B,e.type||"string"),j("Required",`fb-required-${t}`,e.required||!1)]),r=k([C("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field"),C("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field")]),i=e.formConfig?.span,p=k([C("Column Span",`fb-span-${t}`,"number",i&&i!=="full"?String(i):"1","Columns to span (grid only)"),j("Full Width",`fb-fullwidth-${t}`,i==="full")]);p.classList.add("fb-grid-row"),p.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(a),n.appendChild(l),n.appendChild(r),n.appendChild(p);const d=n.querySelector(`#fb-label-${t}`),m=n.querySelector(`#fb-name-${t}`);d&&d.addEventListener("input",()=>{o&&(o.textContent=d.value||"(unlabelled)"),m&&!m.dataset.manuallyEdited&&(m.value=I(d.value))}),m&&m.addEventListener("input",()=>{m.dataset.manuallyEdited="1"});const c=n.querySelector(`#fb-type-${t}`);c&&c.addEventListener("change",()=>{const s=n.closest(".fb-field-card");if(s){const h=s.querySelector("span");h&&(h.textContent=P(c.value))}const f=n.querySelector(".fb-field-extras");f&&f.remove();const g=O(c.value,e,t);g&&n.appendChild(g)});const u=O(e.type,e,t);return u&&n.appendChild(u),n.appendChild(ne(e,t)),n}const Q=[{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"}],_=new Set(["is_empty","is_not_empty"]);function N(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--text-muted,#888);margin:.6rem 0 .3rem;text-transform:uppercase;letter-spacing:.04em;",t}function L(e,t,o,n,a){const l=document.createElement("div");l.className="fb-logic-cond-row",l.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const r=document.createElement("span");r.textContent="When",r.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const i=document.createElement("select");i.className="form-input fb-logic-cond-field",i.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",t.forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,e&&s.value===e.field&&(f.selected=!0),i.appendChild(f)});const p=document.createElement("select");p.className="form-input fb-logic-cond-op",p.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",Q.forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,e&&s.value===e.operator&&(f.selected=!0),p.appendChild(f)});const d=document.createElement("input");d.type="text",d.className="form-input fb-logic-cond-val",d.placeholder="value",d.style.cssText="flex:2;min-width:60px;font-size:.78rem;padding:.2rem .35rem;",d.value=e?.value||"",e&&_.has(e.operator)&&(d.style.display="none"),p.addEventListener("change",()=>{d.style.display=_.has(p.value)?"none":""});const m=document.createElement("span");m.textContent="\u2192",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const c=document.createElement("select");c.className=`form-input ${n}`,c.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",o.forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,s.value===a&&(f.selected=!0),c.appendChild(f)});const u=document.createElement("button");return u.type="button",u.className="btn btn-xs btn-danger",u.textContent="\u2715",u.style.flexShrink="0",u.addEventListener("click",()=>l.remove()),l.appendChild(r),l.appendChild(i),l.appendChild(p),l.appendChild(d),l.appendChild(m),l.appendChild(c),l.appendChild(u),l}function X(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(N("Visibility"));const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const l=document.createElement("span");l.textContent="Default:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const r=document.createElement("select");r.className="form-input fb-logic-vis-default",r.style.cssText="font-size:.8rem;padding:.25rem .4rem;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,s.value===(e.default||"visible")&&(f.selected=!0),r.appendChild(f)}),a.appendChild(l),a.appendChild(r),n.appendChild(a);const i=document.createElement("div");i.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const p=document.createElement("span");p.textContent="Transition:",p.style.cssText="font-size:.8rem;flex-shrink:0;";const d=document.createElement("select");d.className="form-input fb-logic-vis-transition",d.style.cssText="font-size:.8rem;padding:.25rem .4rem;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,s.value===(e.transition||"none")&&(f.selected=!0),d.appendChild(f)}),i.appendChild(p),i.appendChild(d),n.appendChild(i);const m=document.createElement("div");m.className="fb-logic-vis-rules";const c=o.map(s=>({value:s.name,label:s.label||s.name})),u=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(s=>{const f=(s.when?.all||s.when?.any||[])[0],g=s.then==="hidden"?"hidden":"visible";c.length>0&&m.appendChild(L(f,c,u,"fb-logic-vis-then",g))}),n.appendChild(m),c.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:.2rem;",s.textContent="+ Add visibility rule",s.addEventListener("click",()=>m.appendChild(L(null,c,u,"fb-logic-vis-then","visible"))),n.appendChild(s)}return n}function Z(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(N("Conditional Requirement"));const a=document.createElement("label");a.style.cssText="display:flex;align-items:center;gap:.4rem;font-size:.8rem;cursor:pointer;margin-bottom:.4rem;";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 r=document.createElement("div");r.className="fb-logic-req-rules";const i=o.map(d=>({value:d.name,label:d.label||d.name})),p=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(d=>{const m=(d.when?.all||d.when?.any||[])[0],c=d.then===!0?"true":"false";i.length>0&&r.appendChild(L(m,i,p,"fb-logic-req-then",c))}),n.appendChild(r),i.length>0){const d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",d.style.cssText="font-size:.73rem;margin-top:.2rem;",d.textContent="+ Add requirement rule",d.addEventListener("click",()=>r.appendChild(L(null,i,p,"fb-logic-req-then","true"))),n.appendChild(d)}return n}function A(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const o=document.createElement("select");o.className="form-input fb-logic-val-type",o.style.cssText="flex:0 0 auto;font-size:.78rem;padding:.2rem .35rem;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(i=>{const p=document.createElement("option");p.value=i.value,p.textContent=i.label,i.value===(e?.type||"regex")&&(p.selected=!0),o.appendChild(p)});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;font-size:.78rem;padding:.2rem .35rem;";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;font-size:.78rem;padding:.2rem .35rem;",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;font-size:.78rem;padding:.2rem .35rem;";const r=document.createElement("button");return r.type="button",r.className="btn btn-xs btn-danger",r.textContent="\u2715",r.style.flexShrink="0",r.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(a),t.appendChild(l),t.appendChild(r),t}function ee(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(N("Custom Validation"));const a=document.createElement("div");a.className="fb-logic-val-rules",(e||[]).forEach(r=>a.appendChild(A(r))),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:.2rem;",l.textContent="+ Add validation rule",l.addEventListener("click",()=>a.appendChild(A(null))),n.appendChild(l),n}function te(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(N("Cascade Options"));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 r=document.createElement("select");r.className="form-input fb-logic-cascade-source",r.style.cssText="flex:1;font-size:.8rem;padding:.25rem .4rem;";const i=document.createElement("option");i.value="",i.textContent="\u2014 none \u2014",r.appendChild(i),o.forEach(u=>{const s=document.createElement("option");s.value=u.name,s.textContent=u.label||u.name,u.name===e.sourceField&&(s.selected=!0),r.appendChild(s)}),a.appendChild(l),a.appendChild(r),n.appendChild(a);const p=document.createElement("p");p.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',p.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const d=document.createElement("textarea");d.className="form-input fb-logic-cascade-mapping",d.rows=4,d.style.cssText="font-family:monospace;font-size:.78rem;",d.placeholder='{"uk": [{"value": "london", "label": "London"}]}',d.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(p),n.appendChild(d);const m=document.createElement("p");m.textContent="Default options (one per line: value:Label)",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const c=document.createElement("textarea");return c.className="form-input fb-logic-cascade-defaults",c.rows=3,c.style.cssText="font-family:monospace;font-size:.78rem;",c.placeholder=`option1:Option 1
|
|
4
|
-
option2:Option 2`,
|
|
5
|
-
`),n.appendChild(m),n.appendChild(
|
|
1
|
+
import{apiRequest as T}from"/admin/js/api.js";const B=[{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:"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"}],z=new Set(["select","radio","checkbox-group"]);let b=[],w=null,q=null,N=null;function I(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function P(e){return B.find(t=>t.value===e)?.label||e}function M(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function V(e){const t={...b[e]};if(t.type==="spacer")return t;if(t.type==="page-break"){const g=document.getElementById(`fb-pb-label-${e}`),y=document.getElementById(`fb-pb-desc-${e}`);return g&&(t.label=g.value.trim()||t.label),y&&(t.description=y.value.trim()),t}const o=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),a=document.getElementById(`fb-type-${e}`),l=document.getElementById(`fb-required-${e}`),c=document.getElementById(`fb-placeholder-${e}`),s=document.getElementById(`fb-helper-${e}`),p=document.getElementById(`fb-tooltip-${e}`);if(o&&(t.label=o.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),a&&(t.type=a.value||t.type),l&&(t.required=l.checked),c&&(t.placeholder=c.value.trim()),s&&(t.helper=s.value.trim()),p&&(t.tooltip=p.value.trim()),z.has(t.type)){const g=document.getElementById(`fb-options-${e}`);g&&(t.options=g.value.split(`
|
|
2
|
+
`).filter(y=>y.trim()).map(y=>{const[S,...D]=y.split(":");return{value:S.trim(),label:D.join(":").trim()||S.trim()}}))}if(t.type==="textarea"){const g=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);g>0&&(t.formConfig={...t.formConfig||{},rows:g})}const d=document.getElementById(`fb-span-${e}`),m=document.getElementById(`fb-fullwidth-${e}`);if(d||m){const g={...t.formConfig||{}};if(m?.checked)g.span="full";else{const y=parseInt(d?.value,10);y>1?g.span=y:delete g.span}t.formConfig=Object.keys(g).length?g:void 0}const r=document.getElementById(`fb-minlength-${e}`)?.value;r&&(t.minLength=parseInt(r,10));const u=document.getElementById(`fb-maxlength-${e}`)?.value;u&&(t.maxLength=parseInt(u,10));const i=document.getElementById(`fb-min-${e}`)?.value;i!==""&&i!==void 0&&(t.min=parseFloat(i));const f=document.getElementById(`fb-max-${e}`)?.value;f!==""&&f!==void 0&&(t.max=parseFloat(f));const h=W(e);return h?t.logic=h:delete t.logic,t}function W(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 a=!1;const l=o.querySelector('[data-logic-section="visibility"]');if(l){const d=l.querySelector(".fb-logic-vis-default"),m=l.querySelector(".fb-logic-vis-transition"),r=Array.from(l.querySelectorAll(".fb-logic-cond-row")).map(f=>{const h=f.querySelector(".fb-logic-cond-field"),g=f.querySelector(".fb-logic-cond-op"),y=f.querySelector(".fb-logic-cond-val"),S=f.querySelector(".fb-logic-vis-then");return h?.value?{when:{all:[{field:h.value,operator:g.value,value:y.value}]},then:S.value}:null}).filter(Boolean),u=d?.value||"visible",i=m?.value||"none";(u!=="visible"||r.length>0||i!=="none")&&(n.visibility={default:u,conditions:r},i!=="none"&&(n.visibility.transition=i),a=!0)}const c=o.querySelector('[data-logic-section="requirement"]');if(c){const d=c.querySelector(".fb-logic-req-default"),m=Array.from(c.querySelectorAll(".fb-logic-cond-row")).map(r=>{const u=r.querySelector(".fb-logic-cond-field"),i=r.querySelector(".fb-logic-cond-op"),f=r.querySelector(".fb-logic-cond-val"),h=r.querySelector(".fb-logic-req-then");return u?.value?{when:{all:[{field:u.value,operator:i.value,value:f.value}]},then:h.value==="true"}:null}).filter(Boolean);m.length>0&&(n.requirement={default:d?.checked===!0,conditions:m},a=!0)}const s=o.querySelector('[data-logic-section="validation"]');if(s){const d=Array.from(s.querySelectorAll(".fb-logic-val-rule")).map(m=>{const r=m.querySelector(".fb-logic-val-type"),u=m.querySelector(".fb-logic-val-pattern"),i=m.querySelector(".fb-logic-val-flags"),f=m.querySelector(".fb-logic-val-message");if(!u?.value.trim())return null;const h=r?.value||"regex",g={type:h,message:f?.value.trim()||"Invalid value."};return h==="regex"?(g.pattern=u.value.trim(),i?.value.trim()&&(g.flags=i.value.trim())):g.field=u.value.trim(),g}).filter(Boolean);d.length>0&&(n.validation=d,a=!0)}const p=o.querySelector('[data-logic-section="cascade"]');if(p){const d=p.querySelector(".fb-logic-cascade-source"),m=p.querySelector(".fb-logic-cascade-mapping"),r=p.querySelector(".fb-logic-cascade-defaults"),u=d?.value?.trim();if(u){let i={};try{i=JSON.parse(m?.value||"{}")}catch{}const f=(r?.value||"").split(`
|
|
3
|
+
`).filter(h=>h.trim()).map(h=>{const[g,...y]=h.split(":");return{value:g.trim(),label:y.join(":").trim()||g.trim()}});n.cascade={sourceField:u,mapping:i,defaultOptions:f},a=!0}}return a?n:void 0}function v(){b=b.map((e,t)=>V(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()),b.length===0){o&&(o.style.display="");return}o&&(o.style.display="none"),b.forEach((n,a)=>{const l=n.type==="page-break"?Y(n,a,e):n.type==="spacer"?G(n,a,e):K(n,a,e);t.appendChild(l)})}}function Y(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--border-color,#444);border-radius:6px;overflow:hidden;margin-bottom:.5rem;background:var(--card-bg,rgba(255,255,255,.02));";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="\u2014 Page Break \u2014",l.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:rgba(120,120,120,.2);color:var(--text-muted,#888);white-space:nowrap;flex-shrink:0;font-style:italic;";const c=document.createElement("span");c.textContent=e.label||"Untitled Step",c.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-muted,#888);";const s=document.createElement("div");if(s.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const i=document.createElement("button");i.className="btn btn-xs btn-ghost",i.title="Move up",i.textContent="\u2191",i.addEventListener("click",f=>{f.stopPropagation(),v(),[b[t-1],b[t]]=[b[t],b[t-1]],x(o)}),s.appendChild(i)}if(t<b.length-1){const i=document.createElement("button");i.className="btn btn-xs btn-ghost",i.title="Move down",i.textContent="\u2193",i.addEventListener("click",f=>{f.stopPropagation(),v(),[b[t],b[t+1]]=[b[t+1],b[t]],x(o)}),s.appendChild(i)}const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Edit step",p.textContent="\u22EF",p.addEventListener("click",i=>{i.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),s.appendChild(p);const d=document.createElement("button");d.className="btn btn-xs btn-danger",d.title="Remove page break",d.textContent="\u2715",d.addEventListener("click",async i=>{i.stopPropagation(),await E.confirm("Remove this page break?")&&(v(),b.splice(t,1),x(o))}),s.appendChild(d),a.appendChild(l),a.appendChild(c),a.appendChild(s),a.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=document.createElement("div");m.className="fb-field-body",m.style.cssText="padding:.8rem;border-top:1px dashed var(--border-color,#444);display:none;";const r=k([C("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),C("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),u=r.querySelector(`#fb-pb-label-${t}`);return u&&u.addEventListener("input",()=>{c.textContent=u.value||"Untitled Step"}),m.appendChild(r),n.appendChild(a),n.appendChild(m),n}function G(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--border-color,#444);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(--border-color,#444);";const c=document.createElement("span");c.textContent="Spacer",c.style.cssText="font-size:.7rem;color:var(--text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const s=document.createElement("div");s.style.cssText="flex:1;height:1px;background:var(--border-color,#444);";const p=document.createElement("div");if(p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;",t>0){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move up",m.textContent="\u2191",m.addEventListener("click",r=>{r.stopPropagation(),v(),[b[t-1],b[t]]=[b[t],b[t-1]],x(o)}),p.appendChild(m)}if(t<b.length-1){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move down",m.textContent="\u2193",m.addEventListener("click",r=>{r.stopPropagation(),v(),[b[t],b[t+1]]=[b[t+1],b[t]],x(o)}),p.appendChild(m)}const d=document.createElement("button");return d.className="btn btn-xs btn-danger",d.title="Remove spacer",d.textContent="\u2715",d.addEventListener("click",async m=>{m.stopPropagation(),v(),b.splice(t,1),x(o)}),p.appendChild(d),a.appendChild(l),a.appendChild(c),a.appendChild(s),a.appendChild(p),n.appendChild(a),n}function K(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--border-color,#333);border-radius:6px;overflow:hidden;margin-bottom:.5rem;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;background:var(--card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=P(e.type),l.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:var(--primary-soft,rgba(99,102,241,.15));color:var(--primary,#6366f1);white-space:nowrap;flex-shrink:0;";const c=document.createElement("span");c.textContent=e.label||"(unlabelled)",c.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const s=document.createElement("div");if(s.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Move up",r.textContent="\u2191",r.addEventListener("click",u=>{u.stopPropagation(),v(),[b[t-1],b[t]]=[b[t],b[t-1]],x(o)}),s.appendChild(r)}if(t<b.length-1){const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Move down",r.textContent="\u2193",r.addEventListener("click",u=>{u.stopPropagation(),v(),[b[t],b[t+1]]=[b[t+1],b[t]],x(o)}),s.appendChild(r)}const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Edit field",p.textContent="\u22EF",p.addEventListener("click",r=>{r.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),s.appendChild(p);const d=document.createElement("button");if(d.className="btn btn-xs btn-danger",d.title="Remove field",d.textContent="\u2715",d.addEventListener("click",async r=>{r.stopPropagation(),await E.confirm("Remove this field?")&&(v(),b.splice(t,1),x(o))}),s.appendChild(d),a.appendChild(l),a.appendChild(c),e.required){const r=document.createElement("span");r.textContent="required",r.style.cssText="font-size:.7rem;color:var(--danger,#ef4444);flex-shrink:0;",a.appendChild(r)}if(M(e.logic)){const r=document.createElement("span");r.textContent="\u26A1",r.title="Has conditional logic",r.style.cssText="font-size:.75rem;color:var(--primary,#6366f1);flex-shrink:0;",a.appendChild(r)}a.appendChild(s),a.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=Q(e,t,c);return m.style.display="none",n.appendChild(a),n.appendChild(m),n}function Q(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:.8rem;border-top:1px solid var(--border-color,#333);";const a=k([C("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),C("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),l=k([ae("Type",`fb-type-${t}`,B,e.type||"string"),j("Required",`fb-required-${t}`,e.required||!1)]),c=k([C("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field")]),s=k([C("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field"),C("Tooltip",`fb-tooltip-${t}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),p=e.formConfig?.span,d=k([C("Column Span",`fb-span-${t}`,"number",p&&p!=="full"?String(p):"1","Columns to span (grid only)"),j("Full Width",`fb-fullwidth-${t}`,p==="full")]);d.classList.add("fb-grid-row"),d.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(a),n.appendChild(l),n.appendChild(c),n.appendChild(s),n.appendChild(d);const m=n.querySelector(`#fb-label-${t}`),r=n.querySelector(`#fb-name-${t}`);m&&m.addEventListener("input",()=>{o&&(o.textContent=m.value||"(unlabelled)"),r&&!r.dataset.manuallyEdited&&(r.value=I(m.value))}),r&&r.addEventListener("input",()=>{r.dataset.manuallyEdited="1"});const u=n.querySelector(`#fb-type-${t}`);u&&u.addEventListener("change",()=>{const f=n.closest(".fb-field-card");if(f){const y=f.querySelector("span");y&&(y.textContent=P(u.value))}const h=n.querySelector(".fb-field-extras");h&&h.remove();const g=O(u.value,e,t);g&&n.appendChild(g)});const i=O(e.type,e,t);return i&&n.appendChild(i),n.appendChild(le(e,t)),n}const X=[{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"}],_=new Set(["is_empty","is_not_empty"]);function $(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--text-muted,#888);margin:.6rem 0 .3rem;text-transform:uppercase;letter-spacing:.04em;",t}function L(e,t,o,n,a){const l=document.createElement("div");l.className="fb-logic-cond-row",l.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const c=document.createElement("span");c.textContent="When",c.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const s=document.createElement("select");s.className="form-select fb-logic-cond-field",s.style.cssText="flex:1 1 140px;min-width:140px;",t.forEach(i=>{const f=document.createElement("option");f.value=i.value,f.textContent=i.label,e&&i.value===e.field&&(f.selected=!0),s.appendChild(f)});const p=document.createElement("select");p.className="form-select fb-logic-cond-op",p.style.cssText="flex:1 1 160px;min-width:140px;",X.forEach(i=>{const f=document.createElement("option");f.value=i.value,f.textContent=i.label,e&&i.value===e.operator&&(f.selected=!0),p.appendChild(f)});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&&_.has(e.operator)&&(d.style.display="none"),p.addEventListener("change",()=>{d.style.display=_.has(p.value)?"none":""});const m=document.createElement("span");m.textContent="\u2192",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const r=document.createElement("select");r.className=`form-select ${n}`,r.style.cssText="flex:1 1 140px;min-width:120px;",o.forEach(i=>{const f=document.createElement("option");f.value=i.value,f.textContent=i.label,i.value===a&&(f.selected=!0),r.appendChild(f)});const u=document.createElement("button");return u.type="button",u.className="btn btn-xs btn-danger",u.textContent="\u2715",u.style.flexShrink="0",u.addEventListener("click",()=>l.remove()),l.appendChild(c),l.appendChild(s),l.appendChild(p),l.appendChild(d),l.appendChild(m),l.appendChild(r),l.appendChild(u),l}function Z(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild($("Visibility"));const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const l=document.createElement("span");l.textContent="Default:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const c=document.createElement("select");c.className="form-select fb-logic-vis-default",c.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(i=>{const f=document.createElement("option");f.value=i.value,f.textContent=i.label,i.value===(e.default||"visible")&&(f.selected=!0),c.appendChild(f)}),a.appendChild(l),a.appendChild(c),n.appendChild(a);const s=document.createElement("div");s.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const p=document.createElement("span");p.textContent="Transition:",p.style.cssText="font-size:.8rem;flex-shrink:0;";const d=document.createElement("select");d.className="form-select fb-logic-vis-transition",d.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(i=>{const f=document.createElement("option");f.value=i.value,f.textContent=i.label,i.value===(e.transition||"none")&&(f.selected=!0),d.appendChild(f)}),s.appendChild(p),s.appendChild(d),n.appendChild(s);const m=document.createElement("div");m.className="fb-logic-vis-rules";const r=o.map(i=>({value:i.name,label:i.label||i.name})),u=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(i=>{const f=(i.when?.all||i.when?.any||[])[0],h=i.then==="hidden"?"hidden":"visible";r.length>0&&m.appendChild(L(f,r,u,"fb-logic-vis-then",h))}),n.appendChild(m),r.length>0){const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="font-size:.73rem;margin-top:.2rem;",i.textContent="+ Add visibility rule",i.addEventListener("click",()=>m.appendChild(L(null,r,u,"fb-logic-vis-then","visible"))),n.appendChild(i)}return n}function ee(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild($("Conditional Requirement"));const a=document.createElement("label");a.style.cssText="display:flex;align-items:center;gap:.4rem;font-size:.8rem;cursor:pointer;margin-bottom:.4rem;";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 c=document.createElement("div");c.className="fb-logic-req-rules";const s=o.map(d=>({value:d.name,label:d.label||d.name})),p=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(d=>{const m=(d.when?.all||d.when?.any||[])[0],r=d.then===!0?"true":"false";s.length>0&&c.appendChild(L(m,s,p,"fb-logic-req-then",r))}),n.appendChild(c),s.length>0){const d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",d.style.cssText="font-size:.73rem;margin-top:.2rem;",d.textContent="+ Add requirement rule",d.addEventListener("click",()=>c.appendChild(L(null,s,p,"fb-logic-req-then","true"))),n.appendChild(d)}return n}function A(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;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(s=>{const p=document.createElement("option");p.value=s.value,p.textContent=s.label,s.value===(e?.type||"regex")&&(p.selected=!0),o.appendChild(p)});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 c=document.createElement("button");return c.type="button",c.className="btn btn-xs btn-danger",c.textContent="\u2715",c.style.flexShrink="0",c.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(a),t.appendChild(l),t.appendChild(c),t}function te(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild($("Custom Validation"));const a=document.createElement("div");a.className="fb-logic-val-rules",(e||[]).forEach(c=>a.appendChild(A(c))),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:.2rem;",l.textContent="+ Add validation rule",l.addEventListener("click",()=>a.appendChild(A(null))),n.appendChild(l),n}function ne(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild($("Cascade Options"));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 c=document.createElement("select");c.className="form-select fb-logic-cascade-source",c.style.cssText="flex:1;";const s=document.createElement("option");s.value="",s.textContent="\u2014 none \u2014",c.appendChild(s),o.forEach(u=>{const i=document.createElement("option");i.value=u.name,i.textContent=u.label||u.name,u.name===e.sourceField&&(i.selected=!0),c.appendChild(i)}),a.appendChild(l),a.appendChild(c),n.appendChild(a);const p=document.createElement("p");p.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',p.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const d=document.createElement("textarea");d.className="form-input fb-logic-cascade-mapping",d.rows=4,d.style.cssText="font-family:monospace;",d.placeholder='{"uk": [{"value": "london", "label": "London"}]}',d.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(p),n.appendChild(d);const m=document.createElement("p");m.textContent="Default options (one per line: value:Label)",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const r=document.createElement("textarea");return r.className="form-input fb-logic-cascade-defaults",r.rows=3,r.style.cssText="font-family:monospace;",r.placeholder=`option1:Option 1
|
|
4
|
+
option2:Option 2`,r.value=(e.defaultOptions||[]).map(u=>{const i=typeof u=="string"?u:u.value??"",f=typeof u=="string"?u:u.label??i;return i===f?i:`${i}:${f}`}).join(`
|
|
5
|
+
`),n.appendChild(m),n.appendChild(r),n}function le(e,t){const o=e.logic||{},n=b.filter((r,u)=>u!==t&&r.type!=="page-break"&&r.type!=="spacer"),a=document.createElement("div");a.className="fb-field-logic",a.style.cssText="margin-top:.75rem;border-top:1px solid var(--border-color,#333);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 c=document.createElement("span");c.style.cssText="font-size:.8rem;font-weight:600;color:var(--text-muted,#888);",c.textContent="\u26A1 Conditional Logic";const s=M(o),p=document.createElement("button");p.type="button",p.className="btn btn-xs btn-ghost",p.textContent=s?"\u25BE":"\u25B8";const d=document.createElement("div");d.className="fb-logic-body",d.style.cssText="padding:.25rem 0 .25rem;"+(s?"":"display:none;"),l.addEventListener("click",()=>{const r=d.style.display==="none";d.style.display=r?"":"none",p.textContent=r?"\u25BE":"\u25B8"}),l.appendChild(c),l.appendChild(p),a.appendChild(l),d.appendChild(Z(o.visibility||{},t,n)),d.appendChild(ee(o.requirement||{},t,n)),d.appendChild(te(o.validation||[],t,n));const m=document.getElementById(`fb-type-${t}`)?.value||e.type;return z.has(m)&&d.appendChild(ne(o.cascade||{},t,n)),a.appendChild(d),a}function O(e,t,o){const n=document.createElement("div");return n.className="fb-field-extras",z.has(e)&&n.appendChild(oe(t.options||[],o)),e==="textarea"&&n.appendChild(k([C("Rows",`fb-rows-${o}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(k([C("Min Length",`fb-minlength-${o}`,"number",t.minLength||"",""),C("Max Length",`fb-maxlength-${o}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(k([C("Min",`fb-min-${o}`,"number",t.min??"",""),C("Max",`fb-max-${o}`,"number",t.max??"","")])),n.children.length?n:null}function k(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.75rem;margin-bottom:.6rem;",e.forEach(o=>{o&&t.appendChild(o)}),t}function C(e,t,o,n,a){const l=document.createElement("div");l.style.flex="1";const c=document.createElement("label");c.htmlFor=t,c.className="form-label",c.textContent=e,c.style.fontSize=".8rem";const s=document.createElement("input");if(s.id=t,s.type=o||"text",s.className="form-input",s.value=n??"",l.appendChild(c),l.appendChild(s),a){const p=document.createElement("p");p.className="form-hint text-muted",p.textContent=a,p.style.cssText="font-size:.73rem;margin-top:.2rem;",l.appendChild(p)}return l}function ae(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 c=document.createElement("select");return c.id=t,c.className="form-select",o.forEach(s=>{const p=document.createElement("option");p.value=s.value,p.textContent=s.label,s.value===n&&(p.selected=!0),c.appendChild(p)}),a.appendChild(l),a.appendChild(c),a}function j(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 oe(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
|
|
6
6
|
no:No
|
|
7
|
-
maybe:Maybe`,a.value=(e||[]).map(l=>{const
|
|
8
|
-
`),a.style.fontFamily="monospace",o.appendChild(n),o.appendChild(a),o}function H(e){return
|
|
7
|
+
maybe:Maybe`,a.value=(e||[]).map(l=>{const c=typeof l=="string"?l:l.value??"",s=typeof l=="string"?l:l.label??c;return c===s?c:`${c}:${s}`}).join(`
|
|
8
|
+
`),a.style.fontFamily="monospace",o.appendChild(n),o.appendChild(a),o}function H(e){return v(),{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}:{},fields:b,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()||"stacked",columns:parseInt(e.find("#setting-columns").val(),10)||2,submitSpan:e.find("#setting-submit-span").val()||"",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()},...q!==null&&{collection:q}}}}function ie(e){const t=[];let o=[],n="Step 1",a="";return e.forEach(l=>{l.type==="page-break"?(t.push({title:n,description:a,fields:o}),o=[],n=l.label||`Step ${t.length+1}`,a=l.description||""):l.type!=="spacer"&&o.push(l)}),(o.length||t.length===0)&&t.push({title:n,description:a,fields:o}),t}function J(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==="checkbox"?"boolean":n.type==="date"?"string":n.type;o[n.name]={type:l,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}}}),o}function U(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")})}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){b=[],w=null,q=null;const t=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);w=t?t[1]:null;let o=null;if(w)try{o=await T(`/forms/${w}`),b=o.fields||[],q=o.actions?.collection??null}catch{E.toast("Could not load form.",{type:"error"})}if(o?e.find("#editor-title").get(0).textContent=`Edit: ${o.title}`:e.find("#editor-title").get(0).textContent="New Form",w||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(I(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),o){e.find("#field-title").val(o.title),e.find("#field-slug").val(o.slug),e.find("#field-description").val(o.description||""),e.find("#field-bundled").prop("checked",!!o.bundled);const l=o.settings||{};e.find("#setting-submit-text").val(l.submitText||"Submit"),e.find("#setting-success-message").val(l.successMessage||""),e.find("#setting-layout").val(l.layout||"stacked"),e.find("#setting-columns").val(l.columns||2),e.find("#setting-submit-span").val(l.submitSpan||""),e.find("#columns-group").get(0).style.display=l.layout==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",l.honeypot!==!1),e.find("#setting-rate-limit").val(l.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(l.successRedirect||"");const c=o.actions?.email||{};e.find("#action-email-enabled").prop("checked",c.enabled||!1),e.find("#action-email-recipients").val(c.recipients||""),e.find("#action-email-subject-prefix").val(c.subjectPrefix||"");const s=o.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",s.enabled||!1),e.find("#action-webhook-url").val(s.url||""),e.find("#action-webhook-method").val(s.method||"POST")}const n=o?.settings?.actionSlug||"";try{const l=await T("/actions").catch(()=>[]),c=e.find("#action-cms-slug").get(0);if((Array.isArray(l)?l:[]).forEach(s=>{const p=document.createElement("option");p.value=s.slug,p.textContent=s.title||s.slug,s.slug===n&&(p.selected=!0),c.appendChild(p)}),!l.length){const s=document.createElement("option");s.value="",s.textContent="No actions available",s.disabled=!0,c.appendChild(s)}}catch{}e.find("#setting-layout").get(0)?.addEventListener("change",function(){const l=this.value==="grid";e.find("#columns-group").get(0).style.display=l?"":"none",document.querySelectorAll(".fb-grid-row").forEach(c=>{c.style.display=l?"flex":"none"})}),x(e);const a=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",l=>{l.stopPropagation(),a.style.display=a.style.display==="none"?"":"none"}),N&&document.removeEventListener("click",N),N=()=>{a&&(a.style.display="none")},document.addEventListener("click",N),e.find("#add-field-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),v();const l=b.length;b.push({name:`field_${l+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),x(e);const c=e.find("#fields-list").get(0)?.lastElementChild;if(c){const s=c.querySelector(".fb-field-body");s&&(s.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),v(),b.push({type:"spacer"}),x(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),v();const l=b.filter(c=>c.type==="page-break").length+2;b.push({type:"page-break",label:`Step ${l}`,description:""}),x(e)}),e.find("#save-form-btn").get(0).addEventListener("click",async()=>{const l=H(e);if(!l.title){E.toast("Please enter a form title.",{type:"error"});return}try{w?(await T(`/forms/${w}`,{method:"PUT",body:JSON.stringify(l)}),E.toast("Form saved.",{type:"success"})):(w=(await T("/forms",{method:"POST",body:JSON.stringify(l)})).slug,R.navigate(`/forms/edit/${w}`),E.toast("Form created.",{type:"success"}))}catch(c){E.toast(c.message||"Failed to save form.",{type:"error"})}}),e.find("#preview-btn").get(0).addEventListener("click",()=>{const l=H(e),c=e.find("#preview-container").get(0);if(!c)return;const s=e.find("#preview-test-result").get(0),p=e.find("#preview-test-badge").get(0);s&&(s.style.display="none",s.textContent=""),p&&(p.style.display=w?"":"none"),e.find("#preview-card").get(0).style.display="",c.textContent="";const d=document.createElement("div");d.id="fb-preview-form",c.appendChild(d);const m=w?async u=>{s&&(s.style.display="none",s.textContent="");try{const i=await fetch(`/api/forms/submit/${w}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),f=await i.json();if(!i.ok)throw new Error(f.error||"Submission failed.");s&&(s.textContent=f.message||l.settings?.successMessage||"Submitted successfully.",s.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:rgba(34,197,94,.12);color:var(--success,#22c55e);"),E.toast("Test submission stored.",{type:"success"})}catch(i){s&&(s.textContent=i.message,s.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:rgba(239,68,68,.12);color:var(--danger,#ef4444);"),E.toast(i.message,{type:"error"})}return!1}:()=>!1,r=l.fields.some(u=>u.type==="page-break");if(typeof F<"u"){const u=l.settings?.columns||2,i=l.settings?.layout||"stacked";if(r&&F.wizard){const f=ie(l.fields).map(h=>({title:h.title,description:h.description,fields:J(h.fields,u)}));F.wizard("#fb-preview-form",{schema:{steps:f},onSubmit:m}),U("#fb-preview-form",l.fields)}else if(F.render){const f=J(l.fields,u),h={};if(l.fields.forEach(g=>{if(!(!g.name||g.type==="page-break"||g.type==="spacer")&&(g.type==="select"||g.type==="multiselect")&&g.required){const y=(g.options||[])[0];y&&(h[g.name]=typeof y=="object"?y.value:y)}}),F.render("#fb-preview-form",f,h,{submitText:l.settings?.submitText||"Submit",layout:i,columns:u,onSubmit:m}),i==="grid"&&l.settings?.submitSpan==="full"){const g=document.querySelector("#fb-preview-form .form-buttons");g&&g.classList.add("col-span-full")}U("#fb-preview-form",l.fields)}window.FormLogicEngine&&l.fields.some(f=>f.logic)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:l.fields},d).init()})}else{const u=document.createElement("p");u.textContent=`${l.fields.filter(i=>i.type!=="page-break").length} field(s): ${l.fields.filter(i=>i.type!=="page-break").map(i=>i.label).join(", ")}`,u.style.cssText="color:var(--muted);font-style:italic;",d.appendChild(u)}e.find("#preview-card").get(0).scrollIntoView({behavior:"smooth",block:"start"})})}};
|
package/admin/js/views/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dashboardView as o}from"./dashboard.js";import{pagesView as i}from"./pages.js";import{pageEditorView as r}from"./page-editor.js?v=20260422-2";import{settingsView as t}from"./settings.js";import{navigationView as e}from"./navigation.js";import{notificationsView as m}from"./notifications.js";import{layoutsView as s}from"./layouts.js";import{mediaView as f}from"./media.js";import{loginView as p}from"./login.js";import{usersView as w}from"./users.js";import{userEditorView as n}from"./user-editor.js";import{pluginsView as c}from"./plugins.js";import{documentationView as V}from"./documentation.js";import{tutorialsView as l}from"./tutorials.js";import{apiReferenceView as a}from"./api-reference.js";import{collectionsView as d}from"./collections.js";import{collectionEditorView as E}from"./collection-editor.js";import{collectionEntriesView as u}from"./collection-entries.js";import{formsView as g}from"./forms.js";import{formEditorView as v}from"./form-editor.js";import{formSubmissionsView as b}from"./form-submissions.js";import{viewsListView as k}from"./views-list.js";import{viewEditorView as y}from"./view-editor.js";import{viewPreviewView as L}from"./view-preview.js";import{actionsListView as P}from"./actions-list.js";import{actionEditorView as h}from"./action-editor.js";import{proDocsView as D}from"./pro-docs.js";import{blocksView as R}from"./blocks.js?v=3";import{blockEditorView as S}from"./block-editor.js?v=7";import"./block-editor-enhance.js?v=2";import{componentsView as x}from"./components.js?v=3";import{componentEditorView as j}from"./component-editor.js?v=7";import{myProfileView as q}from"./my-profile.js";import{rolesView as z}from"./roles.js";import{roleEditorView as A}from"./role-editor.js";import{effectsView as B}from"./effects.js";export const views={dashboard:o,pages:i,pageEditor:r,settings:t,navigation:e,layouts:s,media:f,login:p,users:w,userEditor:n,plugins:c,documentation:V,tutorials:l,apiReference:a,collections:d,collectionEditor:E,collectionEntries:u,forms:g,formEditor:v,formSubmissions:b,viewsList:k,viewEditor:y,viewPreview:L,actionsList:P,actionEditor:h,proDocs:D,blocks:R,blockEditor:S,components:x,componentEditor:j,myProfile:q,roles:z,roleEditor:A,effects:B,notifications:m};
|
|
1
|
+
import{dashboardView as o}from"./dashboard.js";import{pagesView as i}from"./pages.js";import{pageEditorView as r}from"./page-editor.js?v=20260422-2";import{settingsView as t}from"./settings.js";import{navigationView as e}from"./navigation.js";import{notificationsView as m}from"./notifications.js";import{layoutsView as s}from"./layouts.js";import{mediaView as f}from"./media.js";import{loginView as p}from"./login.js";import{usersView as w}from"./users.js";import{userEditorView as n}from"./user-editor.js";import{pluginsView as c}from"./plugins.js";import{documentationView as V}from"./documentation.js";import{tutorialsView as l}from"./tutorials.js";import{apiReferenceView as a}from"./api-reference.js";import{collectionsView as d}from"./collections.js";import{collectionEditorView as E}from"./collection-editor.js";import{collectionEntriesView as u}from"./collection-entries.js";import{formsView as g}from"./forms.js";import{formEditorView as v}from"./form-editor.js?v=20260422-4";import{formSubmissionsView as b}from"./form-submissions.js";import{viewsListView as k}from"./views-list.js";import{viewEditorView as y}from"./view-editor.js";import{viewPreviewView as L}from"./view-preview.js";import{actionsListView as P}from"./actions-list.js";import{actionEditorView as h}from"./action-editor.js";import{proDocsView as D}from"./pro-docs.js";import{blocksView as R}from"./blocks.js?v=3";import{blockEditorView as S}from"./block-editor.js?v=7";import"./block-editor-enhance.js?v=2";import{componentsView as x}from"./components.js?v=3";import{componentEditorView as j}from"./component-editor.js?v=7";import{myProfileView as q}from"./my-profile.js";import{rolesView as z}from"./roles.js";import{roleEditorView as A}from"./role-editor.js";import{effectsView as B}from"./effects.js";export const views={dashboard:o,pages:i,pageEditor:r,settings:t,navigation:e,layouts:s,media:f,login:p,users:w,userEditor:n,plugins:c,documentation:V,tutorials:l,apiReference:a,collections:d,collectionEditor:E,collectionEntries:u,forms:g,formEditor:v,formSubmissions:b,viewsList:k,viewEditor:y,viewPreview:L,actionsList:P,actionEditor:h,proDocs:D,blocks:R,blockEditor:S,components:x,componentEditor:j,myProfile:q,roles:z,roleEditor:A,effects:B,notifications:m};
|
package/package.json
CHANGED
package/public/js/forms.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const targets=document.querySelectorAll("[data-form]");targets.length&&targets.forEach(initFormTarget);function showMessage(i,r,t){const e=i.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const a=document.createElement("div");a.className=t==="success"?"fb-form-success":"fb-form-error",a.textContent=r,i.appendChild(a)}function attachRuntimeLifecycle(i,r){if(i._formLogicRuntime=r,!i.parentNode||typeof MutationObserver>"u")return;const t=new MutationObserver(function(e){for(const a of e)for(const n of a.removedNodes)if(n===i||n.nodeType===1&&n.contains&&n.contains(i)){r.destroy(),t.disconnect();return}});t.observe(i.parentNode,{childList:!0,subtree:!1})}function buildBlueprintFromFields(i,r){const t={};return i.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="checkbox"?"boolean":e.type==="date"?"string":e.type,n={...e.formConfig||{}};n.span==="full"&&r&&(n.span=r),t[e.name]={type:a,label:e.label||e.name,required:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{
|
|
1
|
+
const targets=document.querySelectorAll("[data-form]");targets.length&&targets.forEach(initFormTarget);function showMessage(i,r,t){const e=i.querySelector(".fb-form-success, .fb-form-error");e&&e.remove();const a=document.createElement("div");a.className=t==="success"?"fb-form-success":"fb-form-error",a.textContent=r,i.appendChild(a)}function attachRuntimeLifecycle(i,r){if(i._formLogicRuntime=r,!i.parentNode||typeof MutationObserver>"u")return;const t=new MutationObserver(function(e){for(const a of e)for(const n of a.removedNodes)if(n===i||n.nodeType===1&&n.contains&&n.contains(i)){r.destroy(),t.disconnect();return}});t.observe(i.parentNode,{childList:!0,subtree:!1})}function buildBlueprintFromFields(i,r){const t={};return i.forEach(function(e){if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const a=e.type==="checkbox"?"boolean":e.type==="date"?"string":e.type,n={...e.formConfig||{}};n.span==="full"&&r&&(n.span=r),t[e.name]={type:a,label:e.label||e.name,required:e.required||!1,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{helperText:e.helper},...e.tooltip&&{tooltip:e.tooltip},...n}},e.minLength!==void 0&&(t[e.name].minLength=e.minLength),e.maxLength!==void 0&&(t[e.name].maxLength=e.maxLength),e.min!==void 0&&(t[e.name].min=e.min),e.max!==void 0&&(t[e.name].max=e.max)}),t}function buildInitialData(i){const r={};return i.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&&(r[t.name]=typeof e=="object"?e.value:e)}}),r}function patchDateInputs(i,r){(r||[]).forEach(function(t){if(t.type!=="date"||!t.name)return;const e=i.querySelector('[name="'+t.name+'"]');e&&e.type!=="date"&&(e.type="date")})}function buildWizardSteps(i,r){const t=[];let e=[],a=r||"Step 1",n="";return i.forEach(function(u){u.type==="page-break"?(t.push({title:a,description:n,fieldGroup:e}),e=[],a=u.label||"Step "+(t.length+1),n=u.description||""):u.type!=="spacer"&&e.push(u)}),t.push({title:a,description:n,fieldGroup:e}),t}function injectHoneypot(i){const r=document.createElement("div");r.className="fb-form-honeypot",r.setAttribute("aria-hidden","true");const t=document.createElement("input");t.name="website",t.type="text",t.tabIndex=-1,t.autocomplete="url",t.placeholder="https://",r.appendChild(t);const e=document.createElement("input");e.name="_t",e.type="hidden",e.value=Date.now(),r.appendChild(e),i.appendChild(r)}function injectSpacers(i,r){const t=i.querySelector("form");if(!t)return;const e=Array.from(t.querySelectorAll(".form-group"));let a=0;r.forEach(function(n){if(n.type==="spacer"){const u=document.createElement("div");u.className="fb-spacer";const s=e[a];if(s)t.insertBefore(u,s);else{const l=t.querySelector('[type="submit"]');l?t.insertBefore(u,l):t.appendChild(u)}}else n.type!=="page-break"&&a++})}function submitForm(i,r,t,e,a){const n=a||e,u=n.querySelector('[name="website"]')?.value||"",s=n.querySelector('[name="_t"]')?.value||"",l=Object.assign({},r,{_hp:u,_t:s});return fetch("/api/forms/submit/"+i,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)}).then(m=>m.json().then(c=>({ok:m.ok,body:c}))).then(m=>{m.ok&&m.body.ok?(e.textContent="",showMessage(e,m.body.message||t.successMessage||"Thank you.","success")):showMessage(e,m.body.error||"Something went wrong.","error")}).catch(()=>{showMessage(e,"Unable to submit. Please check your connection.","error")})}function renderManualForm(i,r,t,e,a){const n=document.createElement("form");n.noValidate=!0,r.forEach(function(s){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=s.label||s.name,s.required){const o=document.createElement("span");o.textContent=" *",o.style.color="#f87171",m.appendChild(o)}let c;s.type==="textarea"?(c=document.createElement("textarea"),c.rows=s.formConfig?.rows||4,c.className="form-input"):s.type==="select"?(c=document.createElement("select"),c.className="form-input",(s.options||[]).forEach(function(o){const p=document.createElement("option");p.value=typeof o=="string"?o:o.value??"",p.textContent=typeof o=="string"?o:o.label||p.value,c.appendChild(p)})):(c=document.createElement("input"),c.type=s.type||"text",c.className="form-input",s.placeholder&&(c.placeholder=s.placeholder)),c.name=s.name,c.required=s.required||!1,l.appendChild(m),l.appendChild(c),n.appendChild(l)}),t.honeypot&&injectHoneypot(n);const u=document.createElement("button");u.type="submit",u.className="btn btn-primary",u.textContent=t.submitText||"Submit",n.appendChild(u),n.addEventListener("submit",function(s){s.preventDefault();const l={};if(r.forEach(function(m){const c=n.querySelector('[name="'+m.name+'"]');c&&(l[m.name]=c.value)}),window.FormLogicEngine&&a){const m=window.FormLogicEngine,c=[],o=[];if(r.forEach(function(p){if(m.evaluateFieldVisibility(p,l)==="hidden"){delete l[p.name];return}const h=m.evaluateFieldRequirement(p,l),f=l[p.name];h&&(!f||!String(f).trim())&&c.push(p.label||p.name);const d=m.validateField(p,f||"",l);d.length&&o.push(d[0].message)}),c.length||o.length){const p=[];c.length&&p.push("Required: "+c.join(", ")),o.length&&p.push(o.join("; ")),showMessage(i,p.join(". "),"error");return}}i.classList.add("fb-form-loading"),u.disabled=!0,submitForm(e,l,t,i,n).finally(function(){i.classList.remove("fb-form-loading"),u.disabled=!1})}),i.appendChild(n),window.FormLogicEngine&&a&&r.some(s=>s.logic)&&new window.FormLogicEngine.FormLogicRuntime(a,i).init()}function initFormTarget(i){const r=i.getAttribute("data-form");r&&fetch("/api/forms/"+r+"/public").then(t=>{if(!t.ok)throw new Error("Form not found: "+r);return t.json()}).then(t=>{const e=t.fields||[],a=t.settings||{},n=document.createElement("div");n.className="fb-form-wrapper",i.appendChild(n);const u=e.some(s=>s.type==="page-break");if(typeof Domma<"u"&&Domma.forms){const s=a.columns||1;if(u&&Domma.forms.wizard){const m=buildWizardSteps(e,t.title).map(function(o){return{title:o.title,description:o.description,fields:buildBlueprintFromFields(o.fieldGroup,s)}}),c=Domma.forms.wizard(n,{schema:{steps:m},onSubmit:function(o){return submitForm(r,o,a,n,null)}});Promise.resolve(c).then(function(){if(patchDateInputs(n,e),window.FormLogicEngine&&e.some(o=>o.logic)){const o=new window.FormLogicEngine.FormLogicRuntime(t,n);o.init(),attachRuntimeLifecycle(n,o)}if(a.honeypot){const o=n.querySelector("form");o&&injectHoneypot(o)}})}else if(Domma.forms.render){const l=buildBlueprintFromFields(e,s),m=buildInitialData(e),c=Domma.forms.render(n,l,m,{submitText:a.submitText||"Submit",layout:a.layout||"stacked",columns:s,onSubmit:function(o){return submitForm(r,o,a,n,null)}});Promise.resolve(c).then(function(){if(patchDateInputs(n,e),window.FormLogicEngine&&e.some(o=>o.logic)){const o=new window.FormLogicEngine.FormLogicRuntime(t,n);o.init(),attachRuntimeLifecycle(n,o)}if(e.some(o=>o.type==="spacer")&&injectSpacers(n,e),a.honeypot){const o=n.querySelector("form");o&&injectHoneypot(o)}})}}else renderManualForm(n,e.filter(s=>s.type!=="page-break"&&s.type!=="spacer"),a,r,t)}).catch(t=>{const e=document.createElement("p");e.textContent="Form unavailable.",e.style.cssText="color:#f87171;font-style:italic;",i.appendChild(e),console.warn("[forms]",t.message)})}
|
package/public/js/site.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
$(()=>{const b=window.__CMS_NAV__||{},d=window.__CMS_SITE__||{};if(d.autoTheme?.enabled){let e=function(s){const f=(s||"07:00").split(":");return+f[0]*60+(+f[1]||0)},o=function(){const s=new Date,f=s.getHours()*60+s.getMinutes();return f>=e(t.dayStart)&&f<e(t.nightStart)?t.dayTheme:t.nightTheme};var r=e,u=o;const t=d.autoTheme;Domma.theme.set(o()),setInterval(()=>Domma.theme.set(o()),6e4)}if($("#site-navbar").length&&b.brand){const t={...b.brand},e=t.size&&t.size!=="md"?` navbar-brand-${t.size}`:"";if(t.logo||t.icon||t.tagline){let o="";t.logo?o+=`<img src="${t.logo}" class="navbar-brand-logo" alt="${t.text||""}">`:t.icon&&(o+=`<span data-icon="${t.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),t.text&&(o+=`<span class="navbar-brand-text${e}">${t.text}</span>`),t.tagline&&(o+=`<small class="navbar-brand-tagline">${t.tagline}</small>`),t.html=o}else e&&t.text&&(t.html=`<span class="navbar-brand-text${e}">${t.text}</span>`);Domma.elements.navbar("#site-navbar",{brand:t,items:b.items||[],variant:b.variant||"dark",position:b.position||"sticky",collapsible:!0}),Domma.icons.scan("#site-navbar")}const y=$("#site-footer");if(y.length){const t=d.social||{},e={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let o='<div class="footer-inner container">';if(d.footer){const m=d.footer;o+=`<p>${m.copyright||""}</p>`,m.links?.length&&(o+='<nav class="footer-links">',m.links.forEach(n=>{o+=`<a href="${n.url}">${n.text}</a>`}),o+="</nav>");const i=Object.keys(e).filter(n=>t[n]);i.length&&(o+='<div class="footer-social">',i.forEach(n=>{const{label:a,svg:c}=e[n];o+=`<a href="${t[n]}" target="_blank" rel="noopener noreferrer" aria-label="${a}" class="footer-social-link">${c}</a>`}),o+="</div>")}o+="</div>",y.html(o);const s=S.get("reduced_motion"),f=s!==null?!!s:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),h=y.get(0).querySelector(".footer-inner");if(h){const m=document.createElement("input");m.type="checkbox",m.className="form-switch-input",m.id="dm-motion-switch",m.checked=f,m.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const i=document.createElement("span");i.className="form-switch-label",i.textContent="Reduce motion";const n=document.createElement("label");n.className="form-switch footer-motion-switch",n.title="Reduce motion",n.appendChild(m),n.appendChild(i),h.appendChild(n)}}$("#site-sidebar").length&&Domma.elements.sidebar("#site-sidebar",{autoGenerate:!0,selector:"h2, h3",collapsible:!1,push:!0,contentSelector:".site-content"}),Domma.icons.scan();const p=$(".page-body");if(p.length){p.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),p.find(".tabs").each(function(){Domma.elements.tabs(this)}),p.find(".carousel").each(function(){Domma.elements.carousel(this,{autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"})}),p.find(".dm-countdown").each(function(){const t={autoStart:!0};this.dataset.to&&(t.targetDate=new Date(this.dataset.to)),this.dataset.duration&&(t.duration=parseInt(this.dataset.duration,10)),this.dataset.format&&(t.format=this.dataset.format),Domma.elements.timer(this,t)}),p.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),p.find(".dm-progression").each(function(){Domma.elements.progression(this,{layout:this.dataset.layout||"vertical",theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0})});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(t=>{const e=t.dataset.revealMode||"stagger",o=t.dataset.revealAnimation||"slide-up",s=parseInt(t.dataset.revealDuration,10)||400,f=parseInt(t.dataset.revealStagger,10)||60,h=parseInt(t.dataset.revealDelay,10)||0,m=t.dataset.revealDirection==="rtl",i=Array.from(t.children),n={"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)"};i.forEach((a,c)=>{a.style.opacity="0",a.style.transform=n[o]||"",a.style.transition=`opacity ${s}ms ease, transform ${s}ms ease`;const l=m?i.length-1-c:c;a.style.transitionDelay=e==="stagger"?`${h+l*f}ms`:`${h}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const a=new IntersectionObserver(c=>{c.forEach(l=>{l.isIntersecting&&(l.target.offsetWidth,l.target.style.opacity="1",l.target.style.transform="none",a.unobserve(l.target))})},{threshold:.1});i.forEach(c=>a.observe(c))}))}),p.find(".card[data-collapsible]").each(function(){const t=this.querySelector(".card-header");t&&t.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),p.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const t=this.dataset.soTarget,e=document.getElementById(t);if(!e)return;const o=E.slideover({title:e.dataset.soTitle||"",size:e.dataset.soSize||"md",position:e.dataset.soPosition||"right"});e.style.display="",o.setContent(e),o.open()})})}if(typeof $.setup=="function"){const t=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(e=>{try{const o=atob(e.dataset.config),s=JSON.parse(o);Object.assign(t,s)}catch{}}),Object.keys(t).length>0){const e={};for(const[o,s]of Object.entries(t)){const f=s?.events?.click,{confirm:h,toast:m,alert:i,prompt:n,...a}=f||{};h||m||i||n?($(o).on("click",async function(l){if(l.preventDefault(),h&&!await E.confirm(h))return;let w=null;if(!(n&&(w=await E.prompt(n,{inputPlaceholder:a.promptPlaceholder||"",inputValue:a.promptDefault||""}),w===null))){if(a.target){const C=$(a.target);a.toggleClass&&C.toggleClass(a.toggleClass),a.addClass&&C.addClass(a.addClass),a.removeClass&&C.removeClass(a.removeClass),w!==null&&(a.setText&&C.text(w),a.setVal&&C.val(w),a.setAttr&&C.attr(a.setAttr,w))}a.href&&(window.location.href=a.href),m&&E.toast(m,{type:a.toastType||"success"}),i&&E.alert(i)}}),Object.keys(a).length&&(e[o]={...s,events:{...s.events,click:a}})):e[o]=s}$.setup(e)}}p.length&&wireCTAButtons(p.get(0))});function wireCTAButtons(b){b.querySelectorAll(".dm-cta-trigger").forEach(d=>{d.addEventListener("click",async()=>{const v=d.dataset.action,y=d.dataset.entry,g=d.dataset.confirm;let p=S.get("auth_token");if(!p){E.toast("Please log in to perform this action.",{type:"warning"});return}if(g&&!await E.confirm(g))return;const r=Array.from(d.childNodes).map(t=>t.cloneNode(!0));d.disabled=!0,d.textContent="Running\u2026";const u=t=>fetch(`/api/actions/${v}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t}`},body:JSON.stringify({entryId:y})});try{let t=await u(p);if(t.status===401){const o=S.get("auth_refresh_token");if(o){const s=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:o})});if(s.ok){const{token:f}=await s.json();S.set("auth_token",f),p=f,t=await u(p)}}}const e=await t.json().catch(()=>({}));if(!t.ok)throw new Error(e.error||e.message||`Error ${t.status}`);E.toast(e.message||"Action completed.",{type:"success"})}catch(t){E.toast(t.message||"Action failed.",{type:"error"})}finally{d.disabled=!1,d.textContent="",r.forEach(t=>d.appendChild(t)),Domma.icons.scan(d)}})})}(function(){const d=document.querySelectorAll("[data-collection-table]");!d.length||typeof T>"u"||!T.create||d.forEach(v=>{let y;try{y=JSON.parse(atob(v.dataset.payload))}catch{return}const{columns:g,rows:p,search:r,sortable:u,exportable:t,pageSize:e,empty:o,ctaConfig:s}=y;if(!g?.length)return;if(s){const m=g.findIndex(i=>i.key==="_cta");m!==-1&&(g[m]={key:"_cta",title:"",render:(i,n)=>{const a=document.createElement("button");if(a.className=`btn btn-${s.style||"primary"} dm-cta-trigger`,a.dataset.action=s.action||"",a.dataset.entry=n._entryId||"",s.confirm&&(a.dataset.confirm=s.confirm),s.icon){const c=document.createElement("span");c.dataset.icon=s.icon,a.appendChild(c),a.appendChild(document.createTextNode(" "))}return a.appendChild(document.createTextNode(s.label||"Run")),a}})}const f="col-table-"+Math.random().toString(36).slice(2,7),h=document.createElement("div");h.id=f,v.replaceChildren(h),T.create("#"+f,{data:p,columns:g,search:r,sortable:u,exportable:t,pageSize:e,emptyMessage:o}),s&&wireCTAButtons(h)})})(),(function(){const d=document.querySelectorAll("[data-form-inline]");if(!d.length||typeof F>"u")return;function v(r,u){const t={};return(r||[]).forEach(e=>{if(e.type==="page-break"||e.type==="spacer"||!e.name)return;const o=e.type==="checkbox"?"boolean":e.type==="date"?"string":e.type,s={...e.formConfig||{}};s.span==="full"&&u&&(s.span=u),t[e.name]={type:o,label:e.label,required:e.required,options:e.options,formConfig:{...e.placeholder&&{placeholder:e.placeholder},...e.helper&&{hint:e.helper},...s}}}),t}function y(r){const u={};return(r||[]).forEach(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&&(u[t.name]=typeof e=="object"?e.value:e)}}),u}function g(r,u){(u||[]).forEach(t=>{if(t.type!=="date"||!t.name)return;const e=r.querySelector(`[name="${t.name}"]`);e&&e.type!=="date"&&(e.type="date")})}function p(r,u,t){let e=r.querySelector(".cms-form-message");e||(e=document.createElement("p"),e.className="cms-form-message",r.appendChild(e)),e.textContent=u,e.style.cssText=t?"color:var(--danger,#f87171);margin-top:.75rem;":"color:var(--success,#4ade80);margin-top:.75rem;"}d.forEach(r=>{let u;try{u=JSON.parse(atob(r.dataset.formInline))}catch{return}const t=u.fields||[],e=u.settings||{},o=e.columns||1,s=e.layout||"stacked",f=t.some(i=>i.type==="page-break"),h=async i=>{try{const n=r.querySelector('[name="website"]'),a=r.querySelector('[name="_t"]'),c=Object.assign({},i);n!==null&&(c._hp=n.value),a!==null&&(c._t=a.value);const l=await H.post(`/api/forms/submit/${u.slug}`,c);if(l?.redirect){window.location.href=l.redirect;return}for(;r.firstChild;)r.removeChild(r.firstChild);p(r,l?.message||e.successMessage||"Thank you for your submission.",!1)}catch(n){throw p(r,n.message||"Submission failed. Please try again.",!0),n}};function m(i){const n=i.querySelector("form");if(!n)return;const a=document.createElement("div");a.className="fb-form-honeypot",a.setAttribute("aria-hidden","true");const c=document.createElement("input");c.name="website",c.type="text",c.tabIndex=-1,c.autocomplete="url",c.placeholder="https://",a.appendChild(c);const l=document.createElement("input");l.name="_t",l.type="hidden",l.value=Date.now(),a.appendChild(l),n.appendChild(a)}if(f&&F.wizard){const i=[];let n=[],a=u.title||"Step 1",c="";t.forEach(l=>{l.type==="page-break"?(i.push({title:a,description:c,fields:v(n,o)}),n=[],a=l.label||`Step ${i.length+1}`,c=l.description||""):l.type!=="spacer"&&n.push(l)}),i.push({title:a,description:c,fields:v(n,o)}),F.wizard(r,{schema:{steps:i},onSubmit:h}),g(r,t),e.honeypot!==!1&&m(r)}else if(F.render){if(F.render(r,v(t,o),y(t),{submitText:e.submitText||"Submit",layout:s,columns:o,onSubmit:h}),s==="grid"&&e.submitSpan==="full"){const i=r.querySelector(".form-buttons");i&&i.classList.add("col-span-full")}g(r,t),e.honeypot!==!1&&m(r)}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
|
1
|
+
$(()=>{const w=window.__CMS_NAV__||{},l=window.__CMS_SITE__||{};if(l.autoTheme?.enabled){let t=function(s){const h=(s||"07:00").split(":");return+h[0]*60+(+h[1]||0)},o=function(){const s=new Date,h=s.getHours()*60+s.getMinutes();return h>=t(e.dayStart)&&h<t(e.nightStart)?e.dayTheme:e.nightTheme};var i=t,d=o;const e=l.autoTheme;Domma.theme.set(o()),setInterval(()=>Domma.theme.set(o()),6e4)}if($("#site-navbar").length&&w.brand){const e={...w.brand},t=e.size&&e.size!=="md"?` navbar-brand-${e.size}`:"";if(e.logo||e.icon||e.tagline){let o="";e.logo?o+=`<img src="${e.logo}" class="navbar-brand-logo" alt="${e.text||""}">`:e.icon&&(o+=`<span data-icon="${e.icon}" style="width:1.1em;height:1.1em;margin-right:.35em;vertical-align:middle;"></span>`),e.text&&(o+=`<span class="navbar-brand-text${t}">${e.text}</span>`),e.tagline&&(o+=`<small class="navbar-brand-tagline">${e.tagline}</small>`),e.html=o}else t&&e.text&&(e.html=`<span class="navbar-brand-text${t}">${e.text}</span>`);Domma.elements.navbar("#site-navbar",{brand:e,items:w.items||[],variant:w.variant||"dark",position:w.position||"sticky",collapsible:!0}),Domma.icons.scan("#site-navbar")}const v=$("#site-footer");if(v.length){const e=l.social||{},t={twitter:{label:"X / Twitter",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.742l7.73-8.835L1.254 2.25H8.08l4.259 5.629L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>'},facebook:{label:"Facebook",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/></svg>'},instagram:{label:"Instagram",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zM12 0C8.741 0 8.333.014 7.053.072 2.695.272.273 2.69.073 7.052.014 8.333 0 8.741 0 12c0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98C8.333 23.986 8.741 24 12 24c3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98C15.668.014 15.259 0 12 0zm0 5.838a6.162 6.162 0 100 12.324 6.162 6.162 0 000-12.324zM12 16a4 4 0 110-8 4 4 0 010 8zm6.406-11.845a1.44 1.44 0 100 2.881 1.44 1.44 0 000-2.881z"/></svg>'},linkedin:{label:"LinkedIn",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>'},github:{label:"GitHub",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>'},youtube:{label:"YouTube",svg:'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M23.495 6.205a3.007 3.007 0 00-2.088-2.088c-1.87-.501-9.396-.501-9.396-.501s-7.507-.01-9.396.501A3.007 3.007 0 00.527 6.205a31.247 31.247 0 00-.522 5.805 31.247 31.247 0 00.522 5.783 3.007 3.007 0 002.088 2.088c1.868.502 9.396.502 9.396.502s7.506 0 9.396-.502a3.007 3.007 0 002.088-2.088 31.247 31.247 0 00.5-5.783 31.247 31.247 0 00-.5-5.805zM9.609 15.601V8.408l6.264 3.602z"/></svg>'}};let o='<div class="footer-inner container">';if(l.footer){const m=l.footer;o+=`<p>${m.copyright||""}</p>`,m.links?.length&&(o+='<nav class="footer-links">',m.links.forEach(n=>{o+=`<a href="${n.url}">${n.text}</a>`}),o+="</nav>");const f=Object.keys(t).filter(n=>e[n]);f.length&&(o+='<div class="footer-social">',f.forEach(n=>{const{label:a,svg:r}=t[n];o+=`<a href="${e[n]}" target="_blank" rel="noopener noreferrer" aria-label="${a}" class="footer-social-link">${r}</a>`}),o+="</div>")}o+="</div>",v.html(o);const s=S.get("reduced_motion"),h=s!==null?!!s:!!(window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches),g=v.get(0).querySelector(".footer-inner");if(g){const m=document.createElement("input");m.type="checkbox",m.className="form-switch-input",m.id="dm-motion-switch",m.checked=h,m.addEventListener("change",function(){S.set("reduced_motion",this.checked),window.location.reload()});const f=document.createElement("span");f.className="form-switch-label",f.textContent="Reduce motion";const n=document.createElement("label");n.className="form-switch footer-motion-switch",n.title="Reduce motion",n.appendChild(m),n.appendChild(f),g.appendChild(n)}}$("#site-sidebar").length&&Domma.elements.sidebar("#site-sidebar",{autoGenerate:!0,selector:"h2, h3",collapsible:!1,push:!0,contentSelector:".site-content"}),Domma.icons.scan();const p=$(".page-body");if(p.length){p.find(".accordion").each(function(){Domma.elements.accordion(this,{allowMultiple:this.dataset.multi==="true"})}),p.find(".tabs").each(function(){Domma.elements.tabs(this)}),p.find(".carousel").each(function(){Domma.elements.carousel(this,{autoplay:this.dataset.autoplay==="true",interval:parseInt(this.dataset.interval,10)||5e3,loop:this.dataset.loop!=="false",animation:this.dataset.animation||"slide"})}),p.find(".dm-countdown").each(function(){const e={autoStart:!0};this.dataset.to&&(e.targetDate=new Date(this.dataset.to)),this.dataset.duration&&(e.duration=parseInt(this.dataset.duration,10)),this.dataset.format&&(e.format=this.dataset.format),Domma.elements.timer(this,e)}),p.find("[data-tooltip]").each(function(){Domma.elements.tooltip(this,{content:$(this).data("tooltip"),position:$(this).data("tooltip-position")||"top"})}),p.find(".dm-progression").each(function(){Domma.elements.progression(this,{layout:this.dataset.layout||"vertical",theme:this.dataset.theme||"minimal",mode:this.dataset.mode||"timeline",statusIcons:!0})});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(e=>{const t=e.dataset.revealMode||"stagger",o=e.dataset.revealAnimation||"slide-up",s=parseInt(e.dataset.revealDuration,10)||400,h=parseInt(e.dataset.revealStagger,10)||60,g=parseInt(e.dataset.revealDelay,10)||0,m=e.dataset.revealDirection==="rtl",f=Array.from(e.children),n={"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)"};f.forEach((a,r)=>{a.style.opacity="0",a.style.transform=n[o]||"",a.style.transition=`opacity ${s}ms ease, transform ${s}ms ease`;const c=m?f.length-1-r:r;a.style.transitionDelay=t==="stagger"?`${g+c*h}ms`:`${g}ms`}),requestAnimationFrame(()=>requestAnimationFrame(()=>{const a=new IntersectionObserver(r=>{r.forEach(c=>{c.isIntersecting&&(c.target.offsetWidth,c.target.style.opacity="1",c.target.style.transform="none",a.unobserve(c.target))})},{threshold:.1});f.forEach(r=>a.observe(r))}))}),p.find(".card[data-collapsible]").each(function(){const e=this.querySelector(".card-header");e&&e.addEventListener("click",()=>this.classList.toggle("is-collapsed"))}),p.find(".dm-so-trigger").each(function(){this.addEventListener("click",()=>{const e=this.dataset.soTarget,t=document.getElementById(e);if(!t)return;const o=E.slideover({title:t.dataset.soTitle||"",size:t.dataset.soSize||"md",position:t.dataset.soPosition||"right"});t.style.display="",o.setContent(t),o.open()})})}if(typeof $.setup=="function"){const e=Object.assign({},window.__CMS_DCONFIG__||{});if(document.querySelectorAll(".dm-page-config[data-config]").forEach(t=>{try{const o=atob(t.dataset.config),s=JSON.parse(o);Object.assign(e,s)}catch{}}),Object.keys(e).length>0){const t={};for(const[o,s]of Object.entries(e)){const h=s?.events?.click,{confirm:g,toast:m,alert:f,prompt:n,...a}=h||{};g||m||f||n?($(o).on("click",async function(c){if(c.preventDefault(),g&&!await E.confirm(g))return;let u=null;if(!(n&&(u=await E.prompt(n,{inputPlaceholder:a.promptPlaceholder||"",inputValue:a.promptDefault||""}),u===null))){if(a.target){const y=$(a.target);a.toggleClass&&y.toggleClass(a.toggleClass),a.addClass&&y.addClass(a.addClass),a.removeClass&&y.removeClass(a.removeClass),u!==null&&(a.setText&&y.text(u),a.setVal&&y.val(u),a.setAttr&&y.attr(a.setAttr,u))}a.href&&(window.location.href=a.href),m&&E.toast(m,{type:a.toastType||"success"}),f&&E.alert(f)}}),Object.keys(a).length&&(t[o]={...s,events:{...s.events,click:a}})):t[o]=s}$.setup(t)}}p.length&&wireCTAButtons(p.get(0))});function wireCTAButtons(w){w.querySelectorAll(".dm-cta-trigger").forEach(l=>{l.addEventListener("click",async()=>{const C=l.dataset.action,v=l.dataset.entry,b=l.dataset.confirm;let p=S.get("auth_token");if(!p){E.toast("Please log in to perform this action.",{type:"warning"});return}if(b&&!await E.confirm(b))return;const i=Array.from(l.childNodes).map(e=>e.cloneNode(!0));l.disabled=!0,l.textContent="Running\u2026";const d=e=>fetch(`/api/actions/${C}/public`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${e}`},body:JSON.stringify({entryId:v})});try{let e=await d(p);if(e.status===401){const o=S.get("auth_refresh_token");if(o){const s=await fetch("/api/auth/refresh",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refreshToken:o})});if(s.ok){const{token:h}=await s.json();S.set("auth_token",h),p=h,e=await d(p)}}}const t=await e.json().catch(()=>({}));if(!e.ok)throw new Error(t.error||t.message||`Error ${e.status}`);E.toast(t.message||"Action completed.",{type:"success"})}catch(e){E.toast(e.message||"Action failed.",{type:"error"})}finally{l.disabled=!1,l.textContent="",i.forEach(e=>l.appendChild(e)),Domma.icons.scan(l)}})})}(function(){const l=document.querySelectorAll("[data-collection-table]");!l.length||typeof T>"u"||!T.create||l.forEach(C=>{let v;try{v=JSON.parse(atob(C.dataset.payload))}catch{return}const{columns:b,rows:p,search:i,sortable:d,exportable:e,pageSize:t,empty:o,ctaConfig:s}=v;if(!b?.length)return;if(s){const m=b.findIndex(f=>f.key==="_cta");m!==-1&&(b[m]={key:"_cta",title:"",render:(f,n)=>{const a=document.createElement("button");if(a.className=`btn btn-${s.style||"primary"} dm-cta-trigger`,a.dataset.action=s.action||"",a.dataset.entry=n._entryId||"",s.confirm&&(a.dataset.confirm=s.confirm),s.icon){const r=document.createElement("span");r.dataset.icon=s.icon,a.appendChild(r),a.appendChild(document.createTextNode(" "))}return a.appendChild(document.createTextNode(s.label||"Run")),a}})}const h="col-table-"+Math.random().toString(36).slice(2,7),g=document.createElement("div");g.id=h,C.replaceChildren(g),T.create("#"+h,{data:p,columns:b,search:i,sortable:d,exportable:e,pageSize:t,emptyMessage:o}),s&&wireCTAButtons(g)})})(),(function(){const l=document.querySelectorAll("[data-form-inline]");if(!l.length||typeof F>"u")return;function C(i,d){const e={};return(i||[]).forEach(t=>{if(t.type==="page-break"||t.type==="spacer"||!t.name)return;const o=t.type==="checkbox"?"boolean":t.type==="date"?"string":t.type,s={...t.formConfig||{}};s.span==="full"&&d&&(s.span=d),e[t.name]={type:o,label:t.label,required:t.required,options:t.options,formConfig:{...t.placeholder&&{placeholder:t.placeholder},...t.helper&&{hint:t.helper},...s}}}),e}function v(i){const d={};return(i||[]).forEach(e=>{if(!(!e.name||e.type==="page-break"||e.type==="spacer")&&(e.type==="select"||e.type==="multiselect")&&e.required){const t=(e.options||[])[0];t&&(d[e.name]=typeof t=="object"?t.value:t)}}),d}function b(i,d){(d||[]).forEach(e=>{if(e.type!=="date"||!e.name)return;const t=i.querySelector(`[name="${e.name}"]`);t&&t.type!=="date"&&(t.type="date")})}function p(i,d,e){let t=i.querySelector(".cms-form-message");t||(t=document.createElement("p"),t.className="cms-form-message",i.appendChild(t)),t.textContent=d,t.style.cssText=e?"color:var(--danger,#f87171);margin-top:.75rem;":"color:var(--success,#4ade80);margin-top:.75rem;"}l.forEach(i=>{let d;try{d=JSON.parse(atob(i.dataset.formInline))}catch{return}const e=d.fields||[],t=d.settings||{},o=t.columns||1,s=t.layout||"stacked",h=e.some(n=>n.type==="page-break"),g=async n=>{try{const a=i.querySelector('[name="website"]'),r=i.querySelector('[name="_t"]'),c=Object.assign({},n);a!==null&&(c._hp=a.value),r!==null&&(c._t=r.value);const u=await H.post(`/api/forms/submit/${d.slug}`,c);if(u?.redirect){window.location.href=u.redirect;return}for(;i.firstChild;)i.removeChild(i.firstChild);p(i,u?.message||t.successMessage||"Thank you for your submission.",!1)}catch(a){throw p(i,a.message||"Submission failed. Please try again.",!0),a}};function m(n){const a=n.querySelector("form");if(!a)return;const r=document.createElement("div");r.className="fb-form-honeypot",r.setAttribute("aria-hidden","true");const c=document.createElement("input");c.name="website",c.type="text",c.tabIndex=-1,c.autocomplete="url",c.placeholder="https://",r.appendChild(c);const u=document.createElement("input");u.name="_t",u.type="hidden",u.value=Date.now(),r.appendChild(u),a.appendChild(r)}function f(){if(!window.FormLogicEngine||!e.some(a=>a.logic))return;const n=new window.FormLogicEngine.FormLogicRuntime(d,i);if(n.init(),i._formLogicRuntime=n,i.parentNode&&typeof MutationObserver<"u"){const a=new MutationObserver(function(r){for(const c of r)for(const u of c.removedNodes)if(u===i||u.nodeType===1&&u.contains&&u.contains(i)){n.destroy(),a.disconnect();return}});a.observe(i.parentNode,{childList:!0,subtree:!1})}}if(h&&F.wizard){const n=[];let a=[],r=d.title||"Step 1",c="";e.forEach(y=>{y.type==="page-break"?(n.push({title:r,description:c,fields:C(a,o)}),a=[],r=y.label||`Step ${n.length+1}`,c=y.description||""):y.type!=="spacer"&&a.push(y)}),n.push({title:r,description:c,fields:C(a,o)});const u=F.wizard(i,{schema:{steps:n},onSubmit:g});Promise.resolve(u).then(function(){b(i,e),t.honeypot!==!1&&m(i),f()})}else if(F.render){const n=F.render(i,C(e,o),v(e),{submitText:t.submitText||"Submit",layout:s,columns:o,onSubmit:g});Promise.resolve(n).then(function(){if(s==="grid"&&t.submitSpan==="full"){const a=i.querySelector(".form-buttons");a&&a.classList.add("col-span-full")}b(i,e),t.honeypot!==!1&&m(i),f()})}}),$(document).on("click",".dm-banner__dismiss",function(){$(this).closest(".dm-banner").remove()})})();
|
package/server/services/forms.js
CHANGED
|
@@ -202,7 +202,8 @@ function buildFormFromCollection(schema) {
|
|
|
202
202
|
label: f.label || f.name,
|
|
203
203
|
required: !!f.required,
|
|
204
204
|
placeholder: f.placeholder || '',
|
|
205
|
-
helper: f.helper || ''
|
|
205
|
+
helper: f.helper || '',
|
|
206
|
+
tooltip: f.tooltip || ''
|
|
206
207
|
};
|
|
207
208
|
if (f.options) field.options = f.options;
|
|
208
209
|
if (f.validation) field.validation = f.validation;
|