domma-cms 0.9.1 → 0.9.6

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.
Files changed (43) hide show
  1. package/admin/js/templates/block-editor.html +163 -163
  2. package/admin/js/templates/form-editor.html +245 -245
  3. package/admin/js/views/action-editor.js +1 -1
  4. package/admin/js/views/block-editor.js +8 -8
  5. package/admin/js/views/collection-editor.js +4 -4
  6. package/admin/js/views/collections.js +1 -1
  7. package/admin/js/views/form-editor.js +7 -7
  8. package/admin/js/views/forms.js +1 -1
  9. package/admin/js/views/navigation.js +14 -14
  10. package/admin/js/views/page-editor.js +35 -35
  11. package/admin/js/views/pages.js +5 -5
  12. package/admin/js/views/plugins.js +13 -10
  13. package/admin/js/views/view-editor.js +1 -1
  14. package/config/plugins.json +25 -0
  15. package/package.json +1 -1
  16. package/plugins/docs/data/documents/57e003f0-68f2-47dc-9c36-ed4b10ed3deb.json +4 -4
  17. package/plugins/docs/data/folders.json +3 -3
  18. package/plugins/docs/data/versions/57e003f0-68f2-47dc-9c36-ed4b10ed3deb/1.json +5 -0
  19. package/plugins/garage/admin/templates/garage.html +30 -0
  20. package/plugins/garage/admin/views/garage.js +62 -1
  21. package/plugins/garage/plugin.json +1 -1
  22. package/plugins/notes/admin/templates/notes.html +2 -11
  23. package/plugins/notes/admin/views/notes.js +108 -129
  24. package/plugins/notes/collections/user-notes/schema.json +2 -1
  25. package/plugins/notes/plugin.json +1 -1
  26. package/plugins/site-search/admin/templates/site-search.html +174 -46
  27. package/plugins/site-search/admin/views/site-search.js +72 -1
  28. package/plugins/site-search/config.js +6 -1
  29. package/plugins/site-search/plugin.json +1 -1
  30. package/plugins/site-search/public/inject-head.html +1 -1
  31. package/plugins/site-search/public/search.css +1 -1
  32. package/plugins/site-search/public/search.js +1 -1
  33. package/plugins/todo/admin/templates/todo.html +2 -8
  34. package/plugins/todo/admin/views/todo.js +123 -106
  35. package/plugins/todo/collections/todos/schema.json +2 -1
  36. package/plugins/todo/plugin.json +1 -1
  37. package/server/routes/api/media.js +127 -118
  38. package/server/routes/api/plugins.js +15 -4
  39. package/server/server.js +288 -285
  40. package/server/services/collections.js +17 -10
  41. package/server/services/plugins.js +77 -67
  42. package/server/services/renderer.js +3 -3
  43. package/plugins/docs/data/documents/452f49b7-9c93-4a67-874d-27f882891ad2.json +0 -11
