|
46
|
|
- </footer>`}function Pt(e,n){const o=e.closest(".os-window")?.querySelector(".os-window__menu-panel")??null;if(!o||n.items.length===0)return null;const s=`${n.prefix}:`,i="data-os-app-menu-section";o.querySelectorAll(`[${i}="${n.prefix}"]`).forEach(f=>f.remove());const r=document.createElement("div");r.className="os-app__menu-section",r.setAttribute("role","presentation"),r.setAttribute(i,n.prefix),r.textContent=n.section,o.appendChild(r);const l=new Map;for(const f of n.items){const d=document.createElement("os-menu-item");d.setAttribute("role","menuitemcheckbox"),d.setAttribute("value",s+f.key),d.setAttribute(i,n.prefix),d.classList.add("os-window__menu-item","os-app__menu-item"),d.textContent=f.label||f.key,o.appendChild(d),l.set(f.key,d)}const u=()=>{for(const[f,d]of l)n.isChecked(f)?d.setAttribute("checked",""):d.removeAttribute("checked")};u();const c=f=>{const d=f.detail?.value;if(typeof d!="string"||!d.startsWith(s))return;const h=d.slice(s.length);l.has(h)&&(n.onToggle(h),u())};return o.addEventListener("os-menu-item-click",c),{refresh:u,dispose:()=>{o.removeEventListener("os-menu-item-click",c),r.remove();for(const f of l.values())f.remove();l.clear()}}}function Rt(e,n=null){const t=n??(typeof document<"u"?document.documentElement:null);if(!!t&&Ee(t)){e.hasAttribute("stacked")||e.setAttribute("stacked","");const i=e.getAttribute("sticky-columns");return i!==null&&(e.setAttribute("data-os-sticky-columns",i),e.removeAttribute("sticky-columns")),!0}e.hasAttribute("stacked")&&e.removeAttribute("stacked");const s=e.getAttribute("data-os-sticky-columns");return s!==null&&(e.setAttribute("sticky-columns",s),e.removeAttribute("data-os-sticky-columns")),!1}function xe(e){return Array.from(e.selection??[],String)}function Dt(){let e=null,n=!1,t=null,o=null;return{invalidateColumns(){e=null},invalidateData(){o=null},sync(s){const i={phone:!1,columnsChanged:!1,dataChanged:!1,selectionChanged:!1},r=s.table;if(!r)return i;const l=s.rowId??(c=>c.id),u=Rt(r);if(i.phone=u,u!==e&&(e=u,r.columns=s.columns(u),i.columnsChanged=!0),n||(n=!0,s.wire?.(r)),s.listKey!==t&&(t=s.listKey,xe(r).length>0&&(r.clearSelection(),i.selectionChanged=!0,s.onSelection?.([]))),s.fingerprint!==o){o=s.fingerprint,r.data=s.rows,i.dataChanged=!0;const c=new Set(s.rows.map(h=>String(l(h)))),f=xe(r),d=f.filter(h=>c.has(h));d.length!==f.length&&(r.selection=d,i.selectionChanged=!0,s.onSelection?.(d))}return i}}}function Bt(e,n){const t=n.local??{},o={id:e,hasLocal:r=>Object.prototype.hasOwnProperty.call(t,r),runLocal:(r,l,u,c)=>{const f=t[r];if(!f)return l;const d={...l},h=f(d,u,c);return h===void 0?d:h},render:r=>{vt(n.view(r),r.root),n.updated?.(r)},mounted:r=>n.mounted?.(r)},{placeholder:s}=n;s&&(o.placeholder=r=>s(r));const i=window;return(i.openStationApps??(i.openStationApps={}))[e]=o,o}function Wt(e){return window.openStationApps?.[e]}const Se=3e4,U=new Map;function jt(e,n){const t=U.get(e.id);if(t&&Date.now()-t.at<Se)return!1;const o={Accept:"application/json","Content-Type":"application/json"};e.restNonce&&(o["X-WP-Nonce"]=e.restNonce);const s=n(e.endpoint,{method:"POST",headers:o,body:JSON.stringify({action:"mount",view:"main",state:{...e.state},args:{},params:{},client:{width:0,height:0}})},{source:`openstation/app/${e.id}/prewarm`,silent:!0}).then(async i=>{if(!i.ok)return null;const r=await i.json();return r&&r.ok===!0?r:null}).catch(()=>null);return U.set(e.id,{promise:s,at:Date.now()}),!0}function Ft(e){const n=U.get(e);if(n)return U.delete(e),Date.now()-n.at<Se?n.promise:void 0}class oe extends Error{constructor(n,t){super(n||t.serverMessage||`HTTP ${t.status}`),this.name="RestError",this.status=t.status,this.code=t.code,this.data=t.data,this.serverMessage=t.serverMessage??""}}function $e(e){return e instanceof oe}function Ht(e){const n=typeof e=="object"&&e!==null?e:void 0;return{code:typeof n?.code=="string"?n.code:void 0,data:n?.data,serverMessage:typeof n?.message=="string"?n.message:""}}function Kt(e,n,t=""){return new oe(t,{status:e,...Ht(n)})}async function qt(e,n=""){let t=null;try{t=await e.json()}catch{t=null}return Kt(e.status,t,n)}const Ut="rest_cookie_invalid_nonce",Ne=()=>T("Could not reach the site. Check your connection and try again.","desktop-mode");function Te(e){return typeof navigator<"u"&&navigator.onLine===!1?!0:e instanceof TypeError}function Vt(e){return $e(e)?e.code===Ut||e.status===401?"session":e.status>=200&&e.status<300?"unreadable":e.status===404?"gone":e.status>=500?"server":e.status>=400?"refused":"unknown":Te(e)?"offline":"unknown"}function Xt(e){return $e(e)?e.serverMessage:Te(e)?Ne():e instanceof Error?e.message:""}function zt(e,n){const{fallback:t,lead:o}=n,s=Vt(e),i=s==="offline"||s==="unreadable"?"warning":"error";let r="",l=!0;switch(s){case"offline":r=Ne();break;case"session":r=T("Your session has expired. Reload the page and try again.","desktop-mode");break;case"unreadable":r=T("The site sent an unreadable reply. Reload the page to check whether the change went through.","desktop-mode");break;case"gone":case"refused":case"server":{const c=e;c.serverMessage?r=c.serverMessage:s==="gone"?(r=T("It no longer exists. Reload the page to catch up.","desktop-mode"),l=!1):s==="server"?(r=ne(T("The server answered with error %d.","desktop-mode"),c.status),l=!1):(r=ne(T("The server refused the request (HTTP %d).","desktop-mode"),c.status),l=!1);break}case"unknown":default:r=Xt(e);break}let u;return o?u=r?`${o}: ${r}`:t:r?l?u=r:u=`${t} ${r}`:u=t,{message:u,reason:r,kind:s,type:i}}function Gt(e,n,t){if(!e)return;const{duration:o,...s}=t,i=zt(n,s),r={message:i.message,type:i.type};o&&(r.duration=o),e(r)}const Yt=["os-avatar-click","os-button-activate","os-cancel","os-card-click","os-categories-change","os-categories-close","os-categories-create","os-categories-delete","os-categories-open","os-chain-remove","os-chain-segment-click","os-chain-segment-dragstart","os-checkbox-change","os-chip-dismiss","os-color-change","os-confirm","os-context-menu-pick","os-copy","os-disclosure-toggle","os-flyout-dismiss","os-form-input","os-form-reset","os-form-submit","os-split-change","os-input-change","os-input-commit","os-log-append","os-menu-item-click","os-modal-cancel","os-multiselect-close","os-multiselect-load-more","os-multiselect-open","os-notice-dismiss","os-pick","os-range-change","os-repeater-add","os-repeater-move","os-repeater-remove","os-role-toggle","os-save-status-change","os-segment-pick","os-series-toggle","os-step-click","os-submit","os-switch-change","os-tab-change","os-tab-pick","os-table-expand-change","os-table-filter-change","os-table-row-click","os-table-selection-change","os-table-sort-change","os-tag-add","os-tag-close","os-tag-open","os-tag-remove","os-tag-suggest","os-toast-action","os-toast-dismiss","os-toast-hold","os-token-field-input","os-token-insert","os-user-pick"],Zt=["click","dblclick","change","input","submit","keydown","contextmenu","toggle"],Ce={"os-button":"click",button:"click",a:"click","os-avatar":"os-avatar-click","os-card":"os-card-click","os-tile":"click","os-select":"os-pick","os-segmented":"os-pick","os-swatch-grid":"os-pick","os-multiselect":"os-pick","os-tabs":"os-tab-change","os-text-field":"os-input-change","os-textarea":"os-input-change","os-number-field":"os-input-change","os-token-field":"os-token-field-input","os-color-field":"os-color-change","os-range-field":"os-range-change","os-split":"os-split-change","os-switch":"os-switch-change","os-checkbox":"os-checkbox-change","os-disclosure":"os-disclosure-toggle","os-histogram":"os-series-toggle","os-chip":"os-chip-dismiss","os-tag-input":"os-tag-add","os-menu":"os-menu-item-click","os-context-menu":"os-context-menu-pick","os-table":"os-table-row-click","os-category-picker":"os-categories-change","os-role-picker":"os-role-toggle","os-user-search":"os-user-pick","os-repeater":"os-repeater-add","os-crumb-chain":"os-chain-segment-click","os-notice":"os-notice-dismiss","os-flyout":"os-flyout-dismiss","os-modal":"os-modal-cancel","os-confirm-dialog":"os-confirm","os-steps":"os-step-click","os-window-button":"os-button-activate","os-form":"os-form-submit","os-code":"os-copy",details:"toggle",form:"submit",select:"change",input:"change",textarea:"change"},Jt=new Set(["os-input-change","os-form-input","os-token-field-input","os-range-change","input"]),Qt=250,en=Array.from(new Set([...Yt,...Zt,...Object.values(Ce)])),tn=new Set(["toggle"]);function Me(e){const n=e.getAttribute("os-on");return n||(Ce[e.tagName.toLowerCase()]??"click")}function nn(e){return e.hasAttribute("os-action")||e.hasAttribute("os-bind")}function on(e,n,t){let o=e;for(;o&&o!==t;){if(nn(o)&&Me(o)===n)return o;o=o.parentElement}return null}function sn(e){const n={};for(const[t,o]of Object.entries(e))t==="originalEvent"||o instanceof Event||o instanceof Node||typeof o!="function"&&(n[t]=o);return n}function rn(e,n){if(e instanceof CustomEvent){const o=e.detail;if(o&&typeof o=="object"&&!Array.isArray(o))return sn(o);if(o!=null&&typeof o!="object")return{value:o}}if(e instanceof KeyboardEvent)return{key:e.key,code:e.code,alt:e.altKey,ctrl:e.ctrlKey,meta:e.metaKey,shift:e.shiftKey};const t=n.tagName.toLowerCase();if(t==="form"){const o={};return new FormData(n).forEach((s,i)=>{if(typeof s=="string")if(i in o){const r=o[i];o[i]=Array.isArray(r)?[...r,s]:[r,s]}else o[i]=s}),{values:o}}if(t==="details")return{open:n.open};if(t==="input"){const o=n;return o.type==="checkbox"||o.type==="radio"?{checked:o.checked,value:o.value}:{value:o.value}}return t==="select"||t==="textarea"?{value:n.value}:{}}function _e(e){const n={};for(const t of Array.from(e.attributes))t.name.startsWith("os-arg-")&&(n[t.name.slice(7)]=t.value);return n}function an(e){if("checked"in e)return e.checked;if("value"in e)return e.value;if("open"in e)return e.open}function cn(e){const n=e.getAttribute("os-confirm");return n?{message:n,title:e.getAttribute("os-confirm-title")??void 0,label:e.getAttribute("os-confirm-label")??void 0,danger:e.hasAttribute("os-confirm-danger")}:null}function ln(e,n){const t=e.getAttribute("os-bind"),o=e.getAttribute("os-action")??"set",s=n?n.type:Me(e),i=e.getAttribute("os-debounce");let r=0;return i!==null?r=Math.max(0,parseInt(i,10)||0):Jt.has(s)&&(r=Qt),{action:o,args:{..._e(e),...n?rn(n,e):{}},bind:t&&t!==""?t:null,debounce:r,confirm:cn(e)}}function un(e){const n=new Map;for(const t of Array.from(e.querySelectorAll("[os-poll]"))){const o=parseInt(t.getAttribute("os-poll")??"",10),s=t.getAttribute("os-action");if(!s||!Number.isFinite(o)||o<250)continue;const i=_e(t),r=`${s}|${o}|${JSON.stringify(i)}`;n.has(r)||n.set(r,{key:r,action:s,args:i,intervalMs:o})}return Array.from(n.values())}function dn(e){return e.slice(8).replace(/-([a-z])/g,(n,t)=>t.toUpperCase())}function Le(e,n){let t=0;for(const o of Array.from(e.querySelectorAll("*"))){let s=n.get(o);for(const i of Array.from(o.attributes)){if(!i.name.startsWith("os-prop-")||s&&s[i.name]===i.value)continue;let r=i.value;try{r=JSON.parse(i.value)}catch{}o[dn(i.name)]=r,s||(s={},n.set(o,s)),s[i.name]=i.value,t++}}return t}function fn(e,n){const t=document.createElement("template");t.innerHTML=n,Oe(e,Array.from(t.content.childNodes))}function se(e){if(e.nodeType!==Node.ELEMENT_NODE)return null;const n=e,t=n.getAttribute("os-key");return t!==null&&t!==""?t:n.id!==""?`#${n.id}`:null}function Ie(e,n){return e.nodeType!==n.nodeType?!1:e.nodeType===Node.ELEMENT_NODE?e.tagName===n.tagName:!0}function Oe(e,n){const t=e.ownerDocument.activeElement,o=new Map;for(const i of Array.from(e.childNodes)){const r=se(i);r!==null&&!o.has(r)&&o.set(r,i)}let s=0;for(const i of n){const r=e.childNodes[s]??null,l=se(i);let u=null;if(l!==null){const c=o.get(l);c&&Ie(c,i)&&(u=c,o.delete(l),c!==r&&e.insertBefore(c,r))}else r&&se(r)===null&&Ie(r,i)&&(u=r);if(!u){e.insertBefore(document.importNode(i,!0),r),s++;continue}pn(u,i,t),s++}for(;e.childNodes.length>s;)e.removeChild(e.childNodes[s])}function pn(e,n,t){if(e.nodeType!==Node.ELEMENT_NODE){e.nodeValue!==n.nodeValue&&(e.nodeValue=n.nodeValue);return}const o=e,s=n;if(o.hasAttribute("os-preserve"))return;const i=!!t&&(o===t||o.contains(t));mn(o,s,i),Oe(o,Array.from(s.childNodes)),hn(o,s,i)}function mn(e,n,t){for(const o of Array.from(n.attributes))t&&o.name==="value"||e.getAttribute(o.name)!==o.value&&e.setAttribute(o.name,o.value);for(const o of Array.from(e.attributes))n.hasAttribute(o.name)||t&&o.name==="value"||e.removeAttribute(o.name)}function hn(e,n,t){t||(e instanceof HTMLInputElement&&n instanceof HTMLInputElement?e.type==="checkbox"||e.type==="radio"?e.checked=n.checked:e.value!==n.value&&(e.value=n.value):(e instanceof HTMLTextAreaElement&&n instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement&&n instanceof HTMLSelectElement)&&e.value!==n.value&&(e.value=n.value))}function Pe(e){return`openstation-app-runtime:${e}`}const V=new Set;function gn(e,n=!0){n?V.add(e):V.delete(e)}const Re=new Set;function re(e,n){Re.has(e)||(Re.add(e),console.warn(n))}function yn(e){const{root:n,config:t,windowId:o,host:s,signal:i,client:r}=e,l=e.view??"main";let u=e.params??{},c={...t.state},f,d=!1,h,b=!1,y=!1,m=0,w=Promise.resolve(),v={x:0,y:0};const k=new Map,S=new Map,W=new WeakMap,G=[],qe=new Set(Object.keys(t.state??{})),En=new Set(["mount","set","refresh",...t.actions??[],...t.lifecycle??[]]),ae=()=>V.has("*")||V.has(o),xn=()=>{if(!(!t.actions||t.actions.length===0))for(const a of Array.from(n.querySelectorAll("[os-action]"))){const p=a.getAttribute("os-action")??"";p===""||En.has(p)||(r?.hasLocal(p)??!1)||re(`${t.id}:action:${p}`,`[openstation] app "${t.id}": os-action="${p}" names no server action, no local reducer and no built-in — dispatching it will fail. Declare ->action( '${p}' ) in the .os.php, or a local reducer in the .os.ts.`)}},Sn=a=>{for(const p of Object.keys(c))qe.has(p)||re(`${t.id}:key:${p}`,`[openstation] app "${t.id}": ${a} wrote state.${p}, which App::state() does not declare — the next server response silently drops it. Declare it in ->state(), or keep client-only values in ctx.ui().`)},$n=async(a,p,g)=>{if(b)return!1;const E=Date.now();m++,n.setAttribute("aria-busy","true"),g&&g.tagName.toLowerCase()==="os-button"&&g.setAttribute("busy","");const A=c;try{if(a==="mount"&&l==="main"&&Object.keys(u).length===0){const $=await Ft(t.id);if(b)return!1;if($)return ce($,A),!0}const N={Accept:"application/json","Content-Type":"application/json"};t.restNonce&&(N["X-WP-Nonce"]=t.restNonce);const L=await s.fetch(t.endpoint,{method:"POST",headers:N,body:JSON.stringify({action:a,view:l,state:A,args:p,params:u,client:{width:n.clientWidth,height:n.clientHeight}}),signal:i},{windowId:o,source:`openstation/app/${t.id}`});if(!L.ok)throw await qt(L);const j=await L.json();if(b)return!1;if(!j||j.ok!==!0){const $=j??{},M=typeof $.message=="string"?$.message:"";let me=L.status;throw typeof $.status=="number"?me=$.status:M&&(me=500),new oe("",{status:me,code:typeof $.error=="string"?$.error:void 0,serverMessage:M})}if(ce(j,A),ae()){const $=Object.keys(c).filter(M=>c[M]!==A[M]);console.groupCollapsed(`[openstation:${t.id}] ${a} · ${Date.now()-E}ms`),console.log("args",p),console.log("state Δ",$,$.length>0?Object.fromEntries($.map(M=>[M,c[M]])):""),console.log("effects",j.effects??[]),console.groupEnd()}return!0}catch(N){return b||i?.aborted||(ae()&&console.warn(`[openstation:${t.id}] ${a} FAILED after ${Date.now()-E}ms:`,N),Gt(s.toast,N,{lead:T("The window could not update"),fallback:T("The window could not update.")})),!1}finally{m--,m===0&&n.removeAttribute("aria-busy"),g&&g.isConnected&&g.removeAttribute("busy")}},P=async(a,p={},g={})=>{if(b||g.confirm&&(!s.confirm||!await s.confirm({title:g.confirm.title,message:g.confirm.message,confirmLabel:g.confirm.label,danger:!!g.confirm.danger})||b))return!1;const E=w.then(()=>$n(a,p,g.trigger??null));return w=E.catch(()=>{}),E},Y=()=>{Le(n,W),Mn(),Ln(),xn()},ce=(a,p,g=!1)=>{const E={...a.state};for(const A of Object.keys(c))c[A]!==p[A]&&(E[A]=c[A]);if(c=E,r){f=a.data,d=g;const A=h===void 0;if(r.render(Z()),Y(),A){const N=r.mounted(Z());h=typeof N=="function"?N:null}}else fn(n,a.html),Y();for(const A of a.effects??[])_n(A)};let le;const Nn=a=>(le===void 0&&(le=a()),le),Tn=()=>{!r||b||(r.render(Z()),Y())},Cn=(a,p={},g={})=>{const E=/^https?:\/\//i.test(a)?a:String(t.restRoot??"")+a.replace(/^\//,""),A=new Headers(p.headers);return A.has("Accept")||A.set("Accept","application/json"),t.restNonce&&!A.has("X-WP-Nonce")&&A.set("X-WP-Nonce",t.restNonce),s.fetch(E,{credentials:"same-origin",signal:i,...p,headers:A},{windowId:o,source:`openstation/app/${t.id}`,...g})},Z=()=>({get state(){return c},get data(){return f},get loading(){return d},root:n,windowId:o,dispatch:(a,p={},g={})=>P(a,p,{confirm:g.confirm??null}),local:(a,p={})=>ue(a,p),ui:Nn,repaint:Tn,fetch:Cn,host:s,extra:t.extra??{}}),ue=(a,p)=>{!r||b||(r.hasLocal(a)&&(c=r.runLocal(a,c,p,f),Sn(`local action "${a}"`),ae()&&console.debug(`[openstation:${t.id}] local ${a}`,p)),r.render(Z()),Y())},Ue=new Set,Mn=async()=>{if(!s.loadComponents)return;const a=new Set;for(const p of Array.from(n.querySelectorAll("*"))){const g=p.tagName.toLowerCase();!g.startsWith("os-")||customElements.get(g)||p.closest("[os-preserve]")||Ue.has(g)||(a.add(g),Ue.add(g))}a.size>0&&(await s.loadComponents(Array.from(a)),Le(n,new WeakMap))},_n=a=>{switch(a.type){case"toast":{const{message:p,toastType:g}=a;s.toast?.(typeof g=="string"&&g?{message:String(p),type:g}:{message:String(p)});return}case"title":s.setTitle?.(o,String(a.title));return;case"close":s.closeWindow?.(o);return;case"open":s.openWindow?.(String(a.window));return;case"open_url":s.openUrl?.(String(a.url),String(a.title??""),String(a.icon??""));return;case"badge":s.setBadge?.(t.id,Number(a.count)||0);return;case"icon":s.setIcon?.(t.id,String(a.icon));return;case"announce":{const p=a;s.announce?.(p.contentType,p.action,p.ids);return}case"menu":{const p=a.items??[];s.menu?.(v,p,g=>{P(g.action,g.args)});return}case"send":{const p=a;s.send?.(p.channel,p.payload);return}case"refresh_menu":s.refreshMenu?.();return;default:n.dispatchEvent(new CustomEvent("os-app-effect",{bubbles:!0,composed:!0,detail:{appId:t.id,windowId:o,view:l,effect:a}}))}},Ln=()=>{const a=new Map(un(n).map(p=>[p.key,p]));for(const[p,g]of S)a.has(p)||(window.clearInterval(g),S.delete(p));for(const[p,g]of a)S.has(p)||S.set(p,window.setInterval(()=>{y||document.hidden||m>0||b||P(g.action,g.args)},g.intervalMs))},In=(a,p)=>{if(a.bind){qe.has(a.bind)||re(`${t.id}:bind:${a.bind}`,`[openstation] app "${t.id}": os-bind="${a.bind}" writes a key App::state() does not declare — the server drops it on the next round trip. Declare it in ->state(), or keep client-only values in ctx.ui().`);const L=an(a.args);L!==void 0&&(c={...c,[a.bind]:L})}const g=!!r&&(r.hasLocal(a.action)||a.action==="set"&&a.bind!==null),E=()=>{if(g){ue(a.action,a.args);return}P(a.action,a.args,{confirm:a.confirm,trigger:p})};if(a.debounce<=0){E();return}const A=a.bind??a.action,N=k.get(A);N!==void 0&&window.clearTimeout(N),k.set(A,window.setTimeout(()=>{k.delete(A),E()},a.debounce))},Ve=a=>{if(b)return;a instanceof MouseEvent&&(v={x:a.clientX,y:a.clientY});const p=a.target instanceof Element?a.target:null,g=on(p,a.type,n);if(g&&!((a.type==="click"||a.type==="dblclick")&&g.hasAttribute("disabled"))){if((a.type==="submit"||a.type==="contextmenu")&&a.preventDefault(),a.type==="keydown"){const E=g.getAttribute("os-keys");if(E&&!E.split(/\s+/).includes(a.key))return;a.preventDefault()}In(ln(g,a),g)}};for(const a of en){const p=tn.has(a);n.addEventListener(a,Ve,p),G.push(()=>n.removeEventListener(a,Ve,p))}let de=!1,fe=!1;const pe=()=>{if(!(b||fe)){if(y){de=!0;return}fe=!0,P("set").finally(()=>{fe=!1})}},On=Pe(o),Xe=a=>!!a&&typeof a=="object"&&a.source===On;if(s.onBroadcast)for(const a of t.watch??[]){if(a==="*"){G.push(s.onBroadcast("*",(p,g)=>{/^os\..+\.changed$/.test(p)&&!Xe(g)&&pe()}));continue}G.push(s.onBroadcast(`os.${a}.changed`,(p,g)=>{Xe(g)||pe()}))}return{appId:t.id,windowId:o,view:l,get state(){return c},get data(){return f},dispatch:P,local:(a,p={})=>ue(a,p),paintEagerly(){if(!r||b||h!==void 0)return!1;const a=t.data!==void 0;if(!a&&!r.placeholder)return!1;const p={...t.state},g=a?t.data:r.placeholder?.(p);return ce({state:p,html:"",data:g,effects:[]},c,!a),!0},setPaused(a){y=a,!a&&de&&(de=!1,pe())},setParams(a){u={...a}},dispose(){b=!0,typeof h=="function"&&h();for(const a of G)a();for(const a of k.values())window.clearTimeout(a);k.clear();for(const a of S.values())window.clearInterval(a);S.clear()}}}const De="openstation-app-runtime",wn=200,D=new Map,Be=new Set;function B(){return window.wp?.os}function X(e,n="main"){return D.get(e)?.get(n)}function ie(e){const n=B();return{fetch:(t,o,s)=>n?n.fetch(t,o,s):Promise.reject(new Error("[openstation] wp.os is not available.")),confirm:t=>n?.confirm?n.confirm({title:t.title,message:t.message,confirmLabel:t.confirmLabel,danger:t.danger}):Promise.resolve(!1),toast:t=>{const o={message:t.message};t.duration&&(o.duration=t.duration),t.type&&(o.type=t.type),n?.showToast(o)},setTitle:(t,o)=>{n?.windowManager.getById(t)?.setTitle(o)},closeWindow:t=>{n?.windowManager.getById(t)?.close()},openWindow:t=>{n?.openWindow(t)},openUrl:(t,o,s)=>{if(!n||Je(t))return;const i=n.deriveWindowId(t);n.windowManager.open({id:i,baseId:i,url:t,title:o||t,icon:s||"dashicons-admin-generic"})},setBadge:(t,o)=>{n?.icons.setBadge(t,o),n?.dock?.setBadge(t,o)},setIcon:(t,o)=>{const s=n;s?.dock?.setArt?.(t,o),s?.taskbar?.setArt?.(t,o),s?.icons?.setArt?.(t,o)},announce:(t,o,s)=>{n?.announceContentChange(t,o,s,Pe(e))},menu:(t,o,s)=>{ct(t,{scope:"os-app",actions:o.map(i=>({id:i.id,label:i.label,icon:i.icon||void 0,danger:i.danger,disabled:i.disabled,onClick:()=>s(i)}))})},refreshMenu:()=>{try{n?.refreshMenu?.()}catch{}},onBroadcast:(t,o)=>n?.subscribe(t,(s,i)=>o(i.topic,s))??(()=>{}),loadComponents:t=>n?.loadComponents(t)??Promise.resolve(),applyAppearance:(t,o)=>bn(t,o)}}function bn(e,n){const t=B();if(t&&(n.theme&&Object.keys(n.theme).length>0&&t.applyWindowTheme(e,n.theme),n.controls&&Object.keys(n.controls).length>0&&t.applyWindowControls(e,n.controls),n.slots))for(const[o,s]of Object.entries(n.slots))t.applyWindowSlot(e,o,s)}function We(){let e=!0;return{focus:()=>e?!1:(e=!0,!0),blur:()=>e?(e=!1,!0):!1}}function vn(e,n){const t=e.closest('[id^="wp-window-"]');return t?t.id.slice(10):n}function je(e,n){return e.id===n||e.config.baseId===n}function Fe(e,n){X(e.id)?.dispatch(n.action,n.args,{confirm:n.confirm})}function kn(e){const n=B();if(n){for(const t of e.titleBarButtons??[])n.registerTitleBarButton({id:`os-app/${e.id}/${t.id}`,label:t.label,icon:t.icon,placement:t.placement??"right",order:t.order,match:o=>je(o,e.id),onClick:o=>Fe(o,t),owner:De});for(const t of e.windowActions??[])n.registerWindowAction({id:`os-app/${e.id}/${t.id}`,label:t.label,icon:t.icon,order:t.order,isVisible:o=>je(o,e.id),onSelect:o=>Fe(o,t),owner:De})}}function An(e){return async(n,t)=>{const o=vn(n,e.id),s=ie(o),i=new Set(e.lifecycle??[]),r=[];s.applyAppearance?.(o,e.appearance??{});const l=Array.from(n.querySelectorAll(`[data-os-app="${e.id}"]`));l.length===0&&l.push(n);const u=e.client?Wt(e.id):void 0,c=new Map;for(const m of l){const w=m.getAttribute("data-os-view")||"main",v=yn({root:m,config:e,windowId:o,host:s,view:w,params:t?.params??{},signal:t?.signal,client:w==="main"?u:void 0});c.set(w,v)}D.set(o,c);const f=m=>{c.forEach(m)};if(t){if(r.push(t.onHide(()=>{f(m=>m.setPaused(!0)),i.has("hide")&&f(m=>void m.dispatch("hide"))})),r.push(t.onShow(()=>{f(m=>m.setPaused(!1)),i.has("show")&&f(m=>void m.dispatch("show"))})),i.has("resize")){let m=null;r.push(t.onResize((w,v)=>{m!==null&&window.clearTimeout(m),m=window.setTimeout(()=>{m=null,f(k=>void k.dispatch("resize",{width:w,height:v}))},wn)}))}for(const[m,w]of Object.entries(e.channels??{}))r.push(t.window.on(m,v=>{f(k=>void k.dispatch(w,{payload:v}))}));s.send=(m,w)=>t.window.send(m,w)}const d=m=>{const w=m.detail;if(!w||w.windowId!==o)return;const v=w.params??{};f(k=>k.setParams(v)),i.has("reopen")&&f(k=>void k.dispatch("reopen",{params:v}))};document.addEventListener("os-window-reopened",d),r.push(()=>document.removeEventListener("os-window-reopened",d));const h=B();if(h&&(i.has("focus")||i.has("blur"))){const m=We();r.push(h.onWindow(o,{focused:()=>{m.focus()&&i.has("focus")&&f(w=>void w.dispatch("focus"))},blurred:()=>{m.blur()&&i.has("blur")&&f(w=>void w.dispatch("blur"))}}))}const b=Array.from(c.values(),m=>m.dispatch("mount"));return Object.keys(t?.params??{}).length===0&&c.get("main")?.paintEagerly()===!0||await Promise.all(b),()=>{for(const m of r)m();f(m=>m.dispose()),D.get(o)===c&&D.delete(o)}}}function z(){const e=window,n=e.openStationWindowConfig??{},t=e.openStationNativeWindows??(e.openStationNativeWindows={}),o=[];for(const[s,i]of Object.entries(n)){const r=i;!r||r.osApp!==!0||Be.has(s)||(Be.add(s),t[s]=An(r),kn(r),o.push(s))}return o}const He={defineApp:Bt,html:_,__:T,_n:ft,_x:dt,sprintf:ne,formatBytes:St,formatDate:$t,createPagedList:Nt,applySelection:Tt,createMarquee:Ct,copyText:Mt,statusControl:It,pager:Ot,mountMenuCheckboxes:Pt,createListTableSync:Dt};function Ke(){const e=window,n=o=>{try{o(He)}catch(s){console.error("[openstation] a queued client view threw.",s)}},t=e.openStationAppsPending;Array.isArray(t)&&t.forEach(n),e.openStationAppsPending={push:n}}return Ke(),z(),document.addEventListener("os-registry-changed",()=>{z()}),B()?.registerNamespace("apps",{...He,debug:(e="*",n=!0)=>gn(e,n),dispatch:(e,n,t={},o="main")=>X(e,o)?.dispatch(n,t)??Promise.resolve(!1),local:(e,n,t={})=>X(e)?.local(n,t),session:(e,n="main")=>X(e,n),refresh:()=>z(),prewarm:e=>{const n=window.openStationWindowConfig?.[e];return!n||n.osApp!==!0||D.has(e)?!1:jt(n,ie(e).fetch)}}),I.buildHost=ie,I.createFocusGate=We,I.publishClientApi=Ke,I.registerApps=z,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"}),I}({}); |
|
46
|
+ </footer>`}function Pt(e,n){const o=e.closest(".os-window")?.querySelector(".os-window__menu-panel")??null;if(!o||n.items.length===0)return null;const s=`${n.prefix}:`,i="data-os-app-menu-section";o.querySelectorAll(`[${i}="${n.prefix}"]`).forEach(f=>f.remove());const r=document.createElement("div");r.className="os-app__menu-section",r.setAttribute("role","presentation"),r.setAttribute(i,n.prefix),r.textContent=n.section,o.appendChild(r);const l=new Map;for(const f of n.items){const d=document.createElement("os-menu-item");d.setAttribute("role","menuitemcheckbox"),d.setAttribute("value",s+f.key),d.setAttribute(i,n.prefix),d.classList.add("os-window__menu-item","os-app__menu-item"),d.textContent=f.label||f.key,o.appendChild(d),l.set(f.key,d)}const u=()=>{for(const[f,d]of l)n.isChecked(f)?d.setAttribute("checked",""):d.removeAttribute("checked")};u();const c=f=>{const d=f.detail?.value;if(typeof d!="string"||!d.startsWith(s))return;const h=d.slice(s.length);l.has(h)&&(n.onToggle(h),u())};return o.addEventListener("os-menu-item-click",c),{refresh:u,dispose:()=>{o.removeEventListener("os-menu-item-click",c),r.remove();for(const f of l.values())f.remove();l.clear()}}}function Rt(e,n=null){const t=n??(typeof document<"u"?document.documentElement:null);if(!!t&&Ee(t)){e.hasAttribute("stacked")||e.setAttribute("stacked","");const i=e.getAttribute("sticky-columns");return i!==null&&(e.setAttribute("data-os-sticky-columns",i),e.removeAttribute("sticky-columns")),!0}e.hasAttribute("stacked")&&e.removeAttribute("stacked");const s=e.getAttribute("data-os-sticky-columns");return s!==null&&(e.setAttribute("sticky-columns",s),e.removeAttribute("data-os-sticky-columns")),!1}function xe(e){return Array.from(e.selection??[],String)}function Dt(){let e=null,n=!1,t=null,o=null;return{invalidateColumns(){e=null},invalidateData(){o=null},sync(s){const i={phone:!1,columnsChanged:!1,dataChanged:!1,selectionChanged:!1},r=s.table;if(!r)return i;const l=s.rowId??(c=>c.id),u=Rt(r);if(i.phone=u,u!==e&&(e=u,r.columns=s.columns(u),i.columnsChanged=!0),n||(n=!0,s.wire?.(r)),s.listKey!==t&&(t=s.listKey,xe(r).length>0&&(r.clearSelection(),i.selectionChanged=!0,s.onSelection?.([]))),s.fingerprint!==o){o=s.fingerprint,r.data=s.rows,i.dataChanged=!0;const c=new Set(s.rows.map(h=>String(l(h)))),f=xe(r),d=f.filter(h=>c.has(h));d.length!==f.length&&(r.selection=d,i.selectionChanged=!0,s.onSelection?.(d))}return i}}}function Bt(e,n){const t=n.local??{},o={id:e,hasLocal:r=>Object.prototype.hasOwnProperty.call(t,r),runLocal:(r,l,u,c)=>{const f=t[r];if(!f)return l;const d={...l},h=f(d,u,c);return h===void 0?d:h},render:r=>{vt(n.view(r),r.root),n.updated?.(r)},mounted:r=>n.mounted?.(r)},{placeholder:s}=n;s&&(o.placeholder=r=>s(r));const i=window;return(i.openStationApps??(i.openStationApps={}))[e]=o,o}function Wt(e){return window.openStationApps?.[e]}const Se=3e4,U=new Map;function jt(e,n){const t=U.get(e.id);if(t&&Date.now()-t.at<Se)return!1;const o={Accept:"application/json","Content-Type":"application/json"};e.restNonce&&(o["X-WP-Nonce"]=e.restNonce);const s=n(e.endpoint,{method:"POST",headers:o,body:JSON.stringify({action:"mount",view:"main",state:{...e.state},args:{},params:{},client:{width:0,height:0}})},{source:`openstation/app/${e.id}/prewarm`,silent:!0}).then(async i=>{if(!i.ok)return null;const r=await i.json();return r&&r.ok===!0?r:null}).catch(()=>null);return U.set(e.id,{promise:s,at:Date.now()}),!0}function Ft(e){const n=U.get(e);if(n)return U.delete(e),Date.now()-n.at<Se?n.promise:void 0}class oe extends Error{constructor(n,t){super(n||t.serverMessage||`HTTP ${t.status}`),this.name="RestError",this.status=t.status,this.code=t.code,this.data=t.data,this.serverMessage=t.serverMessage??""}}function $e(e){return e instanceof oe}function Ht(e){const n=typeof e=="object"&&e!==null?e:void 0;return{code:typeof n?.code=="string"?n.code:void 0,data:n?.data,serverMessage:typeof n?.message=="string"?n.message:""}}function Kt(e,n,t=""){return new oe(t,{status:e,...Ht(n)})}async function qt(e,n=""){let t=null;try{t=await e.json()}catch{t=null}return Kt(e.status,t,n)}const Ut="rest_cookie_invalid_nonce",Ne=()=>T("Could not reach the site. Check your connection and try again.","desktop-mode");function Te(e){return typeof navigator<"u"&&navigator.onLine===!1?!0:e instanceof TypeError}function Vt(e){return $e(e)?e.code===Ut||e.status===401?"session":e.status>=200&&e.status<300?"unreadable":e.status===404?"gone":e.status>=500?"server":e.status>=400?"refused":"unknown":Te(e)?"offline":"unknown"}function Xt(e){return $e(e)?e.serverMessage:Te(e)?Ne():e instanceof Error?e.message:""}function zt(e,n){const{fallback:t,lead:o}=n,s=Vt(e),i=s==="offline"||s==="unreadable"?"warning":"error";let r="",l=!0;switch(s){case"offline":r=Ne();break;case"session":r=T("Your session has expired. Reload the page and try again.","desktop-mode");break;case"unreadable":r=T("The site sent an unreadable reply. Reload the page to check whether the change went through.","desktop-mode");break;case"gone":case"refused":case"server":{const c=e;c.serverMessage?r=c.serverMessage:s==="gone"?(r=T("It no longer exists. Reload the page to catch up.","desktop-mode"),l=!1):s==="server"?(r=ne(T("The server answered with error %d.","desktop-mode"),c.status),l=!1):(r=ne(T("The server refused the request (HTTP %d).","desktop-mode"),c.status),l=!1);break}case"unknown":default:r=Xt(e);break}let u;return o?u=r?`${o}: ${r}`:t:r?l?u=r:u=`${t} ${r}`:u=t,{message:u,reason:r,kind:s,type:i}}function Gt(e,n,t){if(!e)return;const{duration:o,...s}=t,i=zt(n,s),r={message:i.message,type:i.type};o&&(r.duration=o),e(r)}const Yt=["os-avatar-click","os-button-activate","os-cancel","os-card-click","os-categories-change","os-categories-close","os-categories-create","os-categories-delete","os-categories-open","os-chain-remove","os-chain-segment-click","os-chain-segment-dragstart","os-checkbox-change","os-chip-dismiss","os-coachmark-dismiss","os-coachmark-primary","os-coachmark-secondary","os-coachmark-speaker","os-color-change","os-confirm","os-context-menu-pick","os-copy","os-disclosure-toggle","os-flyout-dismiss","os-form-input","os-form-reset","os-form-submit","os-split-change","os-input-change","os-input-commit","os-log-append","os-menu-item-click","os-modal-cancel","os-multiselect-close","os-multiselect-load-more","os-multiselect-open","os-notice-dismiss","os-pick","os-range-change","os-repeater-add","os-repeater-move","os-repeater-remove","os-role-toggle","os-save-status-change","os-segment-pick","os-series-toggle","os-step-click","os-submit","os-switch-change","os-tab-change","os-tab-pick","os-table-expand-change","os-table-filter-change","os-table-row-click","os-table-selection-change","os-table-sort-change","os-tag-add","os-tag-close","os-tag-open","os-tag-remove","os-tag-suggest","os-toast-action","os-toast-dismiss","os-toast-hold","os-token-field-input","os-token-insert","os-user-pick"],Zt=["click","dblclick","change","input","submit","keydown","contextmenu","toggle"],Ce={"os-button":"click",button:"click",a:"click","os-avatar":"os-avatar-click","os-card":"os-card-click","os-tile":"click","os-select":"os-pick","os-segmented":"os-pick","os-swatch-grid":"os-pick","os-multiselect":"os-pick","os-tabs":"os-tab-change","os-text-field":"os-input-change","os-textarea":"os-input-change","os-number-field":"os-input-change","os-token-field":"os-token-field-input","os-color-field":"os-color-change","os-range-field":"os-range-change","os-split":"os-split-change","os-switch":"os-switch-change","os-checkbox":"os-checkbox-change","os-disclosure":"os-disclosure-toggle","os-histogram":"os-series-toggle","os-chip":"os-chip-dismiss","os-tag-input":"os-tag-add","os-menu":"os-menu-item-click","os-context-menu":"os-context-menu-pick","os-table":"os-table-row-click","os-category-picker":"os-categories-change","os-role-picker":"os-role-toggle","os-user-search":"os-user-pick","os-repeater":"os-repeater-add","os-crumb-chain":"os-chain-segment-click","os-notice":"os-notice-dismiss","os-flyout":"os-flyout-dismiss","os-coachmark":"os-coachmark-primary","os-modal":"os-modal-cancel","os-confirm-dialog":"os-confirm","os-steps":"os-step-click","os-window-button":"os-button-activate","os-form":"os-form-submit","os-code":"os-copy",details:"toggle",form:"submit",select:"change",input:"change",textarea:"change"},Jt=new Set(["os-input-change","os-form-input","os-token-field-input","os-range-change","input"]),Qt=250,en=Array.from(new Set([...Yt,...Zt,...Object.values(Ce)])),tn=new Set(["toggle"]);function Me(e){const n=e.getAttribute("os-on");return n||(Ce[e.tagName.toLowerCase()]??"click")}function nn(e){return e.hasAttribute("os-action")||e.hasAttribute("os-bind")}function on(e,n,t){let o=e;for(;o&&o!==t;){if(nn(o)&&Me(o)===n)return o;o=o.parentElement}return null}function sn(e){const n={};for(const[t,o]of Object.entries(e))t==="originalEvent"||o instanceof Event||o instanceof Node||typeof o!="function"&&(n[t]=o);return n}function rn(e,n){if(e instanceof CustomEvent){const o=e.detail;if(o&&typeof o=="object"&&!Array.isArray(o))return sn(o);if(o!=null&&typeof o!="object")return{value:o}}if(e instanceof KeyboardEvent)return{key:e.key,code:e.code,alt:e.altKey,ctrl:e.ctrlKey,meta:e.metaKey,shift:e.shiftKey};const t=n.tagName.toLowerCase();if(t==="form"){const o={};return new FormData(n).forEach((s,i)=>{if(typeof s=="string")if(i in o){const r=o[i];o[i]=Array.isArray(r)?[...r,s]:[r,s]}else o[i]=s}),{values:o}}if(t==="details")return{open:n.open};if(t==="input"){const o=n;return o.type==="checkbox"||o.type==="radio"?{checked:o.checked,value:o.value}:{value:o.value}}return t==="select"||t==="textarea"?{value:n.value}:{}}function _e(e){const n={};for(const t of Array.from(e.attributes))t.name.startsWith("os-arg-")&&(n[t.name.slice(7)]=t.value);return n}function an(e){if("checked"in e)return e.checked;if("value"in e)return e.value;if("open"in e)return e.open}function cn(e){const n=e.getAttribute("os-confirm");return n?{message:n,title:e.getAttribute("os-confirm-title")??void 0,label:e.getAttribute("os-confirm-label")??void 0,danger:e.hasAttribute("os-confirm-danger")}:null}function ln(e,n){const t=e.getAttribute("os-bind"),o=e.getAttribute("os-action")??"set",s=n?n.type:Me(e),i=e.getAttribute("os-debounce");let r=0;return i!==null?r=Math.max(0,parseInt(i,10)||0):Jt.has(s)&&(r=Qt),{action:o,args:{..._e(e),...n?rn(n,e):{}},bind:t&&t!==""?t:null,debounce:r,confirm:cn(e)}}function un(e){const n=new Map;for(const t of Array.from(e.querySelectorAll("[os-poll]"))){const o=parseInt(t.getAttribute("os-poll")??"",10),s=t.getAttribute("os-action");if(!s||!Number.isFinite(o)||o<250)continue;const i=_e(t),r=`${s}|${o}|${JSON.stringify(i)}`;n.has(r)||n.set(r,{key:r,action:s,args:i,intervalMs:o})}return Array.from(n.values())}function dn(e){return e.slice(8).replace(/-([a-z])/g,(n,t)=>t.toUpperCase())}function Le(e,n){let t=0;for(const o of Array.from(e.querySelectorAll("*"))){let s=n.get(o);for(const i of Array.from(o.attributes)){if(!i.name.startsWith("os-prop-")||s&&s[i.name]===i.value)continue;let r=i.value;try{r=JSON.parse(i.value)}catch{}o[dn(i.name)]=r,s||(s={},n.set(o,s)),s[i.name]=i.value,t++}}return t}function fn(e,n){const t=document.createElement("template");t.innerHTML=n,Oe(e,Array.from(t.content.childNodes))}function se(e){if(e.nodeType!==Node.ELEMENT_NODE)return null;const n=e,t=n.getAttribute("os-key");return t!==null&&t!==""?t:n.id!==""?`#${n.id}`:null}function Ie(e,n){return e.nodeType!==n.nodeType?!1:e.nodeType===Node.ELEMENT_NODE?e.tagName===n.tagName:!0}function Oe(e,n){const t=e.ownerDocument.activeElement,o=new Map;for(const i of Array.from(e.childNodes)){const r=se(i);r!==null&&!o.has(r)&&o.set(r,i)}let s=0;for(const i of n){const r=e.childNodes[s]??null,l=se(i);let u=null;if(l!==null){const c=o.get(l);c&&Ie(c,i)&&(u=c,o.delete(l),c!==r&&e.insertBefore(c,r))}else r&&se(r)===null&&Ie(r,i)&&(u=r);if(!u){e.insertBefore(document.importNode(i,!0),r),s++;continue}pn(u,i,t),s++}for(;e.childNodes.length>s;)e.removeChild(e.childNodes[s])}function pn(e,n,t){if(e.nodeType!==Node.ELEMENT_NODE){e.nodeValue!==n.nodeValue&&(e.nodeValue=n.nodeValue);return}const o=e,s=n;if(o.hasAttribute("os-preserve"))return;const i=!!t&&(o===t||o.contains(t));mn(o,s,i),Oe(o,Array.from(s.childNodes)),hn(o,s,i)}function mn(e,n,t){for(const o of Array.from(n.attributes))t&&o.name==="value"||e.getAttribute(o.name)!==o.value&&e.setAttribute(o.name,o.value);for(const o of Array.from(e.attributes))n.hasAttribute(o.name)||t&&o.name==="value"||e.removeAttribute(o.name)}function hn(e,n,t){t||(e instanceof HTMLInputElement&&n instanceof HTMLInputElement?e.type==="checkbox"||e.type==="radio"?e.checked=n.checked:e.value!==n.value&&(e.value=n.value):(e instanceof HTMLTextAreaElement&&n instanceof HTMLTextAreaElement||e instanceof HTMLSelectElement&&n instanceof HTMLSelectElement)&&e.value!==n.value&&(e.value=n.value))}function Pe(e){return`openstation-app-runtime:${e}`}const V=new Set;function gn(e,n=!0){n?V.add(e):V.delete(e)}const Re=new Set;function re(e,n){Re.has(e)||(Re.add(e),console.warn(n))}function yn(e){const{root:n,config:t,windowId:o,host:s,signal:i,client:r}=e,l=e.view??"main";let u=e.params??{},c={...t.state},f,d=!1,h,b=!1,y=!1,m=0,w=Promise.resolve(),v={x:0,y:0};const k=new Map,S=new Map,W=new WeakMap,G=[],qe=new Set(Object.keys(t.state??{})),En=new Set(["mount","set","refresh",...t.actions??[],...t.lifecycle??[]]),ae=()=>V.has("*")||V.has(o),xn=()=>{if(!(!t.actions||t.actions.length===0))for(const a of Array.from(n.querySelectorAll("[os-action]"))){const p=a.getAttribute("os-action")??"";p===""||En.has(p)||(r?.hasLocal(p)??!1)||re(`${t.id}:action:${p}`,`[openstation] app "${t.id}": os-action="${p}" names no server action, no local reducer and no built-in — dispatching it will fail. Declare ->action( '${p}' ) in the .os.php, or a local reducer in the .os.ts.`)}},Sn=a=>{for(const p of Object.keys(c))qe.has(p)||re(`${t.id}:key:${p}`,`[openstation] app "${t.id}": ${a} wrote state.${p}, which App::state() does not declare — the next server response silently drops it. Declare it in ->state(), or keep client-only values in ctx.ui().`)},$n=async(a,p,g)=>{if(b)return!1;const E=Date.now();m++,n.setAttribute("aria-busy","true"),g&&g.tagName.toLowerCase()==="os-button"&&g.setAttribute("busy","");const A=c;try{if(a==="mount"&&l==="main"&&Object.keys(u).length===0){const $=await Ft(t.id);if(b)return!1;if($)return ce($,A),!0}const N={Accept:"application/json","Content-Type":"application/json"};t.restNonce&&(N["X-WP-Nonce"]=t.restNonce);const L=await s.fetch(t.endpoint,{method:"POST",headers:N,body:JSON.stringify({action:a,view:l,state:A,args:p,params:u,client:{width:n.clientWidth,height:n.clientHeight}}),signal:i},{windowId:o,source:`openstation/app/${t.id}`});if(!L.ok)throw await qt(L);const j=await L.json();if(b)return!1;if(!j||j.ok!==!0){const $=j??{},M=typeof $.message=="string"?$.message:"";let me=L.status;throw typeof $.status=="number"?me=$.status:M&&(me=500),new oe("",{status:me,code:typeof $.error=="string"?$.error:void 0,serverMessage:M})}if(ce(j,A),ae()){const $=Object.keys(c).filter(M=>c[M]!==A[M]);console.groupCollapsed(`[openstation:${t.id}] ${a} · ${Date.now()-E}ms`),console.log("args",p),console.log("state Δ",$,$.length>0?Object.fromEntries($.map(M=>[M,c[M]])):""),console.log("effects",j.effects??[]),console.groupEnd()}return!0}catch(N){return b||i?.aborted||(ae()&&console.warn(`[openstation:${t.id}] ${a} FAILED after ${Date.now()-E}ms:`,N),Gt(s.toast,N,{lead:T("The window could not update"),fallback:T("The window could not update.")})),!1}finally{m--,m===0&&n.removeAttribute("aria-busy"),g&&g.isConnected&&g.removeAttribute("busy")}},P=async(a,p={},g={})=>{if(b||g.confirm&&(!s.confirm||!await s.confirm({title:g.confirm.title,message:g.confirm.message,confirmLabel:g.confirm.label,danger:!!g.confirm.danger})||b))return!1;const E=w.then(()=>$n(a,p,g.trigger??null));return w=E.catch(()=>{}),E},Y=()=>{Le(n,W),Mn(),Ln(),xn()},ce=(a,p,g=!1)=>{const E={...a.state};for(const A of Object.keys(c))c[A]!==p[A]&&(E[A]=c[A]);if(c=E,r){f=a.data,d=g;const A=h===void 0;if(r.render(Z()),Y(),A){const N=r.mounted(Z());h=typeof N=="function"?N:null}}else fn(n,a.html),Y();for(const A of a.effects??[])_n(A)};let le;const Nn=a=>(le===void 0&&(le=a()),le),Tn=()=>{!r||b||(r.render(Z()),Y())},Cn=(a,p={},g={})=>{const E=/^https?:\/\//i.test(a)?a:String(t.restRoot??"")+a.replace(/^\//,""),A=new Headers(p.headers);return A.has("Accept")||A.set("Accept","application/json"),t.restNonce&&!A.has("X-WP-Nonce")&&A.set("X-WP-Nonce",t.restNonce),s.fetch(E,{credentials:"same-origin",signal:i,...p,headers:A},{windowId:o,source:`openstation/app/${t.id}`,...g})},Z=()=>({get state(){return c},get data(){return f},get loading(){return d},root:n,windowId:o,dispatch:(a,p={},g={})=>P(a,p,{confirm:g.confirm??null}),local:(a,p={})=>ue(a,p),ui:Nn,repaint:Tn,fetch:Cn,host:s,extra:t.extra??{}}),ue=(a,p)=>{!r||b||(r.hasLocal(a)&&(c=r.runLocal(a,c,p,f),Sn(`local action "${a}"`),ae()&&console.debug(`[openstation:${t.id}] local ${a}`,p)),r.render(Z()),Y())},Ue=new Set,Mn=async()=>{if(!s.loadComponents)return;const a=new Set;for(const p of Array.from(n.querySelectorAll("*"))){const g=p.tagName.toLowerCase();!g.startsWith("os-")||customElements.get(g)||p.closest("[os-preserve]")||Ue.has(g)||(a.add(g),Ue.add(g))}a.size>0&&(await s.loadComponents(Array.from(a)),Le(n,new WeakMap))},_n=a=>{switch(a.type){case"toast":{const{message:p,toastType:g}=a;s.toast?.(typeof g=="string"&&g?{message:String(p),type:g}:{message:String(p)});return}case"title":s.setTitle?.(o,String(a.title));return;case"close":s.closeWindow?.(o);return;case"open":s.openWindow?.(String(a.window));return;case"open_url":s.openUrl?.(String(a.url),String(a.title??""),String(a.icon??""));return;case"badge":s.setBadge?.(t.id,Number(a.count)||0);return;case"icon":s.setIcon?.(t.id,String(a.icon));return;case"announce":{const p=a;s.announce?.(p.contentType,p.action,p.ids);return}case"menu":{const p=a.items??[];s.menu?.(v,p,g=>{P(g.action,g.args)});return}case"send":{const p=a;s.send?.(p.channel,p.payload);return}case"refresh_menu":s.refreshMenu?.();return;default:n.dispatchEvent(new CustomEvent("os-app-effect",{bubbles:!0,composed:!0,detail:{appId:t.id,windowId:o,view:l,effect:a}}))}},Ln=()=>{const a=new Map(un(n).map(p=>[p.key,p]));for(const[p,g]of S)a.has(p)||(window.clearInterval(g),S.delete(p));for(const[p,g]of a)S.has(p)||S.set(p,window.setInterval(()=>{y||document.hidden||m>0||b||P(g.action,g.args)},g.intervalMs))},In=(a,p)=>{if(a.bind){qe.has(a.bind)||re(`${t.id}:bind:${a.bind}`,`[openstation] app "${t.id}": os-bind="${a.bind}" writes a key App::state() does not declare — the server drops it on the next round trip. Declare it in ->state(), or keep client-only values in ctx.ui().`);const L=an(a.args);L!==void 0&&(c={...c,[a.bind]:L})}const g=!!r&&(r.hasLocal(a.action)||a.action==="set"&&a.bind!==null),E=()=>{if(g){ue(a.action,a.args);return}P(a.action,a.args,{confirm:a.confirm,trigger:p})};if(a.debounce<=0){E();return}const A=a.bind??a.action,N=k.get(A);N!==void 0&&window.clearTimeout(N),k.set(A,window.setTimeout(()=>{k.delete(A),E()},a.debounce))},Ve=a=>{if(b)return;a instanceof MouseEvent&&(v={x:a.clientX,y:a.clientY});const p=a.target instanceof Element?a.target:null,g=on(p,a.type,n);if(g&&!((a.type==="click"||a.type==="dblclick")&&g.hasAttribute("disabled"))){if((a.type==="submit"||a.type==="contextmenu")&&a.preventDefault(),a.type==="keydown"){const E=g.getAttribute("os-keys");if(E&&!E.split(/\s+/).includes(a.key))return;a.preventDefault()}In(ln(g,a),g)}};for(const a of en){const p=tn.has(a);n.addEventListener(a,Ve,p),G.push(()=>n.removeEventListener(a,Ve,p))}let de=!1,fe=!1;const pe=()=>{if(!(b||fe)){if(y){de=!0;return}fe=!0,P("set").finally(()=>{fe=!1})}},On=Pe(o),Xe=a=>!!a&&typeof a=="object"&&a.source===On;if(s.onBroadcast)for(const a of t.watch??[]){if(a==="*"){G.push(s.onBroadcast("*",(p,g)=>{/^os\..+\.changed$/.test(p)&&!Xe(g)&&pe()}));continue}G.push(s.onBroadcast(`os.${a}.changed`,(p,g)=>{Xe(g)||pe()}))}return{appId:t.id,windowId:o,view:l,get state(){return c},get data(){return f},dispatch:P,local:(a,p={})=>ue(a,p),paintEagerly(){if(!r||b||h!==void 0)return!1;const a=t.data!==void 0;if(!a&&!r.placeholder)return!1;const p={...t.state},g=a?t.data:r.placeholder?.(p);return ce({state:p,html:"",data:g,effects:[]},c,!a),!0},setPaused(a){y=a,!a&&de&&(de=!1,pe())},setParams(a){u={...a}},dispose(){b=!0,typeof h=="function"&&h();for(const a of G)a();for(const a of k.values())window.clearTimeout(a);k.clear();for(const a of S.values())window.clearInterval(a);S.clear()}}}const De="openstation-app-runtime",wn=200,D=new Map,Be=new Set;function B(){return window.wp?.os}function X(e,n="main"){return D.get(e)?.get(n)}function ie(e){const n=B();return{fetch:(t,o,s)=>n?n.fetch(t,o,s):Promise.reject(new Error("[openstation] wp.os is not available.")),confirm:t=>n?.confirm?n.confirm({title:t.title,message:t.message,confirmLabel:t.confirmLabel,danger:t.danger}):Promise.resolve(!1),toast:t=>{const o={message:t.message};t.duration&&(o.duration=t.duration),t.type&&(o.type=t.type),n?.showToast(o)},setTitle:(t,o)=>{n?.windowManager.getById(t)?.setTitle(o)},closeWindow:t=>{n?.windowManager.getById(t)?.close()},openWindow:t=>{n?.openWindow(t)},openUrl:(t,o,s)=>{if(!n||Je(t))return;const i=n.deriveWindowId(t);n.windowManager.open({id:i,baseId:i,url:t,title:o||t,icon:s||"dashicons-admin-generic"})},setBadge:(t,o)=>{n?.icons.setBadge(t,o),n?.dock?.setBadge(t,o)},setIcon:(t,o)=>{const s=n;s?.dock?.setArt?.(t,o),s?.taskbar?.setArt?.(t,o),s?.icons?.setArt?.(t,o)},announce:(t,o,s)=>{n?.announceContentChange(t,o,s,Pe(e))},menu:(t,o,s)=>{ct(t,{scope:"os-app",actions:o.map(i=>({id:i.id,label:i.label,icon:i.icon||void 0,danger:i.danger,disabled:i.disabled,onClick:()=>s(i)}))})},refreshMenu:()=>{try{n?.refreshMenu?.()}catch{}},onBroadcast:(t,o)=>n?.subscribe(t,(s,i)=>o(i.topic,s))??(()=>{}),loadComponents:t=>n?.loadComponents(t)??Promise.resolve(),applyAppearance:(t,o)=>bn(t,o)}}function bn(e,n){const t=B();if(t&&(n.theme&&Object.keys(n.theme).length>0&&t.applyWindowTheme(e,n.theme),n.controls&&Object.keys(n.controls).length>0&&t.applyWindowControls(e,n.controls),n.slots))for(const[o,s]of Object.entries(n.slots))t.applyWindowSlot(e,o,s)}function We(){let e=!0;return{focus:()=>e?!1:(e=!0,!0),blur:()=>e?(e=!1,!0):!1}}function vn(e,n){const t=e.closest('[id^="wp-window-"]');return t?t.id.slice(10):n}function je(e,n){return e.id===n||e.config.baseId===n}function Fe(e,n){X(e.id)?.dispatch(n.action,n.args,{confirm:n.confirm})}function kn(e){const n=B();if(n){for(const t of e.titleBarButtons??[])n.registerTitleBarButton({id:`os-app/${e.id}/${t.id}`,label:t.label,icon:t.icon,placement:t.placement??"right",order:t.order,match:o=>je(o,e.id),onClick:o=>Fe(o,t),owner:De});for(const t of e.windowActions??[])n.registerWindowAction({id:`os-app/${e.id}/${t.id}`,label:t.label,icon:t.icon,order:t.order,isVisible:o=>je(o,e.id),onSelect:o=>Fe(o,t),owner:De})}}function An(e){return async(n,t)=>{const o=vn(n,e.id),s=ie(o),i=new Set(e.lifecycle??[]),r=[];s.applyAppearance?.(o,e.appearance??{});const l=Array.from(n.querySelectorAll(`[data-os-app="${e.id}"]`));l.length===0&&l.push(n);const u=e.client?Wt(e.id):void 0,c=new Map;for(const m of l){const w=m.getAttribute("data-os-view")||"main",v=yn({root:m,config:e,windowId:o,host:s,view:w,params:t?.params??{},signal:t?.signal,client:w==="main"?u:void 0});c.set(w,v)}D.set(o,c);const f=m=>{c.forEach(m)};if(t){if(r.push(t.onHide(()=>{f(m=>m.setPaused(!0)),i.has("hide")&&f(m=>void m.dispatch("hide"))})),r.push(t.onShow(()=>{f(m=>m.setPaused(!1)),i.has("show")&&f(m=>void m.dispatch("show"))})),i.has("resize")){let m=null;r.push(t.onResize((w,v)=>{m!==null&&window.clearTimeout(m),m=window.setTimeout(()=>{m=null,f(k=>void k.dispatch("resize",{width:w,height:v}))},wn)}))}for(const[m,w]of Object.entries(e.channels??{}))r.push(t.window.on(m,v=>{f(k=>void k.dispatch(w,{payload:v}))}));s.send=(m,w)=>t.window.send(m,w)}const d=m=>{const w=m.detail;if(!w||w.windowId!==o)return;const v=w.params??{};f(k=>k.setParams(v)),i.has("reopen")&&f(k=>void k.dispatch("reopen",{params:v}))};document.addEventListener("os-window-reopened",d),r.push(()=>document.removeEventListener("os-window-reopened",d));const h=B();if(h&&(i.has("focus")||i.has("blur"))){const m=We();r.push(h.onWindow(o,{focused:()=>{m.focus()&&i.has("focus")&&f(w=>void w.dispatch("focus"))},blurred:()=>{m.blur()&&i.has("blur")&&f(w=>void w.dispatch("blur"))}}))}const b=Array.from(c.values(),m=>m.dispatch("mount"));return Object.keys(t?.params??{}).length===0&&c.get("main")?.paintEagerly()===!0||await Promise.all(b),()=>{for(const m of r)m();f(m=>m.dispose()),D.get(o)===c&&D.delete(o)}}}function z(){const e=window,n=e.openStationWindowConfig??{},t=e.openStationNativeWindows??(e.openStationNativeWindows={}),o=[];for(const[s,i]of Object.entries(n)){const r=i;!r||r.osApp!==!0||Be.has(s)||(Be.add(s),t[s]=An(r),kn(r),o.push(s))}return o}const He={defineApp:Bt,html:_,__:T,_n:ft,_x:dt,sprintf:ne,formatBytes:St,formatDate:$t,createPagedList:Nt,applySelection:Tt,createMarquee:Ct,copyText:Mt,statusControl:It,pager:Ot,mountMenuCheckboxes:Pt,createListTableSync:Dt};function Ke(){const e=window,n=o=>{try{o(He)}catch(s){console.error("[openstation] a queued client view threw.",s)}},t=e.openStationAppsPending;Array.isArray(t)&&t.forEach(n),e.openStationAppsPending={push:n}}return Ke(),z(),document.addEventListener("os-registry-changed",()=>{z()}),B()?.registerNamespace("apps",{...He,debug:(e="*",n=!0)=>gn(e,n),dispatch:(e,n,t={},o="main")=>X(e,o)?.dispatch(n,t)??Promise.resolve(!1),local:(e,n,t={})=>X(e)?.local(n,t),session:(e,n="main")=>X(e,n),refresh:()=>z(),prewarm:e=>{const n=window.openStationWindowConfig?.[e];return!n||n.osApp!==!0||D.has(e)?!1:jt(n,ie(e).fetch)}}),I.buildHost=ie,I.createFocusGate=We,I.publishClientApi=Ke,I.registerApps=z,Object.defineProperty(I,Symbol.toStringTag,{value:"Module"}),I}({}); |