diff --git a/assets/js/widget.js b/assets/js/widget.js index f7455c8..699c5e6 100644 --- a/assets/js/widget.js +++ b/assets/js/widget.js @@ -284,6 +284,10 @@ var allTerrainFormsWidget = function(exports) { unsubscribe?.(); }; } + const registryHost = window; + const registry = registryHost.openStationWidgets || registryHost.desktopModeWidgets || {}; + registry["allterrain-forms/recent"] = renderWidget; + registryHost.openStationWidgets = registryHost.desktopModeWidgets = registry; function mountStandalone() { document.querySelectorAll("[data-atfw-root]").forEach((host) => { if (host.dataset.atfwMounted) { diff --git a/assets/js/widget.min.js b/assets/js/widget.min.js index 04c97e9..c6e5346 100644 --- a/assets/js/widget.min.js +++ b/assets/js/widget.min.js @@ -1 +1 @@ -var allTerrainFormsWidget=function(p){"use strict";function S(){return window.wp?.os??null}const d=window.allTerrainForms;class w extends Error{constructor(t,r,n="",s){super(t),this.name="ApiError",this.status=r,this.code=n,this.data=s}}function E(e,t){return e.includes("?")?`${e}${t.replace("?","&")}`:`${e}${t}`}async function u(e,t={}){if(!d?.restUrl)throw new w("AllTerrain Forms is not configured on this page.",0);const r=E(d.restUrl,e),n={"Content-Type":"application/json",...t.headers??{}};d.nonce&&(n["X-WP-Nonce"]=d.nonce);const s=S(),i=await(s?.fetch?(f,h)=>s.fetch(f,h,{source:"allterrain-forms"}):(f,h)=>fetch(f,h))(r,{credentials:"same-origin",...t,headers:n});if(!i.ok){let f=`Request failed with status ${i.status}.`,h="",x;try{const b=await i.json();f=b.message??f,h=b.code??"",x=b.data}catch{}throw new w(f,i.status,h,x)}if(i.status!==204)return await i.json()}const o=e=>u(e);async function j(e){if(!d?.wpRestUrl)throw new w("AllTerrain Forms is not configured on this page.",0);const t=d.nonce?{"X-WP-Nonce":d.nonce}:{},r=S(),n=E(d.wpRestUrl,e),s=r?.fetch?await r.fetch(n,{credentials:"same-origin",headers:t},{source:"allterrain-forms"}):await fetch(n,{credentials:"same-origin",headers:t});if(!s.ok)throw new w(`Request failed with status ${s.status}.`,s.status);return await s.json()}function R(e){if(!e||!e.includes("&"))return e;const t=document.createElement("textarea");return t.innerHTML=e,t.value}const a=(e,t)=>u(e,{method:"POST",body:JSON.stringify(t)}),g=e=>u(e,{method:"DELETE"});function F(e){const t=new URLSearchParams;for(const[n,s]of Object.entries(e))s===void 0||s===""||s===!1||t.set(n,String(s));const r=t.toString();return r?`?${r}`:""}function m(e){const t=e?.schema?.settings;return t&&(!t.themeOverrides||Array.isArray(t.themeOverrides))&&(t.themeOverrides={...t.themeOverrides}),e}const O={assistantRevision:(e,t)=>u(`/assistant/forms/${e}`,{signal:t}),assistantValidate:(e,t)=>u("/assistant/validate",{method:"POST",body:JSON.stringify({draft:e}),signal:t}),assistantApply:(e,t,r,n,s)=>u("/assistant/apply",{method:"POST",body:JSON.stringify({draft:e,formId:t,revision:r,operationKey:s}),signal:n}).then(l=>({...m(l),operation:l.operation})),assistantOperation:(e,t)=>u(`/assistant/operations/${encodeURIComponent(e)}`,{signal:t}),config:()=>o("/config"),mailpoet:()=>o("/mailpoet"),listForms:()=>o("/forms"),listArchivedForms:()=>o("/forms?archived=1"),archiveForm:e=>a(`/forms/${e}/archive`,{}),unarchiveForm:e=>a(`/forms/${e}/unarchive`,{}),getForm:(e,t)=>u(`/forms/${e}`,{signal:t}).then(m),createForm:e=>a("/forms",e).then(m),updateForm:(e,t)=>a(`/forms/${e}`,t).then(m),exportForm:(e,t)=>a(`/forms/${e}/export`,t),validateFormPackage:e=>a("/form-packages/validate",{package:e}),importFormPackage:e=>a("/form-packages/import",{package:e}).then(t=>({...m(t),importWarnings:t.importWarnings})),duplicateForm:e=>a(`/forms/${e}/duplicate`,{}).then(m),deleteForm:e=>g(`/forms/${e}`),preview:(e,t)=>a(`/forms/${e}/preview`,t),pages:()=>j("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(e=>e.map(t=>({id:t.id,title:R(t.title?.rendered??"")||`#${t.id}`}))),mergeTags:e=>o(`/forms/${e}/merge-tags`).then(t=>t.groups),analytics:(e,t="")=>o(`/forms/${e}/analytics${t?`?dimension=${encodeURIComponent(t)}`:""}`),demoStatus:()=>o("/demo"),demoSeed:e=>a("/demo",e?{count:e}:{}),demoRemove:()=>g("/demo"),listEntries:e=>o(`/entries${F(e)}`),getEntry:e=>o(`/entries/${e}`),updateEntry:(e,t)=>a(`/entries/${e}`,t),deleteEntry:e=>g(`/entries/${e}`),exportEntries:e=>o(`/entries/export${F(e)}`),listThemes:()=>o("/themes"),saveTheme:e=>a("/themes",e),deleteTheme:e=>g(`/themes/${e}`)};function c(e,t={}){const r=document.createElement(e);t.class&&(r.className=t.class),t.text!==void 0&&(r.textContent=t.text),t.html!==void 0&&(r.innerHTML=t.html),t.title&&(r.title=t.title),t.type&&"type"in r&&(r.type=t.type),t.value!==void 0&&"value"in r&&(r.value=t.value),t.placeholder!==void 0&&"placeholder"in r&&(r.placeholder=t.placeholder),t.href&&"href"in r&&(r.href=t.href);for(const[n,s]of Object.entries(t.attrs??{}))s===void 0||s===!1||r.setAttribute(n,s===!0?"":String(s));Object.assign(r.style,t.style??{});for(const[n,s]of Object.entries(t.on??{}))r.addEventListener(n,s);for(const n of t.children??[])n==null||n===!1||r.append(n);return r}function v(e){e.replaceChildren()}const A=12e4;async function y(e){try{const t=await O.listForms();if(!t.length){v(e),e.append(c("p",{class:"atfw__empty",text:"No forms yet."}));return}const{entries:r}=await O.listEntries({per_page:8});v(e),e.append(P(t),k(r))}catch(t){v(e),e.append(c("p",{class:"atfw__empty",text:t instanceof Error?t.message:"Could not load submissions."}))}}function P(e){const t=e.reduce((l,i)=>l+i.submissions,0),r=e.reduce((l,i)=>l+i.views,0),n=e.reduce((l,i)=>l+i.unread,0),s=r>0?Math.floor(t/r*100):0;return c("div",{class:"atfw__summary",children:[$(String(t),"submissions"),$(`${s}%`,"converted"),$(String(n),"unread")]})}function $(e,t){return c("div",{class:"atfw__stat",children:[c("strong",{class:"atfw__stat-value",text:e}),c("span",{class:"atfw__stat-label",text:t})]})}function k(e){return e.length?c("ul",{class:"atfw__list",children:e.map(t=>c("li",{class:`atfw__item${t.status==="alltfo-unread"?" is-unread":""}`,children:[c("span",{class:"atfw__title",text:t.title}),c("span",{class:"atfw__meta",text:`${t.formTitle} · ${t.dateHuman}`})]}))}):c("p",{class:"atfw__empty",text:"Nothing submitted yet."})}function _(e){e.classList.add("atfw"),y(e);const t=window.setInterval(()=>void y(e),A),n=window.wp?.os?.subscribe?.("os.alltfo_entry.changed",()=>void y(e));return()=>{window.clearInterval(t),n?.()}}function T(){document.querySelectorAll("[data-atfw-root]").forEach(e=>{e.dataset.atfwMounted||(e.dataset.atfwMounted="1",_(e))})}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",T):T(),p.render=_,p.renderWidget=_,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"}),p}({}); +var allTerrainFormsWidget=function(p){"use strict";function E(){return window.wp?.os??null}const l=window.allTerrainForms;class g extends Error{constructor(t,s,r="",n){super(t),this.name="ApiError",this.status=s,this.code=r,this.data=n}}function F(e,t){return e.includes("?")?`${e}${t.replace("?","&")}`:`${e}${t}`}async function u(e,t={}){if(!l?.restUrl)throw new g("AllTerrain Forms is not configured on this page.",0);const s=F(l.restUrl,e),r={"Content-Type":"application/json",...t.headers??{}};l.nonce&&(r["X-WP-Nonce"]=l.nonce);const n=E(),i=await(n?.fetch?(f,h)=>n.fetch(f,h,{source:"allterrain-forms"}):(f,h)=>fetch(f,h))(s,{credentials:"same-origin",...t,headers:r});if(!i.ok){let f=`Request failed with status ${i.status}.`,h="",k;try{const b=await i.json();f=b.message??f,h=b.code??"",k=b.data}catch{}throw new g(f,i.status,h,k)}if(i.status!==204)return await i.json()}const o=e=>u(e);async function R(e){if(!l?.wpRestUrl)throw new g("AllTerrain Forms is not configured on this page.",0);const t=l.nonce?{"X-WP-Nonce":l.nonce}:{},s=E(),r=F(l.wpRestUrl,e),n=s?.fetch?await s.fetch(r,{credentials:"same-origin",headers:t},{source:"allterrain-forms"}):await fetch(r,{credentials:"same-origin",headers:t});if(!n.ok)throw new g(`Request failed with status ${n.status}.`,n.status);return await n.json()}function W(e){if(!e||!e.includes("&"))return e;const t=document.createElement("textarea");return t.innerHTML=e,t.value}const a=(e,t)=>u(e,{method:"POST",body:JSON.stringify(t)}),w=e=>u(e,{method:"DELETE"});function O(e){const t=new URLSearchParams;for(const[r,n]of Object.entries(e))n===void 0||n===""||n===!1||t.set(r,String(n));const s=t.toString();return s?`?${s}`:""}function m(e){const t=e?.schema?.settings;return t&&(!t.themeOverrides||Array.isArray(t.themeOverrides))&&(t.themeOverrides={...t.themeOverrides}),e}const T={assistantRevision:(e,t)=>u(`/assistant/forms/${e}`,{signal:t}),assistantValidate:(e,t)=>u("/assistant/validate",{method:"POST",body:JSON.stringify({draft:e}),signal:t}),assistantApply:(e,t,s,r,n)=>u("/assistant/apply",{method:"POST",body:JSON.stringify({draft:e,formId:t,revision:s,operationKey:n}),signal:r}).then(d=>({...m(d),operation:d.operation})),assistantOperation:(e,t)=>u(`/assistant/operations/${encodeURIComponent(e)}`,{signal:t}),config:()=>o("/config"),mailpoet:()=>o("/mailpoet"),listForms:()=>o("/forms"),listArchivedForms:()=>o("/forms?archived=1"),archiveForm:e=>a(`/forms/${e}/archive`,{}),unarchiveForm:e=>a(`/forms/${e}/unarchive`,{}),getForm:(e,t)=>u(`/forms/${e}`,{signal:t}).then(m),createForm:e=>a("/forms",e).then(m),updateForm:(e,t)=>a(`/forms/${e}`,t).then(m),exportForm:(e,t)=>a(`/forms/${e}/export`,t),validateFormPackage:e=>a("/form-packages/validate",{package:e}),importFormPackage:e=>a("/form-packages/import",{package:e}).then(t=>({...m(t),importWarnings:t.importWarnings})),duplicateForm:e=>a(`/forms/${e}/duplicate`,{}).then(m),deleteForm:e=>w(`/forms/${e}`),preview:(e,t)=>a(`/forms/${e}/preview`,t),pages:()=>R("wp/v2/pages?per_page=100&status=publish&orderby=title&order=asc&_fields=id,title").then(e=>e.map(t=>({id:t.id,title:W(t.title?.rendered??"")||`#${t.id}`}))),mergeTags:e=>o(`/forms/${e}/merge-tags`).then(t=>t.groups),analytics:(e,t="")=>o(`/forms/${e}/analytics${t?`?dimension=${encodeURIComponent(t)}`:""}`),demoStatus:()=>o("/demo"),demoSeed:e=>a("/demo",e?{count:e}:{}),demoRemove:()=>w("/demo"),listEntries:e=>o(`/entries${O(e)}`),getEntry:e=>o(`/entries/${e}`),updateEntry:(e,t)=>a(`/entries/${e}`,t),deleteEntry:e=>w(`/entries/${e}`),exportEntries:e=>o(`/entries/export${O(e)}`),listThemes:()=>o("/themes"),saveTheme:e=>a("/themes",e),deleteTheme:e=>w(`/themes/${e}`)};function c(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[r,n]of Object.entries(t.attrs??{}))n===void 0||n===!1||s.setAttribute(r,n===!0?"":String(n));Object.assign(s.style,t.style??{});for(const[r,n]of Object.entries(t.on??{}))s.addEventListener(r,n);for(const r of t.children??[])r==null||r===!1||s.append(r);return s}function $(e){e.replaceChildren()}const A=12e4;async function _(e){try{const t=await T.listForms();if(!t.length){$(e),e.append(c("p",{class:"atfw__empty",text:"No forms yet."}));return}const{entries:s}=await T.listEntries({per_page:8});$(e),e.append(M(t),P(s))}catch(t){$(e),e.append(c("p",{class:"atfw__empty",text:t instanceof Error?t.message:"Could not load submissions."}))}}function M(e){const t=e.reduce((d,i)=>d+i.submissions,0),s=e.reduce((d,i)=>d+i.views,0),r=e.reduce((d,i)=>d+i.unread,0),n=s>0?Math.floor(t/s*100):0;return c("div",{class:"atfw__summary",children:[S(String(t),"submissions"),S(`${n}%`,"converted"),S(String(r),"unread")]})}function S(e,t){return c("div",{class:"atfw__stat",children:[c("strong",{class:"atfw__stat-value",text:e}),c("span",{class:"atfw__stat-label",text:t})]})}function P(e){return e.length?c("ul",{class:"atfw__list",children:e.map(t=>c("li",{class:`atfw__item${t.status==="alltfo-unread"?" is-unread":""}`,children:[c("span",{class:"atfw__title",text:t.title}),c("span",{class:"atfw__meta",text:`${t.formTitle} · ${t.dateHuman}`})]}))}):c("p",{class:"atfw__empty",text:"Nothing submitted yet."})}function v(e){e.classList.add("atfw"),_(e);const t=window.setInterval(()=>void _(e),A),r=window.wp?.os?.subscribe?.("os.alltfo_entry.changed",()=>void _(e));return()=>{window.clearInterval(t),r?.()}}const y=window,x=y.openStationWidgets||y.desktopModeWidgets||{};x["allterrain-forms/recent"]=v,y.openStationWidgets=y.desktopModeWidgets=x;function j(){document.querySelectorAll("[data-atfw-root]").forEach(e=>{e.dataset.atfwMounted||(e.dataset.atfwMounted="1",v(e))})}return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",j):j(),p.render=v,p.renderWidget=v,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"}),p}({}); diff --git a/src/widget.ts b/src/widget.ts index 05b8167..c5032a1 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -135,12 +135,22 @@ export function renderWidget( host: HTMLElement ): () => void { * overwritten a moment later by the bundle itself, which is a bug that only * shows up in the built file and never in a test. * - * So the contract is expressed as an export instead: the shell finds - * `window.allTerrainFormsWidget.render` because `render` is what this module - * exports. + * The export stays for anything that reads that global. The shell itself does + * not: OpenStation looks up mount callbacks by widget id in + * `window.openStationWidgets` (`window.desktopModeWidgets` on older Desktop + * Mode builds), so the callback is registered there too. That is a different + * global from the one the IIFE overwrites, so assigning it here is safe. */ export { renderWidget as render }; +type WidgetRegistry = Record< string, ( host: HTMLElement ) => ( () => void ) | void >; + +// Merge, never replace: other plugins' widgets live in the same object. +const registryHost = window as unknown as { openStationWidgets?: WidgetRegistry; desktopModeWidgets?: WidgetRegistry }; +const registry: WidgetRegistry = registryHost.openStationWidgets || registryHost.desktopModeWidgets || {}; +registry[ 'allterrain-forms/recent' ] = renderWidget; +registryHost.openStationWidgets = registryHost.desktopModeWidgets = registry; + /** * Mounts into a plain container, for the admin page. *