@@ -1,8 +1,8 @@
1
- import{api as m}from"../api.js";let u=null;export const blockEditorView={templateUrl:"/admin/js/templates/block-editor.html",async onMount(e){u=null;const s=window.location.hash.match(/\/blocks\/edit\/([^/?#]+)/);s&&(u=decodeURIComponent(s[1]));const i=e.find("#block-name").get(0),n=e.find("#block-content").get(0);if(u){e.find("#block-editor-title").text("Edit Block"),i&&(i.value=u,i.disabled=!0);try{const c=await m.blocks.get(u);n&&(n.value=c.content||""),e.find("#block-bundled").prop("checked",!!c.bundled)}catch(c){E.toast(c.message||"Block not found.",{type:"error"}),R.navigate("/blocks");return}}n&&(v(n,e),w(n,e)),e.find("#save-block-btn").off("click").on("click",async()=>{await L(e)}),Domma.icons.scan()}};function v(e,t){const s=t.find("#block-line-numbers").get(0),i=t.find("#block-cursor-pos").get(0);function n(){const l=e.value.split(`
2
- `).length;s.textContent=Array.from({length:l},(o,r)=>r+1).join(`
3
- `),s.scrollTop=e.scrollTop}n(),e.addEventListener("input",n),e.addEventListener("scroll",()=>{s.scrollTop=e.scrollTop});function c(){if(!i)return;const o=e.value.slice(0,e.selectionStart).split(`
4
- `);i.textContent=`Ln ${o.length}, Col ${o[o.length-1].length+1}`}e.addEventListener("keyup",c),e.addEventListener("click",c),e.addEventListener("keydown",l=>{if(l.key==="Tab"){l.preventDefault();const o=e.selectionStart,r=e.selectionEnd;if(!l.shiftKey)e.value=e.value.slice(0,o)+" "+e.value.slice(r),e.selectionStart=e.selectionEnd=o+2;else{const a=e.value.lastIndexOf(`
5
- `,o-1)+1,p=e.value.slice(a,a+2),f=p===" "?2:p[0]===" "?1:0;f>0&&(e.value=e.value.slice(0,a)+e.value.slice(a+f),e.selectionStart=e.selectionEnd=Math.max(a,o-f))}e.dispatchEvent(new Event("input"))}if(l.key==="Enter"){l.preventDefault();const o=e.selectionStart,r=e.value.lastIndexOf(`
6
- `,o-1)+1,a=e.value.slice(r,o).match(/^(\s*)/)[1];e.value=e.value.slice(0,o)+`
7
- `+a+e.value.slice(e.selectionEnd),e.selectionStart=e.selectionEnd=o+1+a.length,e.dispatchEvent(new Event("input"))}});const d=t.find("#block-editor-toolbar").get(0);d&&d.addEventListener("click",l=>{const o=l.target.closest("[data-action]");o&&(b(o.dataset.action,e),e.focus())})}function b(e,t){switch(e){case"undo":document.execCommand("undo");break;case"redo":document.execCommand("redo");break;case"cut":t.selectionStart!==t.selectionEnd&&(navigator.clipboard.writeText(t.value.slice(t.selectionStart,t.selectionEnd)).catch(()=>{}),document.execCommand("cut"));break;case"copy":t.selectionStart!==t.selectionEnd&&navigator.clipboard.writeText(t.value.slice(t.selectionStart,t.selectionEnd)).catch(()=>{});break;case"paste":navigator.clipboard.readText().then(s=>{const i=t.selectionStart;t.value=t.value.slice(0,i)+s+t.value.slice(t.selectionEnd),t.selectionStart=t.selectionEnd=i+s.length,t.dispatchEvent(new Event("input"))}).catch(()=>E.toast("Use Ctrl+V to paste.",{type:"info"}));break;case"select-all":t.select();break;case"format":g(t);break}}function g(e){const t=e.value.match(/(<[^>]+>|[^<]+)/g)||[],s=[];let i=0;const n=" ";for(const l of t){const o=l.trim();if(o)if(o.startsWith("</"))i=Math.max(0,i-1),s.push(n.repeat(i)+o);else if(o.startsWith("<")&&!o.startsWith("<!")&&!o.endsWith("/>")){s.push(n.repeat(i)+o);const r=(o.match(/^<(\w+)/)||[])[1]||"";k.has(r.toLowerCase())||i++}else s.push(n.repeat(i)+o)}const c=s.join(`
8
- `),d=e.selectionStart;e.value=c,e.selectionStart=e.selectionEnd=Math.min(d,c.length),e.dispatchEvent(new Event("input"))}const k=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);function w(e,t){const s=t.find("#block-editor-body").get(0),i=t.find("#block-sample-data").get(0),n=t.find("#block-preview-output");t.find("[data-mode]").each(function(){this.addEventListener("click",()=>{t.find("[data-mode]").each(function(){this.classList.remove("active")}),this.classList.add("active"),s.className=`editor-body editor-mode-${this.dataset.mode}`,this.dataset.mode!=="write"&&c()})}),e.addEventListener("input",()=>{h(i,e),c()}),e.value.trim()&&h(i,e);function c(){if(!!s.classList.contains("editor-mode-write"))return;const l=e.value.replace(/\{\{([\w_]+)\}\}/g,(o,r)=>{const a=i.querySelector(`[data-placeholder="${CSS.escape(r)}"]`);return C(a?.value??`[${r}]`)});n.html(l,{safe:!1}),Domma.icons.scan(n.get(0))}i._renderPreview=c}function h(e,t){const s=y(t.value),i=new Set([...e.querySelectorAll("[data-placeholder]")].map(n=>n.dataset.placeholder));if(s.size>0&&e.querySelector("p.text-muted")?.remove(),s.forEach(n=>{i.has(n)||S(e,n)}),e.querySelectorAll("[data-placeholder]").forEach(n=>{s.has(n.dataset.placeholder)||n.closest(".block-sample-row")?.remove()}),s.size===0&&!e.querySelector("p.text-muted")){const n=document.createElement("p");n.className="text-muted",n.style.cssText="font-size:.8rem;margin:0;",n.textContent="No {{placeholders}} detected in template.",e.appendChild(n)}}function S(e,t){const s=document.createElement("div");s.className="block-sample-row",s.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.35rem;";const i=document.createElement("label");i.style.cssText="font-size:.75rem;color:var(--dm-text-muted,#888);white-space:nowrap;min-width:90px;text-align:right;flex-shrink:0;",i.textContent=`{{${t}}}`;const n=document.createElement("input");n.type="text",n.className="form-input form-input--sm",n.style.flex="1",n.dataset.placeholder=t,n.placeholder=`Sample ${t}`,n.value=x(t),n.addEventListener("input",()=>{e._renderPreview&&e._renderPreview()}),s.appendChild(i),s.appendChild(n),e.appendChild(s)}function x(e){const t=e.toLowerCase();return t==="_id"?"a1b2c3d4-e5f6-7890-abcd-ef1234567890":t==="_createdat"?new Date().toISOString():t==="_updatedat"?new Date().toISOString():t.includes("email")?"user@example.com":t.includes("phone")?"+44 7700 900000":t.includes("name")?"Jane Smith":t.includes("title")?"Sample Title":t.includes("message")||t.includes("content")||t.includes("description")?"This is a sample value for preview purposes.":t.includes("rating")?"excellent":t.includes("status")?"active":t.includes("priority")?"high":t.includes("date")?new Date().toLocaleDateString():t.includes("tag")?"tag1, tag2":t.includes("subject")?"Sample Subject":t.includes("category")?"general":`Sample ${e}`}function y(e){const t=new Set;for(const[,s]of e.matchAll(/\{\{([\w_]+)\}\}/g))t.add(s);return t}function C(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function L(e){const t=e.find("#block-name").get(0),s=e.find("#block-content").get(0),i=(t?.value||"").trim(),n=s?.value??"";if(!i){E.toast("Block name is required.",{type:"warning"});return}if(!/^[a-z0-9][a-z0-9-]*$/.test(i)){E.toast("Name must start with a letter or digit and contain only lowercase letters, digits, and hyphens.",{type:"warning"});return}const c=e.find("#save-block-btn").get(0);c&&(c.disabled=!0);try{const d=!!e.find("#block-bundled").is(":checked");await m.blocks.put(i,{content:n,bundled:d}),E.toast(u?"Block updated.":"Block created.",{type:"success"}),u||(u=i,R.navigate(`/blocks/edit/${encodeURIComponent(i)}`))}catch(d){E.toast(d.message||"Failed to save block.",{type:"error"})}finally{c&&(c.disabled=!1)}}
1
+ import{api as h}from"../api.js";let u=null;export const blockEditorView={templateUrl:"/admin/js/templates/block-editor.html",async onMount(e){u=null;const t=window.location.hash.match(/\/blocks\/edit\/([^/?#]+)/);t&&(u=decodeURIComponent(t[1]));const c=e.find("#block-name").get(0),a=e.find("#block-content").get(0);if(u){e.find("#block-editor-title").text("Edit Block"),c&&(c.value=u,c.disabled=!0);try{const n=await h.blocks.get(u);a&&(a.value=n.content||""),e.find("#block-bundled").prop("checked",!!n.bundled)}catch(n){E.toast(n.message||"Block not found.",{type:"error"}),R.navigate("/blocks");return}}a&&(v(a,e),w(a,e)),e.find("#save-block-btn").off("click").on("click",async()=>{await L(e)}),Domma.icons.scan()}};function v(e,t){const c=t.find("#block-line-numbers").get(0),a=t.find("#block-cursor-pos").get(0);function n(){const s=e.value.split(`
2
+ `).length;c.textContent=Array.from({length:s},(o,r)=>r+1).join(`
3
+ `),c.scrollTop=e.scrollTop}n(),e.addEventListener("input",n),e.addEventListener("scroll",()=>{c.scrollTop=e.scrollTop});function l(){if(!a)return;const s=e.value.slice(0,e.selectionStart).split(`
4
+ `);a.textContent=`Ln ${s.length}, Col ${s[s.length-1].length+1}`}e.addEventListener("keyup",l),e.addEventListener("click",l),e.addEventListener("keydown",s=>{if(s.key==="Tab"){s.preventDefault();const o=e.selectionStart,r=e.selectionEnd;if(!s.shiftKey)e.value=e.value.slice(0,o)+" "+e.value.slice(r),e.selectionStart=e.selectionEnd=o+2;else{const d=e.value.lastIndexOf(`
5
+ `,o-1)+1,m=e.value.slice(d,d+2),p=m===" "?2:m[0]===" "?1:0;p>0&&(e.value=e.value.slice(0,d)+e.value.slice(d+p),e.selectionStart=e.selectionEnd=Math.max(d,o-p))}e.dispatchEvent(new Event("input"))}if(s.key==="Enter"){s.preventDefault();const o=e.selectionStart,r=e.value.lastIndexOf(`
6
+ `,o-1)+1,d=e.value.slice(r,o).match(/^(\s*)/)[1];e.value=e.value.slice(0,o)+`
7
+ `+d+e.value.slice(e.selectionEnd),e.selectionStart=e.selectionEnd=o+1+d.length,e.dispatchEvent(new Event("input"))}});const i=t.find("#block-editor-toolbar").get(0);i&&i.addEventListener("click",s=>{const o=s.target.closest("[data-action]");o&&(b(o.dataset.action,e),e.focus())})}function b(e,t){switch(e){case"undo":document.execCommand("undo");break;case"redo":document.execCommand("redo");break;case"cut":t.selectionStart!==t.selectionEnd&&(navigator.clipboard.writeText(t.value.slice(t.selectionStart,t.selectionEnd)).catch(()=>{}),document.execCommand("cut"));break;case"copy":t.selectionStart!==t.selectionEnd&&navigator.clipboard.writeText(t.value.slice(t.selectionStart,t.selectionEnd)).catch(()=>{});break;case"paste":navigator.clipboard.readText().then(c=>{const a=t.selectionStart;t.value=t.value.slice(0,a)+c+t.value.slice(t.selectionEnd),t.selectionStart=t.selectionEnd=a+c.length,t.dispatchEvent(new Event("input"))}).catch(()=>E.toast("Use Ctrl+V to paste.",{type:"info"}));break;case"select-all":t.select();break;case"format":g(t);break}}function g(e){const t=e.value.match(/(<[^>]+>|[^<]+)/g)||[],c=[];let a=0;const n=" ";for(const s of t){const o=s.trim();if(o)if(o.startsWith("</"))a=Math.max(0,a-1),c.push(n.repeat(a)+o);else if(o.startsWith("<")&&!o.startsWith("<!")&&!o.endsWith("/>")){c.push(n.repeat(a)+o);const r=(o.match(/^<(\w+)/)||[])[1]||"";k.has(r.toLowerCase())||a++}else c.push(n.repeat(a)+o)}const l=c.join(`
8
+ `),i=e.selectionStart;e.value=l,e.selectionStart=e.selectionEnd=Math.min(i,l.length),e.dispatchEvent(new Event("input"))}const k=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);function w(e,t){const c=t.find("#block-editor-body").get(0),a=t.find("#block-sample-data").get(0),n=t.find("#block-preview-output");t.find("[data-mode]").each(function(){this.addEventListener("click",()=>{t.find("[data-mode]").each(function(){this.classList.remove("active")}),this.classList.add("active"),c.className=`editor-body editor-mode-${this.dataset.mode}`,this.dataset.mode!=="write"&&l()})}),e.addEventListener("input",()=>{f(a,e),l()}),e.value.trim()&&f(a,e);function l(){if(c.classList.contains("editor-mode-write"))return;const i=e.value.replace(/\{\{([\w_]+)\}\}/g,(s,o)=>{const r=a.querySelector(`[data-placeholder="${CSS.escape(o)}"]`);return C(r?.value??`[${o}]`)});n.html(i,{safe:!1}),Domma.icons.scan(n.get(0))}a._renderPreview=l}function f(e,t){const c=x(t.value),a=new Set([...e.querySelectorAll("[data-placeholder]")].map(n=>n.dataset.placeholder));if(c.size>0&&e.querySelector("p.text-muted")?.remove(),c.forEach(n=>{a.has(n)||y(e,n)}),e.querySelectorAll("[data-placeholder]").forEach(n=>{c.has(n.dataset.placeholder)||n.closest(".block-sample-row")?.remove()}),c.size===0&&!e.querySelector("p.text-muted")){const n=document.createElement("p");n.className="text-muted",n.style.cssText="font-size:.8rem;margin:0;",n.textContent="No {{placeholders}} detected in template.",e.appendChild(n)}}function y(e,t){const c=document.createElement("div");c.className="block-sample-row",c.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.35rem;";const a=document.createElement("label");a.style.cssText="font-size:.75rem;color:var(--dm-text-muted,#888);white-space:nowrap;min-width:90px;text-align:right;flex-shrink:0;",a.textContent=`{{${t}}}`;const n=document.createElement("input");n.type="text",n.className="form-input form-input--sm",n.style.flex="1",n.dataset.placeholder=t,n.placeholder=`Sample ${t}`,n.value=S(t),n.addEventListener("input",()=>{e._renderPreview&&e._renderPreview()}),c.appendChild(a),c.appendChild(n),e.appendChild(c)}function S(e){const t=e.toLowerCase();return t==="_id"?"a1b2c3d4-e5f6-7890-abcd-ef1234567890":t==="_createdat"?new Date().toISOString():t==="_updatedat"?new Date().toISOString():t.includes("email")?"user@example.com":t.includes("phone")?"+44 7700 900000":t.includes("name")?"Jane Smith":t.includes("title")?"Sample Title":t.includes("message")||t.includes("content")||t.includes("description")?"This is a sample value for preview purposes.":t.includes("rating")?"excellent":t.includes("status")?"active":t.includes("priority")?"high":t.includes("date")?new Date().toLocaleDateString():t.includes("tag")?"tag1, tag2":t.includes("subject")?"Sample Subject":t.includes("category")?"general":`Sample ${e}`}function x(e){const t=new Set;for(const[,c]of e.matchAll(/\{\{([\w_]+)\}\}/g))t.add(c);return t}function C(e){return String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}async function L(e){const t=e.find("#block-name").get(0),c=e.find("#block-content").get(0),a=(t?.value||"").trim(),n=c?.value??"";if(!a){E.toast("Block name is required.",{type:"warning"});return}if(!/^[a-z0-9][a-z0-9-]*$/.test(a)){E.toast("Name must start with a letter or digit and contain only lowercase letters, digits, and hyphens.",{type:"warning"});return}const l=!!e.find("#block-bundled").is(":checked"),i=e.find("#save-block-btn").get(0);i&&(i.disabled=!0);try{await h.blocks.put(a,{content:n,bundled:l}),E.toast(u?"Block updated.":"Block created.",{type:"success"}),u||(u=a,R.navigate(`/blocks/edit/${encodeURIComponent(a)}`))}catch(s){E.toast(s.message||"Failed to save block.",{type:"error"})}finally{i&&(i.disabled=!1)}}
@@ -1,5 +1,5 @@
1
- import{api as S}from"../api.js";const Z=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"hidden",label:"Hidden field"}],Q=new Set(["select","radio","checkbox-group"]),ae=["public","subscriber","editor","manager","admin"],ee=["create","read","update","delete"];let f=[],y=null,q=!0,M=null,I="file";function te(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function le(e){return Z.find(t=>t.value===e)?.label||e}function ne(e){const t={...f[e]},a=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),i=document.getElementById(`fb-type-${e}`),p=document.getElementById(`fb-required-${e}`),r=document.getElementById(`fb-placeholder-${e}`),l=document.getElementById(`fb-helper-${e}`);if(a&&(t.label=a.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),i&&(t.type=i.value||t.type),p&&(t.required=p.checked),r&&(t.placeholder=r.value.trim()),l&&(t.helper=l.value.trim()),Q.has(t.type)){const c=document.getElementById(`fb-options-${e}`);c&&(t.options=c.value.split(`
2
- `).filter(g=>g.trim()).map(g=>{const[b,...u]=g.split(":");return{value:b.trim(),label:u.join(":").trim()||b.trim()}}))}const o=document.getElementById(`fb-span-${e}`);if(document.getElementById(`fb-fullwidth-${e}`)?.checked)t.fullWidth=!0,delete t.span;else{delete t.fullWidth;const c=parseInt(o?.value,10);c>1?t.span=c:delete t.span}return t}function X(){return f.map((e,t)=>ne(t))}function oe(e,t){const a=document.createElement("div");a.className="fb-field-card",a.dataset.index=t,a.style.cssText="border:1px solid var(--border-color,#333);border-radius:8px;margin-bottom:.75rem;overflow:hidden;";const n=document.createElement("div");n.className="fb-field-header",n.style.cssText="display:flex;align-items:center;gap:.5rem;padding:.6rem .75rem;background:var(--card-header-bg,rgba(255,255,255,.03));cursor:pointer;user-select:none;";const i=document.createElement("span");i.textContent="\u283F",i.style.cssText="cursor:grab;opacity:.4;font-size:1.1rem;flex-shrink:0;",a.draggable=!0,i.addEventListener("mousedown",()=>{a.draggable=!0}),a.addEventListener("dragstart",s=>{M=t,s.dataTransfer.effectAllowed="move",a.style.opacity="0.4"}),a.addEventListener("dragend",()=>{a.style.opacity="",document.querySelectorAll(".fb-field-card").forEach(s=>s.classList.remove("fb-drag-over"))}),a.addEventListener("dragover",s=>{s.preventDefault(),s.dataTransfer.dropEffect="move",document.querySelectorAll(".fb-field-card").forEach(L=>L.classList.remove("fb-drag-over")),a.classList.add("fb-drag-over")}),a.addEventListener("dragleave",()=>{a.classList.remove("fb-drag-over")}),a.addEventListener("drop",s=>{if(s.preventDefault(),a.classList.remove("fb-drag-over"),M===null||M===t)return;f=X();const[L]=f.splice(M,1);f.splice(t,0,L),M=null,_(document.getElementById("fields-list"))});const p=document.createElement("span");p.className="fb-field-summary",p.style.cssText="flex:1;font-weight:500;font-size:.9rem;",p.textContent=e.label||"(Untitled field)";const r=document.createElement("span");r.style.cssText="font-size:.75rem;opacity:.5;",r.textContent=le(e.type);const l=document.createElement("span");l.className="fb-field-chevron",l.textContent="\u25BE",l.style.cssText="opacity:.5;transition:transform .2s;";const o=document.createElement("button");o.type="button",o.textContent="\xD7",o.className="btn btn-sm",o.style.cssText="padding:.15rem .45rem;line-height:1;font-size:1rem;opacity:.6;",o.title="Remove field",o.addEventListener("click",s=>{s.stopPropagation(),f.splice(t,1),_(document.getElementById("fields-list"))}),n.appendChild(i),n.appendChild(p),n.appendChild(r),n.appendChild(l),n.appendChild(o);const d=document.createElement("div");d.className="fb-field-body",d.style.cssText="padding:.75rem;display:none;";const c=document.createElement("div");c.style.cssText="display:grid;grid-template-columns:1fr 1fr 1fr;gap:.6rem;margin-bottom:.6rem;";const g=document.createElement("div"),b=document.createElement("label");b.className="form-label",b.textContent="Label";const u=document.createElement("input");u.id=`fb-label-${t}`,u.type="text",u.className="form-input",u.value=e.label||"",u.addEventListener("input",()=>{p.textContent=u.value.trim()||"(Untitled field)";const s=document.getElementById(`fb-name-${t}`);s&&!s.dataset.manual&&(s.value=te(u.value).replace(/-/g,"_"))}),g.appendChild(b),g.appendChild(u);const m=document.createElement("div"),k=document.createElement("label");k.className="form-label",k.textContent="Name (key)";const h=document.createElement("input");h.id=`fb-name-${t}`,h.type="text",h.className="form-input",h.value=e.name||"",h.addEventListener("input",()=>{h.dataset.manual="1"}),m.appendChild(k),m.appendChild(h);const v=document.createElement("div"),w=document.createElement("label");w.className="form-label",w.textContent="Type";const C=document.createElement("select");C.id=`fb-type-${t}`,C.className="form-input",Z.forEach(s=>{const L=document.createElement("option");L.value=s.value,L.textContent=s.label,s.value===e.type&&(L.selected=!0),C.appendChild(L)}),C.addEventListener("change",()=>{r.textContent=le(C.value);const s=d.querySelector(".fb-options-wrap");s&&(s.style.display=Q.has(C.value)?"":"none")}),v.appendChild(w),v.appendChild(C),c.appendChild(g),c.appendChild(m),c.appendChild(v);const B=document.createElement("div");B.style.cssText="display:grid;grid-template-columns:1fr 1fr auto;gap:.6rem;align-items:end;margin-bottom:.6rem;";const T=document.createElement("div"),j=document.createElement("label");j.className="form-label",j.textContent="Placeholder";const A=document.createElement("input");A.id=`fb-placeholder-${t}`,A.type="text",A.className="form-input",A.value=e.placeholder||"",T.appendChild(j),T.appendChild(A);const V=document.createElement("div"),Y=document.createElement("label");Y.className="form-label",Y.textContent="Helper text";const W=document.createElement("input");W.id=`fb-helper-${t}`,W.type="text",W.className="form-input",W.value=e.helper||"",V.appendChild(Y),V.appendChild(W);const H=document.createElement("div");H.style.cssText="padding-bottom:.35rem;";const z=document.createElement("label");z.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const P=document.createElement("input");P.id=`fb-required-${t}`,P.type="checkbox",P.checked=!!e.required,z.appendChild(P),z.appendChild(document.createTextNode("Required")),H.appendChild(z),B.appendChild(T),B.appendChild(V),B.appendChild(H);const F=document.createElement("div");F.className="fb-options-wrap",F.style.display=Q.has(e.type)?"":"none";const $=document.createElement("label");$.className="form-label",$.textContent="Options (one per line: value: Label)";const D=document.createElement("textarea");D.id=`fb-options-${t}`,D.className="form-input",D.rows=4,D.value=(e.options||[]).map(s=>typeof s=="string"?`${s}: ${s}`:`${s.value??""}: ${s.label??s.value??""}`).join(`
3
- `),F.appendChild($),F.appendChild(D);const x=document.createElement("div");x.className="fb-grid-row",x.style.gridTemplateColumns="1fr auto",x.style.gap=".6rem",x.style.alignItems="end",x.style.marginBottom=".6rem",x.style.display=document.getElementById("collection-layout")?.value==="grid"?"grid":"none";const G=document.createElement("div"),J=document.createElement("label");J.className="form-label",J.textContent="Column Span";const N=document.createElement("input");N.id=`fb-span-${t}`,N.type="number",N.className="form-input",N.min="1",N.max="6",N.value=e.span>1?String(e.span):"1",G.appendChild(J),G.appendChild(N);const K=document.createElement("div");K.style.cssText="padding-bottom:.35rem;";const O=document.createElement("label");O.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const U=document.createElement("input");return U.id=`fb-fullwidth-${t}`,U.type="checkbox",U.checked=!!e.fullWidth,O.appendChild(U),O.appendChild(document.createTextNode("Full Width")),K.appendChild(O),x.appendChild(G),x.appendChild(K),d.appendChild(c),d.appendChild(B),d.appendChild(F),d.appendChild(x),n.addEventListener("click",()=>{const s=d.style.display!=="none";d.style.display=s?"none":"",l.style.transform=s?"":"rotate(180deg)"}),a.appendChild(n),a.appendChild(d),a}function _(e){if(e){if(e.textContent="",f.length===0){const t=document.createElement("p");t.className="text-muted",t.id="fields-empty-msg",t.style.cssText="text-align:center;padding:2rem 0;",t.textContent='No fields yet. Click "Add Field" to get started.',e.appendChild(t);return}f.forEach((t,a)=>{e.appendChild(oe(t,a))})}}function se(e,t){t.textContent="",ee.forEach(a=>{const n=e?.[a]||{enabled:!1,access:"admin"},i=document.createElement("div");i.style.cssText="display:grid;grid-template-columns:140px 1fr 160px;gap:.75rem;align-items:center;padding:.6rem 0;border-bottom:1px solid var(--border-color,#333);";const p=document.createElement("strong");p.textContent=a.charAt(0).toUpperCase()+a.slice(1),p.style.cssText="font-size:.9rem;";const r=document.createElement("label");r.style.cssText="display:flex;align-items:center;gap:.45rem;cursor:pointer;font-size:.875rem;";const l=document.createElement("input");l.type="checkbox",l.id=`api-${a}-enabled`,l.checked=!!n.enabled,r.appendChild(l),r.appendChild(document.createTextNode("Enable public access"));const o=document.createElement("select");o.id=`api-${a}-access`,o.className="form-input",ae.forEach(d=>{const c=document.createElement("option");c.value=d,c.textContent=d.charAt(0).toUpperCase()+d.slice(1),d===n.access&&(c.selected=!0),o.appendChild(c)}),i.appendChild(p),i.appendChild(r),i.appendChild(o),t.appendChild(i)})}function de(e,t){E.dropdown("#storage-adapter-trigger",{items:[{label:"File (default)",value:"file"},{label:"MongoDB",value:"mongodb"}],onSelect:({item:n})=>{e.find("#storage-adapter").val(n.value),e.find("#storage-adapter-label").text(n.label);const i=n.value==="mongodb";e.find("#storage-connection-group").toggle(i),e.find("#storage-migration-warning").toggle(i&&!q)}});const a=t.map(n=>({label:n,value:n}));E.dropdown("#storage-connection-trigger",{items:a.length?a:[{label:"default",value:"default"}],onSelect:({item:n})=>{e.find("#storage-connection").val(n.value),e.find("#storage-connection-label").text(n.label)}})}function ce(){return(document.getElementById("storage-adapter")?.value||"file")==="mongodb"?{adapter:"mongodb",connection:document.getElementById("storage-connection")?.value||"default"}:{adapter:"file"}}function ie(){const e={};return ee.forEach(t=>{const a=document.getElementById(`api-${t}-enabled`)?.checked??!1,n=document.getElementById(`api-${t}-access`)?.value||"admin";e[t]={enabled:a,access:n}}),e}export const collectionEditorView={templateUrl:"/admin/js/templates/collection-editor.html",async onMount(e){f=[],y=null,q=!0;const a=window.location.hash.match(/\/collections\/edit\/([^/?#]+)/);a&&(y=a[1],q=!1),E.tabs(e.find("#collection-tabs").get(0)),e.find("#collection-layout").get(0)?.addEventListener("change",function(){const l=this.value==="grid";e.find("#collection-columns-group").get(0).style.display=l?"":"none",document.querySelectorAll(".fb-grid-row").forEach(o=>{o.style.display=l?"grid":"none"})});const n=e.find("#fields-list").get(0),i=e.find("#api-access-rows").get(0),p=await S.collections.proStatus();p?.pro&&y!=="roles"&&(e.find("#storage-tab-btn").show(),de(e,p.connections));let r={create:{enabled:!1,access:"admin"},read:{enabled:!0,access:"public"},update:{enabled:!1,access:"admin"},delete:{enabled:!1,access:"admin"}};if(q){const l=e.find("#field-title").get(0),o=e.find("#field-slug").get(0);l&&o&&(l.addEventListener("input",()=>{o.dataset.manual||(o.value=te(l.value))}),o.addEventListener("input",()=>{o.dataset.manual="1"}))}else try{const l=await S.collections.get(y);if(!l){E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const o=e.find("#editor-title-text").get(0);o&&(o.textContent=l.title),e.find("#field-title").val(l.title||""),e.find("#field-slug").val(l.slug||""),e.find("#field-slug").prop("readonly",!0),e.find("#slug-hint").get(0).textContent="Slug cannot be changed after creation.",e.find("#field-description").val(l.description||""),e.find("#collection-layout").val(l.layout||"stacked"),e.find("#collection-columns").val(l.columns||2),e.find("#collection-bundled").prop("checked",!!l.bundled),e.find("#collection-columns-group").get(0).style.display=l.layout==="grid"?"":"none",f=l.fields||[],r=l.api||r,I=l.storage?.adapter||"file",l.storage&&(e.find("#storage-adapter").val(l.storage.adapter||"file"),e.find("#storage-adapter-label").text(l.storage.adapter==="mongodb"?"MongoDB":"File (default)"),l.storage.adapter==="mongodb"&&(e.find("#storage-connection-group").show(),e.find("#storage-connection").val(l.storage.connection||"default"),e.find("#storage-connection-label").text(l.storage.connection||"default"))),y==="roles"&&e.find("#storage-tab-btn").hide()}catch{E.toast("Failed to load collection.",{type:"error"}),R.navigate("/collections");return}_(n),se(r,i),e.find("#add-field-btn").off("click").on("click",()=>{f=X(),f.push({id:`field-${Date.now()}`,name:"",label:"",type:"string",required:!1,placeholder:"",helper:"",options:[],validation:[],logic:null}),_(n);const l=n.querySelectorAll(".fb-field-card");if(l.length){const o=l[l.length-1],d=o.querySelector(".fb-field-body"),c=o.querySelector(".fb-field-chevron");d&&(d.style.display=""),c&&(c.style.transform="rotate(180deg)"),o.querySelector(`#fb-label-${f.length-1}`)?.focus()}}),e.find("#save-collection-btn").off("click").on("click",async()=>{const l=e.find("#field-title").val().trim(),o=e.find("#field-slug").val().trim(),d=e.find("#field-description").val().trim();if(!l){E.toast("Title is required.",{type:"warning"});return}const c=X(),g=ie(),b=e.find("#collection-layout").val()||"stacked",u=parseInt(e.find("#collection-columns").val(),10)||2,m=ce(),k=e.find("#collection-bundled").is(":checked"),h=e.find("#save-collection-btn");h.prop("disabled",!0);try{if(q){const v=await S.collections.create({title:l,slug:o,description:d,layout:b,columns:u,fields:c,api:g,storage:m,...k?{bundled:!0}:{}});y=v.slug,I=m.adapter||"file",q=!1,E.toast("Collection created.",{type:"success"}),R.navigate(`/collections/edit/${v.slug}`)}else if((m.adapter||"file")!==I){let w=0;try{w=(await S.collections.listEntries(y,{limit:1}))?.total??0}catch{}const C=I==="file"?`file \u2192 ${m.adapter}`:`${I} \u2192 ${m.adapter||"file"}`;if(w>0&&await E.confirm(`You changed the storage adapter (${C}).
1
+ import{api as w}from"../api.js";const Z=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"hidden",label:"Hidden field"}],Q=new Set(["select","radio","checkbox-group"]),le=["public","subscriber","editor","manager","admin"],ee=["create","read","update","delete"];let f=[],b=null,L=!0,z=null,N="file";function te(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}function ne(e){return Z.find(t=>t.value===e)?.label||e}function ae(e){const t={...f[e]},l=document.getElementById(`fb-label-${e}`),d=document.getElementById(`fb-name-${e}`),s=document.getElementById(`fb-type-${e}`),u=document.getElementById(`fb-required-${e}`),n=document.getElementById(`fb-placeholder-${e}`),o=document.getElementById(`fb-helper-${e}`);if(l&&(t.label=l.value.trim()||t.label),d&&(t.name=d.value.trim()||t.name),s&&(t.type=s.value||t.type),u&&(t.required=u.checked),n&&(t.placeholder=n.value.trim()),o&&(t.helper=o.value.trim()),Q.has(t.type)){const i=document.getElementById(`fb-options-${e}`);i&&(t.options=i.value.split(`
2
+ `).filter(p=>p.trim()).map(p=>{const[g,...h]=p.split(":");return{value:g.trim(),label:h.join(":").trim()||g.trim()}}))}const c=document.getElementById(`fb-span-${e}`);if(document.getElementById(`fb-fullwidth-${e}`)?.checked)t.fullWidth=!0,delete t.span;else{delete t.fullWidth;const i=parseInt(c?.value,10);i>1?t.span=i:delete t.span}return t}function X(){return f.map((e,t)=>ae(t))}function oe(e,t){const l=document.createElement("div");l.className="fb-field-card",l.dataset.index=t,l.style.cssText="border:1px solid var(--border-color,#333);border-radius:8px;margin-bottom:.75rem;overflow:hidden;";const d=document.createElement("div");d.className="fb-field-header",d.style.cssText="display:flex;align-items:center;gap:.5rem;padding:.6rem .75rem;background:var(--card-header-bg,rgba(255,255,255,.03));cursor:pointer;user-select:none;";const s=document.createElement("span");s.textContent="\u283F",s.style.cssText="cursor:grab;opacity:.4;font-size:1.1rem;flex-shrink:0;",l.draggable=!0,s.addEventListener("mousedown",()=>{l.draggable=!0}),l.addEventListener("dragstart",a=>{z=t,a.dataTransfer.effectAllowed="move",l.style.opacity="0.4"}),l.addEventListener("dragend",()=>{l.style.opacity="",document.querySelectorAll(".fb-field-card").forEach(a=>a.classList.remove("fb-drag-over"))}),l.addEventListener("dragover",a=>{a.preventDefault(),a.dataTransfer.dropEffect="move",document.querySelectorAll(".fb-field-card").forEach(v=>v.classList.remove("fb-drag-over")),l.classList.add("fb-drag-over")}),l.addEventListener("dragleave",()=>{l.classList.remove("fb-drag-over")}),l.addEventListener("drop",a=>{if(a.preventDefault(),l.classList.remove("fb-drag-over"),z===null||z===t)return;f=X();const[v]=f.splice(z,1);f.splice(t,0,v),z=null,j(document.getElementById("fields-list"))});const u=document.createElement("span");u.className="fb-field-summary",u.style.cssText="flex:1;font-weight:500;font-size:.9rem;",u.textContent=e.label||"(Untitled field)";const n=document.createElement("span");n.style.cssText="font-size:.75rem;opacity:.5;",n.textContent=ne(e.type);const o=document.createElement("span");o.className="fb-field-chevron",o.textContent="\u25BE",o.style.cssText="opacity:.5;transition:transform .2s;";const c=document.createElement("button");c.type="button",c.textContent="\xD7",c.className="btn btn-sm",c.style.cssText="padding:.15rem .45rem;line-height:1;font-size:1rem;opacity:.6;",c.title="Remove field",c.addEventListener("click",a=>{a.stopPropagation(),f.splice(t,1),j(document.getElementById("fields-list"))}),d.appendChild(s),d.appendChild(u),d.appendChild(n),d.appendChild(o),d.appendChild(c);const i=document.createElement("div");i.className="fb-field-body",i.style.cssText="padding:.75rem;display:none;";const p=document.createElement("div");p.style.cssText="display:grid;grid-template-columns:1fr 1fr 1fr;gap:.6rem;margin-bottom:.6rem;";const g=document.createElement("div"),h=document.createElement("label");h.className="form-label",h.textContent="Label";const r=document.createElement("input");r.id=`fb-label-${t}`,r.type="text",r.className="form-input",r.value=e.label||"",r.addEventListener("input",()=>{u.textContent=r.value.trim()||"(Untitled field)";const a=document.getElementById(`fb-name-${t}`);a&&!a.dataset.manual&&(a.value=te(r.value).replace(/-/g,"_"))}),g.appendChild(h),g.appendChild(r);const x=document.createElement("div"),T=document.createElement("label");T.className="form-label",T.textContent="Name (key)";const m=document.createElement("input");m.id=`fb-name-${t}`,m.type="text",m.className="form-input",m.value=e.name||"",m.addEventListener("input",()=>{m.dataset.manual="1"}),x.appendChild(T),x.appendChild(m);const B=document.createElement("div"),k=document.createElement("label");k.className="form-label",k.textContent="Type";const C=document.createElement("select");C.id=`fb-type-${t}`,C.className="form-input",Z.forEach(a=>{const v=document.createElement("option");v.value=a.value,v.textContent=a.label,a.value===e.type&&(v.selected=!0),C.appendChild(v)}),C.addEventListener("change",()=>{n.textContent=ne(C.value);const a=i.querySelector(".fb-options-wrap");a&&(a.style.display=Q.has(C.value)?"":"none")}),B.appendChild(k),B.appendChild(C),p.appendChild(g),p.appendChild(x),p.appendChild(B);const I=document.createElement("div");I.style.cssText="display:grid;grid-template-columns:1fr 1fr auto;gap:.6rem;align-items:end;margin-bottom:.6rem;";const P=document.createElement("div"),H=document.createElement("label");H.className="form-label",H.textContent="Placeholder";const S=document.createElement("input");S.id=`fb-placeholder-${t}`,S.type="text",S.className="form-input",S.value=e.placeholder||"",P.appendChild(H),P.appendChild(S);const O=document.createElement("div"),V=document.createElement("label");V.className="form-label",V.textContent="Helper text";const q=document.createElement("input");q.id=`fb-helper-${t}`,q.type="text",q.className="form-input",q.value=e.helper||"",O.appendChild(V),O.appendChild(q);const Y=document.createElement("div");Y.style.cssText="padding-bottom:.35rem;";const F=document.createElement("label");F.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const U=document.createElement("input");U.id=`fb-required-${t}`,U.type="checkbox",U.checked=!!e.required,F.appendChild(U),F.appendChild(document.createTextNode("Required")),Y.appendChild(F),I.appendChild(P),I.appendChild(O),I.appendChild(Y);const D=document.createElement("div");D.className="fb-options-wrap",D.style.display=Q.has(e.type)?"":"none";const _=document.createElement("label");_.className="form-label",_.textContent="Options (one per line: value: Label)";const A=document.createElement("textarea");A.id=`fb-options-${t}`,A.className="form-input",A.rows=4,A.value=(e.options||[]).map(a=>typeof a=="string"?`${a}: ${a}`:`${a.value??""}: ${a.label??a.value??""}`).join(`
3
+ `),D.appendChild(_),D.appendChild(A);const y=document.createElement("div");y.className="fb-grid-row",y.style.gridTemplateColumns="1fr auto",y.style.gap=".6rem",y.style.alignItems="end",y.style.marginBottom=".6rem",y.style.display=document.getElementById("collection-layout")?.value==="grid"?"grid":"none";const G=document.createElement("div"),J=document.createElement("label");J.className="form-label",J.textContent="Column Span";const $=document.createElement("input");$.id=`fb-span-${t}`,$.type="number",$.className="form-input",$.min="1",$.max="6",$.value=e.span>1?String(e.span):"1",G.appendChild(J),G.appendChild($);const K=document.createElement("div");K.style.cssText="padding-bottom:.35rem;";const M=document.createElement("label");M.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;white-space:nowrap;";const W=document.createElement("input");return W.id=`fb-fullwidth-${t}`,W.type="checkbox",W.checked=!!e.fullWidth,M.appendChild(W),M.appendChild(document.createTextNode("Full Width")),K.appendChild(M),y.appendChild(G),y.appendChild(K),i.appendChild(p),i.appendChild(I),i.appendChild(D),i.appendChild(y),d.addEventListener("click",()=>{const a=i.style.display!=="none";i.style.display=a?"none":"",o.style.transform=a?"":"rotate(180deg)"}),l.appendChild(d),l.appendChild(i),l}function j(e){if(e){if(e.textContent="",f.length===0){const t=document.createElement("p");t.className="text-muted",t.id="fields-empty-msg",t.style.cssText="text-align:center;padding:2rem 0;",t.textContent='No fields yet. Click "Add Field" to get started.',e.appendChild(t);return}f.forEach((t,l)=>{e.appendChild(oe(t,l))})}}function de(e,t){t.textContent="",ee.forEach(l=>{const d=e?.[l]||{enabled:!1,access:"admin"},s=document.createElement("div");s.style.cssText="display:grid;grid-template-columns:140px 1fr 160px;gap:.75rem;align-items:center;padding:.6rem 0;border-bottom:1px solid var(--border-color,#333);";const u=document.createElement("strong");u.textContent=l.charAt(0).toUpperCase()+l.slice(1),u.style.cssText="font-size:.9rem;";const n=document.createElement("label");n.style.cssText="display:flex;align-items:center;gap:.45rem;cursor:pointer;font-size:.875rem;";const o=document.createElement("input");o.type="checkbox",o.id=`api-${l}-enabled`,o.checked=!!d.enabled,n.appendChild(o),n.appendChild(document.createTextNode("Enable public access"));const c=document.createElement("select");c.id=`api-${l}-access`,c.className="form-input",le.forEach(i=>{const p=document.createElement("option");p.value=i,p.textContent=i.charAt(0).toUpperCase()+i.slice(1),i===d.access&&(p.selected=!0),c.appendChild(p)}),s.appendChild(u),s.appendChild(n),s.appendChild(c),t.appendChild(s)})}function ie(e,t){E.dropdown("#storage-adapter-trigger",{items:[{label:"File (default)",value:"file"},{label:"MongoDB",value:"mongodb"}],onSelect:({item:d})=>{e.find("#storage-adapter").val(d.value),e.find("#storage-adapter-label").text(d.label);const s=d.value==="mongodb";e.find("#storage-connection-group").toggle(s),e.find("#storage-migration-warning").toggle(s&&!L)}});const l=t.map(d=>({label:d,value:d}));E.dropdown("#storage-connection-trigger",{items:l.length?l:[{label:"default",value:"default"}],onSelect:({item:d})=>{e.find("#storage-connection").val(d.value),e.find("#storage-connection-label").text(d.label)}})}function ce(){return(document.getElementById("storage-adapter")?.value||"file")==="mongodb"?{adapter:"mongodb",connection:document.getElementById("storage-connection")?.value||"default"}:{adapter:"file"}}function se(){const e={};return ee.forEach(t=>{const l=document.getElementById(`api-${t}-enabled`)?.checked??!1,d=document.getElementById(`api-${t}-access`)?.value||"admin";e[t]={enabled:l,access:d}}),e}export const collectionEditorView={templateUrl:"/admin/js/templates/collection-editor.html",async onMount(e){f=[],b=null,L=!0;const t=window.location.hash.match(/\/collections\/edit\/([^/?#]+)/);t&&(b=t[1],L=!1),E.tabs(e.find("#collection-tabs").get(0)),e.find("#collection-layout").get(0)?.addEventListener("change",function(){const n=this.value==="grid";e.find("#collection-columns-group").get(0).style.display=n?"":"none",document.querySelectorAll(".fb-grid-row").forEach(o=>{o.style.display=n?"grid":"none"})});const l=e.find("#fields-list").get(0),d=e.find("#api-access-rows").get(0),s=await w.collections.proStatus();s?.pro&&b!=="roles"&&(e.find("#storage-tab-btn").show(),ie(e,s.connections));let u={create:{enabled:!1,access:"admin"},read:{enabled:!0,access:"public"},update:{enabled:!1,access:"admin"},delete:{enabled:!1,access:"admin"}};if(L){const n=e.find("#field-title").get(0),o=e.find("#field-slug").get(0);n&&o&&(n.addEventListener("input",()=>{o.dataset.manual||(o.value=te(n.value))}),o.addEventListener("input",()=>{o.dataset.manual="1"}))}else try{const n=await w.collections.get(b);if(!n){E.toast("Collection not found.",{type:"error"}),R.navigate("/collections");return}const o=e.find("#editor-title-text").get(0);o&&(o.textContent=n.title),e.find("#field-title").val(n.title||""),e.find("#field-slug").val(n.slug||""),e.find("#field-slug").prop("readonly",!0),e.find("#slug-hint").get(0).textContent="Slug cannot be changed after creation.",e.find("#field-description").val(n.description||""),e.find("#collection-layout").val(n.layout||"stacked"),e.find("#collection-columns").val(n.columns||2),e.find("#collection-bundled").prop("checked",!!n.bundled),e.find("#collection-columns-group").get(0).style.display=n.layout==="grid"?"":"none",f=n.fields||[],u=n.api||u,N=n.storage?.adapter||"file",n.storage&&(e.find("#storage-adapter").val(n.storage.adapter||"file"),e.find("#storage-adapter-label").text(n.storage.adapter==="mongodb"?"MongoDB":"File (default)"),n.storage.adapter==="mongodb"&&(e.find("#storage-connection-group").show(),e.find("#storage-connection").val(n.storage.connection||"default"),e.find("#storage-connection-label").text(n.storage.connection||"default"))),b==="roles"&&e.find("#storage-tab-btn").hide()}catch{E.toast("Failed to load collection.",{type:"error"}),R.navigate("/collections");return}j(l),de(u,d),e.find("#add-field-btn").off("click").on("click",()=>{f=X(),f.push({id:`field-${Date.now()}`,name:"",label:"",type:"string",required:!1,placeholder:"",helper:"",options:[],validation:[],logic:null}),j(l);const n=l.querySelectorAll(".fb-field-card");if(n.length){const o=n[n.length-1],c=o.querySelector(".fb-field-body"),i=o.querySelector(".fb-field-chevron");c&&(c.style.display=""),i&&(i.style.transform="rotate(180deg)"),o.querySelector(`#fb-label-${f.length-1}`)?.focus()}}),e.find("#save-collection-btn").off("click").on("click",async()=>{const n=e.find("#field-title").val().trim(),o=e.find("#field-slug").val().trim(),c=e.find("#field-description").val().trim();if(!n){E.toast("Title is required.",{type:"warning"});return}const i=X(),p=se(),g=e.find("#collection-layout").val()||"stacked",h=parseInt(e.find("#collection-columns").val(),10)||2,r=ce(),x=e.find("#collection-bundled").is(":checked"),T=e.find("#save-collection-btn");T.prop("disabled",!0);try{if(L){const m=await w.collections.create({title:n,slug:o,description:c,layout:g,columns:h,fields:i,api:p,storage:r,...x?{bundled:!0}:{}});b=m.slug,N=r.adapter||"file",L=!1,E.toast("Collection created.",{type:"success"}),R.navigate(`/collections/edit/${m.slug}`)}else if((r.adapter||"file")!==N){let m=0;try{m=(await w.collections.listEntries(b,{limit:1}))?.total??0}catch{}const B=N==="file"?`file \u2192 ${r.adapter}`:`${N} \u2192 ${r.adapter||"file"}`;if(m>0&&await E.confirm(`You changed the storage adapter (${B}).
4
4
 
5
- Migrate ${w} existing ${w===1?"entry":"entries"} to the new storage?`)){const T=await S.collections.migrateStorage(y,m);I=m.adapter||"file",E.toast(`Migrated ${T.migrated} of ${T.total} entries.`,{type:"success"})}else await S.collections.update(y,{title:l,description:d,layout:b,columns:u,fields:c,api:g,storage:m,...k?{bundled:!0}:{bundled:!1}}),I=m.adapter||"file",E.toast("Collection saved.",{type:"success"})}else await S.collections.update(y,{title:l,description:d,layout:b,columns:u,fields:c,api:g,storage:m}),E.toast("Collection saved.",{type:"success"})}catch(v){E.toast(v.message||"Failed to save.",{type:"error"})}finally{h.prop("disabled",!1)}}),Domma.icons.scan()}};
5
+ Migrate ${m} existing ${m===1?"entry":"entries"} to the new storage?`)){const k=await w.collections.migrateStorage(b,r);N=r.adapter||"file",E.toast(`Migrated ${k.migrated} of ${k.total} entries.`,{type:"success"})}else await w.collections.update(b,{title:n,description:c,layout:g,columns:h,fields:i,api:p,storage:r,...x?{bundled:!0}:{bundled:!1}}),N=r.adapter||"file",E.toast("Collection saved.",{type:"success"})}else await w.collections.update(b,{title:n,description:c,layout:g,columns:h,fields:i,api:p,storage:r,...x?{bundled:!0}:{bundled:!1}}),E.toast("Collection saved.",{type:"success"})}catch(m){E.toast(m.message||"Failed to save.",{type:"error"})}finally{T.prop("disabled",!1)}}),Domma.icons.scan()}};
@@ -1 +1 @@
1
- import{api as b}from"../api.js";function h(e){return String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}let i={};export const collectionsView={templateUrl:"/admin/js/templates/collections.html",async onMount(e){const s=E.loader(e.get(0),{type:"dots"});E.tabs(e.find("#collections-tabs").get(0));const c=e.find("#collections-tabs").get(0)?.querySelector(".tab-list");if(c){const t=e.find("#collections-header-actions").get(0);Array.from(c.querySelectorAll(".tab-item")).forEach((n,l)=>{n.addEventListener("click",()=>{t&&(t.style.display=l===0?"":"none")})})}await Promise.all([B(e),j(e)]),s.destroy(),e.find("#create-collection-btn").off("click").on("click",()=>{const t=E.modal({title:"New Collection",size:"sm"}),n=document.createElement("div");n.style.cssText="padding:.25rem 0 .5rem;";const l=document.createElement("div");F.create({title:{type:"string",label:"Collection Title",placeholder:"e.g. Products, Blog Posts\u2026",required:!0}},{},{showSubmitButton:!1}).renderTo(l),n.appendChild(l);const o=document.createElement("div");o.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem;";const d=document.createElement("button");d.className="btn btn-ghost",d.textContent="Cancel";const a=document.createElement("button");a.className="btn btn-primary",a.textContent="Create",o.appendChild(d),o.appendChild(a),n.appendChild(o),t.element.appendChild(n),t.open();const r=l.querySelector('input[name="title"]');setTimeout(()=>r?.focus(),50);async function m(){const p=r?.value.trim();if(p)try{const u=await b.collections.create({title:p});t.close(),R.navigate(`/collections/edit/${u.slug}`)}catch(u){E.toast(u.message||"Failed to create collection.",{type:"error"})}}d.addEventListener("click",()=>t.close()),a.addEventListener("click",m),r?.addEventListener("keydown",p=>{p.key==="Enter"&&m()})}),e.find("#connections-raw-toggle").on("change",function(){if(this.checked)i=x(e),v(e),e.find("#connections-form-view").hide(),e.find("#connections-raw-view").show();else{const t=e.find("#connections-raw-json").get(0)?.value||"{}";try{i=JSON.parse(t),C(e),e.find("#connections-form-view").show(),e.find("#connections-raw-view").hide()}catch{E.toast("Invalid JSON \u2014 fix before switching to form view.",{type:"warning"}),this.checked=!0}}}),e.find("#add-connection-btn").on("click",()=>{i=x(e);let t=Object.keys(i).length+1,n=`connection${t}`;for(;i[n];)t++,n=`connection${t}`;i[n]={type:"mongodb",uri:"",database:"",options:{}},C(e),v(e)}),e.find("#save-connections-btn").on("click",async()=>{const t=e.find("#connections-raw-toggle").get(0)?.checked;let n;if(t)try{n=JSON.parse(e.find("#connections-raw-json").get(0)?.value||"{}")}catch{E.toast("Invalid JSON \u2014 fix before saving.",{type:"warning"});return}else n=x(e);try{await b.collections.saveConnections(n),i=n,E.toast("Connections saved.",{type:"success"})}catch(l){E.toast(l.message||"Failed to save connections.",{type:"error"})}}),Domma.icons.scan()}};async function B(e){let s=[];try{s=await b.collections.list()}catch{E.toast("Could not load collections.",{type:"error"})}T.create("#collections-table",{data:s,columns:[{key:"title",title:"Title",render:(c,t)=>{const n=document.createElement("span");n.style.cssText="display:flex;align-items:center;gap:.4rem;";const l=document.createElement("a");if(l.href=`#/collections/${h(t.slug)}/entries`,l.textContent=c,l.style.fontWeight="600",n.appendChild(l),t.storage?.adapter==="mongodb"){const o=document.createElement("span");o.className="badge badge-outline",o.textContent="MongoDB",o.title=`Connection: ${t.storage.connection||"default"}`,o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-success,#16a34a);border-color:var(--dm-success,#16a34a);flex-shrink:0;",n.appendChild(o)}if(t.bundled){const o=document.createElement("span");o.className="badge badge-outline",o.textContent="Bundled",o.title="Seeded on fresh installs",o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-info,#2563eb);border-color:var(--dm-info,#2563eb);flex-shrink:0;",n.appendChild(o)}if(t.plugin){const o=document.createElement("span");o.className="badge badge-outline",o.textContent=t.plugin,o.title=`Managed by the ${t.plugin} plugin`,o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-warning,#d97706);border-color:var(--dm-warning,#d97706);flex-shrink:0;",n.appendChild(o)}return n.outerHTML}},{key:"slug",title:"Slug",render:c=>{const t=document.createElement("code");return t.textContent=c,t.outerHTML}},{key:"fields",title:"Field Count",render:c=>String(c?.length??0)},{key:"entryCount",title:"Entry Count",render:c=>String(c??0)},{key:"slug",title:"Actions",render:(c,t)=>{const n=document.createElement("div");n.style.cssText="display:flex;gap:.4rem;justify-content:flex-end;flex-wrap:wrap;";const l=document.createElement("a");l.href=`#/collections/edit/${h(c)}`,l.className="btn btn-sm btn-ghost",l.textContent="Edit Schema";const o=document.createElement("a");if(o.href=`#/collections/${h(c)}/entries`,o.className="btn btn-sm btn-ghost",o.textContent="Entries",n.appendChild(l),n.appendChild(o),!new Set(["roles","user-profiles"]).has(c)){const a=document.createElement("a");a.href=`#/forms/edit/${h(c)}`,a.className="btn btn-sm btn-ghost",a.textContent="Form",n.appendChild(a)}if(!t.plugin){const a=document.createElement("button");a.className="btn btn-sm btn-danger js-delete-collection",a.dataset.slug=c,a.textContent="Delete",n.appendChild(a)}return n.outerHTML}}],emptyMessage:'No collections yet. Click "New Collection" to get started.'}),document.querySelectorAll(".js-delete-collection").forEach(c=>{c.addEventListener("click",async()=>{const t=c.dataset.slug;if(await E.confirm(`Delete collection "${t}" and all its data? This cannot be undone.`))try{await b.collections.delete(t),E.toast("Collection deleted.",{type:"success"}),await B(e)}catch{E.toast("Failed to delete collection.",{type:"error"})}})}),Domma.icons.scan()}async function j(e){try{i=await b.collections.getConnections()}catch{i={}}C(e),v(e)}function C(e){const s=e.find("#connections-list").get(0),c=e.find("#connections-empty").get(0);if(!s)return;s.textContent="";const t=Object.keys(i);c&&(c.style.display=t.length?"none":""),t.forEach(n=>{const l=i[n],o=document.createElement("div");o.className="conn-card card mb-3",o.dataset.connKey=n;const d=document.createElement("div");d.className="card-header",d.style.cssText="display:flex;align-items:center;gap:.5rem;";const a=document.createElement("input");a.type="text",a.className="form-input conn-name",a.value=n,a.placeholder="Connection name",a.style.cssText="flex:1;";const r=document.createElement("button");r.type="button",r.className="btn btn-sm btn-danger",r.textContent="Delete",r.addEventListener("click",()=>{i=x(e);const L=a.value.trim();L&&delete i[L],C(e),v(e)}),d.appendChild(a),d.appendChild(r);const m=document.createElement("div");m.className="card-body",m.style.cssText="display:grid;grid-template-columns:1fr 2fr 1fr;gap:.6rem;";const p=document.createElement("div"),u=document.createElement("label");u.className="form-label",u.textContent="Type";const f=document.createElement("input");f.type="text",f.className="form-input conn-type",f.value=l.type||"mongodb",f.disabled=!0,p.appendChild(u),p.appendChild(f);const w=document.createElement("div"),N=document.createElement("label");N.className="form-label",N.textContent="URI";const g=document.createElement("input");g.type="text",g.className="form-input conn-uri",g.value=l.uri||"",g.placeholder="mongodb://localhost:27017",w.appendChild(N),w.appendChild(g);const S=document.createElement("div"),k=document.createElement("label");k.className="form-label",k.textContent="Database";const y=document.createElement("input");y.type="text",y.className="form-input conn-database",y.value=l.database||"",y.placeholder="mydb",S.appendChild(k),S.appendChild(y),m.appendChild(p),m.appendChild(w),m.appendChild(S),o.appendChild(d),o.appendChild(m),s.appendChild(o)})}function x(e){const s={},c=e.find("#connections-list").get(0)?.querySelectorAll(".conn-card")||[];for(const t of c){const n=t.querySelector(".conn-name")?.value.trim(),l=t.querySelector(".conn-uri")?.value.trim()||"",o=t.querySelector(".conn-database")?.value.trim()||"";n&&(s[n]={type:"mongodb",uri:l,database:o,options:{}})}return s}function v(e){const s=e.find("#connections-raw-json").get(0);s&&(s.value=JSON.stringify(i,null,2))}
1
+ import{api as b}from"../api.js";function h(e){return String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}let d={};export const collectionsView={templateUrl:"/admin/js/templates/collections.html",async onMount(e){const a=E.loader(e.get(0),{type:"dots"});E.tabs(e.find("#collections-tabs").get(0));const c=e.find("#collections-tabs").get(0)?.querySelector(".tab-list");if(c){const n=e.find("#collections-header-actions").get(0);Array.from(c.querySelectorAll(".tab-item")).forEach((t,l)=>{t.addEventListener("click",()=>{n&&(n.style.display=l===0?"":"none")})})}await Promise.all([B(e),j(e)]),a.destroy(),e.find("#create-collection-btn").off("click").on("click",()=>{const n=E.modal({title:"New Collection",size:"sm"}),t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;";const l=document.createElement("div");F.create({title:{type:"string",label:"Collection Title",placeholder:"e.g. Products, Blog Posts\u2026",required:!0}},{},{showSubmitButton:!1}).renderTo(l),t.appendChild(l);const o=document.createElement("div");o.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem;";const r=document.createElement("button");r.className="btn btn-ghost",r.textContent="Cancel";const s=document.createElement("button");s.className="btn btn-primary",s.textContent="Create",o.appendChild(r),o.appendChild(s),t.appendChild(o),n.element.appendChild(t),n.open();const i=l.querySelector('input[name="title"]');setTimeout(()=>i?.focus(),50);async function m(){const p=i?.value.trim();if(p)try{const u=await b.collections.create({title:p});n.close(),R.navigate(`/collections/edit/${u.slug}`)}catch(u){E.toast(u.message||"Failed to create collection.",{type:"error"})}}r.addEventListener("click",()=>n.close()),s.addEventListener("click",m),i?.addEventListener("keydown",p=>{p.key==="Enter"&&m()})}),e.find("#connections-raw-toggle").on("change",function(){if(this.checked)d=x(e),v(e),e.find("#connections-form-view").hide(),e.find("#connections-raw-view").show();else{const n=e.find("#connections-raw-json").get(0)?.value||"{}";try{d=JSON.parse(n),C(e),e.find("#connections-form-view").show(),e.find("#connections-raw-view").hide()}catch{E.toast("Invalid JSON \u2014 fix before switching to form view.",{type:"warning"}),this.checked=!0}}}),e.find("#add-connection-btn").on("click",()=>{d=x(e);let n=Object.keys(d).length+1,t=`connection${n}`;for(;d[t];)n++,t=`connection${n}`;d[t]={type:"mongodb",uri:"",database:"",options:{}},C(e),v(e)}),e.find("#save-connections-btn").on("click",async()=>{const n=e.find("#connections-raw-toggle").get(0)?.checked;let t;if(n)try{t=JSON.parse(e.find("#connections-raw-json").get(0)?.value||"{}")}catch{E.toast("Invalid JSON \u2014 fix before saving.",{type:"warning"});return}else t=x(e);try{await b.collections.saveConnections(t),d=t,E.toast("Connections saved.",{type:"success"})}catch(l){E.toast(l.message||"Failed to save connections.",{type:"error"})}}),Domma.icons.scan()}};async function B(e){let a=[];try{a=await b.collections.list()}catch{E.toast("Could not load collections.",{type:"error"})}T.create("#collections-table",{data:a,columns:[{key:"title",title:"Title",render:(c,n)=>{const t=document.createElement("span");t.style.cssText="display:flex;align-items:center;gap:.4rem;";const l=document.createElement("a");if(l.href=`#/collections/${h(n.slug)}/entries`,l.textContent=c,l.style.fontWeight="600",t.appendChild(l),n.storage?.adapter==="mongodb"){const o=document.createElement("span");o.className="badge badge-outline",o.textContent="MongoDB",o.title=`Connection: ${n.storage.connection||"default"}`,o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-success,#16a34a);border-color:var(--dm-success,#16a34a);flex-shrink:0;",t.appendChild(o)}if(n.bundled){const o=document.createElement("span");o.className="badge badge-outline",o.textContent="Bundled",o.title="Seeded on fresh installs",o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-info,#2563eb);border-color:var(--dm-info,#2563eb);flex-shrink:0;",t.appendChild(o)}if(n.plugin){const o=document.createElement("span");o.className="badge badge-outline",o.textContent=n.plugin,o.title=`Managed by the ${n.plugin} plugin`,o.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-warning,#d97706);border-color:var(--dm-warning,#d97706);flex-shrink:0;",t.appendChild(o)}return t.outerHTML}},{key:"slug",title:"Slug",render:c=>{const n=document.createElement("code");return n.textContent=c,n.outerHTML}},{key:"fields",title:"Field Count",render:c=>String(c?.length??0)},{key:"entryCount",title:"Entry Count",render:c=>String(c??0)},{key:"slug",title:"Actions",render:(c,n)=>{const t=document.createElement("div");t.style.cssText="display:flex;gap:.4rem;justify-content:flex-end;flex-wrap:wrap;";const l=document.createElement("a");l.href=`#/collections/edit/${h(c)}`,l.className="btn btn-sm btn-ghost",l.textContent="Edit Schema";const o=document.createElement("a");if(o.href=`#/collections/${h(c)}/entries`,o.className="btn btn-sm btn-ghost",o.textContent="Entries",t.appendChild(l),t.appendChild(o),!new Set(["roles","user-profiles"]).has(c)){const i=document.createElement("a");i.href=`#/forms/edit/${h(c)}`,i.className="btn btn-sm btn-ghost",i.textContent="Form",t.appendChild(i)}const s=document.createElement("button");return s.className="btn btn-sm btn-danger js-delete-collection",s.dataset.slug=c,s.dataset.plugin=n.plugin||"",s.textContent="Delete",t.appendChild(s),t.outerHTML}}],emptyMessage:'No collections yet. Click "New Collection" to get started.'}),document.querySelectorAll(".js-delete-collection").forEach(c=>{c.addEventListener("click",async()=>{const n=c.dataset.slug,t=c.dataset.plugin,l=t?`This collection is managed by the <strong>${t}</strong> plugin. Deleting it may cause the plugin to malfunction. Continue?`:`Delete collection "${n}" and all its data? This cannot be undone.`;if(await E.confirm(l))try{await b.collections.delete(n),E.toast("Collection deleted.",{type:"success"}),await B(e)}catch{E.toast("Failed to delete collection.",{type:"error"})}})}),Domma.icons.scan()}async function j(e){try{d=await b.collections.getConnections()}catch{d={}}C(e),v(e)}function C(e){const a=e.find("#connections-list").get(0),c=e.find("#connections-empty").get(0);if(!a)return;a.textContent="";const n=Object.keys(d);c&&(c.style.display=n.length?"none":""),n.forEach(t=>{const l=d[t],o=document.createElement("div");o.className="conn-card card mb-3",o.dataset.connKey=t;const r=document.createElement("div");r.className="card-header",r.style.cssText="display:flex;align-items:center;gap:.5rem;";const s=document.createElement("input");s.type="text",s.className="form-input conn-name",s.value=t,s.placeholder="Connection name",s.style.cssText="flex:1;";const i=document.createElement("button");i.type="button",i.className="btn btn-sm btn-danger",i.textContent="Delete",i.addEventListener("click",()=>{d=x(e);const L=s.value.trim();L&&delete d[L],C(e),v(e)}),r.appendChild(s),r.appendChild(i);const m=document.createElement("div");m.className="card-body",m.style.cssText="display:grid;grid-template-columns:1fr 2fr 1fr;gap:.6rem;";const p=document.createElement("div"),u=document.createElement("label");u.className="form-label",u.textContent="Type";const f=document.createElement("input");f.type="text",f.className="form-input conn-type",f.value=l.type||"mongodb",f.disabled=!0,p.appendChild(u),p.appendChild(f);const w=document.createElement("div"),N=document.createElement("label");N.className="form-label",N.textContent="URI";const g=document.createElement("input");g.type="text",g.className="form-input conn-uri",g.value=l.uri||"",g.placeholder="mongodb://localhost:27017",w.appendChild(N),w.appendChild(g);const S=document.createElement("div"),k=document.createElement("label");k.className="form-label",k.textContent="Database";const y=document.createElement("input");y.type="text",y.className="form-input conn-database",y.value=l.database||"",y.placeholder="mydb",S.appendChild(k),S.appendChild(y),m.appendChild(p),m.appendChild(w),m.appendChild(S),o.appendChild(r),o.appendChild(m),a.appendChild(o)})}function x(e){const a={},c=e.find("#connections-list").get(0)?.querySelectorAll(".conn-card")||[];for(const n of c){const t=n.querySelector(".conn-name")?.value.trim(),l=n.querySelector(".conn-uri")?.value.trim()||"",o=n.querySelector(".conn-database")?.value.trim()||"";t&&(a[t]={type:"mongodb",uri:l,database:o,options:{}})}return a}function v(e){const a=e.find("#connections-raw-json").get(0);a&&(a.value=JSON.stringify(d,null,2))}
@@ -1,8 +1,8 @@
1
- import{apiRequest as T}from"/admin/js/api.js";const z=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"password",label:"Password"},{value:"file",label:"File upload"},{value:"hidden",label:"Hidden field"}],I=new Set(["select","radio","checkbox-group"]);let b=[],C=null,L=null,q=null;function O(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function P(e){return z.find(t=>t.value===e)?.label||e}function M(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function G(e){const t={...b[e]};if(t.type==="spacer")return t;if(t.type==="page-break"){const g=document.getElementById(`fb-pb-label-${e}`),h=document.getElementById(`fb-pb-desc-${e}`);return g&&(t.label=g.value.trim()||t.label),h&&(t.description=h.value.trim()),t}const c=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),s=document.getElementById(`fb-type-${e}`),a=document.getElementById(`fb-required-${e}`),l=document.getElementById(`fb-placeholder-${e}`),d=document.getElementById(`fb-helper-${e}`);if(c&&(t.label=c.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),s&&(t.type=s.value||t.type),a&&(t.required=a.checked),l&&(t.placeholder=l.value.trim()),d&&(t.helper=d.value.trim()),I.has(t.type)){const g=document.getElementById(`fb-options-${e}`);g&&(t.options=g.value.split(`
2
- `).filter(h=>h.trim()).map(h=>{const[y,...S]=h.split(":");return{value:y.trim(),label:S.join(":").trim()||y.trim()}}))}if(t.type==="textarea"){const g=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);g>0&&(t.formConfig={...t.formConfig||{},rows:g})}const o=document.getElementById(`fb-span-${e}`),i=document.getElementById(`fb-fullwidth-${e}`);if(o||i){const g={...t.formConfig||{}};if(i?.checked)g.span="full";else{const h=parseInt(o?.value,10);h>1?g.span=h:delete g.span}t.formConfig=Object.keys(g).length?g:void 0}const m=document.getElementById(`fb-minlength-${e}`)?.value;m&&(t.minLength=parseInt(m,10));const p=document.getElementById(`fb-maxlength-${e}`)?.value;p&&(t.maxLength=parseInt(p,10));const f=document.getElementById(`fb-min-${e}`)?.value;f!==""&&f!==void 0&&(t.min=parseFloat(f));const r=document.getElementById(`fb-max-${e}`)?.value;r!==""&&r!==void 0&&(t.max=parseFloat(r));const u=J(e);return u?t.logic=u:delete t.logic,t}function J(e){const t=document.querySelector(`.fb-field-card[data-index="${e}"]`);if(!t)return;const c=t.querySelector(".fb-field-logic");if(!c)return;const n={};let s=!1;const a=c.querySelector('[data-logic-section="visibility"]');if(a){const i=a.querySelector(".fb-logic-vis-default"),m=a.querySelector(".fb-logic-vis-transition"),p=Array.from(a.querySelectorAll(".fb-logic-cond-row")).map(u=>{const g=u.querySelector(".fb-logic-cond-field"),h=u.querySelector(".fb-logic-cond-op"),y=u.querySelector(".fb-logic-cond-val"),S=u.querySelector(".fb-logic-vis-then");return g?.value?{when:{all:[{field:g.value,operator:h.value,value:y.value}]},then:S.value}:null}).filter(Boolean),f=i?.value||"visible",r=m?.value||"none";(f!=="visible"||p.length>0||r!=="none")&&(n.visibility={default:f,conditions:p},r!=="none"&&(n.visibility.transition=r),s=!0)}const l=c.querySelector('[data-logic-section="requirement"]');if(l){const i=l.querySelector(".fb-logic-req-default"),m=Array.from(l.querySelectorAll(".fb-logic-cond-row")).map(p=>{const f=p.querySelector(".fb-logic-cond-field"),r=p.querySelector(".fb-logic-cond-op"),u=p.querySelector(".fb-logic-cond-val"),g=p.querySelector(".fb-logic-req-then");return f?.value?{when:{all:[{field:f.value,operator:r.value,value:u.value}]},then:g.value==="true"}:null}).filter(Boolean);m.length>0&&(n.requirement={default:i?.checked===!0,conditions:m},s=!0)}const d=c.querySelector('[data-logic-section="validation"]');if(d){const i=Array.from(d.querySelectorAll(".fb-logic-val-rule")).map(m=>{const p=m.querySelector(".fb-logic-val-type"),f=m.querySelector(".fb-logic-val-pattern"),r=m.querySelector(".fb-logic-val-flags"),u=m.querySelector(".fb-logic-val-message");if(!f?.value.trim())return null;const g=p?.value||"regex",h={type:g,message:u?.value.trim()||"Invalid value."};return g==="regex"?(h.pattern=f.value.trim(),r?.value.trim()&&(h.flags=r.value.trim())):h.field=f.value.trim(),h}).filter(Boolean);i.length>0&&(n.validation=i,s=!0)}const o=c.querySelector('[data-logic-section="cascade"]');if(o){const i=o.querySelector(".fb-logic-cascade-source"),m=o.querySelector(".fb-logic-cascade-mapping"),p=o.querySelector(".fb-logic-cascade-defaults"),f=i?.value?.trim();if(f){let r={};try{r=JSON.parse(m?.value||"{}")}catch{}const u=(p?.value||"").split(`
3
- `).filter(g=>g.trim()).map(g=>{const[h,...y]=g.split(":");return{value:h.trim(),label:y.join(":").trim()||h.trim()}});n.cascade={sourceField:f,mapping:r,defaultOptions:u},s=!0}}return s?n:void 0}function v(){b=b.map((e,t)=>G(t))}function x(e){const t=e.find("#fields-list").get(0),c=e.find("#fields-empty-msg").get(0);if(t){if(Array.from(t.querySelectorAll(".fb-field-card")).forEach(n=>n.remove()),b.length===0){c&&(c.style.display="");return}c&&(c.style.display="none"),b.forEach((n,s)=>{const a=n.type==="page-break"?W(n,s,e):n.type==="spacer"?Y(n,s,e):K(n,s,e);t.appendChild(a)})}}function W(e,t,c){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--border-color,#444);border-radius:6px;overflow:hidden;margin-bottom:.5rem;background:var(--card-bg,rgba(255,255,255,.02));";const s=document.createElement("div");s.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent="\u2014 Page Break \u2014",a.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:rgba(120,120,120,.2);color:var(--text-muted,#888);white-space:nowrap;flex-shrink:0;font-style:italic;";const l=document.createElement("span");l.textContent=e.label||"Untitled Step",l.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-muted,#888);";const d=document.createElement("div");if(d.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Move up",r.textContent="\u2191",r.addEventListener("click",u=>{u.stopPropagation(),v(),[b[t-1],b[t]]=[b[t],b[t-1]],x(c)}),d.appendChild(r)}if(t<b.length-1){const r=document.createElement("button");r.className="btn btn-xs btn-ghost",r.title="Move down",r.textContent="\u2193",r.addEventListener("click",u=>{u.stopPropagation(),v(),[b[t],b[t+1]]=[b[t+1],b[t]],x(c)}),d.appendChild(r)}const o=document.createElement("button");o.className="btn btn-xs btn-ghost",o.title="Edit step",o.textContent="\u22EF",o.addEventListener("click",r=>{r.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),d.appendChild(o);const i=document.createElement("button");i.className="btn btn-xs btn-danger",i.title="Remove page break",i.textContent="\u2715",i.addEventListener("click",async r=>{r.stopPropagation(),await E.confirm("Remove this page break?")&&(v(),b.splice(t,1),x(c))}),d.appendChild(i),s.appendChild(a),s.appendChild(l),s.appendChild(d),s.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=document.createElement("div");m.className="fb-field-body",m.style.cssText="padding:.8rem;border-top:1px dashed var(--border-color,#444);display:none;";const p=k([w("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),w("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),f=p.querySelector(`#fb-pb-label-${t}`);return f&&f.addEventListener("input",()=>{l.textContent=f.value||"Untitled Step"}),m.appendChild(p),n.appendChild(s),n.appendChild(m),n}function Y(e,t,c){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--border-color,#444);border-radius:6px;margin-bottom:.5rem;background:transparent;";const s=document.createElement("div");s.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(--border-color,#444);";const l=document.createElement("span");l.textContent="Spacer",l.style.cssText="font-size:.7rem;color:var(--text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const d=document.createElement("div");d.style.cssText="flex:1;height:1px;background:var(--border-color,#444);";const o=document.createElement("div");if(o.style.cssText="display:flex;gap:.25rem;flex-shrink:0;",t>0){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move up",m.textContent="\u2191",m.addEventListener("click",p=>{p.stopPropagation(),v(),[b[t-1],b[t]]=[b[t],b[t-1]],x(c)}),o.appendChild(m)}if(t<b.length-1){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move down",m.textContent="\u2193",m.addEventListener("click",p=>{p.stopPropagation(),v(),[b[t],b[t+1]]=[b[t+1],b[t]],x(c)}),o.appendChild(m)}const i=document.createElement("button");return i.className="btn btn-xs btn-danger",i.title="Remove spacer",i.textContent="\u2715",i.addEventListener("click",async m=>{m.stopPropagation(),v(),b.splice(t,1),x(c)}),o.appendChild(i),s.appendChild(a),s.appendChild(l),s.appendChild(d),s.appendChild(o),n.appendChild(s),n}function K(e,t,c){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--border-color,#333);border-radius:6px;overflow:hidden;margin-bottom:.5rem;";const s=document.createElement("div");s.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;background:var(--card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const a=document.createElement("span");a.textContent=P(e.type),a.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:var(--primary-soft,rgba(99,102,241,.15));color:var(--primary,#6366f1);white-space:nowrap;flex-shrink:0;";const l=document.createElement("span");l.textContent=e.label||"(unlabelled)",l.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const d=document.createElement("div");if(d.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Move up",p.textContent="\u2191",p.addEventListener("click",f=>{f.stopPropagation(),v(),[b[t-1],b[t]]=[b[t],b[t-1]],x(c)}),d.appendChild(p)}if(t<b.length-1){const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Move down",p.textContent="\u2193",p.addEventListener("click",f=>{f.stopPropagation(),v(),[b[t],b[t+1]]=[b[t+1],b[t]],x(c)}),d.appendChild(p)}const o=document.createElement("button");o.className="btn btn-xs btn-ghost",o.title="Edit field",o.textContent="\u22EF",o.addEventListener("click",p=>{p.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),d.appendChild(o);const i=document.createElement("button");if(i.className="btn btn-xs btn-danger",i.title="Remove field",i.textContent="\u2715",i.addEventListener("click",async p=>{p.stopPropagation(),await E.confirm("Remove this field?")&&(v(),b.splice(t,1),x(c))}),d.appendChild(i),s.appendChild(a),s.appendChild(l),e.required){const p=document.createElement("span");p.textContent="required",p.style.cssText="font-size:.7rem;color:var(--danger,#ef4444);flex-shrink:0;",s.appendChild(p)}if(M(e.logic)){const p=document.createElement("span");p.textContent="\u26A1",p.title="Has conditional logic",p.style.cssText="font-size:.75rem;color:var(--primary,#6366f1);flex-shrink:0;",s.appendChild(p)}s.appendChild(d),s.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=Q(e,t,l);return m.style.display="none",n.appendChild(s),n.appendChild(m),n}function Q(e,t,c){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:.8rem;border-top:1px solid var(--border-color,#333);";const s=k([w("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),w("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),a=k([le("Type",`fb-type-${t}`,z,e.type||"string"),D("Required",`fb-required-${t}`,e.required||!1)]),l=k([w("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field"),w("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field")]),d=e.formConfig?.span,o=k([w("Column Span",`fb-span-${t}`,"number",d&&d!=="full"?String(d):"1","Columns to span (grid only)"),D("Full Width",`fb-fullwidth-${t}`,d==="full")]);o.classList.add("fb-grid-row"),o.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(s),n.appendChild(a),n.appendChild(l),n.appendChild(o);const i=n.querySelector(`#fb-label-${t}`),m=n.querySelector(`#fb-name-${t}`);i&&i.addEventListener("input",()=>{c&&(c.textContent=i.value||"(unlabelled)"),m&&!m.dataset.manuallyEdited&&(m.value=O(i.value))}),m&&m.addEventListener("input",()=>{m.dataset.manuallyEdited="1"});const p=n.querySelector(`#fb-type-${t}`);p&&p.addEventListener("change",()=>{const r=n.closest(".fb-field-card");if(r){const h=r.querySelector("span");h&&(h.textContent=P(p.value))}const u=n.querySelector(".fb-field-extras");u&&u.remove();const g=j(p.value,e,t);g&&n.appendChild(g)});const f=j(e.type,e,t);return f&&n.appendChild(f),n.appendChild(ne(e,t)),n}const X=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],_=new Set(["is_empty","is_not_empty"]);function N(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--text-muted,#888);margin:.6rem 0 .3rem;text-transform:uppercase;letter-spacing:.04em;",t}function B(e,t,c,n,s){const a=document.createElement("div");a.className="fb-logic-cond-row",a.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const l=document.createElement("span");l.textContent="When",l.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const d=document.createElement("select");d.className="form-input fb-logic-cond-field",d.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",t.forEach(r=>{const u=document.createElement("option");u.value=r.value,u.textContent=r.label,e&&r.value===e.field&&(u.selected=!0),d.appendChild(u)});const o=document.createElement("select");o.className="form-input fb-logic-cond-op",o.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",X.forEach(r=>{const u=document.createElement("option");u.value=r.value,u.textContent=r.label,e&&r.value===e.operator&&(u.selected=!0),o.appendChild(u)});const i=document.createElement("input");i.type="text",i.className="form-input fb-logic-cond-val",i.placeholder="value",i.style.cssText="flex:2;min-width:60px;font-size:.78rem;padding:.2rem .35rem;",i.value=e?.value||"",e&&_.has(e.operator)&&(i.style.display="none"),o.addEventListener("change",()=>{i.style.display=_.has(o.value)?"none":""});const m=document.createElement("span");m.textContent="\u2192",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const p=document.createElement("select");p.className=`form-input ${n}`,p.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",c.forEach(r=>{const u=document.createElement("option");u.value=r.value,u.textContent=r.label,r.value===s&&(u.selected=!0),p.appendChild(u)});const f=document.createElement("button");return f.type="button",f.className="btn btn-xs btn-danger",f.textContent="\u2715",f.style.flexShrink="0",f.addEventListener("click",()=>a.remove()),a.appendChild(l),a.appendChild(d),a.appendChild(o),a.appendChild(i),a.appendChild(m),a.appendChild(p),a.appendChild(f),a}function Z(e,t,c){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(N("Visibility"));const s=document.createElement("div");s.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const a=document.createElement("span");a.textContent="Default:",a.style.cssText="font-size:.8rem;flex-shrink:0;";const l=document.createElement("select");l.className="form-input fb-logic-vis-default",l.style.cssText="font-size:.8rem;padding:.25rem .4rem;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(r=>{const u=document.createElement("option");u.value=r.value,u.textContent=r.label,r.value===(e.default||"visible")&&(u.selected=!0),l.appendChild(u)}),s.appendChild(a),s.appendChild(l),n.appendChild(s);const d=document.createElement("div");d.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const o=document.createElement("span");o.textContent="Transition:",o.style.cssText="font-size:.8rem;flex-shrink:0;";const i=document.createElement("select");i.className="form-input fb-logic-vis-transition",i.style.cssText="font-size:.8rem;padding:.25rem .4rem;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(r=>{const u=document.createElement("option");u.value=r.value,u.textContent=r.label,r.value===(e.transition||"none")&&(u.selected=!0),i.appendChild(u)}),d.appendChild(o),d.appendChild(i),n.appendChild(d);const m=document.createElement("div");m.className="fb-logic-vis-rules";const p=c.map(r=>({value:r.name,label:r.label||r.name})),f=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(r=>{const u=(r.when?.all||r.when?.any||[])[0],g=r.then==="hidden"?"hidden":"visible";p.length>0&&m.appendChild(B(u,p,f,"fb-logic-vis-then",g))}),n.appendChild(m),p.length>0){const r=document.createElement("button");r.type="button",r.className="btn btn-xs btn-ghost",r.style.cssText="font-size:.73rem;margin-top:.2rem;",r.textContent="+ Add visibility rule",r.addEventListener("click",()=>m.appendChild(B(null,p,f,"fb-logic-vis-then","visible"))),n.appendChild(r)}return n}function $(e,t,c){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(N("Conditional Requirement"));const s=document.createElement("label");s.style.cssText="display:flex;align-items:center;gap:.4rem;font-size:.8rem;cursor:pointer;margin-bottom:.4rem;";const a=document.createElement("input");a.type="checkbox",a.className="fb-logic-req-default",a.checked=e.default===!0,s.appendChild(a),s.appendChild(document.createTextNode("Required by default")),n.appendChild(s);const l=document.createElement("div");l.className="fb-logic-req-rules";const d=c.map(i=>({value:i.name,label:i.label||i.name})),o=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(i=>{const m=(i.when?.all||i.when?.any||[])[0],p=i.then===!0?"true":"false";d.length>0&&l.appendChild(B(m,d,o,"fb-logic-req-then",p))}),n.appendChild(l),d.length>0){const i=document.createElement("button");i.type="button",i.className="btn btn-xs btn-ghost",i.style.cssText="font-size:.73rem;margin-top:.2rem;",i.textContent="+ Add requirement rule",i.addEventListener("click",()=>l.appendChild(B(null,d,o,"fb-logic-req-then","true"))),n.appendChild(i)}return n}function A(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const c=document.createElement("select");c.className="form-input fb-logic-val-type",c.style.cssText="flex:0 0 auto;font-size:.78rem;padding:.2rem .35rem;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(d=>{const o=document.createElement("option");o.value=d.value,o.textContent=d.label,d.value===(e?.type||"regex")&&(o.selected=!0),c.appendChild(o)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;font-size:.78rem;padding:.2rem .35rem;";const s=document.createElement("input");s.type="text",s.className="form-input fb-logic-val-flags",s.placeholder="flags",s.value=e?.flags||"",s.style.cssText="flex:0 0 55px;font-size:.78rem;padding:.2rem .35rem;",e?.type==="match"&&(s.style.display="none"),c.addEventListener("change",()=>{s.style.display=c.value==="match"?"none":"",n.placeholder=c.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;font-size:.78rem;padding:.2rem .35rem;";const l=document.createElement("button");return l.type="button",l.className="btn btn-xs btn-danger",l.textContent="\u2715",l.style.flexShrink="0",l.addEventListener("click",()=>t.remove()),t.appendChild(c),t.appendChild(n),t.appendChild(s),t.appendChild(a),t.appendChild(l),t}function ee(e,t,c){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(N("Custom Validation"));const s=document.createElement("div");s.className="fb-logic-val-rules",(e||[]).forEach(l=>s.appendChild(A(l))),n.appendChild(s);const a=document.createElement("button");return a.type="button",a.className="btn btn-xs btn-ghost",a.style.cssText="font-size:.73rem;margin-top:.2rem;",a.textContent="+ Add validation rule",a.addEventListener("click",()=>s.appendChild(A(null))),n.appendChild(a),n}function te(e,t,c){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(N("Cascade Options"));const s=document.createElement("div");s.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 l=document.createElement("select");l.className="form-input fb-logic-cascade-source",l.style.cssText="flex:1;font-size:.8rem;padding:.25rem .4rem;";const d=document.createElement("option");d.value="",d.textContent="\u2014 none \u2014",l.appendChild(d),c.forEach(f=>{const r=document.createElement("option");r.value=f.name,r.textContent=f.label||f.name,f.name===e.sourceField&&(r.selected=!0),l.appendChild(r)}),s.appendChild(a),s.appendChild(l),n.appendChild(s);const o=document.createElement("p");o.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',o.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const i=document.createElement("textarea");i.className="form-input fb-logic-cascade-mapping",i.rows=4,i.style.cssText="font-family:monospace;font-size:.78rem;",i.placeholder='{"uk": [{"value": "london", "label": "London"}]}',i.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(o),n.appendChild(i);const m=document.createElement("p");m.textContent="Default options (one per line: value:Label)",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const p=document.createElement("textarea");return p.className="form-input fb-logic-cascade-defaults",p.rows=3,p.style.cssText="font-family:monospace;font-size:.78rem;",p.placeholder=`option1:Option 1
4
- option2:Option 2`,p.value=(e.defaultOptions||[]).map(f=>{const r=typeof f=="string"?f:f.value??"",u=typeof f=="string"?f:f.label??r;return r===u?r:`${r}:${u}`}).join(`
5
- `),n.appendChild(m),n.appendChild(p),n}function ne(e,t){const c=e.logic||{},n=b.filter((p,f)=>f!==t&&p.type!=="page-break"&&p.type!=="spacer"),s=document.createElement("div");s.className="fb-field-logic",s.style.cssText="margin-top:.75rem;border-top:1px solid var(--border-color,#333);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 l=document.createElement("span");l.style.cssText="font-size:.8rem;font-weight:600;color:var(--text-muted,#888);",l.textContent="\u26A1 Conditional Logic";const d=M(c),o=document.createElement("button");o.type="button",o.className="btn btn-xs btn-ghost",o.textContent=d?"\u25BE":"\u25B8";const i=document.createElement("div");i.className="fb-logic-body",i.style.cssText="padding:.25rem 0 .25rem;"+(d?"":"display:none;"),a.addEventListener("click",()=>{const p=i.style.display==="none";i.style.display=p?"":"none",o.textContent=p?"\u25BE":"\u25B8"}),a.appendChild(l),a.appendChild(o),s.appendChild(a),i.appendChild(Z(c.visibility||{},t,n)),i.appendChild($(c.requirement||{},t,n)),i.appendChild(ee(c.validation||[],t,n));const m=document.getElementById(`fb-type-${t}`)?.value||e.type;return I.has(m)&&i.appendChild(te(c.cascade||{},t,n)),s.appendChild(i),s}function j(e,t,c){const n=document.createElement("div");return n.className="fb-field-extras",I.has(e)&&n.appendChild(ae(t.options||[],c)),e==="textarea"&&n.appendChild(k([w("Rows",`fb-rows-${c}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(k([w("Min Length",`fb-minlength-${c}`,"number",t.minLength||"",""),w("Max Length",`fb-maxlength-${c}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(k([w("Min",`fb-min-${c}`,"number",t.min??"",""),w("Max",`fb-max-${c}`,"number",t.max??"","")])),n.children.length?n:null}function k(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.75rem;margin-bottom:.6rem;",e.forEach(c=>{c&&t.appendChild(c)}),t}function w(e,t,c,n,s){const a=document.createElement("div");a.style.flex="1";const l=document.createElement("label");l.htmlFor=t,l.className="form-label",l.textContent=e,l.style.fontSize=".8rem";const d=document.createElement("input");if(d.id=t,d.type=c||"text",d.className="form-input",d.value=n??"",a.appendChild(l),a.appendChild(d),s){const o=document.createElement("p");o.className="form-hint text-muted",o.textContent=s,o.style.cssText="font-size:.73rem;margin-top:.2rem;",a.appendChild(o)}return a}function le(e,t,c,n){const s=document.createElement("div");s.style.flex="1";const a=document.createElement("label");a.htmlFor=t,a.className="form-label",a.textContent=e,a.style.fontSize=".8rem";const l=document.createElement("select");return l.id=t,l.className="form-input",c.forEach(d=>{const o=document.createElement("option");o.value=d.value,o.textContent=d.label,d.value===n&&(o.selected=!0),l.appendChild(o)}),s.appendChild(a),s.appendChild(l),s}function D(e,t,c){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const s=document.createElement("label");s.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=c,s.appendChild(a),s.appendChild(document.createTextNode(e)),n.appendChild(s),n}function ae(e,t){const c=document.createElement("div");c.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 s=document.createElement("textarea");return s.id=`fb-options-${t}`,s.className="form-input",s.rows=4,s.placeholder=`yes:Yes
1
+ import{apiRequest as S}from"/admin/js/api.js";const B=[{value:"string",label:"Text (single line)"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"number",label:"Number"},{value:"textarea",label:"Textarea (multi-line)"},{value:"select",label:"Dropdown (select)"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Single checkbox"},{value:"checkbox-group",label:"Checkbox group"},{value:"date",label:"Date"},{value:"time",label:"Time"},{value:"url",label:"URL"},{value:"password",label:"Password"},{value:"file",label:"File upload"},{value:"hidden",label:"Hidden field"}],z=new Set(["select","radio","checkbox-group"]);let b=[],x=null,T=null,q=null;function I(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"")}function P(e){return B.find(t=>t.value===e)?.label||e}function M(e){return e?!!(e.visibility?.conditions?.length||e.requirement?.conditions?.length||e.validation?.length||e.cascade?.sourceField):!1}function D(e){const t={...b[e]};if(t.type==="spacer")return t;if(t.type==="page-break"){const g=document.getElementById(`fb-pb-label-${e}`),h=document.getElementById(`fb-pb-desc-${e}`);return g&&(t.label=g.value.trim()||t.label),h&&(t.description=h.value.trim()),t}const o=document.getElementById(`fb-label-${e}`),n=document.getElementById(`fb-name-${e}`),a=document.getElementById(`fb-type-${e}`),l=document.getElementById(`fb-required-${e}`),r=document.getElementById(`fb-placeholder-${e}`),i=document.getElementById(`fb-helper-${e}`);if(o&&(t.label=o.value.trim()||t.label),n&&(t.name=n.value.trim()||t.name),a&&(t.type=a.value||t.type),l&&(t.required=l.checked),r&&(t.placeholder=r.value.trim()),i&&(t.helper=i.value.trim()),z.has(t.type)){const g=document.getElementById(`fb-options-${e}`);g&&(t.options=g.value.split(`
2
+ `).filter(h=>h.trim()).map(h=>{const[w,...$]=h.split(":");return{value:w.trim(),label:$.join(":").trim()||w.trim()}}))}if(t.type==="textarea"){const g=parseInt(document.getElementById(`fb-rows-${e}`)?.value,10);g>0&&(t.formConfig={...t.formConfig||{},rows:g})}const p=document.getElementById(`fb-span-${e}`),d=document.getElementById(`fb-fullwidth-${e}`);if(p||d){const g={...t.formConfig||{}};if(d?.checked)g.span="full";else{const h=parseInt(p?.value,10);h>1?g.span=h:delete g.span}t.formConfig=Object.keys(g).length?g:void 0}const m=document.getElementById(`fb-minlength-${e}`)?.value;m&&(t.minLength=parseInt(m,10));const c=document.getElementById(`fb-maxlength-${e}`)?.value;c&&(t.maxLength=parseInt(c,10));const u=document.getElementById(`fb-min-${e}`)?.value;u!==""&&u!==void 0&&(t.min=parseFloat(u));const s=document.getElementById(`fb-max-${e}`)?.value;s!==""&&s!==void 0&&(t.max=parseFloat(s));const f=V(e);return f?t.logic=f:delete t.logic,t}function V(e){const t=document.querySelector(`.fb-field-card[data-index="${e}"]`);if(!t)return;const o=t.querySelector(".fb-field-logic");if(!o)return;const n={};let a=!1;const l=o.querySelector('[data-logic-section="visibility"]');if(l){const d=l.querySelector(".fb-logic-vis-default"),m=l.querySelector(".fb-logic-vis-transition"),c=Array.from(l.querySelectorAll(".fb-logic-cond-row")).map(f=>{const g=f.querySelector(".fb-logic-cond-field"),h=f.querySelector(".fb-logic-cond-op"),w=f.querySelector(".fb-logic-cond-val"),$=f.querySelector(".fb-logic-vis-then");return g?.value?{when:{all:[{field:g.value,operator:h.value,value:w.value}]},then:$.value}:null}).filter(Boolean),u=d?.value||"visible",s=m?.value||"none";(u!=="visible"||c.length>0||s!=="none")&&(n.visibility={default:u,conditions:c},s!=="none"&&(n.visibility.transition=s),a=!0)}const r=o.querySelector('[data-logic-section="requirement"]');if(r){const d=r.querySelector(".fb-logic-req-default"),m=Array.from(r.querySelectorAll(".fb-logic-cond-row")).map(c=>{const u=c.querySelector(".fb-logic-cond-field"),s=c.querySelector(".fb-logic-cond-op"),f=c.querySelector(".fb-logic-cond-val"),g=c.querySelector(".fb-logic-req-then");return u?.value?{when:{all:[{field:u.value,operator:s.value,value:f.value}]},then:g.value==="true"}:null}).filter(Boolean);m.length>0&&(n.requirement={default:d?.checked===!0,conditions:m},a=!0)}const i=o.querySelector('[data-logic-section="validation"]');if(i){const d=Array.from(i.querySelectorAll(".fb-logic-val-rule")).map(m=>{const c=m.querySelector(".fb-logic-val-type"),u=m.querySelector(".fb-logic-val-pattern"),s=m.querySelector(".fb-logic-val-flags"),f=m.querySelector(".fb-logic-val-message");if(!u?.value.trim())return null;const g=c?.value||"regex",h={type:g,message:f?.value.trim()||"Invalid value."};return g==="regex"?(h.pattern=u.value.trim(),s?.value.trim()&&(h.flags=s.value.trim())):h.field=u.value.trim(),h}).filter(Boolean);d.length>0&&(n.validation=d,a=!0)}const p=o.querySelector('[data-logic-section="cascade"]');if(p){const d=p.querySelector(".fb-logic-cascade-source"),m=p.querySelector(".fb-logic-cascade-mapping"),c=p.querySelector(".fb-logic-cascade-defaults"),u=d?.value?.trim();if(u){let s={};try{s=JSON.parse(m?.value||"{}")}catch{}const f=(c?.value||"").split(`
3
+ `).filter(g=>g.trim()).map(g=>{const[h,...w]=g.split(":");return{value:h.trim(),label:w.join(":").trim()||h.trim()}});n.cascade={sourceField:u,mapping:s,defaultOptions:f},a=!0}}return a?n:void 0}function y(){b=b.map((e,t)=>D(t))}function v(e){const t=e.find("#fields-list").get(0),o=e.find("#fields-empty-msg").get(0);if(t){if(Array.from(t.querySelectorAll(".fb-field-card")).forEach(n=>n.remove()),b.length===0){o&&(o.style.display="");return}o&&(o.style.display="none"),b.forEach((n,a)=>{const l=n.type==="page-break"?W(n,a,e):n.type==="spacer"?Y(n,a,e):G(n,a,e);t.appendChild(l)})}}function W(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:2px dashed var(--border-color,#444);border-radius:6px;overflow:hidden;margin-bottom:.5rem;background:var(--card-bg,rgba(255,255,255,.02));";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent="\u2014 Page Break \u2014",l.style.cssText="font-size:.7rem;padding:.15rem .5rem;border-radius:999px;background:rgba(120,120,120,.2);color:var(--text-muted,#888);white-space:nowrap;flex-shrink:0;font-style:italic;";const r=document.createElement("span");r.textContent=e.label||"Untitled Step",r.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text-muted,#888);";const i=document.createElement("div");if(i.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.title="Move up",s.textContent="\u2191",s.addEventListener("click",f=>{f.stopPropagation(),y(),[b[t-1],b[t]]=[b[t],b[t-1]],v(o)}),i.appendChild(s)}if(t<b.length-1){const s=document.createElement("button");s.className="btn btn-xs btn-ghost",s.title="Move down",s.textContent="\u2193",s.addEventListener("click",f=>{f.stopPropagation(),y(),[b[t],b[t+1]]=[b[t+1],b[t]],v(o)}),i.appendChild(s)}const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Edit step",p.textContent="\u22EF",p.addEventListener("click",s=>{s.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),i.appendChild(p);const d=document.createElement("button");d.className="btn btn-xs btn-danger",d.title="Remove page break",d.textContent="\u2715",d.addEventListener("click",async s=>{s.stopPropagation(),await E.confirm("Remove this page break?")&&(y(),b.splice(t,1),v(o))}),i.appendChild(d),a.appendChild(l),a.appendChild(r),a.appendChild(i),a.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=document.createElement("div");m.className="fb-field-body",m.style.cssText="padding:.8rem;border-top:1px dashed var(--border-color,#444);display:none;";const c=k([C("Step Title",`fb-pb-label-${t}`,"text",e.label||"","Shown as the wizard step heading"),C("Step Description",`fb-pb-desc-${t}`,"text",e.description||"","Optional sub-heading")]),u=c.querySelector(`#fb-pb-label-${t}`);return u&&u.addEventListener("input",()=>{r.textContent=u.value||"Untitled Step"}),m.appendChild(c),n.appendChild(a),n.appendChild(m),n}function Y(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px dashed var(--border-color,#444);border-radius:6px;margin-bottom:.5rem;background:transparent;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.4rem .8rem;";const l=document.createElement("div");l.style.cssText="flex:1;height:1px;background:var(--border-color,#444);";const r=document.createElement("span");r.textContent="Spacer",r.style.cssText="font-size:.7rem;color:var(--text-muted,#888);white-space:nowrap;padding:0 .4rem;font-style:italic;";const i=document.createElement("div");i.style.cssText="flex:1;height:1px;background:var(--border-color,#444);";const p=document.createElement("div");if(p.style.cssText="display:flex;gap:.25rem;flex-shrink:0;",t>0){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move up",m.textContent="\u2191",m.addEventListener("click",c=>{c.stopPropagation(),y(),[b[t-1],b[t]]=[b[t],b[t-1]],v(o)}),p.appendChild(m)}if(t<b.length-1){const m=document.createElement("button");m.className="btn btn-xs btn-ghost",m.title="Move down",m.textContent="\u2193",m.addEventListener("click",c=>{c.stopPropagation(),y(),[b[t],b[t+1]]=[b[t+1],b[t]],v(o)}),p.appendChild(m)}const d=document.createElement("button");return d.className="btn btn-xs btn-danger",d.title="Remove spacer",d.textContent="\u2715",d.addEventListener("click",async m=>{m.stopPropagation(),y(),b.splice(t,1),v(o)}),p.appendChild(d),a.appendChild(l),a.appendChild(r),a.appendChild(i),a.appendChild(p),n.appendChild(a),n}function G(e,t,o){const n=document.createElement("div");n.className="fb-field-card",n.dataset.index=t,n.style.cssText="border:1px solid var(--border-color,#333);border-radius:6px;overflow:hidden;margin-bottom:.5rem;";const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.6rem;padding:.6rem .8rem;background:var(--card-header-bg,rgba(255,255,255,.04));cursor:pointer;user-select:none;";const l=document.createElement("span");l.textContent=P(e.type),l.style.cssText="font-size:.7rem;padding:.15rem .45rem;border-radius:999px;background:var(--primary-soft,rgba(99,102,241,.15));color:var(--primary,#6366f1);white-space:nowrap;flex-shrink:0;";const r=document.createElement("span");r.textContent=e.label||"(unlabelled)",r.style.cssText="flex:1;font-weight:600;font-size:.9rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;";const i=document.createElement("div");if(i.style.cssText="display:flex;gap:.25rem;flex-shrink:0;margin-left:.5rem;",t>0){const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Move up",c.textContent="\u2191",c.addEventListener("click",u=>{u.stopPropagation(),y(),[b[t-1],b[t]]=[b[t],b[t-1]],v(o)}),i.appendChild(c)}if(t<b.length-1){const c=document.createElement("button");c.className="btn btn-xs btn-ghost",c.title="Move down",c.textContent="\u2193",c.addEventListener("click",u=>{u.stopPropagation(),y(),[b[t],b[t+1]]=[b[t+1],b[t]],v(o)}),i.appendChild(c)}const p=document.createElement("button");p.className="btn btn-xs btn-ghost",p.title="Edit field",p.textContent="\u22EF",p.addEventListener("click",c=>{c.stopPropagation(),m.style.display=m.style.display==="none"?"":"none"}),i.appendChild(p);const d=document.createElement("button");if(d.className="btn btn-xs btn-danger",d.title="Remove field",d.textContent="\u2715",d.addEventListener("click",async c=>{c.stopPropagation(),await E.confirm("Remove this field?")&&(y(),b.splice(t,1),v(o))}),i.appendChild(d),a.appendChild(l),a.appendChild(r),e.required){const c=document.createElement("span");c.textContent="required",c.style.cssText="font-size:.7rem;color:var(--danger,#ef4444);flex-shrink:0;",a.appendChild(c)}if(M(e.logic)){const c=document.createElement("span");c.textContent="\u26A1",c.title="Has conditional logic",c.style.cssText="font-size:.75rem;color:var(--primary,#6366f1);flex-shrink:0;",a.appendChild(c)}a.appendChild(i),a.addEventListener("click",()=>{m.style.display=m.style.display==="none"?"":"none"});const m=K(e,t,r);return m.style.display="none",n.appendChild(a),n.appendChild(m),n}function K(e,t,o){const n=document.createElement("div");n.className="fb-field-body",n.style.cssText="padding:.8rem;border-top:1px solid var(--border-color,#333);";const a=k([C("Label",`fb-label-${t}`,"text",e.label||"","Shown above the field"),C("Field Name",`fb-name-${t}`,"text",e.name||"","Used as data key")]),l=k([le("Type",`fb-type-${t}`,B,e.type||"string"),j("Required",`fb-required-${t}`,e.required||!1)]),r=k([C("Placeholder",`fb-placeholder-${t}`,"text",e.placeholder||"","Hint text inside the field"),C("Helper Text",`fb-helper-${t}`,"text",e.helper||"","Shown below the field")]),i=e.formConfig?.span,p=k([C("Column Span",`fb-span-${t}`,"number",i&&i!=="full"?String(i):"1","Columns to span (grid only)"),j("Full Width",`fb-fullwidth-${t}`,i==="full")]);p.classList.add("fb-grid-row"),p.style.display=document.getElementById("setting-layout")?.value==="grid"?"flex":"none",n.appendChild(a),n.appendChild(l),n.appendChild(r),n.appendChild(p);const d=n.querySelector(`#fb-label-${t}`),m=n.querySelector(`#fb-name-${t}`);d&&d.addEventListener("input",()=>{o&&(o.textContent=d.value||"(unlabelled)"),m&&!m.dataset.manuallyEdited&&(m.value=I(d.value))}),m&&m.addEventListener("input",()=>{m.dataset.manuallyEdited="1"});const c=n.querySelector(`#fb-type-${t}`);c&&c.addEventListener("change",()=>{const s=n.closest(".fb-field-card");if(s){const h=s.querySelector("span");h&&(h.textContent=P(c.value))}const f=n.querySelector(".fb-field-extras");f&&f.remove();const g=O(c.value,e,t);g&&n.appendChild(g)});const u=O(e.type,e,t);return u&&n.appendChild(u),n.appendChild(ne(e,t)),n}const Q=[{value:"equals",label:"equals"},{value:"not_equals",label:"does not equal"},{value:"contains",label:"contains"},{value:"not_contains",label:"does not contain"},{value:"starts_with",label:"starts with"},{value:"ends_with",label:"ends with"},{value:"greater_than",label:"is greater than"},{value:"less_than",label:"is less than"},{value:"is_empty",label:"is empty"},{value:"is_not_empty",label:"is not empty"},{value:"in",label:"is one of (comma sep)"},{value:"not_in",label:"is not one of (comma sep)"},{value:"matches_regex",label:"matches regex"}],_=new Set(["is_empty","is_not_empty"]);function N(e){const t=document.createElement("p");return t.textContent=e,t.style.cssText="font-size:.75rem;font-weight:700;color:var(--text-muted,#888);margin:.6rem 0 .3rem;text-transform:uppercase;letter-spacing:.04em;",t}function L(e,t,o,n,a){const l=document.createElement("div");l.className="fb-logic-cond-row",l.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const r=document.createElement("span");r.textContent="When",r.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const i=document.createElement("select");i.className="form-input fb-logic-cond-field",i.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",t.forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,e&&s.value===e.field&&(f.selected=!0),i.appendChild(f)});const p=document.createElement("select");p.className="form-input fb-logic-cond-op",p.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",Q.forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,e&&s.value===e.operator&&(f.selected=!0),p.appendChild(f)});const d=document.createElement("input");d.type="text",d.className="form-input fb-logic-cond-val",d.placeholder="value",d.style.cssText="flex:2;min-width:60px;font-size:.78rem;padding:.2rem .35rem;",d.value=e?.value||"",e&&_.has(e.operator)&&(d.style.display="none"),p.addEventListener("change",()=>{d.style.display=_.has(p.value)?"none":""});const m=document.createElement("span");m.textContent="\u2192",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);flex-shrink:0;";const c=document.createElement("select");c.className=`form-input ${n}`,c.style.cssText="flex:2;min-width:80px;font-size:.78rem;padding:.2rem .35rem;",o.forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,s.value===a&&(f.selected=!0),c.appendChild(f)});const u=document.createElement("button");return u.type="button",u.className="btn btn-xs btn-danger",u.textContent="\u2715",u.style.flexShrink="0",u.addEventListener("click",()=>l.remove()),l.appendChild(r),l.appendChild(i),l.appendChild(p),l.appendChild(d),l.appendChild(m),l.appendChild(c),l.appendChild(u),l}function X(e,t,o){const n=document.createElement("div");n.dataset.logicSection="visibility",n.appendChild(N("Visibility"));const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const l=document.createElement("span");l.textContent="Default:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const r=document.createElement("select");r.className="form-input fb-logic-vis-default",r.style.cssText="font-size:.8rem;padding:.25rem .4rem;",[{value:"visible",label:"Visible"},{value:"hidden",label:"Hidden"}].forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,s.value===(e.default||"visible")&&(f.selected=!0),r.appendChild(f)}),a.appendChild(l),a.appendChild(r),n.appendChild(a);const i=document.createElement("div");i.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem;";const p=document.createElement("span");p.textContent="Transition:",p.style.cssText="font-size:.8rem;flex-shrink:0;";const d=document.createElement("select");d.className="form-input fb-logic-vis-transition",d.style.cssText="font-size:.8rem;padding:.25rem .4rem;",[{value:"none",label:"None (instant)"},{value:"fade",label:"Fade"},{value:"slide",label:"Slide"},{value:"scale",label:"Scale"}].forEach(s=>{const f=document.createElement("option");f.value=s.value,f.textContent=s.label,s.value===(e.transition||"none")&&(f.selected=!0),d.appendChild(f)}),i.appendChild(p),i.appendChild(d),n.appendChild(i);const m=document.createElement("div");m.className="fb-logic-vis-rules";const c=o.map(s=>({value:s.name,label:s.label||s.name})),u=[{value:"visible",label:"Show"},{value:"hidden",label:"Hide"}];if((e.conditions||[]).forEach(s=>{const f=(s.when?.all||s.when?.any||[])[0],g=s.then==="hidden"?"hidden":"visible";c.length>0&&m.appendChild(L(f,c,u,"fb-logic-vis-then",g))}),n.appendChild(m),c.length>0){const s=document.createElement("button");s.type="button",s.className="btn btn-xs btn-ghost",s.style.cssText="font-size:.73rem;margin-top:.2rem;",s.textContent="+ Add visibility rule",s.addEventListener("click",()=>m.appendChild(L(null,c,u,"fb-logic-vis-then","visible"))),n.appendChild(s)}return n}function Z(e,t,o){const n=document.createElement("div");n.dataset.logicSection="requirement",n.appendChild(N("Conditional Requirement"));const a=document.createElement("label");a.style.cssText="display:flex;align-items:center;gap:.4rem;font-size:.8rem;cursor:pointer;margin-bottom:.4rem;";const l=document.createElement("input");l.type="checkbox",l.className="fb-logic-req-default",l.checked=e.default===!0,a.appendChild(l),a.appendChild(document.createTextNode("Required by default")),n.appendChild(a);const r=document.createElement("div");r.className="fb-logic-req-rules";const i=o.map(d=>({value:d.name,label:d.label||d.name})),p=[{value:"true",label:"Make required"},{value:"false",label:"Make optional"}];if((e.conditions||[]).forEach(d=>{const m=(d.when?.all||d.when?.any||[])[0],c=d.then===!0?"true":"false";i.length>0&&r.appendChild(L(m,i,p,"fb-logic-req-then",c))}),n.appendChild(r),i.length>0){const d=document.createElement("button");d.type="button",d.className="btn btn-xs btn-ghost",d.style.cssText="font-size:.73rem;margin-top:.2rem;",d.textContent="+ Add requirement rule",d.addEventListener("click",()=>r.appendChild(L(null,i,p,"fb-logic-req-then","true"))),n.appendChild(d)}return n}function A(e){const t=document.createElement("div");t.className="fb-logic-val-rule",t.style.cssText="display:flex;gap:.35rem;align-items:center;margin-bottom:.35rem;flex-wrap:wrap;";const o=document.createElement("select");o.className="form-input fb-logic-val-type",o.style.cssText="flex:0 0 auto;font-size:.78rem;padding:.2rem .35rem;",[{value:"regex",label:"Regex"},{value:"match",label:"Match field"}].forEach(i=>{const p=document.createElement("option");p.value=i.value,p.textContent=i.label,i.value===(e?.type||"regex")&&(p.selected=!0),o.appendChild(p)});const n=document.createElement("input");n.type="text",n.className="form-input fb-logic-val-pattern",n.placeholder=e?.type==="match"?"field name":"pattern",n.value=e?.pattern||e?.field||"",n.style.cssText="flex:3;font-size:.78rem;padding:.2rem .35rem;";const a=document.createElement("input");a.type="text",a.className="form-input fb-logic-val-flags",a.placeholder="flags",a.value=e?.flags||"",a.style.cssText="flex:0 0 55px;font-size:.78rem;padding:.2rem .35rem;",e?.type==="match"&&(a.style.display="none"),o.addEventListener("change",()=>{a.style.display=o.value==="match"?"none":"",n.placeholder=o.value==="match"?"field name":"pattern"});const l=document.createElement("input");l.type="text",l.className="form-input fb-logic-val-message",l.placeholder="Error message",l.value=e?.message||"",l.style.cssText="flex:4;font-size:.78rem;padding:.2rem .35rem;";const r=document.createElement("button");return r.type="button",r.className="btn btn-xs btn-danger",r.textContent="\u2715",r.style.flexShrink="0",r.addEventListener("click",()=>t.remove()),t.appendChild(o),t.appendChild(n),t.appendChild(a),t.appendChild(l),t.appendChild(r),t}function ee(e,t,o){const n=document.createElement("div");n.dataset.logicSection="validation",n.appendChild(N("Custom Validation"));const a=document.createElement("div");a.className="fb-logic-val-rules",(e||[]).forEach(r=>a.appendChild(A(r))),n.appendChild(a);const l=document.createElement("button");return l.type="button",l.className="btn btn-xs btn-ghost",l.style.cssText="font-size:.73rem;margin-top:.2rem;",l.textContent="+ Add validation rule",l.addEventListener("click",()=>a.appendChild(A(null))),n.appendChild(l),n}function te(e,t,o){const n=document.createElement("div");n.dataset.logicSection="cascade",n.appendChild(N("Cascade Options"));const a=document.createElement("div");a.style.cssText="display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem;";const l=document.createElement("span");l.textContent="Source field:",l.style.cssText="font-size:.8rem;flex-shrink:0;";const r=document.createElement("select");r.className="form-input fb-logic-cascade-source",r.style.cssText="flex:1;font-size:.8rem;padding:.25rem .4rem;";const i=document.createElement("option");i.value="",i.textContent="\u2014 none \u2014",r.appendChild(i),o.forEach(u=>{const s=document.createElement("option");s.value=u.name,s.textContent=u.label||u.name,u.name===e.sourceField&&(s.selected=!0),r.appendChild(s)}),a.appendChild(l),a.appendChild(r),n.appendChild(a);const p=document.createElement("p");p.textContent='Mapping JSON \u2014 {"value":[{"value":"...","label":"..."}]}',p.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const d=document.createElement("textarea");d.className="form-input fb-logic-cascade-mapping",d.rows=4,d.style.cssText="font-family:monospace;font-size:.78rem;",d.placeholder='{"uk": [{"value": "london", "label": "London"}]}',d.value=e.mapping?JSON.stringify(e.mapping,null,2):"",n.appendChild(p),n.appendChild(d);const m=document.createElement("p");m.textContent="Default options (one per line: value:Label)",m.style.cssText="font-size:.73rem;color:var(--text-muted,#888);margin:.3rem 0 .2rem;";const c=document.createElement("textarea");return c.className="form-input fb-logic-cascade-defaults",c.rows=3,c.style.cssText="font-family:monospace;font-size:.78rem;",c.placeholder=`option1:Option 1
4
+ option2:Option 2`,c.value=(e.defaultOptions||[]).map(u=>{const s=typeof u=="string"?u:u.value??"",f=typeof u=="string"?u:u.label??s;return s===f?s:`${s}:${f}`}).join(`
5
+ `),n.appendChild(m),n.appendChild(c),n}function ne(e,t){const o=e.logic||{},n=b.filter((c,u)=>u!==t&&c.type!=="page-break"&&c.type!=="spacer"),a=document.createElement("div");a.className="fb-field-logic",a.style.cssText="margin-top:.75rem;border-top:1px solid var(--border-color,#333);padding-top:.5rem;";const l=document.createElement("div");l.style.cssText="display:flex;align-items:center;justify-content:space-between;cursor:pointer;padding:.15rem 0;";const r=document.createElement("span");r.style.cssText="font-size:.8rem;font-weight:600;color:var(--text-muted,#888);",r.textContent="\u26A1 Conditional Logic";const i=M(o),p=document.createElement("button");p.type="button",p.className="btn btn-xs btn-ghost",p.textContent=i?"\u25BE":"\u25B8";const d=document.createElement("div");d.className="fb-logic-body",d.style.cssText="padding:.25rem 0 .25rem;"+(i?"":"display:none;"),l.addEventListener("click",()=>{const c=d.style.display==="none";d.style.display=c?"":"none",p.textContent=c?"\u25BE":"\u25B8"}),l.appendChild(r),l.appendChild(p),a.appendChild(l),d.appendChild(X(o.visibility||{},t,n)),d.appendChild(Z(o.requirement||{},t,n)),d.appendChild(ee(o.validation||[],t,n));const m=document.getElementById(`fb-type-${t}`)?.value||e.type;return z.has(m)&&d.appendChild(te(o.cascade||{},t,n)),a.appendChild(d),a}function O(e,t,o){const n=document.createElement("div");return n.className="fb-field-extras",z.has(e)&&n.appendChild(ae(t.options||[],o)),e==="textarea"&&n.appendChild(k([C("Rows",`fb-rows-${o}`,"number",t.formConfig?.rows||4,"Height of textarea")])),(e==="string"||e==="textarea")&&n.appendChild(k([C("Min Length",`fb-minlength-${o}`,"number",t.minLength||"",""),C("Max Length",`fb-maxlength-${o}`,"number",t.maxLength||"","")])),e==="number"&&n.appendChild(k([C("Min",`fb-min-${o}`,"number",t.min??"",""),C("Max",`fb-max-${o}`,"number",t.max??"","")])),n.children.length?n:null}function k(e){const t=document.createElement("div");return t.style.cssText="display:flex;gap:.75rem;margin-bottom:.6rem;",e.forEach(o=>{o&&t.appendChild(o)}),t}function C(e,t,o,n,a){const l=document.createElement("div");l.style.flex="1";const r=document.createElement("label");r.htmlFor=t,r.className="form-label",r.textContent=e,r.style.fontSize=".8rem";const i=document.createElement("input");if(i.id=t,i.type=o||"text",i.className="form-input",i.value=n??"",l.appendChild(r),l.appendChild(i),a){const p=document.createElement("p");p.className="form-hint text-muted",p.textContent=a,p.style.cssText="font-size:.73rem;margin-top:.2rem;",l.appendChild(p)}return l}function le(e,t,o,n){const a=document.createElement("div");a.style.flex="1";const l=document.createElement("label");l.htmlFor=t,l.className="form-label",l.textContent=e,l.style.fontSize=".8rem";const r=document.createElement("select");return r.id=t,r.className="form-input",o.forEach(i=>{const p=document.createElement("option");p.value=i.value,p.textContent=i.label,i.value===n&&(p.selected=!0),r.appendChild(p)}),a.appendChild(l),a.appendChild(r),a}function j(e,t,o){const n=document.createElement("div");n.style.cssText="flex:0;min-width:80px;display:flex;flex-direction:column;justify-content:flex-end;";const a=document.createElement("label");a.style.cssText="display:flex;align-items:center;gap:.4rem;cursor:pointer;font-size:.8rem;white-space:nowrap;";const l=document.createElement("input");return l.id=t,l.type="checkbox",l.checked=o,a.appendChild(l),a.appendChild(document.createTextNode(e)),n.appendChild(a),n}function ae(e,t){const o=document.createElement("div");o.style.cssText="margin-top:.4rem;";const n=document.createElement("p");n.textContent="Options (one per line: value or value:Label)",n.style.cssText="font-size:.8rem;font-weight:600;margin-bottom:.3rem;";const a=document.createElement("textarea");return a.id=`fb-options-${t}`,a.className="form-input",a.rows=4,a.placeholder=`yes:Yes
6
6
  no:No
7
- maybe:Maybe`,s.value=(e||[]).map(a=>{const l=typeof a=="string"?a:a.value??"",d=typeof a=="string"?a:a.label??l;return l===d?l:`${l}:${d}`}).join(`
8
- `),s.style.fontFamily="monospace",c.appendChild(n),c.appendChild(s),c}function V(e){return v(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},fields:b,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"stacked",columns:parseInt(e.find("#setting-columns").val(),10)||2,submitSpan:e.find("#setting-submit-span").val()||"",honeypot:e.find("#setting-honeypot").prop("checked"),rateLimitPerMinute:parseInt(e.find("#setting-rate-limit").val(),10)||3,successRedirect:e.find("#setting-success-redirect").val().trim()||null,actionSlug:e.find("#action-cms-slug").val()||null},actions:{email:{enabled:e.find("#action-email-enabled").prop("checked"),recipients:e.find("#action-email-recipients").val().trim(),subjectPrefix:e.find("#action-email-subject-prefix").val().trim()},webhook:{enabled:e.find("#action-webhook-enabled").prop("checked"),url:e.find("#action-webhook-url").val().trim(),method:e.find("#action-webhook-method").val()},...L!==null&&{collection:L}}}}function se(e){const t=[];let c=[],n="Step 1",s="";return e.forEach(a=>{a.type==="page-break"?(t.push({title:n,description:s,fields:c}),c=[],n=a.label||`Step ${t.length+1}`,s=a.description||""):a.type!=="spacer"&&c.push(a)}),(c.length||t.length===0)&&t.push({title:n,description:s,fields:c}),t}function H(e,t){const c={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const s={...n.formConfig||{}};s.span==="full"&&t&&(s.span=t);const a=n.type==="checkbox"?"boolean":n.type==="date"?"string":n.type;c[n.name]={type:a,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{hint:n.helper},...s}}}),c}function U(e,t){const c=typeof e=="string"?document.querySelector(e):e;c&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const s=c.querySelector(`[name="${n.name}"]`);s&&s.type!=="date"&&(s.type="date")})}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){b=[],C=null,L=null;const c=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);C=c?c[1]:null;let n=null;if(C)try{n=await T(`/forms/${C}`),b=n.fields||[],L=n.actions?.collection??null}catch{E.toast("Could not load form.",{type:"error"})}if(n?e.find("#editor-title").get(0).textContent=`Edit: ${n.title}`:e.find("#editor-title").get(0).textContent="New Form",C||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(O(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),n){e.find("#field-title").val(n.title),e.find("#field-slug").val(n.slug),e.find("#field-description").val(n.description||""),e.find("#field-bundled").prop("checked",!!n.bundled);const l=n.settings||{};e.find("#setting-submit-text").val(l.submitText||"Submit"),e.find("#setting-success-message").val(l.successMessage||""),e.find("#setting-layout").val(l.layout||"stacked"),e.find("#setting-columns").val(l.columns||2),e.find("#setting-submit-span").val(l.submitSpan||""),e.find("#columns-group").get(0).style.display=l.layout==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",l.honeypot!==!1),e.find("#setting-rate-limit").val(l.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(l.successRedirect||"");const d=n.actions?.email||{};e.find("#action-email-enabled").prop("checked",d.enabled||!1),e.find("#action-email-recipients").val(d.recipients||""),e.find("#action-email-subject-prefix").val(d.subjectPrefix||"");const o=n.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",o.enabled||!1),e.find("#action-webhook-url").val(o.url||""),e.find("#action-webhook-method").val(o.method||"POST")}const s=n?.settings?.actionSlug||"";try{const l=await T("/actions").catch(()=>[]),d=e.find("#action-cms-slug").get(0);if((Array.isArray(l)?l:[]).forEach(o=>{const i=document.createElement("option");i.value=o.slug,i.textContent=o.title||o.slug,o.slug===s&&(i.selected=!0),d.appendChild(i)}),!l.length){const o=document.createElement("option");o.value="",o.textContent="No actions available",o.disabled=!0,d.appendChild(o)}}catch{}e.find("#setting-layout").get(0)?.addEventListener("change",function(){const l=this.value==="grid";e.find("#columns-group").get(0).style.display=l?"":"none",document.querySelectorAll(".fb-grid-row").forEach(d=>{d.style.display=l?"flex":"none"})}),x(e);const a=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",l=>{l.stopPropagation(),a.style.display=a.style.display==="none"?"":"none"}),q&&document.removeEventListener("click",q),q=()=>{a&&(a.style.display="none")},document.addEventListener("click",q),e.find("#add-field-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),v();const l=b.length;b.push({name:`field_${l+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),x(e);const o=e.find("#fields-list").get(0)?.lastElementChild;if(o){const i=o.querySelector(".fb-field-body");i&&(i.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),v(),b.push({type:"spacer"}),x(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),v();const l=b.filter(d=>d.type==="page-break").length+2;b.push({type:"page-break",label:`Step ${l}`,description:""}),x(e)}),e.find("#save-form-btn").get(0).addEventListener("click",async()=>{const l=V(e);if(!l.title){E.toast("Please enter a form title.",{type:"error"});return}try{C?(await T(`/forms/${C}`,{method:"PUT",body:JSON.stringify(l)}),E.toast("Form saved.",{type:"success"})):(C=(await T("/forms",{method:"POST",body:JSON.stringify(l)})).slug,R.navigate(`/forms/edit/${C}`),E.toast("Form created.",{type:"success"}))}catch(d){E.toast(d.message||"Failed to save form.",{type:"error"})}}),e.find("#preview-btn").get(0).addEventListener("click",()=>{const l=V(e),d=e.find("#preview-container").get(0);if(!d)return;const o=e.find("#preview-test-result").get(0),i=e.find("#preview-test-badge").get(0);o&&(o.style.display="none",o.textContent=""),i&&(i.style.display=C?"":"none"),e.find("#preview-card").get(0).style.display="",d.textContent="";const m=document.createElement("div");m.id="fb-preview-form",d.appendChild(m);const p=C?async r=>{o&&(o.style.display="none",o.textContent="");try{const u=await fetch(`/api/forms/submit/${C}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)}),g=await u.json();if(!u.ok)throw new Error(g.error||"Submission failed.");o&&(o.textContent=g.message||l.settings?.successMessage||"Submitted successfully.",o.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:rgba(34,197,94,.12);color:var(--success,#22c55e);"),E.toast("Test submission stored.",{type:"success"})}catch(u){o&&(o.textContent=u.message,o.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:rgba(239,68,68,.12);color:var(--danger,#ef4444);"),E.toast(u.message,{type:"error"})}return!1}:()=>!1,f=l.fields.some(r=>r.type==="page-break");if(typeof F<"u"){const r=l.settings?.columns||2,u=l.settings?.layout||"stacked";if(f&&F.wizard){const g=se(l.fields).map(h=>({title:h.title,description:h.description,fields:H(h.fields,r)}));F.wizard("#fb-preview-form",{schema:{steps:g},onSubmit:p}),U("#fb-preview-form",l.fields)}else if(F.render){const g=H(l.fields,r),h={};if(l.fields.forEach(y=>{if(!(!y.name||y.type==="page-break"||y.type==="spacer")&&(y.type==="select"||y.type==="multiselect")&&y.required){const S=(y.options||[])[0];S&&(h[y.name]=typeof S=="object"?S.value:S)}}),F.render("#fb-preview-form",g,h,{submitText:l.settings?.submitText||"Submit",layout:u,columns:r,onSubmit:p}),u==="grid"&&l.settings?.submitSpan==="full"){const y=document.querySelector("#fb-preview-form .form-buttons");y&&y.classList.add("col-span-full")}U("#fb-preview-form",l.fields)}window.FormLogicEngine&&l.fields.some(g=>g.logic)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:l.fields},m).init()})}else{const r=document.createElement("p");r.textContent=`${l.fields.filter(u=>u.type!=="page-break").length} field(s): ${l.fields.filter(u=>u.type!=="page-break").map(u=>u.label).join(", ")}`,r.style.cssText="color:var(--muted);font-style:italic;",m.appendChild(r)}e.find("#preview-card").get(0).scrollIntoView({behavior:"smooth",block:"start"})})}};
7
+ maybe:Maybe`,a.value=(e||[]).map(l=>{const r=typeof l=="string"?l:l.value??"",i=typeof l=="string"?l:l.label??r;return r===i?r:`${r}:${i}`}).join(`
8
+ `),a.style.fontFamily="monospace",o.appendChild(n),o.appendChild(a),o}function H(e){return y(),{title:e.find("#field-title").val().trim(),slug:e.find("#field-slug").val().trim(),description:e.find("#field-description").val().trim(),...e.find("#field-bundled").is(":checked")?{bundled:!0}:{},fields:b,settings:{submitText:e.find("#setting-submit-text").val().trim()||"Submit",successMessage:e.find("#setting-success-message").val().trim()||"Thank you.",layout:e.find("#setting-layout").val()||"stacked",columns:parseInt(e.find("#setting-columns").val(),10)||2,submitSpan:e.find("#setting-submit-span").val()||"",honeypot:e.find("#setting-honeypot").prop("checked"),rateLimitPerMinute:parseInt(e.find("#setting-rate-limit").val(),10)||3,successRedirect:e.find("#setting-success-redirect").val().trim()||null,actionSlug:e.find("#action-cms-slug").val()||null},actions:{email:{enabled:e.find("#action-email-enabled").prop("checked"),recipients:e.find("#action-email-recipients").val().trim(),subjectPrefix:e.find("#action-email-subject-prefix").val().trim()},webhook:{enabled:e.find("#action-webhook-enabled").prop("checked"),url:e.find("#action-webhook-url").val().trim(),method:e.find("#action-webhook-method").val()},...T!==null&&{collection:T}}}}function oe(e){const t=[];let o=[],n="Step 1",a="";return e.forEach(l=>{l.type==="page-break"?(t.push({title:n,description:a,fields:o}),o=[],n=l.label||`Step ${t.length+1}`,a=l.description||""):l.type!=="spacer"&&o.push(l)}),(o.length||t.length===0)&&t.push({title:n,description:a,fields:o}),t}function J(e,t){const o={};return e.forEach(n=>{if(n.type==="page-break"||n.type==="spacer")return;const a={...n.formConfig||{}};a.span==="full"&&t&&(a.span=t);const l=n.type==="checkbox"?"boolean":n.type==="date"?"string":n.type;o[n.name]={type:l,label:n.label,required:n.required,options:n.options,formConfig:{...n.placeholder&&{placeholder:n.placeholder},...n.helper&&{hint:n.helper},...a}}}),o}function U(e,t){const o=typeof e=="string"?document.querySelector(e):e;o&&(t||[]).forEach(n=>{if(n.type!=="date"||!n.name)return;const a=o.querySelector(`[name="${n.name}"]`);a&&a.type!=="date"&&(a.type="date")})}export const formEditorView={templateUrl:"/admin/js/templates/form-editor.html",async onMount(e){b=[],x=null,T=null;const t=window.location.hash.match(/\/forms\/edit\/([^/?#]+)/);x=t?t[1]:null;let o=null;if(x)try{o=await S(`/forms/${x}`),b=o.fields||[],T=o.actions?.collection??null}catch{E.toast("Could not load form.",{type:"error"})}if(o?e.find("#editor-title").get(0).textContent=`Edit: ${o.title}`:e.find("#editor-title").get(0).textContent="New Form",x||e.find("#field-title").get(0).addEventListener("input",function(){e.find("#field-slug").val(I(this.value))}),E.tabs(e.find("#editor-tabs").get(0)),o){e.find("#field-title").val(o.title),e.find("#field-slug").val(o.slug),e.find("#field-description").val(o.description||""),e.find("#field-bundled").prop("checked",!!o.bundled);const l=o.settings||{};e.find("#setting-submit-text").val(l.submitText||"Submit"),e.find("#setting-success-message").val(l.successMessage||""),e.find("#setting-layout").val(l.layout||"stacked"),e.find("#setting-columns").val(l.columns||2),e.find("#setting-submit-span").val(l.submitSpan||""),e.find("#columns-group").get(0).style.display=l.layout==="grid"?"":"none",e.find("#setting-honeypot").prop("checked",l.honeypot!==!1),e.find("#setting-rate-limit").val(l.rateLimitPerMinute||3),e.find("#setting-success-redirect").val(l.successRedirect||"");const r=o.actions?.email||{};e.find("#action-email-enabled").prop("checked",r.enabled||!1),e.find("#action-email-recipients").val(r.recipients||""),e.find("#action-email-subject-prefix").val(r.subjectPrefix||"");const i=o.actions?.webhook||{};e.find("#action-webhook-enabled").prop("checked",i.enabled||!1),e.find("#action-webhook-url").val(i.url||""),e.find("#action-webhook-method").val(i.method||"POST")}const n=o?.settings?.actionSlug||"";try{const l=await S("/actions").catch(()=>[]),r=e.find("#action-cms-slug").get(0);if((Array.isArray(l)?l:[]).forEach(i=>{const p=document.createElement("option");p.value=i.slug,p.textContent=i.title||i.slug,i.slug===n&&(p.selected=!0),r.appendChild(p)}),!l.length){const i=document.createElement("option");i.value="",i.textContent="No actions available",i.disabled=!0,r.appendChild(i)}}catch{}e.find("#setting-layout").get(0)?.addEventListener("change",function(){const l=this.value==="grid";e.find("#columns-group").get(0).style.display=l?"":"none",document.querySelectorAll(".fb-grid-row").forEach(r=>{r.style.display=l?"flex":"none"})}),v(e);const a=e.find("#add-element-menu").get(0);e.find("#add-element-btn").get(0).addEventListener("click",l=>{l.stopPropagation(),a.style.display=a.style.display==="none"?"":"none"}),q&&document.removeEventListener("click",q),q=()=>{a&&(a.style.display="none")},document.addEventListener("click",q),e.find("#add-field-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),y();const l=b.length;b.push({name:`field_${l+1}`,type:"string",label:"New Field",required:!1,placeholder:""}),v(e);const r=e.find("#fields-list").get(0)?.lastElementChild;if(r){const i=r.querySelector(".fb-field-body");i&&(i.style.display="")}}),e.find("#add-spacer-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),y(),b.push({type:"spacer"}),v(e)}),e.find("#add-page-break-btn").get(0).addEventListener("click",()=>{a&&(a.style.display="none"),y();const l=b.filter(r=>r.type==="page-break").length+2;b.push({type:"page-break",label:`Step ${l}`,description:""}),v(e)}),e.find("#save-form-btn").get(0).addEventListener("click",async()=>{const l=H(e);if(!l.title){E.toast("Please enter a form title.",{type:"error"});return}try{x?(await S(`/forms/${x}`,{method:"PUT",body:JSON.stringify(l)}),E.toast("Form saved.",{type:"success"})):(x=(await S("/forms",{method:"POST",body:JSON.stringify(l)})).slug,R.navigate(`/forms/edit/${x}`),E.toast("Form created.",{type:"success"}))}catch(r){E.toast(r.message||"Failed to save form.",{type:"error"})}}),e.find("#preview-btn").get(0).addEventListener("click",()=>{const l=H(e),r=e.find("#preview-container").get(0);if(!r)return;const i=e.find("#preview-test-result").get(0),p=e.find("#preview-test-badge").get(0);i&&(i.style.display="none",i.textContent=""),p&&(p.style.display=x?"":"none"),e.find("#preview-card").get(0).style.display="",r.textContent="";const d=document.createElement("div");d.id="fb-preview-form",r.appendChild(d);const m=x?async u=>{i&&(i.style.display="none",i.textContent="");try{const s=await fetch(`/api/forms/submit/${x}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),f=await s.json();if(!s.ok)throw new Error(f.error||"Submission failed.");i&&(i.textContent=f.message||l.settings?.successMessage||"Submitted successfully.",i.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:rgba(34,197,94,.12);color:var(--success,#22c55e);"),E.toast("Test submission stored.",{type:"success"})}catch(s){i&&(i.textContent=s.message,i.style.cssText="display:block;margin-top:.75rem;padding:.6rem .9rem;border-radius:6px;font-size:.9rem;background:rgba(239,68,68,.12);color:var(--danger,#ef4444);"),E.toast(s.message,{type:"error"})}return!1}:()=>!1,c=l.fields.some(u=>u.type==="page-break");if(typeof F<"u"){const u=l.settings?.columns||2,s=l.settings?.layout||"stacked";if(c&&F.wizard){const f=oe(l.fields).map(g=>({title:g.title,description:g.description,fields:J(g.fields,u)}));F.wizard("#fb-preview-form",{schema:{steps:f},onSubmit:m}),U("#fb-preview-form",l.fields)}else if(F.render){const f=J(l.fields,u),g={};if(l.fields.forEach(h=>{if(!(!h.name||h.type==="page-break"||h.type==="spacer")&&(h.type==="select"||h.type==="multiselect")&&h.required){const w=(h.options||[])[0];w&&(g[h.name]=typeof w=="object"?w.value:w)}}),F.render("#fb-preview-form",f,g,{submitText:l.settings?.submitText||"Submit",layout:s,columns:u,onSubmit:m}),s==="grid"&&l.settings?.submitSpan==="full"){const h=document.querySelector("#fb-preview-form .form-buttons");h&&h.classList.add("col-span-full")}U("#fb-preview-form",l.fields)}window.FormLogicEngine&&l.fields.some(f=>f.logic)&&requestAnimationFrame(()=>{new window.FormLogicEngine.FormLogicRuntime({fields:l.fields},d).init()})}else{const u=document.createElement("p");u.textContent=`${l.fields.filter(s=>s.type!=="page-break").length} field(s): ${l.fields.filter(s=>s.type!=="page-break").map(s=>s.label).join(", ")}`,u.style.cssText="color:var(--muted);font-style:italic;",d.appendChild(u)}e.find("#preview-card").get(0).scrollIntoView({behavior:"smooth",block:"start"})})}};
@@ -1 +1 @@
1
- import{apiRequest as p}from"/admin/js/api.js";function u(i){return String(i).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}export const formsView={templateUrl:"/admin/js/templates/forms.html",async onMount(i){await y(i),i.find("#create-form-btn").off("click").on("click",()=>{const c=E.modal({title:"Create Form",size:"sm"}),t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;";const e=document.createElement("div");F.create({title:{type:"string",label:"Form Title",placeholder:"e.g. Contact, Feedback\u2026",required:!0}},{},{showSubmitButton:!1}).renderTo(e),t.appendChild(e);const n=document.createElement("div");n.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem;";const s=document.createElement("button");s.className="btn btn-ghost",s.textContent="Cancel";const o=document.createElement("button");o.className="btn btn-primary",o.textContent="Create",n.appendChild(s),n.appendChild(o),t.appendChild(n),c.element.appendChild(t),c.open();const a=e.querySelector('input[name="title"]');setTimeout(()=>a?.focus(),50);async function m(){const r=a?.value.trim();if(r)try{const l=await p("/forms",{method:"POST",body:JSON.stringify({title:r})});c.close(),R.navigate(`/forms/edit/${l.slug}`)}catch(l){E.toast(l.message||"Failed to create form.",{type:"error"})}}s.addEventListener("click",()=>c.close()),o.addEventListener("click",m),a?.addEventListener("keydown",r=>{r.key==="Enter"&&m()})}),i.find("#test-email-btn").off("click").on("click",async()=>{const t=(window.__CMS_SITE__?.smtp||{}).fromAddress||"",e=E.modal({title:"Send Test Email",size:"sm"}),n=document.createElement("div");n.style.cssText="padding:.25rem 0 .5rem;";const s=document.createElement("div");s.className="mb-3";const o=document.createElement("label");o.className="form-label",o.textContent="Send to";const a=document.createElement("input");a.type="email",a.className="form-input",a.value=t,a.placeholder="test@example.com",s.appendChild(o),s.appendChild(a),n.appendChild(s);const m=document.createElement("p");m.className="text-muted",m.style.cssText="font-size:.8rem;margin-bottom:.75rem;",m.textContent="SMTP settings are configured in Site Settings.",n.appendChild(m);const r=document.createElement("div");r.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem;";const l=document.createElement("button");l.className="btn btn-ghost",l.textContent="Cancel";const d=document.createElement("button");d.className="btn btn-primary",d.textContent="Send",r.appendChild(l),r.appendChild(d),n.appendChild(r),e.element.appendChild(n),e.open(),setTimeout(()=>a?.focus(),50),l.addEventListener("click",()=>e.close()),d.addEventListener("click",async()=>{const f=a.value.trim();if(f){d.disabled=!0;try{await p("/forms/test-email",{method:"POST",body:JSON.stringify({to:f})}),e.close(),E.toast("Test email sent.",{type:"success"})}catch(b){E.toast(b.message||"Failed to send test email.",{type:"error"})}finally{d.disabled=!1}}})}),Domma.icons.scan()}};async function y(i){let c=[];try{c=await p("/forms")}catch{E.toast("Could not load forms.",{type:"error"})}T.create("#forms-table",{data:c,columns:[{key:"title",title:"Title",render:(t,e)=>{const n=document.createElement("a");return n.href=`#/forms/edit/${u(e.slug)}`,n.textContent=t,n.style.fontWeight="600",n.outerHTML}},{key:"slug",title:"Slug",render:t=>{const e=document.createElement("code");return e.textContent=t,e.outerHTML}},{key:"fields",title:"Field Count",render:t=>String(t?.length??0)},{key:"submissionCount",title:"Submission Count",render:t=>String(t??0)},{key:"slug",title:"Actions",render:t=>{const e=document.createElement("div");e.style.cssText="display:flex;gap:.4rem;justify-content:flex-end;";const n=document.createElement("a");n.href=`#/forms/edit/${u(t)}`,n.className="btn btn-sm btn-primary",n.textContent="Edit";const s=document.createElement("a");s.href=`#/forms/${u(t)}/submissions`,s.className="btn btn-sm btn-ghost",s.textContent="Submissions";const o=document.createElement("button");return o.className="btn btn-sm btn-danger js-delete-form",o.dataset.slug=t,o.textContent="Delete",e.appendChild(n),e.appendChild(s),e.appendChild(o),e.outerHTML}}],emptyMessage:'No forms yet. Click "Create Form" to get started.'}),document.querySelectorAll(".js-delete-form").forEach(t=>{t.addEventListener("click",async()=>{const e=t.dataset.slug;if(await E.confirm(`Delete form "${e}" and all its submissions? This cannot be undone.`))try{await p(`/forms/${e}`,{method:"DELETE"}),E.toast("Form deleted.",{type:"success"}),await y(i)}catch{E.toast("Failed to delete form.",{type:"error"})}})}),Domma.icons.scan()}
1
+ import{apiRequest as p}from"/admin/js/api.js";function u(i){return String(i).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}export const formsView={templateUrl:"/admin/js/templates/forms.html",async onMount(i){await g(i),i.find("#create-form-btn").off("click").on("click",()=>{const r=E.modal({title:"Create Form",size:"sm"}),t=document.createElement("div");t.style.cssText="padding:.25rem 0 .5rem;";const n=document.createElement("div");F.create({title:{type:"string",label:"Form Title",placeholder:"e.g. Contact, Feedback\u2026",required:!0}},{},{showSubmitButton:!1}).renderTo(n),t.appendChild(n);const e=document.createElement("div");e.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem;";const s=document.createElement("button");s.className="btn btn-ghost",s.textContent="Cancel";const a=document.createElement("button");a.className="btn btn-primary",a.textContent="Create",e.appendChild(s),e.appendChild(a),t.appendChild(e),r.element.appendChild(t),r.open();const o=n.querySelector('input[name="title"]');setTimeout(()=>o?.focus(),50);async function d(){const l=o?.value.trim();if(l)try{const c=await p("/forms",{method:"POST",body:JSON.stringify({title:l})});r.close(),R.navigate(`/forms/edit/${c.slug}`)}catch(c){E.toast(c.message||"Failed to create form.",{type:"error"})}}s.addEventListener("click",()=>r.close()),a.addEventListener("click",d),o?.addEventListener("keydown",l=>{l.key==="Enter"&&d()})}),i.find("#test-email-btn").off("click").on("click",async()=>{const t=(window.__CMS_SITE__?.smtp||{}).fromAddress||"",n=E.modal({title:"Send Test Email",size:"sm"}),e=document.createElement("div");e.style.cssText="padding:.25rem 0 .5rem;";const s=document.createElement("div");s.className="mb-3";const a=document.createElement("label");a.className="form-label",a.textContent="Send to";const o=document.createElement("input");o.type="email",o.className="form-input",o.value=t,o.placeholder="test@example.com",s.appendChild(a),s.appendChild(o),e.appendChild(s);const d=document.createElement("p");d.className="text-muted",d.style.cssText="font-size:.8rem;margin-bottom:.75rem;",d.textContent="SMTP settings are configured in Site Settings.",e.appendChild(d);const l=document.createElement("div");l.style.cssText="display:flex;justify-content:flex-end;gap:.5rem;margin-top:.75rem;";const c=document.createElement("button");c.className="btn btn-ghost",c.textContent="Cancel";const m=document.createElement("button");m.className="btn btn-primary",m.textContent="Send",l.appendChild(c),l.appendChild(m),e.appendChild(l),n.element.appendChild(e),n.open(),setTimeout(()=>o?.focus(),50),c.addEventListener("click",()=>n.close()),m.addEventListener("click",async()=>{const f=o.value.trim();if(f){m.disabled=!0;try{await p("/forms/test-email",{method:"POST",body:JSON.stringify({to:f})}),n.close(),E.toast("Test email sent.",{type:"success"})}catch(y){E.toast(y.message||"Failed to send test email.",{type:"error"})}finally{m.disabled=!1}}})}),Domma.icons.scan()}};async function g(i){let r=[];try{r=await p("/forms")}catch{E.toast("Could not load forms.",{type:"error"})}T.create("#forms-table",{data:r,columns:[{key:"title",title:"Title",render:(t,n)=>{const e=document.createElement("span");e.style.cssText="display:inline-flex;align-items:center;gap:.4rem;flex-wrap:wrap;";const s=document.createElement("a");if(s.href=`#/forms/edit/${u(n.slug)}`,s.textContent=t,s.style.fontWeight="600",e.appendChild(s),n.plugin){const a=document.createElement("span");a.className="badge badge-outline",a.textContent=n.plugin,a.title=`Managed by the ${n.plugin} plugin`,a.style.cssText="font-size:0.65rem;padding:1px 6px;color:var(--dm-warning,#d97706);border-color:var(--dm-warning,#d97706);flex-shrink:0;",e.appendChild(a)}return e.outerHTML}},{key:"slug",title:"Slug",render:t=>{const n=document.createElement("code");return n.textContent=t,n.outerHTML}},{key:"fields",title:"Field Count",render:t=>String(t?.length??0)},{key:"submissionCount",title:"Submission Count",render:t=>String(t??0)},{key:"slug",title:"Actions",render:(t,n)=>{const e=document.createElement("div");e.style.cssText="display:flex;gap:.4rem;justify-content:flex-end;";const s=document.createElement("a");s.href=`#/forms/edit/${u(t)}`,s.className="btn btn-sm btn-primary",s.textContent="Edit";const a=document.createElement("a");a.href=`#/forms/${u(t)}/submissions`,a.className="btn btn-sm btn-ghost",a.textContent="Submissions";const o=document.createElement("button");return o.className="btn btn-sm btn-danger js-delete-form",o.dataset.slug=t,o.dataset.plugin=n.plugin||"",o.textContent="Delete",e.appendChild(s),e.appendChild(a),e.appendChild(o),e.outerHTML}}],emptyMessage:'No forms yet. Click "Create Form" to get started.'}),document.querySelectorAll(".js-delete-form").forEach(t=>{t.addEventListener("click",async()=>{const n=t.dataset.slug,e=t.dataset.plugin,s=e?`This form is managed by the <strong>${e}</strong> plugin. Deleting it may cause the plugin to malfunction. Continue?`:`Delete form "${n}" and all its submissions? This cannot be undone.`;if(await E.confirm(s))try{await p(`/forms/${n}`,{method:"DELETE"}),E.toast("Form deleted.",{type:"success"}),await g(i)}catch{E.toast("Failed to delete form.",{type:"error"})}})}),Domma.icons.scan()}