domma-cms 1.8.6 → 1.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/CLAUDE.md +13 -1
- package/admin/js/lib/menu-editor-arrange.js +2 -2
- package/admin/js/lib/shortcode-registry.js +2 -2
- package/admin/js/lib/wordpress-import-arrange.js +1 -1
- package/admin/js/templates/docs/usage-editions.html +0 -1
- package/admin/js/templates/menu-editor.html +6 -0
- package/admin/js/templates/wordpress-import.html +23 -1
- package/admin/js/views/menu-editor.js +5 -5
- package/admin/js/views/wordpress-import.js +30 -7
- package/config/cache.json.example +0 -4
- package/docs/DommaFeatures.md +1 -1
- package/docs/cache.md +3 -3
- package/docs/editions-and-licences.md +0 -3
- package/docs/plugin-development.md +1 -1
- package/package.json +1 -1
- package/public/css/site.css +1 -1
- package/public/js/mobile-ui.mjs +1 -0
- package/public/js/site.js +1 -1
- package/server/routes/api/wordpress-import.js +81 -4
- package/server/server.js +1 -6
- package/server/services/cache/index.js +3 -11
- package/server/services/markdown.js +2 -1
- package/server/services/menus.js +21 -0
- package/server/services/passwordReset.js +71 -3
- package/server/services/renderer.js +2 -0
- package/server/services/wpImport/index.js +183 -20
- package/server/services/wpImport/people.js +202 -0
- package/server/services/wpImport/plan.js +13 -2
- package/server/services/wpImport/wxr.js +5 -2
- package/server/templates/page.html +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{api as
|
|
1
|
+
import{api as O}from"../api.js";import{colourToCss as St,HIGHLIGHT_HOVER as lt,HIGHLIGHT_ACTIVE as it,HIGHLIGHT_HOVER_LABELS as ct,HIGHLIGHT_ACTIVE_LABELS as rt,cssClassProblems as dt,normaliseCssClasses as At,ENTRANCE_ANIMATIONS as qe,ENTRANCE_ANIMATION_LABELS as Et}from"/public/js/menu-decor.mjs?v=20261014-menu-entrance";import{openIconPicker as $t}from"../lib/card-builder.js";import{sortableMenuRows as xt}from"../lib/menu-drag.js";import{placeTools as Ct,ensureLockedTools as Lt,isLockedUrl as _t,groupKeyFor as It,slugify as Ht,GROUP_ICON as Tt,TOOLS_FOLDER_KEY as Rt}from"../lib/sidebar-grouping.js";import{flatten as ut,nest as Nt,uid as _e}from"../lib/menu-rows.js";import{addBannerAction as Ue}from"../lib/plugin-chrome.js";import{helpPopovers as Ot}from"../lib/help-popover.js";import{onceClosed as Dt,openMenuAt as Ge,sidebarCount as jt}from"../lib/tool-kit.js";import{addChild as Pt,bindingFrom as Bt,duplicateRow as Ft,indentRow as Mt,insertBelow as zt,isStructural as ae,menuFromForm as Wt,menuProblems as Kt,moveRow as mt,outdentRow as qt,siblingsOf as Ut,snapshot as Ie}from"../lib/menu-editor-arrange.js";import{fmtDateTime as Gt}from"../lib/dates.js";const Vt=760,Yt="admin-sidebar",Xt=/^\/menus\/(new|edit\/[^?#]+)(\?.*)?$/;function y(o){return String(o||"").replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<")}const He=o=>String(o??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Jt(o,r){let i=0,c=r.find(s=>s.id===o);for(;c&&c.parentId;)i++,c=r.find(s=>s.id===c.parentId);return i}function pt(o){const r=new Set,i=new Set,c=s=>{for(const v of o.filter(k=>k.parentId===s))!v.type&&_t(v.url)&&!i.has(v.url)&&(i.add(v.url),r.add(v.id)),c(v.id)};return c(null),r}const Te='<button type="button" class="btn btn-sm btn-ghost mex-kebab" aria-label="Actions" title="Actions (right-click, or Shift+F10)">\u22EE</button>';function Qt(o,r,i=!1){const c=i?pt(r):new Set,s=[];function v(k){for(const p of r.filter(F=>F.parentId===k)){const x=`style="margin-left:${Jt(p.id,r)*28}px"`;if(p.type==="separator"){s.push(`
|
|
2
2
|
<div class="menu-tree-row menu-tree-row--separator" data-id="${p.id}" tabindex="0" ${x}>
|
|
3
3
|
<span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
|
|
4
4
|
<span class="me-sep-line"><span class="me-sep-label">Separator</span></span>
|
|
5
5
|
${Te}
|
|
6
|
-
</div>`);continue}if(p.type==="spacer"){const ne=["xs","sm","md","lg","xl","flex"].map(
|
|
6
|
+
</div>`);continue}if(p.type==="spacer"){const ne=["xs","sm","md","lg","xl","flex"].map(z=>`<option value="${z}"${(p.size||"md")===z?" selected":""}>${z==="flex"?"flexible":z}</option>`).join("");s.push(`
|
|
7
7
|
<div class="menu-tree-row menu-tree-row--spacer" data-id="${p.id}" tabindex="0" ${x}>
|
|
8
8
|
<span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
|
|
9
9
|
<span class="me-spacer-line">
|
|
@@ -24,7 +24,7 @@ import{api as N}from"../api.js";import{colourToCss as St,HIGHLIGHT_HOVER as lt,H
|
|
|
24
24
|
${le}
|
|
25
25
|
<button type="button" class="btn btn-sm btn-ghost me-edit" title="Edit" aria-label="Edit"><span data-icon="edit"></span></button>
|
|
26
26
|
${Te}
|
|
27
|
-
</div>`),v(p.id)}}v(null),o.innerHTML=s.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(o)}function w(o,r={},...i){const c=document.createElement(o);Object.assign(c,r);for(const s of i)s!=null&&c.append(s);return c}function T(o,r,i){const c=w("label",{className:"form-field"},w("span",{className:"form-label",textContent:o}),r);return i&&c.append(w("small",{className:"form-hint",textContent:i,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),c}function Zt(o,r){const i=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(r||[]).map(s=>[s.name,`${s.label||s.name} and above`]),...(r||[]).filter(s=>s.level!==0).map(s=>[`=${s.name}`,`${s.label||s.name} only`]),["private","Private - super-admin only"]];o&&!i.some(([s])=>s===o)&&i.push([o,`${o} (custom)`]);const c=ee(i,o||"");return c.name="visibility",c}function ee(o,r){const i=w("select",{className:"form-select"});return o.forEach(([c,s])=>i.add(new Option(s,c))),i.value=r??"",i}function Re(o,r){const i=typeof r=="string"&&r.startsWith("#"),c=ee([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],i?"__custom__":r||""),s=w("input",{type:"color",className:"form-input me-colour-hex",value:i?r:"#000000"});s.style.display=i?"":"none",c.addEventListener("change",()=>{s.style.display=c.value==="__custom__"?"":"none"});const v=T(o,c);return v.append(s),v._read=()=>c.value==="__custom__"?s.value:c.value,v}function en(o,r){const i=w("input",{className:"form-input me-icon",name:"icon",value:r||""}),c=w("span",{className:"me-icon-preview"});r&&c.setAttribute("data-icon",r);const s=w("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),v=k=>{k?c.setAttribute("data-icon",k):c.removeAttribute("data-icon"),Domma.icons.scan(c.parentNode||c)};return s.addEventListener("click",()=>$t(k=>{i.value=k,v(k)})),i.addEventListener("input",()=>v(i.value.trim())),T(o,w("div",{className:"me-icon-field"},i,s,c))}function Ne(...o){return w("div",{className:"me-field-grid"},...o)}async function tn(o,r,i,c,s){const v=o.text||o.tool?.label||"",k=u=>w("h4",{className:"me-form-section",textContent:u}),p=T("Label",w("input",{className:"form-input",name:"text",value:o.text||""}),"The text shown for this item."),B=w("input",{className:"form-input",name:"url",value:o.url||""}),x=T("URL",B,o.tool||o.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(o.tool||o.locked)&&(B.readOnly=!0);const J=en("Icon",o.icon||""),C=Zt(o.visibility||"",c),g=T("Visibility",C,o.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');o.locked&&(C.disabled=!0);const q=ee([["","- no permission gate -"],...(r||[]).map(u=>[u.key,u.label||u.key])],o.permission||"");q.name="permission";const se=T("Permission",q,o.tool||o.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(o.tool||o.locked)&&(q.disabled=!0);const te=T("Badge text",w("input",{className:"form-input",name:"badgeText",value:o.badge?.text||""})),U=ee([["","- none -"],...(i||[]).map(u=>[u.slug,u.title||u.slug])],o.badge?.countFrom||"");U.name="badgeCount";const le=T("Badge count from",U,"Show a live count of this collection\u2019s entries as the badge."),ne=Re("Badge colour",o.badge?.variant||""),F=ee([["link","Link"],["pill","Pill"]],o.pill?"pill":"link");F.name="renderAs";const Oe=T("Render as",F,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),O=T("Pill style",ee([["filled","Filled"],["outline","Outline"]],o.pill?.style||"filled"));O.querySelector("select").name="pillStyle";const pe=Re("Pill colour",o.pill?.variant||""),ie=w("div",{className:"me-pill-wrap"},Ne(O,pe));ie.style.display=o.pill?"":"none",F.addEventListener("change",()=>{ie.style.display=F.value==="pill"?"":"none"});const h=Re("Text colour",o.colour||""),D=ee([["","- use the menu default -"],...lt.map(u=>[u,ct[u]||u])],o.highlight?.hover||"");D.name="hlHover";const ce=T("Hover effect",D,"Overrides the menu-wide hover effect for this item only."),he=ee([["","- use the menu default -"],...it.map(u=>[u,rt[u]||u])],o.highlight?.active||"");he.name="hlActive";const Se=T("When selected",he,"How this item is marked when it points at the page being viewed."),z=Re("Highlight colour",o.highlight?.accent||""),L=w("input",{className:"form-input",name:"class",value:o.class||"",placeholder:"nav-cta push-right",autocomplete:"off",spellcheck:!1}),re=T("CSS classes",L,"Your own class names, separated by spaces, added to this item's <li> - target the link with .your-class > a. Style them in Custom CSS."),_=w("small",{className:"text-danger",style:"display:none;margin-top:.25rem"});re.append(_);const G=w("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),j=w("div",{className:"me-item-form"},k("Link"),p,x,J,k("Access"),Ne(g,se),k("Badge"),Ne(te,ne),le,k("Appearance"),Oe,ie,h,k("Highlighting"),Ne(ce,Se),z,k("Styling"),re,G),$=E.slideover({title:v?`Edit ${He(v)}`:"Edit menu item",size:"lg",position:"right"});$.element.appendChild(j);const fe=()=>JSON.stringify([...j.querySelectorAll("input, select, textarea")].map(u=>u.type==="checkbox"?u.checked:u.value)),Ae=fe();let de=!1,ue=!1;Dt($);const V=$.close.bind($);$.close=async u=>{if(!de&&u!==!0&&fe()!==Ae){if(ue)return;ue=!0;const Q=await E.confirm("Discard the changes to this item?");if(ue=!1,!Q)return}return de=!0,V()},j.addEventListener("keydown",u=>{(u.ctrlKey||u.metaKey)&&u.key==="Enter"&&(u.preventDefault(),G.click())}),$.open();const oe=$.element.closest(".dm-slideover")||$.element.querySelector(".dm-slideover")||$.element;oe.style.setProperty("width",Vt+"px","important"),oe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(j);const A=u=>j.querySelector(`[name="${u}"]`)?.value||"";G.addEventListener("click",()=>{const u=dt(A("class"));if(u.length){_.textContent=u.join("; "),_.style.display="block",L.focus();return}o.class=At(A("class")),o.text=A("text"),o.icon=A("icon"),o.locked||(o.visibility=A("visibility")),!o.tool&&!o.locked?(o.url=A("url"),o.permission=A("permission")):o.touched=!0;const Q=A("badgeText"),me=A("badgeCount"),ge=ne._read();if(o.badge=Q||me?{...Q&&{text:Q},...me&&{countFrom:me},...ge&&{variant:ge}}:null,A("renderAs")==="pill"){const we=pe._read();o.pill={style:A("pillStyle")||"filled",...we&&{variant:we}}}else o.pill=null;o.colour=h._read();const ve=A("hlHover"),be=A("hlActive"),ye=z._read();o.highlight=ve||be||ye?{...ve&&{hover:ve},...be&&{active:be},...ye&&{accent:ye}}:null,de=!0,$.close(!0),s()})}let K=null,ht=!1;function nn(){ht||!window.R?.use||(ht=!0,R.use((o,r,i)=>{const c=r?.path||"";return!(Xt.test(c)&&(o?.path||"")!==c)||!K?.dirty()?i():E.confirm(`You have unsaved changes to the menu "${He(K.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(v=>{v?i():history.replaceState(null,"",`#${c}`)})}),M.subscribe("router:afterChange",({to:o}={})=>{if(K&&(o?.path||"")!==K.path){const r=K;K=null,r.dispose()}}))}function ft(o,r){const i=o.querySelector(".dm-plugin-banner-name"),c=i?.querySelector(".dm-plugin-banner-sep");if(!(!i||!c)){for(;c.nextSibling;)c.nextSibling.remove();i.appendChild(document.createTextNode(r))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(o){if(nn(),K){const e=K;K=null,e.dispose()}const r=[],i=e=>(r.push(e),e);let c=!1;const s=o.get(0).querySelector(".mex")||o.get(0),v=()=>!c&&s.isConnected,k=location.hash.replace(/^#/,""),p=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),B=p?decodeURIComponent(p[1]):null,x=!B,J=`menu-editor.draft.${B||"new"}`,C=E.loader(o.get(0),{type:"dots"});let g,q,se,te,U,le,ne;try{if(x)g={slug:"",name:"",description:"",items:[]};else try{g=await N.menus.get(B)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[q,se,te,U,le,ne]=await Promise.all([N.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),N.collections.list().catch(()=>[]),N.get("/collections/roles/entries?limit=100").catch(()=>null),N.menuLocations.registry().catch(()=>[]),N.pages.list().catch(()=>[])])}finally{C.destroy()}if(!s.isConnected)return;const Oe=(Array.isArray(U)?U:U?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,t)=>t.level-e.level),O=!x&&B===Yt;let pe=[];if(O&&(pe=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!s.isConnected))return;const ie=e=>ut(O?Lt(Ct(e||[],pe,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let h=ie(g.items);const D=M.observable(!1),ce=M.observable(!1),he=M.observable(""),Se=M.observable(0);let z="";const L=s.querySelector("#me-items-list");function re(){Qt(L,h,O),Se.value=h.filter(e=>!ae(e)).length}const _=()=>{re(),Y()},G=()=>O?pt(h):new Set,j=e=>h.find(t=>t.id===e);function $(e){requestAnimationFrame(()=>L.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function fe(e){const t=f=>h.find(l=>!l.type&&!l.url&&!l.tool&&(l.key||"").toLowerCase()===f)||h.find(l=>!l.type&&!l.url&&!l.tool&&!l.key&&(l.text||"").toLowerCase()===f);let a=t(String(e.tool.folder||"").toLowerCase())||t(Rt);const m=String(e.tool.group||"").trim();if(a&&m){const f=It(a.key||Ht(a.text),m),l=d=>d!==e&&!d.type&&!d.url&&!d.tool;let b=h.find(d=>l(d)&&(d.key||"").toLowerCase()===f)||h.find(d=>l(d)&&d.parentId===a.id&&(!d.key||d.key.toLowerCase()===f)&&(d.text||"").toLowerCase()===m.toLowerCase());b||([b]=ut([{text:m,key:f,icon:Tt,synthesised:!0}],a.id),h.push(b)),a=b}e.parentId=a?a.id:null,h.splice(h.indexOf(e),1),h.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const Ae=e=>!G().has(e.id)&&!(e.tool&&!e.tool.orphan);async function de(e){const t=j(e);if(!t||!Ae(t))return;const a=d=>{let X=d;for(;X;){if(X.id===e)return!0;X=h.find(P=>P.id===X.parentId)}return!1},m=h.filter(d=>d.id!==e&&a(d));if(m.length&&!await E.confirm(`Remove "${He(t.text||t.type||"this item")}" and the ${m.length} item${m.length===1?"":"s"} beneath it?`))return;const f=G(),l=m.filter(d=>d.tool),b=m.filter(d=>!d.tool&&f.has(d.id));h=h.filter(d=>!a(d)||l.includes(d)||b.includes(d));for(const d of b)d.parentId=t.parentId??null;for(const d of l)d.tool.orphan?d.parentId=t.parentId??null:fe(d);_()}function ue(e){const t=j(e);!t||ae(t)||G().has(e)||(t.hidden=!t.hidden,t.touched=!0,_())}function V(e){const t=j(e);!t||ae(t)||(t.locked=O&&G().has(t.id),tn(t,se.resources||[],te,Oe,()=>{_(),$(e)}))}function oe(e){const t={id:_e(),parentId:null,...e==="separator"||e==="theme-switcher"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};h.push(t),_(),ae(t)?$(t.id):V(t.id)}const A=e=>t=>{e(t)&&(_(),$(t))},u=A(e=>mt(h,e,-1)),Q=A(e=>mt(h,e,1)),me=A(e=>Mt(h,e)),ge=A(e=>qt(h,e));function ve(e){const t=j(e);if(!t)return[];const a=ae(t),m=G().has(e),f=Ut(h,e),l=f.findIndex(P=>P.id===e),b=t.tool,d=b&&(b.persisted||t.touched),X=P=>()=>{const ke=zt(h,e,P,_e());_(),ke&&!ae(ke)?V(ke.id):ke&&$(ke.id)};return[{header:a?{separator:"Separator",spacer:"Spacer","theme-switcher":"Theme switcher"}[t.type]:t.text||b?.label||"(untitled)"},...a?[]:[{label:"Edit\u2026",icon:"edit",action:()=>V(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:X("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:a,action:()=>{const P=Pt(h,e,_e());_(),P&&V(P.id)}},{label:"Add separator below",icon:"minus",action:X("separator")},{label:"Add spacer below",icon:"move",action:X("spacer")},...O?[]:[{label:"Add theme switcher below",icon:"palette",action:X("theme-switcher")}],{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:l<=0,action:()=>u(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:l<0||l>=f.length-1,action:()=>Q(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:l<=0||ae(f[l-1]),action:()=>me(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:t.parentId==null,action:()=>ge(e)},{type:"divider"},...a?[]:[{label:t.hidden?"Show":"Hide",icon:t.hidden?"eye":"eye-off",disabled:m,action:()=>ue(e)}],{label:"Duplicate",icon:"copy",disabled:!!b,action:()=>{const P=Ft(h,e,_e);_(),P&&$(P.id)}},...b&&!b.orphan&&d?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{fe(t),_()}}]:[],{label:m?"Remove - always in the sidebar":b&&!b.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!Ae(t),action:()=>de(e)}]}const be=E.contextMenu(L,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>ve(e.dataset.id)});i(()=>be?.destroy?.());const ye=xt(L,()=>h,_,{items:".menu-tree-row",handle:".menu-tree-grip"});i(()=>ye?.destroy());const we=e=>{const t=e.target.closest(".menu-tree-row");if(!t)return;const a=t.dataset.id;if(e.target.closest(".mex-kebab")){Ge(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){ue(a);return}if(e.target.closest(".me-edit")){V(a);return}e.target.closest("select, .menu-tree-grip, button")||V(a)},Ve=e=>{const t=e.target.closest(".menu-tree-row");if(!t||e.target!==t){t&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),Ge(t));return}const a=t.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),Ge(t);else if(e.key==="Enter")e.preventDefault(),V(a);else if(e.key==="Delete")e.preventDefault(),de(a);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),u(a);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),Q(a);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),me(a);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),ge(a);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const m=[...L.querySelectorAll(".menu-tree-row")],f=m.indexOf(t)+(e.key==="ArrowDown"?1:-1);m[f]&&(e.preventDefault(),m[f].focus())}},Ye=e=>{if(!e.target.matches(".me-spacer-size"))return;const t=j(e.target.closest(".menu-tree-row")?.dataset.id);t&&(t.size=e.target.value,Y())};L.addEventListener("click",we),L.addEventListener("keydown",Ve),L.addEventListener("change",Ye),i(()=>{L.removeEventListener("click",we),L.removeEventListener("keydown",Ve),L.removeEventListener("change",Ye)});const n=e=>o.find(e),Ee=n("#me-float-accent"),De=n("#me-float-accent-hex"),je=()=>{De.get(0).style.display=Ee.val()==="__custom__"?"":"none"},gt=()=>Ee.val()==="__custom__"?De.val():Ee.val(),$e=n("#me-highlight-accent"),Pe=n("#me-highlight-accent-hex"),Xe=()=>{Pe.get(0).style.display=$e.val()==="__custom__"?"":"none"},vt=()=>$e.val()==="__custom__"?Pe.val():$e.val(),Je=()=>{const e=!!(n("#me-entrance-enabled").get(0)||{}).checked;n(".dm-entrance-field").each(function(){this.style.display=e?"":"none"});const t=n("#me-position").val()==="floating";n(".dm-float-field").each(function(){this.style.display=t?"":"none"}),t&&je();const a=n("#me-orientation").val()==="vertical";n(".dm-vertical-field").each(function(){this.style.display=a?"":"none"}),n(".dm-dock-rail-field").each(function(){this.style.display=a&&!t?"":"none"}),n(".dm-dock-bar-field").each(function(){this.style.display=!a&&!t?"":"none"});const m=!!(n("#me-dock-collapsible").get(0)||{}).checked,f=!!(n("#me-dock-autohide").get(0)||{}).checked;n(".dm-dock-collapsed-field").each(function(){this.style.display=m&&!f?"":"none"});const l=!!(n("#me-float-collapsible").get(0)||{}).checked;n(".dm-float-collapsed-field").each(function(){this.style.display=t&&l?"":"none"})},Qe=(e,t,a,m)=>{const f=n(e).get(0);f&&(f.innerHTML="",f.add(new Option(m,"")),t.forEach(l=>f.add(new Option(a[l]||l,l))))};Qe("#me-highlight-hover",lt,ct,"- theme default -"),Qe("#me-highlight-active",it,rt,"- theme default -");{const e=n("#me-entrance-animation").get(0);e&&(e.innerHTML="",qe.forEach(t=>e.add(new Option(Et[t]||t,t))))}const Be=n("#me-bind-slot"),Fe=n("#me-bind-projects"),xe=n("#me-bind-pages");Be.html('<option value="">- not bound -</option>'+(le||[]).map(e=>`<option value="${y(e.slot)}">${y(e.label||e.slot)} (${y(e.slot)})</option>`).join("")),Fe.html(q.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join("")),n("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ne.map(e=>{const t=e.urlPath||e.url||"";return t?`<option value="${y(t)}">${y(e.title||t)} - ${y(t)}</option>`:""}).join(""));const Ze=()=>Bt({slot:Be.val(),projects:Array.from(Fe.get(0).selectedOptions).map(e=>e.value),pagesText:xe.val()});function Me(){const e=Ze(),t=n("#me-bind-summary");if(!e){t.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const a=[];e.projects.length&&a.push(`pages in ${e.projects.map(l=>`<code>${y(l)}</code>`).join(", ")}`),e.pages.length&&a.push(`pages matching ${e.pages.map(l=>`<code>${y(l)}</code>`).join(", ")}`);const m=e.pages.filter(l=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(l)),f=m.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${m.map(l=>`<code>${y(l)}</code>`).join(", ")}</div>`:"";t.html(a.length?`Takes over the <code>${y(e.slot)}</code> slot on ${a.join(" and ")}.${f}`:`<span class="text-warning">Slot <code>${y(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:bt}=await import("../lib/project-context.js");if(!v())return;const yt=x?bt():null;n("#me-project").html('<option value="">- none -</option>'+q.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join(""));function ze(e){h=ie(e.items),n("#me-variant").val(e.variant||""),n("#me-position").val(e.position||"");const t=n("#me-appearOnHover").get(0);t&&(t.checked=e.appearOnHover===!0),n("#me-float-anchor").val(e.float?.anchor||"TL"),n("#me-float-offsetX").val(e.float?.offsetX??""),n("#me-float-offsetY").val(e.float?.offsetY??""),n("#me-float-width").val(e.float?.width??""),n("#me-float-radius").val(e.float?.radius??""),n("#me-float-shadow").val(e.float?.shadow||""),n("#me-float-opacity").val(e.float?.opacity??""),n("#me-float-title").val(e.float?.title||"");for(const[l,b]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const d=n(l).get(0);d&&(d.checked=b===!0)}const a=e.float?.accent||"";Ee.val(a.startsWith("#")?"__custom__":a),a.startsWith("#")&&De.val(a),je(),n("#me-orientation").val(e.orientation||""),n("#me-align").val(e.align||""),n("#me-side").val(e.side||"left"),n("#me-dock-width").val(e.dock?.width??"");for(const l of["collapsible","collapsed","autohide","hideOnScroll"]){const b=n(`#me-dock-${l}`).get(0);b&&(b.checked=e.dock?.[l]===!0)}n("#me-class").val(e.class||""),n("#me-highlight-hover").val(e.highlight?.hover||""),n("#me-highlight-active").val(e.highlight?.active||"");const m=e.highlight?.accent||"";$e.val(m.startsWith("#")?"__custom__":m),m.startsWith("#")&&Pe.val(m),Xe();{const l=n("#me-entrance-enabled").get(0);l&&(l.checked=e.entrance?.enabled===!0)}n("#me-entrance-animation").val(qe.includes(e.entrance?.animation)?e.entrance.animation:qe[0]),n("#me-entrance-stagger").val(e.entrance?.stagger??""),n("#me-entrance-duration").val(e.entrance?.duration??""),n("#me-fontFamily").val(e.style?.fontFamily||""),n("#me-fontSize").val(e.style?.fontSize||""),n("#me-fontWeight").val(e.style?.fontWeight||""),n("#me-letterSpacing").val(e.style?.letterSpacing||""),n("#me-iconSize").val(e.style?.iconSize||""),Be.val(e.binding?.slot||"");const f=new Set(e.binding?.projects||[]);Array.from(Fe.get(0).options).forEach(l=>{l.selected=f.has(l.value)}),xe.val((e.binding?.pages||[]).join(`
|
|
28
|
-
`)),n("#me-slug").val(e.slug||""),n("#me-name").val(e.name||""),n("#me-description").val(e.description||""),n("#me-project").val(e.meta?.project||yt||""),Je(),Me(),re()}const
|
|
27
|
+
</div>`),v(p.id)}}v(null),o.innerHTML=s.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(o)}function w(o,r={},...i){const c=document.createElement(o);Object.assign(c,r);for(const s of i)s!=null&&c.append(s);return c}function T(o,r,i){const c=w("label",{className:"form-field"},w("span",{className:"form-label",textContent:o}),r);return i&&c.append(w("small",{className:"form-hint",textContent:i,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),c}function Zt(o,r){const i=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(r||[]).map(s=>[s.name,`${s.label||s.name} and above`]),...(r||[]).filter(s=>s.level!==0).map(s=>[`=${s.name}`,`${s.label||s.name} only`]),["private","Private - super-admin only"]];o&&!i.some(([s])=>s===o)&&i.push([o,`${o} (custom)`]);const c=ee(i,o||"");return c.name="visibility",c}function ee(o,r){const i=w("select",{className:"form-select"});return o.forEach(([c,s])=>i.add(new Option(s,c))),i.value=r??"",i}function Re(o,r){const i=typeof r=="string"&&r.startsWith("#"),c=ee([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],i?"__custom__":r||""),s=w("input",{type:"color",className:"form-input me-colour-hex",value:i?r:"#000000"});s.style.display=i?"":"none",c.addEventListener("change",()=>{s.style.display=c.value==="__custom__"?"":"none"});const v=T(o,c);return v.append(s),v._read=()=>c.value==="__custom__"?s.value:c.value,v}function en(o,r){const i=w("input",{className:"form-input me-icon",name:"icon",value:r||""}),c=w("span",{className:"me-icon-preview"});r&&c.setAttribute("data-icon",r);const s=w("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),v=k=>{k?c.setAttribute("data-icon",k):c.removeAttribute("data-icon"),Domma.icons.scan(c.parentNode||c)};return s.addEventListener("click",()=>$t(k=>{i.value=k,v(k)})),i.addEventListener("input",()=>v(i.value.trim())),T(o,w("div",{className:"me-icon-field"},i,s,c))}function Ne(...o){return w("div",{className:"me-field-grid"},...o)}async function tn(o,r,i,c,s){const v=o.text||o.tool?.label||"",k=u=>w("h4",{className:"me-form-section",textContent:u}),p=T("Label",w("input",{className:"form-input",name:"text",value:o.text||""}),"The text shown for this item."),F=w("input",{className:"form-input",name:"url",value:o.url||""}),x=T("URL",F,o.tool||o.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(o.tool||o.locked)&&(F.readOnly=!0);const J=en("Icon",o.icon||""),C=Zt(o.visibility||"",c),g=T("Visibility",C,o.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');o.locked&&(C.disabled=!0);const q=ee([["","- no permission gate -"],...(r||[]).map(u=>[u.key,u.label||u.key])],o.permission||"");q.name="permission";const se=T("Permission",q,o.tool||o.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(o.tool||o.locked)&&(q.disabled=!0);const te=T("Badge text",w("input",{className:"form-input",name:"badgeText",value:o.badge?.text||""})),U=ee([["","- none -"],...(i||[]).map(u=>[u.slug,u.title||u.slug])],o.badge?.countFrom||"");U.name="badgeCount";const le=T("Badge count from",U,"Show a live count of this collection\u2019s entries as the badge."),ne=Re("Badge colour",o.badge?.variant||""),z=ee([["link","Link"],["pill","Pill"]],o.pill?"pill":"link");z.name="renderAs";const Oe=T("Render as",z,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),D=T("Pill style",ee([["filled","Filled"],["outline","Outline"]],o.pill?.style||"filled"));D.querySelector("select").name="pillStyle";const pe=Re("Pill colour",o.pill?.variant||""),ie=w("div",{className:"me-pill-wrap"},Ne(D,pe));ie.style.display=o.pill?"":"none",z.addEventListener("change",()=>{ie.style.display=z.value==="pill"?"":"none"});const h=Re("Text colour",o.colour||""),j=ee([["","- use the menu default -"],...lt.map(u=>[u,ct[u]||u])],o.highlight?.hover||"");j.name="hlHover";const ce=T("Hover effect",j,"Overrides the menu-wide hover effect for this item only."),he=ee([["","- use the menu default -"],...it.map(u=>[u,rt[u]||u])],o.highlight?.active||"");he.name="hlActive";const Se=T("When selected",he,"How this item is marked when it points at the page being viewed."),W=Re("Highlight colour",o.highlight?.accent||""),L=w("input",{className:"form-input",name:"class",value:o.class||"",placeholder:"nav-cta push-right",autocomplete:"off",spellcheck:!1}),re=T("CSS classes",L,"Your own class names, separated by spaces, added to this item's <li> - target the link with .your-class > a. Style them in Custom CSS."),_=w("small",{className:"text-danger",style:"display:none;margin-top:.25rem"});re.append(_);const G=w("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),P=w("div",{className:"me-item-form"},k("Link"),p,x,J,k("Access"),Ne(g,se),k("Badge"),Ne(te,ne),le,k("Appearance"),Oe,ie,h,k("Highlighting"),Ne(ce,Se),W,k("Styling"),re,G),$=E.slideover({title:v?`Edit ${He(v)}`:"Edit menu item",size:"lg",position:"right"});$.element.appendChild(P);const fe=()=>JSON.stringify([...P.querySelectorAll("input, select, textarea")].map(u=>u.type==="checkbox"?u.checked:u.value)),Ae=fe();let de=!1,ue=!1;Dt($);const V=$.close.bind($);$.close=async u=>{if(!de&&u!==!0&&fe()!==Ae){if(ue)return;ue=!0;const Q=await E.confirm("Discard the changes to this item?");if(ue=!1,!Q)return}return de=!0,V()},P.addEventListener("keydown",u=>{(u.ctrlKey||u.metaKey)&&u.key==="Enter"&&(u.preventDefault(),G.click())}),$.open();const oe=$.element.closest(".dm-slideover")||$.element.querySelector(".dm-slideover")||$.element;oe.style.setProperty("width",Vt+"px","important"),oe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(P);const A=u=>P.querySelector(`[name="${u}"]`)?.value||"";G.addEventListener("click",()=>{const u=dt(A("class"));if(u.length){_.textContent=u.join("; "),_.style.display="block",L.focus();return}o.class=At(A("class")),o.text=A("text"),o.icon=A("icon"),o.locked||(o.visibility=A("visibility")),!o.tool&&!o.locked?(o.url=A("url"),o.permission=A("permission")):o.touched=!0;const Q=A("badgeText"),me=A("badgeCount"),ge=ne._read();if(o.badge=Q||me?{...Q&&{text:Q},...me&&{countFrom:me},...ge&&{variant:ge}}:null,A("renderAs")==="pill"){const we=pe._read();o.pill={style:A("pillStyle")||"filled",...we&&{variant:we}}}else o.pill=null;o.colour=h._read();const ve=A("hlHover"),be=A("hlActive"),ye=W._read();o.highlight=ve||be||ye?{...ve&&{hover:ve},...be&&{active:be},...ye&&{accent:ye}}:null,de=!0,$.close(!0),s()})}let K=null,ht=!1;function nn(){ht||!window.R?.use||(ht=!0,R.use((o,r,i)=>{const c=r?.path||"";return!(Xt.test(c)&&(o?.path||"")!==c)||!K?.dirty()?i():E.confirm(`You have unsaved changes to the menu "${He(K.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(v=>{v?i():history.replaceState(null,"",`#${c}`)})}),M.subscribe("router:afterChange",({to:o}={})=>{if(K&&(o?.path||"")!==K.path){const r=K;K=null,r.dispose()}}))}function ft(o,r){const i=o.querySelector(".dm-plugin-banner-name"),c=i?.querySelector(".dm-plugin-banner-sep");if(!(!i||!c)){for(;c.nextSibling;)c.nextSibling.remove();i.appendChild(document.createTextNode(r))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(o){if(nn(),K){const e=K;K=null,e.dispose()}const r=[],i=e=>(r.push(e),e);let c=!1;const s=o.get(0).querySelector(".mex")||o.get(0),v=()=>!c&&s.isConnected,k=location.hash.replace(/^#/,""),p=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),F=p?decodeURIComponent(p[1]):null,x=!F,J=`menu-editor.draft.${F||"new"}`,C=E.loader(o.get(0),{type:"dots"});let g,q,se,te,U,le,ne;try{if(x)g={slug:"",name:"",description:"",items:[]};else try{g=await O.menus.get(F)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[q,se,te,U,le,ne]=await Promise.all([O.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),O.collections.list().catch(()=>[]),O.get("/collections/roles/entries?limit=100").catch(()=>null),O.menuLocations.registry().catch(()=>[]),O.pages.list().catch(()=>[])])}finally{C.destroy()}if(!s.isConnected)return;const Oe=(Array.isArray(U)?U:U?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,t)=>t.level-e.level),D=!x&&F===Yt;let pe=[];if(D&&(pe=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!s.isConnected))return;const ie=e=>ut(D?Lt(Ct(e||[],pe,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let h=ie(g.items);const j=M.observable(!1),ce=M.observable(!1),he=M.observable(""),Se=M.observable(0);let W="";const L=s.querySelector("#me-items-list");function re(){Qt(L,h,D),Se.value=h.filter(e=>!ae(e)).length}const _=()=>{re(),Y()},G=()=>D?pt(h):new Set,P=e=>h.find(t=>t.id===e);function $(e){requestAnimationFrame(()=>L.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function fe(e){const t=f=>h.find(l=>!l.type&&!l.url&&!l.tool&&(l.key||"").toLowerCase()===f)||h.find(l=>!l.type&&!l.url&&!l.tool&&!l.key&&(l.text||"").toLowerCase()===f);let a=t(String(e.tool.folder||"").toLowerCase())||t(Rt);const m=String(e.tool.group||"").trim();if(a&&m){const f=It(a.key||Ht(a.text),m),l=d=>d!==e&&!d.type&&!d.url&&!d.tool;let b=h.find(d=>l(d)&&(d.key||"").toLowerCase()===f)||h.find(d=>l(d)&&d.parentId===a.id&&(!d.key||d.key.toLowerCase()===f)&&(d.text||"").toLowerCase()===m.toLowerCase());b||([b]=ut([{text:m,key:f,icon:Tt,synthesised:!0}],a.id),h.push(b)),a=b}e.parentId=a?a.id:null,h.splice(h.indexOf(e),1),h.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const Ae=e=>!G().has(e.id)&&!(e.tool&&!e.tool.orphan);async function de(e){const t=P(e);if(!t||!Ae(t))return;const a=d=>{let X=d;for(;X;){if(X.id===e)return!0;X=h.find(B=>B.id===X.parentId)}return!1},m=h.filter(d=>d.id!==e&&a(d));if(m.length&&!await E.confirm(`Remove "${He(t.text||t.type||"this item")}" and the ${m.length} item${m.length===1?"":"s"} beneath it?`))return;const f=G(),l=m.filter(d=>d.tool),b=m.filter(d=>!d.tool&&f.has(d.id));h=h.filter(d=>!a(d)||l.includes(d)||b.includes(d));for(const d of b)d.parentId=t.parentId??null;for(const d of l)d.tool.orphan?d.parentId=t.parentId??null:fe(d);_()}function ue(e){const t=P(e);!t||ae(t)||G().has(e)||(t.hidden=!t.hidden,t.touched=!0,_())}function V(e){const t=P(e);!t||ae(t)||(t.locked=D&&G().has(t.id),tn(t,se.resources||[],te,Oe,()=>{_(),$(e)}))}function oe(e){const t={id:_e(),parentId:null,...e==="separator"||e==="theme-switcher"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};h.push(t),_(),ae(t)?$(t.id):V(t.id)}const A=e=>t=>{e(t)&&(_(),$(t))},u=A(e=>mt(h,e,-1)),Q=A(e=>mt(h,e,1)),me=A(e=>Mt(h,e)),ge=A(e=>qt(h,e));function ve(e){const t=P(e);if(!t)return[];const a=ae(t),m=G().has(e),f=Ut(h,e),l=f.findIndex(B=>B.id===e),b=t.tool,d=b&&(b.persisted||t.touched),X=B=>()=>{const ke=zt(h,e,B,_e());_(),ke&&!ae(ke)?V(ke.id):ke&&$(ke.id)};return[{header:a?{separator:"Separator",spacer:"Spacer","theme-switcher":"Theme switcher"}[t.type]:t.text||b?.label||"(untitled)"},...a?[]:[{label:"Edit\u2026",icon:"edit",action:()=>V(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:X("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:a,action:()=>{const B=Pt(h,e,_e());_(),B&&V(B.id)}},{label:"Add separator below",icon:"minus",action:X("separator")},{label:"Add spacer below",icon:"move",action:X("spacer")},...D?[]:[{label:"Add theme switcher below",icon:"palette",action:X("theme-switcher")}],{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:l<=0,action:()=>u(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:l<0||l>=f.length-1,action:()=>Q(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:l<=0||ae(f[l-1]),action:()=>me(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:t.parentId==null,action:()=>ge(e)},{type:"divider"},...a?[]:[{label:t.hidden?"Show":"Hide",icon:t.hidden?"eye":"eye-off",disabled:m,action:()=>ue(e)}],{label:"Duplicate",icon:"copy",disabled:!!b,action:()=>{const B=Ft(h,e,_e);_(),B&&$(B.id)}},...b&&!b.orphan&&d?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{fe(t),_()}}]:[],{label:m?"Remove - always in the sidebar":b&&!b.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!Ae(t),action:()=>de(e)}]}const be=E.contextMenu(L,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>ve(e.dataset.id)});i(()=>be?.destroy?.());const ye=xt(L,()=>h,_,{items:".menu-tree-row",handle:".menu-tree-grip"});i(()=>ye?.destroy());const we=e=>{const t=e.target.closest(".menu-tree-row");if(!t)return;const a=t.dataset.id;if(e.target.closest(".mex-kebab")){Ge(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){ue(a);return}if(e.target.closest(".me-edit")){V(a);return}e.target.closest("select, .menu-tree-grip, button")||V(a)},Ve=e=>{const t=e.target.closest(".menu-tree-row");if(!t||e.target!==t){t&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),Ge(t));return}const a=t.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),Ge(t);else if(e.key==="Enter")e.preventDefault(),V(a);else if(e.key==="Delete")e.preventDefault(),de(a);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),u(a);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),Q(a);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),me(a);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),ge(a);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const m=[...L.querySelectorAll(".menu-tree-row")],f=m.indexOf(t)+(e.key==="ArrowDown"?1:-1);m[f]&&(e.preventDefault(),m[f].focus())}},Ye=e=>{if(!e.target.matches(".me-spacer-size"))return;const t=P(e.target.closest(".menu-tree-row")?.dataset.id);t&&(t.size=e.target.value,Y())};L.addEventListener("click",we),L.addEventListener("keydown",Ve),L.addEventListener("change",Ye),i(()=>{L.removeEventListener("click",we),L.removeEventListener("keydown",Ve),L.removeEventListener("change",Ye)});const n=e=>o.find(e),Ee=n("#me-float-accent"),De=n("#me-float-accent-hex"),je=()=>{De.get(0).style.display=Ee.val()==="__custom__"?"":"none"},gt=()=>Ee.val()==="__custom__"?De.val():Ee.val(),$e=n("#me-highlight-accent"),Pe=n("#me-highlight-accent-hex"),Xe=()=>{Pe.get(0).style.display=$e.val()==="__custom__"?"":"none"},vt=()=>$e.val()==="__custom__"?Pe.val():$e.val(),Je=()=>{const e=!!(n("#me-entrance-enabled").get(0)||{}).checked;n(".dm-entrance-field").each(function(){this.style.display=e?"":"none"});const t=n("#me-position").val()==="floating";n(".dm-float-field").each(function(){this.style.display=t?"":"none"}),t&&je();const a=n("#me-orientation").val()==="vertical";n(".dm-vertical-field").each(function(){this.style.display=a?"":"none"}),n(".dm-dock-rail-field").each(function(){this.style.display=a&&!t?"":"none"}),n(".dm-dock-bar-field").each(function(){this.style.display=!a&&!t?"":"none"});const m=!!(n("#me-dock-collapsible").get(0)||{}).checked,f=!!(n("#me-dock-autohide").get(0)||{}).checked;n(".dm-dock-collapsed-field").each(function(){this.style.display=m&&!f?"":"none"});const l=!!(n("#me-float-collapsible").get(0)||{}).checked;n(".dm-float-collapsed-field").each(function(){this.style.display=t&&l?"":"none"})},Qe=(e,t,a,m)=>{const f=n(e).get(0);f&&(f.innerHTML="",f.add(new Option(m,"")),t.forEach(l=>f.add(new Option(a[l]||l,l))))};Qe("#me-highlight-hover",lt,ct,"- theme default -"),Qe("#me-highlight-active",it,rt,"- theme default -");{const e=n("#me-entrance-animation").get(0);e&&(e.innerHTML="",qe.forEach(t=>e.add(new Option(Et[t]||t,t))))}const Be=n("#me-bind-slot"),Fe=n("#me-bind-projects"),xe=n("#me-bind-pages");Be.html('<option value="">- not bound -</option>'+(le||[]).map(e=>`<option value="${y(e.slot)}">${y(e.label||e.slot)} (${y(e.slot)})</option>`).join("")),Fe.html(q.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join("")),n("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ne.map(e=>{const t=e.urlPath||e.url||"";return t?`<option value="${y(t)}">${y(e.title||t)} - ${y(t)}</option>`:""}).join(""));const Ze=()=>Bt({slot:Be.val(),projects:Array.from(Fe.get(0).selectedOptions).map(e=>e.value),pagesText:xe.val()});function Me(){const e=Ze(),t=n("#me-bind-summary");if(!e){t.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const a=[];e.projects.length&&a.push(`pages in ${e.projects.map(l=>`<code>${y(l)}</code>`).join(", ")}`),e.pages.length&&a.push(`pages matching ${e.pages.map(l=>`<code>${y(l)}</code>`).join(", ")}`);const m=e.pages.filter(l=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(l)),f=m.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${m.map(l=>`<code>${y(l)}</code>`).join(", ")}</div>`:"";t.html(a.length?`Takes over the <code>${y(e.slot)}</code> slot on ${a.join(" and ")}.${f}`:`<span class="text-warning">Slot <code>${y(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:bt}=await import("../lib/project-context.js");if(!v())return;const yt=x?bt():null;n("#me-project").html('<option value="">- none -</option>'+q.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join(""));function ze(e){h=ie(e.items),n("#me-variant").val(e.variant||""),n("#me-position").val(e.position||"");const t=n("#me-appearOnHover").get(0);t&&(t.checked=e.appearOnHover===!0),n("#me-float-anchor").val(e.float?.anchor||"TL"),n("#me-float-offsetX").val(e.float?.offsetX??""),n("#me-float-offsetY").val(e.float?.offsetY??""),n("#me-float-width").val(e.float?.width??""),n("#me-float-radius").val(e.float?.radius??""),n("#me-float-shadow").val(e.float?.shadow||""),n("#me-float-opacity").val(e.float?.opacity??""),n("#me-float-title").val(e.float?.title||"");for(const[l,b]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const d=n(l).get(0);d&&(d.checked=b===!0)}const a=e.float?.accent||"";Ee.val(a.startsWith("#")?"__custom__":a),a.startsWith("#")&&De.val(a),je(),n("#me-orientation").val(e.orientation||""),n("#me-align").val(e.align||""),n("#me-mobile-hamburger").get(0).checked=e.mobile?.hamburgerOnly===!0,n("#me-mobile-brand").get(0).checked=e.mobile?.hideBrand===!0,n("#me-side").val(e.side||"left"),n("#me-dock-width").val(e.dock?.width??"");for(const l of["collapsible","collapsed","autohide","hideOnScroll"]){const b=n(`#me-dock-${l}`).get(0);b&&(b.checked=e.dock?.[l]===!0)}n("#me-class").val(e.class||""),n("#me-highlight-hover").val(e.highlight?.hover||""),n("#me-highlight-active").val(e.highlight?.active||"");const m=e.highlight?.accent||"";$e.val(m.startsWith("#")?"__custom__":m),m.startsWith("#")&&Pe.val(m),Xe();{const l=n("#me-entrance-enabled").get(0);l&&(l.checked=e.entrance?.enabled===!0)}n("#me-entrance-animation").val(qe.includes(e.entrance?.animation)?e.entrance.animation:qe[0]),n("#me-entrance-stagger").val(e.entrance?.stagger??""),n("#me-entrance-duration").val(e.entrance?.duration??""),n("#me-fontFamily").val(e.style?.fontFamily||""),n("#me-fontSize").val(e.style?.fontSize||""),n("#me-fontWeight").val(e.style?.fontWeight||""),n("#me-letterSpacing").val(e.style?.letterSpacing||""),n("#me-iconSize").val(e.style?.iconSize||""),Be.val(e.binding?.slot||"");const f=new Set(e.binding?.projects||[]);Array.from(Fe.get(0).options).forEach(l=>{l.selected=f.has(l.value)}),xe.val((e.binding?.pages||[]).join(`
|
|
28
|
+
`)),n("#me-slug").val(e.slug||""),n("#me-name").val(e.name||""),n("#me-description").val(e.description||""),n("#me-project").val(e.meta?.project||yt||""),Je(),Me(),re()}const N=e=>!!(n(e).get(0)||{}).checked;function Ce(){const e={variant:n("#me-variant").val(),position:n("#me-position").val(),appearOnHover:N("#me-appearOnHover"),floatAnchor:n("#me-float-anchor").val(),floatOffsetX:n("#me-float-offsetX").val(),floatOffsetY:n("#me-float-offsetY").val(),floatWidth:n("#me-float-width").val(),floatRadius:n("#me-float-radius").val(),floatShadow:n("#me-float-shadow").val(),floatAccent:gt(),floatOpacity:n("#me-float-opacity").val(),floatTitle:n("#me-float-title").val(),floatCollapsible:N("#me-float-collapsible"),floatCollapsed:N("#me-float-collapsed"),floatMovable:N("#me-float-movable"),floatResizable:N("#me-float-resizable"),highlightHover:n("#me-highlight-hover").val(),highlightActive:n("#me-highlight-active").val(),highlightAccent:vt(),class:n("#me-class").val(),entranceEnabled:N("#me-entrance-enabled"),entranceAnimation:n("#me-entrance-animation").val(),entranceStagger:n("#me-entrance-stagger").val(),entranceDuration:n("#me-entrance-duration").val(),orientation:n("#me-orientation").val(),align:n("#me-align").val(),side:n("#me-side").val(),fontFamily:n("#me-fontFamily").val(),fontSize:n("#me-fontSize").val(),fontWeight:n("#me-fontWeight").val(),letterSpacing:n("#me-letterSpacing").val(),iconSize:n("#me-iconSize").val(),dockWidth:n("#me-dock-width").val(),dockCollapsible:N("#me-dock-collapsible"),dockCollapsed:N("#me-dock-collapsed"),dockAutohide:N("#me-dock-autohide"),mobileHamburgerOnly:N("#me-mobile-hamburger"),mobileHideBrand:N("#me-mobile-brand"),dockHideOnScroll:N("#me-dock-hideOnScroll")},t={slug:n("#me-slug").val(),name:n("#me-name").val(),description:n("#me-description").val(),project:n("#me-project").val()};return Wt(e,t,Ze(),Nt(h),g.meta||{})}const et=e=>[...Kt(e),...dt(e.class).map(t=>`CSS classes: ${t} (Behaviour tab).`)];let tt=!1,We=null;function Y(){if(!W)return;const e=Ce();We=e,j.value=Ie(e)!==W,he.value=j.peek()||tt?et(e).join(" "):""}const Le=e=>{e.target.closest("#me-items-list")||(e.target.matches("#me-position, #me-orientation, #me-float-collapsible, #me-dock-collapsible, #me-dock-autohide, #me-entrance-enabled")&&Je(),e.target.matches("#me-float-accent")&&je(),e.target.matches("#me-highlight-accent")&&Xe(),e.target.closest("#me-binding")&&Me(),Y())};s.addEventListener("input",Le),s.addEventListener("change",Le),i(()=>{s.removeEventListener("input",Le),s.removeEventListener("change",Le)}),n("#me-bind-page-add").on("click",()=>{const e=n("#me-bind-page-pick").val();if(!e)return;const t=xe.val().split(`
|
|
29
29
|
`).map(a=>a.trim()).filter(Boolean);t.includes(e)||t.push(e),xe.val(t.join(`
|
|
30
|
-
`)),Me(),Y()}),ze(g),
|
|
30
|
+
`)),Me(),Y()}),ze(g),W=Ie(Ce()),Y();const nt=()=>{try{S.remove?S.remove(J):S.set(J,null)}catch{}};async function Ke(){if(ce.peek())return;const e=Ce(),t=et(e);if(t.length){tt=!0,Y(),E.toast(t.join(" "),{type:"warning",duration:7e3});return}ce.value=!0;try{if(x)await O.menus.create(e);else if(e.slug!==g.slug){await O.menus.create(e);const a=await O.menuLocations.get();let m=!1;for(const[f,l]of Object.entries(a))l===g.slug&&(a[f]=e.slug,m=!0);m&&await O.menuLocations.save(a),await O.menus.remove(g.slug)}else await O.menus.update(g.slug,e);if(W=Ie(e),j.value=!1,nt(),jt("#/menus"),E.toast("Saved.",{type:"success"}),x||e.slug!==g.slug)location.hash="#/menus/edit/"+encodeURIComponent(e.slug);else{g={...g,...e};for(const a of h)a.tool&&a.touched&&(a.tool={...a.tool,persisted:!0});re(),W=Ie(Ce()),Y(),ft(o.get(0),e.name||e.slug)}if(D)try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}catch(a){E.toast(`Save failed: ${a.message||a}`,{type:"error"})}finally{ce.value=!1}}async function wt(){!j.peek()||!await E.confirm("Throw away the changes you have not saved?")||(ze(g),Y())}E.tabs(n("#me-tabs").get(0));const kt=M.applyBindings({dirty:j,saving:ce,problems:he,itemCount:Se},s,{methods:{save:()=>Ke(),discard:()=>wt(),addItem:()=>oe("item"),addSeparator:()=>oe("separator"),addSpacer:()=>oe("spacer"),addSwitcher:()=>oe("theme-switcher")}});i(()=>kt.dispose()),i(Ot(s,{position:"bottom"})),D&&n("#me-add-switcher").hide(),ft(o.get(0),x?"New menu":g.name||g.slug),Ue(o,{id:"menu-editor-back",icon:"arrow-left",title:"All menus",onClick:()=>{location.hash="#/menus"}}),Ue(o,{id:"menu-editor-locations",icon:"map-pin",title:"Menu locations",onClick:()=>{location.hash="#/menu-locations"}}),Ue(o,{id:"menu-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>Ke()});const ot=e=>{if(!(!(e.ctrlKey||e.metaKey)||e.key!=="s")){if(e.preventDefault(),e.stopImmediatePropagation(),document.querySelector(".me-item-form")?.offsetParent){E.toast("Apply the item first (Ctrl+Enter), then Save.",{type:"info"});return}Ke()}};document.addEventListener("keydown",ot,!0),i(()=>document.removeEventListener("keydown",ot,!0));const at=()=>{if(!(!j.peek()||!We))try{S.set(J,{menu:We,base:W,at:new Date().toISOString()})}catch{}},st=e=>{j.peek()&&(at(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",st),i(()=>window.removeEventListener("beforeunload",st)),K={path:k,dirty:()=>j.peek(),name:()=>n("#me-name").val()||g.name||g.slug||"new menu",dispose(){c=!0,at(),r.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(s);let Z=null;try{Z=S.get(J)}catch{}if(Z?.menu){nt();const e=Z.base&&Z.base!==W,t=Z.at?` (${Gt(Z.at)})`:"",a=x?"the new menu you started":`the menu "${He(g.name||g.slug)}"`,m=e?`You left unsaved changes to ${a}${t}, but the saved menu has changed since. Restore your version anyway?`:`You left unsaved changes to ${a}${t}. Restore them?`;await E.confirm(m)&&v()&&(ze({...Z.menu,meta:{...g.meta||{},...Z.menu.meta||{}}}),Y())}}};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{apiRequest as
|
|
1
|
+
import{apiRequest as A,getToken as Aa}from"../api.js";import{addBannerAction as Ia}from"../lib/plugin-chrome.js";import{helpPopovers as pt}from"../lib/help-popover.js";import{onceClosed as Na,openMenuAt as H,sidebarCount as N,viewLifetime as Oa}from"../lib/tool-kit.js";import{SHAPES as ct,whileLoading as dt}from"../lib/loading.js";import{fmtDateTime as Da}from"../lib/dates.js";import{applyChoice as Ha,chooseAllPeople as ut,choosePerson as Ua,choiceItems as Ba,cleanOptions as fe,counts as mt,customTypeRows as _a,inviteNote as za,peopleSummary as ja,personMenuItems as Fa,personRow as Wa,reportPersonRow as Ka,defaultOptions as Ne,draftKey as Za,draftQuestion as Va,historyRow as Ja,internalTypeRows as Ya,isDirty as Ga,kindTabs as Xa,liveDrafts as vt,optionsSnapshot as ht,PLAN_FILTERS as wt,planMatches as ft,planRow as Qa,planTiles as bt,productSummary as eo,progressPercent as to,progressText as ao,REPORT_FILTERS as yt,reportMatches as gt,reportRow as oo,stagedRow as so,typeMenuItems as no,withDraft as xt,withListPage as ro,withTypeChoice as lo}from"../lib/wordpress-import-arrange.js";const kt=/^#\/wordpress-import\/?(\?.*)?$/,se="#/wordpress-import",$="/import/wordpress",be=400,io=`
|
|
2
2
|
<div class="wpx-row" data-id="{{id}}" tabindex="0">
|
|
3
3
|
<span class="wpx-main"><strong>{{title}}</strong><small>{{meta}}</small></span>
|
|
4
4
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
5
5
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{title}}" title="Actions">\u22EE</button>
|
|
6
|
-
</div>`,
|
|
6
|
+
</div>`,Mt=`
|
|
7
7
|
<div class="wpx-row" data-key="{{key}}" tabindex="0">
|
|
8
8
|
<span class="wpx-main">
|
|
9
9
|
<strong>{{title}}</strong>
|
|
@@ -14,17 +14,17 @@ import{apiRequest as q,getToken as ua}from"../api.js";import{addBannerAction as
|
|
|
14
14
|
</span>
|
|
15
15
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillCls">{{pill}}</span></span>
|
|
16
16
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{title}}" title="Actions">\u22EE</button>
|
|
17
|
-
</div>`,
|
|
17
|
+
</div>`,Tt=`
|
|
18
18
|
<div class="wpx-row" data-from="{{from}}" tabindex="0">
|
|
19
19
|
<span class="wpx-main"><span class="wpx-where">{{from}} \u2192 {{to}}</span><span class="wpx-reason" data-bind-hidden="!reason">{{reason}}</span></span>
|
|
20
20
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
21
21
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{from}}" title="Actions">\u22EE</button>
|
|
22
|
-
</div>`,
|
|
22
|
+
</div>`,po=`
|
|
23
23
|
<div class="wpx-row" data-id="{{id}}" tabindex="0">
|
|
24
24
|
<span class="wpx-main"><strong>{{title}}</strong><small>{{meta}}</small><span class="wpx-reason">{{summary}}</span></span>
|
|
25
25
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
26
26
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{title}}" title="Actions">\u22EE</button>
|
|
27
|
-
</div>`,
|
|
27
|
+
</div>`,co=`
|
|
28
28
|
<div class="wpx-row wpx-type-row" data-type="{{type}}" tabindex="0">
|
|
29
29
|
<span class="wpx-main">
|
|
30
30
|
<strong>{{label}}</strong>
|
|
@@ -42,7 +42,27 @@ import{apiRequest as q,getToken as ua}from"../api.js";import{addBannerAction as
|
|
|
42
42
|
</span>
|
|
43
43
|
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
44
44
|
<button type="button" class="wpx-kebab" aria-label="Actions for {{label}}" title="Actions">\u22EE</button>
|
|
45
|
-
</div>`,ht='<div class="wpx-tile"><strong>{{value}}</strong><small>{{label}} <span data-bind-hidden="!sub">{{sub}}</span></small></div>',vt='<p class="wpx-alert"><span>{{text}}</span></p>',ft="<li>{{text}}</li>",Na='<div class="wpx-fact"><dt>{{label}}</dt><dd>{{value}}</dd></div>',Re='<button type="button" data-on-click="$root.pickSeg($data)" data-bind-class="cls">{{label}} <b>{{count}}</b></button>',g=va(dt);function wt(l,n,i){return new Promise((w,x)=>{const d=new XMLHttpRequest,L=new FormData;L.append("file",n),d.open("POST",`/api${l}`);const f=ua();f&&d.setRequestHeader("Authorization",`Bearer ${f}`),d.upload.onprogress=c=>{c.lengthComputable&&i(c.loaded/c.total)},d.onload=()=>{let c=null;try{c=JSON.parse(d.responseText)}catch{}d.status>=200&&d.status<300?w(c):x(new Error(c?.error||`The upload failed (${d.status}).`))},d.onerror=()=>x(new Error("The upload failed - the connection dropped.")),d.send(L),g.add(()=>{d.readyState!==4&&d.abort()})})}const fe=l=>l>=1048576?`${Math.round(l/1048576)} MB`:`${Math.max(1,Math.round(l/1024))} KB`,_=l=>String(l??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function Ua(l){const n=document.createElement("template");return n.innerHTML=l.trim(),n.content.firstElementChild}async function we(l,n){const i=E.confirm(l,n);let w=null;try{w=[...document.querySelectorAll(".dm-dialog-overlay")].at(-1)??null}catch{}const x=g.add(()=>{if(!w)return;const d=w;w=null;try{d.querySelector(".dm-dialog-cancel")?.click(),d.remove()}catch{}});try{return await i}finally{w=null,x()}}function bt(l){navigator.clipboard?.writeText(l).then(()=>E.toast("Copied.",{type:"success"}),()=>E.toast(l,{type:"info",duration:8e3}))}function te(l,n,i,w){const x=E.contextMenu(l,{cursor:"glyph",match:n,inherit:!1,density:"compact",items:i});g.add(()=>x?.destroy?.());const d=f=>{const c=f.target.closest(n);if(!c||!l.contains(c))return;const u=f.target.closest(".wpx-kebab");if(u){U(u);return}w?.(c)},L=f=>{const c=f.target.closest(n);c&&(f.key==="F10"&&f.shiftKey?(f.preventDefault(),U(c)):f.key==="Enter"&&f.target===c&&w&&(f.preventDefault(),f.stopPropagation(),w(c)))};l.addEventListener("click",d),l.addEventListener("keydown",L),g.add(()=>{l.removeEventListener("click",d),l.removeEventListener("keydown",L)})}export const wordpressImportView={templateUrl:"/admin/js/templates/wordpress-import.html",async onMount(l){g.reset();const n=l.get(0).querySelector(".wpx")||l.get(0),i=()=>dt.test(location.hash)&&n.isConnected;let w="";try{w=S.get("auth_user")?.id||""}catch{}const x=ga(w),d=()=>{try{return x?S.get(x):null}catch{return null}},L=e=>{try{x&&S.set(x,e)}catch{}},f=n.querySelector(".wpx-loading");let c;try{c=await tt(f,q(`${$}/status`),et.rows)}catch(e){if(!n.isConnected)return;f&&(f.hidden=!0);const t=n.querySelector(".wpx-failed");t&&(t.textContent=`Could not load the importer: ${e.message||e}. Reload the page to try again.`,t.hidden=!1);return}if(!i())return;f&&(f.hidden=!0),n.querySelector(".wpx-body").hidden=!1;const u=M.observable(c.staged||[]),A=M.observable(c.history||[]),z=M.observable(c.blog||{available:!1}),Ae=M.observable(c.shop||{available:!1}),B=c.limits||{},y=M.observable(c.running||null),m=M.observable(""),b=M.observable(null),ae=M.observable(!1),be=M.observable(!1),ye=M.observable(""),p=M.observable(Pe(z.peek().available)),D=M.observable("all"),P=M.observable(""),j=M.observable(""),se=M.observable(""),F=M.observable(""),oe=M.observable(""),ne=M.observable(!1);let re=!0;const _a=()=>u.peek().find(e=>e.id===m.peek())||null,ge=M.computed(()=>u.value.find(e=>e.id===m.value)||null),yt=M.computed(()=>m.value?"preview":"start"),R=M.computed(()=>!!z.value.available),gt=M.computed(()=>!!(b.value?.shop||Ae.value).available),Ie=M.computed(()=>!!m.value&&Ta(p.value,R.value)),K=e=>M.computed({read:()=>p.value[e]!==!1,write:t=>{p.value={...p.peek(),[e]:!!t}}}),O=e=>{p.value={...p.peek(),...e}},W=e=>{try{return fa(e)}catch{return e}},xt=M.computed(()=>u.value.map(e=>Pa(e,W))),kt=M.computed(()=>A.value.map(e=>ka(e,W))),Z=M.computed(()=>(b.value?.items||[]).map(e=>({...e,choice:p.value.choices?.[e.key]}))),Mt=M.computed(()=>Ea(Z.value).map(e=>({...e,cls:P.value===e.id?"is-on":"",seg:"kind"}))),Tt=M.computed(()=>at(Z.value,nt,rt,P.value)),Et=M.computed(()=>nt.map(e=>({...e,count:Tt.value[e.id],cls:D.value===e.id?"is-on":"",seg:"filter"}))),xe=M.computed(()=>{const e=j.value.trim().toLowerCase();return Z.value.filter(t=>(!P.value||t.kind===P.value)&&rt(t,D.value)&&(!e||`${t.title} ${t.target} ${t.oldUrl} ${t.postType||""}`.toLowerCase().includes(e)))}),$t=M.computed(()=>xe.value.slice(0,ve).map(e=>{const t=$a(e);return{...t,pillCls:`${t.pillClass}${e.choice?" is-chosen":""}`}})),Lt=M.computed(()=>xe.value.length>ve?`Showing the first ${ve} of ${xe.value.length} - search or filter to find the rest.`:""),St=M.computed(()=>Z.value.length?"Nothing matches.":"This export has nothing to import."),qt=M.computed(()=>it(b.value)),Ct=M.computed(()=>(b.value?.notes||[]).map(e=>({text:e}))),Pt=M.computed(()=>(b.value?.redirects||[]).slice(0,ve).map(e=>({...e,pill:e.action==="skip"?"Skipped":e.action==="update"?"Update":"New",pillClass:e.action==="skip"?"is-muted":"is-ok"}))),Rt=M.computed(()=>String((b.value?.redirects||[]).filter(e=>e.action!=="skip").length)),At=M.computed(()=>b.value?.site?.title||ge.value?.siteTitle||"WordPress export"),It=M.computed(()=>{const e=ge.value,t=b.value?.site;return[t?.url||e?.siteUrl,e?.fileName,t?.wxrVersion&&`WXR ${t.wxrVersion}`,e?.at&&`uploaded ${W(e.at)}`].filter(Boolean).join(" \xB7 ")}),V=M.computed(()=>La(b.value)),Dt=M.computed(()=>V.value?.note||""),Ot=M.computed(()=>V.value?.tone==="warn"?"is-warn":"is-info"),Ht=M.computed(()=>(V.value?.rows||[]).map(e=>({...e,id:e.label}))),Nt=M.computed(()=>(V.value?.notes||[]).map(e=>({text:e}))),Ut=M.computed(()=>!!V.value),ke=M.computed(()=>ya(b.value)),Me=M.computed(()=>Ma(b.value)),_t=M.computed(()=>!!(ke.value.length||Me.value.length)),zt=M.computed(()=>{const e=Me.value.length;return e?`Not imported: ${e} kind${e===1?"":"s"} of WordPress or plugin housekeeping`:""}),Bt=M.computed(()=>R.value?`Posts go to ${z.value.basePath||"/blog"}.`:z.value.reason||"No Blog is switched on here."),ie=M.computed(()=>ge.value?.uploads||null),jt=M.computed(()=>{const e=ie.value;return e?`${e.fileName} - ${e.files} file${e.files===1?"":"s"}, ${fe(e.size)}${e.unsafe?`. ${e.unsafe} with unsafe names (like ../) were ignored`:""}.`:`Zip the wp-content/uploads folder and upload it here (up to ${fe(B.uploads||0)}).`}),Ft=M.computed(()=>ie.value?"Replace the zip":"Upload the uploads zip"),De=M.computed(()=>!!b.value&&!y.value&&!ae.value&&!(p.value.media==="zip"&&!ie.value)),Kt=M.computed(()=>y.value?`Importing${y.value.siteTitle?` ${y.value.siteTitle}`:""}\u2026`:""),Wt=M.computed(()=>qa(y.value)),Oe=M.computed(()=>Sa(y.value)),Zt=M.observable(fe(B.wxr||0)),He=n.querySelector(".wpx-running .wpx-bar-fill");g.add(M.effect(()=>{He&&(He.style.width=`${Oe.value}%`)}));async function Te(){const e=await q(`${$}/status`);return i()?(u.value=e.staged||[],A.value=e.history||[],z.value=e.blog||{available:!1},Ae.value=e.shop||{available:!1},e.running&&!y.peek()&&(y.value=e.running,Y()),e):null}let le=0,Ee=null;async function ce({first:e=!1}={}){const t=m.peek();if(!t)return;const a=++le;ye.value="";const o=q(`${$}/staged/${t}/preview`,{method:"POST",body:JSON.stringify({options:he(p.peek(),R.peek())})});try{let v;if(e?(ae.value=!0,v=await tt(n.querySelector(".wpx-plan-loading"),o,et.table)):(be.value=!0,v=await o),a!==le||!i()||m.peek()!==t)return;b.value=v.plan}catch(v){if(a!==le||!i())return;if(v.status===404){E.toast("That upload has gone - upload the export again.",{type:"warning"}),J(),Te().catch(()=>{});return}ye.value=`Could not read the export: ${v.message||v}`}finally{a===le&&(ae.value=!1,be.value=!1)}}let pe="";g.add(M.effect(()=>{const e=`${m.value}|${ot(p.value)}`;if(e===pe)return;const t=pe.split("|")[0];pe=e,!(!m.value||t!==m.value)&&(clearTimeout(Ee),Ee=setTimeout(()=>ce(),250))})),g.add(()=>clearTimeout(Ee)),g.add(M.effect(()=>{const e=m.value,t=p.value,a=Ie.value;if(!e||!re||!x)return;const o=d();L(pt(o,w,e,a?{options:he(t,!0),at:new Date().toISOString(),was:e}:null))}));const $e=e=>{x&&L(pt(d(),w,e,null))};async function de(e){if(!u.peek().some(h=>h.id===e))return;const t=u.peek().find(h=>h.id===e),a=st(d(),u.peek().map(h=>h.id),w).items[e];if(re=!a,b.value=null,D.value="all",P.value="",j.value="",p.value=Pe(R.peek()),pe=`${e}|${ot(p.peek())}`,m.value=e,await ce({first:!0}),!i()||m.peek()!==e||!a)return;await new Promise(h=>setTimeout(h,0));const o=xa({when:a.at?W(a.at):"",file:t?.fileName||""}),v=await we(_(o.text),{title:o.title,confirmText:o.confirmText,cancelText:o.cancelText});!i()||m.peek()!==e||(re=!0,v?$e(e):p.value=he(a.options,R.peek()))}function J(){m.value="",b.value=null,re=!0}async function Ne(e=m.peek()){const t=u.peek().find(a=>a.id===e);if(t&&await we(`Discard the upload of <strong>${_(t.siteTitle||t.fileName)}</strong>? Nothing has been imported from it.`,{title:"Discard upload",confirmText:"Discard",danger:!0}))try{if(await q(`${$}/staged/${e}`,{method:"DELETE"}),$e(e),!i())return;m.peek()===e&&J(),u.value=u.peek().filter(a=>a.id!==e),C(ee)}catch(a){E.toast(`Not discarded: ${a.message||a}`,{type:"error"})}}async function Ue(e){if(!e)return;if(F.value="",!/\.(xml|zip)$/i.test(e.name)){F.value="Upload the .xml file WordPress exports, or a .zip holding it.";return}if(B.wxr&&e.size>B.wxr*1.2&&/\.xml$/i.test(e.name)){F.value=`That file is over ${fe(B.wxr)}.`;return}const t=n.querySelector(".wpx-start .wpx-upload .wpx-bar-fill");se.value=`Uploading ${e.name}\u2026`;try{const a=await wt(`${$}/upload`,e,o=>{t&&(t.style.width=`${Math.round(o*100)}%`),se.value=o<1?`Uploading ${e.name} - ${Math.round(o*100)}%`:`Reading ${e.name}\u2026`});if(!i())return;u.value=[a,...u.peek().filter(o=>o.id!==a.id)],C(ee),await de(a.id)}catch(a){i()&&(F.value=a.message||String(a))}finally{i()&&(se.value="",t&&(t.style.width="0"))}}async function Vt(e){const t=m.peek();if(!e||!t)return;if(!/\.zip$/i.test(e.name)){E.toast("Zip the wp-content/uploads folder and upload the .zip.",{type:"warning"});return}const a=n.querySelector(".wpx-zip-fill");oe.value=`Uploading ${e.name}\u2026`;try{const o=await wt(`${$}/staged/${t}/uploads`,e,v=>{a&&(a.style.width=`${Math.round(v*100)}%`),oe.value=v<1?`Uploading ${e.name} - ${Math.round(v*100)}%`:`Checking ${e.name}\u2026`});if(!i())return;u.value=u.peek().map(v=>v.id===o.id?o:v),m.peek()===t&&ce()}catch(o){i()&&E.toast(o.message||String(o),{type:"error"})}finally{i()&&(oe.value="",a&&(a.style.width="0"))}}async function Jt(){const e=m.peek();try{const t=await q(`${$}/staged/${e}/uploads`,{method:"DELETE"});if(!i())return;u.value=u.peek().map(a=>a.id===t.id?t:a),ce()}catch(t){E.toast(`Not removed: ${t.message||t}`,{type:"error"})}}async function Yt(){const e=m.peek(),t=b.peek();if(!e||!t||!De.peek())return;const o=it(t).filter(h=>h.value&&h.id!=="comments").map(h=>`${h.value} ${h.label.toLowerCase()}`);if(!(!await we(`Import <strong>${_(t.site?.title||"this export")}</strong>: ${_(o.join(", ")||"nothing new")}? Pages edited here since an earlier import are left alone unless you chose Overwrite.`,{title:"Run the import",confirmText:"Run import"})||!i()||m.peek()!==e))try{const h=await q(`${$}/staged/${e}/run`,{method:"POST",body:JSON.stringify({options:he(p.peek(),R.peek())})});if($e(e),!i())return;y.value={...h.job,siteTitle:t.site?.title||""},J(),C(ee),Y()}catch(h){E.toast(`The import did not start: ${h.message||h}`,{type:"error"})}}let Le=null;function Y(){clearTimeout(Le);const e=y.peek();e&&(Le=setTimeout(async()=>{try{const t=await q(`${$}/jobs/${e.id}`);if(!i())return;if(y.value={...t.job,siteTitle:e.siteTitle},t.job.status==="running")return Y();if(y.value=null,await Te().catch(()=>{}),C(ee),C("#/pages"),C("#/media"),C("#/plugins/shopping-cart"),C("#/collections"),!i())return;t.job.status==="done"?(E.toast("The import has finished - here is its report.",{type:"success"}),ue(t.job.reportId)):(E.toast(`The import stopped: ${t.job.error||"an error"}`,{type:"error"}),t.job.reportId&&ue(t.job.reportId))}catch(t){if(!i())return;if(t.status===404){y.value=null,Te().catch(()=>{});return}Y()}},700))}g.add(()=>clearTimeout(Le)),y.peek()&&Y();let H=!1;async function ue(e){if(H||!e)return;H=!0;let t;try{t=await q(`${$}/history/${e}`)}catch(s){H=!1,E.toast(`Could not open the report: ${s.message||s}`,{type:"error"});return}if(!i()){H=!1;return}let a;try{a=E.slideover({title:_(`Report - ${t.run?.siteTitle||"WordPress import"}`),size:"lg",position:"right"})}catch(s){throw H=!1,s}const o=Ua(`
|
|
45
|
+
</div>`,uo=`
|
|
46
|
+
<div class="wpx-row wpx-person" data-key="{{key}}" tabindex="0">
|
|
47
|
+
<span class="wpx-main">
|
|
48
|
+
<strong>{{name}}</strong>
|
|
49
|
+
<small>{{meta}}</small>
|
|
50
|
+
<span class="wpx-reason" data-bind-hidden="!reason">{{reason}}</span>
|
|
51
|
+
<span class="wpx-type-ctl" data-bind-hidden="!choosable">
|
|
52
|
+
<span class="wpx-seg" role="group" aria-label="Account for {{name}}">
|
|
53
|
+
<button type="button" data-user="create" data-bind-class="segCreate">New account</button>
|
|
54
|
+
<button type="button" data-user="skip" data-bind-class="segSkip">No account</button>
|
|
55
|
+
</span>
|
|
56
|
+
</span>
|
|
57
|
+
</span>
|
|
58
|
+
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
59
|
+
<button type="button" class="wpx-kebab" aria-label="Actions for {{name}}" title="Actions">\u22EE</button>
|
|
60
|
+
</div>`,mo=`
|
|
61
|
+
<div class="wpx-row" data-key="{{key}}" tabindex="0">
|
|
62
|
+
<span class="wpx-main"><strong>{{name}}</strong><small>{{meta}}</small><span class="wpx-reason" data-bind-hidden="!reason">{{reason}}</span></span>
|
|
63
|
+
<span class="wpx-chips"><span class="wpx-chip" data-bind-class="pillClass">{{pill}}</span></span>
|
|
64
|
+
<button type="button" class="wpx-kebab" aria-label="Actions for {{name}}" title="Actions">\u22EE</button>
|
|
65
|
+
</div>`,Et='<div class="wpx-tile"><strong>{{value}}</strong><small>{{label}} <span data-bind-hidden="!sub">{{sub}}</span></small></div>',St='<p class="wpx-alert"><span>{{text}}</span></p>',$t="<li>{{text}}</li>",vo='<div class="wpx-fact"><dt>{{label}}</dt><dd>{{value}}</dd></div>',Oe='<button type="button" data-on-click="$root.pickSeg($data)" data-bind-class="cls">{{label}} <b>{{count}}</b></button>',y=Oa(kt);function Lt(d,n,p){return new Promise((f,k)=>{const m=new XMLHttpRequest,P=new FormData;P.append("file",n),m.open("POST",`/api${d}`);const w=Aa();w&&m.setRequestHeader("Authorization",`Bearer ${w}`),m.upload.onprogress=u=>{u.lengthComputable&&p(u.loaded/u.total)},m.onload=()=>{let u=null;try{u=JSON.parse(m.responseText)}catch{}m.status>=200&&m.status<300?f(u):k(new Error(u?.error||`The upload failed (${m.status}).`))},m.onerror=()=>k(new Error("The upload failed - the connection dropped.")),m.send(P),y.add(()=>{m.readyState!==4&&m.abort()})})}const ye=d=>d>=1048576?`${Math.round(d/1048576)} MB`:`${Math.max(1,Math.round(d/1024))} KB`,F=d=>String(d??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");function ho(d){const n=document.createElement("template");return n.innerHTML=d.trim(),n.content.firstElementChild}async function ge(d,n){const p=E.confirm(d,n);let f=null;try{f=[...document.querySelectorAll(".dm-dialog-overlay")].at(-1)??null}catch{}const k=y.add(()=>{if(!f)return;const m=f;f=null;try{m.querySelector(".dm-dialog-cancel")?.click(),m.remove()}catch{}});try{return await p}finally{f=null,k()}}function De(d){navigator.clipboard?.writeText(d).then(()=>E.toast("Copied.",{type:"success"}),()=>E.toast(d,{type:"info",duration:8e3}))}function W(d,n,p,f){const k=E.contextMenu(d,{cursor:"glyph",match:n,inherit:!1,density:"compact",items:p});y.add(()=>k?.destroy?.());const m=w=>{const u=w.target.closest(n);if(!u||!d.contains(u))return;const v=w.target.closest(".wpx-kebab");if(v){H(v);return}f?.(u)},P=w=>{const u=w.target.closest(n);u&&(w.key==="F10"&&w.shiftKey?(w.preventDefault(),H(u)):w.key==="Enter"&&w.target===u&&f&&(w.preventDefault(),w.stopPropagation(),f(u)))};d.addEventListener("click",m),d.addEventListener("keydown",P),y.add(()=>{d.removeEventListener("click",m),d.removeEventListener("keydown",P)})}export const wordpressImportView={templateUrl:"/admin/js/templates/wordpress-import.html",async onMount(d){y.reset();const n=d.get(0).querySelector(".wpx")||d.get(0),p=()=>kt.test(location.hash)&&n.isConnected;let f="";try{f=S.get("auth_user")?.id||""}catch{}const k=Za(f),m=()=>{try{return k?S.get(k):null}catch{return null}},P=e=>{try{k&&S.set(k,e)}catch{}},w=n.querySelector(".wpx-loading");let u;try{u=await dt(w,A(`${$}/status`),ct.rows)}catch(e){if(!n.isConnected)return;w&&(w.hidden=!0);const t=n.querySelector(".wpx-failed");t&&(t.textContent=`Could not load the importer: ${e.message||e}. Reload the page to try again.`,t.hidden=!1);return}if(!p())return;w&&(w.hidden=!0),n.querySelector(".wpx-body").hidden=!1;const v=M.observable(u.staged||[]),U=M.observable(u.history||[]),K=M.observable(u.blog||{available:!1}),He=M.observable(u.shop||{available:!1}),Z=u.limits||{},Ue=u.people?.defaultRole||"",g=M.observable(u.running||null),h=M.observable(""),b=M.observable(null),ne=M.observable(!1),xe=M.observable(!1),ke=M.observable(""),l=M.observable(Ne(K.peek().available)),B=M.observable("all"),O=M.observable(""),V=M.observable(""),re=M.observable(""),J=M.observable(""),le=M.observable(""),ie=M.observable(!1);let pe=!0;const wo=()=>v.peek().find(e=>e.id===h.peek())||null,Me=M.computed(()=>v.value.find(e=>e.id===h.value)||null),Ct=M.computed(()=>h.value?"preview":"start"),D=M.computed(()=>!!K.value.available),Pt=M.computed(()=>!!(b.value?.shop||He.value).available),Be=M.computed(()=>!!h.value&&Ga(l.value,D.value)),Y=e=>M.computed({read:()=>l.value[e]!==!1,write:t=>{l.value={...l.peek(),[e]:!!t}}}),L=e=>{l.value={...l.peek(),...e}},G=e=>{try{return Da(e)}catch{return e}},Rt=M.computed(()=>v.value.map(e=>so(e,G))),qt=M.computed(()=>U.value.map(e=>Ja(e,G))),X=M.computed(()=>(b.value?.items||[]).map(e=>({...e,choice:l.value.choices?.[e.key]}))),At=M.computed(()=>Xa(X.value).map(e=>({...e,cls:O.value===e.id?"is-on":"",seg:"kind"}))),It=M.computed(()=>mt(X.value,wt,ft,O.value)),Nt=M.computed(()=>wt.map(e=>({...e,count:It.value[e.id],cls:B.value===e.id?"is-on":"",seg:"filter"}))),Te=M.computed(()=>{const e=V.value.trim().toLowerCase();return X.value.filter(t=>(!O.value||t.kind===O.value)&&ft(t,B.value)&&(!e||`${t.title} ${t.target} ${t.oldUrl} ${t.postType||""}`.toLowerCase().includes(e)))}),Ot=M.computed(()=>Te.value.slice(0,be).map(e=>{const t=Qa(e);return{...t,pillCls:`${t.pillClass}${e.choice?" is-chosen":""}`}})),Dt=M.computed(()=>Te.value.length>be?`Showing the first ${be} of ${Te.value.length} - search or filter to find the rest.`:""),Ht=M.computed(()=>X.value.length?"Nothing matches.":"This export has nothing to import."),Ut=M.computed(()=>bt(b.value)),Bt=M.computed(()=>(b.value?.notes||[]).map(e=>({text:e}))),_t=M.computed(()=>(b.value?.redirects||[]).slice(0,be).map(e=>({...e,pill:e.action==="skip"?"Skipped":e.action==="update"?"Update":"New",pillClass:e.action==="skip"?"is-muted":"is-ok"}))),zt=M.computed(()=>String((b.value?.redirects||[]).filter(e=>e.action!=="skip").length)),jt=M.computed(()=>b.value?.site?.title||Me.value?.siteTitle||"WordPress export"),Ft=M.computed(()=>{const e=Me.value,t=b.value?.site;return[t?.url||e?.siteUrl,e?.fileName,t?.wxrVersion&&`WXR ${t.wxrVersion}`,e?.at&&`uploaded ${G(e.at)}`].filter(Boolean).join(" \xB7 ")}),Q=M.computed(()=>eo(b.value)),Wt=M.computed(()=>Q.value?.note||""),Kt=M.computed(()=>Q.value?.tone==="warn"?"is-warn":"is-info"),Zt=M.computed(()=>(Q.value?.rows||[]).map(e=>({...e,id:e.label}))),Vt=M.computed(()=>(Q.value?.notes||[]).map(e=>({text:e}))),Jt=M.computed(()=>!!Q.value),Ee=M.computed(()=>_a(b.value)),Se=M.computed(()=>Ya(b.value)),Yt=M.computed(()=>!!(Ee.value.length||Se.value.length)),Gt=M.computed(()=>{const e=Se.value.length;return e?`Not imported: ${e} kind${e===1?"":"s"} of WordPress or plugin housekeeping`:""}),T=M.computed(()=>b.value?.people||null),Xt=M.computed(()=>!!T.value?.rows?.length),Qt=M.computed(()=>(T.value?.rows||[]).map(Wa)),ea=M.computed(()=>!!T.value?.canCreate),ta=M.computed(()=>(T.value?.rows||[]).some(e=>e.choosable)),_e=M.computed(()=>ja(T.value)),aa=M.computed(()=>_e.value.text),oa=M.computed(()=>_e.value.tone==="warn"?"is-warn":"is-info"),sa=M.computed(()=>!!(T.value?.canCreate&&T.value?.mailReady&&T.value?.counts?.create)),na=M.computed(()=>za(T.value)),ra=M.computed({read:()=>l.value.invite===!0,write:e=>{l.value={...l.peek(),invite:!!e}}}),la=M.computed(()=>D.value?`Posts go to ${K.value.basePath||"/blog"}.`:K.value.reason||"No Blog is switched on here."),ce=M.computed(()=>Me.value?.uploads||null),ia=M.computed(()=>{const e=ce.value;return e?`${e.fileName} - ${e.files} file${e.files===1?"":"s"}, ${ye(e.size)}${e.unsafe?`. ${e.unsafe} with unsafe names (like ../) were ignored`:""}.`:`Zip the wp-content/uploads folder and upload it here (up to ${ye(Z.uploads||0)}).`}),pa=M.computed(()=>ce.value?"Replace the zip":"Upload the uploads zip"),ze=M.computed(()=>!!b.value&&!g.value&&!ne.value&&!(l.value.media==="zip"&&!ce.value)),ca=M.computed(()=>g.value?`Importing${g.value.siteTitle?` ${g.value.siteTitle}`:""}\u2026`:""),da=M.computed(()=>ao(g.value)),je=M.computed(()=>to(g.value)),ua=M.observable(ye(Z.wxr||0)),Fe=n.querySelector(".wpx-running .wpx-bar-fill");y.add(M.effect(()=>{Fe&&(Fe.style.width=`${je.value}%`)}));async function $e(){const e=await A(`${$}/status`);return p()?(v.value=e.staged||[],U.value=e.history||[],K.value=e.blog||{available:!1},He.value=e.shop||{available:!1},e.running&&!g.peek()&&(g.value=e.running,te()),e):null}let de=0,Le=null;async function ue({first:e=!1}={}){const t=h.peek();if(!t)return;const a=++de;ke.value="";const o=A(`${$}/staged/${t}/preview`,{method:"POST",body:JSON.stringify({options:fe(l.peek(),D.peek())})});try{let i;if(e?(ne.value=!0,i=await dt(n.querySelector(".wpx-plan-loading"),o,ct.table)):(xe.value=!0,i=await o),a!==de||!p()||h.peek()!==t)return;b.value=i.plan}catch(i){if(a!==de||!p())return;if(i.status===404){E.toast("That upload has gone - upload the export again.",{type:"warning"}),ee(),$e().catch(()=>{});return}ke.value=`Could not read the export: ${i.message||i}`}finally{a===de&&(ne.value=!1,xe.value=!1)}}let me="";y.add(M.effect(()=>{const e=`${h.value}|${ht(l.value)}`;if(e===me)return;const t=me.split("|")[0];me=e,!(!h.value||t!==h.value)&&(clearTimeout(Le),Le=setTimeout(()=>ue(),250))})),y.add(()=>clearTimeout(Le)),y.add(M.effect(()=>{const e=h.value,t=l.value,a=Be.value;if(!e||!pe||!k)return;const o=m();P(xt(o,f,e,a?{options:fe(t,!0),at:new Date().toISOString(),was:e}:null))}));const Ce=e=>{k&&P(xt(m(),f,e,null))};async function ve(e){if(!v.peek().some(c=>c.id===e))return;const t=v.peek().find(c=>c.id===e),a=vt(m(),v.peek().map(c=>c.id),f).items[e];if(pe=!a,b.value=null,B.value="all",O.value="",V.value="",l.value=Ne(D.peek()),me=`${e}|${ht(l.peek())}`,h.value=e,await ue({first:!0}),!p()||h.peek()!==e||!a)return;await new Promise(c=>setTimeout(c,0));const o=Va({when:a.at?G(a.at):"",file:t?.fileName||""}),i=await ge(F(o.text),{title:o.title,confirmText:o.confirmText,cancelText:o.cancelText});!p()||h.peek()!==e||(pe=!0,i?Ce(e):l.value=fe(a.options,D.peek()))}function ee(){h.value="",b.value=null,pe=!0}async function We(e=h.peek()){const t=v.peek().find(a=>a.id===e);if(t&&await ge(`Discard the upload of <strong>${F(t.siteTitle||t.fileName)}</strong>? Nothing has been imported from it.`,{title:"Discard upload",confirmText:"Discard",danger:!0}))try{if(await A(`${$}/staged/${e}`,{method:"DELETE"}),Ce(e),!p())return;h.peek()===e&&ee(),v.value=v.peek().filter(a=>a.id!==e),N(se)}catch(a){E.toast(`Not discarded: ${a.message||a}`,{type:"error"})}}async function Ke(e){if(!e)return;if(J.value="",!/\.(xml|zip)$/i.test(e.name)){J.value="Upload the .xml file WordPress exports, or a .zip holding it.";return}if(Z.wxr&&e.size>Z.wxr*1.2&&/\.xml$/i.test(e.name)){J.value=`That file is over ${ye(Z.wxr)}.`;return}const t=n.querySelector(".wpx-start .wpx-upload .wpx-bar-fill");re.value=`Uploading ${e.name}\u2026`;try{const a=await Lt(`${$}/upload`,e,o=>{t&&(t.style.width=`${Math.round(o*100)}%`),re.value=o<1?`Uploading ${e.name} - ${Math.round(o*100)}%`:`Reading ${e.name}\u2026`});if(!p())return;v.value=[a,...v.peek().filter(o=>o.id!==a.id)],N(se),await ve(a.id)}catch(a){p()&&(J.value=a.message||String(a))}finally{p()&&(re.value="",t&&(t.style.width="0"))}}async function ma(e){const t=h.peek();if(!e||!t)return;if(!/\.zip$/i.test(e.name)){E.toast("Zip the wp-content/uploads folder and upload the .zip.",{type:"warning"});return}const a=n.querySelector(".wpx-zip-fill");le.value=`Uploading ${e.name}\u2026`;try{const o=await Lt(`${$}/staged/${t}/uploads`,e,i=>{a&&(a.style.width=`${Math.round(i*100)}%`),le.value=i<1?`Uploading ${e.name} - ${Math.round(i*100)}%`:`Checking ${e.name}\u2026`});if(!p())return;v.value=v.peek().map(i=>i.id===o.id?o:i),h.peek()===t&&ue()}catch(o){p()&&E.toast(o.message||String(o),{type:"error"})}finally{p()&&(le.value="",a&&(a.style.width="0"))}}async function va(){const e=h.peek();try{const t=await A(`${$}/staged/${e}/uploads`,{method:"DELETE"});if(!p())return;v.value=v.peek().map(a=>a.id===t.id?t:a),ue()}catch(t){E.toast(`Not removed: ${t.message||t}`,{type:"error"})}}async function ha(){const e=h.peek(),t=b.peek();if(!e||!t||!ze.peek())return;const o=bt(t).filter(c=>c.value&&c.id!=="comments").map(c=>`${c.value} ${c.label.toLowerCase()}`);if(!(!await ge(`Import <strong>${F(t.site?.title||"this export")}</strong>: ${F(o.join(", ")||"nothing new")}? Pages edited here since an earlier import are left alone unless you chose Overwrite.`,{title:"Run the import",confirmText:"Run import"})||!p()||h.peek()!==e))try{const c=await A(`${$}/staged/${e}/run`,{method:"POST",body:JSON.stringify({options:fe(l.peek(),D.peek())})});if(Ce(e),!p())return;g.value={...c.job,siteTitle:t.site?.title||""},ee(),N(se),te()}catch(c){E.toast(`The import did not start: ${c.message||c}`,{type:"error"})}}let Pe=null;function te(){clearTimeout(Pe);const e=g.peek();e&&(Pe=setTimeout(async()=>{try{const t=await A(`${$}/jobs/${e.id}`);if(!p())return;if(g.value={...t.job,siteTitle:e.siteTitle},t.job.status==="running")return te();if(g.value=null,await $e().catch(()=>{}),N(se),N("#/pages"),N("#/media"),N("#/plugins/shopping-cart"),N("#/collections"),!p())return;t.job.status==="done"?(E.toast("The import has finished - here is its report.",{type:"success"}),he(t.job.reportId)):(E.toast(`The import stopped: ${t.job.error||"an error"}`,{type:"error"}),t.job.reportId&&he(t.job.reportId))}catch(t){if(!p())return;if(t.status===404){g.value=null,$e().catch(()=>{});return}te()}},700))}y.add(()=>clearTimeout(Pe)),g.peek()&&te();let _=!1;async function he(e){if(_||!e)return;_=!0;let t;try{t=await A(`${$}/history/${e}`)}catch(s){_=!1,E.toast(`Could not open the report: ${s.message||s}`,{type:"error"});return}if(!p()){_=!1;return}let a;try{a=E.slideover({title:F(`Report - ${t.run?.siteTitle||"WordPress import"}`),size:"lg",position:"right"})}catch(s){throw _=!1,s}const o=ho(`
|
|
46
66
|
<div class="wpx wpx-report">
|
|
47
67
|
<p class="wpx-note" data-bind-text="meta.value"></p>
|
|
48
68
|
<div class="wpx-tiles" data-each="tiles.value key=id"></div>
|
|
@@ -51,6 +71,9 @@ import{apiRequest as q,getToken as ua}from"../api.js";import{addBannerAction as
|
|
|
51
71
|
<span data-help-title="The report" data-help="Every item of the export and what happened to it. Kept as HTML: the page had tables, columns or other layout Markdown cannot say - it shows as it did, and edits as HTML. Needs rebuilding: shortcodes and page builders this site has no equivalent for. Right-click (or \u22EE, or Shift+F10) an item to open it."></span></div>
|
|
52
72
|
<p class="wpx-note" data-bind-hidden="rows.value.length">Nothing matches.</p>
|
|
53
73
|
<div class="wpx-list wpx-report-items" data-each="rows.value key=key"></div>
|
|
74
|
+
<div class="wpx-card-title" data-bind-hidden="!people.value.length">Users
|
|
75
|
+
<span data-help="What each WordPress author came to: an account made (with no password until one is set), matched to a user here by email (not changed), or no account (what they wrote is credited to whoever ran the import). Right-click (or \u22EE) one to open their account."></span></div>
|
|
76
|
+
<div class="wpx-list wpx-report-people" data-each="people.value key=key"></div>
|
|
54
77
|
<div class="wpx-card-title" data-bind-hidden="!redirects.value.length">Redirects</div>
|
|
55
78
|
<div class="wpx-list wpx-report-redirects" data-each="redirects.value key=from"></div>
|
|
56
|
-
</div>`);o.querySelector(".wpx-tiles").innerHTML=ht,o.querySelector(".wpx-note-list").innerHTML=vt,o.querySelector(".wpx-seg").innerHTML=Re,o.querySelector(".wpx-report-items").innerHTML=ut,o.querySelector(".wpx-report-redirects").innerHTML=mt;const v=M.observable(t.run?.summary?.failed?"failed":"all"),h=t.items||[],Ye=at(h,lt,ct),Q=t.run?.summary||{},qe=s=>Object.values(Q.kinds||{}).reduce((r,T)=>r+(T[s]||0),0),aa={meta:M.observable([W(t.run?.at),t.run?.by,t.run?.file,t.run?.durationMs?`${Math.max(1,Math.round(t.run.durationMs/1e3))} s`:""].filter(Boolean).join(" \xB7 ")),tiles:M.observable([{id:"made",label:"Made",value:qe("created"),sub:""},{id:"updated",label:"Updated",value:qe("updated"),sub:""},{id:"kept",label:"Left as is",value:qe("kept"),sub:""},{id:"redirects",label:"Redirects",value:(Q.redirects?.created||0)+(Q.redirects?.updated||0),sub:""},{id:"comments",label:"Comments",value:Q.comments||0,sub:""},{id:"failed",label:"Failed",value:Q.failed||0,sub:""}]),notes:M.observable((t.notes||[]).map(s=>({text:s}))),filters:M.computed(()=>lt.filter(s=>s.id==="all"||Ye[s.id]).map(s=>({...s,count:Ye[s.id],cls:v.value===s.id?"is-on":""}))),rows:M.computed(()=>h.filter(s=>ct(s,v.value)).slice(0,1e3).map(s=>{const r=Ca(s);return{...r,pillCls:r.pillClass}})),redirects:M.observable((t.redirects||[]).filter(s=>s.result!=="skipped").slice(0,1e3).map(s=>({...s,reason:s.error||"",pill:s.result==="failed"?"Failed":s.result==="updated"?"Updated":"Added",pillClass:s.result==="failed"?"is-bad":"is-ok"})))};a.element.appendChild(o);const sa=M.applyBindings(aa,o,{methods:{pickSeg:s=>{v.value=s.id}}}),oa=Qe(o),Ge=new Map(h.map(s=>[s.key,s])),na=o.querySelector(".wpx-report-items"),ra=s=>{const r=Ge.get(s.dataset.key);if(!r)return[];const T=typeof r.target=="string"&&r.target.startsWith("/")?r.target:"",k=[{header:r.title}];if(T&&r.result!=="failed"&&r.result!=="skipped"&&k.push({label:"Open on the site",icon:"external-link",action:()=>window.open(T,"_blank","noopener")}),T&&(r.kind==="page"||r.kind==="custom"&&!r.collection)&&(r.result==="created"||r.result==="updated"||r.result==="kept")&&k.push({label:"Edit the page",icon:"edit",action:()=>{a.close(),location.hash=`#/pages/edit${T}`}}),(r.kind==="collection"||r.kind==="custom")&&r.result!=="failed"&&r.result!=="skipped"&&/^[a-z0-9-]{1,80}$/.test(r.kind==="collection"?r.target:r.collection||"")){const da=r.kind==="collection"?r.target:r.collection;k.push({label:"Open the collection",icon:"database",action:()=>{a.close(),location.hash=`#/collections/${da}/entries`}})}return r.kind==="product"&&r.entryId&&/^[\w-]{1,64}$/.test(r.entryId)&&k.push({label:"Edit in the Shop",icon:"shopping-bag",action:()=>{a.close(),location.hash=`#/plugins/shopping-cart/products/${encodeURIComponent(r.entryId)}`}}),/^https?:\/\//i.test(r.oldUrl)&&k.push({label:"Open the old address",icon:"link",action:()=>window.open(r.oldUrl,"_blank","noopener,noreferrer")}),T&&k.push({label:"Copy the new address",icon:"copy",action:()=>bt(new URL(T,location.origin).href)}),k},ia=E.contextMenu(na,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:ra}),la=o.querySelector(".wpx-report-redirects"),ca=E.contextMenu(la,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:s=>[{header:s.dataset.from},...s.dataset.from.includes("*")?[]:[{label:"Try it on the site",icon:"external-link",action:()=>window.open(s.dataset.from,"_blank","noopener")}],{label:"Open SEO \u203A Redirects",icon:"corner-up-right",action:()=>{a.close(),location.hash="#/seo/redirects"}}]}),Ce=s=>{const r=s.target.closest(".wpx-kebab");if(r){U(r);return}const T=s.target.closest(".wpx-report-items .wpx-row");if(!T)return;const k=Ge.get(T.dataset.key);k?.target?.startsWith("/")&&k.result!=="failed"&&k.result!=="skipped"&&window.open(k.target,"_blank","noopener")},Xe=s=>{const r=s.target.closest(".wpx-row");r&&(s.key==="F10"&&s.shiftKey?(s.preventDefault(),U(r)):s.key==="Enter"&&s.target===r&&(s.preventDefault(),s.stopPropagation(),Ce({target:r})))};o.addEventListener("click",Ce),o.addEventListener("keydown",Xe);const pa=g.add(()=>a.close());ha(a,()=>{H=!1,sa.dispose(),oa(),ia?.destroy?.(),ca?.destroy?.(),o.removeEventListener("click",Ce),o.removeEventListener("keydown",Xe),pa()}),a.open(),I.scan(o)}async function Gt(e){const t=A.peek().find(a=>a.id===e);if(t&&await we(`Remove the import of <strong>${_(t.siteTitle||t.source)}</strong> from this list? Everything it imported stays on the site.`,{title:"Remove from the history",confirmText:"Remove"}))try{if(await q(`${$}/history/${e}`,{method:"DELETE"}),!i())return;A.value=A.peek().filter(a=>a.id!==e),C(ee)}catch(a){E.toast(`Not removed: ${a.message||a}`,{type:"error"})}}n.querySelector(".wpx-staged").innerHTML=Da,n.querySelector(".wpx-items").innerHTML=ut,n.querySelector(".wpx-redirects").innerHTML=mt,n.querySelector(".wpx-history").innerHTML=Oa,n.querySelector(".wpx-tiles").innerHTML=ht,n.querySelector(".wpx-note-list").innerHTML=vt,n.querySelector(".wpx-kinds").innerHTML=Re,n.querySelector(".wpx-filters").innerHTML=Re,n.querySelector(".wpx-facts").innerHTML=Na,n.querySelector(".wpx-product-notes").innerHTML=ft,n.querySelector(".wpx-types").innerHTML=Ha,n.querySelector(".wpx-internal").innerHTML=ft;const Xt={mode:yt,job:y,jobTitle:Kt,jobText:Wt,jobPct:Oe,staged:u,stagedRows:xt,historyRows:kt,plan:b,planLoading:ae,planError:ye,refreshing:be,opt:p,blogAvailable:R,blogNote:Bt,dirty:Ie,canRun:De,siteTitle:At,siteMeta:It,tiles:qt,notes:Ct,kinds:Mt,filters:Et,rows:$t,moreText:Lt,emptyText:St,redirectRows:Pt,redirectCount:Rt,query:j,uploadText:se,uploadError:F,dropping:ne,wxrLimit:Zt,zipInfo:ie,zipText:jt,zipButton:Ft,zipUploadText:oe,shopAvailable:gt,hasProducts:Ut,productNote:Dt,productNoteCls:Ot,productFacts:Ht,productNotes:Nt,typeRows:ke,internalRows:Me,hasCustom:_t,internalSummary:zt,optComments:K("comments"),optMenus:K("menus"),optRedirects:K("redirects"),optDrafts:K("drafts"),optProducts:K("products")},Qt=M.applyBindings(Xt,n,{methods:{back:()=>J(),discard:()=>Ne(),run:()=>Yt(),resetChoices:()=>{p.value=Pe(R.peek())},postsBlog:()=>O({posts:"blog"}),postsPages:()=>O({posts:"pages"}),postsSkip:()=>O({posts:"skip"}),mediaDownload:()=>O({media:"download"}),mediaZip:()=>O({media:"zip"}),mediaSkip:()=>O({media:"skip"}),removeZip:()=>Jt(),pickSeg:e=>{e.seg==="kind"?P.value=e.id:D.value=e.id},showProducts:()=>{P.value="product",D.value="all",j.value="",n.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})}}});g.add(()=>Qt.dispose()),g.add(Qe(n,{position:"bottom"}));const G=n.querySelector(".wpx-file"),_e=()=>{const e=G.files?.[0];G.value="",Ue(e)};G.addEventListener("change",_e);const N=n.querySelector(".wpx-drop"),ze=e=>{e.preventDefault(),ne.value=!0},Be=()=>{ne.value=!1},je=e=>{e.preventDefault(),ne.value=!1,Ue(e.dataTransfer?.files?.[0])};N.addEventListener("dragover",ze),N.addEventListener("dragleave",Be),N.addEventListener("drop",je);const me=n.querySelector(".wpx-zip-file"),Fe=()=>{const e=me.files?.[0];me.value="",Vt(e)};me.addEventListener("change",Fe),g.add(()=>{G.removeEventListener("change",_e),N.removeEventListener("dragover",ze),N.removeEventListener("dragleave",Be),N.removeEventListener("drop",je),me.removeEventListener("change",Fe)}),te(n.querySelector(".wpx-staged"),".wpx-row",e=>[{header:u.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Upload"},{label:"Preview the import",icon:"eye",action:()=>de(e.dataset.id)},{label:"Discard the upload",icon:"trash-2",action:()=>Ne(e.dataset.id)}],e=>de(e.dataset.id));const ea=(e,t)=>{p.value={...p.peek(),choices:wa(p.peek().choices,e,t)}};te(n.querySelector(".wpx-items"),".wpx-row",e=>{const t=Z.peek().find(o=>o.key===e.dataset.key);if(!t)return[];const a=[{header:t.title}];for(const o of ba(t,t.choice))a.push({label:o.label,icon:o.icon,action:()=>ea(t.key,o.id)});return t.oldUrl&&/^https?:\/\//i.test(t.oldUrl)&&a.push({label:"Open the old address",icon:"link",action:()=>window.open(t.oldUrl,"_blank","noopener,noreferrer")}),t.target?.startsWith("/")&&(t.action==="update"||t.action==="keep")&&a.push({label:"Open it on this site",icon:"external-link",action:()=>window.open(t.target,"_blank","noopener")}),a.length===1&&a.push({label:"Nothing to change here",icon:"info",disabled:!0,action:()=>{}}),a},e=>U(e.querySelector(".wpx-kebab")||e));const Ke=(e,t)=>{p.value=Ia(p.peek(),e,t)},We=(e,t)=>{p.value=Aa(p.peek(),e,t)},ta=e=>{P.value="",D.value="all",j.value=e,n.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})},X=n.querySelector(".wpx-types"),Ze=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-as]"),o=e.target.closest(".wpx-type-row");a&&o&&Ke(o.dataset.type,a.dataset.as)},Ve=e=>{const t=e.target.closest("input[data-list-page]"),a=e.target.closest(".wpx-type-row");t&&a&&We(a.dataset.type,t.checked)};X.addEventListener("click",Ze,!0),X.addEventListener("change",Ve),g.add(()=>{X.removeEventListener("click",Ze,!0),X.removeEventListener("change",Ve)}),te(X,".wpx-type-row",e=>{const t=ke.peek().find(a=>a.type===e.dataset.type);return t?[{header:`${t.label} ("${t.type}")`},...Ra(t).map(a=>({label:a.label,icon:a.icon,action:()=>{a.id==="show"?ta(t.type):a.id==="list"||a.id==="nolist"?We(t.type,a.id==="list"):Ke(t.type,a.id)}}))]:[]},e=>U(e.querySelector(".wpx-kebab")||e)),te(n.querySelector(".wpx-redirects"),".wpx-row",e=>[{header:e.dataset.from},{label:"Copy the old address",icon:"copy",action:()=>bt(e.dataset.from)}],null),te(n.querySelector(".wpx-history"),".wpx-row",e=>[{header:A.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Import"},{label:"Open the report",icon:"file-text",action:()=>ue(e.dataset.id)},{label:"Remove from the history",icon:"trash-2",action:()=>Gt(e.dataset.id)}],e=>ue(e.dataset.id)),ma(l,{id:"wpx-upload",icon:"upload",title:"Upload an export",onClick:()=>{m.peek()&&J(),setTimeout(()=>G.click(),0)}}),I.scan(n);const Se=st(d(),u.peek().map(e=>e.id),w);Se.pruned&&x&&L({owner:w,items:Se.items});const Je=Object.entries(Se.items).sort((e,t)=>String(t[1].at).localeCompare(String(e[1].at)))[0];Je&&!y.peek()&&await de(Je[0])}};
|
|
79
|
+
</div>`);o.querySelector(".wpx-tiles").innerHTML=Et,o.querySelector(".wpx-note-list").innerHTML=St,o.querySelector(".wpx-seg").innerHTML=Oe,o.querySelector(".wpx-report-items").innerHTML=Mt,o.querySelector(".wpx-report-redirects").innerHTML=Tt,o.querySelector(".wpx-report-people").innerHTML=mo;const i=M.observable(t.run?.summary?.failed?"failed":"all"),c=t.items||[],rt=mt(c,yt,gt),q=t.run?.summary||{},Ae=s=>Object.values(q.kinds||{}).reduce((r,x)=>r+(x[s]||0),0),xa={meta:M.observable([G(t.run?.at),t.run?.by,t.run?.file,t.run?.durationMs?`${Math.max(1,Math.round(t.run.durationMs/1e3))} s`:""].filter(Boolean).join(" \xB7 ")),tiles:M.observable([{id:"made",label:"Made",value:Ae("created"),sub:""},{id:"updated",label:"Updated",value:Ae("updated"),sub:""},{id:"kept",label:"Left as is",value:Ae("kept"),sub:""},{id:"redirects",label:"Redirects",value:(q.redirects?.created||0)+(q.redirects?.updated||0),sub:""},...q.people?[{id:"people",label:"Accounts made",value:q.people.created||0,sub:q.people.invited?`${q.people.invited} emailed`:""}]:[],{id:"comments",label:"Comments",value:q.comments||0,sub:""},{id:"failed",label:"Failed",value:q.failed||0,sub:""}]),notes:M.observable((t.notes||[]).map(s=>({text:s}))),people:M.observable((t.people||[]).map(Ka)),filters:M.computed(()=>yt.filter(s=>s.id==="all"||rt[s.id]).map(s=>({...s,count:rt[s.id],cls:i.value===s.id?"is-on":""}))),rows:M.computed(()=>c.filter(s=>gt(s,i.value)).slice(0,1e3).map(s=>{const r=oo(s);return{...r,pillCls:r.pillClass}})),redirects:M.observable((t.redirects||[]).filter(s=>s.result!=="skipped").slice(0,1e3).map(s=>({...s,reason:s.error||"",pill:s.result==="failed"?"Failed":s.result==="updated"?"Updated":"Added",pillClass:s.result==="failed"?"is-bad":"is-ok"})))};a.element.appendChild(o);const ka=M.applyBindings(xa,o,{methods:{pickSeg:s=>{i.value=s.id}}}),Ma=pt(o),lt=new Map(c.map(s=>[s.key,s])),Ta=o.querySelector(".wpx-report-items"),Ea=s=>{const r=lt.get(s.dataset.key);if(!r)return[];const x=typeof r.target=="string"&&r.target.startsWith("/")?r.target:"",C=[{header:r.title}];if(x&&r.result!=="failed"&&r.result!=="skipped"&&C.push({label:"Open on the site",icon:"external-link",action:()=>window.open(x,"_blank","noopener")}),x&&(r.kind==="page"||r.kind==="custom"&&!r.collection)&&(r.result==="created"||r.result==="updated"||r.result==="kept")&&C.push({label:"Edit the page",icon:"edit",action:()=>{a.close(),location.hash=`#/pages/edit${x}`}}),(r.kind==="collection"||r.kind==="custom")&&r.result!=="failed"&&r.result!=="skipped"&&/^[a-z0-9-]{1,80}$/.test(r.kind==="collection"?r.target:r.collection||"")){const j=r.kind==="collection"?r.target:r.collection;C.push({label:"Open the collection",icon:"database",action:()=>{a.close(),location.hash=`#/collections/${j}/entries`}})}return r.kind==="product"&&r.entryId&&/^[\w-]{1,64}$/.test(r.entryId)&&C.push({label:"Edit in the Shop",icon:"shopping-bag",action:()=>{a.close(),location.hash=`#/plugins/shopping-cart/products/${encodeURIComponent(r.entryId)}`}}),/^https?:\/\//i.test(r.oldUrl)&&C.push({label:"Open the old address",icon:"link",action:()=>window.open(r.oldUrl,"_blank","noopener,noreferrer")}),x&&C.push({label:"Copy the new address",icon:"copy",action:()=>De(new URL(x,location.origin).href)}),C},Sa=E.contextMenu(Ta,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:Ea}),$a=o.querySelector(".wpx-report-people"),La=new Map((t.people||[]).map(s=>[s.key,s])),Ca=E.contextMenu($a,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:s=>{const r=La.get(s.dataset.key);if(!r)return[];const x=/^[0-9a-f-]{36}$/i.test(r.userId||"")?r.userId:"";return[{header:r.name},...x&&r.result!=="skipped"?[{label:"Open their account",icon:"user",action:()=>{a.close(),location.hash=`#/users/edit/${x}`}}]:[],{label:"Open Users",icon:"users",action:()=>{a.close(),location.hash="#/users"}}]}}),Pa=o.querySelector(".wpx-report-redirects"),Ra=E.contextMenu(Pa,{cursor:"glyph",match:".wpx-row",inherit:!1,density:"compact",items:s=>[{header:s.dataset.from},...s.dataset.from.includes("*")?[]:[{label:"Try it on the site",icon:"external-link",action:()=>window.open(s.dataset.from,"_blank","noopener")}],{label:"Open SEO \u203A Redirects",icon:"corner-up-right",action:()=>{a.close(),location.hash="#/seo/redirects"}}]}),Ie=s=>{const r=s.target.closest(".wpx-kebab");if(r){H(r);return}const x=s.target.closest(".wpx-report-people .wpx-row");if(x){H(x.querySelector(".wpx-kebab")||x);return}const C=s.target.closest(".wpx-report-items .wpx-row");if(!C)return;const j=lt.get(C.dataset.key);j?.target?.startsWith("/")&&j.result!=="failed"&&j.result!=="skipped"&&window.open(j.target,"_blank","noopener")},it=s=>{const r=s.target.closest(".wpx-row");r&&(s.key==="F10"&&s.shiftKey?(s.preventDefault(),H(r)):s.key==="Enter"&&s.target===r&&(s.preventDefault(),s.stopPropagation(),Ie({target:r})))};o.addEventListener("click",Ie),o.addEventListener("keydown",it);const qa=y.add(()=>a.close());Na(a,()=>{_=!1,ka.dispose(),Ma(),Sa?.destroy?.(),Ra?.destroy?.(),Ca?.destroy?.(),o.removeEventListener("click",Ie),o.removeEventListener("keydown",it),qa()}),a.open(),I.scan(o)}async function wa(e){const t=U.peek().find(a=>a.id===e);if(t&&await ge(`Remove the import of <strong>${F(t.siteTitle||t.source)}</strong> from this list? Everything it imported stays on the site.`,{title:"Remove from the history",confirmText:"Remove"}))try{if(await A(`${$}/history/${e}`,{method:"DELETE"}),!p())return;U.value=U.peek().filter(a=>a.id!==e),N(se)}catch(a){E.toast(`Not removed: ${a.message||a}`,{type:"error"})}}n.querySelector(".wpx-staged").innerHTML=io,n.querySelector(".wpx-items").innerHTML=Mt,n.querySelector(".wpx-redirects").innerHTML=Tt,n.querySelector(".wpx-history").innerHTML=po,n.querySelector(".wpx-tiles").innerHTML=Et,n.querySelector(".wpx-note-list").innerHTML=St,n.querySelector(".wpx-kinds").innerHTML=Oe,n.querySelector(".wpx-filters").innerHTML=Oe,n.querySelector(".wpx-facts").innerHTML=vo,n.querySelector(".wpx-product-notes").innerHTML=$t,n.querySelector(".wpx-types").innerHTML=co,n.querySelector(".wpx-internal").innerHTML=$t,n.querySelector(".wpx-people-list").innerHTML=uo;const fa={mode:Ct,job:g,jobTitle:ca,jobText:da,jobPct:je,staged:v,stagedRows:Rt,historyRows:qt,plan:b,planLoading:ne,planError:ke,refreshing:xe,opt:l,blogAvailable:D,blogNote:la,dirty:Be,canRun:ze,siteTitle:jt,siteMeta:Ft,tiles:Ut,notes:Bt,kinds:At,filters:Nt,rows:Ot,moreText:Dt,emptyText:Ht,redirectRows:_t,redirectCount:zt,query:V,uploadText:re,uploadError:J,dropping:ie,wxrLimit:ua,zipInfo:ce,zipText:ia,zipButton:pa,zipUploadText:le,hasPeople:Xt,peopleRows:Qt,peopleCanCreate:ea,peopleChoosable:ta,peopleNote:aa,peopleNoteCls:oa,inviteAvailable:sa,inviteText:na,optInvite:ra,shopAvailable:Pt,hasProducts:Jt,productNote:Wt,productNoteCls:Kt,productFacts:Zt,productNotes:Vt,typeRows:Ee,internalRows:Se,hasCustom:Yt,internalSummary:Gt,optComments:Y("comments"),optMenus:Y("menus"),optRedirects:Y("redirects"),optDrafts:Y("drafts"),optProducts:Y("products")},ba=M.applyBindings(fa,n,{methods:{back:()=>ee(),discard:()=>We(),run:()=>ha(),resetChoices:()=>{l.value=Ne(D.peek())},postsBlog:()=>L({posts:"blog"}),postsPages:()=>L({posts:"pages"}),postsSkip:()=>L({posts:"skip"}),mediaDownload:()=>L({media:"download"}),mediaZip:()=>L({media:"zip"}),mediaSkip:()=>L({media:"skip"}),removeZip:()=>va(),peopleAll:()=>L({users:ut(T.peek(),"create")}),peopleNone:()=>L({users:ut(T.peek(),"skip")}),pickSeg:e=>{e.seg==="kind"?O.value=e.id:B.value=e.id},showProducts:()=>{O.value="product",B.value="all",V.value="",n.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})}}});y.add(()=>ba.dispose()),y.add(pt(n,{position:"bottom"}));const ae=n.querySelector(".wpx-file"),Ze=()=>{const e=ae.files?.[0];ae.value="",Ke(e)};ae.addEventListener("change",Ze);const z=n.querySelector(".wpx-drop"),Ve=e=>{e.preventDefault(),ie.value=!0},Je=()=>{ie.value=!1},Ye=e=>{e.preventDefault(),ie.value=!1,Ke(e.dataTransfer?.files?.[0])};z.addEventListener("dragover",Ve),z.addEventListener("dragleave",Je),z.addEventListener("drop",Ye);const we=n.querySelector(".wpx-zip-file"),Ge=()=>{const e=we.files?.[0];we.value="",ma(e)};we.addEventListener("change",Ge),y.add(()=>{ae.removeEventListener("change",Ze),z.removeEventListener("dragover",Ve),z.removeEventListener("dragleave",Je),z.removeEventListener("drop",Ye),we.removeEventListener("change",Ge)}),W(n.querySelector(".wpx-staged"),".wpx-row",e=>[{header:v.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Upload"},{label:"Preview the import",icon:"eye",action:()=>ve(e.dataset.id)},{label:"Discard the upload",icon:"trash-2",action:()=>We(e.dataset.id)}],e=>ve(e.dataset.id));const ya=(e,t)=>{l.value={...l.peek(),choices:Ha(l.peek().choices,e,t)}};W(n.querySelector(".wpx-items"),".wpx-row",e=>{const t=X.peek().find(o=>o.key===e.dataset.key);if(!t)return[];const a=[{header:t.title}];for(const o of Ba(t,t.choice))a.push({label:o.label,icon:o.icon,action:()=>ya(t.key,o.id)});return t.oldUrl&&/^https?:\/\//i.test(t.oldUrl)&&a.push({label:"Open the old address",icon:"link",action:()=>window.open(t.oldUrl,"_blank","noopener,noreferrer")}),t.target?.startsWith("/")&&(t.action==="update"||t.action==="keep")&&a.push({label:"Open it on this site",icon:"external-link",action:()=>window.open(t.target,"_blank","noopener")}),a.length===1&&a.push({label:"Nothing to change here",icon:"info",disabled:!0,action:()=>{}}),a},e=>H(e.querySelector(".wpx-kebab")||e));const Xe=(e,t)=>{l.value=lo(l.peek(),e,t)},Qe=(e,t)=>{l.value=ro(l.peek(),e,t)},ga=e=>{O.value="",B.value="all",V.value=e,n.querySelector(".wpx-items")?.closest(".wpx-card")?.scrollIntoView({behavior:"smooth",block:"start"})},oe=n.querySelector(".wpx-types"),et=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-as]"),o=e.target.closest(".wpx-type-row");a&&o&&Xe(o.dataset.type,a.dataset.as)},tt=e=>{const t=e.target.closest("input[data-list-page]"),a=e.target.closest(".wpx-type-row");t&&a&&Qe(a.dataset.type,t.checked)};oe.addEventListener("click",et,!0),oe.addEventListener("change",tt),y.add(()=>{oe.removeEventListener("click",et,!0),oe.removeEventListener("change",tt)}),W(oe,".wpx-type-row",e=>{const t=Ee.peek().find(a=>a.type===e.dataset.type);return t?[{header:`${t.label} ("${t.type}")`},...no(t).map(a=>({label:a.label,icon:a.icon,action:()=>{a.id==="show"?ga(t.type):a.id==="list"||a.id==="nolist"?Qe(t.type,a.id==="list"):Xe(t.type,a.id)}}))]:[]},e=>H(e.querySelector(".wpx-kebab")||e));const at=(e,t)=>{const a=T.peek()?.rows?.find(o=>o.key===e);a&&L({users:Ua(l.peek().users,a,t)})},Re=n.querySelector(".wpx-people-list"),ot=e=>{if(!e.target.closest(".wpx-type-ctl"))return;e.stopPropagation();const a=e.target.closest("button[data-user]"),o=e.target.closest(".wpx-person");a&&o&&at(o.dataset.key,a.dataset.user)};Re.addEventListener("click",ot,!0),y.add(()=>Re.removeEventListener("click",ot,!0)),W(Re,".wpx-person",e=>{const t=T.peek()?.rows?.find(a=>a.key===e.dataset.key);return t?[{header:t.name},...Fa(t).map(a=>({label:a.label,icon:a.icon,disabled:!!a.disabled,action:()=>{a.disabled||(a.id==="copy"?De(t.email):at(t.key,a.id))}}))]:[]},e=>H(e.querySelector(".wpx-kebab")||e));const R=n.querySelector(".wpx-role");y.add(M.effect(()=>{const e=T.value;if(!R)return;const t=e?.roles||[],a=e?.role||"",o=`${t.map(i=>i.name).join(",")}|${a}`;R.dataset.sig!==o&&(R.dataset.sig=o,R.replaceChildren(...t.map(i=>{const c=document.createElement("option");return c.value=i.name,c.textContent=i.name===Ue?`${i.label} (default)`:i.label,c})),R.value=a)}));const st=()=>L({userRole:R.value===Ue?"":R.value});R?.addEventListener("change",st),y.add(()=>R?.removeEventListener("change",st)),W(n.querySelector(".wpx-redirects"),".wpx-row",e=>[{header:e.dataset.from},{label:"Copy the old address",icon:"copy",action:()=>De(e.dataset.from)}],null),W(n.querySelector(".wpx-history"),".wpx-row",e=>[{header:U.peek().find(t=>t.id===e.dataset.id)?.siteTitle||"Import"},{label:"Open the report",icon:"file-text",action:()=>he(e.dataset.id)},{label:"Remove from the history",icon:"trash-2",action:()=>wa(e.dataset.id)}],e=>he(e.dataset.id)),Ia(d,{id:"wpx-upload",icon:"upload",title:"Upload an export",onClick:()=>{h.peek()&&ee(),setTimeout(()=>ae.click(),0)}}),I.scan(n);const qe=vt(m(),v.peek().map(e=>e.id),f);qe.pruned&&k&&P({owner:f,items:qe.items});const nt=Object.entries(qe.items).sort((e,t)=>String(t[1].at).localeCompare(String(e[1].at)))[0];nt&&!g.peek()&&await ve(nt[0])}};
|
package/docs/DommaFeatures.md
CHANGED
|
@@ -389,7 +389,7 @@ headings (Layouts → Page contents settings, and `[contents]` per page).
|
|
|
389
389
|
|
|
390
390
|
- **Server-side rendering** - pages are rendered to full HTML on the server (layout, navbar, footers, theme classes, fonts, overrides, custom CSS, breadcrumbs, DConfig), so content is visible without JavaScript and crawlable.
|
|
391
391
|
- Where: `server/services/renderer.js`, `server/templates/page.html`
|
|
392
|
-
- **Response cache** - fully rendered pages are cached per URL, file modification time, set of viewer roles and origin, and invalidated by tags when pages, collections, forms, blocks, views, menus, context menus or settings change; concurrent cold requests render once.
|
|
392
|
+
- **Response cache** - fully rendered pages are cached per URL, file modification time, set of viewer roles and origin, and invalidated by tags when pages, collections, forms, blocks, views, menus, context menus or settings change; concurrent cold requests render once. In-process memory driver, toggle and flush from the admin. Drafts and previews are never cached; responses are `private, no-cache` so shared proxies never mix roles.
|
|
393
393
|
- Where: **System > Site Settings > Cache** (key viewer, on/off, clear); dashboard widget; `config/cache.json`; `/api/cache/*`; `docs/cache.md`
|
|
394
394
|
- Since: file-change self-invalidation 0.36.12
|
|
395
395
|
|
package/docs/cache.md
CHANGED
|
@@ -10,8 +10,7 @@ Domma CMS caches assembled public page responses so the markdown → shortcode
|
|
|
10
10
|
{
|
|
11
11
|
"enabled": true,
|
|
12
12
|
"driver": "memory",
|
|
13
|
-
"memory": { "maxItems": 1000, "defaultTtlSeconds": 3600 }
|
|
14
|
-
"redis": { "url": "redis://localhost:6379", "keyPrefix": "domma:" }
|
|
13
|
+
"memory": { "maxItems": 1000, "defaultTtlSeconds": 3600 }
|
|
15
14
|
}
|
|
16
15
|
```
|
|
17
16
|
|
|
@@ -19,7 +18,8 @@ Domma CMS caches assembled public page responses so the markdown → shortcode
|
|
|
19
18
|
- `driver`:
|
|
20
19
|
- `"memory"` - default, in-process LRU with TTL and a tag index. Zero dependencies.
|
|
21
20
|
- `"none"` - same as `enabled: false` but expressed via the driver name.
|
|
22
|
-
|
|
21
|
+
|
|
22
|
+
There is no shared (Redis-style) driver. Each site runs as one Node process, where an in-process hit is a single Map lookup; a networked cache would only add a round trip and serialisation. It would pay off only if one site ran as several processes or servers.
|
|
23
23
|
|
|
24
24
|
A template lives at `config/cache.json.example`.
|
|
25
25
|
|
|
@@ -40,9 +40,6 @@ Add a connection under **Data > Collections > Database connections** (admins onl
|
|
|
40
40
|
`npm run pro enable`. On a site run by the Domma Manager, the MongoDB Adapter plugin sets the connection
|
|
41
41
|
up for you (see below).
|
|
42
42
|
|
|
43
|
-
The optional Redis cache driver is also described as a Pro feature. It needs Redis, not a licence.
|
|
44
|
-
See `docs/cache.md`.
|
|
45
|
-
|
|
46
43
|
## Free plugins
|
|
47
44
|
|
|
48
45
|
These are marked `free` in their manifests and ship in the CMS `plugins/` folder. Switch them on in the
|
|
@@ -413,7 +413,7 @@ options.hooks.on('content:pageCreated', ({ page, urlPath }) => {
|
|
|
413
413
|
| `auth:rateLimited` | `{ ip, ua, route }` | The sign-in rate limit refuses an address |
|
|
414
414
|
| `auth:passwordChanged` | `{ userId, by, ip, ua? }` | A password changes - `by` is `'reset'` (a reset link) or the id of whoever changed it |
|
|
415
415
|
| `auth:resetRequested` | `{ email, userId, ip, ua, sent, reason }` | Someone asks "Forgot your password?" - after the reply; `reason`: `sent`, `unknown`, `inactive`, `throttled`, `no-smtp`, `no-origin`, `failed` |
|
|
416
|
-
| `auth:resetIssued` | `{ userId, by, via }` | An administrator makes a reset link from Users - `via`: `email` or `link`
|
|
416
|
+
| `auth:resetIssued` | `{ userId, by, via }` | An administrator makes a reset link from Users - `via`: `email` or `link` - or an invitation is emailed to a new account (`invite`, a 7-day link) |
|
|
417
417
|
|
|
418
418
|
Every `auth:passwordChanged` also emails the account holder ("your password was changed"), when a mail server is
|
|
419
419
|
set up.
|