domma-cms 0.92.1 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +5 -3
- package/admin/css/admin.css +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/lib/action-editor-arrange.js +1 -1
- package/admin/js/lib/api-tokens-arrange.js +2 -2
- package/admin/js/lib/block-editor-arrange.js +1 -1
- package/admin/js/lib/blocks-arrange.js +1 -1
- package/admin/js/lib/collection-entries-arrange.js +1 -1
- package/admin/js/lib/components-arrange.js +1 -1
- package/admin/js/lib/dashboard-arrange.js +1 -1
- package/admin/js/lib/dates.js +1 -0
- package/admin/js/lib/forms-arrange.js +1 -1
- package/admin/js/lib/media-arrange.js +1 -1
- package/admin/js/lib/notifications-arrange.js +1 -1
- package/admin/js/lib/pages-arrange.js +1 -1
- package/admin/js/lib/related.js +1 -1
- package/admin/js/lib/timeline-builder.js +2 -2
- package/admin/js/templates/action-editor.html +6 -5
- package/admin/js/templates/actions-list.html +1 -1
- package/admin/js/templates/contacts.html +1 -1
- package/admin/js/templates/docs/api-actions.html +86 -60
- package/admin/js/templates/docs/api-authentication.html +159 -123
- package/admin/js/templates/docs/api-builder.html +197 -0
- package/admin/js/templates/docs/api-collections.html +199 -259
- package/admin/js/templates/docs/api-external.html +225 -0
- package/admin/js/templates/docs/api-forms.html +268 -0
- package/admin/js/templates/docs/api-layouts.html +70 -45
- package/admin/js/templates/docs/api-media.html +57 -80
- package/admin/js/templates/docs/api-navigation.html +66 -22
- package/admin/js/templates/docs/api-pages.html +109 -129
- package/admin/js/templates/docs/api-plugins.html +123 -61
- package/admin/js/templates/docs/api-scaffold.html +185 -0
- package/admin/js/templates/docs/api-settings.html +72 -64
- package/admin/js/templates/docs/api-users.html +74 -107
- package/admin/js/templates/docs/api-views.html +68 -54
- package/admin/js/templates/docs/components-howto.html +20 -17
- package/admin/js/templates/docs/components-reference.html +13 -16
- package/admin/js/templates/docs/components-rules.html +7 -6
- package/admin/js/templates/docs/components-walkthrough.html +19 -19
- package/admin/js/templates/docs/tutorial-crud.html +71 -40
- package/admin/js/templates/docs/tutorial-forms.html +51 -35
- package/admin/js/templates/docs/tutorial-plugin.html +132 -56
- package/admin/js/templates/docs/usage-actions.html +61 -15
- package/admin/js/templates/docs/usage-collections.html +108 -0
- package/admin/js/templates/docs/usage-cta-shortcode.html +14 -3
- package/admin/js/templates/docs/usage-dconfig.html +0 -3
- package/admin/js/templates/docs/usage-editions.html +213 -0
- package/admin/js/templates/docs/usage-media.html +22 -6
- package/admin/js/templates/docs/usage-navigation.html +74 -18
- package/admin/js/templates/docs/usage-pages.html +60 -20
- package/admin/js/templates/docs/usage-plugins.html +89 -17
- package/admin/js/templates/docs/usage-shortcodes.html +123 -70
- package/admin/js/templates/docs/usage-site-settings.html +50 -18
- package/admin/js/templates/docs/usage-tools.html +73 -0
- package/admin/js/templates/docs/usage-users-roles.html +99 -20
- package/admin/js/templates/docs/usage-views.html +36 -19
- package/admin/js/templates/documentation.html +153 -32
- package/admin/js/templates/page-editor.html +0 -5
- package/admin/js/templates/plugin-guide.html +15 -0
- package/admin/js/templates/plugin-guides.html +21 -0
- package/admin/js/templates/pro-docs.html +53 -234
- package/admin/js/templates/tutorials.html +5 -4
- package/admin/js/views/actions-list.js +3 -3
- package/admin/js/views/analytics.js +5 -5
- package/admin/js/views/api-endpoint-editor.js +2 -2
- package/admin/js/views/block-editor.js +4 -4
- package/admin/js/views/blocks.js +4 -4
- package/admin/js/views/collection-editor.js +4 -4
- package/admin/js/views/collection-entries.js +7 -7
- package/admin/js/views/component-editor.js +2 -2
- package/admin/js/views/contacts.js +22 -20
- package/admin/js/views/context-menu-editor.js +5 -5
- package/admin/js/views/doc-pages.js +1 -1
- package/admin/js/views/form-editor.js +4 -4
- package/admin/js/views/form-submissions.js +2 -2
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/media.js +3 -3
- package/admin/js/views/menu-editor.js +13 -13
- package/admin/js/views/menu-locations.js +2 -2
- package/admin/js/views/my-profile.js +1 -1
- package/admin/js/views/page-editor.js +8 -8
- package/admin/js/views/plugin-guides.js +5 -0
- package/admin/js/views/project-detail.js +2 -2
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/role-editor.js +4 -4
- package/admin/js/views/search.js +2 -2
- package/admin/js/views/seo.js +17 -17
- package/admin/js/views/settings.js +3 -3
- package/admin/js/views/theme.js +3 -3
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +2 -2
- package/admin/js/views/view-editor.js +1 -1
- package/bin/cli.js +13 -13
- package/bin/lib/node-version.js +29 -0
- package/package.json +1 -1
- package/plugins/_lib/admin/mail/compose-window.js +3 -2
- package/plugins/_lib/admin/mail/reader-view.js +7 -6
- package/plugins/_lib/admin/mail/scheduling.js +4 -2
- package/plugins/_lib/admin/mail/templates.js +4 -4
- package/plugins/_lib/admin/ui/dates.js +85 -0
- package/plugins/blog/CLAUDE.md +31 -22
- package/plugins/blog/admin/views/blog.js +3 -2
- package/plugins/blog/admin/views/comments.js +2 -1
- package/plugins/blog/admin/views/post-editor.js +4 -4
- package/plugins/blog/blocks/blog-card-row.html +1 -1
- package/plugins/blog/blocks/blog-card.html +2 -2
- package/plugins/blog/blocks/blog-post-classic.html +2 -2
- package/plugins/blog/blocks/blog-post-essay.html +2 -2
- package/plugins/blog/blocks/blog-post-feature.html +2 -2
- package/plugins/blog/blocks/blog-post-minimal.html +2 -2
- package/plugins/blog/blocks/blog-post-sidebar.html +2 -2
- package/plugins/blog/blocks/blog-post-split.html +2 -2
- package/plugins/blog/docs/guide.md +205 -0
- package/plugins/blog/lib/layouts.js +3 -3
- package/plugins/blog/lib/page.js +2 -1
- package/plugins/blog/plugin.js +3 -3
- package/plugins/blog/plugin.json +4 -4
- package/plugins/blog/tests/layouts.test.js +6 -0
- package/plugins/feedback/CLAUDE.md +22 -3
- package/plugins/feedback/admin/lib/kit.js +6 -7
- package/plugins/feedback/admin/views/feedback.js +79 -10
- package/plugins/feedback/admin/views/send.js +28 -6
- package/plugins/feedback/docs/guide.md +95 -0
- package/plugins/feedback/lib/receiver.js +9 -2
- package/plugins/feedback/lib/sender.js +3 -2
- package/plugins/feedback/plugin.js +54 -6
- package/plugins/feedback/plugin.json +4 -4
- package/plugins/feedback/tests/api.test.js +74 -2
- package/plugins/free-tier.lock.json +49 -44
- package/plugins/mail-reader/CLAUDE.md +33 -18
- package/plugins/mail-reader/docs/guide.md +147 -0
- package/plugins/mail-reader/plugin.json +1 -1
- package/plugins/security/CLAUDE.md +4 -1
- package/plugins/security/admin/views/security.js +5 -5
- package/plugins/security/docs/guide.md +170 -0
- package/plugins/security/plugin.js +2 -1
- package/plugins/security/plugin.json +2 -1
- package/plugins/shopping-cart/CLAUDE.md +7 -1
- package/plugins/shopping-cart/admin/lib/kit.js +5 -2
- package/plugins/shopping-cart/admin/views/orders.js +4 -4
- package/plugins/shopping-cart/admin/views/overview.js +2 -2
- package/plugins/shopping-cart/docs/guide.md +191 -0
- package/plugins/shopping-cart/lib/render.js +2 -1
- package/plugins/shopping-cart/plugin.json +3 -3
- package/public/js/collection-browser.js +2 -2
- package/public/js/site.js +1 -1
- package/scripts/gen-instance-secret.js +3 -1
- package/scripts/setup.js +3 -1
- package/server/middleware/auth.js +2 -1
- package/server/routes/api/actions.js +47 -27
- package/server/routes/api/blocks.js +2 -1
- package/server/routes/api/collections.js +16 -52
- package/server/routes/api/contacts.js +66 -3
- package/server/routes/api/documentation.js +42 -0
- package/server/routes/api/notifications.js +3 -2
- package/server/routes/api/users.js +10 -6
- package/server/server.js +16 -1
- package/server/services/actions.js +110 -34
- package/server/services/adapterRegistry.js +169 -16
- package/server/services/adapters/FileAdapter.js +25 -0
- package/server/services/adapters/MongoAdapter.js +23 -0
- package/server/services/collections.js +104 -1
- package/server/services/connectionManager.js +12 -0
- package/server/services/dates.js +81 -0
- package/server/services/docs.js +13 -2
- package/server/services/markdown.js +75 -26
- package/server/services/notification-sources.js +6 -5
- package/server/services/passwordReset.js +2 -1
- package/server/services/permissionRegistry.js +3 -2
- package/server/services/pluginGuides.js +255 -0
- package/server/services/pluginInstaller.js +54 -13
- package/server/services/plugins.js +29 -1
- package/server/services/presetCollections.js +31 -5
- package/server/services/renderer.js +2 -2
- package/server/services/sidebarBadges.js +3 -1
- package/server/services/tools.js +4 -2
- package/server/templates/page.html +2 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{apiRequest as
|
|
1
|
+
import{apiRequest as ie}from"/admin/js/api.js";import{makeIconInput as Mt}from"/admin/js/lib/shortcode-modal.js";import{enhancePickerFields as tt}from"/public/js/forms.js";import{buildWizardSteps as zt}from"/public/js/form-steps.mjs";import{addBannerAction as $e}from"../lib/plugin-chrome.js";import{helpPopovers as Pt}from"../lib/help-popover.js";import{openMenuAt as nt,sidebarCount as _t}from"../lib/tool-kit.js";import{draftKey as se,draftOf as jt,duplicateField as Vt,fieldTitle as Ae,fingerprint as lt,leavingEditor as at,moveField as ot,restoreDraft as Gt,snapshotOf as Fe}from"../lib/form-editor-arrange.js";import{fmtDateTime as Wt}from"../lib/dates.js";const it=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"chooser",label:"Chooser (visual options)"},{value:"icon",label:"Icon (icon picker)"},{value:"image",label:"Image (media library)"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"password",label:"Password"},{value:"file",label:"File upload"},{value:"hidden",label:"Hidden field"}],Ie=new Set(["select","radio","checkbox-group","chooser"]);let C=[],he=[],N=null,be=null,ne=null,ge={};function q(e,t,o=14){e.textContent="";const n=document.createElement("span");return n.setAttribute("data-icon",t),n.setAttribute("data-icon-size",String(o)),n.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;",e.appendChild(n),window.I?.scan?.(e),e}function re(e,t,o,n=14){return q(e,t,n),e.appendChild(document.createTextNode(" "+o)),e}function Be(e){const t=document.createElement("span");return t.setAttribute("data-icon","help-circle"),t.setAttribute("data-icon-size","12"),t.style.cssText="display:inline-flex;align-items:center;vertical-align:middle;margin-left:.3rem;opacity:.55;cursor:help;",t.title=e,window.I?.scan?.(t),requestAnimationFrame(()=>{try{t.parentNode&&typeof E<"u"&&E.tooltip&&(t.removeAttribute("title"),E.tooltip(t,{content:e,position:"top"}))}catch{}}),t}let ye=null,st=null,Oe=null,ce=null;function Re(){Oe?.(),clearTimeout(st),st=setTimeout(()=>{ye&&ye()},350)}function rt(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function ct(e){return it.find(t=>t.value===e)?.label||e}function dt(e){return(e||[]).some(t=>t.logic||Array.isArray(t.triggers)&&t.triggers.length)}function pt(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function Ht(e){const t={...C[e]};if(t.type==="spacer")return t;if(t.type==="page-break"){const f=document.getElementById(`fb-pb-label-${e}`),x=document.getElementById(`fb-pb-desc-${e}`);return f&&(t.label=f.value.trim()||t.label),x&&(t.description=x.value.trim()),t}const o=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),l=document.getElementById(`fb-type-${e}`),a=document.getElementById(`fb-required-${e}`),i=document.getElementById(`fb-placeholder-${e}`),r=document.getElementById(`fb-helper-${e}`),c=document.getElementById(`fb-tooltip-${e}`);if(o&&(t.label=o.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),l&&(t.type=l.value||t.type),a&&(t.required=a.checked),i&&(t.placeholder=i.value.trim()),r&&(t.helper=r.value.trim()),c&&(t.tooltip=c.value.trim()),t.type==="chooser"){const f=document.getElementById(`fb-chooser-variant-${e}`)?.value;f&&(t.variant=f);const x=document.getElementById(`fb-chooser-multiple-${e}`);x&&(t.multiple=x.checked);const $=document.getElementById(`fb-chooser-density-${e}`)?.value;$&&(t.density=$);const A=document.getElementById(`fb-chooser-columns-${e}`)?.value;A!==""&&A!==void 0&&(t.columns=parseInt(A,10)||3);const G=document.getElementById(`fb-chooser-accent-${e}`)?.value.trim();G?t.accent=G:delete t.accent;const P=document.getElementById(`fb-chooser-accent-style-${e}`)?.value;P?t.accentStyle=P:delete t.accentStyle;const _=document.getElementById(`fb-chooser-glow-${e}`);_&&(t.glow=_.checked);const I=document.getElementById(`fb-chooser-glow-colour-${e}`)?.value.trim();I?t.glowColour=I:delete t.glowColour;const Q=document.getElementById(`fb-chooser-shadow-${e}`)?.value;Q&&Q!=="none"?t.shadow=Q:delete t.shadow;const H=document.getElementById(`fb-chooser-shadow-colour-${e}`)?.value.trim();H?t.shadowColour=H:delete t.shadowColour,ke(e),C[e]&&Array.isArray(C[e].options)&&(t.options=C[e].options)}else if(Ie.has(t.type)){["variant","density","columns","accent","accentStyle","glow","glowColour","shadow","shadowColour"].forEach(x=>delete t[x]),t.type!=="checkbox-group"&&t.type!=="multiselect"&&delete t.multiple;const f=document.getElementById(`fb-options-${e}`);f&&(t.options=f.value.split(`
|
|
2
2
|
`).filter(x=>x.trim()).map(x=>{const[$,...A]=x.split(":");return{value:$.trim(),label:A.join(":").trim()||$.trim()}}))}if(t.type==="textarea"){const f=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);f>0&&(t.formConfig={...t.formConfig||{},rows:f})}const s=document.getElementById(`fb-span-${e}`),d=document.getElementById(`fb-fullwidth-${e}`);if(s||d){const f={...t.formConfig||{}};if(d?.checked)f.span="full";else{const x=parseInt(s?.value,10);x>1?f.span=x:delete f.span}t.formConfig=Object.keys(f).length?f:void 0}const u=document.getElementById(`fb-minlength-${e}`)?.value;u&&(t.minLength=parseInt(u,10));const b=document.getElementById(`fb-maxlength-${e}`)?.value;b&&(t.maxLength=parseInt(b,10));const g=document.getElementById(`fb-min-${e}`)?.value;g!==""&&g!==void 0&&(t.min=parseFloat(g));const m=document.getElementById(`fb-max-${e}`)?.value;m!==""&&m!==void 0&&(t.max=parseFloat(m));const h=Ut(e);h?t.logic=h:delete t.logic;const w=dn(e);return w?t.triggers=w:delete t.triggers,t}function Ut(e){const t=document.querySelector(`.fb-field-card[data-index="${e}"]`);if(!t)return;const o=t.querySelector(".fb-field-logic");if(!o)return;const n={};let l=!1;const a=o.querySelector('[data-logic-section="visibility"]');if(a){const s=a.querySelector(".fb-logic-vis-default"),d=a.querySelector(".fb-logic-vis-transition"),u=Array.from(a.querySelectorAll(".fb-logic-cond-row")).map(h=>{const w=h.querySelector(".fb-logic-cond-field"),f=h.querySelector(".fb-logic-cond-op"),x=h.querySelector(".fb-logic-cond-val"),$=h.querySelector(".fb-logic-vis-then");return w?.value?{when:{all:[{field:w.value,operator:f.value,value:x.value}]},then:$.value}:null}).filter(Boolean),b=s?.value||"visible",g=d?.value||"none",m=parseInt(a.querySelector(".fb-logic-vis-duration")?.value||"",10);(b!=="visible"||u.length>0||g!=="none")&&(n.visibility={default:b,conditions:u},g!=="none"&&(n.visibility.transition=g),g!=="none"&&Number.isFinite(m)&&(n.visibility.duration=m),l=!0)}const i=o.querySelector('[data-logic-section="requirement"]');if(i){const s=i.querySelector(".fb-logic-req-default"),d=Array.from(i.querySelectorAll(".fb-logic-cond-row")).map(u=>{const b=u.querySelector(".fb-logic-cond-field"),g=u.querySelector(".fb-logic-cond-op"),m=u.querySelector(".fb-logic-cond-val"),h=u.querySelector(".fb-logic-req-then");return b?.value?{when:{all:[{field:b.value,operator:g.value,value:m.value}]},then:h.value==="true"}:null}).filter(Boolean);d.length>0&&(n.requirement={default:s?.checked===!0,conditions:d},l=!0)}const r=o.querySelector('[data-logic-section="validation"]');if(r){const s=Array.from(r.querySelectorAll(".fb-logic-val-rule")).map(d=>{const u=d.querySelector(".fb-logic-val-type"),b=d.querySelector(".fb-logic-val-pattern"),g=d.querySelector(".fb-logic-val-flags"),m=d.querySelector(".fb-logic-val-message");if(!b?.value.trim())return null;const h=u?.value||"regex",w={type:h,message:m?.value.trim()||"Invalid value."};return h==="regex"?(w.pattern=b.value.trim(),g?.value.trim()&&(w.flags=g.value.trim())):w.field=b.value.trim(),w}).filter(Boolean);s.length>0&&(n.validation=s,l=!0)}const c=o.querySelector('[data-logic-section="cascade"]');if(c){const s=c.querySelector(".fb-logic-cascade-source"),d=c.querySelector(".fb-logic-cascade-mapping"),u=c.querySelector(".fb-logic-cascade-defaults"),b=s?.value?.trim();if(b){let g={};try{g=JSON.parse(d?.value||"{}")}catch{}const m=(u?.value||"").split(`
|
|
3
|
-
`).filter(h=>h.trim()).map(h=>{const[w,...f]=h.split(":");return{value:w.trim(),label:f.join(":").trim()||w.trim()}});n.cascade={sourceField:b,mapping:g,defaultOptions:m},l=!0}}return l?n:void 0}function O(){C=C.map((e,t)=>Wt(t))}let ae=null;function Jt(e,t,o){const n=e.firstElementChild;if(!n)return;const l=document.createElement("span");l.setAttribute("data-icon","menu"),l.setAttribute("data-icon-size","13"),l.title="Drag to reorder",l.style.cssText="cursor:grab;opacity:.35;flex-shrink:0;display:inline-flex;align-items:center;",n.insertBefore(l,n.firstChild),window.I?.scan?.(n),n.draggable=!0,n.addEventListener("dragstart",a=>{ae=t,a.dataTransfer.effectAllowed="move",e.style.opacity="0.4"}),n.addEventListener("dragend",()=>{e.style.opacity="",document.querySelectorAll("#fields-list .fb-field-card").forEach(a=>a.classList.remove("fb-drag-over"))}),e.addEventListener("dragover",a=>{ae!=null&&(a.preventDefault(),a.dataTransfer.dropEffect="move",document.querySelectorAll("#fields-list .fb-field-card").forEach(i=>i.classList.remove("fb-drag-over")),e.classList.add("fb-drag-over"))}),e.addEventListener("dragleave",()=>e.classList.remove("fb-drag-over")),e.addEventListener("drop",a=>{if(a.preventDefault(),e.classList.remove("fb-drag-over"),ae==null||ae===t){ae=null;return}O();const[i]=C.splice(ae,1);C.splice(t,0,i),ae=null,Y(o)})}function Y(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()),C.length===0){o&&(o.style.display=""),de?.(t),Re();return}o&&(o.style.display="none"),C.forEach((n,l)=>{const a=n.type==="page-break"?Yt(n,l,e):n.type==="spacer"?Kt(n,l,e):Qt(n,l,e);Jt(a,l,e),t.appendChild(a)}),de?.(t),Re()}}function Yt(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent="- Page Break -",a.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:color-mix(in srgb, var(--dm-text-muted) 20%, transparent);color:var(--dm-text-muted);white-space:nowrap;flex-shrink:0;font-style:italic;";const i=document.createElement("span");i.textContent=e.label||"Untitled Step",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text-muted);";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit step",q(c,"more-horizontal"),c.addEventListener("click",g=>{g.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove page break",q(s,"x"),s.addEventListener("click",async g=>{g.stopPropagation(),await E.confirm("Remove this page break?")&&(O(),C.splice(t,1),Y(o))}),r.appendChild(s),l.appendChild(a),l.appendChild(i),l.appendChild(r),l.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=document.createElement("div");d.className="fb-field-body",d.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border);display:none;";const u=z([P("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),P("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),b=u.querySelector(`#fb-pb-label-${t}`);return b&&b.addEventListener("input",()=>{i.textContent=b.value||"Untitled Step"}),d.appendChild(u),n.appendChild(l),n.appendChild(d),n}function Kt(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--dm-border);border-radius:6px;margin-bottom:.5rem;background:transparent;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const a=document.createElement("div");a.style.cssText="flex:1;height:1px;background:var(--dm-border);";const i=document.createElement("span");i.textContent="Spacer",i.style.cssText="font-size:.7rem;color:var(--dm-text-muted);white-space:nowrap;padding:0 .4rem;font-style:italic;";const r=document.createElement("div");r.style.cssText="flex:1;height:1px;background:var(--dm-border);";const c=document.createElement("div");c.style.cssText="display:flex;gap:.25rem;flex-shrink:0;";const s=document.createElement("button");return s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove spacer",q(s,"x"),s.addEventListener("click",async d=>{d.stopPropagation(),O(),C.splice(t,1),Y(o)}),c.appendChild(s),l.appendChild(a),l.appendChild(i),l.appendChild(r),l.appendChild(c),n.appendChild(l),n}function Qt(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);box-shadow:var(--dm-shadow-sm);";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;background:var(--dm-card-header-bg);cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent=dt(e.type),a.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:color-mix(in srgb, var(--dm-primary) 14%, transparent);color:var(--dm-primary);white-space:nowrap;flex-shrink:0;";const i=document.createElement("span");i.textContent=e.label||"(unlabelled)",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit field",q(c,"more-horizontal"),c.addEventListener("click",u=>{u.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");if(s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove field",q(s,"x"),s.addEventListener("click",async u=>{u.stopPropagation(),await E.confirm("Remove this field?")&&(O(),C.splice(t,1),Y(o))}),r.appendChild(s),l.appendChild(a),l.appendChild(i),e.required){const u=document.createElement("span");u.textContent="required",u.style.cssText="font-size:.7rem;color:var(--dm-danger);flex-shrink:0;",l.appendChild(u)}if(ut(e.logic)){const u=document.createElement("span");q(u,"zap"),u.title="Has conditional logic",u.style.cssText="font-size:.75rem;color:var(--dm-primary);flex-shrink:0;",l.appendChild(u)}l.appendChild(r),l.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=Xt(e,t,i);return d.style.display="none",n.appendChild(l),n.appendChild(d),n}function Xt(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:1rem .9rem;border-top:1px solid var(--dm-border);";const l=z([P("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),P("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),a=z([gn("Type",`fb-type-${t}`,st,e.type||"string"),qt("Required",`fb-required-${t}`,e.required||!1)]),i=z([P("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field")]),r=z([P("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field"),P("Tooltip",`fb-tooltip-${t}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),c=e.formConfig?.span,s=z([P("Column Span",`fb-span-${t}`,"number",c&&c!=="full"?String(c):"1","Columns to span (grid only)"),qt("Full Width",`fb-fullwidth-${t}`,c==="full")]);s.classList.add("fb-grid-row"),s.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(l),n.appendChild(a),n.appendChild(i),n.appendChild(r),n.appendChild(s);const d=n.querySelector(`#fb-label-${t}`),u=n.querySelector(`#fb-name-${t}`);d&&d.addEventListener("input",()=>{o&&(o.textContent=d.value||"(unlabelled)"),u&&!u.dataset.manuallyEdited&&(u.value=ct(d.value))}),u&&u.addEventListener("input",()=>{u.dataset.manuallyEdited="1"});const b=n.querySelector(`#fb-type-${t}`);b&&b.addEventListener("change",()=>{const m=n.closest(".fb-field-card");if(m){const f=m.querySelector("span");f&&(f.textContent=dt(b.value))}const h=n.querySelector(".fb-field-extras");h&&h.remove();const w=St(b.value,e,t);w&&n.appendChild(w)});const g=St(e.type,e,t);return g&&n.appendChild(g),n.appendChild(ln(e,t)),n.appendChild(rn(e,t)),n}const xe=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],De=new Set(["is_empty","is_not_empty"]),mt={equals:"includes",not_equals:"does not include",contains:"any value contains",not_contains:"no value contains",starts_with:"any value starts with",ends_with:"any value ends with",greater_than:"any value is greater than",less_than:"any value is less than",is_empty:"nothing selected",is_not_empty:"something selected",in:"includes one of (comma sep)",not_in:"includes none of (comma sep)",matches_regex:"any value matches regex"};function ze(e){return!!e&&(e.type==="checkbox-group"||!!e.multiple)}function Ce(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--dm-text-muted);margin:0 0 .7rem;text-transform:uppercase;letter-spacing:.06em;",t}function Ee(e,t,o,n,l){const a=document.createElement("div");a.className="fb-logic-cond-row",a.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const i=document.createElement("span");i.textContent="When",i.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const r=document.createElement("select");r.className="form-select fb-logic-cond-field",r.style.cssText="flex:1 1 140px;min-width:140px;",t.forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,e&&m.value===e.field&&(h.selected=!0),r.appendChild(h)});const c=document.createElement("select");c.className="form-select fb-logic-cond-op",c.style.cssText="flex:1 1 160px;min-width:140px;",xe.forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,e&&m.value===e.operator&&(h.selected=!0),c.appendChild(h)});const s=()=>{const m=t.find(h=>h.value===r.value);Array.from(c.options).forEach(h=>{const w=xe.find(f=>f.value===h.value);h.textContent=m?.multi&&mt[h.value]||w?.label||h.value})};s(),r.addEventListener("change",s);const d=document.createElement("input");d.type="text",d.className="form-input fb-logic-cond-val",d.placeholder="value",d.style.cssText="flex:1 1 120px;min-width:100px;",d.value=e?.value||"",e&&De.has(e.operator)&&(d.style.display="none"),c.addEventListener("change",()=>{d.style.display=De.has(c.value)?"none":""});const u=document.createElement("span");q(u,"arrow-right"),u.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const b=document.createElement("select");b.className=`form-select ${n}`,b.style.cssText="flex:1 1 140px;min-width:120px;",o.forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,m.value===l&&(h.selected=!0),b.appendChild(h)});const g=document.createElement("button");return g.type="button",g.className="btn btn-xs btn-ghost",g.style.cssText="line-height:1;opacity:.6;",q(g,"x"),g.style.flexShrink="0",g.addEventListener("click",()=>a.remove()),a.appendChild(i),a.appendChild(r),a.appendChild(c),a.appendChild(d),a.appendChild(u),a.appendChild(b),a.appendChild(g),a}function Zt(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(Ce("Visibility"));const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const a=document.createElement("span");a.textContent="Default:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-vis-default",i.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(f=>{const x=document.createElement("option");x.value=f.value,x.textContent=f.label,f.value===(e.default||"visible")&&(x.selected=!0),i.appendChild(x)}),l.appendChild(a),l.appendChild(i),n.appendChild(l);const r=document.createElement("div");r.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const c=document.createElement("span");c.textContent="Transition:",c.style.cssText="font-size:.8rem;flex-shrink:0;";const s=document.createElement("select");s.className="form-select fb-logic-vis-transition",s.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(f=>{const x=document.createElement("option");x.value=f.value,x.textContent=f.label,f.value===(e.transition||"none")&&(x.selected=!0),s.appendChild(x)}),r.appendChild(c),r.appendChild(s),n.appendChild(r);const d=document.createElement("div");d.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const u=document.createElement("span");u.textContent="Speed:",u.style.cssText="font-size:.8rem;flex-shrink:0;";const b=document.createElement("select");b.className="form-select fb-logic-vis-duration",b.style.cssText="max-width:240px;",[{value:"",label:"Default"},{value:"120",label:"Very fast (120ms)"},{value:"200",label:"Fast (200ms)"},{value:"350",label:"Medium (350ms)"},{value:"600",label:"Slow (600ms)"},{value:"1000",label:"Very slow (1s)"}].forEach(f=>{const x=document.createElement("option");x.value=f.value,x.textContent=f.label,f.value===String(e.duration??"")&&(x.selected=!0),b.appendChild(x)}),d.appendChild(u),d.appendChild(b),n.appendChild(d);const g=()=>{d.style.display=s.value==="none"?"none":""};g(),s.addEventListener("change",g);const m=document.createElement("div");m.className="fb-logic-vis-rules";const h=o.map(f=>({value:f.name,label:f.label||f.name,multi:ze(f)})),w=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(f=>{const x=(f.when?.all||f.when?.any||[])[0],$=f.then==="hidden"?"hidden":"visible";h.length>0&&m.appendChild(Ee(x,h,w,"fb-logic-vis-then",$))}),n.appendChild(m),h.length>0){const f=document.createElement("button");f.type="button",f.className="btn btn-xs btn-ghost",f.style.cssText="font-size:.73rem;margin-top:.35rem;",ce(f,"plus","Add visibility rule"),f.addEventListener("click",()=>m.appendChild(Ee(null,h,w,"fb-logic-vis-then","visible"))),n.appendChild(f)}return n}function en(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(Ce("Conditional Requirement"));const l=document.createElement("label");l.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8rem;cursor:pointer;margin-bottom:.65rem;";const a=document.createElement("input");a.type="checkbox",a.className="fb-logic-req-default",a.checked=e.default===!0,l.appendChild(a),l.appendChild(document.createTextNode("Required by default")),n.appendChild(l);const i=document.createElement("div");i.className="fb-logic-req-rules";const r=o.map(s=>({value:s.name,label:s.label||s.name,multi:ze(s)})),c=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(s=>{const d=(s.when?.all||s.when?.any||[])[0],u=s.then===!0?"true":"false";r.length>0&&i.appendChild(Ee(d,r,c,"fb-logic-req-then",u))}),n.appendChild(i),r.length>0){const s=document.createElement("button");s.type="button",s.className="btn btn-xs btn-ghost",s.style.cssText="font-size:.73rem;margin-top:.35rem;",ce(s,"plus","Add requirement rule"),s.addEventListener("click",()=>i.appendChild(Ee(null,r,c,"fb-logic-req-then","true"))),n.appendChild(s)}return n}function ft(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const o=document.createElement("select");o.className="form-select fb-logic-val-type",o.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===(e?.type||"regex")&&(c.selected=!0),o.appendChild(c)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;";const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-flags",l.placeholder="flags",l.value=e?.flags||"",l.style.cssText="flex:0 0 55px;",e?.type==="match"&&(l.style.display="none"),o.addEventListener("change",()=>{l.style.display=o.value==="match"?"none":"",n.placeholder=o.value==="match"?"field name":"pattern"});const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-val-message",a.placeholder="Error message",a.value=e?.message||"",a.style.cssText="flex:4;";const i=document.createElement("button");return i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="line-height:1;opacity:.6;",q(i,"x"),i.style.flexShrink="0",i.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(l),t.appendChild(a),t.appendChild(i),t}function tn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(Ce("Custom Validation"));const l=document.createElement("div");l.className="fb-logic-val-rules",(e||[]).forEach(i=>l.appendChild(ft(i))),n.appendChild(l);const a=document.createElement("button");return a.type="button",a.className="btn btn-xs btn-ghost",a.style.cssText="font-size:.73rem;margin-top:.35rem;",ce(a,"plus","Add validation rule"),a.addEventListener("click",()=>l.appendChild(ft(null))),n.appendChild(a),n}function nn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(Ce("Cascade Options")),n.lastChild.appendChild(Oe("Make this field's options depend on another field. When the source field changes, the options here are replaced by the mapping entry for its value; if nothing matches, the default options below are shown."));const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const a=document.createElement("span");a.textContent="Source field:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-cascade-source",i.style.cssText="flex:1;";const r=document.createElement("option");r.value="",r.textContent="- none -",i.appendChild(r),o.forEach(b=>{const g=document.createElement("option");g.value=b.name,g.textContent=b.label||b.name,b.name===e.sourceField&&(g.selected=!0),i.appendChild(g)}),l.appendChild(a),l.appendChild(i),n.appendChild(l);const c=document.createElement("p");c.textContent='Mapping JSON - {"value":[{"value":"...","label":"..."}]}',c.appendChild(Oe(`Each key is a value of the source field; its list becomes this field's options when that value is picked. Example: {"uk":[{"value":"london","label":"London"}]} shows London when the source is "uk".`)),c.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const s=document.createElement("textarea");s.className="form-input fb-logic-cascade-mapping",s.rows=4,s.style.cssText="font-family:monospace;",s.placeholder='{"uk": [{"value": "london", "label": "London"}]}',s.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(c),n.appendChild(s);const d=document.createElement("p");d.textContent="Default options (one per line: value:Label)",d.appendChild(Oe("Shown before the source field has a value, or when its value has no mapping entry.")),d.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const u=document.createElement("textarea");return u.className="form-input fb-logic-cascade-defaults",u.rows=3,u.style.cssText="font-family:monospace;",u.placeholder=`option1:Option 1
|
|
3
|
+
`).filter(h=>h.trim()).map(h=>{const[w,...f]=h.split(":");return{value:w.trim(),label:f.join(":").trim()||w.trim()}});n.cascade={sourceField:b,mapping:g,defaultOptions:m},l=!0}}return l?n:void 0}function O(){C=C.map((e,t)=>Ht(t))}let le=null;function Jt(e,t,o){const n=e.firstElementChild;if(!n)return;const l=document.createElement("span");l.setAttribute("data-icon","menu"),l.setAttribute("data-icon-size","13"),l.title="Drag to reorder",l.style.cssText="cursor:grab;opacity:.35;flex-shrink:0;display:inline-flex;align-items:center;",n.insertBefore(l,n.firstChild),window.I?.scan?.(n),n.draggable=!0,n.addEventListener("dragstart",a=>{le=t,a.dataTransfer.effectAllowed="move",e.style.opacity="0.4"}),n.addEventListener("dragend",()=>{e.style.opacity="",document.querySelectorAll("#fields-list .fb-field-card").forEach(a=>a.classList.remove("fb-drag-over"))}),e.addEventListener("dragover",a=>{le!=null&&(a.preventDefault(),a.dataTransfer.dropEffect="move",document.querySelectorAll("#fields-list .fb-field-card").forEach(i=>i.classList.remove("fb-drag-over")),e.classList.add("fb-drag-over"))}),e.addEventListener("dragleave",()=>e.classList.remove("fb-drag-over")),e.addEventListener("drop",a=>{if(a.preventDefault(),e.classList.remove("fb-drag-over"),le==null||le===t){le=null;return}O();const[i]=C.splice(le,1);C.splice(t,0,i),le=null,J(o)})}function J(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()),C.length===0){o&&(o.style.display=""),ce?.(t),Re();return}o&&(o.style.display="none"),C.forEach((n,l)=>{const a=n.type==="page-break"?Yt(n,l,e):n.type==="spacer"?Kt(n,l,e):Qt(n,l,e);Jt(a,l,e),t.appendChild(a)}),ce?.(t),Re()}}function Yt(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent="- Page Break -",a.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:color-mix(in srgb, var(--dm-text-muted) 20%, transparent);color:var(--dm-text-muted);white-space:nowrap;flex-shrink:0;font-style:italic;";const i=document.createElement("span");i.textContent=e.label||"Untitled Step",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text-muted);";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit step",q(c,"more-horizontal"),c.addEventListener("click",g=>{g.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove page break",q(s,"x"),s.addEventListener("click",async g=>{g.stopPropagation(),await E.confirm("Remove this page break?")&&(O(),C.splice(t,1),J(o))}),r.appendChild(s),l.appendChild(a),l.appendChild(i),l.appendChild(r),l.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=document.createElement("div");d.className="fb-field-body",d.style.cssText="padding:.8rem;border-top:1px dashed var(--dm-border);display:none;";const u=D([z("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),z("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),b=u.querySelector(`#fb-pb-label-${t}`);return b&&b.addEventListener("input",()=>{i.textContent=b.value||"Untitled Step"}),d.appendChild(u),n.appendChild(l),n.appendChild(d),n}function Kt(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--dm-border);border-radius:6px;margin-bottom:.5rem;background:transparent;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const a=document.createElement("div");a.style.cssText="flex:1;height:1px;background:var(--dm-border);";const i=document.createElement("span");i.textContent="Spacer",i.style.cssText="font-size:.7rem;color:var(--dm-text-muted);white-space:nowrap;padding:0 .4rem;font-style:italic;";const r=document.createElement("div");r.style.cssText="flex:1;height:1px;background:var(--dm-border);";const c=document.createElement("div");c.style.cssText="display:flex;gap:.25rem;flex-shrink:0;";const s=document.createElement("button");return s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove spacer",q(s,"x"),s.addEventListener("click",async d=>{d.stopPropagation(),O(),C.splice(t,1),J(o)}),c.appendChild(s),l.appendChild(a),l.appendChild(i),l.appendChild(r),l.appendChild(c),n.appendChild(l),n}function Qt(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--dm-border);border-radius:8px;overflow:hidden;margin-bottom:.75rem;background:var(--dm-card-bg);box-shadow:var(--dm-shadow-sm);";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;background:var(--dm-card-header-bg);cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent=ct(e.type),a.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:color-mix(in srgb, var(--dm-primary) 14%, transparent);color:var(--dm-primary);white-space:nowrap;flex-shrink:0;";const i=document.createElement("span");i.textContent=e.label||"(unlabelled)",i.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const r=document.createElement("div");r.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;";const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Edit field",q(c,"more-horizontal"),c.addEventListener("click",u=>{u.stopPropagation(),d.style.display=d.style.display==="none"?"":"none"}),r.appendChild(c);const s=document.createElement("button");if(s.className="btn btn-xs btn-ghost",s.style.cssText="line-height:1;opacity:.6;",s.title="Remove field",q(s,"x"),s.addEventListener("click",async u=>{u.stopPropagation(),await E.confirm("Remove this field?")&&(O(),C.splice(t,1),J(o))}),r.appendChild(s),l.appendChild(a),l.appendChild(i),e.required){const u=document.createElement("span");u.textContent="required",u.style.cssText="font-size:.7rem;color:var(--dm-danger);flex-shrink:0;",l.appendChild(u)}if(pt(e.logic)){const u=document.createElement("span");q(u,"zap"),u.title="Has conditional logic",u.style.cssText="font-size:.75rem;color:var(--dm-primary);flex-shrink:0;",l.appendChild(u)}l.appendChild(r),l.addEventListener("click",()=>{d.style.display=d.style.display==="none"?"":"none"});const d=Xt(e,t,i);return d.style.display="none",n.appendChild(l),n.appendChild(d),n}function Xt(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:1rem .9rem;border-top:1px solid var(--dm-border);";const l=D([z("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),z("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),a=D([gn("Type",`fb-type-${t}`,it,e.type||"string"),Lt("Required",`fb-required-${t}`,e.required||!1)]),i=D([z("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field")]),r=D([z("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field"),z("Tooltip",`fb-tooltip-${t}`,"text",e.tooltip||"","Shown on hover via a help icon next to the label")]),c=e.formConfig?.span,s=D([z("Column Span",`fb-span-${t}`,"number",c&&c!=="full"?String(c):"1","Columns to span (grid only)"),Lt("Full Width",`fb-fullwidth-${t}`,c==="full")]);s.classList.add("fb-grid-row"),s.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(l),n.appendChild(a),n.appendChild(i),n.appendChild(r),n.appendChild(s);const d=n.querySelector(`#fb-label-${t}`),u=n.querySelector(`#fb-name-${t}`);d&&d.addEventListener("input",()=>{o&&(o.textContent=d.value||"(unlabelled)"),u&&!u.dataset.manuallyEdited&&(u.value=rt(d.value))}),u&&u.addEventListener("input",()=>{u.dataset.manuallyEdited="1"});const b=n.querySelector(`#fb-type-${t}`);b&&b.addEventListener("change",()=>{const m=n.closest(".fb-field-card");if(m){const f=m.querySelector("span");f&&(f.textContent=ct(b.value))}const h=n.querySelector(".fb-field-extras");h&&h.remove();const w=kt(b.value,e,t);w&&n.appendChild(w)});const g=kt(e.type,e,t);return g&&n.appendChild(g),n.appendChild(ln(e,t)),n.appendChild(rn(e,t)),n}const ve=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],De=new Set(["is_empty","is_not_empty"]),ut={equals:"includes",not_equals:"does not include",contains:"any value contains",not_contains:"no value contains",starts_with:"any value starts with",ends_with:"any value ends with",greater_than:"any value is greater than",less_than:"any value is less than",is_empty:"nothing selected",is_not_empty:"something selected",in:"includes one of (comma sep)",not_in:"includes none of (comma sep)",matches_regex:"any value matches regex"};function Me(e){return!!e&&(e.type==="checkbox-group"||!!e.multiple)}function xe(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--dm-text-muted);margin:0 0 .7rem;text-transform:uppercase;letter-spacing:.06em;",t}function Ce(e,t,o,n,l){const a=document.createElement("div");a.className="fb-logic-cond-row",a.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const i=document.createElement("span");i.textContent="When",i.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const r=document.createElement("select");r.className="form-select fb-logic-cond-field",r.style.cssText="flex:1 1 140px;min-width:140px;",t.forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,e&&m.value===e.field&&(h.selected=!0),r.appendChild(h)});const c=document.createElement("select");c.className="form-select fb-logic-cond-op",c.style.cssText="flex:1 1 160px;min-width:140px;",ve.forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,e&&m.value===e.operator&&(h.selected=!0),c.appendChild(h)});const s=()=>{const m=t.find(h=>h.value===r.value);Array.from(c.options).forEach(h=>{const w=ve.find(f=>f.value===h.value);h.textContent=m?.multi&&ut[h.value]||w?.label||h.value})};s(),r.addEventListener("change",s);const d=document.createElement("input");d.type="text",d.className="form-input fb-logic-cond-val",d.placeholder="value",d.style.cssText="flex:1 1 120px;min-width:100px;",d.value=e?.value||"",e&&De.has(e.operator)&&(d.style.display="none"),c.addEventListener("change",()=>{d.style.display=De.has(c.value)?"none":""});const u=document.createElement("span");q(u,"arrow-right"),u.style.cssText="font-size:.73rem;color:var(--dm-text-muted);flex-shrink:0;";const b=document.createElement("select");b.className=`form-select ${n}`,b.style.cssText="flex:1 1 140px;min-width:120px;",o.forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,m.value===l&&(h.selected=!0),b.appendChild(h)});const g=document.createElement("button");return g.type="button",g.className="btn btn-xs btn-ghost",g.style.cssText="line-height:1;opacity:.6;",q(g,"x"),g.style.flexShrink="0",g.addEventListener("click",()=>a.remove()),a.appendChild(i),a.appendChild(r),a.appendChild(c),a.appendChild(d),a.appendChild(u),a.appendChild(b),a.appendChild(g),a}function Zt(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(xe("Visibility"));const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const a=document.createElement("span");a.textContent="Default:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-vis-default",i.style.cssText="max-width:240px;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(f=>{const x=document.createElement("option");x.value=f.value,x.textContent=f.label,f.value===(e.default||"visible")&&(x.selected=!0),i.appendChild(x)}),l.appendChild(a),l.appendChild(i),n.appendChild(l);const r=document.createElement("div");r.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const c=document.createElement("span");c.textContent="Transition:",c.style.cssText="font-size:.8rem;flex-shrink:0;";const s=document.createElement("select");s.className="form-select fb-logic-vis-transition",s.style.cssText="max-width:240px;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(f=>{const x=document.createElement("option");x.value=f.value,x.textContent=f.label,f.value===(e.transition||"none")&&(x.selected=!0),s.appendChild(x)}),r.appendChild(c),r.appendChild(s),n.appendChild(r);const d=document.createElement("div");d.style.cssText="display:flex;align-items:center;gap:.6rem;margin-bottom:.65rem;flex-wrap:wrap;";const u=document.createElement("span");u.textContent="Speed:",u.style.cssText="font-size:.8rem;flex-shrink:0;";const b=document.createElement("select");b.className="form-select fb-logic-vis-duration",b.style.cssText="max-width:240px;",[{value:"",label:"Default"},{value:"120",label:"Very fast (120ms)"},{value:"200",label:"Fast (200ms)"},{value:"350",label:"Medium (350ms)"},{value:"600",label:"Slow (600ms)"},{value:"1000",label:"Very slow (1s)"}].forEach(f=>{const x=document.createElement("option");x.value=f.value,x.textContent=f.label,f.value===String(e.duration??"")&&(x.selected=!0),b.appendChild(x)}),d.appendChild(u),d.appendChild(b),n.appendChild(d);const g=()=>{d.style.display=s.value==="none"?"none":""};g(),s.addEventListener("change",g);const m=document.createElement("div");m.className="fb-logic-vis-rules";const h=o.map(f=>({value:f.name,label:f.label||f.name,multi:Me(f)})),w=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(f=>{const x=(f.when?.all||f.when?.any||[])[0],$=f.then==="hidden"?"hidden":"visible";h.length>0&&m.appendChild(Ce(x,h,w,"fb-logic-vis-then",$))}),n.appendChild(m),h.length>0){const f=document.createElement("button");f.type="button",f.className="btn btn-xs btn-ghost",f.style.cssText="font-size:.73rem;margin-top:.35rem;",re(f,"plus","Add visibility rule"),f.addEventListener("click",()=>m.appendChild(Ce(null,h,w,"fb-logic-vis-then","visible"))),n.appendChild(f)}return n}function en(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(xe("Conditional Requirement"));const l=document.createElement("label");l.style.cssText="display:flex;align-items:center;gap:.5rem;font-size:.8rem;cursor:pointer;margin-bottom:.65rem;";const a=document.createElement("input");a.type="checkbox",a.className="fb-logic-req-default",a.checked=e.default===!0,l.appendChild(a),l.appendChild(document.createTextNode("Required by default")),n.appendChild(l);const i=document.createElement("div");i.className="fb-logic-req-rules";const r=o.map(s=>({value:s.name,label:s.label||s.name,multi:Me(s)})),c=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(s=>{const d=(s.when?.all||s.when?.any||[])[0],u=s.then===!0?"true":"false";r.length>0&&i.appendChild(Ce(d,r,c,"fb-logic-req-then",u))}),n.appendChild(i),r.length>0){const s=document.createElement("button");s.type="button",s.className="btn btn-xs btn-ghost",s.style.cssText="font-size:.73rem;margin-top:.35rem;",re(s,"plus","Add requirement rule"),s.addEventListener("click",()=>i.appendChild(Ce(null,r,c,"fb-logic-req-then","true"))),n.appendChild(s)}return n}function mt(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.55rem;align-items:center;margin-bottom:.6rem;flex-wrap:wrap;";const o=document.createElement("select");o.className="form-select fb-logic-val-type",o.style.cssText="flex:0 0 140px;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===(e?.type||"regex")&&(c.selected=!0),o.appendChild(c)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;";const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-flags",l.placeholder="flags",l.value=e?.flags||"",l.style.cssText="flex:0 0 55px;",e?.type==="match"&&(l.style.display="none"),o.addEventListener("change",()=>{l.style.display=o.value==="match"?"none":"",n.placeholder=o.value==="match"?"field name":"pattern"});const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-val-message",a.placeholder="Error message",a.value=e?.message||"",a.style.cssText="flex:4;";const i=document.createElement("button");return i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="line-height:1;opacity:.6;",q(i,"x"),i.style.flexShrink="0",i.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(l),t.appendChild(a),t.appendChild(i),t}function tn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(xe("Custom Validation"));const l=document.createElement("div");l.className="fb-logic-val-rules",(e||[]).forEach(i=>l.appendChild(mt(i))),n.appendChild(l);const a=document.createElement("button");return a.type="button",a.className="btn btn-xs btn-ghost",a.style.cssText="font-size:.73rem;margin-top:.35rem;",re(a,"plus","Add validation rule"),a.addEventListener("click",()=>l.appendChild(mt(null))),n.appendChild(a),n}function nn(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(xe("Cascade Options")),n.lastChild.appendChild(Be("Make this field's options depend on another field. When the source field changes, the options here are replaced by the mapping entry for its value; if nothing matches, the default options below are shown."));const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const a=document.createElement("span");a.textContent="Source field:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-select fb-logic-cascade-source",i.style.cssText="flex:1;";const r=document.createElement("option");r.value="",r.textContent="- none -",i.appendChild(r),o.forEach(b=>{const g=document.createElement("option");g.value=b.name,g.textContent=b.label||b.name,b.name===e.sourceField&&(g.selected=!0),i.appendChild(g)}),l.appendChild(a),l.appendChild(i),n.appendChild(l);const c=document.createElement("p");c.textContent='Mapping JSON - {"value":[{"value":"...","label":"..."}]}',c.appendChild(Be(`Each key is a value of the source field; its list becomes this field's options when that value is picked. Example: {"uk":[{"value":"london","label":"London"}]} shows London when the source is "uk".`)),c.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const s=document.createElement("textarea");s.className="form-input fb-logic-cascade-mapping",s.rows=4,s.style.cssText="font-family:monospace;",s.placeholder='{"uk": [{"value": "london", "label": "London"}]}',s.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(c),n.appendChild(s);const d=document.createElement("p");d.textContent="Default options (one per line: value:Label)",d.appendChild(Be("Shown before the source field has a value, or when its value has no mapping entry.")),d.style.cssText="font-size:.73rem;color:var(--dm-text-muted);margin:.3rem 0 .2rem;";const u=document.createElement("textarea");return u.className="form-input fb-logic-cascade-defaults",u.rows=3,u.style.cssText="font-family:monospace;",u.placeholder=`option1:Option 1
|
|
4
4
|
option2:Option 2`,u.value=(e.defaultOptions||[]).map(b=>{const g=typeof b=="string"?b:b.value??"",m=typeof b=="string"?b:b.label??g;return g===m?g:`${g}:${m}`}).join(`
|
|
5
|
-
`),n.appendChild(d),n.appendChild(u),n}function ln(e,t){const o=e.logic||{},n=C.filter((u,b)=>b!==t&&u.type!=="page-break"&&u.type!=="spacer"),l=document.createElement("div");l.className="fb-field-logic",l.style.cssText="margin-top:.75rem;border-top:1px solid var(--dm-border);padding-top:.5rem;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const i=document.createElement("span");i.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted);",i.textContent="\u26A1 Conditional Logic";const r=ut(o),c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",q(c,r?"chevron-down":"chevron-right",12);const s=document.createElement("div");s.className="fb-logic-body",s.style.cssText="padding:.25rem 0 .25rem;"+(r?"":"display:none;"),a.addEventListener("click",()=>{const u=s.style.display==="none";s.style.display=u?"":"none",q(c,u?"chevron-down":"chevron-right",12)}),a.appendChild(i),a.appendChild(c),l.appendChild(a),s.appendChild(Zt(o.visibility||{},t,n)),s.appendChild(en(o.requirement||{},t,n)),s.appendChild(tn(o.validation||[],t,n));const d=document.getElementById(`fb-type-${t}`)?.value||e.type;return Be.has(d)&&s.appendChild(nn(o.cascade||{},t,n)),l.appendChild(s),l}const pe=[{value:"banner",label:"Show a banner",kind:"state",params:["message","level","position","dismissible"],placeholder:"e.g. You must be 18 or over to continue."},{value:"toast",label:"Show a toast",kind:"event",params:["message","level"],placeholder:"e.g. Thanks - carry on."},{value:"hide-fields",label:"Hide fields",kind:"state",params:["target"]},{value:"disable-fields",label:"Disable fields",kind:"state",params:["target"]},{value:"require-fields",label:"Make fields required",kind:"state",params:["target"]},{value:"block-submit",label:"Block submission",kind:"state",params:["message"],messageLabel:"Reason, shown under the button",placeholder:'Blank: "This form cannot be submitted yet."'},{value:"end-form",label:"End the form here",kind:"state",params:["message","finish","finishLabel","doneMessage","record"],messageLabel:"Message shown in place of the rest",placeholder:"e.g. Sorry - you must be 18 or over to apply."},{value:"goto-step",label:"Jump to a wizard step",kind:"event",params:["step"]},{value:"redirect",label:"Redirect after submit",kind:"event",params:["url"]},{value:"celebrate",label:"Celebrate",kind:"event",params:["theme","intensity"]},{value:"run-action",label:"Run a CMS action",kind:"event",params:["slug"]},{value:"notify",label:"Notify the admins",kind:"event",params:["message","level"],messageLabel:"Notification title",placeholder:"Blank: titled after the form",noOnce:!0,kindText:"when the form is submitted"}],we=[{value:"info",label:"Info"},{value:"success",label:"Success"},{value:"warning",label:"Warning"},{value:"error",label:"Error"}],ht=[{value:"field-below",label:"Below this field"},{value:"field-above",label:"Above this field"},{value:"form-top",label:"Top of the form"}],bt=[{value:"rest",label:"The rest of the form"},{value:"all",label:"Every other field"},{value:"listed",label:"Chosen fields"}],gt=[{value:"auto",label:"Whatever is in season"},{value:"christmas",label:"Christmas"},{value:"halloween",label:"Halloween"},{value:"valentines",label:"Valentine's Day"},{value:"guy-fawkes",label:"Guy Fawkes Night"},{value:"st-patricks",label:"St Patrick's Day"},{value:"st-andrews",label:"St Andrew's Day"},{value:"st-davids",label:"St David's Day"},{value:"st-georges",label:"St George's Day"}];function yt(e,t=!1){const o=(i,r)=>({value:i.name,label:`${i.label||i.name}${r?" (this field)":""}`,multi:ze(i)}),n=i=>i&&i.type!=="page-break"&&i.type!=="spacer"&&i.name,l=C.filter((i,r)=>r!==e&&n(i)).map(i=>o(i,!1)),a=C[e];return t&&n(a)?[o(a,!0),...l]:l}function K(e,t,o){const n=document.createElement("select");return n.className=`form-select ${e}`,t.forEach(l=>{const a=document.createElement("option");a.value=l.value,a.textContent=l.label,l.value===o&&(a.selected=!0),n.appendChild(a)}),n}function oe(e,t,o){const n=document.createElement("input");return n.type="text",n.className=`form-input ${e}`,n.value=t==null?"":String(t),o&&(n.placeholder=o),n}function Pe(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-remove",t&&(o.title=t,o.setAttribute("aria-label",t)),q(o,"x"),o.addEventListener("click",n=>{n.stopPropagation(),e()}),o}function G(e,t,{full:o=!1,hint:n=""}={}){const l=document.createElement("label");l.className=`fb-trig-f${o?" fb-trig-f--full":""}`;const a=document.createElement("span");if(a.className="fb-trig-f-label",a.textContent=e,l.appendChild(a),l.appendChild(t),n){const i=document.createElement("span");i.className="fb-trig-f-hint",i.textContent=n,l.appendChild(i)}return l}function ue(e,t,o,n){const l=document.createElement("label");l.className="fb-trig-check",n&&(l.title=n);const a=document.createElement("input");return a.type="checkbox",a.className=`form-check ${e}`,a.checked=!!t,l.appendChild(a),l.appendChild(document.createTextNode(o)),l}function vt(e,t){const o=document.createElement("div");o.className="fb-trig-cond-row";const n=K("fb-trig-cond-field",t,e?.field),l=K("fb-trig-cond-op",xe,e?.operator),a=oe("fb-trig-cond-val",e?.value,"value"),i=()=>{const c=t.find(s=>s.value===n.value);Array.from(l.options).forEach(s=>{const d=xe.find(u=>u.value===s.value);s.textContent=c?.multi&&mt[s.value]||d?.label||s.value})},r=()=>{a.hidden=De.has(l.value)};return i(),r(),n.addEventListener("change",i),l.addEventListener("change",r),o.appendChild(n),o.appendChild(l),o.appendChild(a),o.appendChild(Pe(()=>o.remove(),"Remove condition")),o}function xt(e,t){const o=document.createElement("div");o.className="fb-trig-params";const n=pe.find(c=>c.value===(e.type||"banner"));if(!n)return o;const l=document.createElement("div");l.className="fb-trig-grid";const a=document.createElement("div");a.className="fb-trig-opts";const i=[];for(const c of n.params)switch(c){case"message":l.appendChild(G(n.messageLabel||"Message",oe("fb-trig-p-message",e.message,n.placeholder||""),{full:!0}));break;case"finish":a.appendChild(ue("fb-trig-p-finish-on",e.finish!==!1,"Let the visitor finish (send the answers given so far)",'Untick to stop the form dead: the submit button is disabled and nothing is sent, so nothing is saved and "Notify the admins" cannot fire.'));break;case"finishLabel":{const s=G("Button text",oe("fb-trig-p-finish",e.finishLabel,"Finish"));i.push(s),l.appendChild(s);break}case"doneMessage":{const s=G("Closing message",oe("fb-trig-p-done",e.doneMessage,"Blank: the form's own success message"));i.push(s),l.appendChild(s);break}case"record":{const s=ue("fb-trig-p-record",e.record!==!1,"Save the answers given so far",`Untick to keep nothing: no submission is stored and the form's email, webhook and actions do not run. A "Notify the admins" action still fires.`);i.push(s),a.appendChild(s);break}case"level":l.appendChild(G(n.value==="notify"?"Severity":"Level",K("fb-trig-p-level",we,e.level||"info")));break;case"position":l.appendChild(G("Where",K("fb-trig-p-position",ht,e.position||"field-below")));break;case"dismissible":a.appendChild(ue("fb-trig-p-dismissible",e.dismissible!==!1,"The visitor can dismiss it"));break;case"target":{const s=K("fb-trig-p-target",bt,e.target||(e.fields?.length?"listed":"rest")),d=document.createElement("select");d.className="form-select fb-trig-p-fields",d.multiple=!0,d.size=4;const u=new Set(e.fields||[]);yt(t).forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,u.has(m.value)&&(h.selected=!0),d.appendChild(h)});const b=G("Fields",d,{hint:"Ctrl/Cmd-click to pick several"}),g=()=>{b.hidden=s.value!=="listed"};g(),s.addEventListener("change",g),l.appendChild(G("Which fields",s)),l.appendChild(b);break}case"step":{const s=oe("fb-trig-p-step",e.step,"0");s.type="number",s.min="0",l.appendChild(G("Step",s,{hint:"Counting from 0"}));break}case"url":l.appendChild(G("Send them to",oe("fb-trig-p-url",e.url,"/thank-you"),{full:!0}));break;case"theme":l.appendChild(G("Theme",K("fb-trig-p-theme",gt,e.theme||"auto")));break;case"intensity":l.appendChild(G("Intensity",K("fb-trig-p-intensity",[{value:"low",label:"Low"},{value:"medium",label:"Medium"},{value:"high",label:"High"}],e.intensity||"medium")));break;case"slug":{const s=[{value:"",label:be.length?"Choose an action":"No actions available"}].concat(be.map(d=>({value:d.slug,label:d.title||d.slug})));l.appendChild(G("Action",K("fb-trig-p-slug",s,e.slug||""),{full:!0}));break}default:break}n.kind==="event"&&!n.noOnce&&a.appendChild(ue("fb-trig-p-once",!!e.once,"Only once","Fire the first time only, rather than every time the answer swings back."));const r=a.querySelector(".fb-trig-p-finish-on");if(r){const c=()=>i.forEach(s=>{s.hidden=!r.checked});c(),r.addEventListener("change",c)}return l.children.length&&o.appendChild(l),a.children.length&&o.appendChild(a),o}function an(e){return e?.kindText?e.kindText:e?.kind==="event"?"once, when it becomes true":"while it is true"}const on=(e,t=48)=>e.length>t?`${e.slice(0,t-1)}\u2026`:e,ie=(e,t)=>e.find(o=>o.value===t)?.label||t;function sn(e){if(!e)return"";const t=[],o=l=>l?`"${on(l)}"`:"",n=()=>e.target==="listed"?e.fields?.length?e.fields.join(", "):"no fields chosen":ie(bt,e.target||"rest").toLowerCase();switch(e.type){case"banner":t.push(o(e.message)||"No message yet",ie(we,e.level||"info"),ie(ht,e.position||"field-below").toLowerCase());break;case"toast":t.push(o(e.message)||"No message yet",ie(we,e.level||"info"));break;case"hide-fields":case"disable-fields":case"require-fields":t.push(n());break;case"block-submit":t.push(o(e.message)||"the standard reason");break;case"end-form":t.push(o(e.message)||"no message"),e.finish===!1?t.push("submit disabled"):t.push(`button "${e.finishLabel||"Finish"}"`,e.record===!1?"saves nothing":"saves the answers");break;case"goto-step":t.push(Number.isFinite(e.step)?`step ${e.step}`:"no step yet");break;case"redirect":t.push(e.url||"no address yet");break;case"celebrate":t.push(ie(gt,e.theme||"auto"),`${e.intensity||"medium"} intensity`);break;case"run-action":t.push(e.slug?be.find(l=>l.slug===e.slug)?.title||e.slug:"no action chosen");break;case"notify":t.push(o(e.message)||"titled after the form",ie(we,e.level||"info"));break;default:break}return e.once&&t.push("only once"),t.filter(Boolean).join(" \xB7 ")}function _e(e,t,{open:o=!1}={}){const n=document.createElement("div");n.className="fb-trig-action-row";const l=document.createElement("div");l.className="fb-trig-action-head",l.tabIndex=0,l.setAttribute("role","button");const a=document.createElement("span");a.className="fb-trig-chevron";const i=document.createElement("span");i.className="fb-trig-action-main";const r=document.createElement("strong"),c=document.createElement("small");c.className="fb-trig-action-summary",i.append(r,c);const s=document.createElement("span");s.className="fb-trig-kind",l.append(a,i,s,Pe(()=>n.remove(),"Remove action"));const d=document.createElement("div");d.className="fb-trig-action-body";const u=K("fb-trig-action-type",pe,e.type||"banner");d.appendChild(G("Action",u,{full:!0})),d.appendChild(xt(e,t));const b=()=>{const m=pe.find(h=>h.value===u.value);r.textContent=m?.label||u.value,s.textContent=an(m),s.classList.toggle("fb-trig-kind--event",m?.kind==="event"),c.textContent=sn(kt(n))},g=m=>{d.hidden=!m,n.classList.toggle("is-open",m),l.setAttribute("aria-expanded",String(m)),q(a,m?"chevron-down":"chevron-right",12)};return l.addEventListener("click",()=>g(d.hidden)),l.addEventListener("keydown",m=>{m.target!==l||m.key!=="Enter"&&m.key!==" "||(m.preventDefault(),g(d.hidden))}),u.addEventListener("change",()=>{const m=xt({type:u.value},t);d.replaceChild(m,d.querySelector(".fb-trig-params")),b(),window.I?.scan?.()}),d.addEventListener("input",b),d.addEventListener("change",b),n.append(l,d),g(o),b(),n}function Ct(e,t,o){const n=document.createElement("section");n.className=`fb-trig-sec fb-trig-sec--${e}`;const l=document.createElement("div");l.className="fb-trig-sec-head";const a=document.createElement("span");if(a.className="fb-trig-sec-title",a.textContent=t,l.appendChild(a),o){const i=document.createElement("span");i.className="fb-trig-sec-hint",i.textContent=o,l.appendChild(i)}return n.appendChild(l),n}function je(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-add",ce(o,"plus",e,12),o.addEventListener("click",t),o}function Et(e,t,o,n){const a=Ct(e,t,e==="then"?"What happens while the answers match.":"What happens while they do not. Leave empty for nothing.");a.classList.add("fb-trig-branch"),a.dataset.branch=e;const i=document.createElement("div");return i.className="fb-trig-action-list",(o||[]).forEach(r=>i.appendChild(_e(r,n))),a.appendChild(i),a.appendChild(je("Add action",()=>{i.appendChild(_e({type:"banner"},n,{open:!0})),window.I?.scan?.()})),a}function wt(e,t,o){const n=yt(t,!0),l=document.createElement("div");l.className="fb-trig-card",l.dataset.triggerId=e.id||`trg-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;const a=document.createElement("div");a.className="fb-trig-card-head";const i=document.createElement("span");i.className="fb-trig-card-title",i.textContent=`Trigger ${o+1}`,a.appendChild(i);const r=ue("fb-trig-enabled",e.enabled!==!1,"Enabled","Untick to keep the trigger but switch it off.");if(a.appendChild(r),a.appendChild(Pe(()=>l.remove(),"Remove trigger")),l.appendChild(a),!n.length){const u=document.createElement("p");return u.className="fb-trig-empty",u.textContent="Give this field a name first - a trigger tests an answer, and it needs something to test.",l.appendChild(u),l}const c=Ct("when","When");c.querySelector(".fb-trig-sec-head").appendChild(K("fb-trig-match",[{value:"all",label:"all of these are true"},{value:"any",label:"any of these is true"}],Array.isArray(e.when?.any)?"any":"all"));const s=document.createElement("div");s.className="fb-trig-cond-list";const d=e.when?.all||e.when?.any||[];return(d.length?d:[{}]).forEach(u=>s.appendChild(vt(u,n))),c.appendChild(s),c.appendChild(je("Add condition",()=>{s.appendChild(vt({},n)),window.I?.scan?.()})),l.appendChild(c),l.appendChild(Et("then","Then",e.then,t)),l.appendChild(Et("otherwise","Otherwise",e.otherwise,t)),l}function rn(e,t){const o=Array.isArray(e.triggers)?e.triggers:[],n=document.createElement("div");n.className="fb-field-triggers";const l=document.createElement("div");l.className="fb-trig-panel-head";const a=document.createElement("span");a.className="fb-trig-panel-title",a.textContent=`\u{1F3AF} Triggers${o.length?` (${o.length})`:""}`;const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",q(i,o.length?"chevron-down":"chevron-right",12);const r=document.createElement("div");r.className="fb-triggers-body",r.hidden=!o.length,l.addEventListener("click",()=>{r.hidden=!r.hidden,q(i,r.hidden?"chevron-right":"chevron-down",12)});const c=document.createElement("p");c.className="fb-trig-blurb",c.textContent="Do something to the form when the answers meet a condition - show a banner or toast, hide, disable or require other fields, refuse the submit, end the form early, notify the admins, jump to a step, or celebrate.",r.appendChild(c);const s=document.createElement("div");return s.className="fb-trig-list",o.forEach((d,u)=>s.appendChild(wt(d,t,u))),r.appendChild(s),r.appendChild(je("Add trigger",()=>{const d=wt({enabled:!0,then:[]},t,s.children.length);s.appendChild(d),d.querySelector('.fb-trig-branch[data-branch="then"] .fb-trig-action-list')?.appendChild(_e({type:"banner"},t,{open:!0})),window.I?.scan?.()})),l.appendChild(a),l.appendChild(i),n.appendChild(l),n.appendChild(r),n}function kt(e){const t=e.querySelector(".fb-trig-action-type")?.value,o=pe.find(a=>a.value===t);if(!o)return null;const n={type:t},l=a=>e.querySelector(a)?.value?.trim()||"";for(const a of o.params)switch(a){case"message":n.message=l(".fb-trig-p-message");break;case"finishLabel":{const i=l(".fb-trig-p-finish");i&&(n.finishLabel=i);break}case"doneMessage":{const i=l(".fb-trig-p-done");i&&(n.doneMessage=i);break}case"finish":e.querySelector(".fb-trig-p-finish-on")?.checked||(n.finish=!1);break;case"record":e.querySelector(".fb-trig-p-record")?.checked||(n.record=!1);break;case"level":n.level=l(".fb-trig-p-level")||"info";break;case"position":n.position=l(".fb-trig-p-position")||"field-below";break;case"dismissible":n.dismissible=!!e.querySelector(".fb-trig-p-dismissible")?.checked;break;case"target":{const i=l(".fb-trig-p-target")||"rest";n.target=i,i==="listed"&&(n.fields=Array.from(e.querySelectorAll(".fb-trig-p-fields option")).filter(r=>r.selected).map(r=>r.value));break}case"step":{const i=parseInt(l(".fb-trig-p-step"),10);Number.isFinite(i)&&(n.step=i);break}case"url":n.url=l(".fb-trig-p-url");break;case"theme":n.theme=l(".fb-trig-p-theme")||"auto";break;case"intensity":n.intensity=l(".fb-trig-p-intensity")||"medium";break;case"slug":n.slug=l(".fb-trig-p-slug");break;default:break}return o.kind==="event"&&!o.noOnce&&e.querySelector(".fb-trig-p-once")?.checked&&(n.once=!0),n}function cn(e){const t=kt(e);if(!t)return null;const o=pe.find(a=>a.value===t.type),n=t.type,l=["block-submit","end-form","notify"].includes(o.value);return o.params.includes("message")&&!t.message&&!l?(delete t.message,null):(l&&!t.message&&delete t.message,n==="redirect"&&!t.url||n==="run-action"&&!t.slug?null:t)}function dn(e){const o=document.querySelector(`.fb-field-card[data-index="${e}"]`)?.querySelector(".fb-field-triggers");if(!o)return;const n=[];return o.querySelectorAll(".fb-trig-card").forEach(l=>{const a=Array.from(l.querySelectorAll(".fb-trig-cond-row")).map(u=>{const b=u.querySelector(".fb-trig-cond-field")?.value,g=u.querySelector(".fb-trig-cond-op")?.value;if(!b||!g)return null;const m=u.querySelector(".fb-trig-cond-val")?.value??"";return{field:b,operator:g,value:m}}).filter(Boolean);if(!a.length)return;const i=u=>Array.from(l.querySelectorAll(`.fb-trig-branch[data-branch="${u}"] .fb-trig-action-row`)).map(cn).filter(Boolean),r=i("then"),c=i("otherwise");if(!r.length&&!c.length)return;const s=l.querySelector(".fb-trig-match")?.value==="any"?"any":"all",d={id:l.dataset.triggerId,enabled:!!l.querySelector(".fb-trig-enabled")?.checked,when:{[s]:a}};r.length&&(d.then=r),c.length&&(d.otherwise=c),n.push(d)}),n.length?n:void 0}function St(e,t,o){const n=document.createElement("div");return n.className="fb-field-extras",e==="chooser"?(n.appendChild(pn(t,o)),n.appendChild(mn(t.options||[],o))):(Be.has(e)&&n.appendChild(yn(t.options||[],o)),e==="textarea"&&n.appendChild(z([P("Rows",`fb-rows-${o}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(z([P("Min Length",`fb-minlength-${o}`,"number",t.minLength||"",""),P("Max Length",`fb-maxlength-${o}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(z([P("Min",`fb-min-${o}`,"number",t.min??"",""),P("Max",`fb-max-${o}`,"number",t.max??"","")]))),n.children.length?n:null}function Tt(e){const t=document.createElement("div");t.className="fb-chooser-section",t.style.cssText="border:1px solid var(--dm-border); border-radius:6px; margin-top:.5rem; overflow:hidden;";const o=document.createElement("div");o.style.cssText="padding:.4rem .6rem; background:color-mix(in srgb, var(--dm-background) 60%, transparent); font-weight:600; font-size:.82rem; border-bottom:1px solid var(--dm-border);",o.textContent=e,t.appendChild(o);const n=document.createElement("div");return n.className="fb-chooser-section-body",n.style.cssText="padding:.55rem .6rem; display:flex; flex-direction:column; gap:.45rem;",t.appendChild(n),{wrap:t,body:n}}function ke(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem";const r=document.createElement("select");if(r.id=e,r.className="form-input",n.forEach(([c,s])=>{const d=document.createElement("option");d.value=c,d.textContent=s,String(c)===String(o)&&(d.selected=!0),r.appendChild(d)}),a.appendChild(i),a.appendChild(r),l){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=l,c.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(c)}return a}function Nt(e,t,o,n){const l=document.createElement("div");l.style.flex="1";const a=document.createElement("label");a.style.cssText="display:inline-flex;align-items:center;gap:.4rem;font-size:.82rem;";const i=document.createElement("input");if(i.id=e,i.type="checkbox",i.checked=!!o,a.appendChild(i),a.appendChild(document.createTextNode(" "+t)),l.appendChild(a),n){const r=document.createElement("p");r.className="form-hint text-muted",r.textContent=n,r.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(r)}return l}function Ve(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem",a.appendChild(i);const r=document.createElement("div");r.style.cssText="display:flex;gap:.4rem;align-items:stretch;";const c=document.createElement("input");c.id=e,c.type="text",c.className="form-input",c.value=o||"",n&&(c.placeholder=n),c.style.flex="1";const s=document.createElement("input");s.type="color",s.title="Pick a colour",s.style.cssText="width:36px;height:auto;padding:0;border:1px solid var(--dm-border);border-radius:4px;cursor:pointer;";const d=String(c.value).match(/^#[0-9a-fA-F]{3,8}$/);if(s.value=d?c.value:"#000000",s.addEventListener("input",()=>{c.value=s.value,c.dispatchEvent(new Event("input",{bubbles:!0}))}),r.appendChild(c),r.appendChild(s),a.appendChild(r),l){const u=document.createElement("p");u.className="form-hint text-muted",u.textContent=l,u.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(u)}return a}function pn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const n=Tt("Layout");n.body.appendChild(z([ke(`fb-chooser-variant-${t}`,"Variant",e.variant||"card",[["card","Card - rich tiles"],["chip","Chip - compact pills"]],"Card supports description and grid columns; chips wrap."),Nt(`fb-chooser-multiple-${t}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),n.body.appendChild(z([ke(`fb-chooser-density-${t}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),P("Columns",`fb-chooser-columns-${t}`,"number",e.columns||3,"Card grid (1-6). Ignored for chips.")])),o.appendChild(n.wrap);const l=Tt("Visual");return l.body.appendChild(z([Ve(`fb-chooser-accent-${t}`,"Accent",e.accent||"","primary / success / #ec4899","Selected highlight colour - semantic name or any CSS colour."),ke(`fb-chooser-accent-style-${t}`,"Accent style",e.accentStyle||"border",[["border","Border (default)"],["solid","Solid"],["glow","Glow"],["overlay","Overlay"],["underline","Underline"]],"Visual treatment of the selected state.")])),l.body.appendChild(z([Nt(`fb-chooser-glow-${t}`,"Glow on selected",!!e.glow,"Soft outer glow."),Ve(`fb-chooser-glow-colour-${t}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),l.body.appendChild(z([ke(`fb-chooser-shadow-${t}`,"Shadow",e.shadow||"none",[["none","None"],["sm","Small"],["md","Medium"],["lg","Large"],["xl","Extra Large"]],"Drop shadow on every option."),Ve(`fb-chooser-shadow-colour-${t}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),o.appendChild(l.wrap),o}function un(e,t,o,n){const l=document.createElement("div");l.className="fb-chooser-option-row",l.dataset.optIdx=String(o),l.style.cssText="border:1px solid var(--dm-border); border-radius:4px; padding:.5rem; background:var(--dm-background-alt); display:flex; flex-direction:column; gap:.35rem;";const a=document.createElement("div");a.style.cssText="display:flex; gap:.4rem; align-items:center;";const i=document.createElement("div");i.style.cssText="display:flex; flex-direction:column; gap:1px;";const r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",r.title="Move up",q(r,"arrow-up"),r.addEventListener("click",I=>{I.preventDefault(),Lt(t,o,-1,n)});const c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",c.title="Move down",q(c,"arrow-down"),c.addEventListener("click",I=>{I.preventDefault(),Lt(t,o,1,n)}),i.appendChild(r),i.appendChild(c),a.appendChild(i);const s=document.createElement("input");s.type="text",s.className="form-input fb-chooser-opt-value",s.placeholder="value",s.value=e.value||"",s.style.flex="1",a.appendChild(s);const d=document.createElement("input");d.type="text",d.className="form-input fb-chooser-opt-label",d.placeholder="label (visible to users)",d.value=e.label||"",d.style.flex="2",a.appendChild(d);const u=document.createElement("button");u.type="button",u.className="btn btn-xs btn-ghost",u.style.cssText="line-height:1;opacity:.6;",u.title="Remove option",q(u,"x"),u.addEventListener("click",I=>{I.preventDefault(),bn(t,o,n)}),a.appendChild(u),l.appendChild(a);const b=document.createElement("div");b.style.cssText="display:flex; gap:.4rem;";const g=zt("icon name (optional)",e.icon||"");g.input.classList.add("fb-chooser-opt-icon"),g.el.style.flex="1",b.appendChild(g.el);const m=document.createElement("input");m.type="text",m.className="form-input fb-chooser-opt-description",m.placeholder="description (card + comfortable only)",m.value=e.description||"",m.style.flex="2",b.appendChild(m),l.appendChild(b);const h=document.createElement("div");h.style.cssText="display:flex; gap:.4rem;";const w=document.createElement("input");w.type="text",w.className="form-input fb-chooser-opt-tooltip",w.placeholder="tooltip (hover hint)",w.value=e.tooltip||"",w.style.flex="2",h.appendChild(w);const f=document.createElement("input");f.type="text",f.className="form-input fb-chooser-opt-badge-text",f.placeholder="badge text",f.value=e.badge?.text||"",f.style.flex="1",h.appendChild(f);const x=document.createElement("select");x.className="form-input fb-chooser-opt-badge-type",x.style.flex="1",[["","no badge"],["primary","primary"],["success","success"],["info","info"],["warning","warning"],["danger","danger"]].forEach(([I,X])=>{const U=document.createElement("option");U.value=I,U.textContent=X,(e.badge?.type||"")===I&&(U.selected=!0),x.appendChild(U)}),h.appendChild(x),l.appendChild(h);const $=document.createElement("div");$.style.cssText="display:flex; gap:1rem; font-size:.8rem;";const A=document.createElement("label");A.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const H=document.createElement("input");H.type="checkbox",H.className="fb-chooser-opt-recommended",H.checked=!!e.recommended,A.appendChild(H),A.appendChild(document.createTextNode(" Recommended")),$.appendChild(A);const _=document.createElement("label");_.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const j=document.createElement("input");return j.type="checkbox",j.className="fb-chooser-opt-disabled",j.checked=!!e.disabled,_.appendChild(j),_.appendChild(document.createTextNode(" Disabled")),$.appendChild(_),l.appendChild($),l}function mn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem;";const n=document.createElement("div");n.style.cssText="display:flex; align-items:center; justify-content:space-between; margin-bottom:.4rem;";const l=document.createElement("p");l.textContent="Options",l.style.cssText="font-size:.85rem;font-weight:600;margin:0;",n.appendChild(l);const a=document.createElement("button");a.type="button",a.className="btn btn-xs btn-ghost",ce(a,"plus","Add option"),n.appendChild(a),o.appendChild(n);const i=document.createElement("div");i.className="fb-chooser-options-list",i.id=`fb-chooser-options-${t}`,i.style.cssText="display:flex; flex-direction:column; gap:.4rem;",o.appendChild(i);const r=()=>{i.replaceChildren();const c=fn(t);(c.length?c:e||[]).forEach((d,u)=>{i.appendChild(un(d,t,u,r))})};return a.addEventListener("click",c=>{c.preventDefault(),hn(t,r)}),r(),o}function fn(e){const t=C[e];return!t||!Array.isArray(t.options)?[]:t.options}function Ge(e){return C[e]?(Array.isArray(C[e].options)||(C[e].options=[]),C[e].options):[]}function hn(e,t){Se(e),Ge(e).push({value:"new",label:"New option"}),t()}function bn(e,t,o){Se(e),Ge(e).splice(t,1),o()}function Lt(e,t,o,n){Se(e);const l=Ge(e),a=t+o;if(a<0||a>=l.length)return;const[i]=l.splice(t,1);l.splice(a,0,i),n()}function Se(e){const t=document.getElementById(`fb-chooser-options-${e}`);if(!t)return;const o=t.querySelectorAll(".fb-chooser-option-row"),n=[];o.forEach(l=>{const a={value:l.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:l.querySelector(".fb-chooser-opt-label")?.value.trim()||""},i=l.querySelector(".fb-chooser-opt-icon")?.value.trim();i&&(a.icon=i);const r=l.querySelector(".fb-chooser-opt-description")?.value.trim();r&&(a.description=r);const c=l.querySelector(".fb-chooser-opt-tooltip")?.value.trim();c&&(a.tooltip=c);const s=l.querySelector(".fb-chooser-opt-badge-text")?.value.trim(),d=l.querySelector(".fb-chooser-opt-badge-type")?.value;(s||d)&&(a.badge={},s&&(a.badge.text=s),d&&(a.badge.type=d)),l.querySelector(".fb-chooser-opt-recommended")?.checked&&(a.recommended=!0),l.querySelector(".fb-chooser-opt-disabled")?.checked&&(a.disabled=!0),n.push(a)}),C[e]&&(C[e].options=n)}function z(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.85rem;margin-bottom:.75rem;",e.forEach(o=>{o&&t.appendChild(o)}),t}function P(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=t,i.className="form-label",i.textContent=e,i.style.fontSize=".8rem";const r=document.createElement("input");if(r.id=t,r.type=o||"text",r.className="form-input",r.value=n??"",a.appendChild(i),a.appendChild(r),l){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=l,c.style.cssText="font-size:.73rem;margin-top:.35rem;",a.appendChild(c)}return a}function gn(e,t,o,n){const l=document.createElement("div");l.style.flex="1";const a=document.createElement("label");a.htmlFor=t,a.className="form-label",a.textContent=e,a.style.fontSize=".8rem";const i=document.createElement("select");return i.id=t,i.className="form-select",o.forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===n&&(c.selected=!0),i.appendChild(c)}),l.appendChild(a),l.appendChild(i),l}function qt(e,t,o){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const l=document.createElement("label");l.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const a=document.createElement("input");return a.id=t,a.type="checkbox",a.checked=o,l.appendChild(a),l.appendChild(document.createTextNode(e)),n.appendChild(l),n}function yn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.4rem;";const n=document.createElement("p");n.textContent="Options (one per line: value or value:Label)",n.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const l=document.createElement("textarea");return l.id=`fb-options-${t}`,l.className="form-input",l.rows=4,l.placeholder=`yes:Yes
|
|
5
|
+
`),n.appendChild(d),n.appendChild(u),n}function ln(e,t){const o=e.logic||{},n=C.filter((u,b)=>b!==t&&u.type!=="page-break"&&u.type!=="spacer"),l=document.createElement("div");l.className="fb-field-logic",l.style.cssText="margin-top:.75rem;border-top:1px solid var(--dm-border);padding-top:.5rem;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const i=document.createElement("span");i.style.cssText="font-size:.8rem;font-weight:600;color:var(--dm-text-muted);",i.textContent="\u26A1 Conditional Logic";const r=pt(o),c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",q(c,r?"chevron-down":"chevron-right",12);const s=document.createElement("div");s.className="fb-logic-body",s.style.cssText="padding:.25rem 0 .25rem;"+(r?"":"display:none;"),a.addEventListener("click",()=>{const u=s.style.display==="none";s.style.display=u?"":"none",q(c,u?"chevron-down":"chevron-right",12)}),a.appendChild(i),a.appendChild(c),l.appendChild(a),s.appendChild(Zt(o.visibility||{},t,n)),s.appendChild(en(o.requirement||{},t,n)),s.appendChild(tn(o.validation||[],t,n));const d=document.getElementById(`fb-type-${t}`)?.value||e.type;return Ie.has(d)&&s.appendChild(nn(o.cascade||{},t,n)),l.appendChild(s),l}const de=[{value:"banner",label:"Show a banner",kind:"state",params:["message","level","position","dismissible"],placeholder:"e.g. You must be 18 or over to continue."},{value:"toast",label:"Show a toast",kind:"event",params:["message","level"],placeholder:"e.g. Thanks - carry on."},{value:"hide-fields",label:"Hide fields",kind:"state",params:["target"]},{value:"disable-fields",label:"Disable fields",kind:"state",params:["target"]},{value:"require-fields",label:"Make fields required",kind:"state",params:["target"]},{value:"block-submit",label:"Block submission",kind:"state",params:["message"],messageLabel:"Reason, shown under the button",placeholder:'Blank: "This form cannot be submitted yet."'},{value:"end-form",label:"End the form here",kind:"state",params:["message","finish","finishLabel","doneMessage","record"],messageLabel:"Message shown in place of the rest",placeholder:"e.g. Sorry - you must be 18 or over to apply."},{value:"goto-step",label:"Jump to a wizard step",kind:"event",params:["step"]},{value:"redirect",label:"Redirect after submit",kind:"event",params:["url"]},{value:"celebrate",label:"Celebrate",kind:"event",params:["theme","intensity"]},{value:"run-action",label:"Run a CMS action",kind:"event",params:["slug"]},{value:"notify",label:"Notify the admins",kind:"event",params:["message","level"],messageLabel:"Notification title",placeholder:"Blank: titled after the form",noOnce:!0,kindText:"when the form is submitted"}],Ee=[{value:"info",label:"Info"},{value:"success",label:"Success"},{value:"warning",label:"Warning"},{value:"error",label:"Error"}],ft=[{value:"field-below",label:"Below this field"},{value:"field-above",label:"Above this field"},{value:"form-top",label:"Top of the form"}],ht=[{value:"rest",label:"The rest of the form"},{value:"all",label:"Every other field"},{value:"listed",label:"Chosen fields"}],bt=[{value:"auto",label:"Whatever is in season"},{value:"christmas",label:"Christmas"},{value:"halloween",label:"Halloween"},{value:"valentines",label:"Valentine's Day"},{value:"guy-fawkes",label:"Guy Fawkes Night"},{value:"st-patricks",label:"St Patrick's Day"},{value:"st-andrews",label:"St Andrew's Day"},{value:"st-davids",label:"St David's Day"},{value:"st-georges",label:"St George's Day"}];function gt(e,t=!1){const o=(i,r)=>({value:i.name,label:`${i.label||i.name}${r?" (this field)":""}`,multi:Me(i)}),n=i=>i&&i.type!=="page-break"&&i.type!=="spacer"&&i.name,l=C.filter((i,r)=>r!==e&&n(i)).map(i=>o(i,!1)),a=C[e];return t&&n(a)?[o(a,!0),...l]:l}function Y(e,t,o){const n=document.createElement("select");return n.className=`form-select ${e}`,t.forEach(l=>{const a=document.createElement("option");a.value=l.value,a.textContent=l.label,l.value===o&&(a.selected=!0),n.appendChild(a)}),n}function ae(e,t,o){const n=document.createElement("input");return n.type="text",n.className=`form-input ${e}`,n.value=t==null?"":String(t),o&&(n.placeholder=o),n}function ze(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-remove",t&&(o.title=t,o.setAttribute("aria-label",t)),q(o,"x"),o.addEventListener("click",n=>{n.stopPropagation(),e()}),o}function V(e,t,{full:o=!1,hint:n=""}={}){const l=document.createElement("label");l.className=`fb-trig-f${o?" fb-trig-f--full":""}`;const a=document.createElement("span");if(a.className="fb-trig-f-label",a.textContent=e,l.appendChild(a),l.appendChild(t),n){const i=document.createElement("span");i.className="fb-trig-f-hint",i.textContent=n,l.appendChild(i)}return l}function pe(e,t,o,n){const l=document.createElement("label");l.className="fb-trig-check",n&&(l.title=n);const a=document.createElement("input");return a.type="checkbox",a.className=`form-check ${e}`,a.checked=!!t,l.appendChild(a),l.appendChild(document.createTextNode(o)),l}function yt(e,t){const o=document.createElement("div");o.className="fb-trig-cond-row";const n=Y("fb-trig-cond-field",t,e?.field),l=Y("fb-trig-cond-op",ve,e?.operator),a=ae("fb-trig-cond-val",e?.value,"value"),i=()=>{const c=t.find(s=>s.value===n.value);Array.from(l.options).forEach(s=>{const d=ve.find(u=>u.value===s.value);s.textContent=c?.multi&&ut[s.value]||d?.label||s.value})},r=()=>{a.hidden=De.has(l.value)};return i(),r(),n.addEventListener("change",i),l.addEventListener("change",r),o.appendChild(n),o.appendChild(l),o.appendChild(a),o.appendChild(ze(()=>o.remove(),"Remove condition")),o}function vt(e,t){const o=document.createElement("div");o.className="fb-trig-params";const n=de.find(c=>c.value===(e.type||"banner"));if(!n)return o;const l=document.createElement("div");l.className="fb-trig-grid";const a=document.createElement("div");a.className="fb-trig-opts";const i=[];for(const c of n.params)switch(c){case"message":l.appendChild(V(n.messageLabel||"Message",ae("fb-trig-p-message",e.message,n.placeholder||""),{full:!0}));break;case"finish":a.appendChild(pe("fb-trig-p-finish-on",e.finish!==!1,"Let the visitor finish (send the answers given so far)",'Untick to stop the form dead: the submit button is disabled and nothing is sent, so nothing is saved and "Notify the admins" cannot fire.'));break;case"finishLabel":{const s=V("Button text",ae("fb-trig-p-finish",e.finishLabel,"Finish"));i.push(s),l.appendChild(s);break}case"doneMessage":{const s=V("Closing message",ae("fb-trig-p-done",e.doneMessage,"Blank: the form's own success message"));i.push(s),l.appendChild(s);break}case"record":{const s=pe("fb-trig-p-record",e.record!==!1,"Save the answers given so far",`Untick to keep nothing: no submission is stored and the form's email, webhook and actions do not run. A "Notify the admins" action still fires.`);i.push(s),a.appendChild(s);break}case"level":l.appendChild(V(n.value==="notify"?"Severity":"Level",Y("fb-trig-p-level",Ee,e.level||"info")));break;case"position":l.appendChild(V("Where",Y("fb-trig-p-position",ft,e.position||"field-below")));break;case"dismissible":a.appendChild(pe("fb-trig-p-dismissible",e.dismissible!==!1,"The visitor can dismiss it"));break;case"target":{const s=Y("fb-trig-p-target",ht,e.target||(e.fields?.length?"listed":"rest")),d=document.createElement("select");d.className="form-select fb-trig-p-fields",d.multiple=!0,d.size=4;const u=new Set(e.fields||[]);gt(t).forEach(m=>{const h=document.createElement("option");h.value=m.value,h.textContent=m.label,u.has(m.value)&&(h.selected=!0),d.appendChild(h)});const b=V("Fields",d,{hint:"Ctrl/Cmd-click to pick several"}),g=()=>{b.hidden=s.value!=="listed"};g(),s.addEventListener("change",g),l.appendChild(V("Which fields",s)),l.appendChild(b);break}case"step":{const s=ae("fb-trig-p-step",e.step,"0");s.type="number",s.min="0",l.appendChild(V("Step",s,{hint:"Counting from 0"}));break}case"url":l.appendChild(V("Send them to",ae("fb-trig-p-url",e.url,"/thank-you"),{full:!0}));break;case"theme":l.appendChild(V("Theme",Y("fb-trig-p-theme",bt,e.theme||"auto")));break;case"intensity":l.appendChild(V("Intensity",Y("fb-trig-p-intensity",[{value:"low",label:"Low"},{value:"medium",label:"Medium"},{value:"high",label:"High"}],e.intensity||"medium")));break;case"slug":{const s=[{value:"",label:he.length?"Choose an action":"No actions available"}].concat(he.map(d=>({value:d.slug,label:d.title||d.slug})));l.appendChild(V("Action",Y("fb-trig-p-slug",s,e.slug||""),{full:!0}));break}default:break}n.kind==="event"&&!n.noOnce&&a.appendChild(pe("fb-trig-p-once",!!e.once,"Only once","Fire the first time only, rather than every time the answer swings back."));const r=a.querySelector(".fb-trig-p-finish-on");if(r){const c=()=>i.forEach(s=>{s.hidden=!r.checked});c(),r.addEventListener("change",c)}return l.children.length&&o.appendChild(l),a.children.length&&o.appendChild(a),o}function an(e){return e?.kindText?e.kindText:e?.kind==="event"?"once, when it becomes true":"while it is true"}const on=(e,t=48)=>e.length>t?`${e.slice(0,t-1)}\u2026`:e,oe=(e,t)=>e.find(o=>o.value===t)?.label||t;function sn(e){if(!e)return"";const t=[],o=l=>l?`"${on(l)}"`:"",n=()=>e.target==="listed"?e.fields?.length?e.fields.join(", "):"no fields chosen":oe(ht,e.target||"rest").toLowerCase();switch(e.type){case"banner":t.push(o(e.message)||"No message yet",oe(Ee,e.level||"info"),oe(ft,e.position||"field-below").toLowerCase());break;case"toast":t.push(o(e.message)||"No message yet",oe(Ee,e.level||"info"));break;case"hide-fields":case"disable-fields":case"require-fields":t.push(n());break;case"block-submit":t.push(o(e.message)||"the standard reason");break;case"end-form":t.push(o(e.message)||"no message"),e.finish===!1?t.push("submit disabled"):t.push(`button "${e.finishLabel||"Finish"}"`,e.record===!1?"saves nothing":"saves the answers");break;case"goto-step":t.push(Number.isFinite(e.step)?`step ${e.step}`:"no step yet");break;case"redirect":t.push(e.url||"no address yet");break;case"celebrate":t.push(oe(bt,e.theme||"auto"),`${e.intensity||"medium"} intensity`);break;case"run-action":t.push(e.slug?he.find(l=>l.slug===e.slug)?.title||e.slug:"no action chosen");break;case"notify":t.push(o(e.message)||"titled after the form",oe(Ee,e.level||"info"));break;default:break}return e.once&&t.push("only once"),t.filter(Boolean).join(" \xB7 ")}function Pe(e,t,{open:o=!1}={}){const n=document.createElement("div");n.className="fb-trig-action-row";const l=document.createElement("div");l.className="fb-trig-action-head",l.tabIndex=0,l.setAttribute("role","button");const a=document.createElement("span");a.className="fb-trig-chevron";const i=document.createElement("span");i.className="fb-trig-action-main";const r=document.createElement("strong"),c=document.createElement("small");c.className="fb-trig-action-summary",i.append(r,c);const s=document.createElement("span");s.className="fb-trig-kind",l.append(a,i,s,ze(()=>n.remove(),"Remove action"));const d=document.createElement("div");d.className="fb-trig-action-body";const u=Y("fb-trig-action-type",de,e.type||"banner");d.appendChild(V("Action",u,{full:!0})),d.appendChild(vt(e,t));const b=()=>{const m=de.find(h=>h.value===u.value);r.textContent=m?.label||u.value,s.textContent=an(m),s.classList.toggle("fb-trig-kind--event",m?.kind==="event"),c.textContent=sn(wt(n))},g=m=>{d.hidden=!m,n.classList.toggle("is-open",m),l.setAttribute("aria-expanded",String(m)),q(a,m?"chevron-down":"chevron-right",12)};return l.addEventListener("click",()=>g(d.hidden)),l.addEventListener("keydown",m=>{m.target!==l||m.key!=="Enter"&&m.key!==" "||(m.preventDefault(),g(d.hidden))}),u.addEventListener("change",()=>{const m=vt({type:u.value},t);d.replaceChild(m,d.querySelector(".fb-trig-params")),b(),window.I?.scan?.()}),d.addEventListener("input",b),d.addEventListener("change",b),n.append(l,d),g(o),b(),n}function xt(e,t,o){const n=document.createElement("section");n.className=`fb-trig-sec fb-trig-sec--${e}`;const l=document.createElement("div");l.className="fb-trig-sec-head";const a=document.createElement("span");if(a.className="fb-trig-sec-title",a.textContent=t,l.appendChild(a),o){const i=document.createElement("span");i.className="fb-trig-sec-hint",i.textContent=o,l.appendChild(i)}return n.appendChild(l),n}function _e(e,t){const o=document.createElement("button");return o.type="button",o.className="btn btn-xs btn-ghost fb-trig-add",re(o,"plus",e,12),o.addEventListener("click",t),o}function Ct(e,t,o,n){const a=xt(e,t,e==="then"?"What happens while the answers match.":"What happens while they do not. Leave empty for nothing.");a.classList.add("fb-trig-branch"),a.dataset.branch=e;const i=document.createElement("div");return i.className="fb-trig-action-list",(o||[]).forEach(r=>i.appendChild(Pe(r,n))),a.appendChild(i),a.appendChild(_e("Add action",()=>{i.appendChild(Pe({type:"banner"},n,{open:!0})),window.I?.scan?.()})),a}function Et(e,t,o){const n=gt(t,!0),l=document.createElement("div");l.className="fb-trig-card",l.dataset.triggerId=e.id||`trg-${Date.now()}-${Math.random().toString(36).slice(2,7)}`;const a=document.createElement("div");a.className="fb-trig-card-head";const i=document.createElement("span");i.className="fb-trig-card-title",i.textContent=`Trigger ${o+1}`,a.appendChild(i);const r=pe("fb-trig-enabled",e.enabled!==!1,"Enabled","Untick to keep the trigger but switch it off.");if(a.appendChild(r),a.appendChild(ze(()=>l.remove(),"Remove trigger")),l.appendChild(a),!n.length){const u=document.createElement("p");return u.className="fb-trig-empty",u.textContent="Give this field a name first - a trigger tests an answer, and it needs something to test.",l.appendChild(u),l}const c=xt("when","When");c.querySelector(".fb-trig-sec-head").appendChild(Y("fb-trig-match",[{value:"all",label:"all of these are true"},{value:"any",label:"any of these is true"}],Array.isArray(e.when?.any)?"any":"all"));const s=document.createElement("div");s.className="fb-trig-cond-list";const d=e.when?.all||e.when?.any||[];return(d.length?d:[{}]).forEach(u=>s.appendChild(yt(u,n))),c.appendChild(s),c.appendChild(_e("Add condition",()=>{s.appendChild(yt({},n)),window.I?.scan?.()})),l.appendChild(c),l.appendChild(Ct("then","Then",e.then,t)),l.appendChild(Ct("otherwise","Otherwise",e.otherwise,t)),l}function rn(e,t){const o=Array.isArray(e.triggers)?e.triggers:[],n=document.createElement("div");n.className="fb-field-triggers";const l=document.createElement("div");l.className="fb-trig-panel-head";const a=document.createElement("span");a.className="fb-trig-panel-title",a.textContent=`\u{1F3AF} Triggers${o.length?` (${o.length})`:""}`;const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",q(i,o.length?"chevron-down":"chevron-right",12);const r=document.createElement("div");r.className="fb-triggers-body",r.hidden=!o.length,l.addEventListener("click",()=>{r.hidden=!r.hidden,q(i,r.hidden?"chevron-right":"chevron-down",12)});const c=document.createElement("p");c.className="fb-trig-blurb",c.textContent="Do something to the form when the answers meet a condition - show a banner or toast, hide, disable or require other fields, refuse the submit, end the form early, notify the admins, jump to a step, or celebrate.",r.appendChild(c);const s=document.createElement("div");return s.className="fb-trig-list",o.forEach((d,u)=>s.appendChild(Et(d,t,u))),r.appendChild(s),r.appendChild(_e("Add trigger",()=>{const d=Et({enabled:!0,then:[]},t,s.children.length);s.appendChild(d),d.querySelector('.fb-trig-branch[data-branch="then"] .fb-trig-action-list')?.appendChild(Pe({type:"banner"},t,{open:!0})),window.I?.scan?.()})),l.appendChild(a),l.appendChild(i),n.appendChild(l),n.appendChild(r),n}function wt(e){const t=e.querySelector(".fb-trig-action-type")?.value,o=de.find(a=>a.value===t);if(!o)return null;const n={type:t},l=a=>e.querySelector(a)?.value?.trim()||"";for(const a of o.params)switch(a){case"message":n.message=l(".fb-trig-p-message");break;case"finishLabel":{const i=l(".fb-trig-p-finish");i&&(n.finishLabel=i);break}case"doneMessage":{const i=l(".fb-trig-p-done");i&&(n.doneMessage=i);break}case"finish":e.querySelector(".fb-trig-p-finish-on")?.checked||(n.finish=!1);break;case"record":e.querySelector(".fb-trig-p-record")?.checked||(n.record=!1);break;case"level":n.level=l(".fb-trig-p-level")||"info";break;case"position":n.position=l(".fb-trig-p-position")||"field-below";break;case"dismissible":n.dismissible=!!e.querySelector(".fb-trig-p-dismissible")?.checked;break;case"target":{const i=l(".fb-trig-p-target")||"rest";n.target=i,i==="listed"&&(n.fields=Array.from(e.querySelectorAll(".fb-trig-p-fields option")).filter(r=>r.selected).map(r=>r.value));break}case"step":{const i=parseInt(l(".fb-trig-p-step"),10);Number.isFinite(i)&&(n.step=i);break}case"url":n.url=l(".fb-trig-p-url");break;case"theme":n.theme=l(".fb-trig-p-theme")||"auto";break;case"intensity":n.intensity=l(".fb-trig-p-intensity")||"medium";break;case"slug":n.slug=l(".fb-trig-p-slug");break;default:break}return o.kind==="event"&&!o.noOnce&&e.querySelector(".fb-trig-p-once")?.checked&&(n.once=!0),n}function cn(e){const t=wt(e);if(!t)return null;const o=de.find(a=>a.value===t.type),n=t.type,l=["block-submit","end-form","notify"].includes(o.value);return o.params.includes("message")&&!t.message&&!l?(delete t.message,null):(l&&!t.message&&delete t.message,n==="redirect"&&!t.url||n==="run-action"&&!t.slug?null:t)}function dn(e){const o=document.querySelector(`.fb-field-card[data-index="${e}"]`)?.querySelector(".fb-field-triggers");if(!o)return;const n=[];return o.querySelectorAll(".fb-trig-card").forEach(l=>{const a=Array.from(l.querySelectorAll(".fb-trig-cond-row")).map(u=>{const b=u.querySelector(".fb-trig-cond-field")?.value,g=u.querySelector(".fb-trig-cond-op")?.value;if(!b||!g)return null;const m=u.querySelector(".fb-trig-cond-val")?.value??"";return{field:b,operator:g,value:m}}).filter(Boolean);if(!a.length)return;const i=u=>Array.from(l.querySelectorAll(`.fb-trig-branch[data-branch="${u}"] .fb-trig-action-row`)).map(cn).filter(Boolean),r=i("then"),c=i("otherwise");if(!r.length&&!c.length)return;const s=l.querySelector(".fb-trig-match")?.value==="any"?"any":"all",d={id:l.dataset.triggerId,enabled:!!l.querySelector(".fb-trig-enabled")?.checked,when:{[s]:a}};r.length&&(d.then=r),c.length&&(d.otherwise=c),n.push(d)}),n.length?n:void 0}function kt(e,t,o){const n=document.createElement("div");return n.className="fb-field-extras",e==="chooser"?(n.appendChild(pn(t,o)),n.appendChild(mn(t.options||[],o))):(Ie.has(e)&&n.appendChild(yn(t.options||[],o)),e==="textarea"&&n.appendChild(D([z("Rows",`fb-rows-${o}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(D([z("Min Length",`fb-minlength-${o}`,"number",t.minLength||"",""),z("Max Length",`fb-maxlength-${o}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(D([z("Min",`fb-min-${o}`,"number",t.min??"",""),z("Max",`fb-max-${o}`,"number",t.max??"","")]))),n.children.length?n:null}function St(e){const t=document.createElement("div");t.className="fb-chooser-section",t.style.cssText="border:1px solid var(--dm-border); border-radius:6px; margin-top:.5rem; overflow:hidden;";const o=document.createElement("div");o.style.cssText="padding:.4rem .6rem; background:color-mix(in srgb, var(--dm-background) 60%, transparent); font-weight:600; font-size:.82rem; border-bottom:1px solid var(--dm-border);",o.textContent=e,t.appendChild(o);const n=document.createElement("div");return n.className="fb-chooser-section-body",n.style.cssText="padding:.55rem .6rem; display:flex; flex-direction:column; gap:.45rem;",t.appendChild(n),{wrap:t,body:n}}function we(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem";const r=document.createElement("select");if(r.id=e,r.className="form-input",n.forEach(([c,s])=>{const d=document.createElement("option");d.value=c,d.textContent=s,String(c)===String(o)&&(d.selected=!0),r.appendChild(d)}),a.appendChild(i),a.appendChild(r),l){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=l,c.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(c)}return a}function Tt(e,t,o,n){const l=document.createElement("div");l.style.flex="1";const a=document.createElement("label");a.style.cssText="display:inline-flex;align-items:center;gap:.4rem;font-size:.82rem;";const i=document.createElement("input");if(i.id=e,i.type="checkbox",i.checked=!!o,a.appendChild(i),a.appendChild(document.createTextNode(" "+t)),l.appendChild(a),n){const r=document.createElement("p");r.className="form-hint text-muted",r.textContent=n,r.style.cssText="font-size:.72rem;margin-top:.2rem;",l.appendChild(r)}return l}function je(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=e,i.className="form-label",i.textContent=t,i.style.fontSize=".8rem",a.appendChild(i);const r=document.createElement("div");r.style.cssText="display:flex;gap:.4rem;align-items:stretch;";const c=document.createElement("input");c.id=e,c.type="text",c.className="form-input",c.value=o||"",n&&(c.placeholder=n),c.style.flex="1";const s=document.createElement("input");s.type="color",s.title="Pick a colour",s.style.cssText="width:36px;height:auto;padding:0;border:1px solid var(--dm-border);border-radius:4px;cursor:pointer;";const d=String(c.value).match(/^#[0-9a-fA-F]{3,8}$/);if(s.value=d?c.value:"#000000",s.addEventListener("input",()=>{c.value=s.value,c.dispatchEvent(new Event("input",{bubbles:!0}))}),r.appendChild(c),r.appendChild(s),a.appendChild(r),l){const u=document.createElement("p");u.className="form-hint text-muted",u.textContent=l,u.style.cssText="font-size:.72rem;margin-top:.2rem;",a.appendChild(u)}return a}function pn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem; display:flex; flex-direction:column; gap:.4rem;";const n=St("Layout");n.body.appendChild(D([we(`fb-chooser-variant-${t}`,"Variant",e.variant||"card",[["card","Card - rich tiles"],["chip","Chip - compact pills"]],"Card supports description and grid columns; chips wrap."),Tt(`fb-chooser-multiple-${t}`,"Multi-select",!!e.multiple,"Off = single (radio); on = multi (checkbox).")])),n.body.appendChild(D([we(`fb-chooser-density-${t}`,"Density",e.density||"comfortable",[["comfortable","Comfortable"],["compact","Compact"]],"Compact strips description (card variant only)."),z("Columns",`fb-chooser-columns-${t}`,"number",e.columns||3,"Card grid (1-6). Ignored for chips.")])),o.appendChild(n.wrap);const l=St("Visual");return l.body.appendChild(D([je(`fb-chooser-accent-${t}`,"Accent",e.accent||"","primary / success / #ec4899","Selected highlight colour - semantic name or any CSS colour."),we(`fb-chooser-accent-style-${t}`,"Accent style",e.accentStyle||"border",[["border","Border (default)"],["solid","Solid"],["glow","Glow"],["overlay","Overlay"],["underline","Underline"]],"Visual treatment of the selected state.")])),l.body.appendChild(D([Tt(`fb-chooser-glow-${t}`,"Glow on selected",!!e.glow,"Soft outer glow."),je(`fb-chooser-glow-colour-${t}`,"Glow colour",e.glowColour||"","defaults to accent","Optional; semantic name or CSS colour.")])),l.body.appendChild(D([we(`fb-chooser-shadow-${t}`,"Shadow",e.shadow||"none",[["none","None"],["sm","Small"],["md","Medium"],["lg","Large"],["xl","Extra Large"]],"Drop shadow on every option."),je(`fb-chooser-shadow-colour-${t}`,"Shadow colour",e.shadowColour||"","rgba(0,0,0,0.1)","Optional shadow tint.")])),o.appendChild(l.wrap),o}function un(e,t,o,n){const l=document.createElement("div");l.className="fb-chooser-option-row",l.dataset.optIdx=String(o),l.style.cssText="border:1px solid var(--dm-border); border-radius:4px; padding:.5rem; background:var(--dm-background-alt); display:flex; flex-direction:column; gap:.35rem;";const a=document.createElement("div");a.style.cssText="display:flex; gap:.4rem; align-items:center;";const i=document.createElement("div");i.style.cssText="display:flex; flex-direction:column; gap:1px;";const r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",r.title="Move up",q(r,"arrow-up"),r.addEventListener("click",I=>{I.preventDefault(),Nt(t,o,-1,n)});const c=document.createElement("button");c.type="button",c.className="btn btn-xs btn-ghost",c.title="Move down",q(c,"arrow-down"),c.addEventListener("click",I=>{I.preventDefault(),Nt(t,o,1,n)}),i.appendChild(r),i.appendChild(c),a.appendChild(i);const s=document.createElement("input");s.type="text",s.className="form-input fb-chooser-opt-value",s.placeholder="value",s.value=e.value||"",s.style.flex="1",a.appendChild(s);const d=document.createElement("input");d.type="text",d.className="form-input fb-chooser-opt-label",d.placeholder="label (visible to users)",d.value=e.label||"",d.style.flex="2",a.appendChild(d);const u=document.createElement("button");u.type="button",u.className="btn btn-xs btn-ghost",u.style.cssText="line-height:1;opacity:.6;",u.title="Remove option",q(u,"x"),u.addEventListener("click",I=>{I.preventDefault(),bn(t,o,n)}),a.appendChild(u),l.appendChild(a);const b=document.createElement("div");b.style.cssText="display:flex; gap:.4rem;";const g=Mt("icon name (optional)",e.icon||"");g.input.classList.add("fb-chooser-opt-icon"),g.el.style.flex="1",b.appendChild(g.el);const m=document.createElement("input");m.type="text",m.className="form-input fb-chooser-opt-description",m.placeholder="description (card + comfortable only)",m.value=e.description||"",m.style.flex="2",b.appendChild(m),l.appendChild(b);const h=document.createElement("div");h.style.cssText="display:flex; gap:.4rem;";const w=document.createElement("input");w.type="text",w.className="form-input fb-chooser-opt-tooltip",w.placeholder="tooltip (hover hint)",w.value=e.tooltip||"",w.style.flex="2",h.appendChild(w);const f=document.createElement("input");f.type="text",f.className="form-input fb-chooser-opt-badge-text",f.placeholder="badge text",f.value=e.badge?.text||"",f.style.flex="1",h.appendChild(f);const x=document.createElement("select");x.className="form-input fb-chooser-opt-badge-type",x.style.flex="1",[["","no badge"],["primary","primary"],["success","success"],["info","info"],["warning","warning"],["danger","danger"]].forEach(([I,Q])=>{const H=document.createElement("option");H.value=I,H.textContent=Q,(e.badge?.type||"")===I&&(H.selected=!0),x.appendChild(H)}),h.appendChild(x),l.appendChild(h);const $=document.createElement("div");$.style.cssText="display:flex; gap:1rem; font-size:.8rem;";const A=document.createElement("label");A.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const G=document.createElement("input");G.type="checkbox",G.className="fb-chooser-opt-recommended",G.checked=!!e.recommended,A.appendChild(G),A.appendChild(document.createTextNode(" Recommended")),$.appendChild(A);const P=document.createElement("label");P.style.cssText="display:inline-flex;align-items:center;gap:.3rem;";const _=document.createElement("input");return _.type="checkbox",_.className="fb-chooser-opt-disabled",_.checked=!!e.disabled,P.appendChild(_),P.appendChild(document.createTextNode(" Disabled")),$.appendChild(P),l.appendChild($),l}function mn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.5rem;";const n=document.createElement("div");n.style.cssText="display:flex; align-items:center; justify-content:space-between; margin-bottom:.4rem;";const l=document.createElement("p");l.textContent="Options",l.style.cssText="font-size:.85rem;font-weight:600;margin:0;",n.appendChild(l);const a=document.createElement("button");a.type="button",a.className="btn btn-xs btn-ghost",re(a,"plus","Add option"),n.appendChild(a),o.appendChild(n);const i=document.createElement("div");i.className="fb-chooser-options-list",i.id=`fb-chooser-options-${t}`,i.style.cssText="display:flex; flex-direction:column; gap:.4rem;",o.appendChild(i);const r=()=>{i.replaceChildren();const c=fn(t);(c.length?c:e||[]).forEach((d,u)=>{i.appendChild(un(d,t,u,r))})};return a.addEventListener("click",c=>{c.preventDefault(),hn(t,r)}),r(),o}function fn(e){const t=C[e];return!t||!Array.isArray(t.options)?[]:t.options}function Ve(e){return C[e]?(Array.isArray(C[e].options)||(C[e].options=[]),C[e].options):[]}function hn(e,t){ke(e),Ve(e).push({value:"new",label:"New option"}),t()}function bn(e,t,o){ke(e),Ve(e).splice(t,1),o()}function Nt(e,t,o,n){ke(e);const l=Ve(e),a=t+o;if(a<0||a>=l.length)return;const[i]=l.splice(t,1);l.splice(a,0,i),n()}function ke(e){const t=document.getElementById(`fb-chooser-options-${e}`);if(!t)return;const o=t.querySelectorAll(".fb-chooser-option-row"),n=[];o.forEach(l=>{const a={value:l.querySelector(".fb-chooser-opt-value")?.value.trim()||"",label:l.querySelector(".fb-chooser-opt-label")?.value.trim()||""},i=l.querySelector(".fb-chooser-opt-icon")?.value.trim();i&&(a.icon=i);const r=l.querySelector(".fb-chooser-opt-description")?.value.trim();r&&(a.description=r);const c=l.querySelector(".fb-chooser-opt-tooltip")?.value.trim();c&&(a.tooltip=c);const s=l.querySelector(".fb-chooser-opt-badge-text")?.value.trim(),d=l.querySelector(".fb-chooser-opt-badge-type")?.value;(s||d)&&(a.badge={},s&&(a.badge.text=s),d&&(a.badge.type=d)),l.querySelector(".fb-chooser-opt-recommended")?.checked&&(a.recommended=!0),l.querySelector(".fb-chooser-opt-disabled")?.checked&&(a.disabled=!0),n.push(a)}),C[e]&&(C[e].options=n)}function D(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.85rem;margin-bottom:.75rem;",e.forEach(o=>{o&&t.appendChild(o)}),t}function z(e,t,o,n,l){const a=document.createElement("div");a.style.flex="1";const i=document.createElement("label");i.htmlFor=t,i.className="form-label",i.textContent=e,i.style.fontSize=".8rem";const r=document.createElement("input");if(r.id=t,r.type=o||"text",r.className="form-input",r.value=n??"",a.appendChild(i),a.appendChild(r),l){const c=document.createElement("p");c.className="form-hint text-muted",c.textContent=l,c.style.cssText="font-size:.73rem;margin-top:.35rem;",a.appendChild(c)}return a}function gn(e,t,o,n){const l=document.createElement("div");l.style.flex="1";const a=document.createElement("label");a.htmlFor=t,a.className="form-label",a.textContent=e,a.style.fontSize=".8rem";const i=document.createElement("select");return i.id=t,i.className="form-select",o.forEach(r=>{const c=document.createElement("option");c.value=r.value,c.textContent=r.label,r.value===n&&(c.selected=!0),i.appendChild(c)}),l.appendChild(a),l.appendChild(i),l}function Lt(e,t,o){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const l=document.createElement("label");l.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const a=document.createElement("input");return a.id=t,a.type="checkbox",a.checked=o,l.appendChild(a),l.appendChild(document.createTextNode(e)),n.appendChild(l),n}function yn(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.4rem;";const n=document.createElement("p");n.textContent="Options (one per line: value or value:Label)",n.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const l=document.createElement("textarea");return l.id=`fb-options-${t}`,l.className="form-input",l.rows=4,l.placeholder=`yes:Yes
|
|
6
6
|
no:No
|
|
7
7
|
maybe:Maybe`,l.value=(e||[]).map(a=>{const i=typeof a=="string"?a:a.value??"",r=typeof a=="string"?a:a.label??i;return i===r?i:`${i}:${r}`}).join(`
|
|
8
|
-
`),l.style.fontFamily="monospace",o.appendChild(n),o.appendChild(l),o}function Te(e){return parseInt(e,10)===3?3:2}function Ne(e){const t=e.find("#field-project").val()||"";return O(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},meta:{...ye||{},project:t||null},fields:C,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"grid",columns:Te(e.find("#setting-columns").val()),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()},...ge!==null&&{collection:ge}}}}function $t(e,t){const o={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const l={...n.formConfig||{}};l.span==="full"&&t&&(l.span=t);const a=n.type==="chooser"||!!(n.variant&&["select","radio","checkbox-group"].includes(n.type)),r={type:n.type==="checkbox"?"boolean":n.type==="date"||n.type==="icon"||n.type==="image"?"string":a?"chooser":n.type,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{helperText:n.helper},...n.tooltip&&{tooltip:n.tooltip},...l}};a&&(n.variant&&(r.variant=n.variant),(n.multiple||n.type==="checkbox-group")&&(r.multiple=!0),n.density&&(r.density=n.density),n.columns&&(r.columns=n.columns),n.accent&&(r.accent=n.accent),n.accentStyle&&(r.accentStyle=n.accentStyle),n.glow&&(r.glow=!0),n.glowColour&&(r.glowColour=n.glowColour),n.shadow&&(r.shadow=n.shadow),n.shadowColour&&(r.shadowColour=n.shadowColour)),o[n.name]=r}),o}function At(e,t){const o=typeof e=="string"?document.querySelector(e):e;o&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const l=o.querySelector(`[name="${n.name}"]`);l&&l.type!=="date"&&(l.type="date")})}function Ft(e,t){const o=e?.querySelector?.(".dm-plugin-banner-name .dm-plugin-banner-sep");if(o){for(;o.nextSibling;)o.nextSibling.remove();o.after(document.createTextNode(String(t||"")))}}const vn=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");let W=null,It=0,Bt=!1;const Le=e=>String(e||"").split("?")[0].replace(/\/$/,"");function xn(){Bt||!window.R?.use||(Bt=!0,R.use((e,t,o)=>!W||!ot(t?.path,e?.path)||W.path!==Le(t?.path)||(W.flush(),!W.dirty())?o():E.confirm("You have unsaved changes to this form. Leave anyway? They are kept as a draft for your next visit to it.").then(n=>{n?o():history.replaceState(null,"",`#${t.path}`)})),M.subscribe("router:afterChange",({to:e,from:t}={})=>{if(W&&W.path===Le(t?.path)&&ot(t?.path,e?.path)){const o=W;W=null,o.dispose()}}))}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){if(xn(),W){const p=W;W=null,p.dispose()}const t=Le(location.hash.replace(/^#/,"")),o=++It,n=()=>o!==It||!e.get(0)?.isConnected||Le(location.hash.replace(/^#/,""))!==t;C=[],N=null,ge=null;const l=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);N=l?l[1]:null;let a=null;const i=E.loader(e.get(0),{type:"dots"});if(N)try{if(a=await se(`/forms/${N}`),n()){i.destroy();return}C=a.fields||[],ge=a.actions?.collection??null}catch{if(n()){i.destroy();return}E.toast("Could not load form.",{type:"error"})}ye={};try{const p=await se("/projects").catch(()=>[]);if(n()){i.destroy();return}const v=e.find("#field-project").get(0);v&&(Array.isArray(p)?p:[]).forEach(y=>{const k=document.createElement("option");k.value=y.slug,k.textContent=y.name||y.slug,v.appendChild(k)})}catch{}if(i.destroy(),Ft(e.get(0),a?a.title||a.slug:"New form"),N||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(ct(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),a){e.find("#field-title").val(a.title),e.find("#field-slug").val(a.slug),e.find("#field-description").val(a.description||""),e.find("#field-bundled").prop("checked",!!a.bundled),ye=a.meta||{},e.find("#field-project").val(a.meta?.project||"");const p=a.settings||{};e.find("#setting-submit-text").val(p.submitText||"Submit"),e.find("#setting-success-message").val(p.successMessage||""),e.find("#setting-layout").val(p.layout||"grid"),e.find("#setting-columns").val(Te(p.columns)),e.find("#setting-submit-span").val(p.submitSpan||""),e.find("#columns-group").get(0).style.display=(p.layout||"grid")==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",p.honeypot!==!1),e.find("#setting-rate-limit").val(p.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(p.successRedirect||"");const v=a.actions?.email||{};e.find("#action-email-enabled").prop("checked",v.enabled||!1),e.find("#action-email-recipients").val(v.recipients||""),e.find("#action-email-subject-prefix").val(v.subjectPrefix||"");const y=a.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",y.enabled||!1),e.find("#action-webhook-url").val(y.url||""),e.find("#action-webhook-method").val(y.method||"POST")}const r=a?.settings?.actionSlug||"";try{const p=await se("/actions").catch(()=>[]);if(n())return;const v=e.find("#action-cms-slug").get(0);if(be=Array.isArray(p)?p:[],(Array.isArray(p)?p:[]).forEach(y=>{const k=document.createElement("option");k.value=y.slug,k.textContent=y.title||y.slug,y.slug===r&&(k.selected=!0),v.appendChild(k)}),!p.length){const y=document.createElement("option");y.value="",y.textContent="No actions available",y.disabled=!0,v.appendChild(y)}}catch{}const c=p=>{e.find("#columns-group").get(0).style.display=p?"":"none",document.querySelectorAll(".fb-grid-row").forEach(v=>{v.style.display=p?"flex":"none"})};e.find("#setting-layout").get(0)?.addEventListener("change",function(){c(this.value==="grid")}),c(e.find("#setting-layout").val()==="grid"),Y(e);const s=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",p=>{p.stopPropagation(),s.style.display=s.style.display==="none"?"":"none"}),le&&document.removeEventListener("click",le),le=()=>{s&&(s.style.display="none")},document.addEventListener("click",le),e.find("#add-field-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),O();const p=C.length;C.push({name:`field_${p+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),Y(e);const v=e.find("#fields-list").get(0)?.lastElementChild;if(v){const y=v.querySelector(".fb-field-body");y&&(y.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),O(),C.push({type:"spacer"}),Y(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),O();const p=C.filter(v=>v.type==="page-break").length+2;C.push({type:"page-break",label:`Step ${p}`,description:""}),Y(e)}),ve=()=>{const p=Ne(e),v=e.find("#preview-container").get(0);if(!v)return;const y=e.find("#preview-test-result").get(0),k=e.find("#preview-test-badge").get(0);y&&(y.style.display="none",y.textContent=""),k&&(k.style.display=N?"":"none"),e.find("#preview-card").get(0).style.display="",v.textContent="";const V=document.createElement("div");V.id="fb-preview-form",v.appendChild(V);const J=N?async L=>{y&&(y.style.display="none",y.textContent="");try{const T=await fetch(`/api/forms/submit/${N}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(L)}),Q=await T.json();if(!T.ok)throw new Error(Q.error||"Submission failed.");y&&(y.textContent=Q.message||p.settings?.successMessage||"Submitted successfully.",y.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-success) 12%, transparent);color:var(--dm-success);"),E.toast("Test submission stored.",{type:"success"})}catch(T){y&&(y.textContent=T.message,y.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-danger) 12%, transparent);color:var(--dm-danger);"),E.toast(T.message,{type:"error"})}return!1}:()=>!1,fe=p.fields.some(L=>L.type==="page-break");if(V.addEventListener("dm-form-end",L=>{const T=L.detail?.validation;if(T&&!T.valid){E.toast(`Still to answer: ${T.missing.map(Q=>Q.label).concat(T.errors).join(", ")}`,{type:"warning"});return}J(L.detail?.values||{})}),typeof F<"u"){const L=Te(p.settings?.columns),T=p.settings?.layout||"grid";if(fe&&F.wizard){const Q=Pt(p.fields,p.title),he=Q.map(ne=>({title:ne.title,description:ne.description,fields:$t(ne.fields,L)}));let B=0,Z=null,$e=null;const et=ne=>{const tt=(Q[B]||{}).fields||[];At("#fb-preview-form",tt),nt(V,tt),ne&&window.FormLogicEngine&&pt(p.fields)&&(Z?.destroy?.(),Z=new window.FormLogicEngine.FormLogicRuntime({fields:p.fields},V,{baseValues:$e?.getStepData?$e.getStepData():{}}),Z.init())};$e=F.wizard("#fb-preview-form",{schema:{steps:he},layout:T,columns:L,finishText:p.settings?.submitText||"Finish",onStepChange:ne=>{B=ne,queueMicrotask(()=>et(!0))},onSubmit:J}),et(!1)}else if(F.render){const Q=$t(p.fields,L),he={};if(p.fields.forEach(B=>{if(!(!B.name||B.type==="page-break"||B.type==="spacer")&&(B.type==="select"||B.type==="multiselect")&&B.required){const Z=(B.options||[])[0];Z&&(he[B.name]=typeof Z=="object"?Z.value:Z)}}),F.render("#fb-preview-form",Q,he,{submitText:p.settings?.submitText||"Submit",layout:T,columns:L,onSubmit:J}),T==="grid"&&p.settings?.submitSpan==="full"){const B=document.querySelector("#fb-preview-form .form-buttons");B&&B.classList.add("col-span-full")}At("#fb-preview-form",p.fields),nt(V,p.fields)}window.FormLogicEngine&&pt(p.fields)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:p.fields},V).init()})}else{const L=document.createElement("p");L.textContent=`${p.fields.filter(T=>T.type!=="page-break").length} field(s): ${p.fields.filter(T=>T.type!=="page-break").map(T=>T.label).join(", ")}`,L.style.cssText="color:var(--dm-text-muted);font-style:italic;",V.appendChild(L)}},ve();const d=e.find("#editor-tabs").get(0),u=e.find("#preview-card").get(0),b=p=>{u&&u.contains(p.target)||Re()};d&&(d.addEventListener("input",b),d.addEventListener("change",b));const g=e.get(0),m=[],h=p=>(m.push(p),p);let w=!1;const f=M.observable(!1),x=M.observable(!1);let $=N,A=Ne(e),H=Ie(A),_=A;const j=()=>{w||!g.isConnected||(_=Ne(e),f.value=Ie(_)!==H)};let I=null;Me=()=>{clearTimeout(I),I=setTimeout(j,150)},h(()=>{clearTimeout(I),Me=null,de=null});const X=p=>{const v=p.settings||{};e.find("#field-title").val(p.title||""),e.find("#field-slug").val(p.slug||""),e.find("#field-description").val(p.description||""),e.find("#field-bundled").prop("checked",!!p.bundled),ye={...p.meta||{}},e.find("#field-project").val(p.meta?.project||""),e.find("#setting-submit-text").val(v.submitText||"Submit"),e.find("#setting-success-message").val(v.successMessage||""),e.find("#setting-layout").val(v.layout||"grid"),e.find("#setting-columns").val(Te(v.columns)),e.find("#setting-submit-span").val(v.submitSpan||""),e.find("#setting-honeypot").prop("checked",v.honeypot!==!1),e.find("#setting-rate-limit").val(v.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(v.successRedirect||""),e.find("#action-cms-slug").val(v.actionSlug||"");const y=p.actions?.email||{};e.find("#action-email-enabled").prop("checked",!!y.enabled),e.find("#action-email-recipients").val(y.recipients||""),e.find("#action-email-subject-prefix").val(y.subjectPrefix||"");const k=p.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",!!k.enabled),e.find("#action-webhook-url").val(k.url||""),e.find("#action-webhook-method").val(k.method||"POST"),C=JSON.parse(JSON.stringify(p.fields||[])),c((v.layout||"grid")==="grid"),Y(e)};async function U(){if(x.peek()||w)return;const p=Ne(e);if(!p.title){E.toast("Please enter a form title (Form Details).",{type:"error"});return}x.value=!0;const v=N;try{N?(await se(`/forms/${N}`,{method:"PUT",body:JSON.stringify(p)}),E.toast("Form saved.",{type:"success"})):(N=(await se("/forms",{method:"POST",body:JSON.stringify(p)})).slug,E.toast("Form created.",{type:"success"})),$=N,A=p,H=Ie(p),_=p,f.value=!1;for(const y of new Set([re(v),re(N)]))try{S.remove?S.remove(y):S.set(y,null)}catch{}Ft(g,p.title),jt("#/forms"),v||R.navigate(`/forms/edit/${N}`)}catch(y){v||(N=null),E.toast(y.message||"Failed to save form.",{type:"error"})}finally{x.value=!1}}async function Ot(){f.peek()&&(!await E.confirm("Discard the changes you have not saved?")||w||(X(A),j(),Qe()))}const He=g.querySelector(".fex-bar");if(He){const p=M.applyBindings({dirty:f,saving:x},He,{methods:{save:U,discard:Ot}});h(()=>p.dispose())}h(_t(g,{position:"bottom"})),Ae(e,{id:"form-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>U()}),Ae(e,{id:"form-editor-back",icon:"arrow-left",title:"All forms",onClick:()=>{location.hash="#/forms"}}),N&&Ae(e,{id:"form-editor-subs",icon:"list",title:"Submissions",onClick:()=>{location.hash=`#/forms/${encodeURIComponent(N)}/submissions`}});const We=p=>{n()||!(p.ctrlKey||p.metaKey)||String(p.key).toLowerCase()!=="s"||(p.preventDefault(),p.stopImmediatePropagation(),U())};document.addEventListener("keydown",We,!0),h(()=>document.removeEventListener("keydown",We,!0));const ee=e.find("#fields-list").get(0),Mt=p=>p?.closest?.(".fb-field-card"),Ue=p=>Number(p?.dataset.index),Je=p=>p?.querySelector(":scope > .fb-field-body"),Ye=p=>{const v=Je(p);v&&(v.style.display=v.style.display==="none"?"":"none")},me=(p,v)=>{C=p,Y(e),v!=null&&ee?.querySelectorAll(".fb-field-card")[v]?.focus()},Rt=async p=>{try{await navigator.clipboard.writeText(p),E.toast(`Copied "${p}".`,{type:"success"})}catch{E.toast(`Copy failed - the name is ${p}.`,{type:"info"})}},Dt=p=>{const v=Mt(p),y=Ue(v);O();const k=C[y];if(!k)return[];const V=k.type!=="spacer"&&k.type!=="page-break",J=Je(v),fe=J&&J.style.display!=="none";return[{header:Fe(k)},...J?[{label:fe?"Close":"Edit",icon:fe?"chevron-up":"edit",action:()=>Ye(v)}]:[],...V?[{label:"Logic & triggers",icon:"zap",action:()=>{J&&(J.style.display=""),(J?.querySelector(".fb-field-logic")||J)?.scrollIntoView({block:"center",behavior:"smooth"})}}]:[],{label:"Duplicate",icon:"copy",action:()=>{O(),me(Gt(C,y),y+1)}},{type:"divider"},{label:"Move up",icon:"arrow-up",disabled:y===0,action:()=>{O(),me(it(C,y,-1),y-1)}},{label:"Move down",icon:"arrow-down",disabled:y>=C.length-1,action:()=>{O(),me(it(C,y,1),y+1)}},...V&&k.name?[{label:"Copy field name",icon:"clipboard",action:()=>Rt(k.name)}]:[],{type:"divider"},{label:"Delete\u2026",icon:"trash",danger:!0,action:async()=>{if(k.type!=="spacer"&&!await E.confirm(`Remove "${vn(Fe(k))}"?`))return;O();const L=[...C];L.splice(y,1),me(L,Math.min(y,L.length-1))}}]};let Ke=null;if(ee&&E.contextMenu&&(Ke=E.contextMenu(ee,{cursor:"glyph",match:".fb-field-card > :first-child",inherit:!1,density:"compact",items:p=>Dt(p)}),h(()=>Ke?.destroy?.())),de=p=>{for(const v of p.querySelectorAll(".fb-field-card")){v.tabIndex=0;const y=v.firstElementChild;if(!y||y.querySelector(".fex-kebab"))continue;const k=document.createElement("button");k.type="button",k.className="fex-kebab",k.textContent="\u22EE",k.title="Actions",O(),k.setAttribute("aria-label",`Actions for ${Fe(C[Ue(v)])}`),k.addEventListener("click",V=>{V.stopPropagation(),lt(k)}),y.appendChild(k)}},ee){de(ee);const p=v=>{const y=v.target?.classList?.contains("fb-field-card")?v.target:null;y&&(v.key==="F10"&&v.shiftKey?(v.preventDefault(),lt(y.firstElementChild)):v.key==="Enter"&&(v.preventDefault(),Ye(y)))};ee.addEventListener("keydown",p),h(()=>ee.removeEventListener("keydown",p))}const Qe=()=>{try{const p=re($);S.remove?S.remove(p):S.set(p,null)}catch{}},Xe=p=>{if(!f.peek()||!p){Qe();return}try{S.set(re($),{data:Vt(p),base:at(H),at:new Date().toISOString()})}catch{}},Ze=p=>{j(),f.peek()&&(Xe(_),p.preventDefault(),p.returnValue="")};window.addEventListener("beforeunload",Ze),h(()=>window.removeEventListener("beforeunload",Ze)),h(()=>{le&&(document.removeEventListener("click",le),le=null)}),W={path:t,dirty:()=>f.peek(),flush:()=>{clearTimeout(I),j()},dispose(){w||(Xe(_),w=!0,m.splice(0).reverse().forEach(p=>{try{p?.()}catch{}}))}};const qe=re(N);let te=null;try{te=S.get(qe)}catch{}if(te?.data){try{S.remove?S.remove(qe):S.set(qe,null)}catch{}const p=te.base&&te.base!==at(H),v=te.at?` (${D(te.at).format("D MMM HH:mm")})`:"";await E.confirm(`You left unsaved changes to this form${v}.${p?" The saved form has changed since then.":""} Pick up where you left off?`)&&!w&&(X(Ht(te.data,A)),j())}}};
|
|
8
|
+
`),l.style.fontFamily="monospace",o.appendChild(n),o.appendChild(l),o}function Se(e){return parseInt(e,10)===3?3:2}function Te(e){const t=e.find("#field-project").val()||"";return O(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},meta:{...ge||{},project:t||null},fields:C,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"grid",columns:Se(e.find("#setting-columns").val()),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()},...be!==null&&{collection:be}}}}function qt(e,t){const o={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const l={...n.formConfig||{}};l.span==="full"&&t&&(l.span=t);const a=n.type==="chooser"||!!(n.variant&&["select","radio","checkbox-group"].includes(n.type)),r={type:n.type==="checkbox"?"boolean":n.type==="date"||n.type==="icon"||n.type==="image"?"string":a?"chooser":n.type,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{helperText:n.helper},...n.tooltip&&{tooltip:n.tooltip},...l}};a&&(n.variant&&(r.variant=n.variant),(n.multiple||n.type==="checkbox-group")&&(r.multiple=!0),n.density&&(r.density=n.density),n.columns&&(r.columns=n.columns),n.accent&&(r.accent=n.accent),n.accentStyle&&(r.accentStyle=n.accentStyle),n.glow&&(r.glow=!0),n.glowColour&&(r.glowColour=n.glowColour),n.shadow&&(r.shadow=n.shadow),n.shadowColour&&(r.shadowColour=n.shadowColour)),o[n.name]=r}),o}function $t(e,t){const o=typeof e=="string"?document.querySelector(e):e;o&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const l=o.querySelector(`[name="${n.name}"]`);l&&l.type!=="date"&&(l.type="date")})}function At(e,t){const o=e?.querySelector?.(".dm-plugin-banner-name .dm-plugin-banner-sep");if(o){for(;o.nextSibling;)o.nextSibling.remove();o.after(document.createTextNode(String(t||"")))}}const vn=e=>String(e??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");let W=null,Ft=0,It=!1;const Ne=e=>String(e||"").split("?")[0].replace(/\/$/,"");function xn(){It||!window.R?.use||(It=!0,R.use((e,t,o)=>!W||!at(t?.path,e?.path)||W.path!==Ne(t?.path)||(W.flush(),!W.dirty())?o():E.confirm("You have unsaved changes to this form. Leave anyway? They are kept as a draft for your next visit to it.").then(n=>{n?o():history.replaceState(null,"",`#${t.path}`)})),M.subscribe("router:afterChange",({to:e,from:t}={})=>{if(W&&W.path===Ne(t?.path)&&at(t?.path,e?.path)){const o=W;W=null,o.dispose()}}))}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){if(xn(),W){const p=W;W=null,p.dispose()}const t=Ne(location.hash.replace(/^#/,"")),o=++Ft,n=()=>o!==Ft||!e.get(0)?.isConnected||Ne(location.hash.replace(/^#/,""))!==t;C=[],N=null,be=null;const l=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);N=l?l[1]:null;let a=null;const i=E.loader(e.get(0),{type:"dots"});if(N)try{if(a=await ie(`/forms/${N}`),n()){i.destroy();return}C=a.fields||[],be=a.actions?.collection??null}catch{if(n()){i.destroy();return}E.toast("Could not load form.",{type:"error"})}ge={};try{const p=await ie("/projects").catch(()=>[]);if(n()){i.destroy();return}const v=e.find("#field-project").get(0);v&&(Array.isArray(p)?p:[]).forEach(y=>{const k=document.createElement("option");k.value=y.slug,k.textContent=y.name||y.slug,v.appendChild(k)})}catch{}if(i.destroy(),At(e.get(0),a?a.title||a.slug:"New form"),N||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(rt(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),a){e.find("#field-title").val(a.title),e.find("#field-slug").val(a.slug),e.find("#field-description").val(a.description||""),e.find("#field-bundled").prop("checked",!!a.bundled),ge=a.meta||{},e.find("#field-project").val(a.meta?.project||"");const p=a.settings||{};e.find("#setting-submit-text").val(p.submitText||"Submit"),e.find("#setting-success-message").val(p.successMessage||""),e.find("#setting-layout").val(p.layout||"grid"),e.find("#setting-columns").val(Se(p.columns)),e.find("#setting-submit-span").val(p.submitSpan||""),e.find("#columns-group").get(0).style.display=(p.layout||"grid")==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",p.honeypot!==!1),e.find("#setting-rate-limit").val(p.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(p.successRedirect||"");const v=a.actions?.email||{};e.find("#action-email-enabled").prop("checked",v.enabled||!1),e.find("#action-email-recipients").val(v.recipients||""),e.find("#action-email-subject-prefix").val(v.subjectPrefix||"");const y=a.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",y.enabled||!1),e.find("#action-webhook-url").val(y.url||""),e.find("#action-webhook-method").val(y.method||"POST")}const r=a?.settings?.actionSlug||"";try{const p=await ie("/actions").catch(()=>[]);if(n())return;const v=e.find("#action-cms-slug").get(0);if(he=Array.isArray(p)?p:[],(Array.isArray(p)?p:[]).forEach(y=>{const k=document.createElement("option");k.value=y.slug,k.textContent=y.title||y.slug,y.slug===r&&(k.selected=!0),v.appendChild(k)}),!p.length){const y=document.createElement("option");y.value="",y.textContent="No actions available",y.disabled=!0,v.appendChild(y)}}catch{}const c=p=>{e.find("#columns-group").get(0).style.display=p?"":"none",document.querySelectorAll(".fb-grid-row").forEach(v=>{v.style.display=p?"flex":"none"})};e.find("#setting-layout").get(0)?.addEventListener("change",function(){c(this.value==="grid")}),c(e.find("#setting-layout").val()==="grid"),J(e);const s=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",p=>{p.stopPropagation(),s.style.display=s.style.display==="none"?"":"none"}),ne&&document.removeEventListener("click",ne),ne=()=>{s&&(s.style.display="none")},document.addEventListener("click",ne),e.find("#add-field-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),O();const p=C.length;C.push({name:`field_${p+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),J(e);const v=e.find("#fields-list").get(0)?.lastElementChild;if(v){const y=v.querySelector(".fb-field-body");y&&(y.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),O(),C.push({type:"spacer"}),J(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{s&&(s.style.display="none"),O();const p=C.filter(v=>v.type==="page-break").length+2;C.push({type:"page-break",label:`Step ${p}`,description:""}),J(e)}),ye=()=>{const p=Te(e),v=e.find("#preview-container").get(0);if(!v)return;const y=e.find("#preview-test-result").get(0),k=e.find("#preview-test-badge").get(0);y&&(y.style.display="none",y.textContent=""),k&&(k.style.display=N?"":"none"),e.find("#preview-card").get(0).style.display="",v.textContent="";const j=document.createElement("div");j.id="fb-preview-form",v.appendChild(j);const U=N?async L=>{y&&(y.style.display="none",y.textContent="");try{const T=await fetch(`/api/forms/submit/${N}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(L)}),K=await T.json();if(!T.ok)throw new Error(K.error||"Submission failed.");y&&(y.textContent=K.message||p.settings?.successMessage||"Submitted successfully.",y.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-success) 12%, transparent);color:var(--dm-success);"),E.toast("Test submission stored.",{type:"success"})}catch(T){y&&(y.textContent=T.message,y.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:color-mix(in srgb, var(--dm-danger) 12%, transparent);color:var(--dm-danger);"),E.toast(T.message,{type:"error"})}return!1}:()=>!1,me=p.fields.some(L=>L.type==="page-break");if(j.addEventListener("dm-form-end",L=>{const T=L.detail?.validation;if(T&&!T.valid){E.toast(`Still to answer: ${T.missing.map(K=>K.label).concat(T.errors).join(", ")}`,{type:"warning"});return}U(L.detail?.values||{})}),typeof F<"u"){const L=Se(p.settings?.columns),T=p.settings?.layout||"grid";if(me&&F.wizard){const K=zt(p.fields,p.title),fe=K.map(te=>({title:te.title,description:te.description,fields:qt(te.fields,L)}));let B=0,X=null,qe=null;const Ze=te=>{const et=(K[B]||{}).fields||[];$t("#fb-preview-form",et),tt(j,et),te&&window.FormLogicEngine&&dt(p.fields)&&(X?.destroy?.(),X=new window.FormLogicEngine.FormLogicRuntime({fields:p.fields},j,{baseValues:qe?.getStepData?qe.getStepData():{}}),X.init())};qe=F.wizard("#fb-preview-form",{schema:{steps:fe},layout:T,columns:L,finishText:p.settings?.submitText||"Finish",onStepChange:te=>{B=te,queueMicrotask(()=>Ze(!0))},onSubmit:U}),Ze(!1)}else if(F.render){const K=qt(p.fields,L),fe={};if(p.fields.forEach(B=>{if(!(!B.name||B.type==="page-break"||B.type==="spacer")&&(B.type==="select"||B.type==="multiselect")&&B.required){const X=(B.options||[])[0];X&&(fe[B.name]=typeof X=="object"?X.value:X)}}),F.render("#fb-preview-form",K,fe,{submitText:p.settings?.submitText||"Submit",layout:T,columns:L,onSubmit:U}),T==="grid"&&p.settings?.submitSpan==="full"){const B=document.querySelector("#fb-preview-form .form-buttons");B&&B.classList.add("col-span-full")}$t("#fb-preview-form",p.fields),tt(j,p.fields)}window.FormLogicEngine&&dt(p.fields)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:p.fields},j).init()})}else{const L=document.createElement("p");L.textContent=`${p.fields.filter(T=>T.type!=="page-break").length} field(s): ${p.fields.filter(T=>T.type!=="page-break").map(T=>T.label).join(", ")}`,L.style.cssText="color:var(--dm-text-muted);font-style:italic;",j.appendChild(L)}},ye();const d=e.find("#editor-tabs").get(0),u=e.find("#preview-card").get(0),b=p=>{u&&u.contains(p.target)||Re()};d&&(d.addEventListener("input",b),d.addEventListener("change",b));const g=e.get(0),m=[],h=p=>(m.push(p),p);let w=!1;const f=M.observable(!1),x=M.observable(!1);let $=N,A=Te(e),G=Fe(A),P=A;const _=()=>{w||!g.isConnected||(P=Te(e),f.value=Fe(P)!==G)};let I=null;Oe=()=>{clearTimeout(I),I=setTimeout(_,150)},h(()=>{clearTimeout(I),Oe=null,ce=null});const Q=p=>{const v=p.settings||{};e.find("#field-title").val(p.title||""),e.find("#field-slug").val(p.slug||""),e.find("#field-description").val(p.description||""),e.find("#field-bundled").prop("checked",!!p.bundled),ge={...p.meta||{}},e.find("#field-project").val(p.meta?.project||""),e.find("#setting-submit-text").val(v.submitText||"Submit"),e.find("#setting-success-message").val(v.successMessage||""),e.find("#setting-layout").val(v.layout||"grid"),e.find("#setting-columns").val(Se(v.columns)),e.find("#setting-submit-span").val(v.submitSpan||""),e.find("#setting-honeypot").prop("checked",v.honeypot!==!1),e.find("#setting-rate-limit").val(v.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(v.successRedirect||""),e.find("#action-cms-slug").val(v.actionSlug||"");const y=p.actions?.email||{};e.find("#action-email-enabled").prop("checked",!!y.enabled),e.find("#action-email-recipients").val(y.recipients||""),e.find("#action-email-subject-prefix").val(y.subjectPrefix||"");const k=p.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",!!k.enabled),e.find("#action-webhook-url").val(k.url||""),e.find("#action-webhook-method").val(k.method||"POST"),C=JSON.parse(JSON.stringify(p.fields||[])),c((v.layout||"grid")==="grid"),J(e)};async function H(){if(x.peek()||w)return;const p=Te(e);if(!p.title){E.toast("Please enter a form title (Form Details).",{type:"error"});return}x.value=!0;const v=N;try{N?(await ie(`/forms/${N}`,{method:"PUT",body:JSON.stringify(p)}),E.toast("Form saved.",{type:"success"})):(N=(await ie("/forms",{method:"POST",body:JSON.stringify(p)})).slug,E.toast("Form created.",{type:"success"})),$=N,A=p,G=Fe(p),P=p,f.value=!1;for(const y of new Set([se(v),se(N)]))try{S.remove?S.remove(y):S.set(y,null)}catch{}At(g,p.title),_t("#/forms"),v||R.navigate(`/forms/edit/${N}`)}catch(y){v||(N=null),E.toast(y.message||"Failed to save form.",{type:"error"})}finally{x.value=!1}}async function Bt(){f.peek()&&(!await E.confirm("Discard the changes you have not saved?")||w||(Q(A),_(),Ke()))}const Ge=g.querySelector(".fex-bar");if(Ge){const p=M.applyBindings({dirty:f,saving:x},Ge,{methods:{save:H,discard:Bt}});h(()=>p.dispose())}h(Pt(g,{position:"bottom"})),$e(e,{id:"form-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>H()}),$e(e,{id:"form-editor-back",icon:"arrow-left",title:"All forms",onClick:()=>{location.hash="#/forms"}}),N&&$e(e,{id:"form-editor-subs",icon:"list",title:"Submissions",onClick:()=>{location.hash=`#/forms/${encodeURIComponent(N)}/submissions`}});const We=p=>{n()||!(p.ctrlKey||p.metaKey)||String(p.key).toLowerCase()!=="s"||(p.preventDefault(),p.stopImmediatePropagation(),H())};document.addEventListener("keydown",We,!0),h(()=>document.removeEventListener("keydown",We,!0));const Z=e.find("#fields-list").get(0),Ot=p=>p?.closest?.(".fb-field-card"),He=p=>Number(p?.dataset.index),Ue=p=>p?.querySelector(":scope > .fb-field-body"),Je=p=>{const v=Ue(p);v&&(v.style.display=v.style.display==="none"?"":"none")},ue=(p,v)=>{C=p,J(e),v!=null&&Z?.querySelectorAll(".fb-field-card")[v]?.focus()},Rt=async p=>{try{await navigator.clipboard.writeText(p),E.toast(`Copied "${p}".`,{type:"success"})}catch{E.toast(`Copy failed - the name is ${p}.`,{type:"info"})}},Dt=p=>{const v=Ot(p),y=He(v);O();const k=C[y];if(!k)return[];const j=k.type!=="spacer"&&k.type!=="page-break",U=Ue(v),me=U&&U.style.display!=="none";return[{header:Ae(k)},...U?[{label:me?"Close":"Edit",icon:me?"chevron-up":"edit",action:()=>Je(v)}]:[],...j?[{label:"Logic & triggers",icon:"zap",action:()=>{U&&(U.style.display=""),(U?.querySelector(".fb-field-logic")||U)?.scrollIntoView({block:"center",behavior:"smooth"})}}]:[],{label:"Duplicate",icon:"copy",action:()=>{O(),ue(Vt(C,y),y+1)}},{type:"divider"},{label:"Move up",icon:"arrow-up",disabled:y===0,action:()=>{O(),ue(ot(C,y,-1),y-1)}},{label:"Move down",icon:"arrow-down",disabled:y>=C.length-1,action:()=>{O(),ue(ot(C,y,1),y+1)}},...j&&k.name?[{label:"Copy field name",icon:"clipboard",action:()=>Rt(k.name)}]:[],{type:"divider"},{label:"Delete\u2026",icon:"trash",danger:!0,action:async()=>{if(k.type!=="spacer"&&!await E.confirm(`Remove "${vn(Ae(k))}"?`))return;O();const L=[...C];L.splice(y,1),ue(L,Math.min(y,L.length-1))}}]};let Ye=null;if(Z&&E.contextMenu&&(Ye=E.contextMenu(Z,{cursor:"glyph",match:".fb-field-card > :first-child",inherit:!1,density:"compact",items:p=>Dt(p)}),h(()=>Ye?.destroy?.())),ce=p=>{for(const v of p.querySelectorAll(".fb-field-card")){v.tabIndex=0;const y=v.firstElementChild;if(!y||y.querySelector(".fex-kebab"))continue;const k=document.createElement("button");k.type="button",k.className="fex-kebab",k.textContent="\u22EE",k.title="Actions",O(),k.setAttribute("aria-label",`Actions for ${Ae(C[He(v)])}`),k.addEventListener("click",j=>{j.stopPropagation(),nt(k)}),y.appendChild(k)}},Z){ce(Z);const p=v=>{const y=v.target?.classList?.contains("fb-field-card")?v.target:null;y&&(v.key==="F10"&&v.shiftKey?(v.preventDefault(),nt(y.firstElementChild)):v.key==="Enter"&&(v.preventDefault(),Je(y)))};Z.addEventListener("keydown",p),h(()=>Z.removeEventListener("keydown",p))}const Ke=()=>{try{const p=se($);S.remove?S.remove(p):S.set(p,null)}catch{}},Qe=p=>{if(!f.peek()||!p){Ke();return}try{S.set(se($),{data:jt(p),base:lt(G),at:new Date().toISOString()})}catch{}},Xe=p=>{_(),f.peek()&&(Qe(P),p.preventDefault(),p.returnValue="")};window.addEventListener("beforeunload",Xe),h(()=>window.removeEventListener("beforeunload",Xe)),h(()=>{ne&&(document.removeEventListener("click",ne),ne=null)}),W={path:t,dirty:()=>f.peek(),flush:()=>{clearTimeout(I),_()},dispose(){w||(Qe(P),w=!0,m.splice(0).reverse().forEach(p=>{try{p?.()}catch{}}))}};const Le=se(N);let ee=null;try{ee=S.get(Le)}catch{}if(ee?.data){try{S.remove?S.remove(Le):S.set(Le,null)}catch{}const p=ee.base&&ee.base!==lt(G),v=ee.at?` (${Wt(ee.at)})`:"";await E.confirm(`You left unsaved changes to this form${v}.${p?" The saved form has changed since then.":""} Pick up where you left off?`)&&!w&&(Q(Gt(ee.data,A)),_())}}};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{apiRequest as A}from"/admin/js/api.js";import{addBannerAction as
|
|
1
|
+
import{apiRequest as A}from"/admin/js/api.js";import{addBannerAction as H}from"/admin/js/lib/plugin-chrome.js";import{helpPopovers as re}from"/admin/js/lib/help-popover.js";import{onceClosed as ke,openMenuAt as ce,sidebarCount as G,viewLifetime as $e}from"/admin/js/lib/tool-kit.js";import{FILTERS as Se,answerFields as Ne,answerText as O,arrangeSubmissions as Te,submissionCounts as Me,submissionRow as L,submissionText as Ae}from"/admin/js/lib/form-submissions-arrange.js";import{fmtDateTime as De}from"../lib/dates.js";const le=/^#\/forms\/[^/?#]+\/submissions\/?(\?.*)?$/,X="form-submissions.filter",Le=`
|
|
2
2
|
<div class="fsx-row" data-id="{{id}}" tabindex="0" data-bind-class="rowCls">
|
|
3
3
|
<span class="fsx-dot" aria-hidden="true"></span>
|
|
4
4
|
<span class="fsx-main"><strong>{{title}}</strong><small>{{meta}}</small></span>
|
|
@@ -8,4 +8,4 @@ import{apiRequest as A}from"/admin/js/api.js";import{addBannerAction as V}from"/
|
|
|
8
8
|
</span>
|
|
9
9
|
<span class="fsx-when" title="{{whenFull}}">{{when}}</span>
|
|
10
10
|
<button type="button" class="fsx-kebab" aria-label="Actions for this submission" title="Actions">\u22EE</button>
|
|
11
|
-
</div>`,X=i=>String(i??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),U=(i,r,b=`${r}s`)=>`${i} ${i===1?r:b}`,Q=i=>i?D(i).format("DD MMM YYYY HH:mm"):"";async function me(i){try{return await navigator.clipboard.writeText(i),!0}catch{}try{const r=document.createElement("textarea");r.value=i,r.style.cssText="position:fixed;opacity:0;",document.body.appendChild(r),r.select();const b=document.execCommand("copy");return r.remove(),b}catch{return!1}}const h=$e(le);export const formSubmissionsView={templateUrl:"/admin/js/templates/form-submissions.html",async onMount(i){h.reset();const r=i.get(0).querySelector(".fsx")||i.get(0),b=()=>le.test(location.hash)&&r.isConnected,p=decodeURIComponent((location.hash.match(/^#\/forms\/([^/?#]+)\/submissions/)||[])[1]||"");if(!p){E.toast("No form selected.",{type:"error"});return}const C=encodeURIComponent(p),y=M.observable(null),c=M.observable([]),Z=M.observable(!0),q=M.observable("");let ee="inbox";try{ee=Se.includes(S.get(G))?S.get(G):"inbox"}catch{}const w=M.observable(ee),te=M.observable(""),j=M.observable(""),F=M.observable("");h.add(M.effect(()=>{const e=w.value;try{S.set(G,e)}catch{}}));const k=M.computed(()=>Ne(y.value||{})),P=M.observable([]);h.add(M.effect(()=>{const e=Date.now(),t=Me(c.value,{filter:w.value,query:te.value,from:j.value,to:F.value,now:e}),s=k.value;P.value=t.map(n=>{const a=L(n,s,e);return{...a,when:a.at?D(a.at).fromNow():"",whenFull:Q(a.at)}})}));const de=M.computed(()=>Te(c.value)),pe=M.computed(()=>{const e=P.value.length,t=c.value.length;return t?e===t?U(t,"submission"):`${e} of ${U(t,"submission")}`:""}),ue=M.computed(()=>c.value.length?w.value==="spam"?"Nothing marked as spam.":"No submissions match.":"No submissions yet - they appear here as people send the form."),fe=M.computed(()=>y.value?`What people sent through "${y.value.title||p}".`:"What people sent through this form."),R=e=>c.peek().find(t=>String(t.id)===String(e));async function he(){try{const[e,t]=await Promise.all([A(`/forms/${C}`),A(`/forms/${C}/submissions`)]);if(!b())return;y.value=e||null,c.value=Array.isArray(t)?t:[],q.value="",be(e?.title||p)}catch(e){if(!b())return;q.value=`Could not load the submissions: ${e.message||e}`}finally{Z.value=!1}}function be(e){const t=i.get(0).querySelector(".dm-plugin-banner-name"),s=t?.lastChild;s&&s.nodeType===Node.TEXT_NODE&&t.querySelector(".dm-plugin-banner-sep")&&(s.textContent=`${e} submissions`),document.title=`${e} - Submissions - Domma CMS`}async function B(e,t){try{const s=await A(`/forms/${C}/submissions/${encodeURIComponent(e.id)}/spam`,{method:"POST",body:JSON.stringify({spam:t})});return c.value=c.peek().map(n=>String(n.id)===String(e.id)?{...n,data:s?.entry?.data||{...n.data,spam:t}}:n),E.toast(t?"Marked as spam - it is under Spam now.":"Back in the inbox.",{type:"success"}),z("#/forms"),!0}catch(s){return E.toast(`Not changed: ${s.message||s}`,{type:"error"}),!1}}async function Y(e){const t=L(e,k.peek()).title;if(!await E.confirm(`Delete the submission from "${X(t)}"? This cannot be undone.`))return!1;try{return await A(`/forms/${C}/submissions/${encodeURIComponent(e.id)}`,{method:"DELETE"}),c.value=c.peek().filter(s=>String(s.id)!==String(e.id)),E.toast("Submission deleted.",{type:"success"}),z("#/forms"),!0}catch(s){return E.toast(`Not deleted: ${s.message||s}`,{type:"error"}),!1}}async function ye(){const e=c.peek().length;if(!e){E.toast("There are no submissions to clear.",{type:"info"});return}const t=y.peek()?.title||p;if(await E.confirm(`Delete all ${U(e,"submission")} to "${X(t)}", spam included? This cannot be undone - Export them first if you may need them.`))try{await A(`/forms/${C}/submissions`,{method:"DELETE"}),c.value=[],E.toast("All submissions cleared.",{type:"success"}),z("#/forms")}catch(s){E.toast(`Not cleared: ${s.message||s}`,{type:"error"})}}const se=async e=>{const t=Ae(e,k.peek(),{formTitle:y.peek()?.title||p,when:Q(e.meta?.createdAt)});E.toast(await me(t)?"Copied.":"Copy failed.",{type:"info"})},we=async e=>{E.toast(await me(e)?`Copied ${e}.`:"Copy failed.",{type:"info"})},ne=e=>{const t=L(e,k.peek()).email;if(!t)return;const s=`Re: ${y.peek()?.title||p}`;window.location.href=`mailto:${encodeURIComponent(t)}?subject=${encodeURIComponent(s)}`};async function Ee(e,t){try{const s=await fetch(`/api/forms/${C}/submissions/${e}`,{headers:{Authorization:`Bearer ${S.get("auth_token")||""}`}});if(!s.ok)throw new Error(`${s.status} ${s.statusText}`);const n=await s.blob(),a=document.createElement("a");return a.href=URL.createObjectURL(n),a.download=t,document.body.appendChild(a),a.click(),a.remove(),setTimeout(()=>URL.revokeObjectURL(a.href),1e3),!0}catch(s){return E.toast(`Export failed: ${s.message||s}`,{type:"error"}),!1}}const H=new Set;function oe(e,t,s="md"){const n=E.slideover({title:X(e),size:s,position:"right"});n.element.appendChild(t);const a=re(t);return H.add(n),ke(n,()=>{H.delete(n),a()}),I.scan(t),n.open(),n}function ve(){const e=c.peek().length,t=document.createElement("div");t.className="fsx-export";const s=document.createElement("p");s.className="fsx-note",s.textContent=e?`All ${U(e,"submission")}, spam included.`:"There are no submissions yet - the file will be empty.",t.appendChild(s);let n;const a=(N,v,_,J,$)=>{const l=document.createElement("button");l.type="button",l.className="btn btn-ghost";const x=document.createElement("span");x.setAttribute("data-icon",v),l.append(x,document.createTextNode(` ${N}`));const T=document.createElement("span");T.setAttribute("data-help",$),l.addEventListener("click",async()=>{await Ee(_,`${p}-submissions.${J}`)&&n?.close()});const o=document.createElement("div");o.append(l,T),t.appendChild(o)};a("Export as CSV","file-text","export","csv","One row per submission, one column per question - opens in Excel, Numbers or Google Sheets."),a("Export as JSON","code","export/json","json","Every submission exactly as stored, with its id and dates - for importing elsewhere or keeping a full copy."),n=oe("Export submissions",t,"sm")}function W(e){if(!e)return;const t=k.peek(),s=L(e,t),n=document.createElement("div");n.className="fsx-detail";const a=document.createElement("div");a.className="fsx-facts";const N=o=>{const m=document.createElement("span");m.textContent=o,a.appendChild(m)};e.meta?.createdAt&&N(`Sent ${Q(e.meta.createdAt)} (${D(e.meta.createdAt).fromNow()})`),e.meta?.ip&&N(`IP ${e.meta.ip}`),s.spam&&N("Marked as spam"),n.appendChild(a);const v=document.createElement("dl");v.className="fsx-answers";const _=t.filter(o=>O(e.data?.[o.name])!=="");for(const o of _){const m=document.createElement("div");m.className="fsx-answer";const f=document.createElement("dt");f.textContent=o.label;const g=document.createElement("dd");g.textContent=O(e.data[o.name]),m.append(f,g),v.appendChild(m)}const J=new Set(t.map(o=>o.name));for(const[o,m]of Object.entries(e.data||{})){if(J.has(o)||o==="spam"||O(m)==="")continue;const f=document.createElement("div");f.className="fsx-answer";const g=document.createElement("dt");g.textContent=`${o} (no longer on the form)`;const d=document.createElement("dd");d.textContent=O(m),f.append(g,d),v.appendChild(f)}if(v.children.length)n.appendChild(v);else{const o=document.createElement("p");o.className="fsx-note",o.textContent="Nothing was filled in.",n.appendChild(o)}const $=document.createElement("div");$.className="fsx-actions";const l=(o,m,f,g)=>{const d=document.createElement("button");d.type="button",d.className=`btn btn-sm ${f}`;const K=document.createElement("span");return K.setAttribute("data-icon",m),K.setAttribute("data-icon-size","13"),d.append(K,document.createTextNode(` ${o}`)),d.addEventListener("click",g),$.appendChild(d),d};let x;l("Copy","copy","btn-ghost",()=>se(e)),s.email&&l("Email them","mail","btn-ghost",()=>ne(e)),l(s.spam?"Not spam":"Mark as spam",s.spam?"inbox":"alert-triangle","btn-ghost",async()=>{await B(e,!s.spam)&&x.close()});const T=document.createElement("span");T.className="fsx-spacer",$.appendChild(T),l("Delete","trash","btn-ghost text-danger",async()=>{await Y(e)&&x.close()}),l("Close","x","btn-ghost",()=>x.close()),n.appendChild($),x=oe(s.title,n)}function xe(e){const t=R(e);if(!t)return[];const s=L(t,k.peek());return[{header:s.title},{label:"Open\u2026",icon:"eye",action:()=>W(t)},{label:"Copy submission",icon:"copy",action:()=>se(t)},{type:"divider"},{label:s.email?`Copy ${s.email}`:"Copy email",icon:"at-sign",disabled:!s.email,action:()=>we(s.email)},{label:"Email them\u2026",icon:"mail",disabled:!s.email,action:()=>ne(t)},{type:"divider"},s.spam?{label:"Not spam - back to the inbox",icon:"inbox",action:()=>B(t,!1)}:{label:"Mark as spam",icon:"alert-triangle",action:()=>B(t,!0)},{label:"Delete\u2026",icon:"trash",danger:!0,action:()=>Y(t)}]}const u=r.querySelector(".fsx-list");u.innerHTML=De;const ge=M.applyBindings({loading:Z,loadError:q,filter:w,query:te,from:j,to:F,rows:P,counts:de,summary:pe,emptyText:ue,intro:fe},r,{methods:{showInbox:()=>{w.value="inbox"},showNew:()=>{w.value="new"},showSpam:()=>{w.value="spam"},clearDates:()=>{j.value="",F.value=""}}});h.add(()=>ge.dispose()),h.add(re(r,{position:"bottom"}));const Ce=E.contextMenu(u,{cursor:"glyph",match:".fsx-row",inherit:!1,density:"compact",items:e=>xe(e.dataset.id)});h.add(()=>Ce?.destroy?.());const ae=e=>{const t=e.target.closest(".fsx-row");if(!t)return;const s=e.target.closest(".fsx-kebab");if(s){ce(s);return}W(R(t.dataset.id))},ie=e=>{const t=e.target.closest(".fsx-row");if(!(!t||e.target!==t)){if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ce(t);else if(e.key==="Enter")W(R(t.dataset.id));else if(e.key==="Delete"){e.preventDefault();const s=R(t.dataset.id);s&&Y(s)}}};u.addEventListener("click",ae),u.addEventListener("keydown",ie),h.add(()=>{u.removeEventListener("click",ae),u.removeEventListener("keydown",ie)}),V(i,{id:"form-submissions-back",icon:"arrow-left",title:"All forms",onClick:()=>{location.hash="#/forms"}}),V(i,{id:"form-submissions-export",icon:"download",title:"Export (CSV or JSON)",onClick:ve}),V(i,{id:"form-submissions-clear",icon:"trash",title:"Clear all submissions",onClick:ye}),h.add(()=>{[...H].forEach(e=>{try{e.close()}catch{}})}),I.scan(r),await he(),b()&&requestAnimationFrame(()=>{u.isConnected&&I.scan(u)})}};
|
|
11
|
+
</div>`,Y=i=>String(i??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),U=(i,r,b=`${r}s`)=>`${i} ${i===1?r:b}`,Q=i=>i?De(i):"";async function me(i){try{return await navigator.clipboard.writeText(i),!0}catch{}try{const r=document.createElement("textarea");r.value=i,r.style.cssText="position:fixed;opacity:0;",document.body.appendChild(r),r.select();const b=document.execCommand("copy");return r.remove(),b}catch{return!1}}const h=$e(le);export const formSubmissionsView={templateUrl:"/admin/js/templates/form-submissions.html",async onMount(i){h.reset();const r=i.get(0).querySelector(".fsx")||i.get(0),b=()=>le.test(location.hash)&&r.isConnected,p=decodeURIComponent((location.hash.match(/^#\/forms\/([^/?#]+)\/submissions/)||[])[1]||"");if(!p){E.toast("No form selected.",{type:"error"});return}const C=encodeURIComponent(p),y=M.observable(null),c=M.observable([]),Z=M.observable(!0),q=M.observable("");let ee="inbox";try{ee=Se.includes(S.get(X))?S.get(X):"inbox"}catch{}const w=M.observable(ee),te=M.observable(""),j=M.observable(""),F=M.observable("");h.add(M.effect(()=>{const e=w.value;try{S.set(X,e)}catch{}}));const k=M.computed(()=>Ne(y.value||{})),P=M.observable([]);h.add(M.effect(()=>{const e=Date.now(),t=Te(c.value,{filter:w.value,query:te.value,from:j.value,to:F.value,now:e}),s=k.value;P.value=t.map(n=>{const a=L(n,s,e);return{...a,when:a.at?D(a.at).fromNow():"",whenFull:Q(a.at)}})}));const de=M.computed(()=>Me(c.value)),pe=M.computed(()=>{const e=P.value.length,t=c.value.length;return t?e===t?U(t,"submission"):`${e} of ${U(t,"submission")}`:""}),ue=M.computed(()=>c.value.length?w.value==="spam"?"Nothing marked as spam.":"No submissions match.":"No submissions yet - they appear here as people send the form."),fe=M.computed(()=>y.value?`What people sent through "${y.value.title||p}".`:"What people sent through this form."),R=e=>c.peek().find(t=>String(t.id)===String(e));async function he(){try{const[e,t]=await Promise.all([A(`/forms/${C}`),A(`/forms/${C}/submissions`)]);if(!b())return;y.value=e||null,c.value=Array.isArray(t)?t:[],q.value="",be(e?.title||p)}catch(e){if(!b())return;q.value=`Could not load the submissions: ${e.message||e}`}finally{Z.value=!1}}function be(e){const t=i.get(0).querySelector(".dm-plugin-banner-name"),s=t?.lastChild;s&&s.nodeType===Node.TEXT_NODE&&t.querySelector(".dm-plugin-banner-sep")&&(s.textContent=`${e} submissions`),document.title=`${e} - Submissions - Domma CMS`}async function B(e,t){try{const s=await A(`/forms/${C}/submissions/${encodeURIComponent(e.id)}/spam`,{method:"POST",body:JSON.stringify({spam:t})});return c.value=c.peek().map(n=>String(n.id)===String(e.id)?{...n,data:s?.entry?.data||{...n.data,spam:t}}:n),E.toast(t?"Marked as spam - it is under Spam now.":"Back in the inbox.",{type:"success"}),G("#/forms"),!0}catch(s){return E.toast(`Not changed: ${s.message||s}`,{type:"error"}),!1}}async function W(e){const t=L(e,k.peek()).title;if(!await E.confirm(`Delete the submission from "${Y(t)}"? This cannot be undone.`))return!1;try{return await A(`/forms/${C}/submissions/${encodeURIComponent(e.id)}`,{method:"DELETE"}),c.value=c.peek().filter(s=>String(s.id)!==String(e.id)),E.toast("Submission deleted.",{type:"success"}),G("#/forms"),!0}catch(s){return E.toast(`Not deleted: ${s.message||s}`,{type:"error"}),!1}}async function ye(){const e=c.peek().length;if(!e){E.toast("There are no submissions to clear.",{type:"info"});return}const t=y.peek()?.title||p;if(await E.confirm(`Delete all ${U(e,"submission")} to "${Y(t)}", spam included? This cannot be undone - Export them first if you may need them.`))try{await A(`/forms/${C}/submissions`,{method:"DELETE"}),c.value=[],E.toast("All submissions cleared.",{type:"success"}),G("#/forms")}catch(s){E.toast(`Not cleared: ${s.message||s}`,{type:"error"})}}const se=async e=>{const t=Ae(e,k.peek(),{formTitle:y.peek()?.title||p,when:Q(e.meta?.createdAt)});E.toast(await me(t)?"Copied.":"Copy failed.",{type:"info"})},we=async e=>{E.toast(await me(e)?`Copied ${e}.`:"Copy failed.",{type:"info"})},ne=e=>{const t=L(e,k.peek()).email;if(!t)return;const s=`Re: ${y.peek()?.title||p}`;window.location.href=`mailto:${encodeURIComponent(t)}?subject=${encodeURIComponent(s)}`};async function Ee(e,t){try{const s=await fetch(`/api/forms/${C}/submissions/${e}`,{headers:{Authorization:`Bearer ${S.get("auth_token")||""}`}});if(!s.ok)throw new Error(`${s.status} ${s.statusText}`);const n=await s.blob(),a=document.createElement("a");return a.href=URL.createObjectURL(n),a.download=t,document.body.appendChild(a),a.click(),a.remove(),setTimeout(()=>URL.revokeObjectURL(a.href),1e3),!0}catch(s){return E.toast(`Export failed: ${s.message||s}`,{type:"error"}),!1}}const _=new Set;function oe(e,t,s="md"){const n=E.slideover({title:Y(e),size:s,position:"right"});n.element.appendChild(t);const a=re(t);return _.add(n),ke(n,()=>{_.delete(n),a()}),I.scan(t),n.open(),n}function ve(){const e=c.peek().length,t=document.createElement("div");t.className="fsx-export";const s=document.createElement("p");s.className="fsx-note",s.textContent=e?`All ${U(e,"submission")}, spam included.`:"There are no submissions yet - the file will be empty.",t.appendChild(s);let n;const a=(N,v,K,V,$)=>{const l=document.createElement("button");l.type="button",l.className="btn btn-ghost";const x=document.createElement("span");x.setAttribute("data-icon",v),l.append(x,document.createTextNode(` ${N}`));const T=document.createElement("span");T.setAttribute("data-help",$),l.addEventListener("click",async()=>{await Ee(K,`${p}-submissions.${V}`)&&n?.close()});const o=document.createElement("div");o.append(l,T),t.appendChild(o)};a("Export as CSV","file-text","export","csv","One row per submission, one column per question - opens in Excel, Numbers or Google Sheets."),a("Export as JSON","code","export/json","json","Every submission exactly as stored, with its id and dates - for importing elsewhere or keeping a full copy."),n=oe("Export submissions",t,"sm")}function J(e){if(!e)return;const t=k.peek(),s=L(e,t),n=document.createElement("div");n.className="fsx-detail";const a=document.createElement("div");a.className="fsx-facts";const N=o=>{const m=document.createElement("span");m.textContent=o,a.appendChild(m)};e.meta?.createdAt&&N(`Sent ${Q(e.meta.createdAt)} (${D(e.meta.createdAt).fromNow()})`),e.meta?.ip&&N(`IP ${e.meta.ip}`),s.spam&&N("Marked as spam"),n.appendChild(a);const v=document.createElement("dl");v.className="fsx-answers";const K=t.filter(o=>O(e.data?.[o.name])!=="");for(const o of K){const m=document.createElement("div");m.className="fsx-answer";const f=document.createElement("dt");f.textContent=o.label;const g=document.createElement("dd");g.textContent=O(e.data[o.name]),m.append(f,g),v.appendChild(m)}const V=new Set(t.map(o=>o.name));for(const[o,m]of Object.entries(e.data||{})){if(V.has(o)||o==="spam"||O(m)==="")continue;const f=document.createElement("div");f.className="fsx-answer";const g=document.createElement("dt");g.textContent=`${o} (no longer on the form)`;const d=document.createElement("dd");d.textContent=O(m),f.append(g,d),v.appendChild(f)}if(v.children.length)n.appendChild(v);else{const o=document.createElement("p");o.className="fsx-note",o.textContent="Nothing was filled in.",n.appendChild(o)}const $=document.createElement("div");$.className="fsx-actions";const l=(o,m,f,g)=>{const d=document.createElement("button");d.type="button",d.className=`btn btn-sm ${f}`;const z=document.createElement("span");return z.setAttribute("data-icon",m),z.setAttribute("data-icon-size","13"),d.append(z,document.createTextNode(` ${o}`)),d.addEventListener("click",g),$.appendChild(d),d};let x;l("Copy","copy","btn-ghost",()=>se(e)),s.email&&l("Email them","mail","btn-ghost",()=>ne(e)),l(s.spam?"Not spam":"Mark as spam",s.spam?"inbox":"alert-triangle","btn-ghost",async()=>{await B(e,!s.spam)&&x.close()});const T=document.createElement("span");T.className="fsx-spacer",$.appendChild(T),l("Delete","trash","btn-ghost text-danger",async()=>{await W(e)&&x.close()}),l("Close","x","btn-ghost",()=>x.close()),n.appendChild($),x=oe(s.title,n)}function xe(e){const t=R(e);if(!t)return[];const s=L(t,k.peek());return[{header:s.title},{label:"Open\u2026",icon:"eye",action:()=>J(t)},{label:"Copy submission",icon:"copy",action:()=>se(t)},{type:"divider"},{label:s.email?`Copy ${s.email}`:"Copy email",icon:"at-sign",disabled:!s.email,action:()=>we(s.email)},{label:"Email them\u2026",icon:"mail",disabled:!s.email,action:()=>ne(t)},{type:"divider"},s.spam?{label:"Not spam - back to the inbox",icon:"inbox",action:()=>B(t,!1)}:{label:"Mark as spam",icon:"alert-triangle",action:()=>B(t,!0)},{label:"Delete\u2026",icon:"trash",danger:!0,action:()=>W(t)}]}const u=r.querySelector(".fsx-list");u.innerHTML=Le;const ge=M.applyBindings({loading:Z,loadError:q,filter:w,query:te,from:j,to:F,rows:P,counts:de,summary:pe,emptyText:ue,intro:fe},r,{methods:{showInbox:()=>{w.value="inbox"},showNew:()=>{w.value="new"},showSpam:()=>{w.value="spam"},clearDates:()=>{j.value="",F.value=""}}});h.add(()=>ge.dispose()),h.add(re(r,{position:"bottom"}));const Ce=E.contextMenu(u,{cursor:"glyph",match:".fsx-row",inherit:!1,density:"compact",items:e=>xe(e.dataset.id)});h.add(()=>Ce?.destroy?.());const ae=e=>{const t=e.target.closest(".fsx-row");if(!t)return;const s=e.target.closest(".fsx-kebab");if(s){ce(s);return}J(R(t.dataset.id))},ie=e=>{const t=e.target.closest(".fsx-row");if(!(!t||e.target!==t)){if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ce(t);else if(e.key==="Enter")J(R(t.dataset.id));else if(e.key==="Delete"){e.preventDefault();const s=R(t.dataset.id);s&&W(s)}}};u.addEventListener("click",ae),u.addEventListener("keydown",ie),h.add(()=>{u.removeEventListener("click",ae),u.removeEventListener("keydown",ie)}),H(i,{id:"form-submissions-back",icon:"arrow-left",title:"All forms",onClick:()=>{location.hash="#/forms"}}),H(i,{id:"form-submissions-export",icon:"download",title:"Export (CSV or JSON)",onClick:ve}),H(i,{id:"form-submissions-clear",icon:"trash",title:"Clear all submissions",onClick:ye}),h.add(()=>{[..._].forEach(e=>{try{e.close()}catch{}})}),I.scan(r),await he(),b()&&requestAnimationFrame(()=>{u.isConnected&&I.scan(u)})}};
|
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";import{settingsView as t}from"./settings.js";import{themeView as e}from"./theme.js";import{notificationsView as m}from"./notifications.js";import{layoutsView as p}from"./layouts.js";import{mediaView as
|
|
1
|
+
import{dashboardView as o}from"./dashboard.js";import{pagesView as i}from"./pages.js";import{pageEditorView as r}from"./page-editor.js";import{settingsView as t}from"./settings.js";import{themeView as e}from"./theme.js";import{notificationsView as m}from"./notifications.js";import{layoutsView as p}from"./layouts.js";import{mediaView as n}from"./media.js";import{loginView as s}from"./login.js";import{usersView as f}from"./users.js";import{userEditorView as w}from"./user-editor.js";import{pluginsView as c}from"./plugins.js";import{pluginCodeView as V}from"./plugin-code.js";import{documentationView as d}from"./documentation.js";import{tutorialsView as a}from"./tutorials.js";import{docViews as l}from"./doc-pages.js";import{pluginGuidesView as u,pluginGuideView as E}from"./plugin-guides.js";import{apiReferenceView as g}from"./api-reference.js";import{collectionsView as v}from"./collections.js";import{collectionEditorView as b}from"./collection-editor.js";import{collectionEntriesView as h}from"./collection-entries.js";import{formsView as y}from"./forms.js";import{formEditorView as j}from"./form-editor.js";import{formSubmissionsView as k}from"./form-submissions.js";import{viewsListView as L}from"./views-list.js";import{viewEditorView as x}from"./view-editor.js";import{viewPreviewView as M}from"./view-preview.js";import{actionsListView as D}from"./actions-list.js";import{actionEditorView as G}from"./action-editor.js";import{proDocsView as P}from"./pro-docs.js";import{blocksView as R}from"./blocks.js";import{blockEditorView as S}from"./block-editor.js";import{componentsView as C}from"./components.js";import{componentEditorView as T}from"./component-editor.js";import{myProfileView as U}from"./my-profile.js";import{rolesView as q}from"./roles.js";import{roleEditorView as z}from"./role-editor.js";import{effectsView as A}from"./effects.js";import{searchView as B}from"./search.js";import{notesView as F}from"./notes.js";import{todoView as H}from"./todo.js";import{analyticsView as I}from"./analytics.js";import{seoView as J}from"./seo.js";import{contactsView as K}from"./contacts.js";import{menusView as N}from"./menus.js";import{contextMenusView as O}from"./context-menus.js";import{contextMenuEditorView as Q}from"./context-menu-editor.js";import{menuEditorView as W}from"./menu-editor.js";import{menuLocationsView as X}from"./menu-locations.js";import{projectsView as Y}from"./projects.js";import{projectDetailView as Z}from"./project-detail.js";import{projectSettingsView as _}from"./project-settings.js";import{apiTokensView as $}from"./api-tokens.js";import{apiEndpointsView as oo}from"./api-endpoints.js";import{apiEndpointEditorView as io}from"./api-endpoint-editor.js";const ro={templateUrl:"",async onMount(){location.hash="#/menus"}};export const views={projects:Y,projectDetail:Z,projectSettings:_,apiTokens:$,apiEndpoints:oo,apiEndpointEditor:io,dashboard:o,pages:i,pageEditor:r,settings:t,theme:e,layouts:p,media:n,login:s,users:f,userEditor:w,plugins:c,pluginCode:V,documentation:d,tutorials:a,apiReference:g,collections:v,collectionEditor:b,collectionEntries:h,forms:y,formEditor:j,formSubmissions:k,viewsList:L,viewEditor:x,viewPreview:M,actionsList:D,actionEditor:G,proDocs:P,blocks:R,blockEditor:S,components:C,componentEditor:T,myProfile:U,roles:q,roleEditor:z,effects:A,search:B,notes:F,todo:H,analytics:I,seo:J,contacts:K,notifications:m,menus:N,contextMenus:O,contextMenuEditor:Q,menuEditor:W,menuLocations:X,menusRedirect:ro,pluginGuides:u,pluginGuide:E,...l};
|