From 0b9970955ec0cb7c59a3c7c6f2e7537d4c977ddd Mon Sep 17 00:00:00 2001 From: prismiwi2015 Date: Sun, 23 Aug 2026 19:11:33 +0200 Subject: [PATCH] The canvas previews the drop before it happens MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While a field is dragged over the canvas — or a repeater's zone — a slot the size of the dragged card now follows the pointer: the card leaves the flow, its neighbours slide out of the way with first/last position transforms, and the list shows, in real time, exactly the layout releasing would produce. The drop then reads the gap's own index instead of re-measuring the pointer, because with a card-sized hole open the cards are nowhere near where a measurement of the restored layout would put them. The fallback drag manager learns to emit the same `os.drag.*` lifecycle events the shell's manager broadcasts, so the gap draws from one event stream under either manager instead of silently never appearing without the shell. (Recovered from the long-lived working-tree WIP and rebased over the alltfo_ rename; typecheck and the full vitest suite pass.) Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_0119U4sRRWGcTQdwYreTwpAp --- assets/css/builder.css | 44 ++++- assets/js/builder.js | 231 +++++++++++++++++++++----- assets/js/builder.min.js | 8 +- assets/js/entries.js | 29 ++++ assets/js/entries.min.js | 2 +- src/builder.ts | 342 +++++++++++++++++++++++++++++++-------- src/dnd.ts | 68 ++++++++ 7 files changed, 606 insertions(+), 118 deletions(-) diff --git a/assets/css/builder.css b/assets/css/builder.css index f67bfa3..ddf760c 100644 --- a/assets/css/builder.css +++ b/assets/css/builder.css @@ -729,6 +729,12 @@ body.os-active :is( .atfb-editable, .atfb [contenteditable] ) { body.atf-drag-active, html body.atf-drag-active.atf-drag-active.atf-drag-active.atf-drag-active * { cursor: grabbing !important; + /* Mid-drag nothing is being selected either: without this, every move + paints a selection sweep across the page behind the ghost. The drag + manager clears the anchor the press already planted; this stops a new + one taking. */ + -webkit-user-select: none !important; + user-select: none !important; } /* One survivor outweighs even that: the shell restores the I-beam on text @@ -742,12 +748,40 @@ html body.atf-drag-active [contenteditable="true"] { cursor: grabbing !important; } -/* The insertion line that follows the pointer during a drag. */ +/* The slot that follows the pointer during a drag — sized inline to the card + being dragged, so the gap it opens in the list is the gap the card will + fill. The cards around it are slid aside with animated transforms by the + builder, not by this rule. */ .atfb-marker { - block-size: 3px; - border-radius: 2px; - background: var( --atfb-accent ); - margin-block: -1px; + box-sizing: border-box; + min-block-size: 3px; + border: 1.5px dashed var( --atfb-accent ); + border-radius: var( --atfb-radius ); + background: var( --atfb-accent-soft ); +} + +/* The card a drag lifted out of its list — a canvas card or a repeater + sub-card. The ghost under the pointer is the card now and the open slot + marks its landing — left in the flow it would appear twice. */ +.atfb-lifted { + display: none; +} + +/* The wrapper `buildPayload()` puts around a default ghost. It carries the + scope class the source lived under (`.atfb`, `.atfe`, …) so the clone keeps + the custom properties and type it inherited there — appended bare to + `document.body` its fonts and colours visibly shift mid-drag. The scope + root's own layout must not come with it: the class is doubled to outweigh + the root's own rules whichever manager's ghost class it ends up wearing — + the shell dresses ghosts as `os-drag-ghost`, the fallback as + `atf-drag-ghost`. */ +.atf-ghost-scope.atf-ghost-scope { + display: block; + block-size: auto; + min-block-size: 0; + background: transparent; + padding: 0; + margin: 0; } .atf-is-dragging { diff --git a/assets/js/builder.js b/assets/js/builder.js index 9a7c8a5..fbadce8 100644 --- a/assets/js/builder.js +++ b/assets/js/builder.js @@ -36,6 +36,11 @@ var allTerrainFormsBuilder = function(exports) { this.active = null; this.lastEndMs = Date.now(); }; + const emit = (name, at) => { + document.dispatchEvent( + new CustomEvent(name, { detail: { payload, clientX: at?.clientX, clientY: at?.clientY } }) + ); + }; const session = { payload, isFinished: () => finished, @@ -45,6 +50,9 @@ var allTerrainFormsBuilder = function(exports) { } finished = true; cleanup(); + if (lifted) { + emit("os.drag.end"); + } opts.onCancel?.(reason); } }; @@ -60,6 +68,7 @@ var allTerrainFormsBuilder = function(exports) { ghost.style.width = `${rect.width}px`; document.body.appendChild(ghost); position(event); + emit("os.drag.start", event); }; const position = (event) => { if (ghost) { @@ -83,6 +92,7 @@ var allTerrainFormsBuilder = function(exports) { hovered = next; hovered?.onEnter?.(session); } + emit("os.drag.move", event); }; const onUp = (event) => { if (finished) { @@ -100,8 +110,10 @@ var allTerrainFormsBuilder = function(exports) { if (target && target.accept(payload)) { opts.onCommit?.(target); void target.onDrop(session, { clientX: event.clientX, clientY: event.clientY }); + emit("os.drag.end", event); return; } + emit("os.drag.end", event); opts.onCancel?.(target ? "rejected" : "no-target"); }; const onCancel = () => session.cancel("pointercancel"); @@ -198,11 +210,14 @@ var allTerrainFormsBuilder = function(exports) { const payload = event.detail?.payload; return payload && payloadTypes.includes(payload.type) ? payload.source : null; }; + const preventSelection = (event) => event.preventDefault(); const onStart = (event) => { const source = sourceOf(event); if (source) { source.classList.add("atf-is-dragging"); document.body.classList.add("atf-drag-active"); + window.getSelection()?.removeAllRanges(); + document.addEventListener("selectstart", preventSelection); } }; const onEnd = (event) => { @@ -210,6 +225,7 @@ var allTerrainFormsBuilder = function(exports) { if (source) { source.classList.remove("atf-is-dragging"); document.body.classList.remove("atf-drag-active"); + document.removeEventListener("selectstart", preventSelection); } }; document.addEventListener("os.drag.start", onStart); @@ -217,10 +233,23 @@ var allTerrainFormsBuilder = function(exports) { return () => { document.removeEventListener("os.drag.start", onStart); document.removeEventListener("os.drag.end", onEnd); + document.removeEventListener("selectstart", preventSelection); }; } + const SCOPE_CLASSES = ["atfb", "atfe", "atfs", "atfm"]; function buildPayload(type, source, data, origin, ghost) { const rect = source.getBoundingClientRect(); + if (!ghost) { + const scope = SCOPE_CLASSES.find((cls) => source.closest(`.${cls}`)); + if (scope) { + const clone = source.cloneNode(true); + clone.style.transition = ""; + clone.style.transform = ""; + ghost = document.createElement("div"); + ghost.className = `${scope} atf-ghost-scope`; + ghost.appendChild(clone); + } + } if (ghost) { ghost.style.width = `${Math.round(rect.width)}px`; ghost.style.maxWidth = `${Math.round(rect.width)}px`; @@ -6549,25 +6578,158 @@ var allTerrainFormsBuilder = function(exports) { * canvas, or from a *second* builder window, which is what the shell's * shared drag manager buys and an iframe could not. */ + /** + * The animated insertion gap for one drop container — the canvas list, or + * a repeater's zone. + * + * While a field payload is over the container, a slot the size of the + * dragged card follows the pointer, the dragged card leaves the flow, and + * the other cards slide out of the way with first/last-position + * transforms — so the list previews, in real time, exactly the layout the + * drop will produce. + * + * @param container The drop target element; the gap shows while it has + * the `is-dropping` class. + * @param itemSelector The cards that reflow, `.atfb-card` or `.atfb-subcard`. + * @param findCard Resolves a dragged field id to its card in this + * container's world, or null for one it doesn't hold. + * @param accepts Optional payload gate mirroring the drop target's + * own `accept()`, so a drag the target will refuse + * never opens a gap it cannot honour. + * @return `enter`/`leave`/`drop` to wire into the drop target, and a + * `teardown` for the document-level listeners. + */ + gapAnimator(container, itemSelector, findCard, accepts) { + const marker = el("div", { class: "atfb-marker", attrs: { "aria-hidden": "true" } }); + let shownIndex = null; + let liftedCard = null; + let slotSize = 0; + const restore = () => { + marker.remove(); + liftedCard?.classList.remove("atfb-lifted"); + liftedCard = null; + shownIndex = null; + }; + const moveAnimated = (mutate) => { + const cards = Array.from(container.querySelectorAll(itemSelector)); + const before = new Map( + cards.filter((card) => !card.classList.contains("atfb-lifted")).map((card) => [card, card.getBoundingClientRect().top]) + ); + mutate(); + for (const card of cards) { + card.style.transition = "none"; + card.style.transform = ""; + } + const moved = cards.filter((card) => { + const from = before.get(card); + if (from === void 0 || !card.isConnected || card.classList.contains("atfb-lifted")) { + return false; + } + const delta = from - card.getBoundingClientRect().top; + if (Math.abs(delta) < 0.5) { + return false; + } + card.style.transform = `translateY(${delta}px)`; + return true; + }); + void container.offsetHeight; + for (const card of cards) { + if (!moved.includes(card)) { + card.style.transition = ""; + continue; + } + card.style.transition = "transform 160ms ease"; + card.style.transform = ""; + card.addEventListener( + "transitionend", + () => { + card.style.transition = ""; + }, + { once: true } + ); + } + }; + const onMove = (event) => { + const detail = event.detail; + if (detail?.payload?.type !== FIELD_PAYLOAD_TYPE || !container.classList.contains("is-dropping")) { + return; + } + if (accepts && !accepts(detail.payload.data ?? {})) { + return; + } + const fieldId = detail.payload.data?.fieldId; + const dragged = typeof fieldId === "string" ? findCard(fieldId) : null; + const index = insertionIndex(container, itemSelector, detail.clientY ?? 0, dragged ?? void 0); + if (index === shownIndex && marker.isConnected) { + return; + } + shownIndex = index; + moveAnimated(() => { + if (dragged && dragged !== liftedCard) { + liftedCard?.classList.remove("atfb-lifted"); + dragged.classList.add("atfb-lifted"); + liftedCard = dragged; + } + marker.style.blockSize = `${Math.max(8, Math.round(slotSize))}px`; + const cards = Array.from(container.querySelectorAll(itemSelector)).filter( + (card) => card !== dragged + ); + if (index >= cards.length) { + container.append(marker); + } else { + cards[index].before(marker); + } + }); + }; + const onEnd = () => { + container.classList.remove("is-dropping"); + window.setTimeout(() => moveAnimated(restore), 0); + }; + document.addEventListener("os.drag.move", onMove); + document.addEventListener("os.drag.end", onEnd); + return { + enter: (fieldId) => { + const card = fieldId ? findCard(fieldId) : null; + slotSize = card && !card.classList.contains("atfb-lifted") ? card.getBoundingClientRect().height : slotSize || 44; + }, + leave: () => moveAnimated(restore), + drop: (clientY, source) => { + const index = shownIndex ?? insertionIndex(container, itemSelector, clientY, source ?? void 0); + restore(); + return index; + }, + teardown: () => { + document.removeEventListener("os.drag.move", onMove); + document.removeEventListener("os.drag.end", onEnd); + restore(); + } + }; + } registerCanvasTarget(list) { this.canvasTarget?.(); this.canvasTarget = null; - const marker = el("div", { class: "atfb-marker", attrs: { "aria-hidden": "true" } }); + const gap = this.gapAnimator( + list, + ".atfb-card", + (fieldId) => this.canvas.querySelector(`[data-atfb-card="${CSS.escape(fieldId)}"]`) + ); const teardown = getDragManager().registerDropTarget({ id: `atfb-canvas-${this.form?.id ?? 0}`, element: list, accept: (payload) => payload.type === FIELD_PAYLOAD_TYPE, - onEnter: () => list.classList.add("is-dropping"), + onEnter: (session) => { + list.classList.add("is-dropping"); + gap.enter(session.payload.data.fieldId); + }, onLeave: () => { list.classList.remove("is-dropping"); - marker.remove(); + gap.leave(); }, onDrop: (session, position) => { list.classList.remove("is-dropping"); - marker.remove(); const data = session.payload.data; const source = data.fieldId ? this.canvas.querySelector(`[data-atfb-card="${CSS.escape(data.fieldId)}"]`) : null; - const index = insertionIndex(list, ".atfb-card", position.clientY, source ?? void 0); + const index = gap.drop(position.clientY, source); if (data.isNew && data.fieldType) { this.addField(data.fieldType, index); return; @@ -6582,30 +6744,10 @@ var allTerrainFormsBuilder = function(exports) { } }); const zoneTeardowns = this.wireRepeaterZones(list); - const onMove = (event) => { - const detail = event.detail; - if (detail?.payload?.type !== FIELD_PAYLOAD_TYPE || !list.classList.contains("is-dropping")) { - return; - } - const dragged = detail.payload.data?.fieldId ? this.canvas.querySelector( - `[data-atfb-card="${CSS.escape(detail.payload.data.fieldId)}"]` - ) : null; - const y = detail.clientY ?? 0; - const index = insertionIndex(list, ".atfb-card", y, dragged ?? void 0); - const cards = Array.from(list.querySelectorAll(".atfb-card")).filter( - (card) => card !== dragged - ); - if (index >= cards.length) { - list.append(marker); - } else { - cards[index].before(marker); - } - }; - document.addEventListener("os.drag.move", onMove); this.canvasTarget = () => { teardown(); zoneTeardowns.forEach((zoneTeardown) => zoneTeardown()); - document.removeEventListener("os.drag.move", onMove); + gap.teardown(); }; } /** @@ -6625,30 +6767,41 @@ var allTerrainFormsBuilder = function(exports) { const teardowns = []; list.querySelectorAll("[data-atfb-repeater-zone]").forEach((zone) => { const repeaterId = zone.dataset.atfbRepeaterZone ?? ""; + const acceptsData = (raw) => { + const data = raw; + if (data.fieldId === repeaterId) { + return false; + } + const type = data.isNew ? data.fieldType : this.locateField(data.fieldId ?? "")?.field.type ?? data.field?.type; + return !!type && this.allowedInRepeater(type); + }; + const gap = this.gapAnimator( + zone, + ".atfb-subcard", + (fieldId) => list.querySelector(`[data-atfb-subfield="${CSS.escape(fieldId)}"]`), + acceptsData + ); + teardowns.push(() => gap.teardown()); teardowns.push( getDragManager().registerDropTarget({ id: `atfb-repzone-${this.form?.id ?? 0}-${repeaterId}`, element: zone, - accept: (payload) => { - if (payload.type !== FIELD_PAYLOAD_TYPE) { - return false; - } - const data = payload.data; - if (data.fieldId === repeaterId) { - return false; - } - const type = data.isNew ? data.fieldType : this.locateField(data.fieldId ?? "")?.field.type ?? data.field?.type; - return !!type && this.allowedInRepeater(type); + accept: (payload) => payload.type === FIELD_PAYLOAD_TYPE && acceptsData(payload.data), + onEnter: (session) => { + zone.classList.add("is-dropping"); + gap.enter(session.payload.data.fieldId); + }, + onLeave: () => { + zone.classList.remove("is-dropping"); + gap.leave(); }, - onEnter: () => zone.classList.add("is-dropping"), - onLeave: () => zone.classList.remove("is-dropping"), onDrop: (session, position) => { zone.classList.remove("is-dropping"); const data = session.payload.data; const source = data.fieldId ? list.querySelector( `[data-atfb-subfield="${CSS.escape(data.fieldId)}"]` ) : null; - const index = insertionIndex(zone, ".atfb-subcard", position.clientY, source ?? void 0); + const index = gap.drop(position.clientY, source); if (data.isNew && data.fieldType) { this.addFieldToRepeater(data.fieldType, repeaterId, index); return; diff --git a/assets/js/builder.min.js b/assets/js/builder.min.js index ba4d50c..dc9f14d 100644 --- a/assets/js/builder.min.js +++ b/assets/js/builder.min.js @@ -1,5 +1,5 @@ -var allTerrainFormsBuilder=function(ee){"use strict";class Kt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(e){if(this.active||e.origin.button!==0)return null;const{payload:t,origin:s}=e,a=s.clientX,i=s.clientY;let o=!1,l=!1,c=null,d=null,h=0,w=0;const y=()=>{document.removeEventListener("pointermove",f),document.removeEventListener("pointerup",C),document.removeEventListener("pointercancel",N),document.removeEventListener("keydown",L),window.removeEventListener("blur",N),c?.remove(),c=null,t.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),d?.onLeave?.(u),d=null,this.active=null,this.lastEndMs=Date.now()},u={payload:t,isFinished:()=>l,cancel:(T="caller")=>{l||(l=!0,y(),e.onCancel?.(T))}},x=T=>{o=!0,t.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const M=t.source.getBoundingClientRect();h=t.ghost?.offsetX??a-M.left,w=t.ghost?.offsetY??i-M.top,c=t.ghost?.element??t.source.cloneNode(!0),c.classList.add("atf-drag-ghost"),c.style.width=`${M.width}px`,document.body.appendChild(c),v(T)},v=T=>{c&&(c.style.transform=`translate3d(${T.clientX-h}px, ${T.clientY-w}px, 0)`)},f=T=>{if(l)return;if(!o){if(Math.hypot(T.clientX-a,T.clientY-i)<4)return;x(T)}v(T);const M=this.hitTest(T.clientX,T.clientY);M!==d&&(d?.onLeave?.(u),d=M,d?.onEnter?.(u))},C=T=>{if(l)return;if(!o){l=!0,y(),e.onClickOnly?.();return}const M=d;if(l=!0,y(),M&&M.accept(t)){e.onCommit?.(M),M.onDrop(u,{clientX:T.clientX,clientY:T.clientY});return}e.onCancel?.(M?"rejected":"no-target")},N=()=>u.cancel("pointercancel"),L=T=>{T.key==="Escape"&&u.cancel("escape")};return document.addEventListener("pointermove",f),document.addEventListener("pointerup",C),document.addEventListener("pointercancel",N),document.addEventListener("keydown",L),window.addEventListener("blur",N),this.active=u,u}registerDropTarget(e){return this.targets=this.targets.filter(t=>t.id!==e.id),this.targets.push(e),()=>{this.targets=this.targets.filter(t=>t.id!==e.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(e=500){return Date.now()-this.lastEndMso.right||to.bottom)continue;const l=Xt(i.element);if(l>a){s=i,a=l;continue}l===a&&s&&Vt(i.element,s.element)&&(s=i)}return s}}function Xt(n){let e=0,t=n;for(;t;)e++,t=t.parentElement;return e}function Vt(n,e){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function Se(){return window.wp?.os??null}let Le=null;function K(){const n=Se();return n?.dragManager?n.dragManager:(Le||(Le=new Kt),Le)}function Jt(n){const e=a=>{const i=a.detail?.payload;return i&&n.includes(i.type)?i.source:null},t=a=>{const i=e(a);i&&(i.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"))},s=a=>{const i=e(a);i&&(i.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"))};return document.addEventListener("os.drag.start",t),document.addEventListener("os.drag.end",s),()=>{document.removeEventListener("os.drag.start",t),document.removeEventListener("os.drag.end",s)}}function Ee(n,e,t,s,a){const i=e.getBoundingClientRect();return a&&(a.style.width=`${Math.round(i.width)}px`,a.style.maxWidth=`${Math.round(i.width)}px`,a.style.boxSizing="border-box"),{type:n,source:e,data:t,ghost:{element:a,offsetX:s.clientX-i.left,offsetY:s.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}function Ce(n,e,t,s){const a=Array.from(n.querySelectorAll(e)).filter(i=>i!==s&&!i.classList.contains("atf-drag-ghost"));for(let i=0;ia.fetch(l,c,{source:"allterrain-forms"}):(l,c)=>fetch(l,c))(t,{credentials:"same-origin",...e,headers:s});if(!o.ok){let l=`Request failed with status ${o.status}.`,c="";try{const d=await o.json();l=d.message??l,c=d.code??""}catch{}throw new ce(l,o.status,c)}if(o.status!==204)return await o.json()}const U=n=>$e(n);async function Qt(n){if(!W?.wpRestUrl)throw new ce("AllTerrain Forms is not configured on this page.",0);const e=W.nonce?{"X-WP-Nonce":W.nonce}:{},t=Se(),s=Qe(W.wpRestUrl,n),a=t?.fetch?await t.fetch(s,{credentials:"same-origin",headers:e},{source:"allterrain-forms"}):await fetch(s,{credentials:"same-origin",headers:e});if(!a.ok)throw new ce(`Request failed with status ${a.status}.`,a.status);return await a.json()}function es(n){if(!n||!n.includes("&"))return n;const e=document.createElement("textarea");return e.innerHTML=n,e.value}const X=(n,e)=>$e(n,{method:"POST",body:JSON.stringify(e)}),de=n=>$e(n,{method:"DELETE"});function et(n){const e=new URLSearchParams;for(const[s,a]of Object.entries(n))a===void 0||a===""||a===!1||e.set(s,String(a));const t=e.toString();return t?`?${t}`:""}function he(n){const e=n?.schema?.settings;return e&&(!e.themeOverrides||Array.isArray(e.themeOverrides))&&(e.themeOverrides={...e.themeOverrides}),n}const I={config:()=>U("/config"),mailpoet:()=>U("/mailpoet"),listForms:()=>U("/forms"),listArchivedForms:()=>U("/forms?archived=1"),archiveForm:n=>X(`/forms/${n}/archive`,{}),unarchiveForm:n=>X(`/forms/${n}/unarchive`,{}),getForm:n=>U(`/forms/${n}`).then(he),createForm:n=>X("/forms",n).then(he),updateForm:(n,e)=>X(`/forms/${n}`,e).then(he),duplicateForm:n=>X(`/forms/${n}/duplicate`,{}).then(he),deleteForm:n=>de(`/forms/${n}`),preview:(n,e)=>X(`/forms/${n}/preview`,e),pages:()=>Qt("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(n=>n.map(e=>({id:e.id,title:es(e.title?.rendered??"")||`#${e.id}`}))),mergeTags:n=>U(`/forms/${n}/merge-tags`).then(e=>e.groups),analytics:(n,e="")=>U(`/forms/${n}/analytics${e?`?dimension=${encodeURIComponent(e)}`:""}`),demoStatus:()=>U("/demo"),demoSeed:n=>X("/demo",n?{count:n}:{}),demoRemove:()=>de("/demo"),listEntries:n=>U(`/entries${et(n)}`),getEntry:n=>U(`/entries/${n}`),updateEntry:(n,e)=>X(`/entries/${n}`,e),deleteEntry:n=>de(`/entries/${n}`),exportEntries:n=>U(`/entries/export${et(n)}`),listThemes:()=>U("/themes"),saveTheme:n=>X("/themes",n),deleteTheme:n=>de(`/themes/${n}`)};function r(n,e={}){const t=document.createElement(n);e.class&&(t.className=e.class),e.text!==void 0&&(t.textContent=e.text),e.html!==void 0&&(t.innerHTML=e.html),e.title&&(t.title=e.title),e.type&&"type"in t&&(t.type=e.type),e.value!==void 0&&"value"in t&&(t.value=e.value),e.placeholder!==void 0&&"placeholder"in t&&(t.placeholder=e.placeholder),e.href&&"href"in t&&(t.href=e.href);for(const[s,a]of Object.entries(e.attrs??{}))a===void 0||a===!1||t.setAttribute(s,a===!0?"":String(a));Object.assign(t.style,e.style??{});for(const[s,a]of Object.entries(e.on??{}))t.addEventListener(s,a);for(const s of e.children??[])s==null||s===!1||t.append(s);return t}function P(n){n.replaceChildren()}function z(n){return r("span",{class:`dashicons ${n.startsWith("dashicons-")?n:`dashicons-${n}`}`,attrs:{"aria-hidden":"true"}})}function g(n,e,t){const s=e.matches("input, select, textarea, button")?e:e.querySelector("input, select, textarea");if(s){const a=s.id||`atf-c-${Math.random().toString(36).slice(2,9)}`;return s.id=a,r("div",{class:"atfb-row",children:[r("label",{class:"atfb-row__label",text:n,attrs:{for:a}}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}return r("div",{class:"atfb-row",children:[r("span",{class:"atfb-row__label",text:n}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}function A(n,e,t=""){return r("input",{class:"atfb-input",type:"text",value:n,placeholder:t,on:{input:s=>e(s.target.value)}})}function G(n,e){if(Y("os-number-field")){const t=document.createElement("os-number-field");return t.setAttribute("value",n),t.classList.add("atfb-field"),t.addEventListener("os-input-change",s=>{e(String(s.detail?.value??""))}),t}return r("input",{class:"atfb-input",type:"number",value:n,on:{input:t=>e(t.target.value)}})}function ue(n,e,t=4){const s=r("textarea",{class:"atfb-input atfb-input--area",attrs:{rows:t},on:{input:a=>e(a.target.value)}});return s.value=n,s}function D(n,e,t){if(Y("os-select")&&Y("os-option")){const s=document.createElement("os-select");s.setAttribute("value",n),s.classList.add("atfb-field");for(const a of e){const i=document.createElement("os-option");i.setAttribute("value",a.value),i.textContent=a.label,s.append(i)}return s.addEventListener("os-pick",a=>{t(String(a.detail?.value??""))}),s}return r("select",{class:"atfb-input atfb-select",on:{change:s=>t(s.target.value)},children:e.map(s=>r("option",{value:s.value,text:s.label,attrs:{selected:s.value===n}}))})}function O(n,e,t){if(Y("os-checkbox-label")){const a=document.createElement("os-checkbox-label");return a.setAttribute("label",n),a.classList.add("atfb-check"),e&&a.setAttribute("checked",""),a.addEventListener("os-checkbox-change",i=>{t(!!i.detail?.checked)}),a}const s=r("input",{type:"checkbox",on:{change:a=>t(a.target.checked)}});return s.checked=e,r("label",{class:"atfb-check",children:[s,r("span",{text:n})]})}function E(n,e,t="secondary",s){const a=[s?z(s):null,r("span",{text:n})];if(Y("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",t),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${t}`),i.addEventListener("click",e);for(const o of a)o&&i.append(o);return i}return r("button",{class:`atfb-button atfb-button--${t}`,type:"button",on:{click:e},children:a})}function Y(n){return typeof customElements<"u"&&!!customElements.get(n)}const ts=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let pe=null;function ss(){if(pe)return pe;const n=window.wp?.os;return pe=n?.loadComponents?n.loadComponents(ts).catch(()=>{}):Promise.resolve(),pe}async function fe(n,e=""){const t=window.wp?.os;return t?.confirm?t.confirm({title:e,message:n,danger:!0}):window.confirm(n)}function R(n,e="",t="info"){const s=window.wp?.os;if(s?.notify){s.notify({title:n,body:e,type:t});return}console.info(`[AllTerrain Forms] ${n}${e?`: ${e}`:""}`)}function ns(n){let e=0,t;return(...s)=>{t=s,!e&&(e=window.requestAnimationFrame(()=>{e=0,n(...t)}))}}function Ae(n,e){let t=0;return(...s)=>{window.clearTimeout(t),t=window.setTimeout(()=>n(...s),e)}}function as(n){try{return window.localStorage.getItem(n)??""}catch{return""}}function is(n,e){try{window.localStorage.setItem(n,e)}catch{}}function Te(n){const e=n.closest(".os-window__body");e&&(e.addEventListener("scroll",()=>{e.scrollTop&&(e.scrollTop=0),e.scrollLeft&&(e.scrollLeft=0)},{passive:!0}),e.scrollTop=0,e.scrollLeft=0)}function tt(){const n=[window];try{window.parent&&window.parent!==window&&n.push(window.parent)}catch{}return n}function rs(n){const e=n.wp?.os?.windowManager?.getAll?.()??[];for(const t of e){const s=t.iframe??t.element?.querySelector?.("iframe");if(s&&s.contentWindow===window)return t}return null}const os=4e3,ls=100;function cs(n,e){const t=Date.now()+os,s=()=>{const a=rs(n);if(a&&a.id!==e){typeof a.close=="function"?a.close():n.wp?.os?.windowManager?.remove?.(a.id);return}!a&&Date.now()0?{form:t}:void 0;t>0&&ps(t);for(const a of tt())if(a.wp?.os?.openWindow?.(e,{source:"handoff",params:s})){window.setTimeout(()=>cs(a,e),0);return}}function hs(){document.addEventListener("click",n=>{const e=n.target?.closest?.("[data-atf-open-window]");if(!e)return;n.preventDefault();const t=e.getAttribute("data-atf-open-window")??"";for(const s of tt())if(s.wp?.os?.openWindow?.(t,{source:"handoff"}))return})}const us="allterrain-forms/requested-form";function ps(n){try{window.sessionStorage.setItem(us,String(n))}catch{}}function st(n){return`allterrain-forms/requested-form-${n}`}function fs(n){try{const e=window.sessionStorage.getItem(st(n));return window.sessionStorage.removeItem(st(n)),Number(e)||0}catch{return 0}}const Me={is:"is",is_not:"is not",contains:"contains",not_contains:"does not contain",starts_with:"starts with",ends_with:"ends with",greater:"is more than",less:"is less than",greater_equal:"is at least",less_equal:"is at most",empty:"is empty",not_empty:"has any answer"},Fe=["empty","not_empty"];function nt(n,e){const t=n.find(s=>s.id===e);return t?t.label||"an untitled question":null}function at(n,e,t){return n.find(i=>i.id===e)?.choices?.find(i=>i.value===t)?.label||t}function ms(n,e){const t=Me[n.operator]??String(n.operator);if(Fe.includes(n.operator))return t;const s=at(e,n.field,n.value);return`${n.operator==="is"?"":`${t} `}${s!==""?s:"(nothing)"}`}function it(n,e,t=0){const s=nt(e,n.field),a=Me[n.operator]??String(n.operator);if(s===null)return[{kind:"field",text:"a question that no longer exists",fieldId:n.field,missing:!0}];const i=[{kind:"field",text:s,fieldId:n.field,missing:!1},{kind:"operator",text:a,operator:n.operator,ruleIndex:t}];if(Fe.includes(n.operator))return i;const o=at(e,n.field,n.value);return i.push({kind:"value",text:o!==""?o:"(nothing)",raw:n.value,sourceId:n.field,ruleIndex:t}),i}function bs(n,e){const t=n.logic;if(!t?.enabled||!t.rules.length)return[];const s=[{kind:"verb",text:t.action==="hide"?"Hidden when":"Shown when"}];return t.rules.forEach((a,i)=>{i>0&&s.push({kind:"join",text:t.match==="all"?"and":"or"}),s.push(...it(a,e,i))}),s}function rt(n){return n.map(e=>e.text).join(" ")}function gs(n,e){return rt(it(n,e))}function me(n){const e=[];for(const t of n){const s=t.logic;if(s?.enabled)for(const a of s.rules)!a.field||a.field===t.id||e.push({from:a.field,to:t.id,label:gs(a,n),short:ms(a,n),action:s.action,broken:nt(n,a.field)===null})}return e}function vs(n){const e=new Map,t=new Set;for(const s of me(n)){const a=`${s.from}->${s.to}`;s.broken||t.has(a)||(t.add(a),e.set(s.from,(e.get(s.from)??0)+1))}return e}const ot=10,lt=22,ne="http://www.w3.org/2000/svg";class ys{constructor(e){this.edges=[],this.teardowns=[],this.frame=0,this.host=e,this.svg=document.createElementNS(ne,"svg"),this.svg.setAttribute("class","atfb-logicmap"),this.svg.setAttribute("aria-hidden","true"),this.svg.setAttribute("focusable","false"),e.append(this.svg);const t=()=>this.schedule();window.addEventListener("resize",t),this.teardowns.push(()=>window.removeEventListener("resize",t));const s=e.closest(".atfb__canvas")??e;if(s.addEventListener("scroll",t,{passive:!0}),this.teardowns.push(()=>s.removeEventListener("scroll",t)),typeof ResizeObserver<"u"){const a=new ResizeObserver(t);a.observe(e),this.teardowns.push(()=>a.disconnect())}}setEdges(e){this.edges=e,this.schedule()}highlight(e){this.svg.classList.toggle("is-focused",!!e),this.svg.querySelectorAll("[data-from]").forEach(t=>{const s=e&&(t.dataset.from===e||t.dataset.to===e);t.classList.toggle("is-lit",!!s)})}destroy(){this.teardowns.forEach(e=>e()),this.teardowns=[],this.svg.remove(),this.frame&&cancelAnimationFrame(this.frame)}schedule(){this.frame||(this.frame=requestAnimationFrame(()=>{this.frame=0,this.draw()}))}draw(){this.svg.replaceChildren();const e=this.host.getBoundingClientRect();this.svg.setAttribute("viewBox",`0 0 ${e.width} ${e.height}`),this.svg.setAttribute("width",String(e.width)),this.svg.setAttribute("height",String(e.height));const t=new Map;for(const s of this.edges){const a=this.cardRect(s.from),i=this.cardRect(s.to);if(!a||!i)continue;const o=t.get(s.from)??0;t.set(s.from,o+1),this.drawEdge(s,a,i,e,o)}}cardRect(e){const t=this.host.querySelector(`[data-atfb-card="${CSS.escape(e)}"]`);return t?t.getBoundingClientRect():null}drawEdge(e,t,s,a,i){const o=t.right-a.left,l=t.top+t.height/2-a.top,c=s.right-a.left,d=s.top+s.height/2-a.top,h=Math.max(0,a.width-ot-Math.max(o,c)),w=22+i*11+Math.min(22,Math.abs(d-l)/8),y=Math.max(12,Math.min(w,h*.4)),u=document.createElementNS(ne,"path");u.setAttribute("d",`M ${o} ${l} C ${o+y} ${l}, ${c+y} ${d}, ${c} ${d}`),u.setAttribute("class",`atfb-logicmap__path is-${e.action}${e.broken?" is-broken":""}`),u.dataset.from=e.from,u.dataset.to=e.to;const x=document.createElementNS(ne,"title");x.textContent=e.label,u.append(x);const v=document.createElementNS(ne,"circle");v.setAttribute("cx",String(c)),v.setAttribute("cy",String(d)),v.setAttribute("r","3.5"),v.setAttribute("class",`atfb-logicmap__dot is-${e.action}${e.broken?" is-broken":""}`),v.dataset.from=e.from,v.dataset.to=e.to,this.svg.append(u,v);const f=document.createElementNS(ne,"text");f.setAttribute("x",String(a.width-ot)),f.setAttribute("y",String(d+3)),f.setAttribute("text-anchor","end"),f.setAttribute("class","atfb-logicmap__label"),f.dataset.from=e.from,f.dataset.to=e.to,f.textContent=e.short.length>lt?`${e.short.slice(0,lt-1)}…`:e.short;const C=document.createElementNS(ne,"title");C.textContent=e.label,f.append(C),this.svg.append(f)}}const ws={text:"text",email:"text",url:"text",tel:"text",number:"text",password:"text",date:"text",time:"text",datetime:"text",date_range:"composite",textarea:"textarea",select:"select",country:"select",multiselect:"options",radio:"options",checkboxes:"options",image_choice:"options",quiz:"options",switch:"toggle",consent:"toggle",file:"file",range:"range",rating:"summary",scale:"summary",likert:"summary",signature:"summary",repeater:"repeater",color:"text",name:"composite",address:"composite",total:"text",hidden:"static",heading:"static",html:"static",divider:"static",spacer:"static",page_break:"static"};function _s(n){return ws[n]??"text"}function ct(n,e){const t=/^choice:(\d+):(label|value)$/.exec(e);return String(t?n.choices?.[Number(t[1])]?.[t[2]]??"":n[e]??"")}function V(n){const{value:e,onInput:t,onCommit:s}=n,a=r("span",{class:`${n.class} atfb-editable`,text:e,attrs:{contenteditable:"plaintext-only",role:"textbox",spellcheck:"false","data-placeholder":n.placeholder}});return n.bind&&(a.dataset.atfbBind=n.bind),a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("input",()=>t(a.textContent??"")),a.addEventListener("keydown",i=>{i.key==="Enter"&&(i.preventDefault(),a.blur()),i.key==="Escape"&&(a.textContent=e,a.blur()),i.stopPropagation()}),a.addEventListener("blur",()=>s?.()),a}function xs(n){const e=r("input",{class:"atf-choice__input",type:n==="checkboxes"||n==="multiselect"?"checkbox":"radio"});return e.disabled=!0,e}function dt(n,e,t){const s=_s(n.type),a=V({value:n.label,placeholder:"Write the question…",class:"atf-label",bind:"label",onInput:o=>t.edit(l=>{l.label=o}),onCommit:()=>t.restructure(()=>{})}),i=[s==="static"||s==="toggle"?null:a,Ss(n,e,s,t),ks(n,e,t)];return r("div",{class:"atfb-preview atf-form",children:[r("div",{class:`atf-field atf-field--${n.type}`,children:i})]})}function ks(n,e,t){if(!e?.supports.includes("hint"))return null;const s=V({value:n.hint??"",placeholder:"Add a hint…",class:"atf-hint",bind:"hint",onInput:a=>t.edit(i=>{i.hint=a})});return s.setAttribute("aria-label","Hint"),r("p",{class:"atfb-preview__hint",children:[s]})}function Ss(n,e,t,s){switch(t){case"text":return Ie(n,"atf-input",s);case"textarea":return Ie(n,"atf-input atf-textarea",s,!0);case"select":return r("div",{class:"atfb-preview__select",children:[Ie(n,"atf-input atf-select",s)]});case"options":return $s(n,s);case"toggle":return r("div",{class:n.type==="switch"?"atf-toggle atf-toggle--switch":"atf-toggle",children:[(()=>{const a=r("input",{class:"atf-toggle__input",type:"checkbox"});return a.disabled=!0,a})(),V({value:n.label||"",placeholder:n.type==="consent"?"What are they agreeing to?…":"What does this turn on?…",class:"atf-toggle__label",bind:"label",onInput:a=>s.edit(i=>{i.label=a}),onCommit:()=>s.restructure(()=>{})})]});case"file":return r("div",{class:"atf-file",children:[r("input",{class:"atf-file__input",type:"file"})]});case"range":return r("input",{class:"atf-range__input",type:"range"});case"composite":return r("div",{class:"atf-composite__parts",children:[r("span",{class:"atf-input atfb-preview__ghost",text:""}),r("span",{class:"atf-input atfb-preview__ghost",text:""})]});case"static":return As(n,e,s);case"repeater":return Ls(n,s);default:return r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — set this up in the panel on the right.`})]})}}function Ls(n,e){const t=n.fields??[],s=r("div",{class:"atfb-repeater__zone",attrs:{"data-atfb-repeater-zone":n.id}});return t.forEach(a=>s.append(Es(n,a,e))),t.length||s.append(r("p",{class:"atfb-repeater__empty",text:"Drag fields from the palette in here — the visitor gets a fresh copy of each with every row they add."})),r("div",{class:"atfb-repeater",attrs:{"data-atfb-repeater":n.id},children:[r("div",{class:"atf-repeater__row atfb-repeater__frame",children:[r("div",{class:"atf-repeater__row-head",children:[r("span",{class:"atf-repeater__title atfb-repeater__title",children:[V({value:String(n.itemLabel??""),placeholder:"Row",class:"atfb-repeater__item-label",bind:"itemLabel",onInput:a=>e.edit(i=>{i.itemLabel=a})}),r("span",{class:"atfb-repeater__ordinal",text:"1",attrs:{"aria-hidden":"true"}})]})]}),s]}),Cs(n,e)]})}function Es(n,e,t){const s=e.id,a=l=>c=>{const d=(c.fields??[]).find(h=>h.id===s);d&&l(d)},i={edit:l=>t.edit(a(l)),restructure:l=>t.restructure(a(l)),types:t.types,selectedId:t.selectedId},o=t.types?.(e.type);return r("div",{class:`atfb-subcard${t.selectedId===s?" is-selected":""}`,attrs:{"data-atfb-subfield":s,"data-atfb-parent":n.id,tabindex:"0",role:"button","aria-label":`${e.label||o?.label||e.type}, inside ${n.label||"the repeater"}`},children:[r("div",{class:"atfb-subcard__head",children:[r("span",{class:"atfb-subcard__type",text:o?.label??e.type}),e.required?r("span",{class:"atfb-subcard__required",text:"Required"}):null,r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this field from the repeater",attrs:{"aria-label":`Remove ${e.label||o?.label||"this field"}`},on:{pointerdown:l=>l.stopPropagation(),click:l=>{l.stopPropagation(),t.restructure(c=>{const d=c.fields??[],h=d.findIndex(w=>w.id===s);h>=0&&d.splice(h,1)})}},children:[r("span",{text:"×"})]})]}),dt(e,o,i)]})}function Ie(n,e,t,s=!1){const a=V({value:n.placeholder??"",placeholder:n.type==="select"||n.type==="country"?"Choose…":"Placeholder…",class:`${e} atfb-preview__box${s?" atfb-preview__box--tall":""}`,bind:"placeholder",onInput:i=>t.edit(o=>{o.placeholder=i})});return a.setAttribute("aria-label","Placeholder"),a}function De(n,e,t,s,a,i){return r("span",{class:`atf-button ${t} atfb-preview__button`,children:[V({value:n,placeholder:e,class:"atfb-preview__button-text",bind:s,onInput:o=>a.edit(l=>i(l,o))})]})}function Cs(n,e){return De(String(n.addLabel??""),"Add another","atf-button--ghost atfb-repeater__add","addLabel",e,(t,s)=>{t.addLabel=s})}function $s(n,e){const t=r("div",{class:"atf-choices__list"});return(n.choices??[]).forEach((s,a)=>{t.append(r("div",{class:"atf-choice atfb-preview__option",children:[xs(n.type),V({value:s.label,placeholder:"Option…",class:"atf-choice__label",bind:`choice:${a}:label`,onInput:i=>{e.edit(o=>{const l=o.choices?.[a];if(!l)return;const c=!l.value||l.value===l.label;l.label=i,c&&(l.value=i)})}}),r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this option",attrs:{"aria-label":`Remove ${s.label||"this option"}`},on:{pointerdown:i=>i.stopPropagation(),click:i=>{i.stopPropagation(),e.restructure(o=>{o.choices.splice(a,1)})}},children:[r("span",{text:"×"})]})]}))}),t.append(r("button",{class:"atfb-preview__add",type:"button",on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.restructure(a=>{const i=a.choices.length+1;a.choices.push({label:`Option ${i}`,value:`Option ${i}`})})}},children:[r("span",{text:"+ Add option"})]})),r("fieldset",{class:"atf-choices",children:[t]})}function As(n,e,t){return n.type==="heading"?V({value:n.label,placeholder:"Section heading…",class:"atf-heading",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})}):n.type==="divider"?r("hr",{class:"atf-divider"}):n.type==="page_break"?r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-progress-name",children:[V({value:n.label,placeholder:"Name this step…",class:"atf-progress__label",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})})]}),r("p",{class:"atfb-preview__summary",text:"Everything after this is a new page."}),r("div",{class:"atf-nav atfb-preview__nav",children:[De(String(n.prevLabel??""),"Back","atf-button--secondary","prevLabel",t,(s,a)=>{s.prevLabel=a}),De(String(n.nextLabel??""),"Next","","nextLabel",t,(s,a)=>{s.nextLabel=a})]})]}):r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — nothing is shown to the visitor here.`})}const qe=new Map;function Oe(n){let e=qe.get(n);return e||(e=I.mergeTags(n).catch(()=>[]),qe.set(n,e)),e}function Ts(n){qe.delete(n)}function Ms(n){const e=new Map;for(const t of n)for(const s of t.items)e.set(s.tag,s);return e}function Fs(n,e){const t=Ms(e);return n.replace(/\{[a-z_]+(?::[^}]*)?\}/gi,s=>{const a=t.get(s.toLowerCase());return a?a.sample:s})}function Is(n){return/\{[a-z_]+(?::[^}]*)?\}/i.test(n)}let te=null;function ie(){te?.remove(),te=null}typeof document<"u"&&(document.addEventListener("pointerdown",n=>{const e=n.target;e?.closest(".atfb-tagpick__open")||te&&!te.contains(e)&&ie()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&te&&(ie(),n.stopPropagation())}));function ht(n,e){const t=n.selectionStart??n.value.length,s=n.selectionEnd??n.value.length;n.value=n.value.slice(0,t)+e+n.value.slice(s);const a=t+e.length;n.setSelectionRange(a,a),n.focus(),n.dispatchEvent(new Event("input",{bubbles:!0}))}function Ds(n){let e=n.parentElement;for(;e&&e!==document.body;){const t=getComputedStyle(e).overflowY;if(t==="auto"||t==="scroll"||t==="hidden")return e.getBoundingClientRect().bottom;e=e.parentElement}return window.innerHeight}function qs(n,e){const t=r("input",{class:"atfb-input atfb-tagpick__search",type:"search",placeholder:"Search values…",attrs:{"aria-label":"Search values"}}),s=r("div",{class:"atfb-tagpick__list"}),a=i=>{s.replaceChildren();const o=i.trim().toLowerCase();let l=0;for(const c of n){const d=c.items.filter(h=>!o||h.label.toLowerCase().includes(o)||h.tag.toLowerCase().includes(o));if(!d.length){c.empty&&!o&&!c.items.length&&s.append(r("p",{class:"atfb-tagpick__group",text:c.label}),r("p",{class:"atfb-tagpick__empty",text:c.empty}));continue}s.append(r("p",{class:"atfb-tagpick__group",text:c.label}));for(const h of d)l+=1,s.append(r("button",{class:"atfb-tagpick__item",type:"button",on:{click:()=>{e(h.tag),ie()}},children:[r("span",{class:"atfb-tagpick__item-main",children:[r("span",{class:"atfb-tagpick__label",text:h.label}),r("code",{class:"atfb-tagpick__tag",text:h.tag})]}),h.hint||h.sample?r("span",{class:"atfb-tagpick__meta",text:h.sample?`e.g. ${h.sample}`:h.hint}):null]}))}!l&&o&&s.append(r("p",{class:"atfb-tagpick__empty",text:`Nothing matches “${i}”.`}))};return a(""),t.addEventListener("input",()=>a(t.value)),r("div",{class:"atfb-tagpick",attrs:{role:"dialog","aria-label":"Insert a value"},children:[r("p",{class:"atfb-tagpick__intro",text:"Pick something to drop in. It is filled in when the form is submitted."}),t,s]})}function ut(n,e){const t=r("button",{class:"atfb-button atfb-button--ghost atfb-tagpick__open",type:"button",title:"Insert a value from the submission",children:[z("shortcode"),r("span",{text:"Insert a value"})]}),s=r("div",{class:"atfb-taggable",children:[n,r("div",{class:"atfb-taggable__tools",children:[t]})]}),a=e.preview===!1?null:r("p",{class:"atfb-taggable__preview"});a&&s.append(a);const i=()=>{if(a){if(!Is(n.value)){a.textContent="",a.hidden=!0;return}Oe(e.formId).then(o=>{a.hidden=!1,a.replaceChildren(r("span",{class:"atfb-taggable__preview-label",text:"Reads as"}),r("span",{text:Fs(n.value,o)}))})}};return n.addEventListener("input",i),i(),t.addEventListener("click",o=>{if(o.stopPropagation(),te&&s.contains(te)){ie();return}ie(),Oe(e.formId).then(l=>{const c=qs(l,d=>{ht(n,d),i()});s.append(c),te=c,(window.innerHeight-c.getBoundingClientRect().topDs(s))&&c.classList.add("atfb-tagpick--above"),c.querySelector(".atfb-tagpick__search")?.focus()})}),s}function pt(n,e){const t=parseFloat(String(n??""));return Number.isFinite(t)?t:e}function ft(n,e){let t=e[0];for(const s of e)Math.abs(s.at-n)n.accent??"#2271b1",apply:n=>({accent:n,"accent-soft":`color-mix( in srgb, ${n} 12%, transparent )`,"border-focus":n,"focus-ring-color":n,"button-bg":n,"button-bg-hover":`color-mix( in srgb, ${n} 88%, #000 )`})},{id:"roundness",label:"Roundness",hint:"Corners, everywhere at once.",kind:"scale",steps:Ne.map(({value:n,label:e})=>({value:n,label:e})),owns:["radius-field","radius-button","radius-card","radius-check"],read:n=>ft(pt(n["radius-field"],4),Ne),apply:n=>{const e=Ne.find(t=>t.value===n)?.at??4;return{"radius-field":`${e}px`,"radius-button":`${e}px`,"radius-card":`${Math.min(e*2,28)}px`,"radius-check":`${Math.min(e,6)}px`}}},{id:"density",label:"Density",hint:"How much air the form has.",kind:"scale",steps:Pe.map(({value:n,label:e})=>({value:n,label:e})),owns:["pad-field-x","pad-field-y","gap-fields","gap-label","button-pad-x","button-pad-y"],read:n=>ft(pt(n["pad-field-y"],9),Pe),apply:n=>{const e=Pe.find(t=>t.value===n)?.at??9;return{"pad-field-y":`${e}px`,"pad-field-x":`${Math.round(e*1.4)}px`,"gap-fields":`${Math.round(e*2.2)}px`,"gap-label":`${Math.max(4,Math.round(e*.7))}px`,"button-pad-y":`${e+2}px`,"button-pad-x":`${Math.round(e*2.2)}px`}}},{id:"shadow",label:"Depth",hint:"How far the form sits off the page.",kind:"scale",steps:Os,owns:["shadow-field","shadow-field-focus","shadow-button","shadow-button-hover","shadow-card"],read:n=>{const e=n["shadow-card"]??"none";return e==="none"||e.trim()===""?n["shadow-field"]&&n["shadow-field"]!=="none"?"hard":"none":e.includes("0 1px")||e.includes("2px")?"subtle":"lifted"},apply:n=>{switch(n){case"subtle":return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"0 1px 2px rgba( 0, 0, 0, 0.12 )","shadow-button-hover":"0 2px 4px rgba( 0, 0, 0, 0.16 )","shadow-card":"0 1px 3px rgba( 0, 0, 0, 0.1 )"};case"lifted":return{"shadow-field":"none","shadow-field-focus":"0 4px 12px rgba( 0, 0, 0, 0.12 )","shadow-button":"0 4px 10px rgba( 0, 0, 0, 0.16 )","shadow-button-hover":"0 8px 20px rgba( 0, 0, 0, 0.2 )","shadow-card":"0 10px 30px rgba( 0, 0, 0, 0.14 )"};case"hard":return{"shadow-field":"3px 3px 0 currentColor","shadow-field-focus":"5px 5px 0 currentColor","shadow-button":"4px 4px 0 currentColor","shadow-button-hover":"2px 2px 0 currentColor","shadow-card":"none"};default:return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"none","shadow-button-hover":"none","shadow-card":"none"}}}},{id:"field-style",label:"Fields",hint:"How an input is drawn.",kind:"choice",steps:Ns,owns:["field-style"],read:n=>n["field-style"]??"outline",apply:n=>({"field-style":n})},{id:"labels",label:"Labels",hint:"Where the question sits relative to the answer.",kind:"choice",steps:Ps,owns:["label-position"],read:n=>n["label-position"]??"top",apply:n=>({"label-position":n})}]}function Rs(n){return Re().find(e=>e.owns.includes(n))??null}function mt(n){let e=n.activeSlug,t={...n.overrides},s=n.themes;const a=p=>{t=p,n.onOverridesReplaced?.({...p})},i=r("div",{class:"atfs-preview__frame"}),o=r("div",{class:"atfs-controls__body"}),l=r("div",{class:"atfs-quick"}),c=r("div",{class:"atfs-themes"}),d=Ae(async()=>{try{const p=await n.previewFor(e,t),b=i.closest(".atf-studio__preview"),_=b?.scrollTop??0;i.innerHTML=p,b&&(b.scrollTop=_),document.dispatchEvent(new CustomEvent("alltfo-refresh"))}catch(p){P(i),i.append(r("p",{class:"atfb-error",text:p instanceof Error?p.message:"Preview failed."}))}},180),h={"label-position":"atf-labels-","field-style":"atf-fields-"},w=(p,b,_)=>{const k=_.replace(/[^a-z0-9_-]/gi,"");for(const $ of[...p.classList])$.startsWith(b)&&p.classList.remove($);k&&p.classList.add(b+k)},y=p=>{const b=i.querySelector(".atf-form-wrap"),_=b?.querySelector(".atf-form");if(b)for(const[k,$]of Object.entries(p))$===""?b.style.removeProperty(`--atf-${k}`):b.style.setProperty(`--atf-${k}`,$),_&&h[k]&&w(_,h[k],$||(s.find(B=>B.slug===e)?.resolved[k]??""))},u=p=>{y(p.resolved);const b=i.querySelector(".atf-form");b&&(w(b,"atf-theme-",p.slug),b.classList.toggle("atf-is-dark",!!p.dark))},x=p=>t[p.token]!==void 0?t[p.token]:s.find(_=>_.slug===e)?.resolved?.[p.token]??p.default,v=()=>{P(c);for(const p of s){const b=r("button",{class:`atfs-theme${p.slug===e?" is-active":""}`,type:"button",attrs:{"aria-pressed":p.slug===e,title:p.description},children:[r("span",{class:"atfs-theme__chip",style:{background:p.resolved.surface??"#fff",borderColor:p.resolved.border??"#ccc",borderRadius:p.resolved["radius-field"]??"4px",boxShadow:p.resolved["shadow-card"]??"none"},children:[r("span",{class:"atfs-theme__accent",style:{background:p.resolved.accent??"#2271b1",borderRadius:p.resolved["radius-button"]??"4px"}})]}),r("span",{class:"atfs-theme__name",text:p.label}),p.custom?r("span",{class:"atfb-badge",text:"yours"}):null],on:{click:()=>{e=p.slug,a({}),n.onTheme(e),u(p),v(),L(),N(),Yt()}}});c.append(b)}},f=()=>{const b={...s.find(_=>_.slug===e)?.resolved??{}};for(const[_,k]of Object.entries(t))b[_]=k;return b},C=p=>{const b=l.closest(".atf-studio__controls"),_=b?.scrollTop??0;p(),b&&(b.scrollTop=_)},N=Ae(()=>C(m),150),L=()=>{const p=f(),b=l.querySelectorAll(".atfs-dial");Re().forEach((_,k)=>{const $=b[k];if(!$)return;const B=_.read(p);if(_.kind==="colour"){const q=$.querySelector('input[type="color"]'),Z=$.querySelector("input.atfb-input");q&&document.activeElement!==q&&(q.value=be(B)),Z&&document.activeElement!==Z&&(Z.value=B);return}$.querySelectorAll(".atfs-segment").forEach((q,Z)=>{const Q=_.steps?.[Z]?.value===B;q.classList.toggle("is-on",Q),q.setAttribute("aria-pressed",String(Q))})})},T=(p,b)=>{const _=p.apply(b,f());for(const[k,$]of Object.entries(_))t[k]=$,n.onOverride(k,$);y(_),L(),N()},M=()=>{P(l);const p=f();for(const b of Re()){const _=b.read(p);let k;if(b.kind==="colour"){const $=r("input",{class:"atfs-color",type:"color",value:be(_),attrs:{"aria-label":b.label},on:{input:B=>T(b,B.target.value)}});k=r("div",{class:"atfs-color-row",children:[$,A(_,B=>T(b,B))]})}else k=r("div",{class:`atfs-segmented atfs-segmented--${b.kind}`,attrs:{role:"group","aria-label":b.label},children:(b.steps??[]).map($=>r("button",{class:`atfs-segment${$.value===_?" is-on":""}`,type:"button",text:$.label,attrs:{"aria-pressed":$.value===_},on:{click:()=>T(b,$.value)}}))});l.append(r("div",{class:"atfs-dial",children:[r("div",{class:"atfs-dial__head",children:[r("span",{class:"atfs-dial__label",text:b.label}),r("span",{class:"atfs-dial__hint",text:b.hint})]}),k]}))}},m=()=>{P(o);const p=new Map;for(const _ of n.tokens){const k=p.get(_.group)??[];k.push(_),p.set(_.group,k)}const b={colour:"Colour",shape:"Corners and borders",shadow:"Shadows",fields:"Field style",space:"Spacing",type:"Type",labels:"Labels",button:"Buttons",focus:"Focus ring",motion:"Motion"};for(const[_,k]of p)o.append(r("details",{class:"atfs-group",attrs:{open:_==="colour"},children:[r("summary",{text:b[_]??_}),...k.map($=>F($))]}))},F=p=>{const b=x(p),_=q=>{q===""?delete t[p.token]:t[p.token]=q,n.onOverride(p.token,q),y({[p.token]:q})};let k;if(p.control==="color"){const q=r("input",{class:"atfs-color",type:"color",value:be(b),attrs:{"aria-label":`${p.label} colour`},on:{input:Q=>{const le=Q.target.value;Z.value=le,_(le)}}}),Z=A(b,Q=>{q.value=be(Q),_(Q)});k=r("div",{class:"atfs-color-row",children:[q,Z]})}else if(p.control==="select")k=D(b,(p.options??[]).map(q=>({value:q,label:q})),_);else if(p.control==="length"){const q=parseFloat(b)||0,Z=p.unit??"px",Q=p.token.includes("radius")?60:80,le=r("input",{class:"atfs-range",type:"range",value:String(q),attrs:{min:"0",max:String(Q),step:"1","aria-label":p.label},on:{input:ke=>{const Zt=`${ke.target.value}${Z}`;Gt.value=Zt,_(Zt)}}}),Gt=A(b,ke=>{le.value=String(parseFloat(ke)||0),_(ke)});k=r("div",{class:"atfs-length-row",children:[le,Gt]})}else k=A(b,_);const $=g(p.label,k),B=Rs(p.token);return B&&($.classList.add("is-dialled"),$.append(r("span",{class:"atfs-owned",text:B.label}))),t[p.token]!==void 0&&($.classList.add("is-overridden"),$.append(r("button",{class:"atfs-reset",type:"button",text:"Reset",attrs:{"aria-label":`Reset ${p.label} to the theme's value`},on:{click:()=>{_(""),C(m)}}}))),$},S=async()=>{const p=s.find(k=>k.slug===e),b=p?`${p.label} (mine)`:"My theme",_=window.prompt("Name this theme",b);if(_)try{const k={};for(const B of n.tokens){const q=x(B);q!==B.default&&(k[B.token]=q)}const $=await I.saveTheme({label:_,tokens:k});s=[...s.filter(B=>B.slug!==$.slug),$],n.onThemesChanged(s),e=$.slug,a({}),n.onTheme(e),v(),L(),C(m),R("Theme saved",$.label)}catch(k){R("Could not save the theme",k instanceof Error?k.message:"","error")}},j=async()=>{const p=s.find(b=>b.slug===e);if(p?.custom&&await fe(`Delete “${p.label}”? Forms using it fall back to Clean.`,"Delete theme"))try{await I.deleteTheme(p.id),s=s.filter(_=>_.slug!==p.slug),n.onThemesChanged(s),e="clean",a({}),n.onTheme(e),v(),L(),C(m);const b=s.find(_=>_.slug===e);b&&u(b)}catch(b){R("Could not delete the theme",b instanceof Error?b.message:"","error")}},H=async()=>{const p=s.find(k=>k.slug===e),b={label:p?.label??e,tokens:{...p?.tokens??{},...t}},_=JSON.stringify(b,null," ");try{await navigator.clipboard.writeText(_),R("Theme copied","Paste it into another site to import it.")}catch{window.prompt("Copy this theme",_)}},oe=()=>{const p=window.prompt("Paste a theme");if(p)try{const b=JSON.parse(p);if(!b.tokens||typeof b.tokens!="object")throw new Error("That does not look like a theme.");for(const[_,k]of Object.entries(b.tokens))t[_]=String(k),n.onOverride(_,String(k));y({...t}),L(),C(m)}catch(b){R("Could not read that theme",b instanceof Error?b.message:"","error")}},zt=E("Delete",()=>void j(),"danger"),Yt=()=>{const p=s.find(b=>b.slug===e);zt.hidden=!p?.custom};return v(),M(),m(),d(),Yt(),r("div",{class:"atf-studio",children:[r("div",{class:"atf-studio__top",children:[r("div",{class:"atf-studio__topbar",children:[r("h2",{class:"atf-studio__heading",text:"Theme"}),r("div",{class:"atfs__actions",children:[E("Save as a theme",()=>void S(),"primary"),E("Export",()=>void H()),E("Import",oe),zt]})]}),c]}),r("div",{class:"atf-studio__panes",children:[r("aside",{class:"atf-studio__controls",children:[r("p",{class:"atfb-hint",text:"Changes apply to this form only, until you save them as a theme."}),l,r("details",{class:"atfs-advanced",children:[r("summary",{text:"Every setting"}),r("p",{class:"atfb-hint",text:"The full token list. The dials above write into it."}),o]})]}),r("main",{class:"atf-studio__preview",children:[r("h2",{class:"screen-reader-text",text:"Live preview"}),i]})]})]})}async function Be(){const n=document.querySelector("[data-atfs-root]");if(!n||n.dataset.atfsMounted)return;n.dataset.atfsMounted="1",Te(n);const e=n.querySelector("[data-atfs-bar]"),t=n.querySelector(".atfs__body")??n;try{const[s,a,i]=await Promise.all([I.config(),I.listThemes(),I.listForms()]);if(!i.length){P(t),t.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms to preview"}),r("p",{text:"Make a form first — a theme needs something to dress."})]}));return}let o=i[0],l={},c=o.theme;const d=()=>{P(t),t.append(mt({themes:a,tokens:s.tokens,activeSlug:c,overrides:l,standalone:!0,onTheme:h=>{c=h},onOverride:(h,w)=>{w===""?delete l[h]:l[h]=w},onOverridesReplaced:h=>{l={...h}},previewFor:async(h,w)=>{const y=await I.getForm(o.id);y.schema.settings.theme=h,y.schema.settings.themeOverrides=w;const{html:u}=await I.preview(o.id,{schema:y.schema,theme:h});return u},onThemesChanged:h=>{a.length=0,a.push(...h)}}))};e&&(P(e),e.append(r("span",{class:"atfs__label",text:"Preview against"}),D(String(o.id),i.map(h=>({value:String(h.id),label:h.title||"(untitled)"})),h=>{o=i.find(w=>String(w.id)===h)??i[0],l={},d()}))),d()}catch(s){P(t),t.append(r("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load themes."}))}}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void Be()):Be(),document.addEventListener("os-window-content-loaded",()=>void Be()));function be(n){const e=n.trim();return/^#[0-9a-f]{6}$/i.test(e)?e:/^#[0-9a-f]{3}$/i.test(e)?`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`:"#888888"}const Bs="mailpoet",ge="",Hs=["checkbox","checkboxes","toggle","consent","gdpr"],bt=["email"];function gt(n){return n.schema.actions.find(e=>e.type==="mailpoet")}function He(n){const e=n?.settings??{};return{lists:Array.isArray(e.lists)?e.lists.map(Number).filter(Boolean):[],email_field:typeof e.email_field=="string"?e.email_field:"",first_name_field:typeof e.first_name_field=="string"?e.first_name_field:"",last_name_field:typeof e.last_name_field=="string"?e.last_name_field:""}}function js(n){return n?.logic?.enabled?n.logic.rules[0]?.field??ge:ge}function vt(n,e,t){const s=n.find(a=>e.includes(a.type));return s?s.id:t?n.find(a=>t.test(a.label))?.id??"":""}function Ws(n,e,t){const s=r("section",{class:"atfm-form"}),a=l=>r("span",{class:`atfm-form__mark${l?"":" atfm-form__mark--off"}`,children:[r("img",{attrs:{src:e.symbol,alt:"",width:"20",height:"20"}})]}),i=l=>{P(s),s.classList.remove("is-open"),s.append(r("div",{class:"atfm-form__head",children:[a(l.length>0),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`}),l.length?r("span",{class:"atfm-form__status is-on",text:`Subscribing → ${l.join(", ")}`}):r("span",{class:"atfm-form__status",text:"Not connected"})]}),E(l.length?"Edit":"Connect",()=>void o(),"secondary")]}))},o=async()=>{s.classList.add("is-open"),P(s),s.append(r("p",{class:"atfm-hint",text:"Loading the form…"}));let l;try{l=await I.getForm(n.id)}catch{P(s),s.append(r("p",{class:"atfm-hint",text:"Could not load this form."}));return}const c=l.schema.fields.filter(m=>m.type!=="page_break"),d=gt(l),h=He(d),w=new Set(h.lists.filter(m=>e.lists.some(F=>F.id===m)));let y=js(d),u=h.email_field||vt(c,bt,/mail/i),x=h.first_name_field,v=h.last_name_field;c.some(m=>m.id===u)||(u=vt(c,bt,/mail/i));const f=c.filter(m=>Hs.includes(m.type));!d&&f.length&&(y=f[0].id);const C=(m,F)=>[{value:"",label:F},...m.map(S=>({value:S.id,label:S.label||S.id}))],N=r("div",{class:"atfm-lists"});(()=>{P(N);for(const m of e.lists){const F=r("input",{attrs:{type:"checkbox"}});F.checked=w.has(m.id),F.addEventListener("change",()=>{F.checked?w.add(m.id):w.delete(m.id)}),N.append(r("label",{class:"atfm-list",children:[F,r("span",{text:m.name})]}))}})();const T=async(m=!1)=>{const F=l.schema.actions.filter(S=>S.type!=="mailpoet");if(!m){if(!w.size){R("Pick a list","A subscription needs at least one MailPoet list.","error");return}if(!u){R("Pick the email field","MailPoet needs to know which answer is the address.","error");return}F.push({id:Bs,type:"mailpoet",enabled:!0,logic:y===ge?{enabled:!1,action:"show",match:"all",rules:[]}:{enabled:!0,action:"show",match:"all",rules:[{field:y,operator:"not_empty",value:""}]},settings:{lists:[...w],email_field:u,first_name_field:x,last_name_field:v}})}l.schema.actions=F;try{await I.updateForm(l.id,{schema:l.schema})}catch(S){R("Could not save",S instanceof Error?S.message:"","error");return}R(m?"Disconnected":"Connected to MailPoet",m?`${n.title} no longer subscribes anyone.`:`${n.title} now subscribes opted-in visitors.`),i(m?[]:e.lists.filter(S=>w.has(S.id)).map(S=>S.name))};P(s);const M=m=>r("span",{class:"atfm-form__section",text:m});s.append(r("div",{class:"atfm-form__head",children:[a(!!d),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`})]}),E("Close",()=>i(d?e.lists.filter(m=>He(d).lists.includes(m.id)).map(m=>m.name):[]),"ghost")]}),r("div",{class:"atfm-form__body",children:[M("Where they land"),g("Lists",N,"MailPoet sends its own confirmation email before anyone is truly on a list."),M("Who they are"),g("Email address",D(u,C(c,"— pick a field —"),m=>{u=m}),"The answer that carries their address."),g("First name",D(x,C(c,"— none —"),m=>{x=m})),g("Last name",D(v,C(c,"— none —"),m=>{v=m})),M("When to subscribe"),g("Subscribe",D(y,[...f.map(m=>({value:m.id,label:`Only when “${m.label||m.id}” is ticked`})),{value:ge,label:"Everyone who submits"}],m=>{y=m}),f.length?"Bind it to a box they tick. Subscribing everyone is rarely what visitors expect.":"Add a checkbox or toggle field to the form to offer a proper opt-in."),r("div",{class:"atfm-form__actions",children:d?[E("Save connection",()=>void T(),"primary"),E("Disconnect",()=>void T(!0),"danger")]:[E("Save connection",()=>void T(),"primary")]})]}))};return i([]),I.getForm(n.id).then(l=>{const c=gt(l);if(c&&!s.classList.contains("is-open")){const d=e.lists.filter(h=>He(c).lists.includes(h.id)).map(h=>h.name);i(d)}}).catch(()=>{}),t.append(s),s}function Us(n){const e=n.logo?r("span",{class:"atfm-hero__logo",children:[r("img",{attrs:{src:n.logo,alt:"MailPoet",width:"210",height:"105"}})]}):r("span",{class:"atfm-hero__logo atfm-hero__logo--glyph",text:"📬"});return r("header",{class:"atfm-hero",children:[e,r("div",{class:"atfm-hero__words",children:[r("h1",{text:"Turn submissions into subscribers"}),r("p",{text:"Every submission is someone choosing to talk to you. Connect a form to MailPoet and the ones who opt in land on your lists by themselves — named, consented, and confirmed by MailPoet’s own double opt-in."}),n.active?r("p",{class:"atfm-hero__status is-on",text:n.lists.length===1?"Connected — 1 list ready for subscribers":`Connected — ${n.lists.length} lists ready for subscribers`}):r("p",{class:"atfm-hero__status",text:"MailPoet is not installed on this site yet"})]})]})}function zs(){const n=(t,s,a)=>r("div",{class:"atfm-why__card",children:[r("span",{class:"atfm-why__icon",text:t}),r("strong",{text:s}),r("p",{text:a})]}),e=(t,s)=>r("a",{text:s,attrs:{href:t,target:"_blank",rel:"noreferrer"}});return[r("div",{class:"atfm-why",children:[n("✉️","Beautiful emails, made in WordPress","Design newsletters and welcome emails in a drag-and-drop editor that lives in your own admin — no external account to juggle."),n("🤝","Consent you can stand behind","Double opt-in out of the box: every address your forms send over is confirmed by the visitor before a single campaign reaches it."),n("🚀","Free to grow with","Free up to 500 subscribers, welcome automations, WooCommerce emails and open-rate stats included — a paid addon anywhere else.")]}),r("p",{class:"atfm-links",children:[e("https://www.mailpoet.com/features/","Explore MailPoet’s features ↗"),e("https://kb.mailpoet.com/","Guides & docs ↗"),e("https://www.mailpoet.com/pricing/","Plans & the free tier ↗")]})]}function Ys(){const n=(e,t)=>r("div",{class:"atfm-step",children:[r("span",{class:"atfm-step__n",text:e}),r("span",{text:t})]});return r("div",{class:"atfm-steps",children:[n("1","Pick a form below"),n("2","Choose the lists it feeds"),n("3","Bind it to an opt-in — MailPoet confirms the rest")]})}async function je(){const n=document.querySelector("[data-atfm-root]");if(!n||n.dataset.atfmMounted)return;n.dataset.atfmMounted="1",Te(n);const e=n.querySelector("[data-atfm-bar]"),t=n.querySelector("[data-atfm-body]")??n;try{const[s,a]=await Promise.all([I.mailpoet(),I.listForms()]);if(e?.remove(),P(t),t.append(Us(s),...zs()),!s.active){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet sends newsletters from right inside WordPress — no external account, free to start. Install it and every form here gets a subscribe switch: reservations feed your announcements, signups feed your schedule, enquiries feed your news."}),r("a",{class:"atfm-pitch__cta",text:"Install MailPoet — it’s free",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}if(!s.lists.length){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet is here, but it has no list yet. Make one, and your forms will have somewhere to send subscribers."}),r("a",{class:"atfm-pitch__cta",text:"Open MailPoet lists",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}t.append(Ys());const i=r("section",{class:"atfm-forms",children:[r("div",{class:"atfm-forms__head",children:[r("h2",{text:"Your forms"}),r("p",{class:"atfm-hint",text:"Connected forms wear the MailPoet mark in colour."})]})]});if(t.append(i),!a.length){i.append(r("p",{class:"atfm-hint",text:"No forms yet — make one, then come back to connect it."}));return}for(const o of a)Ws(o,s,i)}catch{e&&(e.textContent="Could not reach the site — reload the window to try again.")}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void je()):je(),document.addEventListener("os-window-content-loaded",()=>void je());const ve={plain:"",simple:"✓",minimal:"",card:"🎉",check:"",confetti:"🎉",fireworks:"🎆",sparkles:"✨",typewriter:""};function yt(){return{style:"simple",title:"",icon:"",accent:"",intensity:"medium",showButton:!1,buttonLabel:""}}function We(n){const e={...yt(),...n??{}};return e.style in ve||(e.style="simple"),e}function Gs(){return typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}function Zs(n,e,t){const s=We(e),a=document.createElement("div");if(a.className=`atf-confirmation atf-success atf-success--${s.style}`,a.setAttribute("role","status"),a.setAttribute("tabindex","-1"),s.style==="plain")return a.className="atf-confirmation",a.innerHTML=n,a;s.accent&&a.style.setProperty("--atf-accent",s.accent);const i=document.createElement("div");i.className="atf-success__inner",a.append(i);const o=s.icon||ve[s.style];if(s.style==="check")i.insertAdjacentHTML("beforeend",'');else if(o){const c=document.createElement("span");c.className="atf-success__icon",c.setAttribute("aria-hidden","true"),c.textContent=o,i.append(c)}if(s.title){const c=document.createElement("h2");c.className="atf-success__title",c.textContent=s.title,i.append(c)}const l=document.createElement("div");if(l.className="atf-success__message",l.innerHTML=n,i.append(l),s.style==="typewriter"&&a.setAttribute("aria-label",l.textContent??""),s.showButton){const c=document.createElement("button");c.type="button",c.className="atf-button atf-button--ghost atf-success__again",c.textContent=s.buttonLabel||"Fill it in again",c.addEventListener("click",()=>t?t():window.location.reload()),i.append(c)}return a}function Ks(n,e){const t=We(e);if(Gs())return()=>{};switch(t.style){case"confetti":return Xs(n,t);case"fireworks":return Vs(t);case"sparkles":return Js(n,t);case"typewriter":return Qs(n);default:return()=>{}}}function re(n){return{low:.5,medium:1,high:1.8}[n.intensity]}function wt(){const n=document.createElement("canvas");n.className="atf-success-canvas",n.setAttribute("aria-hidden","true");const e=Math.min(window.devicePixelRatio||1,2);n.width=Math.floor(window.innerWidth*e),n.height=Math.floor(window.innerHeight*e),document.body.append(n);const t=n.getContext("2d");return t?.scale(e,e),{canvas:n,ctx:t,stop:()=>n.remove()}}const _t=["#f43f5e","#f59e0b","#10b981","#3b82f6","#8b5cf6","#ec4899","#eab308"];function Xs(n,e){const{ctx:t,stop:s}=wt();if(!t)return s(),()=>{};const a=e.accent?[e.accent,..._t]:_t,i=[],o=n.getBoundingClientRect(),l=o.left+o.width/2,c=Math.min(o.top+40,window.innerHeight-20),d=(C,N,L)=>{const T=L?Math.PI*(1.15+.7*Math.random()):0,M=L?9+Math.random()*8:0;return{x:C,y:N,vx:L?Math.cos(T)*M*(Math.random()<.5?1:-1):(Math.random()-.5)*1.5,vy:L?Math.sin(T)*M:1+Math.random()*2,w:6+Math.random()*5,h:8+Math.random()*7,angle:Math.random()*Math.PI,spin:(Math.random()-.5)*.3,color:a[Math.floor(Math.random()*a.length)],wobble:Math.random()*Math.PI*2}},h=Math.round(90*re(e));for(let C=0;C{if(y>=w){window.clearInterval(u);return}i.push(d(Math.random()*window.innerWidth,-20,!1)),y++},2e3/w);let x=0;const v=performance.now(),f=C=>{t.clearRect(0,0,window.innerWidth,window.innerHeight);let N=!1;for(const L of i)L.vy+=.16,L.vx*=.99,L.vy*=.985,L.wobble+=.1,L.x+=L.vx+Math.sin(L.wobble)*.8,L.y+=L.vy,L.angle+=L.spin,L.y{window.clearInterval(u),window.cancelAnimationFrame(x),s()}}function Vs(n){const{ctx:e,stop:t}=wt();if(!e)return t(),()=>{};const s=[],a=[],i=Math.round(6*re(n))+2;let o=0;const l=()=>{s.push({x:window.innerWidth*(.15+.7*Math.random()),y:window.innerHeight,vy:-(9+Math.random()*4),targetY:window.innerHeight*(.15+.3*Math.random()),hue:Math.floor(Math.random()*360)}),o++};l();const c=window.setInterval(()=>{if(o>=i){window.clearInterval(c);return}l()},3500/i),d=u=>{const x=Math.round(70*re(n));for(let v=0;v{e.clearRect(0,0,window.innerWidth,window.innerHeight);for(let v=s.length-1;v>=0;v--){const f=s[v];f.y+=f.vy,f.vy+=.08,e.fillStyle=`hsl(${f.hue} 90% 65%)`,e.fillRect(f.x-1.5,f.y,3,10),(f.y<=f.targetY||f.vy>=-1)&&(d(f),s.splice(v,1))}for(let v=a.length-1;v>=0;v--){const f=a[v];if(f.x+=f.vx,f.y+=f.vy,f.vy+=.045,f.vx*=.985,f.vy*=.985,f.life-=f.decay,f.life<=0){a.splice(v,1);continue}const C=f.life*(.7+.3*Math.random());e.globalAlpha=Math.max(0,C),e.fillStyle=`hsl(${f.hue} 95% ${55+25*f.life}%)`,e.beginPath(),e.arc(f.x,f.y,1.1+1.6*f.life,0,Math.PI*2),e.fill()}e.globalAlpha=1,!(o>=i&&s.length===0&&a.length===0)&&u-w<9e3?h=window.requestAnimationFrame(y):t()};return h=window.requestAnimationFrame(y),()=>{window.clearInterval(c),window.cancelAnimationFrame(h),t()}}function Js(n,e){const t=e.icon||ve.sparkles,s=Math.round(22*re(e)),a=[];let i=0;const o=()=>{const c=document.createElement("span");c.className="atf-success__spark",c.setAttribute("aria-hidden","true"),c.textContent=t,c.style.insetInlineStart=`${4+Math.random()*92}%`,c.style.animationDuration=`${2.6+Math.random()*1.8}s`,c.style.animationDelay=`${Math.random()*.3}s`,c.style.fontSize=`${14+Math.random()*14}px`,c.addEventListener("animationend",()=>c.remove()),n.append(c),a.push(c),i++};o();const l=window.setInterval(()=>{if(i>=s){window.clearInterval(l);return}o()},2800/s);return()=>{window.clearInterval(l),a.forEach(c=>c.remove())}}function Qs(n){const e=n.querySelector(".atf-success__message");if(!e)return()=>{};const t=e.innerHTML,s=e.textContent??"";if(!s)return()=>{};e.textContent="",e.classList.add("is-typing");const a=Math.min(45,3800/s.length);let i=0;const o=window.setInterval(()=>{i++,e.textContent=s.slice(0,i),i>=s.length&&(window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t)},a);return()=>{window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t}}const en={min:-1,max:-1,sum:-1,avg:-1,round:-1,ceil:1,floor:1,abs:1,sqrt:1,pow:2},xt={"+":{precedence:1,right:!1},"-":{precedence:1,right:!1},"*":{precedence:2,right:!1},"/":{precedence:2,right:!1},"%":{precedence:2,right:!1},"^":{precedence:4,right:!0}};function tn(n,e,t=[]){if(!n||!n.trim()||n.length>2e3)return null;const s=sn(n,e,t),a=on(s);if(!a)return null;const i=cn(a);if(!i)return null;const o=dn(i);return o===null||!Number.isFinite(o)?null:o}function sn(n,e,t){return n.replace(/\{([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_]+))?\}/g,(s,a,i,o)=>nn(n,o,s.length,a,i??"",e,t))}function nn(n,e,t,s,a,i,o){const l=an(o,s),c=Object.prototype.hasOwnProperty.call(i,s)?i[s]:null;if(a===""){const u=l?.type==="repeater"?kt(c).length:Ue(c,l);return St(u)}const h=(l?.fields??[]).find(u=>u.id===a)??null,w=kt(c).map(u=>Ue(u[a]??"",h));if(!w.length)return"0";const y=w.map(St);return rn(n,e,t)?y.join(", "):y.length===1?y[0]:`( ${y.join(" + ")} )`}function an(n,e){for(const t of n){if(t.id===e)return t;for(const s of t.fields??[])if(s.id===e)return s}return null}function rn(n,e,t){const s=n.slice(e+t).replace(/^\s+/,"");if(s===""||s[0]!==")")return!1;const a=n.slice(0,e).replace(/\s+$/,""),i=/([a-zA-Z_][a-zA-Z0-9_]*)\s*\($/.exec(a);return!!i&&["sum","avg","min","max"].includes(i[1].toLowerCase())}function kt(n){if(!Array.isArray(n))return[];const e=[];for(const t of n){if(!t||typeof t!="object"||Array.isArray(t))continue;Object.values(t).some(a=>a!==""&&a!==null&&a!==void 0&&a!==!1&&!(Array.isArray(a)&&!a.length))&&e.push(t)}return e}function St(n){const e=n.toFixed(10).replace(/0+$/,"").replace(/\.$/,"");return e===""||e==="-"?"0":e}function Ue(n,e){if(typeof n=="boolean")return n?1:0;if(Array.isArray(n))return n.reduce((a,i)=>a+Ue(i,e),0);if(n==null||n==="")return 0;const t=e?.choices??[];for(const a of t)if(String(a.value)===String(n)){if(typeof a.price=="number")return a.price;if(typeof a.points=="number")return a.points;break}const s=Number(n);return Number.isFinite(s)?s:0}function on(n){const e=[];let t=0;for(;ti.precedence||l.precedence===i.precedence&&!i.right){e.push(t.pop());continue}break}t.push(a);break}case"(":t.push(a);break;case")":{for(;t.length&&t[t.length-1].type!=="(";)e.push(t.pop());if(!t.length)return null;if(t.pop(),t.length&&t[t.length-1].type==="function"){const i=t.pop();i.arity=s.length?s.pop():1,e.push(i)}break}}for(;t.length;){const a=t.pop();if(a.type==="(")return null;e.push(a)}return e}function dn(n){const e=[];for(const t of n)switch(t.type){case"number":e.push(t.value);break;case"unary":{if(!e.length)return null;e.push(-e.pop());break}case"operator":{if(e.length<2)return null;const s=e.pop(),a=e.pop();switch(t.value){case"+":e.push(a+s);break;case"-":e.push(a-s);break;case"*":e.push(a*s);break;case"/":e.push(s===0?0:a/s);break;case"%":e.push(s===0?0:a%s);break;case"^":e.push(Math.pow(a,s));break;default:return null}break}case"function":{const s=t.arity??1;if(e.lengtht+s,0);case"avg":return e.reduce((t,s)=>t+s,0)/e.length;case"round":{const t=Math.max(-10,Math.min(10,Math.trunc(e[1]??0))),s=Math.pow(10,t);return Math.round(e[0]*s)/s}case"ceil":return Math.ceil(e[0]);case"floor":return Math.floor(e[0]);case"abs":return Math.abs(e[0]);case"sqrt":return e[0]<0?0:Math.sqrt(e[0]);case"pow":return Math.pow(e[0],e[1]??2);default:return null}}const un=["sum","min","max","avg","round","ceil","floor","abs","sqrt","pow"],Lt=["number","range","scale","rating","total","select","multiselect","radio","checkboxes","switch","quiz"];function ze(n,e){return n.filter(t=>t.id!==e&&Lt.includes(t.type))}function pn(n){const e=[];for(const t of n){if(t.type!=="repeater")continue;const s=t.label||t.id;e.push({label:`${s} (how many)`,insert:`{${t.id}}`});for(const a of t.fields??[])Lt.includes(a.type)&&e.push({label:`${s} · ${a.label||a.id}`,insert:`{${t.id}.${a.id}}`})}return e}function fn(n,e){const t={};ze(n,e).forEach((s,a)=>{t[s.id]=a+1});for(const s of n){if(s.type!=="repeater"||s.id===e)continue;const a=s.fields??[],i=o=>Object.fromEntries(a.map((l,c)=>[l.id,c+1+o]));t[s.id]=[i(0),i(1)]}return t}function mn(n){const e=r("div",{class:"atfb-overlay"}),t=()=>{e.remove(),document.removeEventListener("keydown",s)},s=u=>{u.key==="Escape"&&t()},a=r("textarea",{class:"atfb-input atfb-formula__input",attrs:{rows:"3","aria-label":"Formula"}});a.value=String(n.field.formula??"");const i=r("p",{class:"atfb-formula__result",attrs:{"aria-live":"polite"}}),o=fn(n.fields,n.field.id),l=()=>{const u=a.value.trim();if(u===""){i.textContent="Empty. Reference a question below to start.",i.classList.remove("is-error");return}const x=tn(u,o,n.fields);if(x===null){i.textContent="This does not compute yet — check the braces and parentheses.",i.classList.add("is-error");return}const v=ze(n.fields,n.field.id).map((f,C)=>`${f.label||f.id} = ${C+1}`).concat(n.fields.filter(f=>f.type==="repeater"&&f.id!==n.field.id).map(f=>`${f.label||f.id} = 2 sample rows`)).join(", ");i.textContent=`With sample answers (${v}): ${x}`,i.classList.remove("is-error")};a.addEventListener("input",l);const c=(u,x,v=0)=>r("button",{class:"atfb-formula__chip",type:"button",text:u,on:{click:()=>{if(ht(a,x),v>0){const f=(a.selectionStart??a.value.length)-v;a.setSelectionRange(f,f)}}}}),d=ze(n.fields,n.field.id),h=pn(n.fields),w=r("div",{class:"atfb-formula__chips",children:d.length||h.length?[...d.map(u=>c(u.label||u.id,`{${u.id}}`)),...h.map(u=>c(u.label,u.insert))]:[r("p",{class:"atfb-hint",text:"No number-shaped questions yet — add a number, scale or priced choice field and it appears here."})]}),y=r("div",{class:"atfb-formula__chips",children:un.map(u=>c(`${u}()`,`${u}()`,1))});e.append(r("div",{class:"atfb-modal atfb-formula",attrs:{role:"dialog","aria-label":"Formula editor"},children:[r("h2",{text:"Formula"}),a,i,g("Your questions",w,"Click one to reference its answer."),g("Functions",y),r("div",{class:"atfb-modal__actions",children:[E("Cancel",t),E("Save formula",()=>{n.onSave(a.value.trim()),t()},"primary")]})]})),e.addEventListener("click",u=>{u.target===e&&t()}),document.addEventListener("keydown",s),n.root.append(e),l(),a.focus(),a.setSelectionRange(a.value.length,a.value.length)}const bn="allterrain-forms/form";function gn(){return window.wp?.os?.relations??null}function Et(n){const e=n.closest("[data-window-id], .os-window");if(!e)return null;const t=e.getAttribute("data-window-id");if(t)return t;const s=e.id??"";return s?s.replace(/^wp-window-/,""):null}const vn=6e3,Ct=120;function $t(n,e){const t=gn();if(Ye.set(n,e),!t?.set)return;const s=i=>{if(ye.get(n)!==a)return;const o=Et(n);if(!o){Date.now()s(i),Ct);return}try{t.set(o,e)}catch(c){At||(At=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",c,e)),ye.delete(n);return}if(!e||t.get?.(o)?.id===e.id||Date.now()>=i){ye.delete(n);return}window.setTimeout(()=>s(i),Ct)},a=Symbol("atf-identity");ye.set(n,a),s(Date.now()+vn)}let At=!1;const ye=new WeakMap,Ye=new Map;function yn(){for(const[n,e]of Ye){if(!n.isConnected){Ye.delete(n);continue}$t(n,e)}}if(typeof document<"u")for(const n of["os-window-content-loaded","os-window-opened"])document.addEventListener(n,()=>yn());function wn(n,e){return{type:bn,id:n.id,label:n.title||"Untitled form",related:[{id:`allterrain-forms/entries-${n.id}`,label:"Entries for this form",url:`${e}admin.php?page=allterrain-forms-entries&form=${n.id}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-list-view"}]}}const we={letters:{label:"Letters",chars:"A-Za-zÀ-ÖØ-öø-ÿ"},numbers:{label:"Numbers",chars:"0-9"},spaces:{label:"Spaces",chars:" "},punctuation:{label:`Punctuation ( . , ! ? ' " - )`,chars:`.,!?'"()\\-:;`},symbols:{label:"Symbols ( @ # & _ / + )",chars:"@#&_/+*%="}};function _n(){return{mode:"blocks",starts:"",ends:"",contains:"",notContains:"",chars:[],minLen:"",maxLen:"",regex:"",message:"",tests:[]}}function Tt(n){const e=_n();let t;try{t=JSON.parse(n)}catch{return e}if(!t||typeof t!="object")return e;const s=t;e.mode=s.mode==="regex"?"regex":"blocks";for(const a of["starts","ends","contains","notContains","minLen","maxLen","regex","message"])typeof s[a]=="string"&&(e[a]=s[a]);return Array.isArray(s.chars)&&(e.chars=s.chars.filter(a=>typeof a=="string"&&a in we)),Array.isArray(s.tests)&&(e.tests=s.tests.filter(a=>typeof a=="string").slice(0,10)),e}function _e(n){return n.replace(/[.*+?^${}()|[\]\\/]/g,"\\$&")}function xe(n){if(n.mode==="regex")return n.regex.trim();const e=[],t=n.minLen.trim(),s=n.maxLen.trim();(t!==""||s!=="")&&e.push(`(?=.{${t===""?"0":parseInt(t,10)||0},${s===""?"":parseInt(s,10)||""}}$)`),n.contains!==""&&e.push(`(?=.*${_e(n.contains)})`),n.notContains!==""&&e.push(`(?!.*${_e(n.notContains)})`),n.starts!==""&&e.push(`(?=${_e(n.starts)})`),n.ends!==""&&e.push(`(?=.*${_e(n.ends)}$)`);const a=n.chars.map(o=>we[o]?.chars??"").join(""),i=a?`[${a}]*$`:".*$";return!e.length&&!a?"":`^${e.join("")}${i}`}function Mt(n){if(n.mode==="regex")return n.regex.trim()?`Matches the expression ${n.regex.trim()}`:"";const e=[];if(n.starts&&e.push(`starts with “${n.starts}”`),n.ends&&e.push(`ends with “${n.ends}”`),n.contains&&e.push(`contains “${n.contains}”`),n.notContains&&e.push(`never contains “${n.notContains}”`),n.chars.length){const i=n.chars.map(o=>(we[o]?.label??o).split(" (")[0].toLowerCase());e.push(`uses only ${i.join(" and ")}`)}const t=n.minLen.trim(),s=n.maxLen.trim();return t&&s?e.push(`is ${t}–${s} characters long`):t?e.push(`is at least ${t} characters long`):s&&e.push(`is at most ${s} characters long`),e.length?`The answer ${e.length>1?`${e.slice(0,-1).join(", ")}, and ${e[e.length-1]}`:e[0]}.`:""}function xn(n,e){const t=xe(n);if(t==="")return null;try{return new RegExp(t).test(e)}catch{return null}}function kn(){return window.wp?.os?.windowManager??null}const Ft="allterrain-forms-validation";function Sn(n){const e=kn(),t=Et(n.root);if(e?.openChild&&t){Ln(e,t,n);return}En(n)}function Ln(n,e,t){const s=`${Ft}-${t.field.id}`;n.getById?.(s)&&n.remove?.(s);const a={saved:!1},i=()=>{const o=n.getById?.(s);o?.close?o.close():n.remove?.(s)};n.openChild?.(e,{id:s,baseId:Ft,url:`#${s}`,title:`Custom rule — ${t.field.label||"this question"}`,icon:"dashicons-yes-alt",native:!0,width:560,height:700,minWidth:440,minHeight:480,ephemeral:!0,autofocus:".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea",render:o=>{const l=r("div",{class:"atfa atfb-valwin atfb-valwin--window"}),c=r("div",{class:"atfb-valwin__scroll"});l.append(c),It(c,t,a,i,"window");const d=c.querySelector(".atfb-modal__actions");d&&l.append(d),o.append(l)},onClose:()=>{a.saved||t.onCancel?.()}})}function En(n){const e=r("div",{class:"atfb-overlay"}),t={saved:!1},s=()=>{e.remove(),document.removeEventListener("keydown",a),t.saved||n.onCancel?.()},a=o=>{o.key==="Escape"&&s()},i=r("div",{class:"atfb-modal atfb-valwin",attrs:{role:"dialog","aria-label":"Custom validation rule"},children:[r("h2",{text:"Custom rule"})]});It(i,n,t,s,"overlay"),e.append(i),e.addEventListener("click",o=>{o.target===e&&s()}),document.addEventListener("keydown",a),n.root.append(e),e.querySelector(".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea")?.focus()}function It(n,e,t,s,a){const i=Tt(String(e.field.validationRecipe??""));i.mode==="blocks"&&xe(i)===""&&e.field.pattern&&(i.mode="regex",i.regex=String(e.field.pattern)),i.message||(i.message=String(e.field.messages?.invalid??""));const o=(m,F)=>{const S=r("input",{class:"atfb-input",value:i[m],placeholder:F,attrs:{type:"text"}});return S.addEventListener("input",()=>{i[m]=S.value,M()}),S},l=(m,F)=>{const S=r("input",{class:"atfb-input atfb-valwin__len",value:i[m],attrs:{type:"number",min:"0","aria-label":F}});return S.addEventListener("input",()=>{i[m]=S.value,M()}),S},c=r("div",{class:"atfb-valwin__chars",children:Object.entries(we).map(([m,F])=>O(F.label,i.chars.includes(m),S=>{i.chars=S?[...i.chars,m]:i.chars.filter(j=>j!==m),M()}))}),d=r("div",{class:"atfb-valwin__pane",children:[g("Starts with",o("starts","e.g. AT-")),g("Ends with",o("ends","e.g. -2026")),g("Must contain",o("contains","e.g. @")),g("Must not contain",o("notContains","e.g. spaces? type one")),g("Only these characters",c,"Leave every box unticked to allow anything."),g("Length",r("div",{class:"atfb-valwin__lengths",children:[r("span",{text:"between"}),l("minLen","Minimum length"),r("span",{text:"and"}),l("maxLen","Maximum length"),r("span",{text:"characters"})]}),"Leave a box empty for no limit.")]}),h=r("textarea",{class:"atfb-input atfb-valwin__regex",attrs:{rows:"2","aria-label":"Regular expression",placeholder:"^AT-[0-9]{4}$"}});h.value=i.regex,h.addEventListener("input",()=>{i.regex=h.value,M()});const w=r("div",{class:"atfb-valwin__pane",children:[g("Expression",h,"A regular expression, without slashes. Checked against the whole answer only if you anchor it with ^ and $.")]}),y=[["blocks","Easy blocks"],["regex","Expression (advanced)"]],u=m=>{i.mode=m,d.hidden=m!=="blocks",w.hidden=m!=="regex",M()},v=(()=>{if(Y("os-segmented")&&Y("os-segment")){const S=document.createElement("os-segmented");S.setAttribute("value",i.mode),S.setAttribute("label","How to write the rule"),S.classList.add("atfb-valwin__tabs");for(const[j,H]of y){const oe=document.createElement("os-segment");oe.setAttribute("value",j),oe.textContent=H,S.append(oe)}return S.addEventListener("os-pick",j=>{const H=j.detail?.value;(H==="blocks"||H==="regex")&&(S.setAttribute("value",H),u(H))}),S}const m=r("div",{class:"atfb-valwin__tabs",attrs:{role:"tablist"}}),F=()=>{m.replaceChildren(...y.map(([S,j])=>{const H=i.mode===S;return r("button",{class:`atfb-valwin__tab${H?" is-active":""}`,type:"button",text:j,attrs:{role:"tab","aria-selected":H?"true":"false"},on:{click:()=>{u(S),F()}}})}))};return F(),m})();d.hidden=i.mode!=="blocks",w.hidden=i.mode!=="regex";const f=r("input",{class:"atfb-input",value:i.message,placeholder:"That is not in the expected format.",attrs:{type:"text"}});f.addEventListener("input",()=>{i.message=f.value});const C=r("p",{class:"atfb-valwin__summary",attrs:{"aria-live":"polite"}}),N=r("div",{class:"atfb-valwin__samples"}),L=m=>{const F=r("span",{class:"atfb-valwin__verdict",attrs:{"aria-live":"polite"}}),S=r("input",{class:"atfb-input",value:m,placeholder:"Type a sample answer…",attrs:{type:"text"}});S.addEventListener("input",()=>M()),N.append(r("div",{class:"atfb-valwin__sample",children:[S,F]}))};for(const m of i.tests.length?i.tests:["","",""])L(m);const T=()=>Array.from(N.querySelectorAll("input")).map(m=>m.value),M=()=>{const m=Mt(i);C.textContent=m||"Nothing yet — fill in a block above and the rule appears here in plain words.";for(const F of Array.from(N.querySelectorAll(".atfb-valwin__sample"))){const S=F.querySelector("input"),j=F.querySelector(".atfb-valwin__verdict");if(!S||!j)continue;const H=S.value===""?null:xn(i,S.value);j.textContent=H===null?"·":H?"✓ passes":"✗ fails",j.classList.toggle("is-pass",H===!0),j.classList.toggle("is-fail",H===!1)}};n.append(r("p",{class:"atfb-hint",text:`Describe what a good answer to “${e.field.label||"this question"}” looks like — no code needed.`}),v,d,w,r("div",{class:"atfb-valwin__try",children:[r("h3",{text:"Try it out"}),C,N,E("Add another sample",()=>{L(""),M()},"ghost","plus-alt2")]}),g("When it fails, say",f,"Shown to the visitor when their answer breaks the rule. Leave empty for the default wording."),r("div",{class:"atfb-modal__actions",children:[E(a==="window"?"Close without saving":"Cancel",s),E("Save rule",()=>{const m=xe(i);i.tests=T().filter(F=>F!=="").slice(0,10),t.saved=!0,e.onSave({pattern:m,recipe:i,message:i.message.trim()}),s()},"primary")]})),M()}const Cn=["Contact","Numbers & codes","Text shape","Web"],Dt=[{slug:"email",label:"An email address",group:"Contact",example:"jane@example.com",pattern:"^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",message:"That does not look like an email address."},{slug:"phone",label:"A phone number",group:"Contact",example:"+34 612 345 678",pattern:"^(?=(?:[^0-9]*[0-9]){5,})\\+?[0-9 ().-]{5,24}$",message:"That does not look like a phone number."},{slug:"handle",label:"A username or @handle",group:"Contact",example:"@yourname",pattern:"^@?[A-Za-z0-9_]{2,30}$",message:"That does not look like a username."},{slug:"digits",label:"Numbers only",group:"Numbers & codes",example:"12345",pattern:"^[0-9]+$",message:"Numbers only, please."},{slug:"decimal",label:"A number, decimals allowed",group:"Numbers & codes",example:"3.14",pattern:"^-?[0-9]+([.,][0-9]+)?$",message:"That does not look like a number."},{slug:"price",label:"A price",group:"Numbers & codes",example:"19.99",pattern:"^[0-9]+([.,][0-9]{1,2})?$",message:"That does not look like a price."},{slug:"zip_us",label:"A ZIP code (US)",group:"Numbers & codes",example:"90210",pattern:"^[0-9]{5}(-[0-9]{4})?$",message:"That does not look like a ZIP code."},{slug:"postcode_uk",label:"A postcode (UK)",group:"Numbers & codes",example:"SW1A 1AA",pattern:"^[A-Za-z]{1,2}[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}$",message:"That does not look like a postcode."},{slug:"iban",label:"An IBAN",group:"Numbers & codes",example:"DE89 3704 0044 0532 0130 00",pattern:"^[A-Za-z]{2}[0-9]{2}(?: ?[A-Za-z0-9]){10,32}$",message:"That does not look like an IBAN."},{slug:"credit_card",label:"A card number",group:"Numbers & codes",example:"4242 4242 4242 4242",pattern:"^[0-9](?:[0-9 -]{9,21})?[0-9]$",message:"That does not look like a card number.",luhn:!0},{slug:"letters",label:"Letters only",group:"Text shape",example:"María López",pattern:"^[\\p{L}\\p{M} .'’-]+$",message:"Letters only, please."},{slug:"alphanumeric",label:"Letters and numbers only",group:"Text shape",example:"abc123",pattern:"^[A-Za-z0-9]+$",message:"Letters and numbers only, please."},{slug:"no_spaces",label:"One word, no spaces",group:"Text shape",example:"one-word",pattern:"^\\S+$",message:"No spaces allowed."},{slug:"url",label:"A web address",group:"Web",example:"https://example.com",pattern:"^(https?://)?([A-Za-z0-9-]+\\.)+[A-Za-z]{2,}([/?#]\\S*)?$",message:"That does not look like a web address."},{slug:"ip",label:"An IP address",group:"Web",example:"192.168.0.1",pattern:"^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$",message:"That does not look like an IP address."},{slug:"slug",label:"A URL slug",group:"Web",example:"my-page-title",pattern:"^[a-z0-9]+(-[a-z0-9]+)*$",message:"Lowercase letters, numbers and dashes only."},{slug:"hex_color",label:"A hex colour",group:"Web",example:"#3366ff",pattern:"^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$",message:"That does not look like a colour code."}];function $n(n){return Dt.find(e=>e.slug===n)??null}function Ge(){return window.wp?.os??null}const qt="allterrain-forms/preview",Ze="allterrain-forms-preview";function An(n){const e=Ge();if(!e?.registerTitleBarButton)return()=>{};const t=()=>{try{e.registerTitleBarButton({id:qt,label:"Preview this form",icon:"dashicons-visibility",placement:"right",order:90,match:s=>{const a=s?.id??s?.config?.id??"";return a==="allterrain-forms"||a.startsWith("allterrain-forms#")},onClick:()=>void Ot(n),owner:"allterrain-forms-builder"})}catch{}};return e.ready?e.ready(t):t(),()=>{try{e.unregisterTitleBarButton?.(qt)}catch{}}}async function Ot(n){n.isDirty()&&await n.save();const e=n.current();e&&Nt(e.id,e.title,e.previewUrl)}function Nt(n,e,t){const s=Ge();if(!s?.windowManager?.open){window.open(t,"_blank","noopener");return}s.windowManager.open({id:`${Ze}-${n}`,baseId:Ze,url:t,title:`Preview: ${e}`,icon:"dashicons-visibility"})}function Tn(n,e,t){if(!Ge()?.windowManager?.open||!document.querySelector(`[data-window-id="${Ze}-${n}"]`))return;const i=t.includes("?")?"&":"?";Nt(n,e,`${t}${i}alltfo_r=${Date.now()}`)}const se="allterrain-forms/field",Mn=["openstation/file","desktop-mode/file","openstation/attachment"],Pt="allterrain-forms/logic-map-v2";function J(n,e){return n.dataset.atfbBind=e,n}const Rt={level:{key:"level",label:"Heading level",control:"select",hint:"Headings should step down one at a time.",options:[{value:"2",label:"Heading 2"},{value:"3",label:"Heading 3"},{value:"4",label:"Heading 4"},{value:"5",label:"Heading 5"},{value:"6",label:"Heading 6"}]},content:{key:"content",label:"HTML",control:"textarea",hint:"Shown as written. Scripts are stripped when the form is saved."},consenttext:{key:"consentText",label:"What they are agreeing to",control:"textarea",hint:"Shown beside the tick box. Links are allowed."},height:{key:"height",label:"Height",control:"number",hint:"In pixels."},columns:{key:"columns",label:"Columns",control:"number",hint:"How many pictures sit side by side."},multiple:{key:"multiple",label:"Let them choose more than one",control:"checkbox"},inline:{key:"inline",label:"Lay the options out in a row",control:"checkbox"},other:{key:"other",label:"Offer an “Other” box",control:"checkbox",hint:"Adds a final option with a box to type in."},filetypes:{key:"filetypes",label:"Accepted file types",control:"commas",hint:"Extensions, separated by commas. Empty accepts anything the site allows."},maxsize:{key:"maxsize",label:"Largest file",control:"number",hint:"In megabytes."},maxfiles:{key:"maxfiles",label:"How many files",control:"number"},minrows:{key:"minRows",label:"Fewest rows",control:"number",also:{key:"maxRows",label:"Most rows"}},itemlabel:{key:"itemLabel",label:"What is one row called?",control:"text",hint:"Names each card — “Attendee 1”, “Attendee 2” — and the Remove button. Also editable on the card itself."},endlabels:{key:"minLabel",label:"Label at the low end",control:"text",also:{key:"maxLabel",label:"Label at the high end"}},points:{key:"points",label:"Points if correct",control:"number"},minchoices:{key:"minChoices",label:"Fewest they may pick",control:"number",also:{key:"maxChoices",label:"Most they may pick"}}},Fn={label:"the canvas edits it in place, and the inspector mirrors it",placeholder:"edited by typing into the control on the canvas",hint:"edited under the control on the canvas",nextlabel:"edited on the page break’s own Next button",prevlabel:"edited on the page break’s own Back button",addlabel:"edited on the repeater’s own Add button",choices:"the choices editor, and the option list on the canvas",required:"the toggle on the card",width:"its own row",css:"its own row",prefill:"its own section",logic:"the conditional logic section",formula:"its own row, with the currency that goes with it",currency:"rendered with the formula",correct:"the choices editor marks the right answer",default:"its own row, typed to match what the field stores",rows:"a row count on a textarea; the statement list on a Likert matrix",parts:"a tick box per part, listed by the server",min:"the validation section, paired with max",max:"the validation section, paired with min",step:"the validation section",minlength:"the validation section, paired with maxlength",maxlength:"the validation section, paired with minlength",mindate:"the validation section, paired with maxdate",maxdate:"the validation section, paired with mindate",mintime:"the validation section, paired with maxtime",maxtime:"the validation section, paired with mintime",pattern:"the validation section",unique:"the validation section",maxchoices:"rendered with minchoices",maxrows:"rendered with minrows"};function Bt(n,e,t){const s=n[e.key],a=i=>t(e.key,i);if(e.control==="checkbox")return O(e.label,!!s,a);if(e.control==="commas"){const i=Array.isArray(s)?s:[];return g(e.label,A(i.join(", "),o=>{a(o.split(",").map(l=>l.trim().replace(/^\./,"").toLowerCase()).filter(Boolean))}),e.hint)}return e.control==="select"?g(e.label,D(String(s??""),e.options??[],a),e.hint):e.control==="textarea"?g(e.label,ue(String(s??""),a),e.hint):e.control==="number"?g(e.label,G(String(s??""),a),e.hint):g(e.label,J(A(String(s??""),a),e.key),e.hint)}function Ht(n,e){const t=new Set(n.map(a=>a.key).filter(Boolean));let s=n.length+1;return e.split(` -`).map(a=>a.trim()).filter(Boolean).map((a,i)=>{const o=n[i]?.key;if(o)return{key:o,label:a};for(;t.has(`r${s}`);)s+=1;return t.add(`r${s}`),{key:`r${s}`,label:a}})}function jt(n,e,t){const s=n.findIndex(i=>i.id===e);if(s<0)return null;const a=Math.max(0,Math.min(t,n.length-1));return a===s?null:{from:s,to:a}}const Ke=[{value:"user:email",label:"Their email address",group:"About the person filling it in",tag:"{user:email}"},{value:"user:display_name",label:"Their name",group:"About the person filling it in",tag:"{user:display_name}"},{value:"user:first_name",label:"Their first name",group:"About the person filling it in"},{value:"user:last_name",label:"Their last name",group:"About the person filling it in"},{value:"user:login",label:"Their username",group:"About the person filling it in"},{value:"date:today",label:"Today’s date",group:"The date and time",tag:"{date}"},{value:"date:now",label:"The time right now",group:"The date and time",tag:"{time}"},{value:"site",label:"This site’s name",group:"About this site",tag:"{site}"},{value:"site:url",label:"This site’s address",group:"About this site",tag:"{site:url}"},{value:"site:admin_email",label:"The site administrator’s email",group:"About this site",tag:"{admin_email}"}],In=["About the person filling it in","The date and time","About this site"],Xe=(n,e)=>W?.i18n?.[n]??e;class Wt{constructor(e){this.config=null,this.themes=[],this.forms=[],this.form=null,this.schema=null,this.selected=null,this.tab="build",this.logicMap=null,this.canvasTheme=r("style"),this.canvasThemeSignature="",this.openSections=new Map,this.logicMapOn=as(Pt)!=="off",this.dirty=!1,this.editGeneration=0,this.saveInFlight=!1,this.queuedSave=null,this.teardowns=[],this.canvasTarget=null,this.history=[],this.historyAt=-1,this.autosave=Ae(()=>{this.save(!0)},2500),this.renderInspector=ns(()=>{if(P(this.inspector),!this.schema||(this.root.classList.toggle("atfb--build-only-panes",this.tab!=="build"),this.tab!=="build"))return;const t=this.selected?this.locateField(this.selected):void 0,s=t?.field,a=t?.parent??null;if(this.root.classList.toggle("atfb--has-selection",!!s),!s){this.inspector.append(r("div",{class:"atfb-placeholder",children:[r("p",{text:"Select a field to change it."}),r("p",{class:"atfb-hint",text:"Drag a field from the palette, or press one to add it to the end."})]}));return}const i=this.config?.fieldTypes.find(c=>c.type===s.type),o=i?.supports??[],l=(c,d)=>{const h=this.liveField(s.id);h&&(h[c]=d,this.markDirty(),this.renderCanvas())};this.inspector.append(r("h3",{class:"atfb-inspector__title",text:i?.label??s.type})),a?this.inspector.append(r("p",{class:"atfb-hint atfb-inspector__crumb",text:`Inside ${a.label||"a repeater"} — the visitor answers this once per ${String(a.itemLabel??"")||"row"}.`}),r("p",{class:"atfb-hint",text:`Formulas aggregate it as {${a.id}.${s.id}} — e.g. sum( {${a.id}.${s.id}} ).`})):this.inspector.append(r("p",{class:"atfb-hint",text:`Reference this field as {field:${s.id}}`})),o.includes("label")&&this.inspector.append(g("Label",J(A(s.label,c=>l("label",c)),"label"))),o.includes("placeholder")&&this.inspector.append(g("Placeholder",J(A(s.placeholder,c=>l("placeholder",c)),"placeholder"))),o.includes("hint")&&this.inspector.append(g("Hint",J(A(s.hint,c=>l("hint",c)),"hint"),"Shown under the field, and read out with it.")),o.includes("nextlabel")&&this.inspector.append(g("Next button",J(A(String(s.nextLabel??""),c=>l("nextLabel",c)),"nextLabel"),"Leave empty for “Next”.")),o.includes("prevlabel")&&this.inspector.append(g("Back button",J(A(String(s.prevLabel??""),c=>l("prevLabel",c)),"prevLabel"),"Leave empty for “Back”.")),o.includes("addlabel")&&this.inspector.append(g("Add button",J(A(String(s.addLabel??""),c=>l("addLabel",c)),"addLabel"),"Leave empty for “Add another”.")),o.includes("required")&&this.inspector.append(O("Required",s.required,c=>l("required",c))),o.includes("width")&&this.inspector.append(g("Width",D(s.width,[{value:"full",label:"Full width"},{value:"two-thirds",label:"Two thirds"},{value:"half",label:"Half"},{value:"third",label:"One third"},{value:"quarter",label:"One quarter"}],c=>l("width",c)))),i?.choices&&this.inspector.append(this.renderChoicesEditor(s,l)),this.renderTypeSettings(s,i,o,l),(s.type==="total"||o.includes("formula"))&&this.inspector.append(g("Formula",r("div",{class:"atfb-formula__row",children:[A(String(s.formula??""),c=>l("formula",c)),E("Formula editor",()=>mn({root:this.root,fields:this.schema?.fields??[],field:s,onSave:c=>{l("formula",c),this.renderInspector()}}))]}),"Reference answers with braces — {f1} * {f2} + 10 — or open the editor and click them in."),g("Currency symbol",A(String(s.currency??""),c=>l("currency",c)))),this.inspector.append(this.renderValidationSection(s,o,l)),a||(this.inspector.append(this.renderLogicSection(s)),o.includes("prefill")&&this.inspector.append(this.prefillControl(s,l))),o.includes("css")&&this.inspector.append(g("CSS class",A(s.cssClass,c=>l("cssClass",c))))}),this.root=e,this.bar=e.querySelector("[data-atfb-bar]")??r("div"),this.palette=e.querySelector("[data-atfb-palette]")??r("div"),this.canvas=e.querySelector("[data-atfb-canvas]")??r("div"),this.inspector=e.querySelector("[data-atfb-inspector]")??r("div"),this.canvas.addEventListener("click",t=>{const s=t.target;if(!(this.tab!=="build"||!this.selected||s.closest("[data-atfb-card], button, os-button, a, input, textarea, select, os-select, label, [contenteditable]"))){this.selected=null;for(const a of this.canvas.querySelectorAll(".atfb-card.is-selected"))a.classList.remove("is-selected");this.renderInspector()}})}async start(){try{const[s,a,i]=await Promise.all([I.config(),I.listThemes(),I.listForms()]);this.config=s,this.themes=a,this.forms=i}catch(s){this.fail(s);return}this.teardowns.push(Jt([se])),this.teardowns.push(An({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)}));const e=s=>{this.dirty&&(s.preventDefault(),s.returnValue="")};window.addEventListener("beforeunload",e),this.teardowns.push(()=>window.removeEventListener("beforeunload",e));const t=s=>{!(s.metaKey||s.ctrlKey)||s.key.toLowerCase()!=="z"||s.target?.closest("input, textarea, [contenteditable]")||(s.preventDefault(),this.travel(s.shiftKey?1:-1))};if(this.root.addEventListener("keydown",t),this.teardowns.push(()=>this.root.removeEventListener("keydown",t)),this.renderBar(),this.renderPalette(),this.forms.length){const s=fs("builder");await this.open(s&&this.forms.some(a=>a.id===s)?s:this.forms[0].id)}else this.renderFormsList()}destroy(){this.canvasTarget?.(),this.canvasTarget=null,this.teardowns.forEach(e=>e()),this.teardowns=[]}fail(e){P(this.bar),this.bar.append(r("p",{class:"atfb-error",text:e instanceof Error?e.message:"Something went wrong loading your forms."}))}renderBar(){P(this.bar);const e=D(String(this.form?.id??""),[...this.forms.map(a=>({value:String(a.id),label:a.title||"(untitled)"}))],a=>void this.open(Number(a)));e.setAttribute("aria-label","Choose a form");const t=r("input",{class:"atfb-title",type:"text",value:this.form?.title??"",placeholder:"Untitled form",attrs:{"aria-label":"Form title"},on:{input:a=>{this.form&&(this.form.title=a.target.value,this.markDirty())}}}),s=r("div",{class:"atfb-tabs",attrs:{role:"tablist"},children:[["build","Build"],["theme","Theme"],["settings","Settings"],["notify","Notifications"],["confirm","Confirmations"]].map(([a,i])=>r("button",{class:`atfb-tab${this.tab===a?" is-active":""}`,type:"button",text:i,attrs:{role:"tab","aria-selected":this.tab===a},on:{click:()=>{this.tab=a,this.renderBar(),this.renderInspector(),this.renderCanvas()}}}))});this.bar.append(r("div",{class:"atfb-bar__left",children:[this.forms.length>1?e:null,t]}),s,r("div",{class:"atfb-bar__right",children:[this.historyButton("undo","Undo",-1),this.historyButton("redo","Redo",1),E("New",()=>void this.showTemplates(),"secondary","plus-alt2"),E("Export",()=>void this.exportForm(),"secondary","download"),E("Import",()=>void this.importForm(),"secondary","upload"),E("Preview",()=>void this.preview(),"secondary","visibility"),E("Entries",()=>this.openEntries(),"secondary","list-view"),this.logicMapButton(),this.saveButton()]}))}liveField(e){return this.locateField(e)?.field}locateField(e){const t=this.schema?.fields??[];for(let s=0;sthis.rebindCanvas(),{once:!0});return}this.renderCanvas()}snapshot(){if(!this.schema)return;const e=JSON.stringify(this.schema);this.history[this.historyAt]!==e&&(this.history=this.history.slice(0,this.historyAt+1),this.history.push(e),this.history.length>60&&this.history.shift(),this.historyAt=this.history.length-1,this.syncHistoryButtons())}travel(e){const t=this.historyAt+e;!this.schema||t<0||t>=this.history.length||(this.historyAt=t,this.schema=JSON.parse(this.history[t]),this.schema.fields.some(s=>s.id===this.selected)||(this.selected=null),this.markDirty(),this.renderBar(),this.renderCanvas(),this.renderInspector())}historyButton(e,t,s){const a=E(t,()=>this.travel(s),"secondary",e);return a.setAttribute("data-atfb-history",String(s)),a.disabled=!this.canTravel(s),a}canTravel(e){const t=this.historyAt+e;return t>=0&&tURL.revokeObjectURL(s),1e3)}async importForm(){const e=r("input",{type:"file",attrs:{accept:"application/json,.json"}});e.addEventListener("change",async()=>{const t=e.files?.[0];if(t)try{const s=JSON.parse(await t.text());if(!s.schema)throw new Error("That file does not contain a form.");const a=await I.createForm({title:s.title??t.name.replace(/\.json$/i,""),schema:s.schema});this.forms.unshift({id:a.id,title:a.title,status:a.status,modified:a.modified,fields:a.schema.fields.length,theme:a.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:a.shortcode}),this.form=a,this.schema=a.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),R("Form imported",a.title)}catch(s){R("Could not import that file",s instanceof Error?s.message:"","error")}}),e.click()}saveButton(){const e=E("Save",()=>void this.save(),"primary");return e.disabled=!this.dirty,e.setAttribute("data-atfb-save",""),e}markDirty(){this.dirty=!0,this.editGeneration+=1;const e=this.bar.querySelector("[data-atfb-save]");e&&(e.disabled=!1),this.autosave()}async save(e=!1){if(!this.form||!this.schema)return;if(this.saveInFlight){this.queuedSave={silent:e&&(this.queuedSave?.silent??!0)};return}this.saveInFlight=!0;const t=this.editGeneration;try{const s=await I.updateForm(this.form.id,{title:this.form.title,schema:this.schema});if(t===this.editGeneration){this.form=s,this.schema=s.schema,this.dirty=!1,this.rebindCanvas();const i=this.bar.querySelector("[data-atfb-save]");i&&(i.disabled=!0)}Ts(s.id);const a=this.forms.find(i=>i.id===s.id);a&&(a.title=s.title),Tn(s.id,s.title,s.previewUrl),e||R("Form saved",s.title)}catch(s){R(Xe("saveFailed","Could not save"),s instanceof Error?s.message:"","error")}finally{this.saveInFlight=!1;const s=this.queuedSave;this.queuedSave=null,s&&this.save(s.silent)}}async openFormById(e){await this.open(e)}async open(e){if(!(this.dirty&&!await fe("You have unsaved changes. Discard them?"))){try{this.form=await I.getForm(e),this.schema=this.form.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot()}catch(t){this.fail(t);return}this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}}announceIdentity(){this.form&&$t(this.root,wn(this.form,W?.adminUrl??""))}async showTemplates(){if(!this.config)return;const e=r("div",{class:"atfb-overlay"}),t=i=>{i.key==="Escape"&&s()},s=()=>{e.remove(),document.removeEventListener("keydown",t)},a=r("div",{class:"atfb-templates",children:this.config.templates.map(i=>r("button",{class:"atfb-template",type:"button",on:{click:async()=>{s();try{const o=await I.createForm({template:i.slug});this.forms.unshift({id:o.id,title:o.title,status:o.status,modified:o.modified,fields:o.schema.fields.length,theme:o.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:o.shortcode}),this.form=o,this.schema=o.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}catch(o){R("Could not create the form",o instanceof Error?o.message:"","error")}}},children:[z(i.icon),r("strong",{text:i.label}),r("span",{text:i.description})]}))});e.append(r("div",{class:"atfb-modal",attrs:{role:"dialog","aria-label":"Start a new form"},children:[r("h2",{text:"Start a new form"}),a,this.archivedFormsSection(s),r("div",{class:"atfb-modal__actions",children:[E("Cancel",s)]})]})),e.addEventListener("click",i=>{i.target===e&&s()}),document.addEventListener("keydown",t),this.root.append(e),a.querySelector("button")?.focus()}archivedFormsSection(e){const t=r("div",{class:"atfb-archived"});return I.listArchivedForms().then(s=>{s.length&&t.append(r("h3",{class:"atfb-archived__title",text:"Or bring one back from the archive"}),...s.map(a=>r("div",{class:"atfb-archived__row",children:[r("div",{class:"atfb-archived__meta",children:[r("strong",{text:a.title||"(untitled)"}),r("span",{class:"atfb-hint",text:`${a.entries} ${a.entries===1?"entry":"entries"} · ${a.submissions} submissions · ${a.views} views`})]}),E("Restore",async()=>{try{const i=await I.unarchiveForm(a.id);e(),this.forms.unshift(i),R("Form restored",`${i.title||"(untitled)"} is back, with its entries and stats.`),await this.open(i.id)}catch(i){R("Could not restore the form",i instanceof Error?i.message:"","error")}},"secondary","undo")]})))}).catch(()=>{}),t}renderFormsList(){P(this.canvas),this.canvas.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms yet"}),r("p",{text:"Start from a template, or build one from nothing."}),E("New form",()=>void this.showTemplates(),"primary","plus-alt2")]}))}openEntries(){const e=window.wp?.os;if(e?.openWindow){e.openWindow("allterrain-forms-entries");return}window.location.assign(`${W?.adminUrl??""}admin.php?page=allterrain-forms-entries`)}renderPalette(){if(!this.config)return;P(this.palette);const e=new Map;for(const s of this.config.fieldTypes){const a=e.get(s.group)??[];a.push(s),e.set(s.group,a)}const t=r("input",{class:"atfb-input atfb-palette__search",type:"search",placeholder:"Search fields",attrs:{"aria-label":"Search field types"},on:{input:s=>{const a=s.target.value.toLowerCase().trim();this.palette.querySelectorAll(".atfb-chip").forEach(i=>{const o=(i.textContent??"").toLowerCase();i.hidden=a!==""&&!o.includes(a)}),this.palette.querySelectorAll(".atfb-group").forEach(i=>{const o=Array.from(i.querySelectorAll(".atfb-chip")).some(l=>!l.hidden);i.hidden=!o})}}});this.palette.append(t);for(const[s,a]of Object.entries(this.config.groups)){const i=e.get(s);i?.length&&this.palette.append(r("div",{class:"atfb-group",children:[r("h3",{class:"atfb-group__title",text:a}),r("div",{class:"atfb-group__items",children:i.map(o=>this.paletteChip(o))})]}))}}paletteChip(e){const t=r("button",{class:"atfb-chip",type:"button",title:e.description,attrs:{"data-atf-type":e.type},children:[z(e.icon),r("span",{text:e.label})]});return t.addEventListener("pointerdown",s=>{const a=r("div",{class:"atfb-chip atfb-chip--ghost",children:[z(e.icon),r("span",{text:e.label})]});K().start({payload:Ee(se,t,{fieldType:e.type,isNew:!0},s,a),origin:s,onClickOnly:()=>this.addField(e.type)})}),t.addEventListener("click",s=>{K().recentlyEndedDrag()&&s.preventDefault()}),t}renderCanvas(){if(P(this.canvas),!this.schema||!this.form){this.renderFormsList();return}if(this.tab!=="build"){this.canvas.append(this.renderTabCanvas());return}const e=r("div",{class:"atfb-canvas__list",attrs:{"data-atfb-list":""}});this.schema.fields.length||e.append(r("div",{class:"atfb-placeholder",text:Xe("emptyCanvas","Drag a field from the left to begin.")})),this.schema.fields.forEach((s,a)=>{e.append(this.renderFieldCard(s,a))});const t=r("div",{class:"atfb-canvas__inner",children:[r("p",{class:"atfb-shortcode",text:this.form.shortcode,title:"Paste this anywhere to place the form"}),e]});this.canvas.append(t),this.registerCanvasTarget(e),this.paintLogicMap(t),this.paintCanvasTheme()}prefillControl(e,t){const s=e.prefill.startsWith("query:"),a=Ke.some(y=>y.value===e.prefill),i=s?"query":a&&e.prefill||(e.prefill?"custom":""),o=r("div",{class:"atfb-prefill__detail"}),l=r("p",{class:"atfb-row__hint atfb-prefill__preview"}),c=y=>{if(o.replaceChildren(),l.replaceChildren(),y==="query"){const u=e.prefill.startsWith("query:")?e.prefill.slice(6):"";o.append(A(u,x=>{const v=x.trim();t("prefill",v?`query:${v}`:""),d(`query:${v}`)},"utm_source"),r("p",{class:"atfb-row__hint",text:"The name of the parameter in the link people arrive on."}))}y==="custom"&&o.append(A(e.prefill,u=>{t("prefill",u),d(u)},"myplugin:something"),r("p",{class:"atfb-row__hint",text:"For a source another plugin has added through alltfo_resolve_prefill."})),d(e.prefill)},d=y=>{if(l.replaceChildren(),!y)return;if(y.startsWith("query:")){const x=y.slice(6);x&&(l.textContent=`A visit to …/your-page/?${x}=abc opens the form with “abc” in it.`);return}const u=Ke.find(x=>x.value===y)?.tag;u&&Oe(this.form?.id??0).then(x=>{for(const v of x)for(const f of v.items)if(f.tag===u){const C=y.startsWith("user:");if(!f.sample){l.textContent="Empty unless the visitor is signed in.";return}l.textContent=C?`Opens with “${f.sample}” for you — empty for a visitor who is not signed in.`:`Opens with “${f.sample}”.`;return}})};c(i);const h=r("select",{class:"atfb-input atfb-select",on:{change:y=>{const u=y.target.value;t("prefill",u==="query"||u==="custom"?"":u),c(u)}}});h.append(r("option",{value:"",text:"Nothing — leave it empty",attrs:{selected:i===""}}));for(const y of In){const u=document.createElement("optgroup");u.label=y;for(const x of Ke.filter(v=>v.group===y))u.append(r("option",{value:x.value,text:x.label,attrs:{selected:x.value===i}}));h.append(u)}const w=document.createElement("optgroup");return w.label="From the link they arrived on",w.append(r("option",{value:"query",text:"A parameter in the web address",attrs:{selected:i==="query"}})),h.append(w,r("option",{value:"custom",text:"Something else (advanced)",attrs:{selected:i==="custom"}})),g("Pre-fill this with",r("div",{class:"atfb-prefill",children:[h,o,l]}),"What the box already contains when the form opens. They can still change it.")}renderCondition(e,t){const s=t.some(i=>i.kind==="field"&&i.missing),a=r("span",{class:`atfb-cond${s?" is-broken":""}`,attrs:{"aria-label":rt(t)},children:[z("randomize"),...t.map(i=>this.renderConditionToken(e,i))]});return a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("click",i=>i.stopPropagation()),a.addEventListener("keydown",i=>i.stopPropagation()),a}editCondition(e,t,s=!0,a=""){const i=this.liveField(e)?.logic;if(i){if(t(i),this.markDirty(),!s){this.logicMap?.setEdges(me(this.schema?.fields??[]));return}this.renderCanvas(),this.renderInspector(),a&&window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-cond="${CSS.escape(a)}"]`)?.focus()})}}condSelect(e,t,s,a,i){if(Y("os-select")&&Y("os-option")){const o=document.createElement("os-select");o.setAttribute("value",e),o.setAttribute("aria-label",a),o.setAttribute("data-cond",s),o.className="atfb-cond__control",o.title=a;for(const l of t){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,o.append(c)}return o.addEventListener("os-pick",l=>{i(String(l.detail?.value??""))}),o}return r("select",{class:"atfb-cond__control atfb-cond__control--native",title:a,attrs:{"aria-label":a,"data-cond":s},on:{change:o=>i(o.target.value)},children:t.map(o=>r("option",{value:o.value,text:o.label,attrs:{selected:o.value===e}}))})}renderConditionToken(e,t){if(t.kind==="field"&&!t.missing)return r("button",{class:"atfb-cond__chip atfb-cond__chip--field",type:"button",text:t.text,title:"Go to this question",on:{click:a=>{a.stopPropagation(),this.selectField(t.fieldId),this.canvas.querySelector(`[data-atfb-card="${CSS.escape(t.fieldId)}"]`)?.scrollIntoView({block:"nearest",behavior:"smooth"})}}});if(t.kind==="verb")return r("button",{class:"atfb-cond__verb",type:"button",text:t.text,title:"Switch between showing and hiding this field when the condition matches.",attrs:{"data-cond":`${e.id}:verb`},on:{click:()=>this.editCondition(e.id,s=>{s.action=s.action==="hide"?"show":"hide"},!0,`${e.id}:verb`)}});if(t.kind==="join")return r("button",{class:"atfb-cond__join",type:"button",text:t.text,title:"Switch between needing every rule (and) or any one of them (or).",attrs:{"data-cond":`${e.id}:join`},on:{click:()=>this.editCondition(e.id,s=>{s.match=s.match==="all"?"any":"all"},!0,`${e.id}:join`)}});if(t.kind==="operator"){const s=`${e.id}:op:${t.ruleIndex}`;return this.condSelect(t.operator,Object.entries(Me).map(([a,i])=>({value:a,label:i})),s,"How the answer is compared",a=>this.editCondition(e.id,i=>{const o=i.rules[t.ruleIndex];o&&(o.operator=a)},!0,s))}return t.kind==="value"?this.renderConditionValue(e,t):r("span",{class:"atfb-cond__chip atfb-cond__chip--missing",text:t.text})}renderConditionValue(e,t){const s=`${e.id}:value:${t.ruleIndex}`,a=this.schema?.fields.find(c=>c.id===t.sourceId),i=(c,d)=>this.editCondition(e.id,h=>{const w=h.rules[t.ruleIndex];w&&(w.value=c)},d,s);if(a?.choices?.length){const c=a.choices.map(d=>({value:d.value,label:d.label||d.value}));return t.raw!==""&&!a.choices.some(d=>d.value===t.raw)&&c.unshift({value:t.raw,label:t.text}),this.condSelect(t.raw,c,s,"The answer that triggers this",d=>i(d,!0))}const o=["number","range","scale","rating","total"].includes(a?.type??""),l=r("input",{class:"atfb-cond__chip atfb-cond__chip--value atfb-cond__value",value:t.raw,title:"The answer that triggers this. Edit it here.",attrs:{type:"text","aria-label":"The answer that triggers this","data-cond":s,inputmode:o?"decimal":void 0,size:String(Math.max(2,Math.min(24,t.raw.length||2)))}});return l.addEventListener("input",()=>{l.size=Math.max(2,Math.min(24,l.value.length||2)),i(l.value,!1)}),l.addEventListener("change",()=>i(l.value,!0)),l.addEventListener("keydown",c=>{c.key==="Enter"&&(c.preventDefault(),i(l.value,!0))}),l}section(e,t,s,a=!1){const i=r("details",{class:"atfb-section",attrs:{open:this.openSections.get(e)??a},children:[r("summary",{text:t}),...s]});return i.addEventListener("toggle",()=>this.openSections.set(e,i.open)),i}logicMapButton(){const e=me(this.schema?.fields??[]).length>0,t=E(this.logicMapOn?"Hide logic":"Show logic",()=>{this.logicMapOn=!this.logicMapOn,is(Pt,this.logicMapOn?"on":"off"),this.renderBar(),this.renderCanvas()},this.logicMapOn?"primary":"secondary","randomize");return t.title="Draw a line from each question to the ones it decides.",t.hidden=!e,t}paintLogicMap(e){this.logicMap?.destroy(),this.logicMap=null;const t=this.schema?.fields??[],s=me(t);if(!s.length||!this.logicMapOn)return;e.classList.add("has-logicmap");const a=new ys(e);a.setEdges(s),a.highlight(this.selected??""),this.logicMap=a,e.addEventListener("pointerover",i=>{const o=i.target.closest("[data-atfb-card]");a.highlight(o?.dataset.atfbCard??this.selected??"")}),e.addEventListener("pointerleave",()=>a.highlight(this.selected??""))}renderFieldCard(e,t){const s=this.config?.fieldTypes.find(d=>d.type===e.type),a=this.selected===e.id,i=this.schema?.fields??[],o=bs(e,i),l=vs(i).get(e.id)??0,c=r("div",{class:`atfb-card${a?" is-selected":""}`,attrs:{"data-atfb-card":e.id,"data-index":t,tabindex:"0",role:"button","aria-pressed":a,"aria-label":`${e.label||s?.label||e.type}, ${t+1} of ${this.schema?.fields.length??0}`},children:[r("div",{class:"atfb-card__bar",children:[r("div",{class:"atfb-card__grip",attrs:{"aria-hidden":"true"},children:[z("menu")]}),r("div",{class:"atfb-card__head",children:[z(s?.icon??"dashicons-forms"),r("span",{class:"atfb-card__type",text:s?.label??e.type}),this.requiredToggle(e),l?r("span",{class:"atfb-badge atfb-badge--controls",text:l===1?"controls 1 field":`controls ${l} fields`,title:"Other questions appear or disappear based on this answer."}):null]}),r("div",{class:"atfb-card__actions",children:[this.cardAction("admin-page","Duplicate",()=>this.duplicateField(e.id)),this.cardAction("trash","Delete",()=>void this.deleteField(e.id))]})]}),r("div",{class:"atfb-card__body",children:[dt(e,s,{edit:d=>{const h=this.liveField(e.id);if(!h)return;d(h),this.markDirty(),this.syncInspector(h);const w=this.selected?this.locateField(this.selected):void 0;w?.parent&&w.parent.id===h.id&&this.syncInspector(w.field)},restructure:d=>{const h=this.liveField(e.id);h&&(this.snapshot(),d(h),this.markDirty(),this.renderCanvas(),this.renderInspector())},types:d=>this.config?.fieldTypes.find(h=>h.type===d),selectedId:this.selected}),o.length?this.renderCondition(e,o):null]})]});return c.addEventListener("click",d=>{d.target.closest(".atfb-card__actions")||K().recentlyEndedDrag()||this.selectField(e.id)}),c.addEventListener("keydown",d=>{if(d.key==="Enter"||d.key===" "){d.preventDefault(),this.selectField(e.id);return}d.altKey&&(d.key==="ArrowUp"||d.key==="ArrowDown")&&(d.preventDefault(),this.moveField(e.id,d.key==="ArrowUp"?t-1:t+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})),(d.key==="Delete"||d.key==="Backspace")&&(d.preventDefault(),this.deleteField(e.id))}),c.addEventListener("pointerdown",d=>{d.target.closest(".atfb-card__actions")||K().start({payload:Ee(se,c,{fieldId:e.id,field:e,isNew:!1},d),origin:d})}),c}requiredToggle(e){return r("button",{class:`atfb-req${e.required?" is-on":""}`,type:"button",text:e.required?"Required":"Optional",title:e.required?"This must be answered. Click to make it optional.":"Click to make this required.",attrs:{"aria-pressed":e.required?"true":"false"},on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.required=!e.required,this.markDirty(),this.renderCanvas(),this.renderInspector()}}})}cardAction(e,t,s){return r("button",{class:"atfb-card__action",type:"button",title:t,attrs:{"aria-label":t},on:{click:a=>{a.stopPropagation(),s()}},children:[z(e)]})}registerCanvasTarget(e){this.canvasTarget?.(),this.canvasTarget=null;const t=r("div",{class:"atfb-marker",attrs:{"aria-hidden":"true"}}),s=K().registerDropTarget({id:`atfb-canvas-${this.form?.id??0}`,element:e,accept:o=>o.type===se,onEnter:()=>e.classList.add("is-dropping"),onLeave:()=>{e.classList.remove("is-dropping"),t.remove()},onDrop:(o,l)=>{e.classList.remove("is-dropping"),t.remove();const c=o.payload.data,d=c.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(c.fieldId)}"]`):null,h=Ce(e,".atfb-card",l.clientY,d??void 0);if(c.isNew&&c.fieldType){this.addField(c.fieldType,h);return}if(c.fieldId&&this.locateField(c.fieldId)){this.relocateField(c.fieldId,null,h);return}c.field&&this.insertField({...c.field,id:""},h)}}),a=this.wireRepeaterZones(e),i=o=>{const l=o.detail;if(l?.payload?.type!==se||!e.classList.contains("is-dropping"))return;const c=l.payload.data?.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(l.payload.data.fieldId)}"]`):null,d=l.clientY??0,h=Ce(e,".atfb-card",d,c??void 0),w=Array.from(e.querySelectorAll(".atfb-card")).filter(y=>y!==c);h>=w.length?e.append(t):w[h].before(t)};document.addEventListener("os.drag.move",i),this.canvasTarget=()=>{s(),a.forEach(o=>o()),document.removeEventListener("os.drag.move",i)}}wireRepeaterZones(e){const t=[];return e.querySelectorAll("[data-atfb-repeater-zone]").forEach(s=>{const a=s.dataset.atfbRepeaterZone??"";t.push(K().registerDropTarget({id:`atfb-repzone-${this.form?.id??0}-${a}`,element:s,accept:i=>{if(i.type!==se)return!1;const o=i.data;if(o.fieldId===a)return!1;const l=o.isNew?o.fieldType:this.locateField(o.fieldId??"")?.field.type??o.field?.type;return!!l&&this.allowedInRepeater(l)},onEnter:()=>s.classList.add("is-dropping"),onLeave:()=>s.classList.remove("is-dropping"),onDrop:(i,o)=>{s.classList.remove("is-dropping");const l=i.payload.data,c=l.fieldId?e.querySelector(`[data-atfb-subfield="${CSS.escape(l.fieldId)}"]`):null,d=Ce(s,".atfb-subcard",o.clientY,c??void 0);if(l.isNew&&l.fieldType){this.addFieldToRepeater(l.fieldType,a,d);return}if(l.fieldId&&this.locateField(l.fieldId)){this.relocateField(l.fieldId,a,d);return}l.field&&this.insertFieldIntoRepeater({...l.field,id:""},a,d)}})),s.querySelectorAll(".atfb-subcard").forEach(i=>{const o=i.dataset.atfbSubfield??"";i.addEventListener("click",l=>{l.target.closest(".atfb-preview__remove")||(l.stopPropagation(),!K().recentlyEndedDrag()&&this.selectField(o))}),i.addEventListener("keydown",l=>{if(l.stopPropagation(),l.key==="Enter"||l.key===" "){l.preventDefault(),this.selectField(o);return}if(l.altKey&&(l.key==="ArrowUp"||l.key==="ArrowDown")){l.preventDefault();const c=this.locateField(o);c&&(this.relocateField(o,a,l.key==="ArrowUp"?c.index-1:c.index+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(o)}"]`)?.focus()}));return}(l.key==="Delete"||l.key==="Backspace")&&(l.preventDefault(),this.deleteField(o))}),i.addEventListener("pointerdown",l=>{if(l.stopPropagation(),l.target.closest(".atfb-preview__remove"))return;const c=this.locateField(o);c&&K().start({payload:Ee(se,i,{fieldId:o,parentId:a,field:c.field,isNew:!1},l),origin:l})})})}),t}addField(e,t){const s=this.buildField(e);s&&this.insertField(s,t)}buildField(e){const t=this.config?.fieldTypes.find(a=>a.type===e);return!t||!this.schema?void 0:{id:this.nextFieldId(),type:e,label:t.input?t.label:"",placeholder:"",hint:"",required:!1,width:"full",cssClass:"",default:"",choices:t.choices?[{label:"First choice",value:"first"},{label:"Second choice",value:"second"}]:[],logic:{enabled:!1,action:"show",match:"all",rules:[]},messages:{},prefill:"",...t.settings}}allowedInRepeater(e){const t=this.config?.fieldTypes.find(s=>s.type===e);return!t||!t.input?!1:!["repeater","page_break","file","signature","total"].includes(e)}addFieldToRepeater(e,t,s){if(!this.allowedInRepeater(e))return;const a=this.buildField(e);a&&this.insertFieldIntoRepeater(a,t,s)}insertFieldIntoRepeater(e,t,s){const a=this.liveField(t);if(!this.schema||!a||a.type!=="repeater")return;e.id||(e.id=this.nextFieldId()),this.snapshot(),Array.isArray(a.fields)||(a.fields=[]);const i=a.fields,o=s===void 0?i.length:Math.max(0,Math.min(s,i.length));i.splice(o,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(e.id)}"]`)?.focus()})}relocateField(e,t,s){if(!this.schema)return;const a=this.locateField(e);if(!a)return;if(!a.parent&&!t){this.moveField(e,s);return}const i=t?this.liveField(t):null;if(t&&(!i||i.type!=="repeater"||e===t))return;i&&!Array.isArray(i.fields)&&(i.fields=[]);const o=i?i.fields:this.schema.fields;this.snapshot(),a.list.splice(a.index,1);const l=Math.max(0,Math.min(s,o.length));o.splice(l,0,a.field),this.selected=a.field.id,this.markDirty(),this.renderCanvas(),this.renderInspector()}insertField(e,t){if(!this.schema)return;e.id||(e.id=this.nextFieldId()),this.snapshot();const s=t===void 0?this.schema.fields.length:Math.max(0,Math.min(t,this.schema.fields.length));this.schema.fields.splice(s,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})}moveField(e,t){if(!this.schema)return;const s=jt(this.schema.fields,e,t);if(!s)return;this.snapshot();const[a]=this.schema.fields.splice(s.from,1);this.schema.fields.splice(s.to,0,a),this.markDirty(),this.renderCanvas()}duplicateField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=JSON.parse(JSON.stringify(t.field)),a=this.usedFieldIds(),i=()=>{let o=a.size+1;for(;a.has(`f${o}`);)o++;const l=`f${o}`;return a.add(l),l};s.id=i();for(const o of s.fields??[])o.id=i();if(t.parent){this.snapshot(),t.list.splice(t.index+1,0,s),this.selected=s.id,this.markDirty(),this.renderCanvas(),this.renderInspector();return}this.insertField(s,t.index+1)}async deleteField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=this.schema.fields.filter(i=>i.logic?.rules?.some(o=>o.field===e)),a=s.length?`Delete this field? ${s.length} other field${s.length===1?"":"s"} use it in a condition, and those conditions will stop working.`:Xe("confirmDelete","Delete this? It cannot be undone.");await fe(a,"Delete field")&&(this.snapshot(),t.list.splice(t.index,1),this.selected===e&&(this.selected=null),this.markDirty(),this.renderCanvas(),this.renderInspector())}selectField(e){this.selected=e;for(const t of this.canvas.querySelectorAll("[data-atfb-card]")){const s=t.dataset.atfbCard===e;t.classList.toggle("is-selected",s),t.setAttribute("aria-pressed",s?"true":"false")}for(const t of this.canvas.querySelectorAll("[data-atfb-subfield]"))t.classList.toggle("is-selected",t.dataset.atfbSubfield===e);this.logicMap?.highlight(e),this.renderInspector()}nextFieldId(){const e=this.usedFieldIds();let t=e.size+1;for(;e.has(`f${t}`);)t++;return`f${t}`}usedFieldIds(){const e=new Set;for(const t of this.schema?.fields??[]){e.add(t.id);for(const s of t.fields??[])e.add(s.id)}return e}nextEntryId(e,t){const s=new Set(t.map(i=>i.id));let a=t.length+1;for(;s.has(`${e}${a}`);)a++;return`${e}${a}`}renderTypeSettings(e,t,s,a){for(const i of s){const o=Rt[i];o&&(this.inspector.append(Bt(e,o,a)),o.also&&this.inspector.append(Bt(e,{...o,key:o.also.key,label:o.also.label,hint:o.also.hint},a)))}s.includes("rows")&&e.type!=="likert"&&this.inspector.append(g("Lines tall",G(String(e.rows??""),i=>a("rows",i)))),s.includes("rows")&&e.type==="likert"&&this.inspector.append(this.renderStatementList(e,a)),s.includes("parts")&&this.inspector.append(this.renderPartsEditor(e,t,a)),s.includes("default")&&!["files","object"].includes(t?.value??"")&&this.inspector.append(this.renderDefaultControl(e,t,a))}renderStatementList(e,t){const s=Array.isArray(e.rows)?e.rows:[];return g("Statements",ue(s.map(a=>a.label??"").join(` -`),a=>t("rows",Ht(s,a)),5),"One per line. Each becomes a row of the matrix.")}renderPartsEditor(e,t,s){const a=t?.parts??[],i=Array.isArray(e.parts)?e.parts:a.map(l=>l.key),o=a.map(l=>O(l.label,i.includes(l.key),c=>{const d=a.map(h=>h.key).filter(h=>h===l.key?c:i.includes(h));s("parts",d.length?d:[l.key])}));return r("div",{class:"atfb-section",children:[r("h4",{class:"atfb-section__title",text:"Parts to ask for"}),...o]})}renderDefaultControl(e,t,s){const a="Filled in before they start. They can change it.";return e.type==="switch"||e.type==="consent"?O("On by default",!!e.default,i=>s("default",i)):t?.choices&&(e.choices??[]).length?g("Default answer",D(String(e.default??""),[{value:"",label:"Nothing chosen"},...(e.choices??[]).map(i=>({value:String(i.value),label:i.label||String(i.value)}))],i=>s("default",i)),a):g("Default answer",A(String(e.default??""),i=>s("default",i)),a)}renderChoicesEditor(e,t){const s=e.choices??[],a=o=>this.liveField(e.id)?.choices?.[o],i=r("div",{class:"atfb-choices"});return s.forEach((o,l)=>{const c=r("div",{class:"atfb-choice-row",children:[e.type==="image_choice"?this.choiceImageWell(o,l,e):null,J(A(o.label,d=>{const h=a(l);if(!h)return;const w=!h.value||h.value===h.label;h.label=d,w&&(h.value=d),this.markDirty();const y=this.liveField(e.id);y&&this.syncCanvas(y)}),`choice:${l}:label`),J(A(o.value,d=>{const h=a(l);h&&(h.value=d,this.markDirty())},"value"),`choice:${l}:value`),e.type==="quiz"||o.points!==void 0?G(String(o.points??""),d=>{const h=a(l);h&&(h.points=d===""?void 0:Number(d),this.markDirty())}):G(String(o.price??""),d=>{const h=a(l);h&&(h.price=d===""?void 0:Number(d),this.markDirty())}),r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":`Remove ${o.label}`},on:{click:()=>{const d=this.liveField(e.id);d&&((d.choices??[]).splice(l,1),t("choices",d.choices),this.renderInspector())}},children:[z("trash")]})]});i.append(c)}),r("div",{class:"atfb-section",children:[r("h4",{text:"Choices"}),r("p",{class:"atfb-hint",text:e.type==="quiz"?"Label, value, points.":"Label, value, and a price for calculations."}),i,E("Add choice",()=>{const o=this.liveField(e.id);if(!o)return;const l=o.choices??[];l.push({label:"",value:""}),t("choices",l),this.renderInspector()},"ghost","plus-alt2"),e.type==="quiz"?g("Correct answer",D(String(e.correct??""),[{value:"",label:"—"},...s.map(o=>({value:o.value,label:o.label}))],o=>t("correct",o))):null]})}choiceImageWell(e,t,s){const a=r("div",{class:`atfb-well${e.image?" has-image":""}`,attrs:{"data-choice":t,"aria-label":`Image for ${e.label||`choice ${t+1}`}`},children:[e.image?r("span",{class:"atfb-well__id",text:`#${e.image}`}):z("format-image")]}),i=K().registerDropTarget({id:`atfb-well-${s.id}-${t}`,element:a,accept:o=>Mn.includes(o.type),onEnter:()=>a.classList.add("is-dropping"),onLeave:()=>a.classList.remove("is-dropping"),onDrop:o=>{a.classList.remove("is-dropping");const l=o.payload.data,c=Number(l.attachmentId??l.id??l.file?.id??0);if(!c){R("That is not an image this field can use","","error");return}const d=this.liveField(s.id)?.choices?.[t];d&&(d.image=c,this.markDirty(),this.renderInspector())}});return this.teardowns.push(i),a.addEventListener("click",()=>{const o=this.liveField(s.id)?.choices?.[t];o?.image&&(o.image=void 0,this.markDirty(),this.renderInspector())}),a}renderValidationSection(e,t,s){const a=[],i=[];t.includes("minlength")&&i.push(["minlength","Minimum characters"],["maxlength","Maximum characters"]),t.includes("min")?i.push(["min","Minimum"],["max","Maximum"]):t.includes("max")&&i.push(["max","Highest"]),t.includes("step")&&i.push(["step","Steps of"]),t.includes("mindate")&&i.push(["minDate","Earliest date"],["maxDate","Latest date"]),t.includes("mintime")&&i.push(["minTime","Earliest time"],["maxTime","Latest time"]);for(const[l,c]of i)a.push(g(c,A(String(e[l]??""),d=>s(l,d))));t.includes("pattern")&&a.push(...this.renderAnswerShapeRows(e,s)),t.includes("unique")&&a.push(O("No two people may submit the same value",!!e.unique,l=>s("unique",l)));const o=e.messages??{};return t.includes("required")&&a.push(g("Message when required",A(o.required??"",l=>{o.required=l,s("messages",o)}),"Leave empty for the default wording.")),a.length?this.section(`validation:${e.id}`,"Validation",a):r("div",{class:"atfb-section is-empty"})}buildShapePicker(e,t){const s=[{heading:null,options:[{value:"",label:"Anything at all"}]},...Cn.map(i=>({heading:i,options:Dt.filter(o=>o.group===i).map(o=>({value:o.slug,label:o.label}))})),{heading:"Your own",options:[{value:"custom",label:"A custom rule…"}]}];if(Y("os-select")&&Y("os-option")){const i=document.createElement("os-select");i.setAttribute("value",e),i.setAttribute("aria-label","What the answer should look like"),i.classList.add("atfb-field");for(const o of s){if(o.heading){const l=document.createElement("os-option");l.setAttribute("value",`__heading:${o.heading}`),l.setAttribute("disabled",""),l.textContent=o.heading,i.append(l)}for(const l of o.options){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,i.append(c)}}return i.addEventListener("os-pick",o=>{t(String(o.detail?.value??""))}),i}const a=r("select",{class:"atfb-input atfb-select",attrs:{"aria-label":"What the answer should look like"},on:{change:i=>t(i.target.value)}});for(const i of s){const o=i.heading?(()=>{const l=document.createElement("optgroup");return l.label=i.heading,a.append(l),l})():a;for(const l of i.options)o.append(r("option",{value:l.value,text:l.label,attrs:{selected:l.value===e}}))}return a}renderAnswerShapeRows(e,t){const a=(typeof e.validation=="string"?e.validation:"")||(e.pattern?"custom":""),i=()=>Sn({root:this.root,field:this.liveField(e.id)??e,onSave:h=>{t("validation","custom"),t("pattern",h.pattern),t("validationRecipe",JSON.stringify(h.recipe));const w={...this.liveField(e.id)?.messages??{}};w.invalid=h.message,t("messages",w),this.renderInspector()},onCancel:()=>this.renderInspector()}),o=h=>{if(h==="custom"){i();return}t("validation",h),t("pattern",""),t("validationRecipe",""),this.renderInspector()},l=this.buildShapePicker(a,o),c=$n(a),d=[g("The answer should be",l,c?`e.g. ${c.example}`:"Checked as they type, and again on the server.")];if(a==="custom"){const h=Tt(String(e.validationRecipe??"")),w=Mt(h)||(e.pattern?`Matches the expression ${String(e.pattern)}`:"No rule yet — open the builder.");d.push(g("Your rule",r("div",{class:"atfb-valrule",children:[r("p",{class:"atfb-valrule__words",text:w}),E("Edit the rule…",i,"secondary","edit")]}),xe(h)||e.pattern?"Built in the rule builder, with a playground to test it.":void 0))}return d}logicRulesEditor(e,t,s=""){const a=(this.schema?.fields??[]).filter(d=>d.id!==s&&d.type!=="page_break"),i=()=>r("div",{class:"atfb-rule-join",children:[r("button",{class:"atfb-rule-join__chip",type:"button",text:e.match==="all"?"and":"or",title:"Switch between needing every rule (and) or any one of them (or).",on:{click:()=>t(d=>{d.match=d.match==="all"?"any":"all"},!0)}})]}),o=(d,h)=>{const w=r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":"Remove this rule"},title:"Remove this rule",on:{click:()=>t(u=>{u.rules.splice(h,1)},!0)},children:[z("trash")]}),y=[r("div",{class:"atfb-rule__top",children:[D(d.field,a.map(u=>({value:u.id,label:u.label||u.id})),u=>t(x=>{const v=x.rules[h];v&&(v.field=u,v.value="")},!0)),w]}),D(d.operator,Object.entries(this.config?.operators??{}).map(([u,x])=>({value:u,label:x})),u=>t(x=>{const v=x.rules[h];v&&(v.operator=u)},!0))];if(!Fe.includes(d.operator)){const u=this.schema?.fields.find(x=>x.id===d.field);if(u?.choices?.length){const x=u.choices.map(v=>({value:v.value,label:v.label||v.value}));d.value!==""&&!u.choices.some(v=>v.value===d.value)&&x.unshift({value:d.value,label:d.value}),y.push(D(d.value,x,v=>t(f=>{const C=f.rules[h];C&&(C.value=v)})))}else y.push(A(d.value,x=>t(v=>{const f=v.rules[h];f&&(f.value=x)}),"The answer to compare against"))}return r("div",{class:"atfb-rule",children:y})},l=r("div",{class:"atfb-rules"});e.rules.forEach((d,h)=>{h>0&&l.append(i()),l.append(o(d,h))});const c=E("Add rule",()=>{t(d=>{d.rules.push({field:a[0]?.id??"",operator:"is",value:""})},!0)},"ghost","plus-alt2");return[l,c]}conditionsSection(e,t,s){const a=(o,l=!1)=>{o(s),this.markDirty(),l&&this.renderCanvas()},i=t==="confirmation"?"Use":"Send";return this.section(`conditions:${e}`,"Conditions",[O(`Only ${i.toLowerCase()} this ${t} sometimes`,s.enabled,o=>a(l=>{l.enabled=o},!0)),s.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[r("span",{text:`${i} it when`}),D(s.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...this.logicRulesEditor(s,a)]}):null],s.enabled)}renderLogicSection(e){const t=e.logic,s=()=>this.liveField(e.id)?.logic,a=(o,l=!1)=>{const c=s();c&&(o(c),this.markDirty(),this.renderCanvas(),l&&this.renderInspector())},i=this.logicRulesEditor(t,a,e.id);return this.section(`logic:${e.id}`,"Conditional logic",[O("Only show this field sometimes",t.enabled,o=>{a(l=>{l.enabled=o},!0)}),t.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[D(t.action,[{value:"show",label:"Show"},{value:"hide",label:"Hide"}],o=>a(l=>{l.action=o},!0)),r("span",{text:"this field when"}),D(t.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...i]}):null],t.enabled)}renderTabCanvas(){return this.schema?this.tab==="theme"?mt({themes:this.themes,tokens:this.config?.tokens??[],activeSlug:this.schema.settings.theme,overrides:this.schema.settings.themeOverrides,onTheme:e=>{this.schema.settings.theme=e,this.markDirty()},onOverride:(e,t)=>{t===""?delete this.schema.settings.themeOverrides[e]:this.schema.settings.themeOverrides[e]=t,this.markDirty()},onOverridesReplaced:e=>{this.schema.settings.themeOverrides={...e},this.markDirty()},previewFor:(e,t)=>this.previewHtml(e,t),onThemesChanged:e=>{this.themes=e}}):this.tab==="settings"?this.renderSettingsPane():this.tab==="notify"?this.renderNotificationsPane():this.renderConfirmationsPane():r("div")}async paintCanvasTheme(){if(!this.form||!this.schema)return;const e=this.schema.settings.theme,t=JSON.stringify([e,this.schema.settings.themeOverrides]);if(t!==this.canvasThemeSignature){this.canvasThemeSignature=t;try{const s=await this.previewHtml(e,this.schema.settings.themeOverrides??{});this.root.classList.toggle("atfb--dark-form",/atf-is-dark/.test(s));const a=/class="atf-form-wrap"[^>]*\sstyle="([^"]*)"/.exec(s);if(!a)return;const i=a[1].replace(/"/g,'"').replace(/�?39;/g,"'").replace(/&/g,"&");this.canvasTheme.textContent=`.atfb .atfb-preview { +var allTerrainFormsBuilder=function(ee){"use strict";class Zt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(e){if(this.active||e.origin.button!==0)return null;const{payload:t,origin:s}=e,a=s.clientX,i=s.clientY;let o=!1,l=!1,c=null,d=null,h=0,w=0;const _=()=>{document.removeEventListener("pointermove",x),document.removeEventListener("pointerup",I),document.removeEventListener("pointercancel",S),document.removeEventListener("keydown",H),window.removeEventListener("blur",S),c?.remove(),c=null,t.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),d?.onLeave?.(b),d=null,this.active=null,this.lastEndMs=Date.now()},u=(E,f)=>{document.dispatchEvent(new CustomEvent(E,{detail:{payload:t,clientX:f?.clientX,clientY:f?.clientY}}))},b={payload:t,isFinished:()=>l,cancel:(E="caller")=>{l||(l=!0,_(),o&&u("os.drag.end"),e.onCancel?.(E))}},g=E=>{o=!0,t.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const f=t.source.getBoundingClientRect();h=t.ghost?.offsetX??a-f.left,w=t.ghost?.offsetY??i-f.top,c=t.ghost?.element??t.source.cloneNode(!0),c.classList.add("atf-drag-ghost"),c.style.width=`${f.width}px`,document.body.appendChild(c),p(E),u("os.drag.start",E)},p=E=>{c&&(c.style.transform=`translate3d(${E.clientX-h}px, ${E.clientY-w}px, 0)`)},x=E=>{if(l)return;if(!o){if(Math.hypot(E.clientX-a,E.clientY-i)<4)return;g(E)}p(E);const f=this.hitTest(E.clientX,E.clientY);f!==d&&(d?.onLeave?.(b),d=f,d?.onEnter?.(b)),u("os.drag.move",E)},I=E=>{if(l)return;if(!o){l=!0,_(),e.onClickOnly?.();return}const f=d;if(l=!0,_(),f&&f.accept(t)){e.onCommit?.(f),f.onDrop(b,{clientX:E.clientX,clientY:E.clientY}),u("os.drag.end",E);return}u("os.drag.end",E),e.onCancel?.(f?"rejected":"no-target")},S=()=>b.cancel("pointercancel"),H=E=>{E.key==="Escape"&&b.cancel("escape")};return document.addEventListener("pointermove",x),document.addEventListener("pointerup",I),document.addEventListener("pointercancel",S),document.addEventListener("keydown",H),window.addEventListener("blur",S),this.active=b,b}registerDropTarget(e){return this.targets=this.targets.filter(t=>t.id!==e.id),this.targets.push(e),()=>{this.targets=this.targets.filter(t=>t.id!==e.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(e=500){return Date.now()-this.lastEndMso.right||to.bottom)continue;const l=Kt(i.element);if(l>a){s=i,a=l;continue}l===a&&s&&Vt(i.element,s.element)&&(s=i)}return s}}function Kt(n){let e=0,t=n;for(;t;)e++,t=t.parentElement;return e}function Vt(n,e){return(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function Se(){return window.wp?.os??null}let Le=null;function Z(){const n=Se();return n?.dragManager?n.dragManager:(Le||(Le=new Zt),Le)}function Jt(n){const e=i=>{const o=i.detail?.payload;return o&&n.includes(o.type)?o.source:null},t=i=>i.preventDefault(),s=i=>{const o=e(i);o&&(o.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"),window.getSelection()?.removeAllRanges(),document.addEventListener("selectstart",t))},a=i=>{const o=e(i);o&&(o.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),document.removeEventListener("selectstart",t))};return document.addEventListener("os.drag.start",s),document.addEventListener("os.drag.end",a),()=>{document.removeEventListener("os.drag.start",s),document.removeEventListener("os.drag.end",a),document.removeEventListener("selectstart",t)}}const Qt=["atfb","atfe","atfs","atfm"];function Ee(n,e,t,s,a){const i=e.getBoundingClientRect();if(!a){const o=Qt.find(l=>e.closest(`.${l}`));if(o){const l=e.cloneNode(!0);l.style.transition="",l.style.transform="",a=document.createElement("div"),a.className=`${o} atf-ghost-scope`,a.appendChild(l)}}return a&&(a.style.width=`${Math.round(i.width)}px`,a.style.maxWidth=`${Math.round(i.width)}px`,a.style.boxSizing="border-box"),{type:n,source:e,data:t,ghost:{element:a,offsetX:s.clientX-i.left,offsetY:s.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}function Je(n,e,t,s){const a=Array.from(n.querySelectorAll(e)).filter(i=>i!==s&&!i.classList.contains("atf-drag-ghost"));for(let i=0;ia.fetch(l,c,{source:"allterrain-forms"}):(l,c)=>fetch(l,c))(t,{credentials:"same-origin",...e,headers:s});if(!o.ok){let l=`Request failed with status ${o.status}.`,c="";try{const d=await o.json();l=d.message??l,c=d.code??""}catch{}throw new ce(l,o.status,c)}if(o.status!==204)return await o.json()}const U=n=>Ce(n);async function es(n){if(!W?.wpRestUrl)throw new ce("AllTerrain Forms is not configured on this page.",0);const e=W.nonce?{"X-WP-Nonce":W.nonce}:{},t=Se(),s=Qe(W.wpRestUrl,n),a=t?.fetch?await t.fetch(s,{credentials:"same-origin",headers:e},{source:"allterrain-forms"}):await fetch(s,{credentials:"same-origin",headers:e});if(!a.ok)throw new ce(`Request failed with status ${a.status}.`,a.status);return await a.json()}function ts(n){if(!n||!n.includes("&"))return n;const e=document.createElement("textarea");return e.innerHTML=n,e.value}const K=(n,e)=>Ce(n,{method:"POST",body:JSON.stringify(e)}),de=n=>Ce(n,{method:"DELETE"});function et(n){const e=new URLSearchParams;for(const[s,a]of Object.entries(n))a===void 0||a===""||a===!1||e.set(s,String(a));const t=e.toString();return t?`?${t}`:""}function he(n){const e=n?.schema?.settings;return e&&(!e.themeOverrides||Array.isArray(e.themeOverrides))&&(e.themeOverrides={...e.themeOverrides}),n}const F={config:()=>U("/config"),mailpoet:()=>U("/mailpoet"),listForms:()=>U("/forms"),listArchivedForms:()=>U("/forms?archived=1"),archiveForm:n=>K(`/forms/${n}/archive`,{}),unarchiveForm:n=>K(`/forms/${n}/unarchive`,{}),getForm:n=>U(`/forms/${n}`).then(he),createForm:n=>K("/forms",n).then(he),updateForm:(n,e)=>K(`/forms/${n}`,e).then(he),duplicateForm:n=>K(`/forms/${n}/duplicate`,{}).then(he),deleteForm:n=>de(`/forms/${n}`),preview:(n,e)=>K(`/forms/${n}/preview`,e),pages:()=>es("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(n=>n.map(e=>({id:e.id,title:ts(e.title?.rendered??"")||`#${e.id}`}))),mergeTags:n=>U(`/forms/${n}/merge-tags`).then(e=>e.groups),analytics:(n,e="")=>U(`/forms/${n}/analytics${e?`?dimension=${encodeURIComponent(e)}`:""}`),demoStatus:()=>U("/demo"),demoSeed:n=>K("/demo",n?{count:n}:{}),demoRemove:()=>de("/demo"),listEntries:n=>U(`/entries${et(n)}`),getEntry:n=>U(`/entries/${n}`),updateEntry:(n,e)=>K(`/entries/${n}`,e),deleteEntry:n=>de(`/entries/${n}`),exportEntries:n=>U(`/entries/export${et(n)}`),listThemes:()=>U("/themes"),saveTheme:n=>K("/themes",n),deleteTheme:n=>de(`/themes/${n}`)};function r(n,e={}){const t=document.createElement(n);e.class&&(t.className=e.class),e.text!==void 0&&(t.textContent=e.text),e.html!==void 0&&(t.innerHTML=e.html),e.title&&(t.title=e.title),e.type&&"type"in t&&(t.type=e.type),e.value!==void 0&&"value"in t&&(t.value=e.value),e.placeholder!==void 0&&"placeholder"in t&&(t.placeholder=e.placeholder),e.href&&"href"in t&&(t.href=e.href);for(const[s,a]of Object.entries(e.attrs??{}))a===void 0||a===!1||t.setAttribute(s,a===!0?"":String(a));Object.assign(t.style,e.style??{});for(const[s,a]of Object.entries(e.on??{}))t.addEventListener(s,a);for(const s of e.children??[])s==null||s===!1||t.append(s);return t}function N(n){n.replaceChildren()}function z(n){return r("span",{class:`dashicons ${n.startsWith("dashicons-")?n:`dashicons-${n}`}`,attrs:{"aria-hidden":"true"}})}function y(n,e,t){const s=e.matches("input, select, textarea, button")?e:e.querySelector("input, select, textarea");if(s){const a=s.id||`atf-c-${Math.random().toString(36).slice(2,9)}`;return s.id=a,r("div",{class:"atfb-row",children:[r("label",{class:"atfb-row__label",text:n,attrs:{for:a}}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}return r("div",{class:"atfb-row",children:[r("span",{class:"atfb-row__label",text:n}),e,t?r("p",{class:"atfb-row__hint",text:t}):null]})}function T(n,e,t=""){return r("input",{class:"atfb-input",type:"text",value:n,placeholder:t,on:{input:s=>e(s.target.value)}})}function G(n,e){if(Y("os-number-field")){const t=document.createElement("os-number-field");return t.setAttribute("value",n),t.classList.add("atfb-field"),t.addEventListener("os-input-change",s=>{e(String(s.detail?.value??""))}),t}return r("input",{class:"atfb-input",type:"number",value:n,on:{input:t=>e(t.target.value)}})}function ue(n,e,t=4){const s=r("textarea",{class:"atfb-input atfb-input--area",attrs:{rows:t},on:{input:a=>e(a.target.value)}});return s.value=n,s}function D(n,e,t){if(Y("os-select")&&Y("os-option")){const s=document.createElement("os-select");s.setAttribute("value",n),s.classList.add("atfb-field");for(const a of e){const i=document.createElement("os-option");i.setAttribute("value",a.value),i.textContent=a.label,s.append(i)}return s.addEventListener("os-pick",a=>{t(String(a.detail?.value??""))}),s}return r("select",{class:"atfb-input atfb-select",on:{change:s=>t(s.target.value)},children:e.map(s=>r("option",{value:s.value,text:s.label,attrs:{selected:s.value===n}}))})}function O(n,e,t){if(Y("os-checkbox-label")){const a=document.createElement("os-checkbox-label");return a.setAttribute("label",n),a.classList.add("atfb-check"),e&&a.setAttribute("checked",""),a.addEventListener("os-checkbox-change",i=>{t(!!i.detail?.checked)}),a}const s=r("input",{type:"checkbox",on:{change:a=>t(a.target.checked)}});return s.checked=e,r("label",{class:"atfb-check",children:[s,r("span",{text:n})]})}function $(n,e,t="secondary",s){const a=[s?z(s):null,r("span",{text:n})];if(Y("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",t),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${t}`),i.addEventListener("click",e);for(const o of a)o&&i.append(o);return i}return r("button",{class:`atfb-button atfb-button--${t}`,type:"button",on:{click:e},children:a})}function Y(n){return typeof customElements<"u"&&!!customElements.get(n)}const ss=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let pe=null;function ns(){if(pe)return pe;const n=window.wp?.os;return pe=n?.loadComponents?n.loadComponents(ss).catch(()=>{}):Promise.resolve(),pe}async function fe(n,e=""){const t=window.wp?.os;return t?.confirm?t.confirm({title:e,message:n,danger:!0}):window.confirm(n)}function R(n,e="",t="info"){const s=window.wp?.os;if(s?.notify){s.notify({title:n,body:e,type:t});return}console.info(`[AllTerrain Forms] ${n}${e?`: ${e}`:""}`)}function as(n){let e=0,t;return(...s)=>{t=s,!e&&(e=window.requestAnimationFrame(()=>{e=0,n(...t)}))}}function $e(n,e){let t=0;return(...s)=>{window.clearTimeout(t),t=window.setTimeout(()=>n(...s),e)}}function is(n){try{return window.localStorage.getItem(n)??""}catch{return""}}function rs(n,e){try{window.localStorage.setItem(n,e)}catch{}}function Ae(n){const e=n.closest(".os-window__body");e&&(e.addEventListener("scroll",()=>{e.scrollTop&&(e.scrollTop=0),e.scrollLeft&&(e.scrollLeft=0)},{passive:!0}),e.scrollTop=0,e.scrollLeft=0)}function tt(){const n=[window];try{window.parent&&window.parent!==window&&n.push(window.parent)}catch{}return n}function os(n){const e=n.wp?.os?.windowManager?.getAll?.()??[];for(const t of e){const s=t.iframe??t.element?.querySelector?.("iframe");if(s&&s.contentWindow===window)return t}return null}const ls=4e3,cs=100;function ds(n,e){const t=Date.now()+ls,s=()=>{const a=os(n);if(a&&a.id!==e){typeof a.close=="function"?a.close():n.wp?.os?.windowManager?.remove?.(a.id);return}!a&&Date.now()0?{form:t}:void 0;t>0&&fs(t);for(const a of tt())if(a.wp?.os?.openWindow?.(e,{source:"handoff",params:s})){window.setTimeout(()=>ds(a,e),0);return}}function us(){document.addEventListener("click",n=>{const e=n.target?.closest?.("[data-atf-open-window]");if(!e)return;n.preventDefault();const t=e.getAttribute("data-atf-open-window")??"";for(const s of tt())if(s.wp?.os?.openWindow?.(t,{source:"handoff"}))return})}const ps="allterrain-forms/requested-form";function fs(n){try{window.sessionStorage.setItem(ps,String(n))}catch{}}function st(n){return`allterrain-forms/requested-form-${n}`}function ms(n){try{const e=window.sessionStorage.getItem(st(n));return window.sessionStorage.removeItem(st(n)),Number(e)||0}catch{return 0}}const Te={is:"is",is_not:"is not",contains:"contains",not_contains:"does not contain",starts_with:"starts with",ends_with:"ends with",greater:"is more than",less:"is less than",greater_equal:"is at least",less_equal:"is at most",empty:"is empty",not_empty:"has any answer"},Me=["empty","not_empty"];function nt(n,e){const t=n.find(s=>s.id===e);return t?t.label||"an untitled question":null}function at(n,e,t){return n.find(i=>i.id===e)?.choices?.find(i=>i.value===t)?.label||t}function bs(n,e){const t=Te[n.operator]??String(n.operator);if(Me.includes(n.operator))return t;const s=at(e,n.field,n.value);return`${n.operator==="is"?"":`${t} `}${s!==""?s:"(nothing)"}`}function it(n,e,t=0){const s=nt(e,n.field),a=Te[n.operator]??String(n.operator);if(s===null)return[{kind:"field",text:"a question that no longer exists",fieldId:n.field,missing:!0}];const i=[{kind:"field",text:s,fieldId:n.field,missing:!1},{kind:"operator",text:a,operator:n.operator,ruleIndex:t}];if(Me.includes(n.operator))return i;const o=at(e,n.field,n.value);return i.push({kind:"value",text:o!==""?o:"(nothing)",raw:n.value,sourceId:n.field,ruleIndex:t}),i}function gs(n,e){const t=n.logic;if(!t?.enabled||!t.rules.length)return[];const s=[{kind:"verb",text:t.action==="hide"?"Hidden when":"Shown when"}];return t.rules.forEach((a,i)=>{i>0&&s.push({kind:"join",text:t.match==="all"?"and":"or"}),s.push(...it(a,e,i))}),s}function rt(n){return n.map(e=>e.text).join(" ")}function vs(n,e){return rt(it(n,e))}function me(n){const e=[];for(const t of n){const s=t.logic;if(s?.enabled)for(const a of s.rules)!a.field||a.field===t.id||e.push({from:a.field,to:t.id,label:vs(a,n),short:bs(a,n),action:s.action,broken:nt(n,a.field)===null})}return e}function ys(n){const e=new Map,t=new Set;for(const s of me(n)){const a=`${s.from}->${s.to}`;s.broken||t.has(a)||(t.add(a),e.set(s.from,(e.get(s.from)??0)+1))}return e}const ot=10,lt=22,ne="http://www.w3.org/2000/svg";class ws{constructor(e){this.edges=[],this.teardowns=[],this.frame=0,this.host=e,this.svg=document.createElementNS(ne,"svg"),this.svg.setAttribute("class","atfb-logicmap"),this.svg.setAttribute("aria-hidden","true"),this.svg.setAttribute("focusable","false"),e.append(this.svg);const t=()=>this.schedule();window.addEventListener("resize",t),this.teardowns.push(()=>window.removeEventListener("resize",t));const s=e.closest(".atfb__canvas")??e;if(s.addEventListener("scroll",t,{passive:!0}),this.teardowns.push(()=>s.removeEventListener("scroll",t)),typeof ResizeObserver<"u"){const a=new ResizeObserver(t);a.observe(e),this.teardowns.push(()=>a.disconnect())}}setEdges(e){this.edges=e,this.schedule()}highlight(e){this.svg.classList.toggle("is-focused",!!e),this.svg.querySelectorAll("[data-from]").forEach(t=>{const s=e&&(t.dataset.from===e||t.dataset.to===e);t.classList.toggle("is-lit",!!s)})}destroy(){this.teardowns.forEach(e=>e()),this.teardowns=[],this.svg.remove(),this.frame&&cancelAnimationFrame(this.frame)}schedule(){this.frame||(this.frame=requestAnimationFrame(()=>{this.frame=0,this.draw()}))}draw(){this.svg.replaceChildren();const e=this.host.getBoundingClientRect();this.svg.setAttribute("viewBox",`0 0 ${e.width} ${e.height}`),this.svg.setAttribute("width",String(e.width)),this.svg.setAttribute("height",String(e.height));const t=new Map;for(const s of this.edges){const a=this.cardRect(s.from),i=this.cardRect(s.to);if(!a||!i)continue;const o=t.get(s.from)??0;t.set(s.from,o+1),this.drawEdge(s,a,i,e,o)}}cardRect(e){const t=this.host.querySelector(`[data-atfb-card="${CSS.escape(e)}"]`);return t?t.getBoundingClientRect():null}drawEdge(e,t,s,a,i){const o=t.right-a.left,l=t.top+t.height/2-a.top,c=s.right-a.left,d=s.top+s.height/2-a.top,h=Math.max(0,a.width-ot-Math.max(o,c)),w=22+i*11+Math.min(22,Math.abs(d-l)/8),_=Math.max(12,Math.min(w,h*.4)),u=document.createElementNS(ne,"path");u.setAttribute("d",`M ${o} ${l} C ${o+_} ${l}, ${c+_} ${d}, ${c} ${d}`),u.setAttribute("class",`atfb-logicmap__path is-${e.action}${e.broken?" is-broken":""}`),u.dataset.from=e.from,u.dataset.to=e.to;const b=document.createElementNS(ne,"title");b.textContent=e.label,u.append(b);const g=document.createElementNS(ne,"circle");g.setAttribute("cx",String(c)),g.setAttribute("cy",String(d)),g.setAttribute("r","3.5"),g.setAttribute("class",`atfb-logicmap__dot is-${e.action}${e.broken?" is-broken":""}`),g.dataset.from=e.from,g.dataset.to=e.to,this.svg.append(u,g);const p=document.createElementNS(ne,"text");p.setAttribute("x",String(a.width-ot)),p.setAttribute("y",String(d+3)),p.setAttribute("text-anchor","end"),p.setAttribute("class","atfb-logicmap__label"),p.dataset.from=e.from,p.dataset.to=e.to,p.textContent=e.short.length>lt?`${e.short.slice(0,lt-1)}…`:e.short;const x=document.createElementNS(ne,"title");x.textContent=e.label,p.append(x),this.svg.append(p)}}const _s={text:"text",email:"text",url:"text",tel:"text",number:"text",password:"text",date:"text",time:"text",datetime:"text",date_range:"composite",textarea:"textarea",select:"select",country:"select",multiselect:"options",radio:"options",checkboxes:"options",image_choice:"options",quiz:"options",switch:"toggle",consent:"toggle",file:"file",range:"range",rating:"summary",scale:"summary",likert:"summary",signature:"summary",repeater:"repeater",color:"text",name:"composite",address:"composite",total:"text",hidden:"static",heading:"static",html:"static",divider:"static",spacer:"static",page_break:"static"};function xs(n){return _s[n]??"text"}function ct(n,e){const t=/^choice:(\d+):(label|value)$/.exec(e);return String(t?n.choices?.[Number(t[1])]?.[t[2]]??"":n[e]??"")}function V(n){const{value:e,onInput:t,onCommit:s}=n,a=r("span",{class:`${n.class} atfb-editable`,text:e,attrs:{contenteditable:"plaintext-only",role:"textbox",spellcheck:"false","data-placeholder":n.placeholder}});return n.bind&&(a.dataset.atfbBind=n.bind),a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("input",()=>t(a.textContent??"")),a.addEventListener("keydown",i=>{i.key==="Enter"&&(i.preventDefault(),a.blur()),i.key==="Escape"&&(a.textContent=e,a.blur()),i.stopPropagation()}),a.addEventListener("blur",()=>s?.()),a}function ks(n){const e=r("input",{class:"atf-choice__input",type:n==="checkboxes"||n==="multiselect"?"checkbox":"radio"});return e.disabled=!0,e}function dt(n,e,t){const s=xs(n.type),a=V({value:n.label,placeholder:"Write the question…",class:"atf-label",bind:"label",onInput:o=>t.edit(l=>{l.label=o}),onCommit:()=>t.restructure(()=>{})}),i=[s==="static"||s==="toggle"?null:a,Ls(n,e,s,t),Ss(n,e,t)];return r("div",{class:"atfb-preview atf-form",children:[r("div",{class:`atf-field atf-field--${n.type}`,children:i})]})}function Ss(n,e,t){if(!e?.supports.includes("hint"))return null;const s=V({value:n.hint??"",placeholder:"Add a hint…",class:"atf-hint",bind:"hint",onInput:a=>t.edit(i=>{i.hint=a})});return s.setAttribute("aria-label","Hint"),r("p",{class:"atfb-preview__hint",children:[s]})}function Ls(n,e,t,s){switch(t){case"text":return Fe(n,"atf-input",s);case"textarea":return Fe(n,"atf-input atf-textarea",s,!0);case"select":return r("div",{class:"atfb-preview__select",children:[Fe(n,"atf-input atf-select",s)]});case"options":return As(n,s);case"toggle":return r("div",{class:n.type==="switch"?"atf-toggle atf-toggle--switch":"atf-toggle",children:[(()=>{const a=r("input",{class:"atf-toggle__input",type:"checkbox"});return a.disabled=!0,a})(),V({value:n.label||"",placeholder:n.type==="consent"?"What are they agreeing to?…":"What does this turn on?…",class:"atf-toggle__label",bind:"label",onInput:a=>s.edit(i=>{i.label=a}),onCommit:()=>s.restructure(()=>{})})]});case"file":return r("div",{class:"atf-file",children:[r("input",{class:"atf-file__input",type:"file"})]});case"range":return r("input",{class:"atf-range__input",type:"range"});case"composite":return r("div",{class:"atf-composite__parts",children:[r("span",{class:"atf-input atfb-preview__ghost",text:""}),r("span",{class:"atf-input atfb-preview__ghost",text:""})]});case"static":return Ts(n,e,s);case"repeater":return Es(n,s);default:return r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — set this up in the panel on the right.`})]})}}function Es(n,e){const t=n.fields??[],s=r("div",{class:"atfb-repeater__zone",attrs:{"data-atfb-repeater-zone":n.id}});return t.forEach(a=>s.append(Cs(n,a,e))),t.length||s.append(r("p",{class:"atfb-repeater__empty",text:"Drag fields from the palette in here — the visitor gets a fresh copy of each with every row they add."})),r("div",{class:"atfb-repeater",attrs:{"data-atfb-repeater":n.id},children:[r("div",{class:"atf-repeater__row atfb-repeater__frame",children:[r("div",{class:"atf-repeater__row-head",children:[r("span",{class:"atf-repeater__title atfb-repeater__title",children:[V({value:String(n.itemLabel??""),placeholder:"Row",class:"atfb-repeater__item-label",bind:"itemLabel",onInput:a=>e.edit(i=>{i.itemLabel=a})}),r("span",{class:"atfb-repeater__ordinal",text:"1",attrs:{"aria-hidden":"true"}})]})]}),s]}),$s(n,e)]})}function Cs(n,e,t){const s=e.id,a=l=>c=>{const d=(c.fields??[]).find(h=>h.id===s);d&&l(d)},i={edit:l=>t.edit(a(l)),restructure:l=>t.restructure(a(l)),types:t.types,selectedId:t.selectedId},o=t.types?.(e.type);return r("div",{class:`atfb-subcard${t.selectedId===s?" is-selected":""}`,attrs:{"data-atfb-subfield":s,"data-atfb-parent":n.id,tabindex:"0",role:"button","aria-label":`${e.label||o?.label||e.type}, inside ${n.label||"the repeater"}`},children:[r("div",{class:"atfb-subcard__head",children:[r("span",{class:"atfb-subcard__type",text:o?.label??e.type}),e.required?r("span",{class:"atfb-subcard__required",text:"Required"}):null,r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this field from the repeater",attrs:{"aria-label":`Remove ${e.label||o?.label||"this field"}`},on:{pointerdown:l=>l.stopPropagation(),click:l=>{l.stopPropagation(),t.restructure(c=>{const d=c.fields??[],h=d.findIndex(w=>w.id===s);h>=0&&d.splice(h,1)})}},children:[r("span",{text:"×"})]})]}),dt(e,o,i)]})}function Fe(n,e,t,s=!1){const a=V({value:n.placeholder??"",placeholder:n.type==="select"||n.type==="country"?"Choose…":"Placeholder…",class:`${e} atfb-preview__box${s?" atfb-preview__box--tall":""}`,bind:"placeholder",onInput:i=>t.edit(o=>{o.placeholder=i})});return a.setAttribute("aria-label","Placeholder"),a}function Ie(n,e,t,s,a,i){return r("span",{class:`atf-button ${t} atfb-preview__button`,children:[V({value:n,placeholder:e,class:"atfb-preview__button-text",bind:s,onInput:o=>a.edit(l=>i(l,o))})]})}function $s(n,e){return Ie(String(n.addLabel??""),"Add another","atf-button--ghost atfb-repeater__add","addLabel",e,(t,s)=>{t.addLabel=s})}function As(n,e){const t=r("div",{class:"atf-choices__list"});return(n.choices??[]).forEach((s,a)=>{t.append(r("div",{class:"atf-choice atfb-preview__option",children:[ks(n.type),V({value:s.label,placeholder:"Option…",class:"atf-choice__label",bind:`choice:${a}:label`,onInput:i=>{e.edit(o=>{const l=o.choices?.[a];if(!l)return;const c=!l.value||l.value===l.label;l.label=i,c&&(l.value=i)})}}),r("button",{class:"atfb-preview__remove",type:"button",title:"Remove this option",attrs:{"aria-label":`Remove ${s.label||"this option"}`},on:{pointerdown:i=>i.stopPropagation(),click:i=>{i.stopPropagation(),e.restructure(o=>{o.choices.splice(a,1)})}},children:[r("span",{text:"×"})]})]}))}),t.append(r("button",{class:"atfb-preview__add",type:"button",on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.restructure(a=>{const i=a.choices.length+1;a.choices.push({label:`Option ${i}`,value:`Option ${i}`})})}},children:[r("span",{text:"+ Add option"})]})),r("fieldset",{class:"atf-choices",children:[t]})}function Ts(n,e,t){return n.type==="heading"?V({value:n.label,placeholder:"Section heading…",class:"atf-heading",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})}):n.type==="divider"?r("hr",{class:"atf-divider"}):n.type==="page_break"?r("div",{class:"atfb-preview__stack",children:[r("p",{class:"atfb-progress-name",children:[V({value:n.label,placeholder:"Name this step…",class:"atf-progress__label",bind:"label",onInput:s=>t.edit(a=>{a.label=s}),onCommit:()=>t.restructure(()=>{})})]}),r("p",{class:"atfb-preview__summary",text:"Everything after this is a new page."}),r("div",{class:"atf-nav atfb-preview__nav",children:[Ie(String(n.prevLabel??""),"Back","atf-button--secondary","prevLabel",t,(s,a)=>{s.prevLabel=a}),Ie(String(n.nextLabel??""),"Next","","nextLabel",t,(s,a)=>{s.nextLabel=a})]})]}):r("p",{class:"atfb-preview__summary",text:`${e?.label??n.type} — nothing is shown to the visitor here.`})}const De=new Map;function qe(n){let e=De.get(n);return e||(e=F.mergeTags(n).catch(()=>[]),De.set(n,e)),e}function Ms(n){De.delete(n)}function Fs(n){const e=new Map;for(const t of n)for(const s of t.items)e.set(s.tag,s);return e}function Is(n,e){const t=Fs(e);return n.replace(/\{[a-z_]+(?::[^}]*)?\}/gi,s=>{const a=t.get(s.toLowerCase());return a?a.sample:s})}function Ds(n){return/\{[a-z_]+(?::[^}]*)?\}/i.test(n)}let te=null;function ie(){te?.remove(),te=null}typeof document<"u"&&(document.addEventListener("pointerdown",n=>{const e=n.target;e?.closest(".atfb-tagpick__open")||te&&!te.contains(e)&&ie()}),document.addEventListener("keydown",n=>{n.key==="Escape"&&te&&(ie(),n.stopPropagation())}));function ht(n,e){const t=n.selectionStart??n.value.length,s=n.selectionEnd??n.value.length;n.value=n.value.slice(0,t)+e+n.value.slice(s);const a=t+e.length;n.setSelectionRange(a,a),n.focus(),n.dispatchEvent(new Event("input",{bubbles:!0}))}function qs(n){let e=n.parentElement;for(;e&&e!==document.body;){const t=getComputedStyle(e).overflowY;if(t==="auto"||t==="scroll"||t==="hidden")return e.getBoundingClientRect().bottom;e=e.parentElement}return window.innerHeight}function Os(n,e){const t=r("input",{class:"atfb-input atfb-tagpick__search",type:"search",placeholder:"Search values…",attrs:{"aria-label":"Search values"}}),s=r("div",{class:"atfb-tagpick__list"}),a=i=>{s.replaceChildren();const o=i.trim().toLowerCase();let l=0;for(const c of n){const d=c.items.filter(h=>!o||h.label.toLowerCase().includes(o)||h.tag.toLowerCase().includes(o));if(!d.length){c.empty&&!o&&!c.items.length&&s.append(r("p",{class:"atfb-tagpick__group",text:c.label}),r("p",{class:"atfb-tagpick__empty",text:c.empty}));continue}s.append(r("p",{class:"atfb-tagpick__group",text:c.label}));for(const h of d)l+=1,s.append(r("button",{class:"atfb-tagpick__item",type:"button",on:{click:()=>{e(h.tag),ie()}},children:[r("span",{class:"atfb-tagpick__item-main",children:[r("span",{class:"atfb-tagpick__label",text:h.label}),r("code",{class:"atfb-tagpick__tag",text:h.tag})]}),h.hint||h.sample?r("span",{class:"atfb-tagpick__meta",text:h.sample?`e.g. ${h.sample}`:h.hint}):null]}))}!l&&o&&s.append(r("p",{class:"atfb-tagpick__empty",text:`Nothing matches “${i}”.`}))};return a(""),t.addEventListener("input",()=>a(t.value)),r("div",{class:"atfb-tagpick",attrs:{role:"dialog","aria-label":"Insert a value"},children:[r("p",{class:"atfb-tagpick__intro",text:"Pick something to drop in. It is filled in when the form is submitted."}),t,s]})}function ut(n,e){const t=r("button",{class:"atfb-button atfb-button--ghost atfb-tagpick__open",type:"button",title:"Insert a value from the submission",children:[z("shortcode"),r("span",{text:"Insert a value"})]}),s=r("div",{class:"atfb-taggable",children:[n,r("div",{class:"atfb-taggable__tools",children:[t]})]}),a=e.preview===!1?null:r("p",{class:"atfb-taggable__preview"});a&&s.append(a);const i=()=>{if(a){if(!Ds(n.value)){a.textContent="",a.hidden=!0;return}qe(e.formId).then(o=>{a.hidden=!1,a.replaceChildren(r("span",{class:"atfb-taggable__preview-label",text:"Reads as"}),r("span",{text:Is(n.value,o)}))})}};return n.addEventListener("input",i),i(),t.addEventListener("click",o=>{if(o.stopPropagation(),te&&s.contains(te)){ie();return}ie(),qe(e.formId).then(l=>{const c=Os(l,d=>{ht(n,d),i()});s.append(c),te=c,(window.innerHeight-c.getBoundingClientRect().topqs(s))&&c.classList.add("atfb-tagpick--above"),c.querySelector(".atfb-tagpick__search")?.focus()})}),s}function pt(n,e){const t=parseFloat(String(n??""));return Number.isFinite(t)?t:e}function ft(n,e){let t=e[0];for(const s of e)Math.abs(s.at-n)n.accent??"#2271b1",apply:n=>({accent:n,"accent-soft":`color-mix( in srgb, ${n} 12%, transparent )`,"border-focus":n,"focus-ring-color":n,"button-bg":n,"button-bg-hover":`color-mix( in srgb, ${n} 88%, #000 )`})},{id:"roundness",label:"Roundness",hint:"Corners, everywhere at once.",kind:"scale",steps:Oe.map(({value:n,label:e})=>({value:n,label:e})),owns:["radius-field","radius-button","radius-card","radius-check"],read:n=>ft(pt(n["radius-field"],4),Oe),apply:n=>{const e=Oe.find(t=>t.value===n)?.at??4;return{"radius-field":`${e}px`,"radius-button":`${e}px`,"radius-card":`${Math.min(e*2,28)}px`,"radius-check":`${Math.min(e,6)}px`}}},{id:"density",label:"Density",hint:"How much air the form has.",kind:"scale",steps:Ne.map(({value:n,label:e})=>({value:n,label:e})),owns:["pad-field-x","pad-field-y","gap-fields","gap-label","button-pad-x","button-pad-y"],read:n=>ft(pt(n["pad-field-y"],9),Ne),apply:n=>{const e=Ne.find(t=>t.value===n)?.at??9;return{"pad-field-y":`${e}px`,"pad-field-x":`${Math.round(e*1.4)}px`,"gap-fields":`${Math.round(e*2.2)}px`,"gap-label":`${Math.max(4,Math.round(e*.7))}px`,"button-pad-y":`${e+2}px`,"button-pad-x":`${Math.round(e*2.2)}px`}}},{id:"shadow",label:"Depth",hint:"How far the form sits off the page.",kind:"scale",steps:Ns,owns:["shadow-field","shadow-field-focus","shadow-button","shadow-button-hover","shadow-card"],read:n=>{const e=n["shadow-card"]??"none";return e==="none"||e.trim()===""?n["shadow-field"]&&n["shadow-field"]!=="none"?"hard":"none":e.includes("0 1px")||e.includes("2px")?"subtle":"lifted"},apply:n=>{switch(n){case"subtle":return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"0 1px 2px rgba( 0, 0, 0, 0.12 )","shadow-button-hover":"0 2px 4px rgba( 0, 0, 0, 0.16 )","shadow-card":"0 1px 3px rgba( 0, 0, 0, 0.1 )"};case"lifted":return{"shadow-field":"none","shadow-field-focus":"0 4px 12px rgba( 0, 0, 0, 0.12 )","shadow-button":"0 4px 10px rgba( 0, 0, 0, 0.16 )","shadow-button-hover":"0 8px 20px rgba( 0, 0, 0, 0.2 )","shadow-card":"0 10px 30px rgba( 0, 0, 0, 0.14 )"};case"hard":return{"shadow-field":"3px 3px 0 currentColor","shadow-field-focus":"5px 5px 0 currentColor","shadow-button":"4px 4px 0 currentColor","shadow-button-hover":"2px 2px 0 currentColor","shadow-card":"none"};default:return{"shadow-field":"none","shadow-field-focus":"none","shadow-button":"none","shadow-button-hover":"none","shadow-card":"none"}}}},{id:"field-style",label:"Fields",hint:"How an input is drawn.",kind:"choice",steps:Rs,owns:["field-style"],read:n=>n["field-style"]??"outline",apply:n=>({"field-style":n})},{id:"labels",label:"Labels",hint:"Where the question sits relative to the answer.",kind:"choice",steps:Ps,owns:["label-position"],read:n=>n["label-position"]??"top",apply:n=>({"label-position":n})}]}function Bs(n){return Re().find(e=>e.owns.includes(n))??null}function mt(n){let e=n.activeSlug,t={...n.overrides},s=n.themes;const a=m=>{t=m,n.onOverridesReplaced?.({...m})},i=r("div",{class:"atfs-preview__frame"}),o=r("div",{class:"atfs-controls__body"}),l=r("div",{class:"atfs-quick"}),c=r("div",{class:"atfs-themes"}),d=$e(async()=>{try{const m=await n.previewFor(e,t),v=i.closest(".atf-studio__preview"),k=v?.scrollTop??0;i.innerHTML=m,v&&(v.scrollTop=k),document.dispatchEvent(new CustomEvent("alltfo-refresh"))}catch(m){N(i),i.append(r("p",{class:"atfb-error",text:m instanceof Error?m.message:"Preview failed."}))}},180),h={"label-position":"atf-labels-","field-style":"atf-fields-"},w=(m,v,k)=>{const L=k.replace(/[^a-z0-9_-]/gi,"");for(const A of[...m.classList])A.startsWith(v)&&m.classList.remove(A);L&&m.classList.add(v+L)},_=m=>{const v=i.querySelector(".atf-form-wrap"),k=v?.querySelector(".atf-form");if(v)for(const[L,A]of Object.entries(m))A===""?v.style.removeProperty(`--atf-${L}`):v.style.setProperty(`--atf-${L}`,A),k&&h[L]&&w(k,h[L],A||(s.find(P=>P.slug===e)?.resolved[L]??""))},u=m=>{_(m.resolved);const v=i.querySelector(".atf-form");v&&(w(v,"atf-theme-",m.slug),v.classList.toggle("atf-is-dark",!!m.dark))},b=m=>t[m.token]!==void 0?t[m.token]:s.find(k=>k.slug===e)?.resolved?.[m.token]??m.default,g=()=>{N(c);for(const m of s){const v=r("button",{class:`atfs-theme${m.slug===e?" is-active":""}`,type:"button",attrs:{"aria-pressed":m.slug===e,title:m.description},children:[r("span",{class:"atfs-theme__chip",style:{background:m.resolved.surface??"#fff",borderColor:m.resolved.border??"#ccc",borderRadius:m.resolved["radius-field"]??"4px",boxShadow:m.resolved["shadow-card"]??"none"},children:[r("span",{class:"atfs-theme__accent",style:{background:m.resolved.accent??"#2271b1",borderRadius:m.resolved["radius-button"]??"4px"}})]}),r("span",{class:"atfs-theme__name",text:m.label}),m.custom?r("span",{class:"atfb-badge",text:"yours"}):null],on:{click:()=>{e=m.slug,a({}),n.onTheme(e),u(m),g(),S(),I(),Yt()}}});c.append(v)}},p=()=>{const v={...s.find(k=>k.slug===e)?.resolved??{}};for(const[k,L]of Object.entries(t))v[k]=L;return v},x=m=>{const v=l.closest(".atf-studio__controls"),k=v?.scrollTop??0;m(),v&&(v.scrollTop=k)},I=$e(()=>x(f),150),S=()=>{const m=p(),v=l.querySelectorAll(".atfs-dial");Re().forEach((k,L)=>{const A=v[L];if(!A)return;const P=k.read(m);if(k.kind==="colour"){const q=A.querySelector('input[type="color"]'),X=A.querySelector("input.atfb-input");q&&document.activeElement!==q&&(q.value=be(P)),X&&document.activeElement!==X&&(X.value=P);return}A.querySelectorAll(".atfs-segment").forEach((q,X)=>{const Q=k.steps?.[X]?.value===P;q.classList.toggle("is-on",Q),q.setAttribute("aria-pressed",String(Q))})})},H=(m,v)=>{const k=m.apply(v,p());for(const[L,A]of Object.entries(k))t[L]=A,n.onOverride(L,A);_(k),S(),I()},E=()=>{N(l);const m=p();for(const v of Re()){const k=v.read(m);let L;if(v.kind==="colour"){const A=r("input",{class:"atfs-color",type:"color",value:be(k),attrs:{"aria-label":v.label},on:{input:P=>H(v,P.target.value)}});L=r("div",{class:"atfs-color-row",children:[A,T(k,P=>H(v,P))]})}else L=r("div",{class:`atfs-segmented atfs-segmented--${v.kind}`,attrs:{role:"group","aria-label":v.label},children:(v.steps??[]).map(A=>r("button",{class:`atfs-segment${A.value===k?" is-on":""}`,type:"button",text:A.label,attrs:{"aria-pressed":A.value===k},on:{click:()=>H(v,A.value)}}))});l.append(r("div",{class:"atfs-dial",children:[r("div",{class:"atfs-dial__head",children:[r("span",{class:"atfs-dial__label",text:v.label}),r("span",{class:"atfs-dial__hint",text:v.hint})]}),L]}))}},f=()=>{N(o);const m=new Map;for(const k of n.tokens){const L=m.get(k.group)??[];L.push(k),m.set(k.group,L)}const v={colour:"Colour",shape:"Corners and borders",shadow:"Shadows",fields:"Field style",space:"Spacing",type:"Type",labels:"Labels",button:"Buttons",focus:"Focus ring",motion:"Motion"};for(const[k,L]of m)o.append(r("details",{class:"atfs-group",attrs:{open:k==="colour"},children:[r("summary",{text:v[k]??k}),...L.map(A=>M(A))]}))},M=m=>{const v=b(m),k=q=>{q===""?delete t[m.token]:t[m.token]=q,n.onOverride(m.token,q),_({[m.token]:q})};let L;if(m.control==="color"){const q=r("input",{class:"atfs-color",type:"color",value:be(v),attrs:{"aria-label":`${m.label} colour`},on:{input:Q=>{const le=Q.target.value;X.value=le,k(le)}}}),X=T(v,Q=>{q.value=be(Q),k(Q)});L=r("div",{class:"atfs-color-row",children:[q,X]})}else if(m.control==="select")L=D(v,(m.options??[]).map(q=>({value:q,label:q})),k);else if(m.control==="length"){const q=parseFloat(v)||0,X=m.unit??"px",Q=m.token.includes("radius")?60:80,le=r("input",{class:"atfs-range",type:"range",value:String(q),attrs:{min:"0",max:String(Q),step:"1","aria-label":m.label},on:{input:ke=>{const Xt=`${ke.target.value}${X}`;Gt.value=Xt,k(Xt)}}}),Gt=T(v,ke=>{le.value=String(parseFloat(ke)||0),k(ke)});L=r("div",{class:"atfs-length-row",children:[le,Gt]})}else L=T(v,k);const A=y(m.label,L),P=Bs(m.token);return P&&(A.classList.add("is-dialled"),A.append(r("span",{class:"atfs-owned",text:P.label}))),t[m.token]!==void 0&&(A.classList.add("is-overridden"),A.append(r("button",{class:"atfs-reset",type:"button",text:"Reset",attrs:{"aria-label":`Reset ${m.label} to the theme's value`},on:{click:()=>{k(""),x(f)}}}))),A},C=async()=>{const m=s.find(L=>L.slug===e),v=m?`${m.label} (mine)`:"My theme",k=window.prompt("Name this theme",v);if(k)try{const L={};for(const P of n.tokens){const q=b(P);q!==P.default&&(L[P.token]=q)}const A=await F.saveTheme({label:k,tokens:L});s=[...s.filter(P=>P.slug!==A.slug),A],n.onThemesChanged(s),e=A.slug,a({}),n.onTheme(e),g(),S(),x(f),R("Theme saved",A.label)}catch(L){R("Could not save the theme",L instanceof Error?L.message:"","error")}},j=async()=>{const m=s.find(v=>v.slug===e);if(m?.custom&&await fe(`Delete “${m.label}”? Forms using it fall back to Clean.`,"Delete theme"))try{await F.deleteTheme(m.id),s=s.filter(k=>k.slug!==m.slug),n.onThemesChanged(s),e="clean",a({}),n.onTheme(e),g(),S(),x(f);const v=s.find(k=>k.slug===e);v&&u(v)}catch(v){R("Could not delete the theme",v instanceof Error?v.message:"","error")}},B=async()=>{const m=s.find(L=>L.slug===e),v={label:m?.label??e,tokens:{...m?.tokens??{},...t}},k=JSON.stringify(v,null," ");try{await navigator.clipboard.writeText(k),R("Theme copied","Paste it into another site to import it.")}catch{window.prompt("Copy this theme",k)}},oe=()=>{const m=window.prompt("Paste a theme");if(m)try{const v=JSON.parse(m);if(!v.tokens||typeof v.tokens!="object")throw new Error("That does not look like a theme.");for(const[k,L]of Object.entries(v.tokens))t[k]=String(L),n.onOverride(k,String(L));_({...t}),S(),x(f)}catch(v){R("Could not read that theme",v instanceof Error?v.message:"","error")}},zt=$("Delete",()=>void j(),"danger"),Yt=()=>{const m=s.find(v=>v.slug===e);zt.hidden=!m?.custom};return g(),E(),f(),d(),Yt(),r("div",{class:"atf-studio",children:[r("div",{class:"atf-studio__top",children:[r("div",{class:"atf-studio__topbar",children:[r("h2",{class:"atf-studio__heading",text:"Theme"}),r("div",{class:"atfs__actions",children:[$("Save as a theme",()=>void C(),"primary"),$("Export",()=>void B()),$("Import",oe),zt]})]}),c]}),r("div",{class:"atf-studio__panes",children:[r("aside",{class:"atf-studio__controls",children:[r("p",{class:"atfb-hint",text:"Changes apply to this form only, until you save them as a theme."}),l,r("details",{class:"atfs-advanced",children:[r("summary",{text:"Every setting"}),r("p",{class:"atfb-hint",text:"The full token list. The dials above write into it."}),o]})]}),r("main",{class:"atf-studio__preview",children:[r("h2",{class:"screen-reader-text",text:"Live preview"}),i]})]})]})}async function Pe(){const n=document.querySelector("[data-atfs-root]");if(!n||n.dataset.atfsMounted)return;n.dataset.atfsMounted="1",Ae(n);const e=n.querySelector("[data-atfs-bar]"),t=n.querySelector(".atfs__body")??n;try{const[s,a,i]=await Promise.all([F.config(),F.listThemes(),F.listForms()]);if(!i.length){N(t),t.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms to preview"}),r("p",{text:"Make a form first — a theme needs something to dress."})]}));return}let o=i[0],l={},c=o.theme;const d=()=>{N(t),t.append(mt({themes:a,tokens:s.tokens,activeSlug:c,overrides:l,standalone:!0,onTheme:h=>{c=h},onOverride:(h,w)=>{w===""?delete l[h]:l[h]=w},onOverridesReplaced:h=>{l={...h}},previewFor:async(h,w)=>{const _=await F.getForm(o.id);_.schema.settings.theme=h,_.schema.settings.themeOverrides=w;const{html:u}=await F.preview(o.id,{schema:_.schema,theme:h});return u},onThemesChanged:h=>{a.length=0,a.push(...h)}}))};e&&(N(e),e.append(r("span",{class:"atfs__label",text:"Preview against"}),D(String(o.id),i.map(h=>({value:String(h.id),label:h.title||"(untitled)"})),h=>{o=i.find(w=>String(w.id)===h)??i[0],l={},d()}))),d()}catch(s){N(t),t.append(r("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load themes."}))}}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void Pe()):Pe(),document.addEventListener("os-window-content-loaded",()=>void Pe()));function be(n){const e=n.trim();return/^#[0-9a-f]{6}$/i.test(e)?e:/^#[0-9a-f]{3}$/i.test(e)?`#${e[1]}${e[1]}${e[2]}${e[2]}${e[3]}${e[3]}`:"#888888"}const Hs="mailpoet",ge="",js=["checkbox","checkboxes","toggle","consent","gdpr"],bt=["email"];function gt(n){return n.schema.actions.find(e=>e.type==="mailpoet")}function Be(n){const e=n?.settings??{};return{lists:Array.isArray(e.lists)?e.lists.map(Number).filter(Boolean):[],email_field:typeof e.email_field=="string"?e.email_field:"",first_name_field:typeof e.first_name_field=="string"?e.first_name_field:"",last_name_field:typeof e.last_name_field=="string"?e.last_name_field:""}}function Ws(n){return n?.logic?.enabled?n.logic.rules[0]?.field??ge:ge}function vt(n,e,t){const s=n.find(a=>e.includes(a.type));return s?s.id:t?n.find(a=>t.test(a.label))?.id??"":""}function Us(n,e,t){const s=r("section",{class:"atfm-form"}),a=l=>r("span",{class:`atfm-form__mark${l?"":" atfm-form__mark--off"}`,children:[r("img",{attrs:{src:e.symbol,alt:"",width:"20",height:"20"}})]}),i=l=>{N(s),s.classList.remove("is-open"),s.append(r("div",{class:"atfm-form__head",children:[a(l.length>0),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`}),l.length?r("span",{class:"atfm-form__status is-on",text:`Subscribing → ${l.join(", ")}`}):r("span",{class:"atfm-form__status",text:"Not connected"})]}),$(l.length?"Edit":"Connect",()=>void o(),"secondary")]}))},o=async()=>{s.classList.add("is-open"),N(s),s.append(r("p",{class:"atfm-hint",text:"Loading the form…"}));let l;try{l=await F.getForm(n.id)}catch{N(s),s.append(r("p",{class:"atfm-hint",text:"Could not load this form."}));return}const c=l.schema.fields.filter(f=>f.type!=="page_break"),d=gt(l),h=Be(d),w=new Set(h.lists.filter(f=>e.lists.some(M=>M.id===f)));let _=Ws(d),u=h.email_field||vt(c,bt,/mail/i),b=h.first_name_field,g=h.last_name_field;c.some(f=>f.id===u)||(u=vt(c,bt,/mail/i));const p=c.filter(f=>js.includes(f.type));!d&&p.length&&(_=p[0].id);const x=(f,M)=>[{value:"",label:M},...f.map(C=>({value:C.id,label:C.label||C.id}))],I=r("div",{class:"atfm-lists"});(()=>{N(I);for(const f of e.lists){const M=r("input",{attrs:{type:"checkbox"}});M.checked=w.has(f.id),M.addEventListener("change",()=>{M.checked?w.add(f.id):w.delete(f.id)}),I.append(r("label",{class:"atfm-list",children:[M,r("span",{text:f.name})]}))}})();const H=async(f=!1)=>{const M=l.schema.actions.filter(C=>C.type!=="mailpoet");if(!f){if(!w.size){R("Pick a list","A subscription needs at least one MailPoet list.","error");return}if(!u){R("Pick the email field","MailPoet needs to know which answer is the address.","error");return}M.push({id:Hs,type:"mailpoet",enabled:!0,logic:_===ge?{enabled:!1,action:"show",match:"all",rules:[]}:{enabled:!0,action:"show",match:"all",rules:[{field:_,operator:"not_empty",value:""}]},settings:{lists:[...w],email_field:u,first_name_field:b,last_name_field:g}})}l.schema.actions=M;try{await F.updateForm(l.id,{schema:l.schema})}catch(C){R("Could not save",C instanceof Error?C.message:"","error");return}R(f?"Disconnected":"Connected to MailPoet",f?`${n.title} no longer subscribes anyone.`:`${n.title} now subscribes opted-in visitors.`),i(f?[]:e.lists.filter(C=>w.has(C.id)).map(C=>C.name))};N(s);const E=f=>r("span",{class:"atfm-form__section",text:f});s.append(r("div",{class:"atfm-form__head",children:[a(!!d),r("div",{class:"atfm-form__title",children:[r("strong",{text:n.title||`Form ${n.id}`})]}),$("Close",()=>i(d?e.lists.filter(f=>Be(d).lists.includes(f.id)).map(f=>f.name):[]),"ghost")]}),r("div",{class:"atfm-form__body",children:[E("Where they land"),y("Lists",I,"MailPoet sends its own confirmation email before anyone is truly on a list."),E("Who they are"),y("Email address",D(u,x(c,"— pick a field —"),f=>{u=f}),"The answer that carries their address."),y("First name",D(b,x(c,"— none —"),f=>{b=f})),y("Last name",D(g,x(c,"— none —"),f=>{g=f})),E("When to subscribe"),y("Subscribe",D(_,[...p.map(f=>({value:f.id,label:`Only when “${f.label||f.id}” is ticked`})),{value:ge,label:"Everyone who submits"}],f=>{_=f}),p.length?"Bind it to a box they tick. Subscribing everyone is rarely what visitors expect.":"Add a checkbox or toggle field to the form to offer a proper opt-in."),r("div",{class:"atfm-form__actions",children:d?[$("Save connection",()=>void H(),"primary"),$("Disconnect",()=>void H(!0),"danger")]:[$("Save connection",()=>void H(),"primary")]})]}))};return i([]),F.getForm(n.id).then(l=>{const c=gt(l);if(c&&!s.classList.contains("is-open")){const d=e.lists.filter(h=>Be(c).lists.includes(h.id)).map(h=>h.name);i(d)}}).catch(()=>{}),t.append(s),s}function zs(n){const e=n.logo?r("span",{class:"atfm-hero__logo",children:[r("img",{attrs:{src:n.logo,alt:"MailPoet",width:"210",height:"105"}})]}):r("span",{class:"atfm-hero__logo atfm-hero__logo--glyph",text:"📬"});return r("header",{class:"atfm-hero",children:[e,r("div",{class:"atfm-hero__words",children:[r("h1",{text:"Turn submissions into subscribers"}),r("p",{text:"Every submission is someone choosing to talk to you. Connect a form to MailPoet and the ones who opt in land on your lists by themselves — named, consented, and confirmed by MailPoet’s own double opt-in."}),n.active?r("p",{class:"atfm-hero__status is-on",text:n.lists.length===1?"Connected — 1 list ready for subscribers":`Connected — ${n.lists.length} lists ready for subscribers`}):r("p",{class:"atfm-hero__status",text:"MailPoet is not installed on this site yet"})]})]})}function Ys(){const n=(t,s,a)=>r("div",{class:"atfm-why__card",children:[r("span",{class:"atfm-why__icon",text:t}),r("strong",{text:s}),r("p",{text:a})]}),e=(t,s)=>r("a",{text:s,attrs:{href:t,target:"_blank",rel:"noreferrer"}});return[r("div",{class:"atfm-why",children:[n("✉️","Beautiful emails, made in WordPress","Design newsletters and welcome emails in a drag-and-drop editor that lives in your own admin — no external account to juggle."),n("🤝","Consent you can stand behind","Double opt-in out of the box: every address your forms send over is confirmed by the visitor before a single campaign reaches it."),n("🚀","Free to grow with","Free up to 500 subscribers, welcome automations, WooCommerce emails and open-rate stats included — a paid addon anywhere else.")]}),r("p",{class:"atfm-links",children:[e("https://www.mailpoet.com/features/","Explore MailPoet’s features ↗"),e("https://kb.mailpoet.com/","Guides & docs ↗"),e("https://www.mailpoet.com/pricing/","Plans & the free tier ↗")]})]}function Gs(){const n=(e,t)=>r("div",{class:"atfm-step",children:[r("span",{class:"atfm-step__n",text:e}),r("span",{text:t})]});return r("div",{class:"atfm-steps",children:[n("1","Pick a form below"),n("2","Choose the lists it feeds"),n("3","Bind it to an opt-in — MailPoet confirms the rest")]})}async function He(){const n=document.querySelector("[data-atfm-root]");if(!n||n.dataset.atfmMounted)return;n.dataset.atfmMounted="1",Ae(n);const e=n.querySelector("[data-atfm-bar]"),t=n.querySelector("[data-atfm-body]")??n;try{const[s,a]=await Promise.all([F.mailpoet(),F.listForms()]);if(e?.remove(),N(t),t.append(zs(s),...Ys()),!s.active){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet sends newsletters from right inside WordPress — no external account, free to start. Install it and every form here gets a subscribe switch: reservations feed your announcements, signups feed your schedule, enquiries feed your news."}),r("a",{class:"atfm-pitch__cta",text:"Install MailPoet — it’s free",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}if(!s.lists.length){t.append(r("div",{class:"atfm-pitch",children:[r("p",{text:"MailPoet is here, but it has no list yet. Make one, and your forms will have somewhere to send subscribers."}),r("a",{class:"atfm-pitch__cta",text:"Open MailPoet lists",attrs:{href:s.adminUrl,target:"_blank",rel:"noreferrer"}})]}));return}t.append(Gs());const i=r("section",{class:"atfm-forms",children:[r("div",{class:"atfm-forms__head",children:[r("h2",{text:"Your forms"}),r("p",{class:"atfm-hint",text:"Connected forms wear the MailPoet mark in colour."})]})]});if(t.append(i),!a.length){i.append(r("p",{class:"atfm-hint",text:"No forms yet — make one, then come back to connect it."}));return}for(const o of a)Us(o,s,i)}catch{e&&(e.textContent="Could not reach the site — reload the window to try again.")}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>void He()):He(),document.addEventListener("os-window-content-loaded",()=>void He());const ve={plain:"",simple:"✓",minimal:"",card:"🎉",check:"",confetti:"🎉",fireworks:"🎆",sparkles:"✨",typewriter:""};function yt(){return{style:"simple",title:"",icon:"",accent:"",intensity:"medium",showButton:!1,buttonLabel:""}}function je(n){const e={...yt(),...n??{}};return e.style in ve||(e.style="simple"),e}function Xs(){return typeof window.matchMedia=="function"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches}function Zs(n,e,t){const s=je(e),a=document.createElement("div");if(a.className=`atf-confirmation atf-success atf-success--${s.style}`,a.setAttribute("role","status"),a.setAttribute("tabindex","-1"),s.style==="plain")return a.className="atf-confirmation",a.innerHTML=n,a;s.accent&&a.style.setProperty("--atf-accent",s.accent);const i=document.createElement("div");i.className="atf-success__inner",a.append(i);const o=s.icon||ve[s.style];if(s.style==="check")i.insertAdjacentHTML("beforeend",'');else if(o){const c=document.createElement("span");c.className="atf-success__icon",c.setAttribute("aria-hidden","true"),c.textContent=o,i.append(c)}if(s.title){const c=document.createElement("h2");c.className="atf-success__title",c.textContent=s.title,i.append(c)}const l=document.createElement("div");if(l.className="atf-success__message",l.innerHTML=n,i.append(l),s.style==="typewriter"&&a.setAttribute("aria-label",l.textContent??""),s.showButton){const c=document.createElement("button");c.type="button",c.className="atf-button atf-button--ghost atf-success__again",c.textContent=s.buttonLabel||"Fill it in again",c.addEventListener("click",()=>t?t():window.location.reload()),i.append(c)}return a}function Ks(n,e){const t=je(e);if(Xs())return()=>{};switch(t.style){case"confetti":return Vs(n,t);case"fireworks":return Js(t);case"sparkles":return Qs(n,t);case"typewriter":return en(n);default:return()=>{}}}function re(n){return{low:.5,medium:1,high:1.8}[n.intensity]}function wt(){const n=document.createElement("canvas");n.className="atf-success-canvas",n.setAttribute("aria-hidden","true");const e=Math.min(window.devicePixelRatio||1,2);n.width=Math.floor(window.innerWidth*e),n.height=Math.floor(window.innerHeight*e),document.body.append(n);const t=n.getContext("2d");return t?.scale(e,e),{canvas:n,ctx:t,stop:()=>n.remove()}}const _t=["#f43f5e","#f59e0b","#10b981","#3b82f6","#8b5cf6","#ec4899","#eab308"];function Vs(n,e){const{ctx:t,stop:s}=wt();if(!t)return s(),()=>{};const a=e.accent?[e.accent,..._t]:_t,i=[],o=n.getBoundingClientRect(),l=o.left+o.width/2,c=Math.min(o.top+40,window.innerHeight-20),d=(x,I,S)=>{const H=S?Math.PI*(1.15+.7*Math.random()):0,E=S?9+Math.random()*8:0;return{x,y:I,vx:S?Math.cos(H)*E*(Math.random()<.5?1:-1):(Math.random()-.5)*1.5,vy:S?Math.sin(H)*E:1+Math.random()*2,w:6+Math.random()*5,h:8+Math.random()*7,angle:Math.random()*Math.PI,spin:(Math.random()-.5)*.3,color:a[Math.floor(Math.random()*a.length)],wobble:Math.random()*Math.PI*2}},h=Math.round(90*re(e));for(let x=0;x{if(_>=w){window.clearInterval(u);return}i.push(d(Math.random()*window.innerWidth,-20,!1)),_++},2e3/w);let b=0;const g=performance.now(),p=x=>{t.clearRect(0,0,window.innerWidth,window.innerHeight);let I=!1;for(const S of i)S.vy+=.16,S.vx*=.99,S.vy*=.985,S.wobble+=.1,S.x+=S.vx+Math.sin(S.wobble)*.8,S.y+=S.vy,S.angle+=S.spin,S.y{window.clearInterval(u),window.cancelAnimationFrame(b),s()}}function Js(n){const{ctx:e,stop:t}=wt();if(!e)return t(),()=>{};const s=[],a=[],i=Math.round(6*re(n))+2;let o=0;const l=()=>{s.push({x:window.innerWidth*(.15+.7*Math.random()),y:window.innerHeight,vy:-(9+Math.random()*4),targetY:window.innerHeight*(.15+.3*Math.random()),hue:Math.floor(Math.random()*360)}),o++};l();const c=window.setInterval(()=>{if(o>=i){window.clearInterval(c);return}l()},3500/i),d=u=>{const b=Math.round(70*re(n));for(let g=0;g{e.clearRect(0,0,window.innerWidth,window.innerHeight);for(let g=s.length-1;g>=0;g--){const p=s[g];p.y+=p.vy,p.vy+=.08,e.fillStyle=`hsl(${p.hue} 90% 65%)`,e.fillRect(p.x-1.5,p.y,3,10),(p.y<=p.targetY||p.vy>=-1)&&(d(p),s.splice(g,1))}for(let g=a.length-1;g>=0;g--){const p=a[g];if(p.x+=p.vx,p.y+=p.vy,p.vy+=.045,p.vx*=.985,p.vy*=.985,p.life-=p.decay,p.life<=0){a.splice(g,1);continue}const x=p.life*(.7+.3*Math.random());e.globalAlpha=Math.max(0,x),e.fillStyle=`hsl(${p.hue} 95% ${55+25*p.life}%)`,e.beginPath(),e.arc(p.x,p.y,1.1+1.6*p.life,0,Math.PI*2),e.fill()}e.globalAlpha=1,!(o>=i&&s.length===0&&a.length===0)&&u-w<9e3?h=window.requestAnimationFrame(_):t()};return h=window.requestAnimationFrame(_),()=>{window.clearInterval(c),window.cancelAnimationFrame(h),t()}}function Qs(n,e){const t=e.icon||ve.sparkles,s=Math.round(22*re(e)),a=[];let i=0;const o=()=>{const c=document.createElement("span");c.className="atf-success__spark",c.setAttribute("aria-hidden","true"),c.textContent=t,c.style.insetInlineStart=`${4+Math.random()*92}%`,c.style.animationDuration=`${2.6+Math.random()*1.8}s`,c.style.animationDelay=`${Math.random()*.3}s`,c.style.fontSize=`${14+Math.random()*14}px`,c.addEventListener("animationend",()=>c.remove()),n.append(c),a.push(c),i++};o();const l=window.setInterval(()=>{if(i>=s){window.clearInterval(l);return}o()},2800/s);return()=>{window.clearInterval(l),a.forEach(c=>c.remove())}}function en(n){const e=n.querySelector(".atf-success__message");if(!e)return()=>{};const t=e.innerHTML,s=e.textContent??"";if(!s)return()=>{};e.textContent="",e.classList.add("is-typing");const a=Math.min(45,3800/s.length);let i=0;const o=window.setInterval(()=>{i++,e.textContent=s.slice(0,i),i>=s.length&&(window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t)},a);return()=>{window.clearInterval(o),e.classList.remove("is-typing"),e.innerHTML=t}}const tn={min:-1,max:-1,sum:-1,avg:-1,round:-1,ceil:1,floor:1,abs:1,sqrt:1,pow:2},xt={"+":{precedence:1,right:!1},"-":{precedence:1,right:!1},"*":{precedence:2,right:!1},"/":{precedence:2,right:!1},"%":{precedence:2,right:!1},"^":{precedence:4,right:!0}};function sn(n,e,t=[]){if(!n||!n.trim()||n.length>2e3)return null;const s=nn(n,e,t),a=ln(s);if(!a)return null;const i=dn(a);if(!i)return null;const o=hn(i);return o===null||!Number.isFinite(o)?null:o}function nn(n,e,t){return n.replace(/\{([a-zA-Z0-9_]+)(?:\.([a-zA-Z0-9_]+))?\}/g,(s,a,i,o)=>an(n,o,s.length,a,i??"",e,t))}function an(n,e,t,s,a,i,o){const l=rn(o,s),c=Object.prototype.hasOwnProperty.call(i,s)?i[s]:null;if(a===""){const u=l?.type==="repeater"?kt(c).length:We(c,l);return St(u)}const h=(l?.fields??[]).find(u=>u.id===a)??null,w=kt(c).map(u=>We(u[a]??"",h));if(!w.length)return"0";const _=w.map(St);return on(n,e,t)?_.join(", "):_.length===1?_[0]:`( ${_.join(" + ")} )`}function rn(n,e){for(const t of n){if(t.id===e)return t;for(const s of t.fields??[])if(s.id===e)return s}return null}function on(n,e,t){const s=n.slice(e+t).replace(/^\s+/,"");if(s===""||s[0]!==")")return!1;const a=n.slice(0,e).replace(/\s+$/,""),i=/([a-zA-Z_][a-zA-Z0-9_]*)\s*\($/.exec(a);return!!i&&["sum","avg","min","max"].includes(i[1].toLowerCase())}function kt(n){if(!Array.isArray(n))return[];const e=[];for(const t of n){if(!t||typeof t!="object"||Array.isArray(t))continue;Object.values(t).some(a=>a!==""&&a!==null&&a!==void 0&&a!==!1&&!(Array.isArray(a)&&!a.length))&&e.push(t)}return e}function St(n){const e=n.toFixed(10).replace(/0+$/,"").replace(/\.$/,"");return e===""||e==="-"?"0":e}function We(n,e){if(typeof n=="boolean")return n?1:0;if(Array.isArray(n))return n.reduce((a,i)=>a+We(i,e),0);if(n==null||n==="")return 0;const t=e?.choices??[];for(const a of t)if(String(a.value)===String(n)){if(typeof a.price=="number")return a.price;if(typeof a.points=="number")return a.points;break}const s=Number(n);return Number.isFinite(s)?s:0}function ln(n){const e=[];let t=0;for(;ti.precedence||l.precedence===i.precedence&&!i.right){e.push(t.pop());continue}break}t.push(a);break}case"(":t.push(a);break;case")":{for(;t.length&&t[t.length-1].type!=="(";)e.push(t.pop());if(!t.length)return null;if(t.pop(),t.length&&t[t.length-1].type==="function"){const i=t.pop();i.arity=s.length?s.pop():1,e.push(i)}break}}for(;t.length;){const a=t.pop();if(a.type==="(")return null;e.push(a)}return e}function hn(n){const e=[];for(const t of n)switch(t.type){case"number":e.push(t.value);break;case"unary":{if(!e.length)return null;e.push(-e.pop());break}case"operator":{if(e.length<2)return null;const s=e.pop(),a=e.pop();switch(t.value){case"+":e.push(a+s);break;case"-":e.push(a-s);break;case"*":e.push(a*s);break;case"/":e.push(s===0?0:a/s);break;case"%":e.push(s===0?0:a%s);break;case"^":e.push(Math.pow(a,s));break;default:return null}break}case"function":{const s=t.arity??1;if(e.lengtht+s,0);case"avg":return e.reduce((t,s)=>t+s,0)/e.length;case"round":{const t=Math.max(-10,Math.min(10,Math.trunc(e[1]??0))),s=Math.pow(10,t);return Math.round(e[0]*s)/s}case"ceil":return Math.ceil(e[0]);case"floor":return Math.floor(e[0]);case"abs":return Math.abs(e[0]);case"sqrt":return e[0]<0?0:Math.sqrt(e[0]);case"pow":return Math.pow(e[0],e[1]??2);default:return null}}const pn=["sum","min","max","avg","round","ceil","floor","abs","sqrt","pow"],Lt=["number","range","scale","rating","total","select","multiselect","radio","checkboxes","switch","quiz"];function Ue(n,e){return n.filter(t=>t.id!==e&&Lt.includes(t.type))}function fn(n){const e=[];for(const t of n){if(t.type!=="repeater")continue;const s=t.label||t.id;e.push({label:`${s} (how many)`,insert:`{${t.id}}`});for(const a of t.fields??[])Lt.includes(a.type)&&e.push({label:`${s} · ${a.label||a.id}`,insert:`{${t.id}.${a.id}}`})}return e}function mn(n,e){const t={};Ue(n,e).forEach((s,a)=>{t[s.id]=a+1});for(const s of n){if(s.type!=="repeater"||s.id===e)continue;const a=s.fields??[],i=o=>Object.fromEntries(a.map((l,c)=>[l.id,c+1+o]));t[s.id]=[i(0),i(1)]}return t}function bn(n){const e=r("div",{class:"atfb-overlay"}),t=()=>{e.remove(),document.removeEventListener("keydown",s)},s=u=>{u.key==="Escape"&&t()},a=r("textarea",{class:"atfb-input atfb-formula__input",attrs:{rows:"3","aria-label":"Formula"}});a.value=String(n.field.formula??"");const i=r("p",{class:"atfb-formula__result",attrs:{"aria-live":"polite"}}),o=mn(n.fields,n.field.id),l=()=>{const u=a.value.trim();if(u===""){i.textContent="Empty. Reference a question below to start.",i.classList.remove("is-error");return}const b=sn(u,o,n.fields);if(b===null){i.textContent="This does not compute yet — check the braces and parentheses.",i.classList.add("is-error");return}const g=Ue(n.fields,n.field.id).map((p,x)=>`${p.label||p.id} = ${x+1}`).concat(n.fields.filter(p=>p.type==="repeater"&&p.id!==n.field.id).map(p=>`${p.label||p.id} = 2 sample rows`)).join(", ");i.textContent=`With sample answers (${g}): ${b}`,i.classList.remove("is-error")};a.addEventListener("input",l);const c=(u,b,g=0)=>r("button",{class:"atfb-formula__chip",type:"button",text:u,on:{click:()=>{if(ht(a,b),g>0){const p=(a.selectionStart??a.value.length)-g;a.setSelectionRange(p,p)}}}}),d=Ue(n.fields,n.field.id),h=fn(n.fields),w=r("div",{class:"atfb-formula__chips",children:d.length||h.length?[...d.map(u=>c(u.label||u.id,`{${u.id}}`)),...h.map(u=>c(u.label,u.insert))]:[r("p",{class:"atfb-hint",text:"No number-shaped questions yet — add a number, scale or priced choice field and it appears here."})]}),_=r("div",{class:"atfb-formula__chips",children:pn.map(u=>c(`${u}()`,`${u}()`,1))});e.append(r("div",{class:"atfb-modal atfb-formula",attrs:{role:"dialog","aria-label":"Formula editor"},children:[r("h2",{text:"Formula"}),a,i,y("Your questions",w,"Click one to reference its answer."),y("Functions",_),r("div",{class:"atfb-modal__actions",children:[$("Cancel",t),$("Save formula",()=>{n.onSave(a.value.trim()),t()},"primary")]})]})),e.addEventListener("click",u=>{u.target===e&&t()}),document.addEventListener("keydown",s),n.root.append(e),l(),a.focus(),a.setSelectionRange(a.value.length,a.value.length)}const gn="allterrain-forms/form";function vn(){return window.wp?.os?.relations??null}function Et(n){const e=n.closest("[data-window-id], .os-window");if(!e)return null;const t=e.getAttribute("data-window-id");if(t)return t;const s=e.id??"";return s?s.replace(/^wp-window-/,""):null}const yn=6e3,Ct=120;function $t(n,e){const t=vn();if(ze.set(n,e),!t?.set)return;const s=i=>{if(ye.get(n)!==a)return;const o=Et(n);if(!o){Date.now()s(i),Ct);return}try{t.set(o,e)}catch(c){At||(At=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",c,e)),ye.delete(n);return}if(!e||t.get?.(o)?.id===e.id||Date.now()>=i){ye.delete(n);return}window.setTimeout(()=>s(i),Ct)},a=Symbol("atf-identity");ye.set(n,a),s(Date.now()+yn)}let At=!1;const ye=new WeakMap,ze=new Map;function wn(){for(const[n,e]of ze){if(!n.isConnected){ze.delete(n);continue}$t(n,e)}}if(typeof document<"u")for(const n of["os-window-content-loaded","os-window-opened"])document.addEventListener(n,()=>wn());function _n(n,e){return{type:gn,id:n.id,label:n.title||"Untitled form",related:[{id:`allterrain-forms/entries-${n.id}`,label:"Entries for this form",url:`${e}admin.php?page=allterrain-forms-entries&form=${n.id}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-list-view"}]}}const we={letters:{label:"Letters",chars:"A-Za-zÀ-ÖØ-öø-ÿ"},numbers:{label:"Numbers",chars:"0-9"},spaces:{label:"Spaces",chars:" "},punctuation:{label:`Punctuation ( . , ! ? ' " - )`,chars:`.,!?'"()\\-:;`},symbols:{label:"Symbols ( @ # & _ / + )",chars:"@#&_/+*%="}};function xn(){return{mode:"blocks",starts:"",ends:"",contains:"",notContains:"",chars:[],minLen:"",maxLen:"",regex:"",message:"",tests:[]}}function Tt(n){const e=xn();let t;try{t=JSON.parse(n)}catch{return e}if(!t||typeof t!="object")return e;const s=t;e.mode=s.mode==="regex"?"regex":"blocks";for(const a of["starts","ends","contains","notContains","minLen","maxLen","regex","message"])typeof s[a]=="string"&&(e[a]=s[a]);return Array.isArray(s.chars)&&(e.chars=s.chars.filter(a=>typeof a=="string"&&a in we)),Array.isArray(s.tests)&&(e.tests=s.tests.filter(a=>typeof a=="string").slice(0,10)),e}function _e(n){return n.replace(/[.*+?^${}()|[\]\\/]/g,"\\$&")}function xe(n){if(n.mode==="regex")return n.regex.trim();const e=[],t=n.minLen.trim(),s=n.maxLen.trim();(t!==""||s!=="")&&e.push(`(?=.{${t===""?"0":parseInt(t,10)||0},${s===""?"":parseInt(s,10)||""}}$)`),n.contains!==""&&e.push(`(?=.*${_e(n.contains)})`),n.notContains!==""&&e.push(`(?!.*${_e(n.notContains)})`),n.starts!==""&&e.push(`(?=${_e(n.starts)})`),n.ends!==""&&e.push(`(?=.*${_e(n.ends)}$)`);const a=n.chars.map(o=>we[o]?.chars??"").join(""),i=a?`[${a}]*$`:".*$";return!e.length&&!a?"":`^${e.join("")}${i}`}function Mt(n){if(n.mode==="regex")return n.regex.trim()?`Matches the expression ${n.regex.trim()}`:"";const e=[];if(n.starts&&e.push(`starts with “${n.starts}”`),n.ends&&e.push(`ends with “${n.ends}”`),n.contains&&e.push(`contains “${n.contains}”`),n.notContains&&e.push(`never contains “${n.notContains}”`),n.chars.length){const i=n.chars.map(o=>(we[o]?.label??o).split(" (")[0].toLowerCase());e.push(`uses only ${i.join(" and ")}`)}const t=n.minLen.trim(),s=n.maxLen.trim();return t&&s?e.push(`is ${t}–${s} characters long`):t?e.push(`is at least ${t} characters long`):s&&e.push(`is at most ${s} characters long`),e.length?`The answer ${e.length>1?`${e.slice(0,-1).join(", ")}, and ${e[e.length-1]}`:e[0]}.`:""}function kn(n,e){const t=xe(n);if(t==="")return null;try{return new RegExp(t).test(e)}catch{return null}}function Sn(){return window.wp?.os?.windowManager??null}const Ft="allterrain-forms-validation";function Ln(n){const e=Sn(),t=Et(n.root);if(e?.openChild&&t){En(e,t,n);return}Cn(n)}function En(n,e,t){const s=`${Ft}-${t.field.id}`;n.getById?.(s)&&n.remove?.(s);const a={saved:!1},i=()=>{const o=n.getById?.(s);o?.close?o.close():n.remove?.(s)};n.openChild?.(e,{id:s,baseId:Ft,url:`#${s}`,title:`Custom rule — ${t.field.label||"this question"}`,icon:"dashicons-yes-alt",native:!0,width:560,height:700,minWidth:440,minHeight:480,ephemeral:!0,autofocus:".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea",render:o=>{const l=r("div",{class:"atfa atfb-valwin atfb-valwin--window"}),c=r("div",{class:"atfb-valwin__scroll"});l.append(c),It(c,t,a,i,"window");const d=c.querySelector(".atfb-modal__actions");d&&l.append(d),o.append(l)},onClose:()=>{a.saved||t.onCancel?.()}})}function Cn(n){const e=r("div",{class:"atfb-overlay"}),t={saved:!1},s=()=>{e.remove(),document.removeEventListener("keydown",a),t.saved||n.onCancel?.()},a=o=>{o.key==="Escape"&&s()},i=r("div",{class:"atfb-modal atfb-valwin",attrs:{role:"dialog","aria-label":"Custom validation rule"},children:[r("h2",{text:"Custom rule"})]});It(i,n,t,s,"overlay"),e.append(i),e.addEventListener("click",o=>{o.target===e&&s()}),document.addEventListener("keydown",a),n.root.append(e),e.querySelector(".atfb-valwin__pane:not([hidden]) input, .atfb-valwin__pane:not([hidden]) textarea")?.focus()}function It(n,e,t,s,a){const i=Tt(String(e.field.validationRecipe??""));i.mode==="blocks"&&xe(i)===""&&e.field.pattern&&(i.mode="regex",i.regex=String(e.field.pattern)),i.message||(i.message=String(e.field.messages?.invalid??""));const o=(f,M)=>{const C=r("input",{class:"atfb-input",value:i[f],placeholder:M,attrs:{type:"text"}});return C.addEventListener("input",()=>{i[f]=C.value,E()}),C},l=(f,M)=>{const C=r("input",{class:"atfb-input atfb-valwin__len",value:i[f],attrs:{type:"number",min:"0","aria-label":M}});return C.addEventListener("input",()=>{i[f]=C.value,E()}),C},c=r("div",{class:"atfb-valwin__chars",children:Object.entries(we).map(([f,M])=>O(M.label,i.chars.includes(f),C=>{i.chars=C?[...i.chars,f]:i.chars.filter(j=>j!==f),E()}))}),d=r("div",{class:"atfb-valwin__pane",children:[y("Starts with",o("starts","e.g. AT-")),y("Ends with",o("ends","e.g. -2026")),y("Must contain",o("contains","e.g. @")),y("Must not contain",o("notContains","e.g. spaces? type one")),y("Only these characters",c,"Leave every box unticked to allow anything."),y("Length",r("div",{class:"atfb-valwin__lengths",children:[r("span",{text:"between"}),l("minLen","Minimum length"),r("span",{text:"and"}),l("maxLen","Maximum length"),r("span",{text:"characters"})]}),"Leave a box empty for no limit.")]}),h=r("textarea",{class:"atfb-input atfb-valwin__regex",attrs:{rows:"2","aria-label":"Regular expression",placeholder:"^AT-[0-9]{4}$"}});h.value=i.regex,h.addEventListener("input",()=>{i.regex=h.value,E()});const w=r("div",{class:"atfb-valwin__pane",children:[y("Expression",h,"A regular expression, without slashes. Checked against the whole answer only if you anchor it with ^ and $.")]}),_=[["blocks","Easy blocks"],["regex","Expression (advanced)"]],u=f=>{i.mode=f,d.hidden=f!=="blocks",w.hidden=f!=="regex",E()},g=(()=>{if(Y("os-segmented")&&Y("os-segment")){const C=document.createElement("os-segmented");C.setAttribute("value",i.mode),C.setAttribute("label","How to write the rule"),C.classList.add("atfb-valwin__tabs");for(const[j,B]of _){const oe=document.createElement("os-segment");oe.setAttribute("value",j),oe.textContent=B,C.append(oe)}return C.addEventListener("os-pick",j=>{const B=j.detail?.value;(B==="blocks"||B==="regex")&&(C.setAttribute("value",B),u(B))}),C}const f=r("div",{class:"atfb-valwin__tabs",attrs:{role:"tablist"}}),M=()=>{f.replaceChildren(..._.map(([C,j])=>{const B=i.mode===C;return r("button",{class:`atfb-valwin__tab${B?" is-active":""}`,type:"button",text:j,attrs:{role:"tab","aria-selected":B?"true":"false"},on:{click:()=>{u(C),M()}}})}))};return M(),f})();d.hidden=i.mode!=="blocks",w.hidden=i.mode!=="regex";const p=r("input",{class:"atfb-input",value:i.message,placeholder:"That is not in the expected format.",attrs:{type:"text"}});p.addEventListener("input",()=>{i.message=p.value});const x=r("p",{class:"atfb-valwin__summary",attrs:{"aria-live":"polite"}}),I=r("div",{class:"atfb-valwin__samples"}),S=f=>{const M=r("span",{class:"atfb-valwin__verdict",attrs:{"aria-live":"polite"}}),C=r("input",{class:"atfb-input",value:f,placeholder:"Type a sample answer…",attrs:{type:"text"}});C.addEventListener("input",()=>E()),I.append(r("div",{class:"atfb-valwin__sample",children:[C,M]}))};for(const f of i.tests.length?i.tests:["","",""])S(f);const H=()=>Array.from(I.querySelectorAll("input")).map(f=>f.value),E=()=>{const f=Mt(i);x.textContent=f||"Nothing yet — fill in a block above and the rule appears here in plain words.";for(const M of Array.from(I.querySelectorAll(".atfb-valwin__sample"))){const C=M.querySelector("input"),j=M.querySelector(".atfb-valwin__verdict");if(!C||!j)continue;const B=C.value===""?null:kn(i,C.value);j.textContent=B===null?"·":B?"✓ passes":"✗ fails",j.classList.toggle("is-pass",B===!0),j.classList.toggle("is-fail",B===!1)}};n.append(r("p",{class:"atfb-hint",text:`Describe what a good answer to “${e.field.label||"this question"}” looks like — no code needed.`}),g,d,w,r("div",{class:"atfb-valwin__try",children:[r("h3",{text:"Try it out"}),x,I,$("Add another sample",()=>{S(""),E()},"ghost","plus-alt2")]}),y("When it fails, say",p,"Shown to the visitor when their answer breaks the rule. Leave empty for the default wording."),r("div",{class:"atfb-modal__actions",children:[$(a==="window"?"Close without saving":"Cancel",s),$("Save rule",()=>{const f=xe(i);i.tests=H().filter(M=>M!=="").slice(0,10),t.saved=!0,e.onSave({pattern:f,recipe:i,message:i.message.trim()}),s()},"primary")]})),E()}const $n=["Contact","Numbers & codes","Text shape","Web"],Dt=[{slug:"email",label:"An email address",group:"Contact",example:"jane@example.com",pattern:"^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$",message:"That does not look like an email address."},{slug:"phone",label:"A phone number",group:"Contact",example:"+34 612 345 678",pattern:"^(?=(?:[^0-9]*[0-9]){5,})\\+?[0-9 ().-]{5,24}$",message:"That does not look like a phone number."},{slug:"handle",label:"A username or @handle",group:"Contact",example:"@yourname",pattern:"^@?[A-Za-z0-9_]{2,30}$",message:"That does not look like a username."},{slug:"digits",label:"Numbers only",group:"Numbers & codes",example:"12345",pattern:"^[0-9]+$",message:"Numbers only, please."},{slug:"decimal",label:"A number, decimals allowed",group:"Numbers & codes",example:"3.14",pattern:"^-?[0-9]+([.,][0-9]+)?$",message:"That does not look like a number."},{slug:"price",label:"A price",group:"Numbers & codes",example:"19.99",pattern:"^[0-9]+([.,][0-9]{1,2})?$",message:"That does not look like a price."},{slug:"zip_us",label:"A ZIP code (US)",group:"Numbers & codes",example:"90210",pattern:"^[0-9]{5}(-[0-9]{4})?$",message:"That does not look like a ZIP code."},{slug:"postcode_uk",label:"A postcode (UK)",group:"Numbers & codes",example:"SW1A 1AA",pattern:"^[A-Za-z]{1,2}[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}$",message:"That does not look like a postcode."},{slug:"iban",label:"An IBAN",group:"Numbers & codes",example:"DE89 3704 0044 0532 0130 00",pattern:"^[A-Za-z]{2}[0-9]{2}(?: ?[A-Za-z0-9]){10,32}$",message:"That does not look like an IBAN."},{slug:"credit_card",label:"A card number",group:"Numbers & codes",example:"4242 4242 4242 4242",pattern:"^[0-9](?:[0-9 -]{9,21})?[0-9]$",message:"That does not look like a card number.",luhn:!0},{slug:"letters",label:"Letters only",group:"Text shape",example:"María López",pattern:"^[\\p{L}\\p{M} .'’-]+$",message:"Letters only, please."},{slug:"alphanumeric",label:"Letters and numbers only",group:"Text shape",example:"abc123",pattern:"^[A-Za-z0-9]+$",message:"Letters and numbers only, please."},{slug:"no_spaces",label:"One word, no spaces",group:"Text shape",example:"one-word",pattern:"^\\S+$",message:"No spaces allowed."},{slug:"url",label:"A web address",group:"Web",example:"https://example.com",pattern:"^(https?://)?([A-Za-z0-9-]+\\.)+[A-Za-z]{2,}([/?#]\\S*)?$",message:"That does not look like a web address."},{slug:"ip",label:"An IP address",group:"Web",example:"192.168.0.1",pattern:"^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$",message:"That does not look like an IP address."},{slug:"slug",label:"A URL slug",group:"Web",example:"my-page-title",pattern:"^[a-z0-9]+(-[a-z0-9]+)*$",message:"Lowercase letters, numbers and dashes only."},{slug:"hex_color",label:"A hex colour",group:"Web",example:"#3366ff",pattern:"^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$",message:"That does not look like a colour code."}];function An(n){return Dt.find(e=>e.slug===n)??null}function Ye(){return window.wp?.os??null}const qt="allterrain-forms/preview",Ge="allterrain-forms-preview";function Tn(n){const e=Ye();if(!e?.registerTitleBarButton)return()=>{};const t=()=>{try{e.registerTitleBarButton({id:qt,label:"Preview this form",icon:"dashicons-visibility",placement:"right",order:90,match:s=>{const a=s?.id??s?.config?.id??"";return a==="allterrain-forms"||a.startsWith("allterrain-forms#")},onClick:()=>void Ot(n),owner:"allterrain-forms-builder"})}catch{}};return e.ready?e.ready(t):t(),()=>{try{e.unregisterTitleBarButton?.(qt)}catch{}}}async function Ot(n){n.isDirty()&&await n.save();const e=n.current();e&&Nt(e.id,e.title,e.previewUrl)}function Nt(n,e,t){const s=Ye();if(!s?.windowManager?.open){window.open(t,"_blank","noopener");return}s.windowManager.open({id:`${Ge}-${n}`,baseId:Ge,url:t,title:`Preview: ${e}`,icon:"dashicons-visibility"})}function Mn(n,e,t){if(!Ye()?.windowManager?.open||!document.querySelector(`[data-window-id="${Ge}-${n}"]`))return;const i=t.includes("?")?"&":"?";Nt(n,e,`${t}${i}alltfo_r=${Date.now()}`)}const se="allterrain-forms/field",Fn=["openstation/file","desktop-mode/file","openstation/attachment"],Rt="allterrain-forms/logic-map-v2";function J(n,e){return n.dataset.atfbBind=e,n}const Pt={level:{key:"level",label:"Heading level",control:"select",hint:"Headings should step down one at a time.",options:[{value:"2",label:"Heading 2"},{value:"3",label:"Heading 3"},{value:"4",label:"Heading 4"},{value:"5",label:"Heading 5"},{value:"6",label:"Heading 6"}]},content:{key:"content",label:"HTML",control:"textarea",hint:"Shown as written. Scripts are stripped when the form is saved."},consenttext:{key:"consentText",label:"What they are agreeing to",control:"textarea",hint:"Shown beside the tick box. Links are allowed."},height:{key:"height",label:"Height",control:"number",hint:"In pixels."},columns:{key:"columns",label:"Columns",control:"number",hint:"How many pictures sit side by side."},multiple:{key:"multiple",label:"Let them choose more than one",control:"checkbox"},inline:{key:"inline",label:"Lay the options out in a row",control:"checkbox"},other:{key:"other",label:"Offer an “Other” box",control:"checkbox",hint:"Adds a final option with a box to type in."},filetypes:{key:"filetypes",label:"Accepted file types",control:"commas",hint:"Extensions, separated by commas. Empty accepts anything the site allows."},maxsize:{key:"maxsize",label:"Largest file",control:"number",hint:"In megabytes."},maxfiles:{key:"maxfiles",label:"How many files",control:"number"},minrows:{key:"minRows",label:"Fewest rows",control:"number",also:{key:"maxRows",label:"Most rows"}},itemlabel:{key:"itemLabel",label:"What is one row called?",control:"text",hint:"Names each card — “Attendee 1”, “Attendee 2” — and the Remove button. Also editable on the card itself."},endlabels:{key:"minLabel",label:"Label at the low end",control:"text",also:{key:"maxLabel",label:"Label at the high end"}},points:{key:"points",label:"Points if correct",control:"number"},minchoices:{key:"minChoices",label:"Fewest they may pick",control:"number",also:{key:"maxChoices",label:"Most they may pick"}}},In={label:"the canvas edits it in place, and the inspector mirrors it",placeholder:"edited by typing into the control on the canvas",hint:"edited under the control on the canvas",nextlabel:"edited on the page break’s own Next button",prevlabel:"edited on the page break’s own Back button",addlabel:"edited on the repeater’s own Add button",choices:"the choices editor, and the option list on the canvas",required:"the toggle on the card",width:"its own row",css:"its own row",prefill:"its own section",logic:"the conditional logic section",formula:"its own row, with the currency that goes with it",currency:"rendered with the formula",correct:"the choices editor marks the right answer",default:"its own row, typed to match what the field stores",rows:"a row count on a textarea; the statement list on a Likert matrix",parts:"a tick box per part, listed by the server",min:"the validation section, paired with max",max:"the validation section, paired with min",step:"the validation section",minlength:"the validation section, paired with maxlength",maxlength:"the validation section, paired with minlength",mindate:"the validation section, paired with maxdate",maxdate:"the validation section, paired with mindate",mintime:"the validation section, paired with maxtime",maxtime:"the validation section, paired with mintime",pattern:"the validation section",unique:"the validation section",maxchoices:"rendered with minchoices",maxrows:"rendered with minrows"};function Bt(n,e,t){const s=n[e.key],a=i=>t(e.key,i);if(e.control==="checkbox")return O(e.label,!!s,a);if(e.control==="commas"){const i=Array.isArray(s)?s:[];return y(e.label,T(i.join(", "),o=>{a(o.split(",").map(l=>l.trim().replace(/^\./,"").toLowerCase()).filter(Boolean))}),e.hint)}return e.control==="select"?y(e.label,D(String(s??""),e.options??[],a),e.hint):e.control==="textarea"?y(e.label,ue(String(s??""),a),e.hint):e.control==="number"?y(e.label,G(String(s??""),a),e.hint):y(e.label,J(T(String(s??""),a),e.key),e.hint)}function Ht(n,e){const t=new Set(n.map(a=>a.key).filter(Boolean));let s=n.length+1;return e.split(` +`).map(a=>a.trim()).filter(Boolean).map((a,i)=>{const o=n[i]?.key;if(o)return{key:o,label:a};for(;t.has(`r${s}`);)s+=1;return t.add(`r${s}`),{key:`r${s}`,label:a}})}function jt(n,e,t){const s=n.findIndex(i=>i.id===e);if(s<0)return null;const a=Math.max(0,Math.min(t,n.length-1));return a===s?null:{from:s,to:a}}const Xe=[{value:"user:email",label:"Their email address",group:"About the person filling it in",tag:"{user:email}"},{value:"user:display_name",label:"Their name",group:"About the person filling it in",tag:"{user:display_name}"},{value:"user:first_name",label:"Their first name",group:"About the person filling it in"},{value:"user:last_name",label:"Their last name",group:"About the person filling it in"},{value:"user:login",label:"Their username",group:"About the person filling it in"},{value:"date:today",label:"Today’s date",group:"The date and time",tag:"{date}"},{value:"date:now",label:"The time right now",group:"The date and time",tag:"{time}"},{value:"site",label:"This site’s name",group:"About this site",tag:"{site}"},{value:"site:url",label:"This site’s address",group:"About this site",tag:"{site:url}"},{value:"site:admin_email",label:"The site administrator’s email",group:"About this site",tag:"{admin_email}"}],Dn=["About the person filling it in","The date and time","About this site"],Ze=(n,e)=>W?.i18n?.[n]??e;class Wt{constructor(e){this.config=null,this.themes=[],this.forms=[],this.form=null,this.schema=null,this.selected=null,this.tab="build",this.logicMap=null,this.canvasTheme=r("style"),this.canvasThemeSignature="",this.openSections=new Map,this.logicMapOn=is(Rt)!=="off",this.dirty=!1,this.editGeneration=0,this.saveInFlight=!1,this.queuedSave=null,this.teardowns=[],this.canvasTarget=null,this.history=[],this.historyAt=-1,this.autosave=$e(()=>{this.save(!0)},2500),this.renderInspector=as(()=>{if(N(this.inspector),!this.schema||(this.root.classList.toggle("atfb--build-only-panes",this.tab!=="build"),this.tab!=="build"))return;const t=this.selected?this.locateField(this.selected):void 0,s=t?.field,a=t?.parent??null;if(this.root.classList.toggle("atfb--has-selection",!!s),!s){this.inspector.append(r("div",{class:"atfb-placeholder",children:[r("p",{text:"Select a field to change it."}),r("p",{class:"atfb-hint",text:"Drag a field from the palette, or press one to add it to the end."})]}));return}const i=this.config?.fieldTypes.find(c=>c.type===s.type),o=i?.supports??[],l=(c,d)=>{const h=this.liveField(s.id);h&&(h[c]=d,this.markDirty(),this.renderCanvas())};this.inspector.append(r("h3",{class:"atfb-inspector__title",text:i?.label??s.type})),a?this.inspector.append(r("p",{class:"atfb-hint atfb-inspector__crumb",text:`Inside ${a.label||"a repeater"} — the visitor answers this once per ${String(a.itemLabel??"")||"row"}.`}),r("p",{class:"atfb-hint",text:`Formulas aggregate it as {${a.id}.${s.id}} — e.g. sum( {${a.id}.${s.id}} ).`})):this.inspector.append(r("p",{class:"atfb-hint",text:`Reference this field as {field:${s.id}}`})),o.includes("label")&&this.inspector.append(y("Label",J(T(s.label,c=>l("label",c)),"label"))),o.includes("placeholder")&&this.inspector.append(y("Placeholder",J(T(s.placeholder,c=>l("placeholder",c)),"placeholder"))),o.includes("hint")&&this.inspector.append(y("Hint",J(T(s.hint,c=>l("hint",c)),"hint"),"Shown under the field, and read out with it.")),o.includes("nextlabel")&&this.inspector.append(y("Next button",J(T(String(s.nextLabel??""),c=>l("nextLabel",c)),"nextLabel"),"Leave empty for “Next”.")),o.includes("prevlabel")&&this.inspector.append(y("Back button",J(T(String(s.prevLabel??""),c=>l("prevLabel",c)),"prevLabel"),"Leave empty for “Back”.")),o.includes("addlabel")&&this.inspector.append(y("Add button",J(T(String(s.addLabel??""),c=>l("addLabel",c)),"addLabel"),"Leave empty for “Add another”.")),o.includes("required")&&this.inspector.append(O("Required",s.required,c=>l("required",c))),o.includes("width")&&this.inspector.append(y("Width",D(s.width,[{value:"full",label:"Full width"},{value:"two-thirds",label:"Two thirds"},{value:"half",label:"Half"},{value:"third",label:"One third"},{value:"quarter",label:"One quarter"}],c=>l("width",c)))),i?.choices&&this.inspector.append(this.renderChoicesEditor(s,l)),this.renderTypeSettings(s,i,o,l),(s.type==="total"||o.includes("formula"))&&this.inspector.append(y("Formula",r("div",{class:"atfb-formula__row",children:[T(String(s.formula??""),c=>l("formula",c)),$("Formula editor",()=>bn({root:this.root,fields:this.schema?.fields??[],field:s,onSave:c=>{l("formula",c),this.renderInspector()}}))]}),"Reference answers with braces — {f1} * {f2} + 10 — or open the editor and click them in."),y("Currency symbol",T(String(s.currency??""),c=>l("currency",c)))),this.inspector.append(this.renderValidationSection(s,o,l)),a||(this.inspector.append(this.renderLogicSection(s)),o.includes("prefill")&&this.inspector.append(this.prefillControl(s,l))),o.includes("css")&&this.inspector.append(y("CSS class",T(s.cssClass,c=>l("cssClass",c))))}),this.root=e,this.bar=e.querySelector("[data-atfb-bar]")??r("div"),this.palette=e.querySelector("[data-atfb-palette]")??r("div"),this.canvas=e.querySelector("[data-atfb-canvas]")??r("div"),this.inspector=e.querySelector("[data-atfb-inspector]")??r("div"),this.canvas.addEventListener("click",t=>{const s=t.target;if(!(this.tab!=="build"||!this.selected||s.closest("[data-atfb-card], button, os-button, a, input, textarea, select, os-select, label, [contenteditable]"))){this.selected=null;for(const a of this.canvas.querySelectorAll(".atfb-card.is-selected"))a.classList.remove("is-selected");this.renderInspector()}})}async start(){try{const[s,a,i]=await Promise.all([F.config(),F.listThemes(),F.listForms()]);this.config=s,this.themes=a,this.forms=i}catch(s){this.fail(s);return}this.teardowns.push(Jt([se])),this.teardowns.push(Tn({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)}));const e=s=>{this.dirty&&(s.preventDefault(),s.returnValue="")};window.addEventListener("beforeunload",e),this.teardowns.push(()=>window.removeEventListener("beforeunload",e));const t=s=>{!(s.metaKey||s.ctrlKey)||s.key.toLowerCase()!=="z"||s.target?.closest("input, textarea, [contenteditable]")||(s.preventDefault(),this.travel(s.shiftKey?1:-1))};if(this.root.addEventListener("keydown",t),this.teardowns.push(()=>this.root.removeEventListener("keydown",t)),this.renderBar(),this.renderPalette(),this.forms.length){const s=ms("builder");await this.open(s&&this.forms.some(a=>a.id===s)?s:this.forms[0].id)}else this.renderFormsList()}destroy(){this.canvasTarget?.(),this.canvasTarget=null,this.teardowns.forEach(e=>e()),this.teardowns=[]}fail(e){N(this.bar),this.bar.append(r("p",{class:"atfb-error",text:e instanceof Error?e.message:"Something went wrong loading your forms."}))}renderBar(){N(this.bar);const e=D(String(this.form?.id??""),[...this.forms.map(a=>({value:String(a.id),label:a.title||"(untitled)"}))],a=>void this.open(Number(a)));e.setAttribute("aria-label","Choose a form");const t=r("input",{class:"atfb-title",type:"text",value:this.form?.title??"",placeholder:"Untitled form",attrs:{"aria-label":"Form title"},on:{input:a=>{this.form&&(this.form.title=a.target.value,this.markDirty())}}}),s=r("div",{class:"atfb-tabs",attrs:{role:"tablist"},children:[["build","Build"],["theme","Theme"],["settings","Settings"],["notify","Notifications"],["confirm","Confirmations"]].map(([a,i])=>r("button",{class:`atfb-tab${this.tab===a?" is-active":""}`,type:"button",text:i,attrs:{role:"tab","aria-selected":this.tab===a},on:{click:()=>{this.tab=a,this.renderBar(),this.renderInspector(),this.renderCanvas()}}}))});this.bar.append(r("div",{class:"atfb-bar__left",children:[this.forms.length>1?e:null,t]}),s,r("div",{class:"atfb-bar__right",children:[this.historyButton("undo","Undo",-1),this.historyButton("redo","Redo",1),$("New",()=>void this.showTemplates(),"secondary","plus-alt2"),$("Export",()=>void this.exportForm(),"secondary","download"),$("Import",()=>void this.importForm(),"secondary","upload"),$("Preview",()=>void this.preview(),"secondary","visibility"),$("Entries",()=>this.openEntries(),"secondary","list-view"),this.logicMapButton(),this.saveButton()]}))}liveField(e){return this.locateField(e)?.field}locateField(e){const t=this.schema?.fields??[];for(let s=0;sthis.rebindCanvas(),{once:!0});return}this.renderCanvas()}snapshot(){if(!this.schema)return;const e=JSON.stringify(this.schema);this.history[this.historyAt]!==e&&(this.history=this.history.slice(0,this.historyAt+1),this.history.push(e),this.history.length>60&&this.history.shift(),this.historyAt=this.history.length-1,this.syncHistoryButtons())}travel(e){const t=this.historyAt+e;!this.schema||t<0||t>=this.history.length||(this.historyAt=t,this.schema=JSON.parse(this.history[t]),this.schema.fields.some(s=>s.id===this.selected)||(this.selected=null),this.markDirty(),this.renderBar(),this.renderCanvas(),this.renderInspector())}historyButton(e,t,s){const a=$(t,()=>this.travel(s),"secondary",e);return a.setAttribute("data-atfb-history",String(s)),a.disabled=!this.canTravel(s),a}canTravel(e){const t=this.historyAt+e;return t>=0&&tURL.revokeObjectURL(s),1e3)}async importForm(){const e=r("input",{type:"file",attrs:{accept:"application/json,.json"}});e.addEventListener("change",async()=>{const t=e.files?.[0];if(t)try{const s=JSON.parse(await t.text());if(!s.schema)throw new Error("That file does not contain a form.");const a=await F.createForm({title:s.title??t.name.replace(/\.json$/i,""),schema:s.schema});this.forms.unshift({id:a.id,title:a.title,status:a.status,modified:a.modified,fields:a.schema.fields.length,theme:a.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:a.shortcode}),this.form=a,this.schema=a.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),R("Form imported",a.title)}catch(s){R("Could not import that file",s instanceof Error?s.message:"","error")}}),e.click()}saveButton(){const e=$("Save",()=>void this.save(),"primary");return e.disabled=!this.dirty,e.setAttribute("data-atfb-save",""),e}markDirty(){this.dirty=!0,this.editGeneration+=1;const e=this.bar.querySelector("[data-atfb-save]");e&&(e.disabled=!1),this.autosave()}async save(e=!1){if(!this.form||!this.schema)return;if(this.saveInFlight){this.queuedSave={silent:e&&(this.queuedSave?.silent??!0)};return}this.saveInFlight=!0;const t=this.editGeneration;try{const s=await F.updateForm(this.form.id,{title:this.form.title,schema:this.schema});if(t===this.editGeneration){this.form=s,this.schema=s.schema,this.dirty=!1,this.rebindCanvas();const i=this.bar.querySelector("[data-atfb-save]");i&&(i.disabled=!0)}Ms(s.id);const a=this.forms.find(i=>i.id===s.id);a&&(a.title=s.title),Mn(s.id,s.title,s.previewUrl),e||R("Form saved",s.title)}catch(s){R(Ze("saveFailed","Could not save"),s instanceof Error?s.message:"","error")}finally{this.saveInFlight=!1;const s=this.queuedSave;this.queuedSave=null,s&&this.save(s.silent)}}async openFormById(e){await this.open(e)}async open(e){if(!(this.dirty&&!await fe("You have unsaved changes. Discard them?"))){try{this.form=await F.getForm(e),this.schema=this.form.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot()}catch(t){this.fail(t);return}this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}}announceIdentity(){this.form&&$t(this.root,_n(this.form,W?.adminUrl??""))}async showTemplates(){if(!this.config)return;const e=r("div",{class:"atfb-overlay"}),t=i=>{i.key==="Escape"&&s()},s=()=>{e.remove(),document.removeEventListener("keydown",t)},a=r("div",{class:"atfb-templates",children:this.config.templates.map(i=>r("button",{class:"atfb-template",type:"button",on:{click:async()=>{s();try{const o=await F.createForm({template:i.slug});this.forms.unshift({id:o.id,title:o.title,status:o.status,modified:o.modified,fields:o.schema.fields.length,theme:o.schema.settings.theme,entries:0,unread:0,views:0,submissions:0,shortcode:o.shortcode}),this.form=o,this.schema=o.schema,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.snapshot(),this.renderBar(),this.renderCanvas(),this.renderInspector(),this.announceIdentity()}catch(o){R("Could not create the form",o instanceof Error?o.message:"","error")}}},children:[z(i.icon),r("strong",{text:i.label}),r("span",{text:i.description})]}))});e.append(r("div",{class:"atfb-modal",attrs:{role:"dialog","aria-label":"Start a new form"},children:[r("h2",{text:"Start a new form"}),a,this.archivedFormsSection(s),r("div",{class:"atfb-modal__actions",children:[$("Cancel",s)]})]})),e.addEventListener("click",i=>{i.target===e&&s()}),document.addEventListener("keydown",t),this.root.append(e),a.querySelector("button")?.focus()}archivedFormsSection(e){const t=r("div",{class:"atfb-archived"});return F.listArchivedForms().then(s=>{s.length&&t.append(r("h3",{class:"atfb-archived__title",text:"Or bring one back from the archive"}),...s.map(a=>r("div",{class:"atfb-archived__row",children:[r("div",{class:"atfb-archived__meta",children:[r("strong",{text:a.title||"(untitled)"}),r("span",{class:"atfb-hint",text:`${a.entries} ${a.entries===1?"entry":"entries"} · ${a.submissions} submissions · ${a.views} views`})]}),$("Restore",async()=>{try{const i=await F.unarchiveForm(a.id);e(),this.forms.unshift(i),R("Form restored",`${i.title||"(untitled)"} is back, with its entries and stats.`),await this.open(i.id)}catch(i){R("Could not restore the form",i instanceof Error?i.message:"","error")}},"secondary","undo")]})))}).catch(()=>{}),t}renderFormsList(){N(this.canvas),this.canvas.append(r("div",{class:"atfb-empty",children:[r("h2",{text:"No forms yet"}),r("p",{text:"Start from a template, or build one from nothing."}),$("New form",()=>void this.showTemplates(),"primary","plus-alt2")]}))}openEntries(){const e=window.wp?.os;if(e?.openWindow){e.openWindow("allterrain-forms-entries");return}window.location.assign(`${W?.adminUrl??""}admin.php?page=allterrain-forms-entries`)}renderPalette(){if(!this.config)return;N(this.palette);const e=new Map;for(const s of this.config.fieldTypes){const a=e.get(s.group)??[];a.push(s),e.set(s.group,a)}const t=r("input",{class:"atfb-input atfb-palette__search",type:"search",placeholder:"Search fields",attrs:{"aria-label":"Search field types"},on:{input:s=>{const a=s.target.value.toLowerCase().trim();this.palette.querySelectorAll(".atfb-chip").forEach(i=>{const o=(i.textContent??"").toLowerCase();i.hidden=a!==""&&!o.includes(a)}),this.palette.querySelectorAll(".atfb-group").forEach(i=>{const o=Array.from(i.querySelectorAll(".atfb-chip")).some(l=>!l.hidden);i.hidden=!o})}}});this.palette.append(t);for(const[s,a]of Object.entries(this.config.groups)){const i=e.get(s);i?.length&&this.palette.append(r("div",{class:"atfb-group",children:[r("h3",{class:"atfb-group__title",text:a}),r("div",{class:"atfb-group__items",children:i.map(o=>this.paletteChip(o))})]}))}}paletteChip(e){const t=r("button",{class:"atfb-chip",type:"button",title:e.description,attrs:{"data-atf-type":e.type},children:[z(e.icon),r("span",{text:e.label})]});return t.addEventListener("pointerdown",s=>{const a=r("div",{class:"atfb-chip atfb-chip--ghost",children:[z(e.icon),r("span",{text:e.label})]});Z().start({payload:Ee(se,t,{fieldType:e.type,isNew:!0},s,a),origin:s,onClickOnly:()=>this.addField(e.type)})}),t.addEventListener("click",s=>{Z().recentlyEndedDrag()&&s.preventDefault()}),t}renderCanvas(){if(N(this.canvas),!this.schema||!this.form){this.renderFormsList();return}if(this.tab!=="build"){this.canvas.append(this.renderTabCanvas());return}const e=r("div",{class:"atfb-canvas__list",attrs:{"data-atfb-list":""}});this.schema.fields.length||e.append(r("div",{class:"atfb-placeholder",text:Ze("emptyCanvas","Drag a field from the left to begin.")})),this.schema.fields.forEach((s,a)=>{e.append(this.renderFieldCard(s,a))});const t=r("div",{class:"atfb-canvas__inner",children:[r("p",{class:"atfb-shortcode",text:this.form.shortcode,title:"Paste this anywhere to place the form"}),e]});this.canvas.append(t),this.registerCanvasTarget(e),this.paintLogicMap(t),this.paintCanvasTheme()}prefillControl(e,t){const s=e.prefill.startsWith("query:"),a=Xe.some(_=>_.value===e.prefill),i=s?"query":a&&e.prefill||(e.prefill?"custom":""),o=r("div",{class:"atfb-prefill__detail"}),l=r("p",{class:"atfb-row__hint atfb-prefill__preview"}),c=_=>{if(o.replaceChildren(),l.replaceChildren(),_==="query"){const u=e.prefill.startsWith("query:")?e.prefill.slice(6):"";o.append(T(u,b=>{const g=b.trim();t("prefill",g?`query:${g}`:""),d(`query:${g}`)},"utm_source"),r("p",{class:"atfb-row__hint",text:"The name of the parameter in the link people arrive on."}))}_==="custom"&&o.append(T(e.prefill,u=>{t("prefill",u),d(u)},"myplugin:something"),r("p",{class:"atfb-row__hint",text:"For a source another plugin has added through alltfo_resolve_prefill."})),d(e.prefill)},d=_=>{if(l.replaceChildren(),!_)return;if(_.startsWith("query:")){const b=_.slice(6);b&&(l.textContent=`A visit to …/your-page/?${b}=abc opens the form with “abc” in it.`);return}const u=Xe.find(b=>b.value===_)?.tag;u&&qe(this.form?.id??0).then(b=>{for(const g of b)for(const p of g.items)if(p.tag===u){const x=_.startsWith("user:");if(!p.sample){l.textContent="Empty unless the visitor is signed in.";return}l.textContent=x?`Opens with “${p.sample}” for you — empty for a visitor who is not signed in.`:`Opens with “${p.sample}”.`;return}})};c(i);const h=r("select",{class:"atfb-input atfb-select",on:{change:_=>{const u=_.target.value;t("prefill",u==="query"||u==="custom"?"":u),c(u)}}});h.append(r("option",{value:"",text:"Nothing — leave it empty",attrs:{selected:i===""}}));for(const _ of Dn){const u=document.createElement("optgroup");u.label=_;for(const b of Xe.filter(g=>g.group===_))u.append(r("option",{value:b.value,text:b.label,attrs:{selected:b.value===i}}));h.append(u)}const w=document.createElement("optgroup");return w.label="From the link they arrived on",w.append(r("option",{value:"query",text:"A parameter in the web address",attrs:{selected:i==="query"}})),h.append(w,r("option",{value:"custom",text:"Something else (advanced)",attrs:{selected:i==="custom"}})),y("Pre-fill this with",r("div",{class:"atfb-prefill",children:[h,o,l]}),"What the box already contains when the form opens. They can still change it.")}renderCondition(e,t){const s=t.some(i=>i.kind==="field"&&i.missing),a=r("span",{class:`atfb-cond${s?" is-broken":""}`,attrs:{"aria-label":rt(t)},children:[z("randomize"),...t.map(i=>this.renderConditionToken(e,i))]});return a.addEventListener("pointerdown",i=>i.stopPropagation()),a.addEventListener("click",i=>i.stopPropagation()),a.addEventListener("keydown",i=>i.stopPropagation()),a}editCondition(e,t,s=!0,a=""){const i=this.liveField(e)?.logic;if(i){if(t(i),this.markDirty(),!s){this.logicMap?.setEdges(me(this.schema?.fields??[]));return}this.renderCanvas(),this.renderInspector(),a&&window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-cond="${CSS.escape(a)}"]`)?.focus()})}}condSelect(e,t,s,a,i){if(Y("os-select")&&Y("os-option")){const o=document.createElement("os-select");o.setAttribute("value",e),o.setAttribute("aria-label",a),o.setAttribute("data-cond",s),o.className="atfb-cond__control",o.title=a;for(const l of t){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,o.append(c)}return o.addEventListener("os-pick",l=>{i(String(l.detail?.value??""))}),o}return r("select",{class:"atfb-cond__control atfb-cond__control--native",title:a,attrs:{"aria-label":a,"data-cond":s},on:{change:o=>i(o.target.value)},children:t.map(o=>r("option",{value:o.value,text:o.label,attrs:{selected:o.value===e}}))})}renderConditionToken(e,t){if(t.kind==="field"&&!t.missing)return r("button",{class:"atfb-cond__chip atfb-cond__chip--field",type:"button",text:t.text,title:"Go to this question",on:{click:a=>{a.stopPropagation(),this.selectField(t.fieldId),this.canvas.querySelector(`[data-atfb-card="${CSS.escape(t.fieldId)}"]`)?.scrollIntoView({block:"nearest",behavior:"smooth"})}}});if(t.kind==="verb")return r("button",{class:"atfb-cond__verb",type:"button",text:t.text,title:"Switch between showing and hiding this field when the condition matches.",attrs:{"data-cond":`${e.id}:verb`},on:{click:()=>this.editCondition(e.id,s=>{s.action=s.action==="hide"?"show":"hide"},!0,`${e.id}:verb`)}});if(t.kind==="join")return r("button",{class:"atfb-cond__join",type:"button",text:t.text,title:"Switch between needing every rule (and) or any one of them (or).",attrs:{"data-cond":`${e.id}:join`},on:{click:()=>this.editCondition(e.id,s=>{s.match=s.match==="all"?"any":"all"},!0,`${e.id}:join`)}});if(t.kind==="operator"){const s=`${e.id}:op:${t.ruleIndex}`;return this.condSelect(t.operator,Object.entries(Te).map(([a,i])=>({value:a,label:i})),s,"How the answer is compared",a=>this.editCondition(e.id,i=>{const o=i.rules[t.ruleIndex];o&&(o.operator=a)},!0,s))}return t.kind==="value"?this.renderConditionValue(e,t):r("span",{class:"atfb-cond__chip atfb-cond__chip--missing",text:t.text})}renderConditionValue(e,t){const s=`${e.id}:value:${t.ruleIndex}`,a=this.schema?.fields.find(c=>c.id===t.sourceId),i=(c,d)=>this.editCondition(e.id,h=>{const w=h.rules[t.ruleIndex];w&&(w.value=c)},d,s);if(a?.choices?.length){const c=a.choices.map(d=>({value:d.value,label:d.label||d.value}));return t.raw!==""&&!a.choices.some(d=>d.value===t.raw)&&c.unshift({value:t.raw,label:t.text}),this.condSelect(t.raw,c,s,"The answer that triggers this",d=>i(d,!0))}const o=["number","range","scale","rating","total"].includes(a?.type??""),l=r("input",{class:"atfb-cond__chip atfb-cond__chip--value atfb-cond__value",value:t.raw,title:"The answer that triggers this. Edit it here.",attrs:{type:"text","aria-label":"The answer that triggers this","data-cond":s,inputmode:o?"decimal":void 0,size:String(Math.max(2,Math.min(24,t.raw.length||2)))}});return l.addEventListener("input",()=>{l.size=Math.max(2,Math.min(24,l.value.length||2)),i(l.value,!1)}),l.addEventListener("change",()=>i(l.value,!0)),l.addEventListener("keydown",c=>{c.key==="Enter"&&(c.preventDefault(),i(l.value,!0))}),l}section(e,t,s,a=!1){const i=r("details",{class:"atfb-section",attrs:{open:this.openSections.get(e)??a},children:[r("summary",{text:t}),...s]});return i.addEventListener("toggle",()=>this.openSections.set(e,i.open)),i}logicMapButton(){const e=me(this.schema?.fields??[]).length>0,t=$(this.logicMapOn?"Hide logic":"Show logic",()=>{this.logicMapOn=!this.logicMapOn,rs(Rt,this.logicMapOn?"on":"off"),this.renderBar(),this.renderCanvas()},this.logicMapOn?"primary":"secondary","randomize");return t.title="Draw a line from each question to the ones it decides.",t.hidden=!e,t}paintLogicMap(e){this.logicMap?.destroy(),this.logicMap=null;const t=this.schema?.fields??[],s=me(t);if(!s.length||!this.logicMapOn)return;e.classList.add("has-logicmap");const a=new ws(e);a.setEdges(s),a.highlight(this.selected??""),this.logicMap=a,e.addEventListener("pointerover",i=>{const o=i.target.closest("[data-atfb-card]");a.highlight(o?.dataset.atfbCard??this.selected??"")}),e.addEventListener("pointerleave",()=>a.highlight(this.selected??""))}renderFieldCard(e,t){const s=this.config?.fieldTypes.find(d=>d.type===e.type),a=this.selected===e.id,i=this.schema?.fields??[],o=gs(e,i),l=ys(i).get(e.id)??0,c=r("div",{class:`atfb-card${a?" is-selected":""}`,attrs:{"data-atfb-card":e.id,"data-index":t,tabindex:"0",role:"button","aria-pressed":a,"aria-label":`${e.label||s?.label||e.type}, ${t+1} of ${this.schema?.fields.length??0}`},children:[r("div",{class:"atfb-card__bar",children:[r("div",{class:"atfb-card__grip",attrs:{"aria-hidden":"true"},children:[z("menu")]}),r("div",{class:"atfb-card__head",children:[z(s?.icon??"dashicons-forms"),r("span",{class:"atfb-card__type",text:s?.label??e.type}),this.requiredToggle(e),l?r("span",{class:"atfb-badge atfb-badge--controls",text:l===1?"controls 1 field":`controls ${l} fields`,title:"Other questions appear or disappear based on this answer."}):null]}),r("div",{class:"atfb-card__actions",children:[this.cardAction("admin-page","Duplicate",()=>this.duplicateField(e.id)),this.cardAction("trash","Delete",()=>void this.deleteField(e.id))]})]}),r("div",{class:"atfb-card__body",children:[dt(e,s,{edit:d=>{const h=this.liveField(e.id);if(!h)return;d(h),this.markDirty(),this.syncInspector(h);const w=this.selected?this.locateField(this.selected):void 0;w?.parent&&w.parent.id===h.id&&this.syncInspector(w.field)},restructure:d=>{const h=this.liveField(e.id);h&&(this.snapshot(),d(h),this.markDirty(),this.renderCanvas(),this.renderInspector())},types:d=>this.config?.fieldTypes.find(h=>h.type===d),selectedId:this.selected}),o.length?this.renderCondition(e,o):null]})]});return c.addEventListener("click",d=>{d.target.closest(".atfb-card__actions")||Z().recentlyEndedDrag()||this.selectField(e.id)}),c.addEventListener("keydown",d=>{if(d.key==="Enter"||d.key===" "){d.preventDefault(),this.selectField(e.id);return}d.altKey&&(d.key==="ArrowUp"||d.key==="ArrowDown")&&(d.preventDefault(),this.moveField(e.id,d.key==="ArrowUp"?t-1:t+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})),(d.key==="Delete"||d.key==="Backspace")&&(d.preventDefault(),this.deleteField(e.id))}),c.addEventListener("pointerdown",d=>{d.target.closest(".atfb-card__actions")||Z().start({payload:Ee(se,c,{fieldId:e.id,field:e,isNew:!1},d),origin:d})}),c}requiredToggle(e){return r("button",{class:`atfb-req${e.required?" is-on":""}`,type:"button",text:e.required?"Required":"Optional",title:e.required?"This must be answered. Click to make it optional.":"Click to make this required.",attrs:{"aria-pressed":e.required?"true":"false"},on:{pointerdown:s=>s.stopPropagation(),click:s=>{s.stopPropagation(),e.required=!e.required,this.markDirty(),this.renderCanvas(),this.renderInspector()}}})}cardAction(e,t,s){return r("button",{class:"atfb-card__action",type:"button",title:t,attrs:{"aria-label":t},on:{click:a=>{a.stopPropagation(),s()}},children:[z(e)]})}gapAnimator(e,t,s,a){const i=r("div",{class:"atfb-marker",attrs:{"aria-hidden":"true"}});let o=null,l=null,c=0;const d=()=>{i.remove(),l?.classList.remove("atfb-lifted"),l=null,o=null},h=u=>{const b=Array.from(e.querySelectorAll(t)),g=new Map(b.filter(x=>!x.classList.contains("atfb-lifted")).map(x=>[x,x.getBoundingClientRect().top]));u();for(const x of b)x.style.transition="none",x.style.transform="";const p=b.filter(x=>{const I=g.get(x);if(I===void 0||!x.isConnected||x.classList.contains("atfb-lifted"))return!1;const S=I-x.getBoundingClientRect().top;return Math.abs(S)<.5?!1:(x.style.transform=`translateY(${S}px)`,!0)});e.offsetHeight;for(const x of b){if(!p.includes(x)){x.style.transition="";continue}x.style.transition="transform 160ms ease",x.style.transform="",x.addEventListener("transitionend",()=>{x.style.transition=""},{once:!0})}},w=u=>{const b=u.detail;if(b?.payload?.type!==se||!e.classList.contains("is-dropping")||a&&!a(b.payload.data??{}))return;const g=b.payload.data?.fieldId,p=typeof g=="string"?s(g):null,x=Je(e,t,b.clientY??0,p??void 0);x===o&&i.isConnected||(o=x,h(()=>{p&&p!==l&&(l?.classList.remove("atfb-lifted"),p.classList.add("atfb-lifted"),l=p),i.style.blockSize=`${Math.max(8,Math.round(c))}px`;const I=Array.from(e.querySelectorAll(t)).filter(S=>S!==p);x>=I.length?e.append(i):I[x].before(i)}))},_=()=>{e.classList.remove("is-dropping"),window.setTimeout(()=>h(d),0)};return document.addEventListener("os.drag.move",w),document.addEventListener("os.drag.end",_),{enter:u=>{const b=u?s(u):null;c=b&&!b.classList.contains("atfb-lifted")?b.getBoundingClientRect().height:c||44},leave:()=>h(d),drop:(u,b)=>{const g=o??Je(e,t,u,b??void 0);return d(),g},teardown:()=>{document.removeEventListener("os.drag.move",w),document.removeEventListener("os.drag.end",_),d()}}}registerCanvasTarget(e){this.canvasTarget?.(),this.canvasTarget=null;const t=this.gapAnimator(e,".atfb-card",i=>this.canvas.querySelector(`[data-atfb-card="${CSS.escape(i)}"]`)),s=Z().registerDropTarget({id:`atfb-canvas-${this.form?.id??0}`,element:e,accept:i=>i.type===se,onEnter:i=>{e.classList.add("is-dropping"),t.enter(i.payload.data.fieldId)},onLeave:()=>{e.classList.remove("is-dropping"),t.leave()},onDrop:(i,o)=>{e.classList.remove("is-dropping");const l=i.payload.data,c=l.fieldId?this.canvas.querySelector(`[data-atfb-card="${CSS.escape(l.fieldId)}"]`):null,d=t.drop(o.clientY,c);if(l.isNew&&l.fieldType){this.addField(l.fieldType,d);return}if(l.fieldId&&this.locateField(l.fieldId)){this.relocateField(l.fieldId,null,d);return}l.field&&this.insertField({...l.field,id:""},d)}}),a=this.wireRepeaterZones(e);this.canvasTarget=()=>{s(),a.forEach(i=>i()),t.teardown()}}wireRepeaterZones(e){const t=[];return e.querySelectorAll("[data-atfb-repeater-zone]").forEach(s=>{const a=s.dataset.atfbRepeaterZone??"",i=l=>{const c=l;if(c.fieldId===a)return!1;const d=c.isNew?c.fieldType:this.locateField(c.fieldId??"")?.field.type??c.field?.type;return!!d&&this.allowedInRepeater(d)},o=this.gapAnimator(s,".atfb-subcard",l=>e.querySelector(`[data-atfb-subfield="${CSS.escape(l)}"]`),i);t.push(()=>o.teardown()),t.push(Z().registerDropTarget({id:`atfb-repzone-${this.form?.id??0}-${a}`,element:s,accept:l=>l.type===se&&i(l.data),onEnter:l=>{s.classList.add("is-dropping"),o.enter(l.payload.data.fieldId)},onLeave:()=>{s.classList.remove("is-dropping"),o.leave()},onDrop:(l,c)=>{s.classList.remove("is-dropping");const d=l.payload.data,h=d.fieldId?e.querySelector(`[data-atfb-subfield="${CSS.escape(d.fieldId)}"]`):null,w=o.drop(c.clientY,h);if(d.isNew&&d.fieldType){this.addFieldToRepeater(d.fieldType,a,w);return}if(d.fieldId&&this.locateField(d.fieldId)){this.relocateField(d.fieldId,a,w);return}d.field&&this.insertFieldIntoRepeater({...d.field,id:""},a,w)}})),s.querySelectorAll(".atfb-subcard").forEach(l=>{const c=l.dataset.atfbSubfield??"";l.addEventListener("click",d=>{d.target.closest(".atfb-preview__remove")||(d.stopPropagation(),!Z().recentlyEndedDrag()&&this.selectField(c))}),l.addEventListener("keydown",d=>{if(d.stopPropagation(),d.key==="Enter"||d.key===" "){d.preventDefault(),this.selectField(c);return}if(d.altKey&&(d.key==="ArrowUp"||d.key==="ArrowDown")){d.preventDefault();const h=this.locateField(c);h&&(this.relocateField(c,a,d.key==="ArrowUp"?h.index-1:h.index+1),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(c)}"]`)?.focus()}));return}(d.key==="Delete"||d.key==="Backspace")&&(d.preventDefault(),this.deleteField(c))}),l.addEventListener("pointerdown",d=>{if(d.stopPropagation(),d.target.closest(".atfb-preview__remove"))return;const h=this.locateField(c);h&&Z().start({payload:Ee(se,l,{fieldId:c,parentId:a,field:h.field,isNew:!1},d),origin:d})})})}),t}addField(e,t){const s=this.buildField(e);s&&this.insertField(s,t)}buildField(e){const t=this.config?.fieldTypes.find(a=>a.type===e);return!t||!this.schema?void 0:{id:this.nextFieldId(),type:e,label:t.input?t.label:"",placeholder:"",hint:"",required:!1,width:"full",cssClass:"",default:"",choices:t.choices?[{label:"First choice",value:"first"},{label:"Second choice",value:"second"}]:[],logic:{enabled:!1,action:"show",match:"all",rules:[]},messages:{},prefill:"",...t.settings}}allowedInRepeater(e){const t=this.config?.fieldTypes.find(s=>s.type===e);return!t||!t.input?!1:!["repeater","page_break","file","signature","total"].includes(e)}addFieldToRepeater(e,t,s){if(!this.allowedInRepeater(e))return;const a=this.buildField(e);a&&this.insertFieldIntoRepeater(a,t,s)}insertFieldIntoRepeater(e,t,s){const a=this.liveField(t);if(!this.schema||!a||a.type!=="repeater")return;e.id||(e.id=this.nextFieldId()),this.snapshot(),Array.isArray(a.fields)||(a.fields=[]);const i=a.fields,o=s===void 0?i.length:Math.max(0,Math.min(s,i.length));i.splice(o,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-subfield="${CSS.escape(e.id)}"]`)?.focus()})}relocateField(e,t,s){if(!this.schema)return;const a=this.locateField(e);if(!a)return;if(!a.parent&&!t){this.moveField(e,s);return}const i=t?this.liveField(t):null;if(t&&(!i||i.type!=="repeater"||e===t))return;i&&!Array.isArray(i.fields)&&(i.fields=[]);const o=i?i.fields:this.schema.fields;this.snapshot(),a.list.splice(a.index,1);const l=Math.max(0,Math.min(s,o.length));o.splice(l,0,a.field),this.selected=a.field.id,this.markDirty(),this.renderCanvas(),this.renderInspector()}insertField(e,t){if(!this.schema)return;e.id||(e.id=this.nextFieldId()),this.snapshot();const s=t===void 0?this.schema.fields.length:Math.max(0,Math.min(t,this.schema.fields.length));this.schema.fields.splice(s,0,e),this.selected=e.id,this.markDirty(),this.renderCanvas(),this.renderInspector(),window.requestAnimationFrame(()=>{this.canvas.querySelector(`[data-atfb-card="${CSS.escape(e.id)}"]`)?.focus()})}moveField(e,t){if(!this.schema)return;const s=jt(this.schema.fields,e,t);if(!s)return;this.snapshot();const[a]=this.schema.fields.splice(s.from,1);this.schema.fields.splice(s.to,0,a),this.markDirty(),this.renderCanvas()}duplicateField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=JSON.parse(JSON.stringify(t.field)),a=this.usedFieldIds(),i=()=>{let o=a.size+1;for(;a.has(`f${o}`);)o++;const l=`f${o}`;return a.add(l),l};s.id=i();for(const o of s.fields??[])o.id=i();if(t.parent){this.snapshot(),t.list.splice(t.index+1,0,s),this.selected=s.id,this.markDirty(),this.renderCanvas(),this.renderInspector();return}this.insertField(s,t.index+1)}async deleteField(e){if(!this.schema)return;const t=this.locateField(e);if(!t)return;const s=this.schema.fields.filter(i=>i.logic?.rules?.some(o=>o.field===e)),a=s.length?`Delete this field? ${s.length} other field${s.length===1?"":"s"} use it in a condition, and those conditions will stop working.`:Ze("confirmDelete","Delete this? It cannot be undone.");await fe(a,"Delete field")&&(this.snapshot(),t.list.splice(t.index,1),this.selected===e&&(this.selected=null),this.markDirty(),this.renderCanvas(),this.renderInspector())}selectField(e){this.selected=e;for(const t of this.canvas.querySelectorAll("[data-atfb-card]")){const s=t.dataset.atfbCard===e;t.classList.toggle("is-selected",s),t.setAttribute("aria-pressed",s?"true":"false")}for(const t of this.canvas.querySelectorAll("[data-atfb-subfield]"))t.classList.toggle("is-selected",t.dataset.atfbSubfield===e);this.logicMap?.highlight(e),this.renderInspector()}nextFieldId(){const e=this.usedFieldIds();let t=e.size+1;for(;e.has(`f${t}`);)t++;return`f${t}`}usedFieldIds(){const e=new Set;for(const t of this.schema?.fields??[]){e.add(t.id);for(const s of t.fields??[])e.add(s.id)}return e}nextEntryId(e,t){const s=new Set(t.map(i=>i.id));let a=t.length+1;for(;s.has(`${e}${a}`);)a++;return`${e}${a}`}renderTypeSettings(e,t,s,a){for(const i of s){const o=Pt[i];o&&(this.inspector.append(Bt(e,o,a)),o.also&&this.inspector.append(Bt(e,{...o,key:o.also.key,label:o.also.label,hint:o.also.hint},a)))}s.includes("rows")&&e.type!=="likert"&&this.inspector.append(y("Lines tall",G(String(e.rows??""),i=>a("rows",i)))),s.includes("rows")&&e.type==="likert"&&this.inspector.append(this.renderStatementList(e,a)),s.includes("parts")&&this.inspector.append(this.renderPartsEditor(e,t,a)),s.includes("default")&&!["files","object"].includes(t?.value??"")&&this.inspector.append(this.renderDefaultControl(e,t,a))}renderStatementList(e,t){const s=Array.isArray(e.rows)?e.rows:[];return y("Statements",ue(s.map(a=>a.label??"").join(` +`),a=>t("rows",Ht(s,a)),5),"One per line. Each becomes a row of the matrix.")}renderPartsEditor(e,t,s){const a=t?.parts??[],i=Array.isArray(e.parts)?e.parts:a.map(l=>l.key),o=a.map(l=>O(l.label,i.includes(l.key),c=>{const d=a.map(h=>h.key).filter(h=>h===l.key?c:i.includes(h));s("parts",d.length?d:[l.key])}));return r("div",{class:"atfb-section",children:[r("h4",{class:"atfb-section__title",text:"Parts to ask for"}),...o]})}renderDefaultControl(e,t,s){const a="Filled in before they start. They can change it.";return e.type==="switch"||e.type==="consent"?O("On by default",!!e.default,i=>s("default",i)):t?.choices&&(e.choices??[]).length?y("Default answer",D(String(e.default??""),[{value:"",label:"Nothing chosen"},...(e.choices??[]).map(i=>({value:String(i.value),label:i.label||String(i.value)}))],i=>s("default",i)),a):y("Default answer",T(String(e.default??""),i=>s("default",i)),a)}renderChoicesEditor(e,t){const s=e.choices??[],a=o=>this.liveField(e.id)?.choices?.[o],i=r("div",{class:"atfb-choices"});return s.forEach((o,l)=>{const c=r("div",{class:"atfb-choice-row",children:[e.type==="image_choice"?this.choiceImageWell(o,l,e):null,J(T(o.label,d=>{const h=a(l);if(!h)return;const w=!h.value||h.value===h.label;h.label=d,w&&(h.value=d),this.markDirty();const _=this.liveField(e.id);_&&this.syncCanvas(_)}),`choice:${l}:label`),J(T(o.value,d=>{const h=a(l);h&&(h.value=d,this.markDirty())},"value"),`choice:${l}:value`),e.type==="quiz"||o.points!==void 0?G(String(o.points??""),d=>{const h=a(l);h&&(h.points=d===""?void 0:Number(d),this.markDirty())}):G(String(o.price??""),d=>{const h=a(l);h&&(h.price=d===""?void 0:Number(d),this.markDirty())}),r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":`Remove ${o.label}`},on:{click:()=>{const d=this.liveField(e.id);d&&((d.choices??[]).splice(l,1),t("choices",d.choices),this.renderInspector())}},children:[z("trash")]})]});i.append(c)}),r("div",{class:"atfb-section",children:[r("h4",{text:"Choices"}),r("p",{class:"atfb-hint",text:e.type==="quiz"?"Label, value, points.":"Label, value, and a price for calculations."}),i,$("Add choice",()=>{const o=this.liveField(e.id);if(!o)return;const l=o.choices??[];l.push({label:"",value:""}),t("choices",l),this.renderInspector()},"ghost","plus-alt2"),e.type==="quiz"?y("Correct answer",D(String(e.correct??""),[{value:"",label:"—"},...s.map(o=>({value:o.value,label:o.label}))],o=>t("correct",o))):null]})}choiceImageWell(e,t,s){const a=r("div",{class:`atfb-well${e.image?" has-image":""}`,attrs:{"data-choice":t,"aria-label":`Image for ${e.label||`choice ${t+1}`}`},children:[e.image?r("span",{class:"atfb-well__id",text:`#${e.image}`}):z("format-image")]}),i=Z().registerDropTarget({id:`atfb-well-${s.id}-${t}`,element:a,accept:o=>Fn.includes(o.type),onEnter:()=>a.classList.add("is-dropping"),onLeave:()=>a.classList.remove("is-dropping"),onDrop:o=>{a.classList.remove("is-dropping");const l=o.payload.data,c=Number(l.attachmentId??l.id??l.file?.id??0);if(!c){R("That is not an image this field can use","","error");return}const d=this.liveField(s.id)?.choices?.[t];d&&(d.image=c,this.markDirty(),this.renderInspector())}});return this.teardowns.push(i),a.addEventListener("click",()=>{const o=this.liveField(s.id)?.choices?.[t];o?.image&&(o.image=void 0,this.markDirty(),this.renderInspector())}),a}renderValidationSection(e,t,s){const a=[],i=[];t.includes("minlength")&&i.push(["minlength","Minimum characters"],["maxlength","Maximum characters"]),t.includes("min")?i.push(["min","Minimum"],["max","Maximum"]):t.includes("max")&&i.push(["max","Highest"]),t.includes("step")&&i.push(["step","Steps of"]),t.includes("mindate")&&i.push(["minDate","Earliest date"],["maxDate","Latest date"]),t.includes("mintime")&&i.push(["minTime","Earliest time"],["maxTime","Latest time"]);for(const[l,c]of i)a.push(y(c,T(String(e[l]??""),d=>s(l,d))));t.includes("pattern")&&a.push(...this.renderAnswerShapeRows(e,s)),t.includes("unique")&&a.push(O("No two people may submit the same value",!!e.unique,l=>s("unique",l)));const o=e.messages??{};return t.includes("required")&&a.push(y("Message when required",T(o.required??"",l=>{o.required=l,s("messages",o)}),"Leave empty for the default wording.")),a.length?this.section(`validation:${e.id}`,"Validation",a):r("div",{class:"atfb-section is-empty"})}buildShapePicker(e,t){const s=[{heading:null,options:[{value:"",label:"Anything at all"}]},...$n.map(i=>({heading:i,options:Dt.filter(o=>o.group===i).map(o=>({value:o.slug,label:o.label}))})),{heading:"Your own",options:[{value:"custom",label:"A custom rule…"}]}];if(Y("os-select")&&Y("os-option")){const i=document.createElement("os-select");i.setAttribute("value",e),i.setAttribute("aria-label","What the answer should look like"),i.classList.add("atfb-field");for(const o of s){if(o.heading){const l=document.createElement("os-option");l.setAttribute("value",`__heading:${o.heading}`),l.setAttribute("disabled",""),l.textContent=o.heading,i.append(l)}for(const l of o.options){const c=document.createElement("os-option");c.setAttribute("value",l.value),c.textContent=l.label,i.append(c)}}return i.addEventListener("os-pick",o=>{t(String(o.detail?.value??""))}),i}const a=r("select",{class:"atfb-input atfb-select",attrs:{"aria-label":"What the answer should look like"},on:{change:i=>t(i.target.value)}});for(const i of s){const o=i.heading?(()=>{const l=document.createElement("optgroup");return l.label=i.heading,a.append(l),l})():a;for(const l of i.options)o.append(r("option",{value:l.value,text:l.label,attrs:{selected:l.value===e}}))}return a}renderAnswerShapeRows(e,t){const a=(typeof e.validation=="string"?e.validation:"")||(e.pattern?"custom":""),i=()=>Ln({root:this.root,field:this.liveField(e.id)??e,onSave:h=>{t("validation","custom"),t("pattern",h.pattern),t("validationRecipe",JSON.stringify(h.recipe));const w={...this.liveField(e.id)?.messages??{}};w.invalid=h.message,t("messages",w),this.renderInspector()},onCancel:()=>this.renderInspector()}),o=h=>{if(h==="custom"){i();return}t("validation",h),t("pattern",""),t("validationRecipe",""),this.renderInspector()},l=this.buildShapePicker(a,o),c=An(a),d=[y("The answer should be",l,c?`e.g. ${c.example}`:"Checked as they type, and again on the server.")];if(a==="custom"){const h=Tt(String(e.validationRecipe??"")),w=Mt(h)||(e.pattern?`Matches the expression ${String(e.pattern)}`:"No rule yet — open the builder.");d.push(y("Your rule",r("div",{class:"atfb-valrule",children:[r("p",{class:"atfb-valrule__words",text:w}),$("Edit the rule…",i,"secondary","edit")]}),xe(h)||e.pattern?"Built in the rule builder, with a playground to test it.":void 0))}return d}logicRulesEditor(e,t,s=""){const a=(this.schema?.fields??[]).filter(d=>d.id!==s&&d.type!=="page_break"),i=()=>r("div",{class:"atfb-rule-join",children:[r("button",{class:"atfb-rule-join__chip",type:"button",text:e.match==="all"?"and":"or",title:"Switch between needing every rule (and) or any one of them (or).",on:{click:()=>t(d=>{d.match=d.match==="all"?"any":"all"},!0)}})]}),o=(d,h)=>{const w=r("button",{class:"atfb-card__action",type:"button",attrs:{"aria-label":"Remove this rule"},title:"Remove this rule",on:{click:()=>t(u=>{u.rules.splice(h,1)},!0)},children:[z("trash")]}),_=[r("div",{class:"atfb-rule__top",children:[D(d.field,a.map(u=>({value:u.id,label:u.label||u.id})),u=>t(b=>{const g=b.rules[h];g&&(g.field=u,g.value="")},!0)),w]}),D(d.operator,Object.entries(this.config?.operators??{}).map(([u,b])=>({value:u,label:b})),u=>t(b=>{const g=b.rules[h];g&&(g.operator=u)},!0))];if(!Me.includes(d.operator)){const u=this.schema?.fields.find(b=>b.id===d.field);if(u?.choices?.length){const b=u.choices.map(g=>({value:g.value,label:g.label||g.value}));d.value!==""&&!u.choices.some(g=>g.value===d.value)&&b.unshift({value:d.value,label:d.value}),_.push(D(d.value,b,g=>t(p=>{const x=p.rules[h];x&&(x.value=g)})))}else _.push(T(d.value,b=>t(g=>{const p=g.rules[h];p&&(p.value=b)}),"The answer to compare against"))}return r("div",{class:"atfb-rule",children:_})},l=r("div",{class:"atfb-rules"});e.rules.forEach((d,h)=>{h>0&&l.append(i()),l.append(o(d,h))});const c=$("Add rule",()=>{t(d=>{d.rules.push({field:a[0]?.id??"",operator:"is",value:""})},!0)},"ghost","plus-alt2");return[l,c]}conditionsSection(e,t,s){const a=(o,l=!1)=>{o(s),this.markDirty(),l&&this.renderCanvas()},i=t==="confirmation"?"Use":"Send";return this.section(`conditions:${e}`,"Conditions",[O(`Only ${i.toLowerCase()} this ${t} sometimes`,s.enabled,o=>a(l=>{l.enabled=o},!0)),s.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[r("span",{text:`${i} it when`}),D(s.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...this.logicRulesEditor(s,a)]}):null],s.enabled)}renderLogicSection(e){const t=e.logic,s=()=>this.liveField(e.id)?.logic,a=(o,l=!1)=>{const c=s();c&&(o(c),this.markDirty(),this.renderCanvas(),l&&this.renderInspector())},i=this.logicRulesEditor(t,a,e.id);return this.section(`logic:${e.id}`,"Conditional logic",[O("Only show this field sometimes",t.enabled,o=>{a(l=>{l.enabled=o},!0)}),t.enabled?r("div",{children:[r("div",{class:"atfb-rule-head",children:[D(t.action,[{value:"show",label:"Show"},{value:"hide",label:"Hide"}],o=>a(l=>{l.action=o},!0)),r("span",{text:"this field when"}),D(t.match,[{value:"all",label:"all"},{value:"any",label:"any"}],o=>a(l=>{l.match=o},!0)),r("span",{text:"of these match:"})]}),...i]}):null],t.enabled)}renderTabCanvas(){return this.schema?this.tab==="theme"?mt({themes:this.themes,tokens:this.config?.tokens??[],activeSlug:this.schema.settings.theme,overrides:this.schema.settings.themeOverrides,onTheme:e=>{this.schema.settings.theme=e,this.markDirty()},onOverride:(e,t)=>{t===""?delete this.schema.settings.themeOverrides[e]:this.schema.settings.themeOverrides[e]=t,this.markDirty()},onOverridesReplaced:e=>{this.schema.settings.themeOverrides={...e},this.markDirty()},previewFor:(e,t)=>this.previewHtml(e,t),onThemesChanged:e=>{this.themes=e}}):this.tab==="settings"?this.renderSettingsPane():this.tab==="notify"?this.renderNotificationsPane():this.renderConfirmationsPane():r("div")}async paintCanvasTheme(){if(!this.form||!this.schema)return;const e=this.schema.settings.theme,t=JSON.stringify([e,this.schema.settings.themeOverrides]);if(t!==this.canvasThemeSignature){this.canvasThemeSignature=t;try{const s=await this.previewHtml(e,this.schema.settings.themeOverrides??{});this.root.classList.toggle("atfb--dark-form",/atf-is-dark/.test(s));const a=/class="atf-form-wrap"[^>]*\sstyle="([^"]*)"/.exec(s);if(!a)return;const i=a[1].replace(/"/g,'"').replace(/�?39;/g,"'").replace(/&/g,"&");this.canvasTheme.textContent=`.atfb .atfb-preview { ${i} -}`,this.canvasTheme.isConnected||this.root.append(this.canvasTheme)}catch{}}}async previewHtml(e,t){if(!this.form||!this.schema)return"";const s=JSON.parse(JSON.stringify(this.schema));s.settings.theme=e,s.settings.themeOverrides=t;const{html:a}=await I.preview(this.form.id,{schema:s,theme:e});return a}renderSettingsPane(){const e=this.schema.settings,t=(s,a)=>{const i=s.split(".");let o=e;for(let l=0;lt("submitLabel",s))),O("Submit without reloading the page",e.ajax,s=>t("ajax",s)),g("Progress indicator",D(e.progressBar,[{value:"steps",label:"Numbered steps"},{value:"bar",label:"A bar"},{value:"none",label:"None"}],s=>t("progressBar",s)),"Only shown on forms with a page break.")]}),r("section",{children:[r("h3",{text:"Who can fill this in"}),O("Only logged-in users",e.requireLogin,s=>t("requireLogin",s)),g("Message for everyone else",A(e.loginMessage,s=>t("loginMessage",s))),g("Open from",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.start,on:{input:s=>t("schedule.start",s.target.value)}})),g("Closes",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.end,on:{input:s=>t("schedule.end",s.target.value)}})),g("Message when closed",A(e.schedule.message,s=>t("schedule.message",s))),g("Stop after this many submissions",G(String(e.limit.total||""),s=>t("limit.total",Number(s)||0)),"0 means no limit."),g("Submissions per logged-in user",G(String(e.limit.perUser||""),s=>t("limit.perUser",Number(s)||0)))]}),r("section",{children:[r("h3",{text:"Spam"}),r("p",{class:"atfb-hint",text:"No captcha. Nothing here asks the visitor to prove anything."}),O("Honeypot field",e.spam.honeypot,s=>t("spam.honeypot",s)),g("Reject submissions faster than (seconds)",G(String(e.spam.timeTrap),s=>t("spam.timeTrap",Number(s)||0)),"A human cannot fill in a form in under a second. A script can."),g("Submissions allowed per hour, per address",G(String(e.spam.rateLimit),s=>t("spam.rateLimit",Number(s)||0))),g("Blocked words",ue(e.spam.blocklist,s=>t("spam.blocklist",s),4),"One per line."),O("Use Akismet when it is installed",e.spam.akismet,s=>t("spam.akismet",s)),O("Ask a simple sum before sending",e.spam.challenge,s=>t("spam.challenge",s)),r("p",{class:"atfb-hint",text:"Only for a form under sustained attack — it is the one check here that asks the visitor to do something. Still kinder than an image captcha: it is answerable by a screen reader, and it hands no data to anyone."})]}),r("section",{children:[r("h3",{text:"Storage and privacy"}),O("Keep entries",e.storage.entries,s=>t("storage.entries",s)),O("Record IP addresses",e.storage.ip,s=>t("storage.ip",s)),O("Anonymise recorded IP addresses",e.storage.anonymise,s=>t("storage.anonymise",s)),g("Delete entries after (days)",G(String(e.storage.retention||""),s=>t("storage.retention",Number(s)||0)),"0 keeps them forever. Anything else deletes automatically, every day.")]}),r("section",{children:[r("h3",{text:"Analytics"}),O("Count views and starts",e.analytics.enabled,s=>t("analytics.enabled",s)),O("Tally device, browser and system",e.analytics.tech,s=>t("analytics.tech",s)),r("p",{class:"atfb-hint",text:"Counters, never people: no cookie, no fingerprint, no per-visitor record — the tallies keep coarse classes like “phone” and “Chrome”, not the visitor’s user-agent string. Nothing here needs a consent banner. Turning the first switch off stops view and start counting entirely."})]}),r("section",{children:[r("h3",{text:"Save and continue later"}),O("Let people save a half-finished form",e.resume.enabled,s=>t("resume.enabled",s)),g("Keep a saved form for (days)",G(String(e.resume.days),s=>t("resume.days",Math.max(1,Number(s)||30)))),r("p",{class:"atfb-hint",text:"The link this creates is the only key to those answers — anyone holding it can read them. For genuinely sensitive questions, require login instead."})]}),r("section",{children:[r("h3",{text:"Archive"}),r("p",{class:"atfb-hint",text:"Retire the form when its moment has passed. It stops accepting responses and leaves every list, and its entries and stats go with it — nothing is deleted, and restoring it brings all of it back exactly as it was."}),E("Archive this form",()=>void this.archiveCurrentForm(),"secondary","archive")]})]})}async archiveCurrentForm(){if(!this.form)return;const e=this.form.title||"(untitled)",t=this.forms.find(a=>a.id===this.form.id)?.entries??0;if(await fe(`Archive “${e}”? It stops accepting responses and leaves every list — its ${t} ${t===1?"entry":"entries"} and its stats go with it. Nothing is deleted: restore it any time from “Start a new form”.`,"Archive form"))try{if(this.dirty&&await this.save(!0),await I.archiveForm(this.form.id),R("Form archived",`${e} — restore it any time from the New form dialog.`),this.forms=this.forms.filter(a=>a.id!==this.form.id),this.form=null,this.schema=null,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.forms.length){await this.open(this.forms[0].id);return}this.renderBar(),this.renderCanvas(),this.renderInspector()}catch(a){R("Could not archive the form",a instanceof Error?a.message:"","error")}}taggableInput(e,t,s=""){return ut(A(e,t,s),{formId:this.form.id})}taggableArea(e,t,s=6){return ut(ue(e,t,s),{formId:this.form.id})}recipientControl(e){const t=this.schema.fields.filter(c=>c.type==="email"),s=c=>{if(c.trim()==="{admin_email}")return"admin";const d=c.trim().match(/^\{field:([a-z0-9_-]+)\}$/i);return d&&t.some(h=>h.id===d[1])?`field:${d[1]}`:/\{/.test(c)?"custom":"address"},a=[{value:"admin",label:"Whoever runs this site"},...t.map(c=>({value:`field:${c.id}`,label:`The person who filled it in — ${c.label||"their email answer"}`})),{value:"address",label:"A specific email address"},{value:"custom",label:"Something else (advanced)"}],i=s(e.to),o=r("div",{class:"atfb-recipient__detail"}),l=c=>{if(o.replaceChildren(),c==="address"){o.append(A(/\{/.test(e.to)?"":e.to,d=>{e.to=d,this.markDirty()},"name@example.com"));return}c==="custom"&&o.append(this.taggableInput(e.to,d=>{e.to=d,this.markDirty()},"{admin_email}, sales@example.com"),r("p",{class:"atfb-row__hint",text:"Separate several addresses with commas."}))};return l(i),g("Send it to",r("div",{class:"atfb-recipient",children:[D(i,a,c=>{c==="admin"?e.to="{admin_email}":c.startsWith("field:")?e.to=`{${c}}`:c==="address"&&(e.to=/\{/.test(e.to)?"":e.to),this.markDirty(),l(c)}),o]}),t.length?void 0:"Add an Email question on the Build tab to reply straight back to the visitor.")}renderNotificationsPane(){const e=this.schema.notifications,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, one email goes to the site administrator with every answer in it."})),e.forEach((s,a)=>{t.append(this.section(`notification:${s.id}`,s.name||`Notification ${a+1}`,[g("Name",A(s.name,i=>{s.name=i,this.markDirty()})),this.recipientControl(s),g("Reply to",this.taggableInput(s.replyTo,i=>{s.replyTo=i,this.markDirty()},"Leave empty to reply to you"),"Set this to the visitor’s email address and hitting Reply answers them directly."),g("Subject",this.taggableInput(s.subject,i=>{s.subject=i,this.markDirty()})),g("Message",this.taggableArea(s.message,i=>{s.message=i,this.markDirty()},8)),O("Attach uploaded files",s.attachFiles,i=>{s.attachFiles=i,this.markDirty()}),this.conditionsSection(s.id,"notification",s.logic),E("Delete this notification",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Notifications"}),t,E("Add a notification",()=>{e.push({id:this.nextEntryId("n",e),enabled:!0,name:"Notification",to:"{admin_email}",cc:"",bcc:"",replyTo:"",fromName:"",fromEmail:"",subject:"New submission",message:"{all_fields}",attachFiles:!1,logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}confirmationDetail(e){if(e.type==="message")return r("div",{children:[g("Message",this.taggableArea(e.message,i=>{e.message=i,this.markDirty()},5),"Insert an answer to greet them by name, or show back what they sent."),this.successDesigner(e)]});const t=g("Extra query parameters",this.taggableInput(e.query,i=>{e.query=i,this.markDirty()},"ref={entry:id}&name={field:f1}"),"Added to the address, so the page they land on can read them. Leave empty for none.");if(e.type==="redirect")return r("div",{children:[g("Web address",this.taggableInput(e.url,i=>{e.url=i,this.markDirty()},"https://example.com/thank-you"),"A full address, starting with https://."),t]});const s=r("div",{class:"atfb-pagepicker"}),a=i=>{s.replaceChildren(D(String(e.pageId||0),i,o=>{e.pageId=Number(o)||0,this.markDirty()}))};return a([{value:"0",label:"Loading pages…"}]),I.pages().then(i=>{a([{value:"0",label:"Choose a page…"},...i.map(o=>({value:String(o.id),label:o.title}))])}).catch(()=>{a([{value:"0",label:"Could not load the pages"}])}),g("Page",s,"They are sent to this page after submitting. Its own content is shown, not the form’s message.")}successDesigner(e){e.success=We(e.success);const t=e.success,s=r("div",{class:"atfb-success"}),a=[{key:"plain",label:"Plain",glyph:"¶",blurb:"Just the message."},{key:"simple",label:"Simple",glyph:"✓",blurb:"Check mark and a gentle fade."},{key:"minimal",label:"Minimalistic",glyph:"—",blurb:"Quiet type, generous space."},{key:"card",label:"Card",glyph:"🎫",blurb:"An elevated card that pops in."},{key:"check",label:"Check mark",glyph:"✔",blurb:"A big check draws itself."},{key:"confetti",label:"Confetti",glyph:"🎉",blurb:"Paper rains over the page."},{key:"fireworks",label:"Fireworks",glyph:"🎆",blurb:"The full night-sky show."},{key:"sparkles",label:"Sparkles",glyph:"✨",blurb:"Your emoji floats up around it."},{key:"typewriter",label:"Typewriter",glyph:"⌨",blurb:"Types itself out, letter by letter."}],i=()=>{const o=r("div",{class:"atfb-success__styles",attrs:{role:"radiogroup","aria-label":"Success screen style"},children:a.map(c=>r("button",{class:`atfb-success__style${t.style===c.key?" is-selected":""}`,type:"button",attrs:{role:"radio","aria-checked":t.style===c.key?"true":"false",title:c.blurb},children:[r("span",{class:"atfb-success__style-glyph",text:c.glyph}),r("span",{class:"atfb-success__style-label",text:c.label})],on:{click:()=>{t.style=c.key,this.markDirty(),i(),c.key!=="plain"&&this.previewSuccessScreen(e)}}}))}),l=[];t.style!=="plain"&&(l.push(g("Heading",this.taggableInput(t.title,c=>{t.title=c,this.markDirty()},"Thank you, {field:name}!"),"Shown above the message. Leave empty for none.")),["simple","card","confetti","fireworks","sparkles"].includes(t.style)&&l.push(g("Emoji",A(t.icon,c=>{t.icon=c,this.markDirty()},ve[t.style]||"🎉"),t.style==="sparkles"?"Also the particle that floats up — try 🎈 or ❤️.":"The badge above the heading.")),l.push(this.successAccentRow(t)),["confetti","fireworks","sparkles"].includes(t.style)&&l.push(g("Intensity",D(t.intensity,[{value:"low",label:"Calm"},{value:"medium",label:"Festive"},{value:"high",label:"Over the top"}],c=>{t.intensity=c,this.markDirty()}))),l.push(O("Offer to fill it in again",t.showButton,c=>{t.showButton=c,this.markDirty(),i()})),t.showButton&&l.push(g("Button label",A(t.buttonLabel,c=>{t.buttonLabel=c,this.markDirty()},"Fill it in again")))),s.replaceChildren(r("div",{class:"atfb-success__head",children:[r("h4",{text:"Success screen"}),E("Preview",()=>this.previewSuccessScreen(e),"ghost","controls-play")]}),o,...l)};return i(),s}successAccentRow(e){const t=r("input",{class:"atfb-success__accent",attrs:{type:"color","aria-label":"Accent colour"}});t.value=e.accent||"#3858e9";const s=E("Use the theme accent",()=>{e.accent="",t.value="#3858e9",s.style.display="none",this.markDirty()},"ghost");return s.style.display=e.accent?"":"none",t.addEventListener("input",()=>{e.accent=t.value,s.style.display="",this.markDirty()}),g("Accent",r("div",{class:"atfb-success__accent-row",children:[t,s]}),"Recolours the screen; the theme decides when left alone.")}previewSuccessScreen(e){const t=e.message||"Thank you. Your submission has been received.";let s=()=>{};const a=r("div",{class:"atfb-success-preview",attrs:{role:"dialog","aria-label":"Success screen preview","aria-modal":"true"}}),i=()=>{s(),a.remove(),document.removeEventListener("keydown",o)},o=h=>{h.key==="Escape"&&(h.stopPropagation(),i())},l=Zs(t,e.success,i),c=r("div",{class:"atfb-success-preview__stage atfb-preview atf-form",children:[l]}),d=()=>{s(),s=Ks(l,e.success)};a.append(c,r("div",{class:"atfb-success-preview__bar",children:[E("Replay",d,"secondary","controls-repeat"),E("Close",i,"primary")]})),a.addEventListener("click",h=>{h.target===a&&i()}),document.addEventListener("keydown",o),this.root.append(a),window.requestAnimationFrame(d)}renderConfirmationsPane(){const e=this.schema.confirmations,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, the form says thank you and stops."})),e.forEach((s,a)=>{const i=r("div",{class:"atfb-confirm__detail"}),o=()=>{i.replaceChildren(this.confirmationDetail(s))};o(),t.append(this.section(`confirmation:${s.id}`,s.name||`Confirmation ${a+1}`,[g("Name",A(s.name,l=>{s.name=l,this.markDirty()})),g("What happens",D(s.type,[{value:"message",label:"Show a message"},{value:"redirect",label:"Send them to a URL"},{value:"page",label:"Send them to a page"}],l=>{s.type=l,this.markDirty(),o()})),i,this.conditionsSection(s.id,"confirmation",s.logic),E("Delete this confirmation",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Confirmations"}),r("p",{class:"atfb-hint",text:"The first one whose conditions match is the one they see."}),t,E("Add a confirmation",()=>{e.push({id:this.nextEntryId("c",e),enabled:!0,name:"Confirmation",type:"message",message:"Thank you. Your submission has been received.",url:"",pageId:0,query:"",success:yt(),logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}async preview(){await Ot({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)})}}let ae=null,Ve=null;document.addEventListener("alltfo-open-form",n=>{const e=Number(n.detail?.formId??0);e&&ae?.openFormById(e)});function Je(){if(Ve?.isConnected)return;ae&&(ae.destroy(),ae=null,Ve=null);const n=document.querySelector("[data-atfb-root]:not([data-atfb-mounted])");n&&(n.dataset.atfbMounted="1",Ve=n,Te(n),ss().then(()=>{n.isConnected&&(ae=new Wt(n),ae.start())}))}function Ut(){Je(),ds()}return hs(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ut):Ut(),document.addEventListener("os-window-content-loaded",Je),ee.Builder=Wt,ee.SETTINGS_HANDLED_ELSEWHERE=Fn,ee.SETTING_CONTROLS=Rt,ee.fieldMove=jt,ee.mountBuilder=Je,ee.restatement=Ht,Object.defineProperty(ee,Symbol.toStringTag,{value:"Module"}),ee}({}); +}`,this.canvasTheme.isConnected||this.root.append(this.canvasTheme)}catch{}}}async previewHtml(e,t){if(!this.form||!this.schema)return"";const s=JSON.parse(JSON.stringify(this.schema));s.settings.theme=e,s.settings.themeOverrides=t;const{html:a}=await F.preview(this.form.id,{schema:s,theme:e});return a}renderSettingsPane(){const e=this.schema.settings,t=(s,a)=>{const i=s.split(".");let o=e;for(let l=0;lt("submitLabel",s))),O("Submit without reloading the page",e.ajax,s=>t("ajax",s)),y("Progress indicator",D(e.progressBar,[{value:"steps",label:"Numbered steps"},{value:"bar",label:"A bar"},{value:"none",label:"None"}],s=>t("progressBar",s)),"Only shown on forms with a page break.")]}),r("section",{children:[r("h3",{text:"Who can fill this in"}),O("Only logged-in users",e.requireLogin,s=>t("requireLogin",s)),y("Message for everyone else",T(e.loginMessage,s=>t("loginMessage",s))),y("Open from",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.start,on:{input:s=>t("schedule.start",s.target.value)}})),y("Closes",r("input",{class:"atfb-input",type:"datetime-local",value:e.schedule.end,on:{input:s=>t("schedule.end",s.target.value)}})),y("Message when closed",T(e.schedule.message,s=>t("schedule.message",s))),y("Stop after this many submissions",G(String(e.limit.total||""),s=>t("limit.total",Number(s)||0)),"0 means no limit."),y("Submissions per logged-in user",G(String(e.limit.perUser||""),s=>t("limit.perUser",Number(s)||0)))]}),r("section",{children:[r("h3",{text:"Spam"}),r("p",{class:"atfb-hint",text:"No captcha. Nothing here asks the visitor to prove anything."}),O("Honeypot field",e.spam.honeypot,s=>t("spam.honeypot",s)),y("Reject submissions faster than (seconds)",G(String(e.spam.timeTrap),s=>t("spam.timeTrap",Number(s)||0)),"A human cannot fill in a form in under a second. A script can."),y("Submissions allowed per hour, per address",G(String(e.spam.rateLimit),s=>t("spam.rateLimit",Number(s)||0))),y("Blocked words",ue(e.spam.blocklist,s=>t("spam.blocklist",s),4),"One per line."),O("Use Akismet when it is installed",e.spam.akismet,s=>t("spam.akismet",s)),O("Ask a simple sum before sending",e.spam.challenge,s=>t("spam.challenge",s)),r("p",{class:"atfb-hint",text:"Only for a form under sustained attack — it is the one check here that asks the visitor to do something. Still kinder than an image captcha: it is answerable by a screen reader, and it hands no data to anyone."})]}),r("section",{children:[r("h3",{text:"Storage and privacy"}),O("Keep entries",e.storage.entries,s=>t("storage.entries",s)),O("Record IP addresses",e.storage.ip,s=>t("storage.ip",s)),O("Anonymise recorded IP addresses",e.storage.anonymise,s=>t("storage.anonymise",s)),y("Delete entries after (days)",G(String(e.storage.retention||""),s=>t("storage.retention",Number(s)||0)),"0 keeps them forever. Anything else deletes automatically, every day.")]}),r("section",{children:[r("h3",{text:"Analytics"}),O("Count views and starts",e.analytics.enabled,s=>t("analytics.enabled",s)),O("Tally device, browser and system",e.analytics.tech,s=>t("analytics.tech",s)),r("p",{class:"atfb-hint",text:"Counters, never people: no cookie, no fingerprint, no per-visitor record — the tallies keep coarse classes like “phone” and “Chrome”, not the visitor’s user-agent string. Nothing here needs a consent banner. Turning the first switch off stops view and start counting entirely."})]}),r("section",{children:[r("h3",{text:"Save and continue later"}),O("Let people save a half-finished form",e.resume.enabled,s=>t("resume.enabled",s)),y("Keep a saved form for (days)",G(String(e.resume.days),s=>t("resume.days",Math.max(1,Number(s)||30)))),r("p",{class:"atfb-hint",text:"The link this creates is the only key to those answers — anyone holding it can read them. For genuinely sensitive questions, require login instead."})]}),r("section",{children:[r("h3",{text:"Archive"}),r("p",{class:"atfb-hint",text:"Retire the form when its moment has passed. It stops accepting responses and leaves every list, and its entries and stats go with it — nothing is deleted, and restoring it brings all of it back exactly as it was."}),$("Archive this form",()=>void this.archiveCurrentForm(),"secondary","archive")]})]})}async archiveCurrentForm(){if(!this.form)return;const e=this.form.title||"(untitled)",t=this.forms.find(a=>a.id===this.form.id)?.entries??0;if(await fe(`Archive “${e}”? It stops accepting responses and leaves every list — its ${t} ${t===1?"entry":"entries"} and its stats go with it. Nothing is deleted: restore it any time from “Start a new form”.`,"Archive form"))try{if(this.dirty&&await this.save(!0),await F.archiveForm(this.form.id),R("Form archived",`${e} — restore it any time from the New form dialog.`),this.forms=this.forms.filter(a=>a.id!==this.form.id),this.form=null,this.schema=null,this.selected=null,this.dirty=!1,this.history=[],this.historyAt=-1,this.forms.length){await this.open(this.forms[0].id);return}this.renderBar(),this.renderCanvas(),this.renderInspector()}catch(a){R("Could not archive the form",a instanceof Error?a.message:"","error")}}taggableInput(e,t,s=""){return ut(T(e,t,s),{formId:this.form.id})}taggableArea(e,t,s=6){return ut(ue(e,t,s),{formId:this.form.id})}recipientControl(e){const t=this.schema.fields.filter(c=>c.type==="email"),s=c=>{if(c.trim()==="{admin_email}")return"admin";const d=c.trim().match(/^\{field:([a-z0-9_-]+)\}$/i);return d&&t.some(h=>h.id===d[1])?`field:${d[1]}`:/\{/.test(c)?"custom":"address"},a=[{value:"admin",label:"Whoever runs this site"},...t.map(c=>({value:`field:${c.id}`,label:`The person who filled it in — ${c.label||"their email answer"}`})),{value:"address",label:"A specific email address"},{value:"custom",label:"Something else (advanced)"}],i=s(e.to),o=r("div",{class:"atfb-recipient__detail"}),l=c=>{if(o.replaceChildren(),c==="address"){o.append(T(/\{/.test(e.to)?"":e.to,d=>{e.to=d,this.markDirty()},"name@example.com"));return}c==="custom"&&o.append(this.taggableInput(e.to,d=>{e.to=d,this.markDirty()},"{admin_email}, sales@example.com"),r("p",{class:"atfb-row__hint",text:"Separate several addresses with commas."}))};return l(i),y("Send it to",r("div",{class:"atfb-recipient",children:[D(i,a,c=>{c==="admin"?e.to="{admin_email}":c.startsWith("field:")?e.to=`{${c}}`:c==="address"&&(e.to=/\{/.test(e.to)?"":e.to),this.markDirty(),l(c)}),o]}),t.length?void 0:"Add an Email question on the Build tab to reply straight back to the visitor.")}renderNotificationsPane(){const e=this.schema.notifications,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, one email goes to the site administrator with every answer in it."})),e.forEach((s,a)=>{t.append(this.section(`notification:${s.id}`,s.name||`Notification ${a+1}`,[y("Name",T(s.name,i=>{s.name=i,this.markDirty()})),this.recipientControl(s),y("Reply to",this.taggableInput(s.replyTo,i=>{s.replyTo=i,this.markDirty()},"Leave empty to reply to you"),"Set this to the visitor’s email address and hitting Reply answers them directly."),y("Subject",this.taggableInput(s.subject,i=>{s.subject=i,this.markDirty()})),y("Message",this.taggableArea(s.message,i=>{s.message=i,this.markDirty()},8)),O("Attach uploaded files",s.attachFiles,i=>{s.attachFiles=i,this.markDirty()}),this.conditionsSection(s.id,"notification",s.logic),$("Delete this notification",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Notifications"}),t,$("Add a notification",()=>{e.push({id:this.nextEntryId("n",e),enabled:!0,name:"Notification",to:"{admin_email}",cc:"",bcc:"",replyTo:"",fromName:"",fromEmail:"",subject:"New submission",message:"{all_fields}",attachFiles:!1,logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}confirmationDetail(e){if(e.type==="message")return r("div",{children:[y("Message",this.taggableArea(e.message,i=>{e.message=i,this.markDirty()},5),"Insert an answer to greet them by name, or show back what they sent."),this.successDesigner(e)]});const t=y("Extra query parameters",this.taggableInput(e.query,i=>{e.query=i,this.markDirty()},"ref={entry:id}&name={field:f1}"),"Added to the address, so the page they land on can read them. Leave empty for none.");if(e.type==="redirect")return r("div",{children:[y("Web address",this.taggableInput(e.url,i=>{e.url=i,this.markDirty()},"https://example.com/thank-you"),"A full address, starting with https://."),t]});const s=r("div",{class:"atfb-pagepicker"}),a=i=>{s.replaceChildren(D(String(e.pageId||0),i,o=>{e.pageId=Number(o)||0,this.markDirty()}))};return a([{value:"0",label:"Loading pages…"}]),F.pages().then(i=>{a([{value:"0",label:"Choose a page…"},...i.map(o=>({value:String(o.id),label:o.title}))])}).catch(()=>{a([{value:"0",label:"Could not load the pages"}])}),y("Page",s,"They are sent to this page after submitting. Its own content is shown, not the form’s message.")}successDesigner(e){e.success=je(e.success);const t=e.success,s=r("div",{class:"atfb-success"}),a=[{key:"plain",label:"Plain",glyph:"¶",blurb:"Just the message."},{key:"simple",label:"Simple",glyph:"✓",blurb:"Check mark and a gentle fade."},{key:"minimal",label:"Minimalistic",glyph:"—",blurb:"Quiet type, generous space."},{key:"card",label:"Card",glyph:"🎫",blurb:"An elevated card that pops in."},{key:"check",label:"Check mark",glyph:"✔",blurb:"A big check draws itself."},{key:"confetti",label:"Confetti",glyph:"🎉",blurb:"Paper rains over the page."},{key:"fireworks",label:"Fireworks",glyph:"🎆",blurb:"The full night-sky show."},{key:"sparkles",label:"Sparkles",glyph:"✨",blurb:"Your emoji floats up around it."},{key:"typewriter",label:"Typewriter",glyph:"⌨",blurb:"Types itself out, letter by letter."}],i=()=>{const o=r("div",{class:"atfb-success__styles",attrs:{role:"radiogroup","aria-label":"Success screen style"},children:a.map(c=>r("button",{class:`atfb-success__style${t.style===c.key?" is-selected":""}`,type:"button",attrs:{role:"radio","aria-checked":t.style===c.key?"true":"false",title:c.blurb},children:[r("span",{class:"atfb-success__style-glyph",text:c.glyph}),r("span",{class:"atfb-success__style-label",text:c.label})],on:{click:()=>{t.style=c.key,this.markDirty(),i(),c.key!=="plain"&&this.previewSuccessScreen(e)}}}))}),l=[];t.style!=="plain"&&(l.push(y("Heading",this.taggableInput(t.title,c=>{t.title=c,this.markDirty()},"Thank you, {field:name}!"),"Shown above the message. Leave empty for none.")),["simple","card","confetti","fireworks","sparkles"].includes(t.style)&&l.push(y("Emoji",T(t.icon,c=>{t.icon=c,this.markDirty()},ve[t.style]||"🎉"),t.style==="sparkles"?"Also the particle that floats up — try 🎈 or ❤️.":"The badge above the heading.")),l.push(this.successAccentRow(t)),["confetti","fireworks","sparkles"].includes(t.style)&&l.push(y("Intensity",D(t.intensity,[{value:"low",label:"Calm"},{value:"medium",label:"Festive"},{value:"high",label:"Over the top"}],c=>{t.intensity=c,this.markDirty()}))),l.push(O("Offer to fill it in again",t.showButton,c=>{t.showButton=c,this.markDirty(),i()})),t.showButton&&l.push(y("Button label",T(t.buttonLabel,c=>{t.buttonLabel=c,this.markDirty()},"Fill it in again")))),s.replaceChildren(r("div",{class:"atfb-success__head",children:[r("h4",{text:"Success screen"}),$("Preview",()=>this.previewSuccessScreen(e),"ghost","controls-play")]}),o,...l)};return i(),s}successAccentRow(e){const t=r("input",{class:"atfb-success__accent",attrs:{type:"color","aria-label":"Accent colour"}});t.value=e.accent||"#3858e9";const s=$("Use the theme accent",()=>{e.accent="",t.value="#3858e9",s.style.display="none",this.markDirty()},"ghost");return s.style.display=e.accent?"":"none",t.addEventListener("input",()=>{e.accent=t.value,s.style.display="",this.markDirty()}),y("Accent",r("div",{class:"atfb-success__accent-row",children:[t,s]}),"Recolours the screen; the theme decides when left alone.")}previewSuccessScreen(e){const t=e.message||"Thank you. Your submission has been received.";let s=()=>{};const a=r("div",{class:"atfb-success-preview",attrs:{role:"dialog","aria-label":"Success screen preview","aria-modal":"true"}}),i=()=>{s(),a.remove(),document.removeEventListener("keydown",o)},o=h=>{h.key==="Escape"&&(h.stopPropagation(),i())},l=Zs(t,e.success,i),c=r("div",{class:"atfb-success-preview__stage atfb-preview atf-form",children:[l]}),d=()=>{s(),s=Ks(l,e.success)};a.append(c,r("div",{class:"atfb-success-preview__bar",children:[$("Replay",d,"secondary","controls-repeat"),$("Close",i,"primary")]})),a.addEventListener("click",h=>{h.target===a&&i()}),document.addEventListener("keydown",o),this.root.append(a),window.requestAnimationFrame(d)}renderConfirmationsPane(){const e=this.schema.confirmations,t=r("div",{class:"atfb-list"});return e.length||t.append(r("p",{class:"atfb-hint",text:"With none set up, the form says thank you and stops."})),e.forEach((s,a)=>{const i=r("div",{class:"atfb-confirm__detail"}),o=()=>{i.replaceChildren(this.confirmationDetail(s))};o(),t.append(this.section(`confirmation:${s.id}`,s.name||`Confirmation ${a+1}`,[y("Name",T(s.name,l=>{s.name=l,this.markDirty()})),y("What happens",D(s.type,[{value:"message",label:"Show a message"},{value:"redirect",label:"Send them to a URL"},{value:"page",label:"Send them to a page"}],l=>{s.type=l,this.markDirty(),o()})),i,this.conditionsSection(s.id,"confirmation",s.logic),$("Delete this confirmation",()=>{e.splice(a,1),this.markDirty(),this.renderCanvas()},"danger")]))}),r("div",{class:"atfb-pane",children:[r("h2",{text:"Confirmations"}),r("p",{class:"atfb-hint",text:"The first one whose conditions match is the one they see."}),t,$("Add a confirmation",()=>{e.push({id:this.nextEntryId("c",e),enabled:!0,name:"Confirmation",type:"message",message:"Thank you. Your submission has been received.",url:"",pageId:0,query:"",success:yt(),logic:{enabled:!1,action:"show",match:"all",rules:[]}}),this.markDirty(),this.renderCanvas()},"primary","plus-alt2")]})}async preview(){await Ot({current:()=>this.form?{id:this.form.id,title:this.form.title,previewUrl:this.form.previewUrl}:null,isDirty:()=>this.dirty,save:()=>this.save(!0)})}}let ae=null,Ke=null;document.addEventListener("alltfo-open-form",n=>{const e=Number(n.detail?.formId??0);e&&ae?.openFormById(e)});function Ve(){if(Ke?.isConnected)return;ae&&(ae.destroy(),ae=null,Ke=null);const n=document.querySelector("[data-atfb-root]:not([data-atfb-mounted])");n&&(n.dataset.atfbMounted="1",Ke=n,Ae(n),ns().then(()=>{n.isConnected&&(ae=new Wt(n),ae.start())}))}function Ut(){Ve(),hs()}return us(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ut):Ut(),document.addEventListener("os-window-content-loaded",Ve),ee.Builder=Wt,ee.SETTINGS_HANDLED_ELSEWHERE=In,ee.SETTING_CONTROLS=Pt,ee.fieldMove=jt,ee.mountBuilder=Ve,ee.restatement=Ht,Object.defineProperty(ee,Symbol.toStringTag,{value:"Module"}),ee}({}); diff --git a/assets/js/entries.js b/assets/js/entries.js index 1488522..b5e1f59 100644 --- a/assets/js/entries.js +++ b/assets/js/entries.js @@ -141,6 +141,11 @@ var allTerrainFormsEntries = function(exports) { this.active = null; this.lastEndMs = Date.now(); }; + const emit = (name, at) => { + document.dispatchEvent( + new CustomEvent(name, { detail: { payload, clientX: at?.clientX, clientY: at?.clientY } }) + ); + }; const session = { payload, isFinished: () => finished, @@ -150,6 +155,9 @@ var allTerrainFormsEntries = function(exports) { } finished = true; cleanup(); + if (lifted) { + emit("os.drag.end"); + } opts.onCancel?.(reason); } }; @@ -165,6 +173,7 @@ var allTerrainFormsEntries = function(exports) { ghost.style.width = `${rect.width}px`; document.body.appendChild(ghost); position(event); + emit("os.drag.start", event); }; const position = (event) => { if (ghost) { @@ -188,6 +197,7 @@ var allTerrainFormsEntries = function(exports) { hovered = next; hovered?.onEnter?.(session); } + emit("os.drag.move", event); }; const onUp = (event) => { if (finished) { @@ -205,8 +215,10 @@ var allTerrainFormsEntries = function(exports) { if (target && target.accept(payload)) { opts.onCommit?.(target); void target.onDrop(session, { clientX: event.clientX, clientY: event.clientY }); + emit("os.drag.end", event); return; } + emit("os.drag.end", event); opts.onCancel?.(target ? "rejected" : "no-target"); }; const onCancel = () => session.cancel("pointercancel"); @@ -303,11 +315,14 @@ var allTerrainFormsEntries = function(exports) { const payload = event.detail?.payload; return payload && payloadTypes.includes(payload.type) ? payload.source : null; }; + const preventSelection = (event) => event.preventDefault(); const onStart = (event) => { const source = sourceOf(event); if (source) { source.classList.add("atf-is-dragging"); document.body.classList.add("atf-drag-active"); + window.getSelection()?.removeAllRanges(); + document.addEventListener("selectstart", preventSelection); } }; const onEnd = (event) => { @@ -315,6 +330,7 @@ var allTerrainFormsEntries = function(exports) { if (source) { source.classList.remove("atf-is-dragging"); document.body.classList.remove("atf-drag-active"); + document.removeEventListener("selectstart", preventSelection); } }; document.addEventListener("os.drag.start", onStart); @@ -322,10 +338,23 @@ var allTerrainFormsEntries = function(exports) { return () => { document.removeEventListener("os.drag.start", onStart); document.removeEventListener("os.drag.end", onEnd); + document.removeEventListener("selectstart", preventSelection); }; } + const SCOPE_CLASSES = ["atfb", "atfe", "atfs", "atfm"]; function buildPayload(type, source, data, origin, ghost) { const rect = source.getBoundingClientRect(); + if (!ghost) { + const scope = SCOPE_CLASSES.find((cls) => source.closest(`.${cls}`)); + if (scope) { + const clone = source.cloneNode(true); + clone.style.transition = ""; + clone.style.transform = ""; + ghost = document.createElement("div"); + ghost.className = `${scope} atf-ghost-scope`; + ghost.appendChild(clone); + } + } if (ghost) { ghost.style.width = `${Math.round(rect.width)}px`; ghost.style.maxWidth = `${Math.round(rect.width)}px`; diff --git a/assets/js/entries.min.js b/assets/js/entries.min.js index 8bc5df3..c74d348 100644 --- a/assets/js/entries.min.js +++ b/assets/js/entries.min.js @@ -1 +1 @@ -var allTerrainFormsEntries=function(I){"use strict";function N(){const e=[window];try{window.parent&&window.parent!==window&&e.push(window.parent)}catch{}return e}function nt(e){const t=e.wp?.os?.windowManager?.getAll?.()??[];for(const s of t){const n=s.iframe??s.element?.querySelector?.("iframe");if(n&&n.contentWindow===window)return s}return null}const rt=4e3,it=100;function ot(e,t){const s=Date.now()+rt,n=()=>{const r=nt(e);if(r&&r.id!==t){typeof r.close=="function"?r.close():e.wp?.os?.windowManager?.remove?.(r.id);return}!r&&Date.now()0?{form:s}:void 0;s>0&&ct(s);for(const r of N())if(r.wp?.os?.openWindow?.(t,{source:"handoff",params:n})){window.setTimeout(()=>ot(r,t),0);return}}function lt(){document.addEventListener("click",e=>{const t=e.target?.closest?.("[data-atf-open-window]");if(!t)return;e.preventDefault();const s=t.getAttribute("data-atf-open-window")??"";for(const n of N())if(n.wp?.os?.openWindow?.(s,{source:"handoff"}))return})}const A="allterrain-forms/requested-form";function ct(e){try{window.sessionStorage.setItem(A,String(e))}catch{}}function U(e){return`allterrain-forms/requested-form-${e}`}function dt(e){try{const t=window.sessionStorage.getItem(U(e));return window.sessionStorage.removeItem(U(e)),Number(t)||0}catch{return 0}}function ut(){try{const e=window.sessionStorage.getItem(A);return window.sessionStorage.removeItem(A),Number(e)||0}catch{return 0}}const ft=4,ht=500;class mt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(t){if(this.active||t.origin.button!==0)return null;const{payload:s,origin:n}=t,r=n.clientX,i=n.clientY;let a=!1,l=!1,d=null,p=null,V=0,Q=0;const P=()=>{document.removeEventListener("pointermove",tt),document.removeEventListener("pointerup",et),document.removeEventListener("pointercancel",T),document.removeEventListener("keydown",st),window.removeEventListener("blur",T),d?.remove(),d=null,s.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),p?.onLeave?.(b),p=null,this.active=null,this.lastEndMs=Date.now()},b={payload:s,isFinished:()=>l,cancel:(c="caller")=>{l||(l=!0,P(),t.onCancel?.(c))}},qt=c=>{a=!0,s.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const f=s.source.getBoundingClientRect();V=s.ghost?.offsetX??r-f.left,Q=s.ghost?.offsetY??i-f.top,d=s.ghost?.element??s.source.cloneNode(!0),d.classList.add("atf-drag-ghost"),d.style.width=`${f.width}px`,document.body.appendChild(d),Z(c)},Z=c=>{d&&(d.style.transform=`translate3d(${c.clientX-V}px, ${c.clientY-Q}px, 0)`)},tt=c=>{if(l)return;if(!a){if(Math.hypot(c.clientX-r,c.clientY-i){if(l)return;if(!a){l=!0,P(),t.onClickOnly?.();return}const f=p;if(l=!0,P(),f&&f.accept(s)){t.onCommit?.(f),f.onDrop(b,{clientX:c.clientX,clientY:c.clientY});return}t.onCancel?.(f?"rejected":"no-target")},T=()=>b.cancel("pointercancel"),st=c=>{c.key==="Escape"&&b.cancel("escape")};return document.addEventListener("pointermove",tt),document.addEventListener("pointerup",et),document.addEventListener("pointercancel",T),document.addEventListener("keydown",st),window.addEventListener("blur",T),this.active=b,b}registerDropTarget(t){return this.targets=this.targets.filter(s=>s.id!==t.id),this.targets.push(t),()=>{this.targets=this.targets.filter(s=>s.id!==t.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(t=ht){return Date.now()-this.lastEndMsa.right||sa.bottom)continue;const l=pt(i.element);if(l>r){n=i,r=l;continue}l===r&&n&&wt(i.element,n.element)&&(n=i)}return n}}function pt(e){let t=0,s=e;for(;s;)t++,s=s.parentElement;return t}function wt(e,t){return(t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function D(){return window.wp?.os??null}let O=null;function j(){const e=D();return e?.dragManager?e.dragManager:(O||(O=new mt),O)}function gt(e){const t=r=>{const i=r.detail?.payload;return i&&e.includes(i.type)?i.source:null},s=r=>{const i=t(r);i&&(i.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"))},n=r=>{const i=t(r);i&&(i.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"))};return document.addEventListener("os.drag.start",s),document.addEventListener("os.drag.end",n),()=>{document.removeEventListener("os.drag.start",s),document.removeEventListener("os.drag.end",n)}}function bt(e,t,s,n,r){const i=t.getBoundingClientRect();return r&&(r.style.width=`${Math.round(i.width)}px`,r.style.maxWidth=`${Math.round(i.width)}px`,r.style.boxSizing="border-box"),{type:e,source:t,data:s,ghost:{element:r,offsetX:n.clientX-i.left,offsetY:n.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}const h=window.allTerrainForms;class S extends Error{constructor(t,s,n=""){super(t),this.name="ApiError",this.status=s,this.code=n}}function B(e,t){return e.includes("?")?`${e}${t.replace("?","&")}`:`${e}${t}`}async function C(e,t={}){if(!h?.restUrl)throw new S("AllTerrain Forms is not configured on this page.",0);const s=B(h.restUrl,e),n={"Content-Type":"application/json",...t.headers??{}};h.nonce&&(n["X-WP-Nonce"]=h.nonce);const r=D(),a=await(r?.fetch?(l,d)=>r.fetch(l,d,{source:"allterrain-forms"}):(l,d)=>fetch(l,d))(s,{credentials:"same-origin",...t,headers:n});if(!a.ok){let l=`Request failed with status ${a.status}.`,d="";try{const p=await a.json();l=p.message??l,d=p.code??""}catch{}throw new S(l,a.status,d)}if(a.status!==204)return await a.json()}const u=e=>C(e);async function vt(e){if(!h?.wpRestUrl)throw new S("AllTerrain Forms is not configured on this page.",0);const t=h.nonce?{"X-WP-Nonce":h.nonce}:{},s=D(),n=B(h.wpRestUrl,e),r=s?.fetch?await s.fetch(n,{credentials:"same-origin",headers:t},{source:"allterrain-forms"}):await fetch(n,{credentials:"same-origin",headers:t});if(!r.ok)throw new S(`Request failed with status ${r.status}.`,r.status);return await r.json()}function yt(e){if(!e||!e.includes("&"))return e;const t=document.createElement("textarea");return t.innerHTML=e,t.value}const w=(e,t)=>C(e,{method:"POST",body:JSON.stringify(t)}),L=e=>C(e,{method:"DELETE"});function Y(e){const t=new URLSearchParams;for(const[n,r]of Object.entries(e))r===void 0||r===""||r===!1||t.set(n,String(r));const s=t.toString();return s?`?${s}`:""}function $(e){const t=e?.schema?.settings;return t&&(!t.themeOverrides||Array.isArray(t.themeOverrides))&&(t.themeOverrides={...t.themeOverrides}),e}const g={config:()=>u("/config"),mailpoet:()=>u("/mailpoet"),listForms:()=>u("/forms"),listArchivedForms:()=>u("/forms?archived=1"),archiveForm:e=>w(`/forms/${e}/archive`,{}),unarchiveForm:e=>w(`/forms/${e}/unarchive`,{}),getForm:e=>u(`/forms/${e}`).then($),createForm:e=>w("/forms",e).then($),updateForm:(e,t)=>w(`/forms/${e}`,t).then($),duplicateForm:e=>w(`/forms/${e}/duplicate`,{}).then($),deleteForm:e=>L(`/forms/${e}`),preview:(e,t)=>w(`/forms/${e}/preview`,t),pages:()=>vt("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(e=>e.map(t=>({id:t.id,title:yt(t.title?.rendered??"")||`#${t.id}`}))),mergeTags:e=>u(`/forms/${e}/merge-tags`).then(t=>t.groups),analytics:(e,t="")=>u(`/forms/${e}/analytics${t?`?dimension=${encodeURIComponent(t)}`:""}`),demoStatus:()=>u("/demo"),demoSeed:e=>w("/demo",e?{count:e}:{}),demoRemove:()=>L("/demo"),listEntries:e=>u(`/entries${Y(e)}`),getEntry:e=>u(`/entries/${e}`),updateEntry:(e,t)=>w(`/entries/${e}`,t),deleteEntry:e=>L(`/entries/${e}`),exportEntries:e=>u(`/entries/export${Y(e)}`),listThemes:()=>u("/themes"),saveTheme:e=>w("/themes",e),deleteTheme:e=>L(`/themes/${e}`)};function o(e,t={}){const s=document.createElement(e);t.class&&(s.className=t.class),t.text!==void 0&&(s.textContent=t.text),t.html!==void 0&&(s.innerHTML=t.html),t.title&&(s.title=t.title),t.type&&"type"in s&&(s.type=t.type),t.value!==void 0&&"value"in s&&(s.value=t.value),t.placeholder!==void 0&&"placeholder"in s&&(s.placeholder=t.placeholder),t.href&&"href"in s&&(s.href=t.href);for(const[n,r]of Object.entries(t.attrs??{}))r===void 0||r===!1||s.setAttribute(n,r===!0?"":String(r));Object.assign(s.style,t.style??{});for(const[n,r]of Object.entries(t.on??{}))s.addEventListener(n,r);for(const n of t.children??[])n==null||n===!1||s.append(n);return s}function v(e){e.replaceChildren()}function M(e){return o("span",{class:`dashicons ${e.startsWith("dashicons-")?e:`dashicons-${e}`}`,attrs:{"aria-hidden":"true"}})}function Et(e,t,s=""){return o("input",{class:"atfb-input",type:"text",value:e,placeholder:s,on:{input:n=>t(n.target.value)}})}function W(e,t,s){if(x("os-select")&&x("os-option")){const n=document.createElement("os-select");n.setAttribute("value",e),n.classList.add("atfb-field");for(const r of t){const i=document.createElement("os-option");i.setAttribute("value",r.value),i.textContent=r.label,n.append(i)}return n.addEventListener("os-pick",r=>{s(String(r.detail?.value??""))}),n}return o("select",{class:"atfb-input atfb-select",on:{change:n=>s(n.target.value)},children:t.map(n=>o("option",{value:n.value,text:n.label,attrs:{selected:n.value===e}}))})}function St(e,t,s){if(x("os-checkbox-label")){const r=document.createElement("os-checkbox-label");return r.setAttribute("label",e),r.classList.add("atfb-check"),t&&r.setAttribute("checked",""),r.addEventListener("os-checkbox-change",i=>{s(!!i.detail?.checked)}),r}const n=o("input",{type:"checkbox",on:{change:r=>s(r.target.checked)}});return n.checked=t,o("label",{class:"atfb-check",children:[n,o("span",{text:e})]})}function m(e,t,s="secondary",n){const r=[n?M(n):null,o("span",{text:e})];if(x("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",s),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${s}`),i.addEventListener("click",t);for(const a of r)a&&i.append(a);return i}return o("button",{class:`atfb-button atfb-button--${s}`,type:"button",on:{click:t},children:r})}function x(e){return typeof customElements<"u"&&!!customElements.get(e)}const Lt=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let k=null;function $t(){if(k)return k;const e=window.wp?.os;return k=e?.loadComponents?e.loadComponents(Lt).catch(()=>{}):Promise.resolve(),k}async function X(e,t=""){const s=window.wp?.os;return s?.confirm?s.confirm({title:t,message:e,danger:!0}):window.confirm(e)}function E(e,t="",s="info"){const n=window.wp?.os;if(n?.notify){n.notify({title:e,body:t,type:s});return}console.info(`[AllTerrain Forms] ${e}${t?`: ${t}`:""}`)}function xt(e,t){let s=0;return(...n)=>{window.clearTimeout(s),s=window.setTimeout(()=>e(...n),t)}}function kt(e){const t=e.closest(".os-window__body");t&&(t.addEventListener("scroll",()=>{t.scrollTop&&(t.scrollTop=0),t.scrollLeft&&(t.scrollLeft=0)},{passive:!0}),t.scrollTop=0,t.scrollLeft=0)}const _t="allterrain-forms/form",Tt="allterrain-forms/entry";function It(){return window.wp?.os?.relations??null}function At(e){const t=e.closest("[data-window-id], .os-window");if(!t)return null;const s=t.getAttribute("data-window-id");if(s)return s;const n=t.id??"";return n?n.replace(/^wp-window-/,""):null}const Dt=6e3,H=120;function z(e,t){const s=It();if(q.set(e,t),!s?.set)return;const n=i=>{if(_.get(e)!==r)return;const a=At(e);if(!a){Date.now()n(i),H);return}try{s.set(a,t)}catch(d){G||(G=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",d,t)),_.delete(e);return}if(!t||s.get?.(a)?.id===t.id||Date.now()>=i){_.delete(e);return}window.setTimeout(()=>n(i),H)},r=Symbol("atf-identity");_.set(e,r),n(Date.now()+Dt)}let G=!1;const _=new WeakMap,q=new Map;function Ot(){for(const[e,t]of q){if(!e.isConnected){q.delete(e);continue}z(e,t)}}if(typeof document<"u")for(const e of["os-window-content-loaded","os-window-opened"])document.addEventListener(e,()=>Ot());function Ct(e,t){const s=[];e.userId&&s.push({type:"user",id:e.userId,rel:"references"});for(const r of e.fields)if(!(r.type!=="file"||!Array.isArray(r.value)))for(const i of r.value){const a=Number(i);a>0&&s.push({type:"media",id:a,rel:"child"})}const n=[{id:`allterrain-forms/form-${e.formId}`,label:e.formTitle||"The form",url:`${t}admin.php?page=allterrain-forms&form=${e.formId}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-feedback"}];return e.userId&&n.push({id:`allterrain-forms/user-${e.userId}`,label:"Who submitted it",url:`${t}user-edit.php?user_id=${e.userId}`,group:"users",groupLabel:"People",icon:"dashicons-admin-users"}),{type:Tt,id:e.id,root:{type:_t,id:e.formId},label:e.title||`Entry #${e.id}`,links:s.slice(0,32),related:n}}const K="allterrain-forms/entry";class Mt{constructor(t){this.forms=[],this.entries=[],this.selected=null,this.selection=new Set,this.paintedSelectionId=-1,this.loadSeq=0,this.selectSeq=0,this.formId=0,this.status="inbox",this.search="",this.starred=!1,this.page=1,this.pages=1,this.total=0,this.teardowns=[],this.root=t,this.bar=t.querySelector("[data-atfe-bar]")??o("div"),this.list=t.querySelector("[data-atfe-list]")??o("div"),this.detail=t.querySelector("[data-atfe-detail]")??o("div")}async start(){this.teardowns.push(gt([K]));try{this.forms=await g.listForms()}catch(n){v(this.bar),this.bar.append(o("p",{class:"atfb-error",text:n instanceof Error?n.message:"Could not load forms."}));return}const t=dt("entries")||ut();this.formId=(t&&this.forms.some(n=>n.id===t)?t:0)||(this.forms.find(n=>n.unread>0)??this.forms[0])?.id||0,this.renderBar(),await this.load();const s=window.wp?.os;s?.subscribe&&this.teardowns.push(s.subscribe("os.alltfo_entry.changed",()=>{if(!this.root.isConnected){this.destroy();return}this.load()}))}destroy(){this.teardowns.forEach(t=>t()),this.teardowns=[]}renderBar(){v(this.bar);const t=Et(this.search,xt(s=>{this.search=s,this.page=1,this.load()},300),"Search answers");t.type="search",t.setAttribute("aria-label","Search entries"),this.bar.append(W(String(this.formId),this.forms.map(s=>({value:String(s.id),label:s.unread?`${s.title} (${s.unread})`:s.title})),s=>{this.formId=Number(s),this.page=1,this.selection.clear(),this.selected=null,this.load()}),W(this.status,[{value:"inbox",label:"All"},{value:"alltfo-unread",label:"Unread"},{value:"alltfo-read",label:"Read"},{value:"alltfo-spam",label:"Spam"}],s=>{this.status=s,this.page=1,this.load()}),t,St("Starred only",this.starred,s=>{this.starred=s,this.page=1,this.load()}),o("span",{class:"atfe__count",attrs:{role:"status"},text:""}),m("Export CSV",()=>void this.exportEntries("csv"),"secondary","download"),m("JSON",()=>void this.exportEntries("json"),"secondary"))}async showForm(t){this.formId=t,this.page=1,this.selection.clear(),this.selected=null,this.renderBar(),await this.load()}async load(){if(!this.formId){v(this.list),this.list.append(o("p",{class:"atfb-hint",text:"No forms yet."}));return}const t=++this.loadSeq;try{const s=await g.listEntries({form_id:this.formId,status:this.status==="inbox"?void 0:this.status,search:this.search,page:this.page,starred:this.starred});if(t!==this.loadSeq)return;if(this.page>1&&this.page>s.pages)return this.page=Math.max(1,s.pages),this.load();this.entries=s.entries,this.total=s.total,this.pages=s.pages,this.renderList(),this.reconcileSelection();const n=this.bar.querySelector(".atfe__count");n&&(n.textContent=`${this.total} ${this.total===1?"entry":"entries"}`)}catch(s){if(t!==this.loadSeq)return;v(this.list),this.list.append(o("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load entries."}))}}reconcileSelection(){this.selected&&!this.entries.some(t=>t.id===this.selected?.id)&&(this.selected=null),this.paintedSelectionId!==(this.selected?.id??0)&&this.renderDetail()}renderList(){if(v(this.list),!this.entries.length){this.list.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:this.search?"Nothing matches that.":"No entries yet."})]}));return}const t=new Set(this.entries.map(n=>n.id));for(const n of Array.from(this.selection))t.has(n)||this.selection.delete(n);this.list.append(this.renderBulkBar());const s=o("div",{class:"atfe__rows",attrs:{role:"list"}});for(const n of this.entries)s.append(this.renderRow(n));this.list.append(s),this.pages>1&&this.list.append(o("div",{class:"atfe__pager",children:[m("Previous",()=>{this.page=Math.max(1,this.page-1),this.load()}),o("span",{text:`Page ${this.page} of ${this.pages}`}),m("Next",()=>{this.page=Math.min(this.pages,this.page+1),this.load()})]}))}renderBulkBar(){const t=this.selection.size,s=o("input",{type:"checkbox",attrs:{"aria-label":"Select every entry on this page"},on:{change:n=>{const r=n.target.checked;this.entries.forEach(i=>{r?this.selection.add(i.id):this.selection.delete(i.id)}),this.renderList()}}});return s.checked=t>0&&t===this.entries.length,s.indeterminate=t>0&&tvoid this.bulk("alltfo-read")):null,t?m("Unread",()=>void this.bulk("alltfo-unread")):null,t?m("Spam",()=>void this.bulk("alltfo-spam")):null,t&&h?.canEdit?m("Delete",()=>void this.bulkDelete(),"danger"):null]})}async bulk(t){const s=Array.from(this.selection);for(const n of s)try{await g.updateEntry(n,{status:t})}catch{}this.selection.clear(),await this.load()}async bulkDelete(){const t=Array.from(this.selection);if(await X(`Delete ${t.length} ${t.length===1?"entry":"entries"} and any files uploaded with them? It cannot be undone.`,"Delete entries")){for(const n of t)try{await g.deleteEntry(n)}catch{}this.selection.clear(),this.selected=null,await this.load(),this.renderDetail()}}renderRow(t){const s=t.status==="alltfo-unread",n=o("div",{class:`atfe__row${s?" is-unread":""}${this.selected?.id===t.id?" is-selected":""}`,attrs:{role:"listitem",tabindex:"0","data-entry":t.id},children:[o("input",{class:"atfe__select",type:"checkbox",attrs:{"aria-label":`Select ${t.title}`,checked:this.selection.has(t.id)},on:{click:r=>r.stopPropagation(),change:r=>{r.target.checked?this.selection.add(t.id):this.selection.delete(t.id),this.list.querySelector(".atfe__bulk")?.replaceWith(this.renderBulkBar())}}}),o("button",{class:`atfe__star${t.starred?" is-on":""}`,type:"button",attrs:{"aria-label":t.starred?"Unstar this entry":"Star this entry"},on:{click:r=>{r.stopPropagation(),this.toggleStar(t)}},children:[M("star-filled")]}),o("div",{class:"atfe__row-body",children:[o("strong",{text:t.title}),o("span",{class:"atfe__row-meta",text:t.dateHuman})]}),t.notes?o("span",{class:"atfb-badge",text:`💬 ${t.notes}`}):null,t.spam?o("span",{class:"atfb-badge atfb-badge--spam",text:"spam"}):null]});return n.addEventListener("click",()=>{j().recentlyEndedDrag()||this.select(t)}),n.addEventListener("keydown",r=>{(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),this.select(t))}),n.addEventListener("pointerdown",r=>{if(r.target.closest("button"))return;const i=o("div",{class:"atfe__ghost",children:[M("feedback"),o("span",{text:t.title})]});j().start({payload:bt(K,n,{entry:t,formId:t.formId,formTitle:t.formTitle},r,i),origin:r})}),n}async select(t){const s=++this.selectSeq;try{const n=await g.getEntry(t.id);if(s!==this.selectSeq)return;this.selected=n;const r=this.entries.find(i=>i.id===t.id);r&&(r.status=this.selected.status),this.renderList(),this.renderDetail()}catch(n){if(s!==this.selectSeq)return;E("Could not open that entry",n instanceof Error?n.message:"","error")}}renderDetail(){this.paintedSelectionId=this.selected?.id??0,z(this.root,this.selected?Ct(this.selected,h?.adminUrl??""):null),v(this.detail);const t=this.selected;if(!t){this.detail.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:"Pick an entry to read it."})]}));return}const s=o("dl",{class:"atfe__answers"});for(const n of t.fields)n.formatted&&s.append(o("dt",{text:n.label||n.id}),o("dd",{text:n.formatted}));this.detail.append(o("div",{class:"atfe__detail",children:[o("div",{class:"atfe__detail-head",children:[o("h2",{text:t.title}),o("p",{class:"atfb-hint",text:`${t.formTitle} — ${t.dateHuman}`})]}),s,t.quiz?o("p",{class:"atfe__quiz",text:`Score: ${t.quiz.score} of ${t.quiz.total} (${t.quiz.percent}%) — ${t.quiz.passed?"passed":"not passed"}`}):null,o("details",{class:"atfb-section",children:[o("summary",{text:"Where it came from"}),o("p",{class:"atfb-hint",text:t.ip?`IP: ${t.ip}`:"No IP recorded."}),t.referrer?o("p",{class:"atfb-hint",text:`Referrer: ${t.referrer}`}):null,t.userAgent?o("p",{class:"atfb-hint",text:t.userAgent}):null]}),o("div",{class:"atfe__actions",children:[m(t.status==="alltfo-spam"?"Not spam":"Mark as spam",()=>void this.setStatus(t,t.status==="alltfo-spam"?"alltfo-read":"alltfo-spam")),m(t.status==="alltfo-unread"?"Mark read":"Mark unread",()=>void this.setStatus(t,t.status==="alltfo-unread"?"alltfo-read":"alltfo-unread")),t.canDelete?m("Delete",()=>void this.remove(t),"danger"):null]})]}))}async toggleStar(t){try{const s=await g.updateEntry(t.id,{starred:!t.starred});t.starred=s.starred,this.renderList()}catch(s){E("Could not update that entry",s instanceof Error?s.message:"","error")}}async setStatus(t,s){try{const n=await g.updateEntry(t.id,{status:s});this.selected=n,await this.load(),this.renderDetail()}catch(n){E("Could not update that entry",n instanceof Error?n.message:"","error")}}async remove(t){if(await X("Delete this entry and any files uploaded with it? It cannot be undone.","Delete entry"))try{await g.deleteEntry(t.id),this.selected=null,await this.load(),this.renderDetail()}catch(s){E("Could not delete that entry",s instanceof Error?s.message:"","error")}}async exportEntries(t){try{const{filename:s,csv:n}=await g.exportEntries({form_id:this.formId,search:this.search,starred:this.starred,format:t}),r=new Blob([n],{type:t==="json"?"application/json":"text/csv;charset=utf-8"}),i=URL.createObjectURL(r),a=o("a",{href:i,attrs:{download:s}});document.body.append(a),a.click(),a.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),1e3)}catch(s){E("Could not export",s instanceof Error?s.message:"","error")}}}let y=null;document.addEventListener("alltfo-open-entries-form",e=>{const t=Number(e.detail?.formId??0);t&&y?.showForm(t)});let F=null;function R(){if(F?.isConnected)return;y&&(y.destroy(),y=null,F=null);const e=document.querySelector("[data-atfe-root]:not([data-atfe-mounted])");!e||!h?.canRead||(e.dataset.atfeMounted="1",F=e,kt(e),$t().then(()=>{e.isConnected&&(y=new Mt(e),y.start())}))}function J(){R(),at()}return lt(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",J):J(),document.addEventListener("os-window-content-loaded",R),I.mountEntries=R,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"}),I}({}); +var allTerrainFormsEntries=function(I){"use strict";function U(){const e=[window];try{window.parent&&window.parent!==window&&e.push(window.parent)}catch{}return e}function rt(e){const t=e.wp?.os?.windowManager?.getAll?.()??[];for(const s of t){const n=s.iframe??s.element?.querySelector?.("iframe");if(n&&n.contentWindow===window)return s}return null}const it=4e3,ot=100;function at(e,t){const s=Date.now()+it,n=()=>{const r=rt(e);if(r&&r.id!==t){typeof r.close=="function"?r.close():e.wp?.os?.windowManager?.remove?.(r.id);return}!r&&Date.now()0?{form:s}:void 0;s>0&&dt(s);for(const r of U())if(r.wp?.os?.openWindow?.(t,{source:"handoff",params:n})){window.setTimeout(()=>at(r,t),0);return}}function ct(){document.addEventListener("click",e=>{const t=e.target?.closest?.("[data-atf-open-window]");if(!t)return;e.preventDefault();const s=t.getAttribute("data-atf-open-window")??"";for(const n of U())if(n.wp?.os?.openWindow?.(s,{source:"handoff"}))return})}const D="allterrain-forms/requested-form";function dt(e){try{window.sessionStorage.setItem(D,String(e))}catch{}}function Y(e){return`allterrain-forms/requested-form-${e}`}function ut(e){try{const t=window.sessionStorage.getItem(Y(e));return window.sessionStorage.removeItem(Y(e)),Number(t)||0}catch{return 0}}function ft(){try{const e=window.sessionStorage.getItem(D);return window.sessionStorage.removeItem(D),Number(e)||0}catch{return 0}}const ht=4,mt=500;class pt{constructor(){this.targets=[],this.active=null,this.lastEndMs=0}start(t){if(this.active||t.origin.button!==0)return null;const{payload:s,origin:n}=t,r=n.clientX,i=n.clientY;let a=!1,l=!1,d=null,p=null,Q=0,Z=0;const N=()=>{document.removeEventListener("pointermove",et),document.removeEventListener("pointerup",st),document.removeEventListener("pointercancel",A),document.removeEventListener("keydown",nt),window.removeEventListener("blur",A),d?.remove(),d=null,s.source.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),p?.onLeave?.(v),p=null,this.active=null,this.lastEndMs=Date.now()},S=(c,u)=>{document.dispatchEvent(new CustomEvent(c,{detail:{payload:s,clientX:u?.clientX,clientY:u?.clientY}}))},v={payload:s,isFinished:()=>l,cancel:(c="caller")=>{l||(l=!0,N(),a&&S("os.drag.end"),t.onCancel?.(c))}},Ft=c=>{a=!0,s.source.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active");const u=s.source.getBoundingClientRect();Q=s.ghost?.offsetX??r-u.left,Z=s.ghost?.offsetY??i-u.top,d=s.ghost?.element??s.source.cloneNode(!0),d.classList.add("atf-drag-ghost"),d.style.width=`${u.width}px`,document.body.appendChild(d),tt(c),S("os.drag.start",c)},tt=c=>{d&&(d.style.transform=`translate3d(${c.clientX-Q}px, ${c.clientY-Z}px, 0)`)},et=c=>{if(l)return;if(!a){if(Math.hypot(c.clientX-r,c.clientY-i){if(l)return;if(!a){l=!0,N(),t.onClickOnly?.();return}const u=p;if(l=!0,N(),u&&u.accept(s)){t.onCommit?.(u),u.onDrop(v,{clientX:c.clientX,clientY:c.clientY}),S("os.drag.end",c);return}S("os.drag.end",c),t.onCancel?.(u?"rejected":"no-target")},A=()=>v.cancel("pointercancel"),nt=c=>{c.key==="Escape"&&v.cancel("escape")};return document.addEventListener("pointermove",et),document.addEventListener("pointerup",st),document.addEventListener("pointercancel",A),document.addEventListener("keydown",nt),window.addEventListener("blur",A),this.active=v,v}registerDropTarget(t){return this.targets=this.targets.filter(s=>s.id!==t.id),this.targets.push(t),()=>{this.targets=this.targets.filter(s=>s.id!==t.id)}}isDragging(){return this.active!==null}recentlyEndedDrag(t=mt){return Date.now()-this.lastEndMsa.right||sa.bottom)continue;const l=wt(i.element);if(l>r){n=i,r=l;continue}l===r&&n&>(i.element,n.element)&&(n=i)}return n}}function wt(e){let t=0,s=e;for(;s;)t++,s=s.parentElement;return t}function gt(e,t){return(t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING)!==0}function C(){return window.wp?.os??null}let O=null;function j(){const e=C();return e?.dragManager?e.dragManager:(O||(O=new pt),O)}function vt(e){const t=i=>{const a=i.detail?.payload;return a&&e.includes(a.type)?a.source:null},s=i=>i.preventDefault(),n=i=>{const a=t(i);a&&(a.classList.add("atf-is-dragging"),document.body.classList.add("atf-drag-active"),window.getSelection()?.removeAllRanges(),document.addEventListener("selectstart",s))},r=i=>{const a=t(i);a&&(a.classList.remove("atf-is-dragging"),document.body.classList.remove("atf-drag-active"),document.removeEventListener("selectstart",s))};return document.addEventListener("os.drag.start",n),document.addEventListener("os.drag.end",r),()=>{document.removeEventListener("os.drag.start",n),document.removeEventListener("os.drag.end",r),document.removeEventListener("selectstart",s)}}const bt=["atfb","atfe","atfs","atfm"];function yt(e,t,s,n,r){const i=t.getBoundingClientRect();if(!r){const a=bt.find(l=>t.closest(`.${l}`));if(a){const l=t.cloneNode(!0);l.style.transition="",l.style.transform="",r=document.createElement("div"),r.className=`${a} atf-ghost-scope`,r.appendChild(l)}}return r&&(r.style.width=`${Math.round(i.width)}px`,r.style.maxWidth=`${Math.round(i.width)}px`,r.style.boxSizing="border-box"),{type:e,source:t,data:s,ghost:{element:r,offsetX:n.clientX-i.left,offsetY:n.clientY-i.top,hint:{neutral:"",accept:"",reject:"",hidden:!0}}}}const h=window.allTerrainForms;class L extends Error{constructor(t,s,n=""){super(t),this.name="ApiError",this.status=s,this.code=n}}function B(e,t){return e.includes("?")?`${e}${t.replace("?","&")}`:`${e}${t}`}async function M(e,t={}){if(!h?.restUrl)throw new L("AllTerrain Forms is not configured on this page.",0);const s=B(h.restUrl,e),n={"Content-Type":"application/json",...t.headers??{}};h.nonce&&(n["X-WP-Nonce"]=h.nonce);const r=C(),a=await(r?.fetch?(l,d)=>r.fetch(l,d,{source:"allterrain-forms"}):(l,d)=>fetch(l,d))(s,{credentials:"same-origin",...t,headers:n});if(!a.ok){let l=`Request failed with status ${a.status}.`,d="";try{const p=await a.json();l=p.message??l,d=p.code??""}catch{}throw new L(l,a.status,d)}if(a.status!==204)return await a.json()}const f=e=>M(e);async function Et(e){if(!h?.wpRestUrl)throw new L("AllTerrain Forms is not configured on this page.",0);const t=h.nonce?{"X-WP-Nonce":h.nonce}:{},s=C(),n=B(h.wpRestUrl,e),r=s?.fetch?await s.fetch(n,{credentials:"same-origin",headers:t},{source:"allterrain-forms"}):await fetch(n,{credentials:"same-origin",headers:t});if(!r.ok)throw new L(`Request failed with status ${r.status}.`,r.status);return await r.json()}function St(e){if(!e||!e.includes("&"))return e;const t=document.createElement("textarea");return t.innerHTML=e,t.value}const w=(e,t)=>M(e,{method:"POST",body:JSON.stringify(t)}),$=e=>M(e,{method:"DELETE"});function W(e){const t=new URLSearchParams;for(const[n,r]of Object.entries(e))r===void 0||r===""||r===!1||t.set(n,String(r));const s=t.toString();return s?`?${s}`:""}function x(e){const t=e?.schema?.settings;return t&&(!t.themeOverrides||Array.isArray(t.themeOverrides))&&(t.themeOverrides={...t.themeOverrides}),e}const g={config:()=>f("/config"),mailpoet:()=>f("/mailpoet"),listForms:()=>f("/forms"),listArchivedForms:()=>f("/forms?archived=1"),archiveForm:e=>w(`/forms/${e}/archive`,{}),unarchiveForm:e=>w(`/forms/${e}/unarchive`,{}),getForm:e=>f(`/forms/${e}`).then(x),createForm:e=>w("/forms",e).then(x),updateForm:(e,t)=>w(`/forms/${e}`,t).then(x),duplicateForm:e=>w(`/forms/${e}/duplicate`,{}).then(x),deleteForm:e=>$(`/forms/${e}`),preview:(e,t)=>w(`/forms/${e}/preview`,t),pages:()=>Et("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(e=>e.map(t=>({id:t.id,title:St(t.title?.rendered??"")||`#${t.id}`}))),mergeTags:e=>f(`/forms/${e}/merge-tags`).then(t=>t.groups),analytics:(e,t="")=>f(`/forms/${e}/analytics${t?`?dimension=${encodeURIComponent(t)}`:""}`),demoStatus:()=>f("/demo"),demoSeed:e=>w("/demo",e?{count:e}:{}),demoRemove:()=>$("/demo"),listEntries:e=>f(`/entries${W(e)}`),getEntry:e=>f(`/entries/${e}`),updateEntry:(e,t)=>w(`/entries/${e}`,t),deleteEntry:e=>$(`/entries/${e}`),exportEntries:e=>f(`/entries/export${W(e)}`),listThemes:()=>f("/themes"),saveTheme:e=>w("/themes",e),deleteTheme:e=>$(`/themes/${e}`)};function o(e,t={}){const s=document.createElement(e);t.class&&(s.className=t.class),t.text!==void 0&&(s.textContent=t.text),t.html!==void 0&&(s.innerHTML=t.html),t.title&&(s.title=t.title),t.type&&"type"in s&&(s.type=t.type),t.value!==void 0&&"value"in s&&(s.value=t.value),t.placeholder!==void 0&&"placeholder"in s&&(s.placeholder=t.placeholder),t.href&&"href"in s&&(s.href=t.href);for(const[n,r]of Object.entries(t.attrs??{}))r===void 0||r===!1||s.setAttribute(n,r===!0?"":String(r));Object.assign(s.style,t.style??{});for(const[n,r]of Object.entries(t.on??{}))s.addEventListener(n,r);for(const n of t.children??[])n==null||n===!1||s.append(n);return s}function b(e){e.replaceChildren()}function q(e){return o("span",{class:`dashicons ${e.startsWith("dashicons-")?e:`dashicons-${e}`}`,attrs:{"aria-hidden":"true"}})}function Lt(e,t,s=""){return o("input",{class:"atfb-input",type:"text",value:e,placeholder:s,on:{input:n=>t(n.target.value)}})}function X(e,t,s){if(k("os-select")&&k("os-option")){const n=document.createElement("os-select");n.setAttribute("value",e),n.classList.add("atfb-field");for(const r of t){const i=document.createElement("os-option");i.setAttribute("value",r.value),i.textContent=r.label,n.append(i)}return n.addEventListener("os-pick",r=>{s(String(r.detail?.value??""))}),n}return o("select",{class:"atfb-input atfb-select",on:{change:n=>s(n.target.value)},children:t.map(n=>o("option",{value:n.value,text:n.label,attrs:{selected:n.value===e}}))})}function $t(e,t,s){if(k("os-checkbox-label")){const r=document.createElement("os-checkbox-label");return r.setAttribute("label",e),r.classList.add("atfb-check"),t&&r.setAttribute("checked",""),r.addEventListener("os-checkbox-change",i=>{s(!!i.detail?.checked)}),r}const n=o("input",{type:"checkbox",on:{change:r=>s(r.target.checked)}});return n.checked=t,o("label",{class:"atfb-check",children:[n,o("span",{text:e})]})}function m(e,t,s="secondary",n){const r=[n?q(n):null,o("span",{text:e})];if(k("os-button")){const i=document.createElement("os-button");i.setAttribute("variant",s),i.setAttribute("type","button"),i.classList.add("atfb-button",`atfb-button--${s}`),i.addEventListener("click",t);for(const a of r)a&&i.append(a);return i}return o("button",{class:`atfb-button atfb-button--${s}`,type:"button",on:{click:t},children:r})}function k(e){return typeof customElements<"u"&&!!customElements.get(e)}const xt=["os-button","os-checkbox-label","os-number-field","os-select","os-option","os-segmented","os-segment","os-color-field","os-empty-state"];let _=null;function kt(){if(_)return _;const e=window.wp?.os;return _=e?.loadComponents?e.loadComponents(xt).catch(()=>{}):Promise.resolve(),_}async function H(e,t=""){const s=window.wp?.os;return s?.confirm?s.confirm({title:t,message:e,danger:!0}):window.confirm(e)}function E(e,t="",s="info"){const n=window.wp?.os;if(n?.notify){n.notify({title:e,body:t,type:s});return}console.info(`[AllTerrain Forms] ${e}${t?`: ${t}`:""}`)}function _t(e,t){let s=0;return(...n)=>{window.clearTimeout(s),s=window.setTimeout(()=>e(...n),t)}}function Tt(e){const t=e.closest(".os-window__body");t&&(t.addEventListener("scroll",()=>{t.scrollTop&&(t.scrollTop=0),t.scrollLeft&&(t.scrollLeft=0)},{passive:!0}),t.scrollTop=0,t.scrollLeft=0)}const At="allterrain-forms/form",It="allterrain-forms/entry";function Dt(){return window.wp?.os?.relations??null}function Ct(e){const t=e.closest("[data-window-id], .os-window");if(!t)return null;const s=t.getAttribute("data-window-id");if(s)return s;const n=t.id??"";return n?n.replace(/^wp-window-/,""):null}const Ot=6e3,z=120;function G(e,t){const s=Dt();if(R.set(e,t),!s?.set)return;const n=i=>{if(T.get(e)!==r)return;const a=Ct(e);if(!a){Date.now()n(i),z);return}try{s.set(a,t)}catch(d){K||(K=!0,console.error("[AllTerrain Forms] The shell refused a window identity.",d,t)),T.delete(e);return}if(!t||s.get?.(a)?.id===t.id||Date.now()>=i){T.delete(e);return}window.setTimeout(()=>n(i),z)},r=Symbol("atf-identity");T.set(e,r),n(Date.now()+Ot)}let K=!1;const T=new WeakMap,R=new Map;function Mt(){for(const[e,t]of R){if(!e.isConnected){R.delete(e);continue}G(e,t)}}if(typeof document<"u")for(const e of["os-window-content-loaded","os-window-opened"])document.addEventListener(e,()=>Mt());function qt(e,t){const s=[];e.userId&&s.push({type:"user",id:e.userId,rel:"references"});for(const r of e.fields)if(!(r.type!=="file"||!Array.isArray(r.value)))for(const i of r.value){const a=Number(i);a>0&&s.push({type:"media",id:a,rel:"child"})}const n=[{id:`allterrain-forms/form-${e.formId}`,label:e.formTitle||"The form",url:`${t}admin.php?page=allterrain-forms&form=${e.formId}`,group:"allterrain-forms",groupLabel:"Forms",icon:"dashicons-feedback"}];return e.userId&&n.push({id:`allterrain-forms/user-${e.userId}`,label:"Who submitted it",url:`${t}user-edit.php?user_id=${e.userId}`,group:"users",groupLabel:"People",icon:"dashicons-admin-users"}),{type:It,id:e.id,root:{type:At,id:e.formId},label:e.title||`Entry #${e.id}`,links:s.slice(0,32),related:n}}const J="allterrain-forms/entry";class Rt{constructor(t){this.forms=[],this.entries=[],this.selected=null,this.selection=new Set,this.paintedSelectionId=-1,this.loadSeq=0,this.selectSeq=0,this.formId=0,this.status="inbox",this.search="",this.starred=!1,this.page=1,this.pages=1,this.total=0,this.teardowns=[],this.root=t,this.bar=t.querySelector("[data-atfe-bar]")??o("div"),this.list=t.querySelector("[data-atfe-list]")??o("div"),this.detail=t.querySelector("[data-atfe-detail]")??o("div")}async start(){this.teardowns.push(vt([J]));try{this.forms=await g.listForms()}catch(n){b(this.bar),this.bar.append(o("p",{class:"atfb-error",text:n instanceof Error?n.message:"Could not load forms."}));return}const t=ut("entries")||ft();this.formId=(t&&this.forms.some(n=>n.id===t)?t:0)||(this.forms.find(n=>n.unread>0)??this.forms[0])?.id||0,this.renderBar(),await this.load();const s=window.wp?.os;s?.subscribe&&this.teardowns.push(s.subscribe("os.alltfo_entry.changed",()=>{if(!this.root.isConnected){this.destroy();return}this.load()}))}destroy(){this.teardowns.forEach(t=>t()),this.teardowns=[]}renderBar(){b(this.bar);const t=Lt(this.search,_t(s=>{this.search=s,this.page=1,this.load()},300),"Search answers");t.type="search",t.setAttribute("aria-label","Search entries"),this.bar.append(X(String(this.formId),this.forms.map(s=>({value:String(s.id),label:s.unread?`${s.title} (${s.unread})`:s.title})),s=>{this.formId=Number(s),this.page=1,this.selection.clear(),this.selected=null,this.load()}),X(this.status,[{value:"inbox",label:"All"},{value:"alltfo-unread",label:"Unread"},{value:"alltfo-read",label:"Read"},{value:"alltfo-spam",label:"Spam"}],s=>{this.status=s,this.page=1,this.load()}),t,$t("Starred only",this.starred,s=>{this.starred=s,this.page=1,this.load()}),o("span",{class:"atfe__count",attrs:{role:"status"},text:""}),m("Export CSV",()=>void this.exportEntries("csv"),"secondary","download"),m("JSON",()=>void this.exportEntries("json"),"secondary"))}async showForm(t){this.formId=t,this.page=1,this.selection.clear(),this.selected=null,this.renderBar(),await this.load()}async load(){if(!this.formId){b(this.list),this.list.append(o("p",{class:"atfb-hint",text:"No forms yet."}));return}const t=++this.loadSeq;try{const s=await g.listEntries({form_id:this.formId,status:this.status==="inbox"?void 0:this.status,search:this.search,page:this.page,starred:this.starred});if(t!==this.loadSeq)return;if(this.page>1&&this.page>s.pages)return this.page=Math.max(1,s.pages),this.load();this.entries=s.entries,this.total=s.total,this.pages=s.pages,this.renderList(),this.reconcileSelection();const n=this.bar.querySelector(".atfe__count");n&&(n.textContent=`${this.total} ${this.total===1?"entry":"entries"}`)}catch(s){if(t!==this.loadSeq)return;b(this.list),this.list.append(o("p",{class:"atfb-error",text:s instanceof Error?s.message:"Could not load entries."}))}}reconcileSelection(){this.selected&&!this.entries.some(t=>t.id===this.selected?.id)&&(this.selected=null),this.paintedSelectionId!==(this.selected?.id??0)&&this.renderDetail()}renderList(){if(b(this.list),!this.entries.length){this.list.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:this.search?"Nothing matches that.":"No entries yet."})]}));return}const t=new Set(this.entries.map(n=>n.id));for(const n of Array.from(this.selection))t.has(n)||this.selection.delete(n);this.list.append(this.renderBulkBar());const s=o("div",{class:"atfe__rows",attrs:{role:"list"}});for(const n of this.entries)s.append(this.renderRow(n));this.list.append(s),this.pages>1&&this.list.append(o("div",{class:"atfe__pager",children:[m("Previous",()=>{this.page=Math.max(1,this.page-1),this.load()}),o("span",{text:`Page ${this.page} of ${this.pages}`}),m("Next",()=>{this.page=Math.min(this.pages,this.page+1),this.load()})]}))}renderBulkBar(){const t=this.selection.size,s=o("input",{type:"checkbox",attrs:{"aria-label":"Select every entry on this page"},on:{change:n=>{const r=n.target.checked;this.entries.forEach(i=>{r?this.selection.add(i.id):this.selection.delete(i.id)}),this.renderList()}}});return s.checked=t>0&&t===this.entries.length,s.indeterminate=t>0&&tvoid this.bulk("alltfo-read")):null,t?m("Unread",()=>void this.bulk("alltfo-unread")):null,t?m("Spam",()=>void this.bulk("alltfo-spam")):null,t&&h?.canEdit?m("Delete",()=>void this.bulkDelete(),"danger"):null]})}async bulk(t){const s=Array.from(this.selection);for(const n of s)try{await g.updateEntry(n,{status:t})}catch{}this.selection.clear(),await this.load()}async bulkDelete(){const t=Array.from(this.selection);if(await H(`Delete ${t.length} ${t.length===1?"entry":"entries"} and any files uploaded with them? It cannot be undone.`,"Delete entries")){for(const n of t)try{await g.deleteEntry(n)}catch{}this.selection.clear(),this.selected=null,await this.load(),this.renderDetail()}}renderRow(t){const s=t.status==="alltfo-unread",n=o("div",{class:`atfe__row${s?" is-unread":""}${this.selected?.id===t.id?" is-selected":""}`,attrs:{role:"listitem",tabindex:"0","data-entry":t.id},children:[o("input",{class:"atfe__select",type:"checkbox",attrs:{"aria-label":`Select ${t.title}`,checked:this.selection.has(t.id)},on:{click:r=>r.stopPropagation(),change:r=>{r.target.checked?this.selection.add(t.id):this.selection.delete(t.id),this.list.querySelector(".atfe__bulk")?.replaceWith(this.renderBulkBar())}}}),o("button",{class:`atfe__star${t.starred?" is-on":""}`,type:"button",attrs:{"aria-label":t.starred?"Unstar this entry":"Star this entry"},on:{click:r=>{r.stopPropagation(),this.toggleStar(t)}},children:[q("star-filled")]}),o("div",{class:"atfe__row-body",children:[o("strong",{text:t.title}),o("span",{class:"atfe__row-meta",text:t.dateHuman})]}),t.notes?o("span",{class:"atfb-badge",text:`💬 ${t.notes}`}):null,t.spam?o("span",{class:"atfb-badge atfb-badge--spam",text:"spam"}):null]});return n.addEventListener("click",()=>{j().recentlyEndedDrag()||this.select(t)}),n.addEventListener("keydown",r=>{(r.key==="Enter"||r.key===" ")&&(r.preventDefault(),this.select(t))}),n.addEventListener("pointerdown",r=>{if(r.target.closest("button"))return;const i=o("div",{class:"atfe__ghost",children:[q("feedback"),o("span",{text:t.title})]});j().start({payload:yt(J,n,{entry:t,formId:t.formId,formTitle:t.formTitle},r,i),origin:r})}),n}async select(t){const s=++this.selectSeq;try{const n=await g.getEntry(t.id);if(s!==this.selectSeq)return;this.selected=n;const r=this.entries.find(i=>i.id===t.id);r&&(r.status=this.selected.status),this.renderList(),this.renderDetail()}catch(n){if(s!==this.selectSeq)return;E("Could not open that entry",n instanceof Error?n.message:"","error")}}renderDetail(){this.paintedSelectionId=this.selected?.id??0,G(this.root,this.selected?qt(this.selected,h?.adminUrl??""):null),b(this.detail);const t=this.selected;if(!t){this.detail.append(o("div",{class:"atfb-placeholder",children:[o("p",{text:"Pick an entry to read it."})]}));return}const s=o("dl",{class:"atfe__answers"});for(const n of t.fields)n.formatted&&s.append(o("dt",{text:n.label||n.id}),o("dd",{text:n.formatted}));this.detail.append(o("div",{class:"atfe__detail",children:[o("div",{class:"atfe__detail-head",children:[o("h2",{text:t.title}),o("p",{class:"atfb-hint",text:`${t.formTitle} — ${t.dateHuman}`})]}),s,t.quiz?o("p",{class:"atfe__quiz",text:`Score: ${t.quiz.score} of ${t.quiz.total} (${t.quiz.percent}%) — ${t.quiz.passed?"passed":"not passed"}`}):null,o("details",{class:"atfb-section",children:[o("summary",{text:"Where it came from"}),o("p",{class:"atfb-hint",text:t.ip?`IP: ${t.ip}`:"No IP recorded."}),t.referrer?o("p",{class:"atfb-hint",text:`Referrer: ${t.referrer}`}):null,t.userAgent?o("p",{class:"atfb-hint",text:t.userAgent}):null]}),o("div",{class:"atfe__actions",children:[m(t.status==="alltfo-spam"?"Not spam":"Mark as spam",()=>void this.setStatus(t,t.status==="alltfo-spam"?"alltfo-read":"alltfo-spam")),m(t.status==="alltfo-unread"?"Mark read":"Mark unread",()=>void this.setStatus(t,t.status==="alltfo-unread"?"alltfo-read":"alltfo-unread")),t.canDelete?m("Delete",()=>void this.remove(t),"danger"):null]})]}))}async toggleStar(t){try{const s=await g.updateEntry(t.id,{starred:!t.starred});t.starred=s.starred,this.renderList()}catch(s){E("Could not update that entry",s instanceof Error?s.message:"","error")}}async setStatus(t,s){try{const n=await g.updateEntry(t.id,{status:s});this.selected=n,await this.load(),this.renderDetail()}catch(n){E("Could not update that entry",n instanceof Error?n.message:"","error")}}async remove(t){if(await H("Delete this entry and any files uploaded with it? It cannot be undone.","Delete entry"))try{await g.deleteEntry(t.id),this.selected=null,await this.load(),this.renderDetail()}catch(s){E("Could not delete that entry",s instanceof Error?s.message:"","error")}}async exportEntries(t){try{const{filename:s,csv:n}=await g.exportEntries({form_id:this.formId,search:this.search,starred:this.starred,format:t}),r=new Blob([n],{type:t==="json"?"application/json":"text/csv;charset=utf-8"}),i=URL.createObjectURL(r),a=o("a",{href:i,attrs:{download:s}});document.body.append(a),a.click(),a.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),1e3)}catch(s){E("Could not export",s instanceof Error?s.message:"","error")}}}let y=null;document.addEventListener("alltfo-open-entries-form",e=>{const t=Number(e.detail?.formId??0);t&&y?.showForm(t)});let F=null;function P(){if(F?.isConnected)return;y&&(y.destroy(),y=null,F=null);const e=document.querySelector("[data-atfe-root]:not([data-atfe-mounted])");!e||!h?.canRead||(e.dataset.atfeMounted="1",F=e,Tt(e),kt().then(()=>{e.isConnected&&(y=new Rt(e),y.start())}))}function V(){P(),lt()}return ct(),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",V):V(),document.addEventListener("os-window-content-loaded",P),I.mountEntries=P,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"}),I}({}); diff --git a/src/builder.ts b/src/builder.ts index 1cd6a9c..f3400e0 100644 --- a/src/builder.ts +++ b/src/builder.ts @@ -2596,6 +2596,232 @@ export class Builder { * canvas, or from a *second* builder window, which is what the shell's * shared drag manager buys and an iframe could not. */ + /** + * The animated insertion gap for one drop container — the canvas list, or + * a repeater's zone. + * + * While a field payload is over the container, a slot the size of the + * dragged card follows the pointer, the dragged card leaves the flow, and + * the other cards slide out of the way with first/last-position + * transforms — so the list previews, in real time, exactly the layout the + * drop will produce. + * + * @param container The drop target element; the gap shows while it has + * the `is-dropping` class. + * @param itemSelector The cards that reflow, `.atfb-card` or `.atfb-subcard`. + * @param findCard Resolves a dragged field id to its card in this + * container's world, or null for one it doesn't hold. + * @param accepts Optional payload gate mirroring the drop target's + * own `accept()`, so a drag the target will refuse + * never opens a gap it cannot honour. + * @return `enter`/`leave`/`drop` to wire into the drop target, and a + * `teardown` for the document-level listeners. + */ + private gapAnimator( + container: HTMLElement, + itemSelector: string, + findCard: ( fieldId: string ) => HTMLElement | null, + accepts?: ( data: Record< string, unknown > ) => boolean + ): { + enter( fieldId?: string ): void; + leave(): void; + drop( clientY: number, source?: HTMLElement | null ): number; + teardown(): void; + } { + const marker = el( 'div', { class: 'atfb-marker', attrs: { 'aria-hidden': 'true' } } ); + + /** + * The slot the marker currently shows, in the same "list without the + * dragged card" indexing the drop uses. Null while no gap is open. + * + * The drop reads this instead of re-measuring the pointer: with a + * card-sized gap open the cards are nowhere near where a measurement + * of the restored layout would put them, so a recomputed index lands + * the field a slot away from where the gap said it would. + */ + let shownIndex: number | null = null; + + /** The card lifted out of the flow while its gap is open, if any. */ + let liftedCard: HTMLElement | null = null; + + /** The gap's height — the dragged card's, measured before it is lifted. */ + let slotSize = 0; + + const restore = () => { + marker.remove(); + liftedCard?.classList.remove( 'atfb-lifted' ); + liftedCard = null; + shownIndex = null; + }; + + // First/last-position animation: measure where every card sits, mutate + // the DOM, transform each card back to its old spot and release — so + // the gap opening, moving and closing reads as cards sliding out of + // the way in real time rather than teleporting. + const moveAnimated = ( mutate: () => void ) => { + const cards = Array.from( container.querySelectorAll< HTMLElement >( itemSelector ) ); + // A lifted card has no box, and a rect of zeros as a start position + // would animate its restore in from the viewport's top corner — so + // only cards visible *before* the mutation get one. + const before = new Map( + cards + .filter( ( card ) => ! card.classList.contains( 'atfb-lifted' ) ) + .map( ( card ) => [ card, card.getBoundingClientRect().top ] ) + ); + + mutate(); + + for ( const card of cards ) { + card.style.transition = 'none'; + card.style.transform = ''; + } + + const moved = cards.filter( ( card ) => { + const from = before.get( card ); + + if ( from === undefined || ! card.isConnected || card.classList.contains( 'atfb-lifted' ) ) { + return false; + } + + const delta = from - card.getBoundingClientRect().top; + + if ( Math.abs( delta ) < 0.5 ) { + return false; + } + + card.style.transform = `translateY(${ delta }px)`; + + return true; + } ); + + // One reflow commits the start positions, then every moved card + // transitions to its natural spot. Cards that didn't move give the + // inline `transition: none` straight back — left on, it would keep + // eating their hover transitions until the next render. + void container.offsetHeight; + + for ( const card of cards ) { + if ( ! moved.includes( card ) ) { + card.style.transition = ''; + continue; + } + + card.style.transition = 'transform 160ms ease'; + card.style.transform = ''; + card.addEventListener( + 'transitionend', + () => { + card.style.transition = ''; + }, + { once: true } + ); + } + }; + + // The gap follows the pointer. Driven from the drag manager's move + // event, which both managers emit. + const onMove = ( event: Event ) => { + const detail = ( + event as CustomEvent< { + payload?: { type: string; data?: Record< string, unknown > }; + clientY?: number; + } > + ).detail; + + if ( detail?.payload?.type !== FIELD_PAYLOAD_TYPE || ! container.classList.contains( 'is-dropping' ) ) { + return; + } + + if ( accepts && ! accepts( detail.payload.data ?? {} ) ) { + return; + } + + // The dragged card is left out of the count, exactly as `drop` + // leaves it out. Gap and drop must be computed in the same + // indexing — counted two different ways, the field lands one slot + // away from where the gap said it would. + const fieldId = detail.payload.data?.fieldId; + const dragged = typeof fieldId === 'string' ? findCard( fieldId ) : null; + const index = insertionIndex( container, itemSelector, detail.clientY ?? 0, dragged ?? undefined ); + + // Every pointer move lands here; only a move that changes the slot + // touches layout. + if ( index === shownIndex && marker.isConnected ) { + return; + } + + shownIndex = index; + + moveAnimated( () => { + // The dragged card leaves the flow the moment its gap first + // opens: the ghost under the pointer is the card now, and the + // gap is where it will land. Both at once would show the field + // twice, one of them stale. + if ( dragged && dragged !== liftedCard ) { + liftedCard?.classList.remove( 'atfb-lifted' ); + dragged.classList.add( 'atfb-lifted' ); + liftedCard = dragged; + } + + marker.style.blockSize = `${ Math.max( 8, Math.round( slotSize ) ) }px`; + + const cards = Array.from( container.querySelectorAll< HTMLElement >( itemSelector ) ).filter( + ( card ) => card !== dragged + ); + + if ( index >= cards.length ) { + container.append( marker ); + } else { + cards[ index ].before( marker ); + } + } ); + }; + + // The safety net for a drag that ends anywhere but a clean drop here — + // Escape, window blur, a drop swallowed by another target. The restore + // is deferred a tick because a manager may emit its end event before + // it delivers the drop, and the drop still needs `shownIndex`; after a + // clean drop this is a no-op. + const onEnd = () => { + container.classList.remove( 'is-dropping' ); + window.setTimeout( () => moveAnimated( restore ), 0 ); + }; + + document.addEventListener( 'os.drag.move', onMove ); + document.addEventListener( 'os.drag.end', onEnd ); + + return { + enter: ( fieldId ) => { + const card = fieldId ? findCard( fieldId ) : null; + + // Measured now, before the card is lifted out of the flow — + // afterwards it has no box left to measure. A palette item has + // no card yet, so its gap is a nominal card height. + slotSize = + card && ! card.classList.contains( 'atfb-lifted' ) + ? card.getBoundingClientRect().height + : slotSize || 44; + }, + leave: () => moveAnimated( restore ), + drop: ( clientY, source ) => { + // The slot the open gap showed, when one is open. Only a drop + // that never opened one — possible with a pointer that never + // moved after entering — falls back to measuring, against a + // layout that in that case was never distorted. + const index = shownIndex ?? insertionIndex( container, itemSelector, clientY, source ?? undefined ); + + restore(); + + return index; + }, + teardown: () => { + document.removeEventListener( 'os.drag.move', onMove ); + document.removeEventListener( 'os.drag.end', onEnd ); + restore(); + }, + }; + } + private registerCanvasTarget( list: HTMLElement ): void { // Every canvas render builds a fresh list element, and this runs on every // render — so the previous registration and its document-level move @@ -2604,20 +2830,24 @@ export class Builder { this.canvasTarget?.(); this.canvasTarget = null; - const marker = el( 'div', { class: 'atfb-marker', attrs: { 'aria-hidden': 'true' } } ); + const gap = this.gapAnimator( list, '.atfb-card', ( fieldId ) => + this.canvas.querySelector< HTMLElement >( `[data-atfb-card="${ CSS.escape( fieldId ) }"]` ) + ); const teardown = getDragManager().registerDropTarget( { id: `atfb-canvas-${ this.form?.id ?? 0 }`, element: list, accept: ( payload ) => payload.type === FIELD_PAYLOAD_TYPE, - onEnter: () => list.classList.add( 'is-dropping' ), + onEnter: ( session ) => { + list.classList.add( 'is-dropping' ); + gap.enter( ( session.payload.data as { fieldId?: string } ).fieldId ); + }, onLeave: () => { list.classList.remove( 'is-dropping' ); - marker.remove(); + gap.leave(); }, onDrop: ( session, position ) => { list.classList.remove( 'is-dropping' ); - marker.remove(); const data = session.payload.data as { fieldType?: string; @@ -2630,7 +2860,7 @@ export class Builder { ? this.canvas.querySelector< HTMLElement >( `[data-atfb-card="${ CSS.escape( data.fieldId ) }"]` ) : null; - const index = insertionIndex( list, '.atfb-card', position.clientY, source ?? undefined ); + const index = gap.drop( position.clientY, source ); if ( data.isNew && data.fieldType ) { this.addField( data.fieldType, index ); @@ -2658,47 +2888,10 @@ export class Builder { const zoneTeardowns = this.wireRepeaterZones( list ); - // The insertion marker follows the pointer while a field is over the - // canvas. Driven from the shell's own move event so it works with either - // manager. - const onMove = ( event: Event ) => { - const detail = ( - event as CustomEvent< { payload?: { type: string; data?: { fieldId?: string } }; clientY?: number } > - ).detail; - - if ( detail?.payload?.type !== FIELD_PAYLOAD_TYPE || ! list.classList.contains( 'is-dropping' ) ) { - return; - } - - // The dragged card is left out of the count, exactly as `onDrop` - // leaves it out. Marker and drop must be computed in the same - // indexing — counted two different ways, the field lands one slot - // away from where the marker said it would. - const dragged = detail.payload.data?.fieldId - ? this.canvas.querySelector< HTMLElement >( - `[data-atfb-card="${ CSS.escape( detail.payload.data.fieldId ) }"]` - ) - : null; - - const y = detail.clientY ?? 0; - const index = insertionIndex( list, '.atfb-card', y, dragged ?? undefined ); - const cards = Array.from( list.querySelectorAll< HTMLElement >( '.atfb-card' ) ).filter( - ( card ) => card !== dragged - ); - - if ( index >= cards.length ) { - list.append( marker ); - } else { - cards[ index ].before( marker ); - } - }; - - document.addEventListener( 'os.drag.move', onMove ); - this.canvasTarget = () => { teardown(); zoneTeardowns.forEach( ( zoneTeardown ) => zoneTeardown() ); - document.removeEventListener( 'os.drag.move', onMove ); + gap.teardown(); }; } @@ -2721,36 +2914,47 @@ export class Builder { list.querySelectorAll< HTMLElement >( '[data-atfb-repeater-zone]' ).forEach( ( zone ) => { const repeaterId = zone.dataset.atfbRepeaterZone ?? ''; - teardowns.push( - getDragManager().registerDropTarget( { - id: `atfb-repzone-${ this.form?.id ?? 0 }-${ repeaterId }`, - element: zone, - accept: ( payload ) => { - if ( payload.type !== FIELD_PAYLOAD_TYPE ) { - return false; - } + // The zone's acceptance rule, shared between the drop target's + // `accept()` and its gap animator — a drag the zone will refuse + // must not open a gap in it either. + const acceptsData = ( raw: Record< string, unknown > ) => { + const data = raw as { fieldType?: string; fieldId?: string; field?: Field; isNew?: boolean }; - const data = payload.data as { - fieldType?: string; - fieldId?: string; - field?: Field; - isNew?: boolean; - }; + // The repeater itself dragged over its own zone must + // fall through to the canvas, not swallow the drop. + if ( data.fieldId === repeaterId ) { + return false; + } - // The repeater itself dragged over its own zone must - // fall through to the canvas, not swallow the drop. - if ( data.fieldId === repeaterId ) { - return false; - } + const type = data.isNew + ? data.fieldType + : this.locateField( data.fieldId ?? '' )?.field.type ?? data.field?.type; + + return !! type && this.allowedInRepeater( type ); + }; + + const gap = this.gapAnimator( + zone, + '.atfb-subcard', + ( fieldId ) => list.querySelector< HTMLElement >( `[data-atfb-subfield="${ CSS.escape( fieldId ) }"]` ), + acceptsData + ); - const type = data.isNew - ? data.fieldType - : this.locateField( data.fieldId ?? '' )?.field.type ?? data.field?.type; + teardowns.push( () => gap.teardown() ); - return !! type && this.allowedInRepeater( type ); + teardowns.push( + getDragManager().registerDropTarget( { + id: `atfb-repzone-${ this.form?.id ?? 0 }-${ repeaterId }`, + element: zone, + accept: ( payload ) => payload.type === FIELD_PAYLOAD_TYPE && acceptsData( payload.data ), + onEnter: ( session ) => { + zone.classList.add( 'is-dropping' ); + gap.enter( ( session.payload.data as { fieldId?: string } ).fieldId ); + }, + onLeave: () => { + zone.classList.remove( 'is-dropping' ); + gap.leave(); }, - onEnter: () => zone.classList.add( 'is-dropping' ), - onLeave: () => zone.classList.remove( 'is-dropping' ), onDrop: ( session, position ) => { zone.classList.remove( 'is-dropping' ); @@ -2767,7 +2971,7 @@ export class Builder { ) : null; - const index = insertionIndex( zone, '.atfb-subcard', position.clientY, source ?? undefined ); + const index = gap.drop( position.clientY, source ); if ( data.isNew && data.fieldType ) { this.addFieldToRepeater( data.fieldType, repeaterId, index ); diff --git a/src/dnd.ts b/src/dnd.ts index 66df3a2..25d4e17 100644 --- a/src/dnd.ts +++ b/src/dnd.ts @@ -76,6 +76,16 @@ class FallbackDragManager implements DragManagerApi { this.lastEndMs = Date.now(); }; + // The same lifecycle events the shell's manager broadcasts, so code + // that draws during a drag — the builder's insertion gap — listens to + // one event stream and works under either manager, instead of the + // fallback silently never showing what the shell shows. + const emit = ( name: 'os.drag.start' | 'os.drag.move' | 'os.drag.end', at?: PointerEvent ) => { + document.dispatchEvent( + new CustomEvent( name, { detail: { payload, clientX: at?.clientX, clientY: at?.clientY } } ) + ); + }; + const session: DragSession = { payload, isFinished: () => finished, @@ -86,6 +96,11 @@ class FallbackDragManager implements DragManagerApi { finished = true; cleanup(); + + if ( lifted ) { + emit( 'os.drag.end' ); + } + opts.onCancel?.( reason ); }, }; @@ -108,6 +123,7 @@ class FallbackDragManager implements DragManagerApi { document.body.appendChild( ghost ); position( event ); + emit( 'os.drag.start', event ); }; const position = ( event: PointerEvent ) => { @@ -138,6 +154,11 @@ class FallbackDragManager implements DragManagerApi { hovered = next; hovered?.onEnter?.( session ); } + + // After the enter/leave bookkeeping, so a listener drawing on this + // event always sees the target already entered — same order as the + // shell. + emit( 'os.drag.move', event ); }; const onUp = ( event: PointerEvent ) => { @@ -164,10 +185,15 @@ class FallbackDragManager implements DragManagerApi { if ( target && target.accept( payload ) ) { opts.onCommit?.( target ); void target.onDrop( session, { clientX: event.clientX, clientY: event.clientY } ); + // End is emitted *after* the drop, so a drop handler can still + // read whatever state the move events built up — the builder's + // insertion gap depends on this ordering. + emit( 'os.drag.end', event ); return; } + emit( 'os.drag.end', event ); opts.onCancel?.( target ? 'rejected' : 'no-target' ); }; @@ -325,6 +351,8 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { return payload && payloadTypes.includes( payload.type ) ? payload.source : null; }; + const preventSelection = ( event: Event ) => event.preventDefault(); + const onStart = ( event: Event ) => { const source = sourceOf( event ); @@ -334,6 +362,15 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { // manager sets at lift — the shell moves the ghost but knows // nothing about this plugin's cursors. document.body.classList.add( 'atf-drag-active' ); + // A drag is not a selection. The press already anchored one during + // the pre-lift travel, and every further move would sweep it across + // the page behind the ghost — so the anchor goes, and `selectstart` + // is refused for the duration in case the browser tries to re-arm + // it mid-drag. The `atf-drag-active` CSS turns off `user-select` + // too; belt and braces, because a half-page blue smear reads as the + // drag having gone wrong. + window.getSelection()?.removeAllRanges(); + document.addEventListener( 'selectstart', preventSelection ); } }; const onEnd = ( event: Event ) => { @@ -342,6 +379,7 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { if ( source ) { source.classList.remove( 'atf-is-dragging' ); document.body.classList.remove( 'atf-drag-active' ); + document.removeEventListener( 'selectstart', preventSelection ); } }; @@ -351,6 +389,7 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { return () => { document.removeEventListener( 'os.drag.start', onStart ); document.removeEventListener( 'os.drag.end', onEnd ); + document.removeEventListener( 'selectstart', preventSelection ); }; } @@ -366,6 +405,13 @@ export function watchShellDragVisuals( payloadTypes: string[] ): () => void { * would snap the element's corner to the cursor at lift time, which reads as the * thing jumping out from under the pointer. */ +/** + * The plugin's style-scope roots. Everything this plugin draws sits under one + * of these classes, which carry the custom properties, font size and line + * height its CSS assumes. + */ +const SCOPE_CLASSES = [ 'atfb', 'atfe', 'atfs', 'atfm' ]; + export function buildPayload( type: string, source: HTMLElement, @@ -375,6 +421,28 @@ export function buildPayload( ): DragPayload { const rect = source.getBoundingClientRect(); + // With no ghost supplied, the manager clones the source — and appends the + // clone to `document.body`, outside the plugin's scope root, where every + // custom property and the root's type settings stop applying: the ghost's + // fonts and colours visibly shift the moment it is lifted. So the default + // ghost is built here instead — the same clone, wrapped in an element + // carrying the scope class the source lived under, with the wrapper's own + // layout neutralised in CSS (`.atf-ghost-scope`). + if ( ! ghost ) { + const scope = SCOPE_CLASSES.find( ( cls ) => source.closest( `.${ cls }` ) ); + + if ( scope ) { + const clone = source.cloneNode( true ) as HTMLElement; + + clone.style.transition = ''; + clone.style.transform = ''; + + ghost = document.createElement( 'div' ); + ghost.className = `${ scope } atf-ghost-scope`; + ghost.appendChild( clone ); + } + } + // The ghost is sized here rather than in CSS. A `position: fixed` element // with no width resolves against the containing block — the viewport — so a // ghost that looks fine in the fallback manager (which sets a width itself)