domma-cms 1.8.44 → 1.8.46
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 +8 -0
- package/admin/js/lib/code-format.js +50 -40
- package/admin/js/templates/docs/usage-blocks.html +29 -0
- package/admin/js/views/page-editor.js +10 -8
- package/docs/configuration.md +19 -7
- package/docs/starter-blocks.md +203 -0
- package/package.json +1 -1
- package/server/blocks/catalog.json +98 -0
- package/server/blocks/domma-block-banner.css +65 -0
- package/server/blocks/domma-block-banner.html +22 -0
- package/server/blocks/domma-block-banner.meta.json +7 -0
- package/server/blocks/domma-block-contact.css +18 -0
- package/server/blocks/domma-block-contact.html +15 -0
- package/server/blocks/domma-block-contact.meta.json +7 -0
- package/server/blocks/domma-block-cta.css +8 -0
- package/server/blocks/domma-block-cta.html +17 -0
- package/server/blocks/domma-block-cta.meta.json +7 -0
- package/server/blocks/domma-block-faq.css +13 -0
- package/server/blocks/domma-block-faq.html +17 -0
- package/server/blocks/domma-block-faq.meta.json +7 -0
- package/server/blocks/domma-block-features.css +18 -0
- package/server/blocks/domma-block-features.html +19 -0
- package/server/blocks/domma-block-features.meta.json +7 -0
- package/server/blocks/domma-block-hero.css +15 -0
- package/server/blocks/domma-block-hero.html +13 -0
- package/server/blocks/domma-block-hero.meta.json +7 -0
- package/server/blocks/domma-block-image.css +8 -0
- package/server/blocks/domma-block-image.html +12 -0
- package/server/blocks/domma-block-image.meta.json +7 -0
- package/server/blocks/domma-block-logos.css +13 -0
- package/server/blocks/domma-block-logos.html +18 -0
- package/server/blocks/domma-block-logos.meta.json +7 -0
- package/server/blocks/domma-block-pricing-card.css +20 -0
- package/server/blocks/domma-block-pricing-card.html +15 -0
- package/server/blocks/domma-block-pricing-card.meta.json +7 -0
- package/server/blocks/domma-block-service-card.css +17 -0
- package/server/blocks/domma-block-service-card.html +15 -0
- package/server/blocks/domma-block-service-card.meta.json +7 -0
- package/server/blocks/domma-block-split.css +26 -0
- package/server/blocks/domma-block-split.html +22 -0
- package/server/blocks/domma-block-split.meta.json +7 -0
- package/server/blocks/domma-block-stats.css +20 -0
- package/server/blocks/domma-block-stats.html +16 -0
- package/server/blocks/domma-block-stats.meta.json +7 -0
- package/server/blocks/domma-block-steps.css +19 -0
- package/server/blocks/domma-block-steps.html +17 -0
- package/server/blocks/domma-block-steps.meta.json +7 -0
- package/server/blocks/domma-block-team-card.css +13 -0
- package/server/blocks/domma-block-team-card.html +14 -0
- package/server/blocks/domma-block-team-card.meta.json +7 -0
- package/server/blocks/domma-block-testimonial.css +13 -0
- package/server/blocks/domma-block-testimonial.html +12 -0
- package/server/blocks/domma-block-testimonial.meta.json +7 -0
- package/server/blocks/domma-block-text.css +9 -0
- package/server/blocks/domma-block-text.html +11 -0
- package/server/blocks/domma-block-text.meta.json +7 -0
- package/server/services/blocks.js +2 -0
- package/server/services/starter-blocks.js +18 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{api as h}from"../api.js";import{CardBuilder as en}from"../lib/card-builder.js";import{TimelineBuilder as tn}from"../lib/timeline-builder.js";import{attachEditorKeybindings as on,createToolbar as an,insertAtCursor as sn}from"../lib/markdown-toolbar.js";import{EffectsBuilder as nn}from"../lib/effects-builder.js";import{attachContextMenu as rn}from"../lib/shortcode-context-menu.js";import{registerCustomInserters as ln}from"../lib/shortcode-insert.js";import{populateThemeSelect as cn}from"../lib/themes.js";import{createFoldingManager as dn}from"../lib/editor-folding.js";import{openScribeComposer as pn}from"../lib/scribe-composer.js";import{openCrudTutorial as un}from"../lib/crud-tutorial.js";import{addBannerAction as dt}from"../lib/plugin-chrome.js";import{exampleJson as mn,parseSchema as Po,schemaText as fn}from"../lib/seo-structured-data.js";import{helpPopovers as qa}from"../lib/help-popover.js";import{onceClosed as jt,openMenuAt as Ce,sidebarCount as pt}from"../lib/tool-kit.js";import{pickMedia as bn}from"../lib/media-picker.js";import{openPageClone as vn}from"../lib/page-clone.js";import{openEditorReference as
|
|
1
|
+
import{api as h}from"../api.js";import{CardBuilder as en}from"../lib/card-builder.js";import{TimelineBuilder as tn}from"../lib/timeline-builder.js";import{attachEditorKeybindings as on,createToolbar as an,insertAtCursor as sn}from"../lib/markdown-toolbar.js";import{EffectsBuilder as nn}from"../lib/effects-builder.js";import{attachContextMenu as rn}from"../lib/shortcode-context-menu.js";import{registerCustomInserters as ln}from"../lib/shortcode-insert.js";import{populateThemeSelect as cn}from"../lib/themes.js";import{createFoldingManager as dn}from"../lib/editor-folding.js";import{openScribeComposer as pn}from"../lib/scribe-composer.js";import{openCrudTutorial as un}from"../lib/crud-tutorial.js";import{addBannerAction as dt}from"../lib/plugin-chrome.js";import{exampleJson as mn,parseSchema as Po,schemaText as fn}from"../lib/seo-structured-data.js";import{helpPopovers as qa}from"../lib/help-popover.js";import{onceClosed as jt,openMenuAt as Ce,sidebarCount as pt}from"../lib/tool-kit.js";import{pickMedia as bn}from"../lib/media-picker.js";import{openPageClone as vn}from"../lib/page-clone.js";import{openEditorReference as Ha}from"../lib/page-editor-reference.js";import{cleanType as Bt,DEFAULT_TYPE as It,EDITOR_FONTS as gn,fontHref as hn,isDefaultType as kn,LINE_HEIGHTS as yn,SIZES as wn,typeVars as Va}from"../lib/editor-type.js";import{getProjectFromHash as Ft}from"../lib/project-context.js";import{attachSmoothCaret as _a,getCaretPreference as Sn,setCaretPreference as En}from"../lib/smooth-caret.js";import{SCREEN as Oo,bannerSection as Tn,draftIsStale as Mn,draftKey as ze,initialProject as Cn,makeDraft as Ka,problems as Ao,readDraft as xn,snapshot as W}from"../lib/page-editor-arrange.js";import{fmtDateTime as qe}from"../lib/dates.js";import{hasDraft as xe,heldBlockEdits as Pn,hold as Ro,takeHeld as $o,wireHeldRouter as On}from"../lib/editor-hop.js";import{hopTarget as Ua}from"../lib/editor-hop-arrange.js";import{checkNewName as An,copyName as Lo,usageText as Rn}from"../lib/blocks-arrange.js";import{isCollapsed as Ja,setCollapsed as Wa}from"../lib/sidebar-size.js";import{blockTagDefs as Ya,blocksInBody as $n}from"../lib/block-tags.js";import{draftKey as He,draftOffer as Ln,extractPlaceholders as Ga,formFromBlock as Xa,payloadFromForm as Za,rawPlaceholders as No,shortcodeFor as Nn,snapshot as Do}from"../lib/block-editor-arrange.js";import{blockTabs as Dn,notHereLine as jn,otherUses as Qa,outlineBlock as Bn,previewBlocks as In,saveQuestion as Fn,savedMessage as zn,usesLine as qn}from"../lib/page-blocks-arrange.js";import{addressFor as es,blockAloneBody as Hn,blockRows as Vn,cleanLayout as jo,closeTab as _n,componentRows as Kn,componentStatusText as Un,componentsInBody as Jn,moveTab as Wn,nextLayout as Yn,openTab as Bo,pageRows as Gn,pageStatusText as Xn,rememberedTabs as Zn,renameTab as Qn,sampleRows as ts,saveAllLabel as er,startingTabs as tr,tabId as X,tabItem as I,tabsToClose as Io,workspaceKey as or}from"../lib/editor-workspace-arrange.js";import{PANES as zt,STARTER_SOURCE as ar,assembleSource as os,attributeFor as sr,draftKey as Ve,draftStatus as nr,nameProblem as rr,previewRows as as,readValue as ir,snapshot as Fo,splitSource as ut,writeValue as ss}from"../lib/component-editor-arrange.js";import{attachColourLayer as ns,createPlainEditor as zo}from"../lib/plain-editor.js";import{cleanCodePrefs as qt,codePrefs as lr,DEFAULT_CODE_PREFS as Ht,formatTextarea as _e,INDENT_SIZES as cr,setCodePrefs as dr}from"../lib/code-format.js";function mt(d){const b=document.createElement("template");return b.innerHTML=d.trim(),b.content.firstElementChild}const pr=qe,rs=d=>qe(d.createdAt)+(d.label?` - ${d.label}`:""),ur=`
|
|
2
2
|
<div class="pe-share">
|
|
3
3
|
<p class="form-hint" style="margin-top:0">Anyone with the link can view this page even while it is unpublished, without
|
|
4
4
|
signing in. The link works for this page only, expires on its own, and can be revoked at any time.</p>
|
|
@@ -71,6 +71,8 @@ import{api as h}from"../api.js";import{CardBuilder as en}from"../lib/card-builde
|
|
|
71
71
|
<label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="shortTags.value"> Indent inside short tags
|
|
72
72
|
<span data-help="Shift+Alt+F indents [grid], [col], [card]\u2026 and what is inside them by how deeply they nest, and Enter after an opening tag goes one deeper. The site never shows the indent - it is taken off before the page is made. Off: short tags and their content stay at the margin."></span></label>
|
|
73
73
|
<label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="tables.value"> Line up tables when formatting</label>
|
|
74
|
+
<label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="html.value"> Lay out HTML in the page body
|
|
75
|
+
<span data-help="Shift+Alt+F puts each block tag (div, p, li, section\u2026) in the body's HTML on a line of its own, indented by nesting - as it does in a block. Text and inline tags keep the lines you wrote them on. An HTML block holding <pre>, a script or a short tag line is left as it is."></span></label>
|
|
74
76
|
<label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="formatOnSave.value"> Format on save
|
|
75
77
|
<span data-help="Save formats the tab you are on first, as Shift+Alt+F would. Ctrl+Z still undoes it."></span></label>
|
|
76
78
|
<div class="pe-settings-sample" aria-label="Sample"># A heading
|
|
@@ -92,13 +94,13 @@ The quick brown fox - 0O 1lI {} [] () => ==
|
|
|
92
94
|
.pe-settings-sample { white-space: pre-wrap; padding: .75rem 1rem; border-radius: var(--dm-radius-md); border: 1px solid var(--dm-border);
|
|
93
95
|
background: var(--dm-background-alt); font-family: var(--pe-font); font-size: var(--pe-size); line-height: var(--pe-line); }
|
|
94
96
|
.pe-settings-actions { display: flex; gap: .5rem; border-top: 1px solid var(--dm-border); padding-top: .75rem; }
|
|
95
|
-
</style>`;function fr(d,b){const v=E.slideover({title:"Editor settings",size:"sm",position:"right"}),i=mt(`<div>${mr}</div>`),y=Bt(d.peek()),
|
|
97
|
+
</style>`;function fr(d,b){const v=E.slideover({title:"Editor settings",size:"sm",position:"right"}),i=mt(`<div>${mr}</div>`),y=Bt(d.peek()),p={font:M.observable(y.font),size:M.observable(String(y.size)),line:M.observable(String(y.line)),wrap:M.observable(y.wrap),caret:M.observable(Sn()),sidebar:M.observable(Pe().closeSidebar===!0)},w=qt(b.peek());p.indent=M.observable(w.indent),p.indentSize=M.observable(String(w.size));for(const T of["detect","autoIndent","continueLists","shortTags","tables","html","formatOnSave"])p[T]=M.observable(w[T]);const k=M.computed(()=>qt({indent:p.indent.value,size:p.indentSize.value,detect:p.detect.value,autoIndent:p.autoIndent.value,continueLists:p.continueLists.value,shortTags:p.shortTags.value,tables:p.tables.value,html:p.html.value,formatOnSave:p.formatOnSave.value})),x=M.effect(()=>{const T=k.value;JSON.stringify(T)!==JSON.stringify(qt(b.peek()))&&(b.value=T,Ke("code",T))}),j=M.effect(()=>{const T=p.sidebar.value;T!==(Pe().closeSidebar===!0)&&Ke("closeSidebar",T)}),c=M.computed(()=>Bt({font:p.font.value,size:p.size.value,line:p.line.value,wrap:p.wrap.value}));p.isDefault=M.computed(()=>kn(c.value)&&p.caret.value==="auto"&&!p.sidebar.value&&JSON.stringify(k.value)===JSON.stringify(Ht));const A=M.effect(()=>En(p.caret.value)),H=i.querySelector("#pe-set-font");for(const[T,ne]of[["mono","Monospace"],["sans","Other"],["serif",null]]){const Oe=gn.filter(re=>re.kind===T),O=ne?Object.assign(document.createElement("optgroup"),{label:ne}):H.querySelector("optgroup:last-of-type");O.append(...Oe.map(re=>new Option(re.label,re.id))),ne&&H.appendChild(O)}i.querySelector("#pe-set-indent-size").append(...cr.map(T=>new Option(String(T),String(T)))),i.querySelector("#pe-set-size").append(...wn.map(T=>new Option(`${T}px`,String(T)))),i.querySelector("#pe-set-line").append(...yn.map(T=>new Option({1.3:"Tight",1.45:"Snug",1.6:"Normal",1.8:"Relaxed",2:"Double"}[T]||String(T),String(T))));const Y=i.querySelector(".pe-settings-sample"),D=M.effect(()=>{const T=c.value;is(T.font);for(const[ne,Oe]of Object.entries(Va(T)))Y.style.setProperty(ne,Oe);Y.style.whiteSpace=T.wrap?"pre-wrap":"pre",Y.style.overflowX=T.wrap?"":"auto",JSON.stringify(T)!==JSON.stringify(Bt(d.peek()))&&(d.value=T,Ke("type",T))});p.reset=()=>{p.font.value=It.font,p.size.value=String(It.size),p.line.value=String(It.line),p.wrap.value=It.wrap,p.caret.value="auto",p.sidebar.value=!1,p.indent.value=Ht.indent,p.indentSize.value=String(Ht.size);for(const T of["detect","autoIndent","continueLists","shortTags","tables","html","formatOnSave"])p[T].value=Ht[T]},p.done=()=>v.close(),v.element.appendChild(i);const se=M.applyBindings(p,i),Vt=qa(i);return jt(v,()=>{se.dispose(),Vt(),D?.(),A?.(),j?.(),x?.()}),Domma.icons?.scan?.(i),v.open(),v}async function br(d){const b=E.slideover({title:"Share preview link",size:"md",position:"right"}),v=mt(`<div>${ur}</div>`),i={expiry:M.observable("7d"),note:M.observable(""),creating:M.observable(!1),url:M.observable(""),links:M.observable([]),loaded:M.observable(!1),listError:M.observable("")},y=async()=>{try{const w=await h.pages.previewLinks.list(d);i.links.value=w.filter(k=>!k.revokedAt&&!k.expired).map(k=>({id:k.id,title:k.label||"Untitled link",meta:`Expires ${pr(k.expiresAt)} - ${k.useCount===1?"1 view":`${k.useCount||0} views`}`})),i.listError.value=""}catch(w){i.listError.value="Could not load existing links: "+(w.message||"unknown error")}finally{i.loaded.value=!0}};i.create=async()=>{i.creating.value=!0;try{const w=await h.pages.previewLinks.create(d,i.expiry.peek(),i.note.peek().trim());i.url.value=w.url,i.note.value="",E.toast("Share link created.",{type:"success"}),await y(),v.querySelector(".pe-share-url")?.select()}catch(w){E.toast("Could not create link: "+(w.message||"unknown error"),{type:"error"})}finally{i.creating.value=!1}},i.copy=async()=>{try{await navigator.clipboard.writeText(i.url.peek()),E.toast("Link copied to clipboard.",{type:"success"})}catch{v.querySelector(".pe-share-url")?.select(),E.toast("Press Ctrl+C to copy the selected link.",{type:"info"})}},i.revoke=async w=>{if(await E.confirm("Revoke this link? Anyone holding it loses access immediately."))try{await h.pages.previewLinks.revoke(w),E.toast("Link revoked.",{type:"success"}),await y()}catch(k){E.toast("Could not revoke: "+(k.message||"unknown error"),{type:"error"})}};const p=M.applyBindings(i,v);jt(b,()=>p.dispose()),b.element.appendChild(v),b.open(),await y()}function vr(d){return new Promise(b=>{const v=E.slideover({title:"Save Named Version",size:"sm",position:"right"}),i=mt(`
|
|
96
98
|
<div style="padding:1rem">
|
|
97
99
|
<label class="form-label" for="pe-version-label">Version Label</label>
|
|
98
100
|
<input id="pe-version-label" type="text" class="form-input" style="margin-bottom:.75rem"
|
|
99
101
|
placeholder="e.g. Initial design, Before restructure" data-model="label.value" data-on-keydown="key">
|
|
100
102
|
<button type="button" class="btn btn-primary" data-on-click="save" data-bind-disabled="saving.value">Save Version</button>
|
|
101
|
-
</div>`);let y=!1;const
|
|
103
|
+
</div>`);let y=!1;const p={label:M.observable(""),saving:M.observable(!1)};p.save=async()=>{p.saving.value=!0;try{await h.versions.create(d,p.label.peek().trim()||null),E.toast("Named version saved.",{type:"success"}),y=!0,v.close()}catch(k){E.toast("Failed to save version: "+k.message,{type:"error"})}finally{p.saving.value=!1}},p.key=k=>{k.key==="Enter"&&(k.preventDefault(),p.save())};const w=M.applyBindings(p,i);jt(v,()=>{w.dispose(),b(y)}),v.element.appendChild(i),v.open(),setTimeout(()=>i.querySelector("input")?.focus(),100)})}const gr=`<div class="card">
|
|
102
104
|
<h3>{{title}}</h3>
|
|
103
105
|
<p>{{description}}</p>
|
|
104
106
|
</div>
|
|
@@ -122,7 +124,7 @@ The quick brown fox - 0O 1lI {} [] () => ==
|
|
|
122
124
|
.pe-new [hidden] { display: none !important; }
|
|
123
125
|
.pe-new-err { display: block; margin-top: .3rem; color: var(--dm-danger); font-size: var(--dm-text-xs); }
|
|
124
126
|
.pe-new-actions { display: flex; justify-content: flex-end; gap: .5rem; margin-top: 1.25rem; }
|
|
125
|
-
</style>`;function ls({kind:d,projects:b,taken:v,project:i="",name:y="",check:u,create:w,register:k=()=>{}}){return new Promise(x=>{const j=E.slideover({title:d==="block"?"New block":"New component",size:"sm",position:"right"});k(()=>{try{j.close()}catch{}});const c=mt(`<div>${hr}</div>`);for(const D of b)c.querySelector("#pe-new-project").append(new Option(D.name||D.slug,D.slug));const A={name:M.observable(y),project:M.observable(i),busy:M.observable(!1),hint:M.observable(d==="block"?"A block is a reusable piece of HTML with {{placeholders}}, used on pages with its short tag or by a collection display. Its name is its tag - fixed once created.":"A component is a custom element - <dm-name> - with a template, props, a script and a style. Its name is its tag - fixed once created."),placeholder:M.observable(d==="block"?"e.g. team-card":"e.g. pricing-table")};A.error=M.computed(()=>A.name.value.trim()?u(A.name.value.trim(),v):""),A.canCreate=M.computed(()=>!A.busy.value&&!!A.name.value.trim()&&!u(A.name.value.trim(),v));let V="";A.create=async()=>{const D=A.name.peek().trim();if(!(!D||A.error.peek()||A.busy.peek())){A.busy.value=!0;try{await w(D,A.project.peek()),V=D,j.close()}catch(se){E.toast(`Not created: ${se.message||se}`,{type:"error"})}finally{A.busy.value=!1}}},A.cancel=()=>j.close(),A.key=D=>{D.key==="Enter"&&(D.preventDefault(),A.create())};const Y=M.applyBindings(A,c);jt(j,()=>{Y.dispose(),x(V)}),j.element.appendChild(c),c.querySelector("#pe-new-project").value=i,j.open(),setTimeout(()=>{const D=c.querySelector("#pe-new-name");D?.focus(),D?.select()},100)})}let F=null,cs=!1;function kr(){cs||!window.R?.use||(cs=!0,On(),R.use((d,b,v)=>{if(F&&!F.alive()){const u=F;F=null,u.dispose()}const i=b?.path||"",y=d?.path||"";if(!F||!Oo.test(i))return v();if(Oo.test(y)){const u=Ha(y);if(u){F.open(u,y);return}return v()}return F.dirty()?E.confirm("You have unsaved changes. Leave anyway? They are kept as drafts for your next visit.").then(u=>{u?(F?.keepDraft(),v()):F&&history.replaceState({pe:1},"","#"+F.address)}):v()}),M.subscribe("router:afterChange",({to:d}={})=>{if(F&&!Oo.test(d?.path||"")){const b=F;F=null,b.dispose()}}))}const ds="editor_prefs";function Pe(){return S.get(ds)||{viewMode:"split",fullscreen:!1}}const yr=()=>{try{return Pe()||{}}catch{return{}}};function Ue(d,b){const v=Pe();v[d]=b,S.set(ds,v)}const ps="editor-workspace.tabs",us="editor-workspace.folded",ft="editor-workspace.css",wr="/__block-preview",Sr=d=>d.replace(/<\/head>/i,"<style>body.dm-cloaked{opacity:1 !important;transition:none !important}</style></head>");function Er(d,b,v=()=>{}){let i=0;try{i=d.contentWindow.scrollY||0}catch{}d.addEventListener("load",()=>{try{d.contentWindow.scrollTo(0,i)}catch{}v()},{once:!0}),d.srcdoc=b}const Mr=["urlPath","title","description","layout","status","sortOrder","category","visibility","project","theme","seoTitle","seoDesc","seoSchema","dconfig"],Tr=["showInNav","sidebar","breadcrumbs","bundled"],ms=()=>({urlPath:"",title:"",description:"",layout:"",status:"draft",sortOrder:"99",showInNav:!1,sidebar:!1,breadcrumbs:!0,bundled:!1,tags:[],adminTags:[],category:"",visibility:"public",project:"",theme:"",seoTitle:"",seoDesc:"",seoSchema:"",dconfig:"",body:"",css:null});export const pageEditorView={templateUrl:"/admin/js/templates/page-editor.html",async onMount(d){if(kr(),F){const e=F;F=null,e.dispose()}const b=window.location.hash.replace(/^#/,""),v=[],i=e=>(v.push(e),e);let y=()=>!1,u=()=>{},w=()=>{};const k=d.get(0),x=k.querySelector("#pe-workspace"),j={address:b,alive:()=>x?.isConnected===!0,dirty:()=>y(),keepDraft:()=>u(),open:(e,t)=>w(e,t),dispose:()=>{v.splice(0).forEach(e=>{try{e()}catch{}})}};F=j;const c=()=>F===j&&j.alive();if(yr().closeSidebar===!0){const e=document.querySelector("#admin-sidebar");e&&!Ja(e)&&!window.matchMedia("(max-width: 768px)").matches&&(Wa(e,!0,!1),i(()=>{e.isConnected&&Ja(e)&&Wa(e,!1,!1)}))}const A=E.loader(k,{type:"dots"});let[V,Y,D,se,_t,T,ne,Oe]=await Promise.all([h.layouts.get().catch(()=>({})),h.settings.get().catch(()=>({})),h.pages.list().catch(()=>[]),h.projects.list().catch(()=>[]),h.pages.tags().catch(()=>[]),h.listTags.list("pages").then(e=>e.map(t=>t.name)).catch(()=>[]),h.get("/blocks?usage=1").catch(()=>h.blocks.list()).catch(()=>[]),h.components.list().catch(()=>[])]);if(!c()){A.destroy();return}A.destroy();const O=e=>k.querySelector(e);if(D=Array.isArray(D)?D:[],cn(O("#field-theme"),{includeDefault:!0}),await Rr(O("#field-visibility")),!c())return;const re=Object.keys(V||{});Or(O("#field-layout"),V,re[0]||"default");const Vo=e=>re.includes(e)?e:re[0]||e||"default";for(const e of se)for(const t of["#field-project","#block-project","#comp-project"])O(t).append(new Option(e.name||e.slug,e.slug));let ie=Array.isArray(ne)?ne:[],bt=Ya(ie);const vt=new Map(ie.map(e=>[e.name,e.updatedAt])),He=new Map(ie.map(e=>[e.name,e.usage])),be=new Set(ie.map(e=>e.name)),_o=async()=>{const e=await h.get("/blocks?usage=1").catch(()=>null);if(!(!c()||!Array.isArray(e))){ie=e,bt=Ya(ie);for(const t of ie)be.add(t.name),He.set(t.name,t.usage),vt.has(t.name)||vt.set(t.name,t.updatedAt)}},Kt=Array.isArray(Y?.footer?.blocks)?Y.footer.blocks.filter(e=>typeof e=="string"):[];let Je=Array.isArray(Oe)?Oe.filter(e=>typeof e?.name=="string"):[];const le=new Set(Je.map(e=>e.name)),Ko=async()=>{const e=await h.components.list().catch(()=>null);if(!(!c()||!Array.isArray(e))){Je=e.filter(t=>typeof t?.name=="string");for(const t of Je)le.add(t.name)}},Z=Pe(),p={urlPath:M.observable(""),title:M.observable(""),description:M.observable(""),layout:M.observable(Vo("default")),status:M.observable("draft"),sortOrder:M.observable("99"),showInNav:M.observable(!1),sidebar:M.observable(!1),breadcrumbs:M.observable(!0),bundled:M.observable(!1),tags:M.observable([]),adminTags:M.observable([]),category:M.observable(""),visibility:M.observable("public"),project:M.observable(""),theme:M.observable(""),seoTitle:M.observable(""),seoDesc:M.observable(""),seoSchema:M.observable(""),dconfig:M.observable(""),css:M.observable(""),cssOpened:M.observable(!1)},a={bodyRev:M.observable(0),base:M.observable(""),saving:M.observable(!1),viewMode:M.observable(jo(Z.viewMode)),fullscreen:M.observable(!!Z.fullscreen),explorerOn:M.observable(Z.explorer??!window.matchMedia("(max-width: 1024px)").matches),dockOn:M.observable(!!Z.dock),dockTab:M.observable("details"),seoSchemaNote:M.observable(""),cssMode:M.observable(!1),folded:M.observable(!1),previewStatus:M.observable("Showing unsaved changes"),liveWidth:M.observable("full"),versions:M.observable([]),histLoading:M.observable(!1),histError:M.observable(""),compare:M.observable(null),heldNote:M.observable(""),tabs:M.observable([]),active:M.observable(""),curId:M.observable(null),blockTab:M.observable(""),blockPart:M.observable("html"),blockReady:M.observable(!1),blockNote:M.observable(""),blockUses:M.observable(""),blockProject:M.observable(""),blockBundled:M.observable(!1),blockWhere:M.observable(""),compTab:M.observable(""),compPart:M.observable("template"),compReady:M.observable(!1),compNote:M.observable(""),compReadOnly:M.observable(!1),compState:M.observable(""),compErrors:M.observable(""),compProject:M.observable(""),compBundled:M.observable(!1),blockRev:M.observable(0),compRev:M.observable(0),docRev:M.observable(0),filter:M.observable(""),secHere:M.observable(Z.secHere!==!1),secPages:M.observable(Z.secPages!==!1),secBlocks:M.observable(Z.secBlocks!==!1),secComps:M.observable(Z.secComps!==!1),thisPage:M.observable([]),pageRows:M.observable([]),blockRows:M.observable([]),compRows:M.observable([])},_=O("#markdown-editor"),ve=O("#css-editor"),fs=Ka(_),bs=Ka(ve);i(()=>fs.destroy()),i(()=>bs.destroy());const ce=document.createElement("div");ce.className="editor-line-numbers editor-line-numbers--foldable",_.parentElement.insertBefore(ce,_);const We=ns(_,"md"),Ut=ns(ve,"css");i(()=>{We.destroy(),Ut.destroy()});const Uo=()=>{We.paint(),Ut.paint()},Q=dn(_,ce,{onFoldChange:()=>We.paint()});let gt=!1;Q.setGuard(e=>{gt=e});const Ht=()=>Q.getUnfoldedContent(),Jt=()=>{Q.unfoldAll(),a.folded.value=!1,We.paint()},vs=e=>{if(e?.kind==="page")Jt(),Ke(_,"md");else if(e?.kind==="block")oe&&Ke(oe.textarea,"html"),me&&Ke(me.textarea,"css");else if(e?.kind==="component"){if(N.get(e.id)?.readOnly)return;for(const[o,s]of Object.entries({template:"html",props:"json",script:"js",style:"css"}))ae[o]&&Ke(ae[o].textarea,s)}},Ho=e=>{e.error?E.toast(e.error,{type:"warning"}):E.toast(e.unchanged?"Already tidy":"Formatted",{type:"info",duration:900})},Jo=M.observable(Bt(Z.type)),Wo=M.observable(qt(Z.code));i(M.effect(()=>{const e=Wo.value;dr(e),O("#editor-body")?.style.setProperty("--pe-tab",String(e.size))})),i(M.effect(()=>{const e=Jo.value,t=O("#editor-body");if(t){is(e.font);for(const[o,s]of Object.entries(_a(e)))t.style.setProperty(o,s);t.classList.toggle("pe-nowrap",!e.wrap),_.wrap=e.wrap?"soft":"off",ve.wrap=e.wrap?"soft":"off",requestAnimationFrame(()=>{c()&&Uo()})}}));let Yo=null;i(()=>{try{Yo?.close()}catch{}});const K=()=>(a.bodyRev.value,{urlPath:p.urlPath.value.trim(),title:p.title.value,description:p.description.value,layout:p.layout.value,status:p.status.value,sortOrder:p.sortOrder.value,showInNav:p.showInNav.value,sidebar:p.sidebar.value,breadcrumbs:p.breadcrumbs.value,bundled:p.bundled.value,tags:p.tags.value,adminTags:p.adminTags.value,category:p.category.value,visibility:p.visibility.value,project:p.project.value,theme:p.theme.value,seoTitle:p.seoTitle.value,seoDesc:p.seoDesc.value,seoSchema:p.seoSchema.value,dconfig:p.dconfig.value,body:Ht(),css:null}),Go=()=>M.untracked?M.untracked(K):K(),ee=M.observable(""),ht=()=>p.cssOpened.peek()&&p.css.peek()!==ee.peek(),U=new Map;let m=null;const L=new Map,N=new Map;let P=[];const de=e=>Do(e.form)!==e.base,ge=()=>[...L.entries()].filter(([,e])=>de(e)).map(([e])=>e),he=e=>!e.readOnly&&Fo({name:e.name,...e.form})!==e.base,Ye=()=>[...N.values()].filter(he).map(e=>e.name),Wt=()=>W(Go())!==a.base.peek(),Yt=e=>e.loaded&&(e===m?Wt():W(e.state)!==e.base),Re=()=>[...U.values()].filter(Yt),gs=M.computed(()=>W(K())!==a.base.value),hs=M.computed(()=>p.cssOpened.value&&p.css.value!==ee.value),ks=M.computed(()=>(a.blockRev.value,a.compRev.value,a.docRev.value,W(K())!==a.base.value||p.cssOpened.value&&p.css.value!==ee.value||Re().some(e=>e!==m)||ge().length>0||Ye().length>0)),ys=M.computed(()=>{a.blockRev.value,a.compRev.value;const e=I(a.active.value);if(e?.kind==="block"){const t=L.get(e.id);return!!(t&&de(t))}if(e?.kind==="component"){const t=N.get(e.id);return!!(t&&he(t))}return W(K())!==a.base.value||p.cssOpened.value&&p.css.value!==ee.value}),ws=M.computed(()=>a.curId.value!==null),Xo=M.computed(()=>I(a.active.value)?.kind||""),Zo=M.computed(()=>!!a.curId.value&&I(a.active.value)?.kind==="page"),Ss=M.computed(()=>p.urlPath.value.trim()||a.curId.value||""),Es=M.computed(()=>Ro({urlPath:p.urlPath.value,dconfig:p.dconfig.value})[0]?.text||""),Ms=M.computed(()=>{a.docRev.value;const e=I(a.active.value);return e?e.kind==="block"?a.blockUses.value:e.kind==="component"?Hn({name:e.id,readOnly:a.compReadOnly.value,state:a.compReady.value?a.compState.value:""}):Xn({urlPath:p.urlPath.value,status:p.status.value,isEdit:!!a.curId.value}):""}),Qo=M.computed(()=>a.compTab.value?"component":a.blockTab.value?"block":a.curId.value!==null?"page":""),Ts=M.computed(()=>a.blockTab.value?`[${a.blockTab.value} /]`:""),Cs=M.computed(()=>({compiling:"Compiling\u2026",ok:"Compiles",error:"Does not compile"})[a.compState.value]||""),xs=M.computed(()=>a.compTab.value?`<dm-${a.compTab.value}>`:""),Ps=M.computed(()=>a.versions.value.some(e=>e.checked.value)),Os=M.computed(()=>a.versions.value.length>0&&a.versions.value.every(e=>e.checked.value)),Rs=M.computed(()=>{const e=a.versions.value.filter(t=>t.checked.value).length;return e>0&&e<a.versions.value.length});y=()=>Re().length>0||ge().length>0||Ye().length>0||ht();const Gt=(e,t,o)=>({title:String(e.title||"").trim()||"Untitled",description:String(e.description||"").trim(),layout:e.layout,status:e.status,sortOrder:parseInt(String(e.sortOrder),10)||99,showInNav:!!e.showInNav,sidebar:!!e.sidebar,...e.breadcrumbs?{}:{breadcrumbs:!1},...e.bundled?{bundled:!0}:{},tags:Array.isArray(e.tags)?e.tags:[],...t?.isEdit&&JSON.stringify(e.adminTags)===t.savedAdminTags?{}:{adminTags:Array.isArray(e.adminTags)?e.adminTags:[]},category:String(e.category||"").trim()||null,visibility:e.visibility||"public",project:e.project||"",seo:{title:String(e.seoTitle||"").trim(),description:String(e.seoDesc||"").trim(),...ea(e)?{schema:ea(e)}:t?.isEdit?{schema:null}:{}},dconfig:o,...e.theme?{theme:e.theme}:{}}),ea=e=>Po(e.seoSchema).value,Xt=e=>{const t=String(e.dconfig||"").trim();if(!t)return null;try{return JSON.parse(t)}catch{return null}},As=()=>p.urlPath.peek().trim()||m?.id||"/";let kt=[],ta=[];const yt=e=>kt.includes(e)||Kt.includes(e);let Ae=new Set;const wt=()=>{const e=[...new Set([...kt,...Kt,...L.keys()])],t=Pn(e.filter(s=>!L.has(s)),vt);Ae=new Set(Object.keys(t));const o=Ae.size?`Preview shows unsaved changes to ${[...Ae].join(", ")}`:"";return o!==a.heldNote.peek()&&(a.heldNote.value=o),In(t,[...L.entries()].map(([s,r])=>({name:s,content:r.form.content,css:r.form.css,dirty:de(r)})))};let Zt="";const $s=()=>{oa();const e=Zt;if(e){Zt="";try{$e.contentDocument?.querySelector(`[data-block="${CSS.escape(e)}"]`)?.scrollIntoView({block:"center"})}catch{}}},$e=O("#markdown-preview");h.settings.getCustomCss().then(({css:e})=>{if(!c())return;ee.value=e||"";let t=null;try{t=S.get(ft)}catch{}typeof t=="string"&&t!==ee.peek()?(ia(),p.css.value=t,E.toast("Your unsaved custom CSS is back - the CSS button shows it.",{type:"info"})):p.cssOpened.peek()||(p.css.value=ee.peek()),J(ft)}).catch(()=>{});const oa=()=>{const e=$e?.contentDocument;if(!e?.head)return;const t=p.cssOpened.peek()?p.css.peek():"";if(!t)return;let o=e.getElementById("preview-custom-css");o||(o=e.createElement("style"),o.id="preview-custom-css",e.head.appendChild(o)),o.textContent=t};let Qt=null,eo=0;const H=(e=!1)=>{clearTimeout(Qt),Qt=setTimeout(async()=>{if(!$e||a.viewMode.peek()==="write"||!a.active.peek()||a.compTab.peek())return;const t=++eo,o=a.blockTab.peek();a.previewStatus.value="Rendering\u2026";try{let s;if(o&&(!m||!yt(o)))({html:s}=await h.pages.previewFull(wr,{title:o,layout:"blank",breadcrumbs:!1},Vn(o,_s(o)),wt()));else if(m){const r=K();({html:s}=await h.pages.previewFull(As(),Gt(r,m,Xt(r)),r.body,wt()))}else{$e.srcdoc="";return}if(!c()||t!==eo)return;Er($e,Bn(Sr(s),o),$s),a.previewStatus.value="Showing unsaved changes"}catch(s){if(!c()||t!==eo)return;a.previewStatus.value="Preview failed - "+(s?.message||"unknown error"),$e.srcdoc='<!doctype html><meta charset="utf-8"><body style="font:14px system-ui;padding:1rem;color:#b91c1c;">Preview failed: '+String(s?.message||"unknown error").replace(/[<&]/g,r=>r==="<"?"<":"&")+"</body>"}},e?0:500)};i(()=>clearTimeout(Qt));const to=an(d.find("#markdown-editor"),d.find("#editor-toolbar"),{spacerDefault:Y?.layoutOptions?.spacerSize??40,beforeFormat:()=>Jt()});rn(_,{blocks:()=>bt,openBlock:e=>Be(e)});const Ge=k.querySelector(".editor-toolbar-right");Ge.querySelectorAll(".editor-view-btn[data-mode]").forEach(e=>{const t=e.getAttribute("data-mode");e.classList.remove("active"),e.setAttribute("data-bind-class",`viewMode.value === '${t}' && 'active'`),e.setAttribute("data-on-click",`setMode('${t}')`)}),O("#fullscreen-btn")?.setAttribute("data-on-click","toggleFullscreen");const Ls=mt(`
|
|
127
|
+
</style>`;function ls({kind:d,projects:b,taken:v,project:i="",name:y="",check:p,create:w,register:k=()=>{}}){return new Promise(x=>{const j=E.slideover({title:d==="block"?"New block":"New component",size:"sm",position:"right"});k(()=>{try{j.close()}catch{}});const c=mt(`<div>${hr}</div>`);for(const D of b)c.querySelector("#pe-new-project").append(new Option(D.name||D.slug,D.slug));const A={name:M.observable(y),project:M.observable(i),busy:M.observable(!1),hint:M.observable(d==="block"?"A block is a reusable piece of HTML with {{placeholders}}, used on pages with its short tag or by a collection display. Its name is its tag - fixed once created.":"A component is a custom element - <dm-name> - with a template, props, a script and a style. Its name is its tag - fixed once created."),placeholder:M.observable(d==="block"?"e.g. team-card":"e.g. pricing-table")};A.error=M.computed(()=>A.name.value.trim()?p(A.name.value.trim(),v):""),A.canCreate=M.computed(()=>!A.busy.value&&!!A.name.value.trim()&&!p(A.name.value.trim(),v));let H="";A.create=async()=>{const D=A.name.peek().trim();if(!(!D||A.error.peek()||A.busy.peek())){A.busy.value=!0;try{await w(D,A.project.peek()),H=D,j.close()}catch(se){E.toast(`Not created: ${se.message||se}`,{type:"error"})}finally{A.busy.value=!1}}},A.cancel=()=>j.close(),A.key=D=>{D.key==="Enter"&&(D.preventDefault(),A.create())};const Y=M.applyBindings(A,c);jt(j,()=>{Y.dispose(),x(H)}),j.element.appendChild(c),c.querySelector("#pe-new-project").value=i,j.open(),setTimeout(()=>{const D=c.querySelector("#pe-new-name");D?.focus(),D?.select()},100)})}let F=null,cs=!1;function kr(){cs||!window.R?.use||(cs=!0,On(),R.use((d,b,v)=>{if(F&&!F.alive()){const p=F;F=null,p.dispose()}const i=b?.path||"",y=d?.path||"";if(!F||!Oo.test(i))return v();if(Oo.test(y)){const p=Ua(y);if(p){F.open(p,y);return}return v()}return F.dirty()?E.confirm("You have unsaved changes. Leave anyway? They are kept as drafts for your next visit.").then(p=>{p?(F?.keepDraft(),v()):F&&history.replaceState({pe:1},"","#"+F.address)}):v()}),M.subscribe("router:afterChange",({to:d}={})=>{if(F&&!Oo.test(d?.path||"")){const b=F;F=null,b.dispose()}}))}const ds="editor_prefs";function Pe(){return S.get(ds)||{viewMode:"split",fullscreen:!1}}const yr=()=>{try{return Pe()||{}}catch{return{}}};function Ke(d,b){const v=Pe();v[d]=b,S.set(ds,v)}const ps="editor-workspace.tabs",us="editor-workspace.folded",ft="editor-workspace.css",wr="/__block-preview",Sr=d=>d.replace(/<\/head>/i,"<style>body.dm-cloaked{opacity:1 !important;transition:none !important}</style></head>");function Er(d,b,v=()=>{}){let i=0;try{i=d.contentWindow.scrollY||0}catch{}d.addEventListener("load",()=>{try{d.contentWindow.scrollTo(0,i)}catch{}v()},{once:!0}),d.srcdoc=b}const Tr=["urlPath","title","description","layout","status","sortOrder","category","visibility","project","theme","seoTitle","seoDesc","seoSchema","dconfig"],Mr=["showInNav","sidebar","breadcrumbs","bundled"],ms=()=>({urlPath:"",title:"",description:"",layout:"",status:"draft",sortOrder:"99",showInNav:!1,sidebar:!1,breadcrumbs:!0,bundled:!1,tags:[],adminTags:[],category:"",visibility:"public",project:"",theme:"",seoTitle:"",seoDesc:"",seoSchema:"",dconfig:"",body:"",css:null});export const pageEditorView={templateUrl:"/admin/js/templates/page-editor.html",async onMount(d){if(kr(),F){const e=F;F=null,e.dispose()}const b=window.location.hash.replace(/^#/,""),v=[],i=e=>(v.push(e),e);let y=()=>!1,p=()=>{},w=()=>{};const k=d.get(0),x=k.querySelector("#pe-workspace"),j={address:b,alive:()=>x?.isConnected===!0,dirty:()=>y(),keepDraft:()=>p(),open:(e,t)=>w(e,t),dispose:()=>{v.splice(0).forEach(e=>{try{e()}catch{}})}};F=j;const c=()=>F===j&&j.alive();if(yr().closeSidebar===!0){const e=document.querySelector("#admin-sidebar");e&&!Ja(e)&&!window.matchMedia("(max-width: 768px)").matches&&(Wa(e,!0,!1),i(()=>{e.isConnected&&Ja(e)&&Wa(e,!1,!1)}))}const A=E.loader(k,{type:"dots"});let[H,Y,D,se,Vt,T,ne,Oe]=await Promise.all([h.layouts.get().catch(()=>({})),h.settings.get().catch(()=>({})),h.pages.list().catch(()=>[]),h.projects.list().catch(()=>[]),h.pages.tags().catch(()=>[]),h.listTags.list("pages").then(e=>e.map(t=>t.name)).catch(()=>[]),h.get("/blocks?usage=1").catch(()=>h.blocks.list()).catch(()=>[]),h.components.list().catch(()=>[])]);if(!c()){A.destroy();return}A.destroy();const O=e=>k.querySelector(e);if(D=Array.isArray(D)?D:[],cn(O("#field-theme"),{includeDefault:!0}),await Ar(O("#field-visibility")),!c())return;const re=Object.keys(H||{});Or(O("#field-layout"),H,re[0]||"default");const Ho=e=>re.includes(e)?e:re[0]||e||"default";for(const e of se)for(const t of["#field-project","#block-project","#comp-project"])O(t).append(new Option(e.name||e.slug,e.slug));let ie=Array.isArray(ne)?ne:[],bt=Ya(ie);const vt=new Map(ie.map(e=>[e.name,e.updatedAt])),Ue=new Map(ie.map(e=>[e.name,e.usage])),be=new Set(ie.map(e=>e.name)),Vo=async()=>{const e=await h.get("/blocks?usage=1").catch(()=>null);if(!(!c()||!Array.isArray(e))){ie=e,bt=Ya(ie);for(const t of ie)be.add(t.name),Ue.set(t.name,t.usage),vt.has(t.name)||vt.set(t.name,t.updatedAt)}},_t=Array.isArray(Y?.footer?.blocks)?Y.footer.blocks.filter(e=>typeof e=="string"):[];let Je=Array.isArray(Oe)?Oe.filter(e=>typeof e?.name=="string"):[];const le=new Set(Je.map(e=>e.name)),_o=async()=>{const e=await h.components.list().catch(()=>null);if(!(!c()||!Array.isArray(e))){Je=e.filter(t=>typeof t?.name=="string");for(const t of Je)le.add(t.name)}},Z=Pe(),u={urlPath:M.observable(""),title:M.observable(""),description:M.observable(""),layout:M.observable(Ho("default")),status:M.observable("draft"),sortOrder:M.observable("99"),showInNav:M.observable(!1),sidebar:M.observable(!1),breadcrumbs:M.observable(!0),bundled:M.observable(!1),tags:M.observable([]),adminTags:M.observable([]),category:M.observable(""),visibility:M.observable("public"),project:M.observable(""),theme:M.observable(""),seoTitle:M.observable(""),seoDesc:M.observable(""),seoSchema:M.observable(""),dconfig:M.observable(""),css:M.observable(""),cssOpened:M.observable(!1)},a={bodyRev:M.observable(0),base:M.observable(""),saving:M.observable(!1),viewMode:M.observable(jo(Z.viewMode)),fullscreen:M.observable(!!Z.fullscreen),explorerOn:M.observable(Z.explorer??!window.matchMedia("(max-width: 1024px)").matches),dockOn:M.observable(!!Z.dock),dockTab:M.observable("details"),seoSchemaNote:M.observable(""),cssMode:M.observable(!1),folded:M.observable(!1),previewStatus:M.observable("Showing unsaved changes"),liveWidth:M.observable("full"),versions:M.observable([]),histLoading:M.observable(!1),histError:M.observable(""),compare:M.observable(null),heldNote:M.observable(""),tabs:M.observable([]),active:M.observable(""),curId:M.observable(null),blockTab:M.observable(""),blockPart:M.observable("html"),blockReady:M.observable(!1),blockNote:M.observable(""),blockUses:M.observable(""),blockProject:M.observable(""),blockBundled:M.observable(!1),blockWhere:M.observable(""),compTab:M.observable(""),compPart:M.observable("template"),compReady:M.observable(!1),compNote:M.observable(""),compReadOnly:M.observable(!1),compState:M.observable(""),compErrors:M.observable(""),compProject:M.observable(""),compBundled:M.observable(!1),blockRev:M.observable(0),compRev:M.observable(0),docRev:M.observable(0),filter:M.observable(""),secHere:M.observable(Z.secHere!==!1),secPages:M.observable(Z.secPages!==!1),secBlocks:M.observable(Z.secBlocks!==!1),secComps:M.observable(Z.secComps!==!1),thisPage:M.observable([]),pageRows:M.observable([]),blockRows:M.observable([]),compRows:M.observable([])},V=O("#markdown-editor"),ve=O("#css-editor"),fs=_a(V),bs=_a(ve);i(()=>fs.destroy()),i(()=>bs.destroy());const ce=document.createElement("div");ce.className="editor-line-numbers editor-line-numbers--foldable",V.parentElement.insertBefore(ce,V);const We=ns(V,"md"),Kt=ns(ve,"css");i(()=>{We.destroy(),Kt.destroy()});const Ko=()=>{We.paint(),Kt.paint()},Q=dn(V,ce,{onFoldChange:()=>We.paint()});let gt=!1;Q.setGuard(e=>{gt=e});const Ut=()=>Q.getUnfoldedContent(),Jt=()=>{Q.unfoldAll(),a.folded.value=!1,We.paint()},vs=e=>{if(e?.kind==="page")Jt(),_e(V,"md");else if(e?.kind==="block")oe&&_e(oe.textarea,"html"),me&&_e(me.textarea,"css");else if(e?.kind==="component"){if(N.get(e.id)?.readOnly)return;for(const[o,s]of Object.entries({template:"html",props:"json",script:"js",style:"css"}))ae[o]&&_e(ae[o].textarea,s)}},Uo=e=>{e.error?E.toast(e.error,{type:"warning"}):E.toast(e.unchanged?"Already tidy":"Formatted",{type:"info",duration:900})},Jo=M.observable(Bt(Z.type)),Wo=M.observable(qt(Z.code));i(M.effect(()=>{const e=Wo.value;dr(e),O("#editor-body")?.style.setProperty("--pe-tab",String(e.size))})),i(M.effect(()=>{const e=Jo.value,t=O("#editor-body");if(t){is(e.font);for(const[o,s]of Object.entries(Va(e)))t.style.setProperty(o,s);t.classList.toggle("pe-nowrap",!e.wrap),V.wrap=e.wrap?"soft":"off",ve.wrap=e.wrap?"soft":"off",requestAnimationFrame(()=>{c()&&Ko()})}}));let Yo=null;i(()=>{try{Yo?.close()}catch{}});const _=()=>(a.bodyRev.value,{urlPath:u.urlPath.value.trim(),title:u.title.value,description:u.description.value,layout:u.layout.value,status:u.status.value,sortOrder:u.sortOrder.value,showInNav:u.showInNav.value,sidebar:u.sidebar.value,breadcrumbs:u.breadcrumbs.value,bundled:u.bundled.value,tags:u.tags.value,adminTags:u.adminTags.value,category:u.category.value,visibility:u.visibility.value,project:u.project.value,theme:u.theme.value,seoTitle:u.seoTitle.value,seoDesc:u.seoDesc.value,seoSchema:u.seoSchema.value,dconfig:u.dconfig.value,body:Ut(),css:null}),Go=()=>M.untracked?M.untracked(_):_(),ee=M.observable(""),ht=()=>u.cssOpened.peek()&&u.css.peek()!==ee.peek(),K=new Map;let m=null;const L=new Map,N=new Map;let P=[];const de=e=>Do(e.form)!==e.base,ge=()=>[...L.entries()].filter(([,e])=>de(e)).map(([e])=>e),he=e=>!e.readOnly&&Fo({name:e.name,...e.form})!==e.base,Ye=()=>[...N.values()].filter(he).map(e=>e.name),Wt=()=>W(Go())!==a.base.peek(),Yt=e=>e.loaded&&(e===m?Wt():W(e.state)!==e.base),Ae=()=>[...K.values()].filter(Yt),gs=M.computed(()=>W(_())!==a.base.value),hs=M.computed(()=>u.cssOpened.value&&u.css.value!==ee.value),ks=M.computed(()=>(a.blockRev.value,a.compRev.value,a.docRev.value,W(_())!==a.base.value||u.cssOpened.value&&u.css.value!==ee.value||Ae().some(e=>e!==m)||ge().length>0||Ye().length>0)),ys=M.computed(()=>{a.blockRev.value,a.compRev.value;const e=I(a.active.value);if(e?.kind==="block"){const t=L.get(e.id);return!!(t&&de(t))}if(e?.kind==="component"){const t=N.get(e.id);return!!(t&&he(t))}return W(_())!==a.base.value||u.cssOpened.value&&u.css.value!==ee.value}),ws=M.computed(()=>a.curId.value!==null),Xo=M.computed(()=>I(a.active.value)?.kind||""),Zo=M.computed(()=>!!a.curId.value&&I(a.active.value)?.kind==="page"),Ss=M.computed(()=>u.urlPath.value.trim()||a.curId.value||""),Es=M.computed(()=>Ao({urlPath:u.urlPath.value,dconfig:u.dconfig.value})[0]?.text||""),Ts=M.computed(()=>{a.docRev.value;const e=I(a.active.value);return e?e.kind==="block"?a.blockUses.value:e.kind==="component"?Un({name:e.id,readOnly:a.compReadOnly.value,state:a.compReady.value?a.compState.value:""}):Xn({urlPath:u.urlPath.value,status:u.status.value,isEdit:!!a.curId.value}):""}),Qo=M.computed(()=>a.compTab.value?"component":a.blockTab.value?"block":a.curId.value!==null?"page":""),Ms=M.computed(()=>a.blockTab.value?`[${a.blockTab.value} /]`:""),Cs=M.computed(()=>({compiling:"Compiling\u2026",ok:"Compiles",error:"Does not compile"})[a.compState.value]||""),xs=M.computed(()=>a.compTab.value?`<dm-${a.compTab.value}>`:""),Ps=M.computed(()=>a.versions.value.some(e=>e.checked.value)),Os=M.computed(()=>a.versions.value.length>0&&a.versions.value.every(e=>e.checked.value)),As=M.computed(()=>{const e=a.versions.value.filter(t=>t.checked.value).length;return e>0&&e<a.versions.value.length});y=()=>Ae().length>0||ge().length>0||Ye().length>0||ht();const Gt=(e,t,o)=>({title:String(e.title||"").trim()||"Untitled",description:String(e.description||"").trim(),layout:e.layout,status:e.status,sortOrder:parseInt(String(e.sortOrder),10)||99,showInNav:!!e.showInNav,sidebar:!!e.sidebar,...e.breadcrumbs?{}:{breadcrumbs:!1},...e.bundled?{bundled:!0}:{},tags:Array.isArray(e.tags)?e.tags:[],...t?.isEdit&&JSON.stringify(e.adminTags)===t.savedAdminTags?{}:{adminTags:Array.isArray(e.adminTags)?e.adminTags:[]},category:String(e.category||"").trim()||null,visibility:e.visibility||"public",project:e.project||"",seo:{title:String(e.seoTitle||"").trim(),description:String(e.seoDesc||"").trim(),...ea(e)?{schema:ea(e)}:t?.isEdit?{schema:null}:{}},dconfig:o,...e.theme?{theme:e.theme}:{}}),ea=e=>Po(e.seoSchema).value,Xt=e=>{const t=String(e.dconfig||"").trim();if(!t)return null;try{return JSON.parse(t)}catch{return null}},Rs=()=>u.urlPath.peek().trim()||m?.id||"/";let kt=[],ta=[];const yt=e=>kt.includes(e)||_t.includes(e);let Re=new Set;const wt=()=>{const e=[...new Set([...kt,..._t,...L.keys()])],t=Pn(e.filter(s=>!L.has(s)),vt);Re=new Set(Object.keys(t));const o=Re.size?`Preview shows unsaved changes to ${[...Re].join(", ")}`:"";return o!==a.heldNote.peek()&&(a.heldNote.value=o),In(t,[...L.entries()].map(([s,r])=>({name:s,content:r.form.content,css:r.form.css,dirty:de(r)})))};let Zt="";const $s=()=>{oa();const e=Zt;if(e){Zt="";try{$e.contentDocument?.querySelector(`[data-block="${CSS.escape(e)}"]`)?.scrollIntoView({block:"center"})}catch{}}},$e=O("#markdown-preview");h.settings.getCustomCss().then(({css:e})=>{if(!c())return;ee.value=e||"";let t=null;try{t=S.get(ft)}catch{}typeof t=="string"&&t!==ee.peek()?(ia(),u.css.value=t,E.toast("Your unsaved custom CSS is back - the CSS button shows it.",{type:"info"})):u.cssOpened.peek()||(u.css.value=ee.peek()),J(ft)}).catch(()=>{});const oa=()=>{const e=$e?.contentDocument;if(!e?.head)return;const t=u.cssOpened.peek()?u.css.peek():"";if(!t)return;let o=e.getElementById("preview-custom-css");o||(o=e.createElement("style"),o.id="preview-custom-css",e.head.appendChild(o)),o.textContent=t};let Qt=null,eo=0;const U=(e=!1)=>{clearTimeout(Qt),Qt=setTimeout(async()=>{if(!$e||a.viewMode.peek()==="write"||!a.active.peek()||a.compTab.peek())return;const t=++eo,o=a.blockTab.peek();a.previewStatus.value="Rendering\u2026";try{let s;if(o&&(!m||!yt(o)))({html:s}=await h.pages.previewFull(wr,{title:o,layout:"blank",breadcrumbs:!1},Hn(o,Vs(o)),wt()));else if(m){const r=_();({html:s}=await h.pages.previewFull(Rs(),Gt(r,m,Xt(r)),r.body,wt()))}else{$e.srcdoc="";return}if(!c()||t!==eo)return;Er($e,Bn(Sr(s),o),$s),a.previewStatus.value="Showing unsaved changes"}catch(s){if(!c()||t!==eo)return;a.previewStatus.value="Preview failed - "+(s?.message||"unknown error"),$e.srcdoc='<!doctype html><meta charset="utf-8"><body style="font:14px system-ui;padding:1rem;color:#b91c1c;">Preview failed: '+String(s?.message||"unknown error").replace(/[<&]/g,r=>r==="<"?"<":"&")+"</body>"}},e?0:500)};i(()=>clearTimeout(Qt));const to=an(d.find("#markdown-editor"),d.find("#editor-toolbar"),{spacerDefault:Y?.layoutOptions?.spacerSize??40,beforeFormat:()=>Jt()});rn(V,{blocks:()=>bt,openBlock:e=>Be(e)});const Ge=k.querySelector(".editor-toolbar-right");Ge.querySelectorAll(".editor-view-btn[data-mode]").forEach(e=>{const t=e.getAttribute("data-mode");e.classList.remove("active"),e.setAttribute("data-bind-class",`viewMode.value === '${t}' && 'active'`),e.setAttribute("data-on-click",`setMode('${t}')`)}),O("#fullscreen-btn")?.setAttribute("data-on-click","toggleFullscreen");const Ls=mt(`
|
|
126
128
|
<span class="pe-toolbar-extras" style="display:contents">
|
|
127
129
|
<button type="button" class="editor-view-btn" data-tip="Edit Custom CSS" data-on-click="toggleCss"
|
|
128
130
|
data-bind-class="cssMode.value && 'active'"><span>CSS</span></button>
|
|
@@ -134,8 +136,8 @@ The quick brown fox - 0O 1lI {} [] () => ==
|
|
|
134
136
|
<span class="pe-fold-icon" hidden data-bind-hidden="!folded.value"><span data-icon="chevrons-right" data-icon-size="10"></span></span>
|
|
135
137
|
</button>
|
|
136
138
|
<span class="editor-toolbar-sep"></span>
|
|
137
|
-
</span>`);Ge.prepend(Ls),Ge.before(O(".pe-block-bar")),Ge.before(O(".pe-comp-bar"));const aa=e=>(Array.isArray(e)?e:[]).map(t=>({value:t,label:t})),sa=O("#field-tags");let St=null;St=sa?E.pillbox(sa,{data:aa(_t),value:[],creatable:!0,searchable:!0,placeholder:"Add tag\u2026",onChange:()=>{St&&(p.tags.value=[...St.getValue()])}}):null;const na=O("#field-admin-tags");let Et=null;Et=na?E.pillbox(na,{data:aa(T),value:[],creatable:!0,searchable:!0,placeholder:"Add admin tag\u2026",onChange:()=>{Et&&(p.adminTags.value=[...Et.getValue()])}}):null;const ra=()=>{a.bodyRev.value=a.bodyRev.peek()+1},Le=()=>{a.blockRev.value=a.blockRev.peek()+1},ke=()=>{a.compRev.value=a.compRev.peek()+1},Xe=()=>{a.docRev.value=a.docRev.peek()+1},ia=()=>{p.cssOpened.peek()||(p.css.peek()||(p.css.value=ee.peek()),p.cssOpened.value=!0,on(ve,{language:"css"}))},Ze=e=>{for(const t of Mr)p[t].value=e[t]==null?"":String(e[t]);for(const t of Tr)p[t].value=!!e[t];p.tags.value=Array.isArray(e.tags)?e.tags:[],St?.setValue(p.tags.peek()),Array.isArray(e.adminTags)&&(p.adminTags.value=e.adminTags),Et?.setValue(p.adminTags.peek()),qo(O("#field-visibility"),p.visibility.peek()),Q.unfoldAll(),a.folded.value=!1,gt=!0,_.value=e.body==null?"":String(e.body),gt=!1,Q.refresh(),Uo(),ra()},la=(e,t)=>({urlPath:t||"",title:e?.title||"",description:e?.description||"",layout:Vo(e?.layout||"default"),status:e?.status||"draft",sortOrder:String(e?.sortOrder??99),showInNav:!!e?.showInNav,sidebar:!!e?.sidebar,breadcrumbs:e?e.breadcrumbs!==!1:!0,bundled:!!e?.bundled,tags:Array.isArray(e?.tags)?e.tags:[],adminTags:Array.isArray(e?.adminTags)?e.adminTags:[],category:e?.category||"",visibility:typeof e?.visibility=="string"&&e.visibility?e.visibility:"public",project:Cn({isEdit:!!t,page:e,projects:se,fromHash:t?"":Ft()||"",urlPath:t||""}),theme:e?.theme||"",seoTitle:e?.seo?.title||"",seoDesc:e?.seo?.description||"",seoSchema:fn(e?.seo?.schema),dconfig:e?.dconfig?JSON.stringify(e.dconfig,null,2):"",body:e?.content||"",css:null}),ca=()=>{m&&(m.state=K(),m.at=Date.now())},da=e=>{m!==e&&(ca(),m=e,Ze(e.state),a.base.value=e.base,a.curId.value=e.id,e.at=Date.now(),Tt(),Xe())},Ns=()=>{ca(),m=null;const e=ms();Ze(e),a.base.value=W(e),a.curId.value=null,Tt(),Xe()};Ze(ms()),a.base.value=W(K());const J=e=>{try{S.remove?S.remove(e):S.set(e,null)}catch{}},pa=(e,t)=>({name:e.name,...e.form,base:e.base,at:t});u=()=>{try{for(const t of Re())S.set(ze(t.id),Ua(t===m?Go():t.state,t.base));ht()&&S.set(ft,p.css.peek());const e=new Date().toISOString();for(const t of ge()){const o=L.get(t);S.set(Ve(t),{form:{...o.form},base:o.base,at:e})}for(const t of Ye())S.set(_e(t),pa(N.get(t),e))}catch{}};const ua=e=>{y()&&(u(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",ua),i(()=>window.removeEventListener("beforeunload",ua));let Qe=!1,Mt=null;const Tt=()=>{Qe=!1,Mt=null,a.versions.value=[],a.compare.value=null,a.histError.value="",a.dockOn.peek()&&a.dockTab.peek()==="history"&&(m?.isEdit?pe():a.dockTab.value="details")},pe=async()=>{const e=m;if(e?.isEdit){Qe=!0,a.histLoading.value=!0,a.histError.value="";try{const t=(await h.versions.list(e.id)).versions||[];if(!c()||m!==e)return;a.versions.value=t.map(o=>({...o,when:qe(o.createdAt),author:o.author||"",label:o.label||"",who:[o.author,o.label].filter(Boolean).join(" - "),checked:M.observable(!1)}))}catch(t){m===e&&(a.histError.value="Failed to load versions: "+t.message)}finally{m===e&&(a.histLoading.value=!1)}}},oo=e=>a.versions.peek().find(t=>t.filename===e),ao=async e=>{const t=m;try{const o=await h.versions.get(t.id,e.filename);if(!c()||m!==t)return;Mt=e.filename,a.compare.value={label:rs(e),old:o.content,current:Ht()}}catch(o){E.toast("Failed to load version: "+o.message,{type:"error"})}},Ds=async()=>{const e=m;if(!e?.isEdit)return;const t=await h.pages.get(e.id).catch(()=>null);if(!c()||m!==e||!t)return;e.page=t;const o=la(t,e.id);e.base=W(o),e.savedAdminTags=JSON.stringify(o.adminTags),Ze(o),a.base.value=e.base,Tt(),a.dockOn.peek()&&a.dockTab.peek()==="history"&&pe(),H()},ma=async e=>{if(!(!e||!await E.confirm("Restore this version? The current page content will be overwritten (a pre-restore snapshot will be saved automatically).")))try{await h.versions.restore(m.id,e),E.toast("Page restored.",{type:"success"}),await Ds()}catch(t){E.toast("Restore failed: "+t.message,{type:"error"})}},js=async e=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await h.versions.delete(m.id,e.filename),E.toast("Version deleted.",{type:"success"}),await pe()}catch(t){E.toast("Failed to delete: "+t.message,{type:"error"})}},Ne=new Map,Bs=e=>{if(!Ne.has(e)){const t=I(e);Ne.set(e,{id:e,kind:t.kind,kindText:t.kind==="page"?"Page":t.kind==="component"?"Component":"Block",label:M.observable(""),title:M.observable(""),active:M.observable(!1),dirty:M.observable(!1)})}return Ne.get(e)},fa=e=>{const t=e===m?p.title.peek():e?.loaded?e.state.title:D.find(o=>o.urlPath===e?.id)?.title;return String(t||"").trim()||e?.id||"New page"};let ba=!0,va="";const Is=()=>{if(ba)return;const e={ids:P,active:a.active.peek()},t=JSON.stringify(e);if(t!==va){va=t;try{S.set(ps,e)}catch{}}},q=()=>{const e=P.map(Bs);for(const t of e){const o=I(t.id);let s,r;if(o.kind==="page"){const l=U.get(o.id);s=fa(l),r=l?.loaded?Yt(l):xe(o),t.title.value=o.id?`${s} (${o.id})`:"New page"}else if(o.kind==="component"){const l=N.get(o.id);s=o.id,r=l?he(l):xe(o),t.title.value=`Component <dm-${o.id}>`}else{const l=L.get(o.id);s=o.id,r=l?de(l):Ae.has(o.id)||xe(o),t.title.value=`Block ${o.id}`}t.label.peek()!==s&&(t.label.value=s),t.dirty.peek()!==r&&(t.dirty.value=r);const n=t.id===a.active.peek();t.active.peek()!==n&&(t.active.value=n)}e.map(t=>t.id).join("|")!==a.tabs.peek().map(t=>t.id).join("|")&&(a.tabs.value=e),Is()};let ye=new Set;try{const e=S.get(us);Array.isArray(e)&&(ye=new Set(e.filter(t=>typeof t=="string")))}catch{}const ga=new Map,so=e=>{let t=ga.get(e.key);return t?(t.label.peek()!==e.label&&(t.label.value=e.label),t.meta.peek()!==(e.meta||"")&&(t.meta.value=e.meta||""),t.status.peek()!==(e.status||"")&&(t.status.value=e.status||""),t.folder.peek()!==!!e.folder&&(t.folder.value=!!e.folder)):(t={...e,label:M.observable(e.label),meta:M.observable(e.meta||""),status:M.observable(e.status||""),folder:M.observable(!!e.folder),active:M.observable(!1),dirty:M.observable(!1),folded:M.observable(!1),title:""},ga.set(e.key,t)),t.title=e.kind==="block"||e.kind==="component"?e.meta?`${e.id} - ${e.meta}`:e.id:e.kind==="folder"?e.meta:`${e.label} (${e.meta})`,t},no=new Map,z=()=>{const e=a.filter.peek(),t=I(a.active.peek()),o=t?.kind==="page"?t.id:null,s=t?.kind==="block"?t.id:null,r=t?.kind==="component"?t.id:null,n=new Set(Re().map(f=>f.id)),l=Gn(D,{filter:e,folded:ye}).map(so);for(const f of l){const C=f.kind==="page"&&f.id===o,B=f.kind==="page"&&(n.has(f.id)||!U.get(f.id)?.loaded&&xe({kind:"page",id:f.id})),fe=ye.has(f.id);f.active.peek()!==C&&(f.active.value=C),f.dirty.peek()!==B&&(f.dirty.value=B),f.folded.peek()!==fe&&(f.folded.value=fe)}const g=_n(ie,e).map(so),$=f=>{const C=L.get(f);return C?de(C):Ae.has(f)||xe({kind:"block",id:f})};for(const f of g){const C=f.id===s,B=$(f.id);f.active.peek()!==C&&(f.active.value=C),f.dirty.peek()!==B&&(f.dirty.value=B)}const G=Un(Je,e).map(so),Te=f=>{const C=N.get(f);return C?he(C):xe({kind:"component",id:f})};for(const f of G){const C=f.id===r,B=Te(f.id);f.active.peek()!==C&&(f.active.value=C),f.dirty.peek()!==B&&(f.dirty.value=B)}const Co=m?Dn(kt,Kt,be):[],za=(f,C,B)=>(no.has(f)||no.set(f,{key:f,id:C,label:B,kindText:"",title:"",active:M.observable(!1),dirty:M.observable(!1)}),no.get(f)),xo=Co.map(f=>{const C=za(`block:${f.name}`,f.name,f.name);C.kindText=f.footer?"Footer":"Block",C.title=`${f.name} - ${f.footer?"in the footer, on every page":"a block on this page"}`;const B=f.name===s,fe=$(f.name);return C.active.peek()!==B&&(C.active.value=B),C.dirty.peek()!==fe&&(C.dirty.value=fe),C});for(const f of ta){const C=za(`component:${f}`,f,f);C.kindText="Component",C.title=`<dm-${f}> - a component on this page`;const B=f===r,fe=Te(f);C.active.peek()!==B&&(C.active.value=B),C.dirty.peek()!==fe&&(C.dirty.value=fe),xo.push(C)}const Dt=(f,C)=>f.map(B=>B.key).join("|")===C.map(B=>B.key).join("|");Dt(l,a.pageRows.peek())||(a.pageRows.value=l),Dt(g,a.blockRows.peek())||(a.blockRows.value=g),Dt(G,a.compRows.peek())||(a.compRows.value=G),Dt(xo,a.thisPage.peek())||(a.thisPage.value=xo)},ha=async()=>{const e=await h.pages.list().catch(()=>null);!c()||!Array.isArray(e)||(D=e,z(),q())},te=()=>{const e=I(a.active.peek()),t=e?es(e):"/pages/new",o=window.location.hash.replace(/^#/,"");j.address=o.split("?")[0]===t?o:t,o.split("?")[0]!==t?history.replaceState({pe:1},"","#"+t):history.state?.pe||history.replaceState({pe:1},"",window.location.hash)},Fs=async e=>{if(e.loading)return e.loading;e.loading=(async()=>{let t=null;if(e.isEdit){if(t=await h.pages.get(e.id).catch(()=>null),!c())return!1;if(!t)return E.toast(`Page ${e.id} not found.`,{type:"error"}),!1}e.page=t;const o=la(t,e.id);e.state=o,e.base=W(o),e.savedAdminTags=JSON.stringify(o.adminTags),e.loaded=!0;let s=null;try{s=S.get(ze(e.id))}catch{}const r=xn(s),n=$o({kind:"page",id:e.id});if(r){J(ze(e.id));const l=W(r.state)!==e.base,g=Tn(r,e.base),$={...o,...r.state,adminTags:o.adminTags};if(l&&n&&!g)e.state=$,E.toast(`Your unsaved changes to ${e.id||"the new page"} are back.`,{type:"info"});else if(l){const G=r.at?` (${qe(r.at)})`:"",Te=g?" The saved page has changed since - restoring puts your version back over it (the saved one stays in History).":"";await E.confirm(`You left unsaved changes to ${e.id||"a new page"}${G}. Restore them?${Te}`)&&c()&&(e.state=$)}}return!0})();try{return await e.loading}finally{e.loading=null}},ka=e=>(U.has(e)||U.set(e,{kind:"page",id:e,isEdit:!!e,loaded:!1,page:null,state:null,base:"",savedAdminTags:"[]",at:0}),U.get(e)),ue=async e=>{const t=X({kind:"page",id:e});({ids:P}=Bo(P,t)),a.active.value=t,a.blockTab.value="",vo();const o=ka(e);if(q(),!o.loaded){a.previewStatus.value=`Opening ${e||"a new page"}\u2026`;const s=await Fs(o);if(!c()||!P.includes(t)||U.get(e)!==o)return;if(!s){ya(t);return}if(a.active.peek()!==t){q(),z();return}}da(o),te(),q(),z(),H(),Q.refresh(),_.focus()};w=async(e,t)=>{if(j.address=t,e.kind==="page"){ue(e.id);return}if(!e.id){(e.kind==="block"?Lt:nt)({project:Ft(t)||""});return}const o=e.kind==="block"?be:le;if(o.has(e.id)||await(e.kind==="block"?_o:Ko)(),!!c()){if(!o.has(e.id)){E.toast(`There is no ${e.kind} called "${e.id}".`,{type:"warning"}),te(),z();return}e.kind==="block"?Be(e.id):st(e.id)}};const ya=e=>{const t=a.active.peek(),o=Kn(P,e,t);P=o.ids,Ne.delete(e);const s=I(e),r=o.active!==t?I(o.active):null;if(s.kind==="page"){if(U.delete(s.id),m?.id===s.id){const n=[...U.values()].filter(l=>l.loaded&&l.id!==s.id).sort((l,g)=>g.at-l.at)[0];n?da(n):Ns()}}else s.kind==="component"?(N.delete(s.id),a.compTab.peek()===s.id&&vo()):(L.delete(s.id),a.blockTab.peek()===s.id&&(a.blockTab.value="",a.blockReady.value=!1));if(a.active.value=o.active,r?.kind==="page"){ue(r.id);return}if(r?.kind==="block"){Be(r.id);return}if(r?.kind==="component"){st(r.id);return}te(),Xe(),Le(),ke(),q(),z(),H()},et=e=>{const t=I(e);if(!t||!P.includes(e))return;let o="";try{if(t.kind==="page"){const s=U.get(t.id);s&&Yt(s)&&(S.set(ze(s.id),Ua(s===m?K():s.state,s.base)),Ao({kind:"page",id:s.id}),o=fa(s))}else if(t.kind==="component"){const s=N.get(t.id);s&&he(s)&&(S.set(_e(t.id),pa(s,new Date().toISOString())),Ao({kind:"component",id:t.id}),o=t.id)}else{const s=L.get(t.id);s&&de(s)&&(S.set(Ve(t.id),{form:{...s.form},base:s.base,at:new Date().toISOString()}),Ao({kind:"block",id:t.id}),o=t.id)}}catch{}ya(e),o&&E.toast(`Changes to "${o}" kept as a draft - back when you open it again.`,{type:"info"})},Ct=e=>{const t=I(e);t&&(t.kind==="page"?ue(t.id):t.kind==="component"?st(t.id):Be(t.id))},wa=new Set,zs=async e=>{const t=[];for(const o of e){const s=L.get(o);if(!s)continue;const r={...s.form};try{const n=Za(r,s.block?.meta);await h.blocks.put(o,n),s.block={...s.block,meta:n.meta},s.saved=r,s.base=Do(r),vt.set(o,new Date().toISOString()),c()&&J(Ve(o)),t.push(o)}catch(n){E.toast(`Block "${o}" not saved: ${n.message||"Unknown error"}`,{type:"error"})}}return t.forEach(o=>wa.add(o)),t.length&&(Le(),pt("#/blocks")),t},qs=async e=>{const t=e===m?K():e.state,o=Po(t.seoSchema).error;if(o)return E.toast(`${e.id||"The new page"} not saved - structured data: ${o}`,{type:"error"}),e===m&&(a.seoSchemaNote.value=o,a.dockOn.value=!0,a.dockTab.value="seo"),!1;const s=Gt(t,e,Xt(t)),r=e.id;try{if(e.isEdit){const n={frontmatter:s,body:t.body};t.urlPath!==e.id&&(n.newUrlPath=t.urlPath),await h.pages.update(e.id,n)}else await h.pages.create({urlPath:t.urlPath,frontmatter:s,body:t.body})}catch(n){return E.toast(`${e.id||"The new page"} not saved: ${n.message||"Unknown error"}`,{type:"error"}),!1}if(!c())return!0;if(e.savedAdminTags=JSON.stringify(t.adminTags),e.base=W(t),e===m?a.base.value=e.base:e.state=t,J(ze(r)),!e.isEdit||t.urlPath!==e.id){U.delete(r),e.id=t.urlPath,e.isEdit=!0,U.set(e.id,e);const n=X({kind:"page",id:r}),l=X({kind:"page",id:e.id});Ne.delete(n),{ids:P}=Qn(P,n,l,a.active.peek()),a.active.peek()===n&&(a.active.value=l),e===m&&(a.curId.value=e.id,te())}return!0},Vs=async e=>{const t=[];for(const o of e){const s=N.get(o);if(!s||s.readOnly)continue;if(At===s?(clearTimeout(Rt),At=null,ke(),at(s)):s.state||at(s),s.compiling&&await s.compiling,!c())return t;if(s.state!=="ok"){E.toast(`Component "${o}" not saved: ${s.state==="error"?"it does not compile - fix the errors first.":"it has not compiled yet - try again in a moment."}`,{type:"warning"});continue}const r={...s.form},n={...s.meta||{}};delete n.bundled,r.project?n.project=r.project:delete n.project;try{await h.components.put(o,{source:r.source,bundled:r.bundled,meta:n}),s.meta=n,s.saved=r,s.base=Fo({name:o,...r});const l=Je.find(g=>g.name===o);l&&(l.bundled=r.bundled,l.meta=n),c()&&J(_e(o)),t.push(o)}catch(l){E.toast(`Component "${o}" not saved: ${l.message||"Unknown error"}`,{type:"error"})}}return t.length&&(ke(),pt("#/components")),t};let ro=!1;const io=async(e=!1)=>{if(a.saving.peek()||ro)return;ro=!0;let t,o,s=[];try{if(await Ea(),!c())return;const n=I(a.active.peek());if(lr().formatOnSave&&vs(n),e)t=Re(),o=ge(),s=Ye();else if(n?.kind==="block")t=[],o=L.has(n.id)&&de(L.get(n.id))?[n.id]:[];else if(n?.kind==="component")t=[],o=[],s=N.has(n.id)&&he(N.get(n.id))?[n.id]:[];else if(n?.kind==="page"&&m)o=ge().filter(yt),t=!m.isEdit||Wt()||!o.length?[m]:[];else return;if(!t.length&&!o.length&&!s.length){E.toast("Nothing to save.",{type:"info"});return}for(const g of t){const $=Ro(g===m?K():g.state);if($.length){E.toast(`${g.id||"New page"}: ${$[0].text}`,{type:"warning"}),g!==m&&await ue(g.id),a.dockOn.value=!0,a.dockTab.value=$[0].field==="dconfig"?"dconfig":"details",Ue("dock",!0);return}}const l=Fn(o,Object.fromEntries(o.map(g=>[g,Qa(He.get(g),m?.id||"")])),wa);if(l&&(!await E.confirm(l)||!c()))return}finally{ro=!1}const r=t.length>0&&ht();a.saving.value=!0;try{let n=0;for(const $ of t)await qs($)&&n++;if(!c())return;if(r){const $=p.css.peek();await h.settings.saveCustomCss($),ee.value=$,J(ft)}const l=await zs(o);if(!c())return;const g=await Vs(s);if((n||l.length||g.length)&&E.toast(zn({pages:n,css:r,blocks:l,components:g}),{type:"success"}),Xe(),!c())return;q(),z(),n&&(pt("#/pages"),Tt(),ha())}catch(n){E.toast(`Save failed: ${n.message||"Unknown error"}`,{type:"error"})}finally{a.saving.value=!1}};let oe=null,me=null;const De=new Map,je=new Map,Sa=()=>{const e=L.get(a.blockTab.peek());!e||!oe||(a.blockReady.value=!1,oe.setValue(e.form.content),me.setValue(e.form.css),a.blockProject.value=e.form.project,qo(O("#block-project"),e.form.project),a.blockBundled.value=e.form.bundled,a.blockWhere.value=An({usage:He.get(e.form.name)})||"Where it is used could not be read.",a.blockNote.value="",a.blockReady.value=!0,uo())},_s=e=>{const t=L.get(e);if(!t)return{};const o=t.form.content;return Object.fromEntries(ts(Ga(o),No(o),t.samples||{}).map(s=>[s.name,s.value]))};i(M.effect(()=>{const e=a.blockProject.value,t=a.blockBundled.value,o=L.get(a.blockTab.peek());!o||!a.blockReady.peek()||o.form.project===e&&o.form.bundled===t||(o.form.project=e,o.form.bundled=t,Le())}));const lo=async(e,{quiet:t=!1}={})=>{for(;De.has(e);)if(await De.get(e),L.has(e)||t)return L.get(e)||null;if(L.has(e))return L.get(e);const o=(async()=>{try{const s=await h.blocks.get(e);if(!c()||!t&&!P.includes(X({kind:"block",id:e})))return null;const r=Xa({...s,name:e}),n={block:s,saved:r,base:Do(r),form:{...r},samples:{}};let l=null;try{l=S.get(Ve(e))}catch{}const g=Ln(l,n.base);if(t&&g?.stale)return null;if($o({kind:"block",id:e}),g){const $=g.at?` (${qe(g.at)})`:"",G=!g.stale||await E.confirm(`You left unsaved changes to "${e}"${$}, but the block has been saved since. Restore your version anyway?`);if(!c())return null;G&&(n.form={...n.form,...g.form,name:e},g.stale||E.toast(`Your unsaved changes to "${e}" are back.`,{type:"info"}))}return l&&J(Ve(e)),L.set(e,n),Le(),n}catch(s){return c()&&a.blockTab.peek()===e&&(a.blockNote.value=`Could not open "${e}": ${s.message||"unknown error"}`),null}finally{De.delete(e)}})();return De.set(e,o),o},Ea=async()=>{for(;De.size||je.size;)await Promise.all([...De.values(),...je.values()])},Be=async e=>{if(!e||!be.has(e))return;const t=X({kind:"block",id:e});({ids:P}=Bo(P,t)),a.active.value=t,vo(),a.cssMode.peek()&&(a.cssMode.value=!1),a.viewMode.peek()==="preview"&&(a.viewMode.value="split"),a.blockTab.peek()!==e&&(a.blockReady.value=!1),a.blockTab.value=e,a.blockUses.value=m&&yt(e)?qn(Qa(He.get(e),m.id||"")):jn(He.get(e)),te(),q(),z();let o=L.get(e);o||(a.blockReady.value=!1,a.blockNote.value=`Opening ${e}\u2026`,o=await lo(e)),!(!o||!c()||a.blockTab.peek()!==e)&&(Sa(),q(),z(),Zt=e,H(),(a.blockPart.peek()==="css"?me:oe)?.focus())};let co=null;i(()=>clearTimeout(co));const Ma=(e,t)=>{const o=L.get(a.blockTab.peek());!o||!a.blockReady.peek()||(o.form[e]=t,clearTimeout(co),co=setTimeout(()=>{Le(),e==="content"&&uo()},120),H())},we=O("#pe-block-samples"),Ta=e=>{we.replaceChildren();const t=document.createElement("p");t.className="pe-dock-none",t.textContent=e,we.appendChild(t)};let tt=[],po=null;function uo(){const e=L.get(a.blockTab.peek());if(!e){tt=[],po=null,Ta("Open a block to see its placeholders.");return}const t=ts(Ga(e.form.content),No(e.form.content),e.samples);if(!(po===e&&t.map(o=>o.name).join("|")===tt.join("|"))){if(tt=t.map(o=>o.name),po=e,!t.length){Ta("No {{placeholders}} in the template yet.");return}we.replaceChildren();for(const o of t){const s=document.createElement("div");s.className="pe-comp-prop",s.tabIndex=0,s.dataset.sample=o.name;const r=document.createElement("label");r.className="pe-comp-prop-label",r.textContent=o.name,r.title=o.raw?`{{{${o.name}}}} - raw markup`:`{{${o.name}}}`;const n=document.createElement("input");n.type="text",n.className="form-input form-input--sm pe-comp-prop-input",n.value=o.value,n.setAttribute("aria-label",`Sample value for ${o.name}`),n.addEventListener("input",()=>{e.samples[o.name]=n.value,H()});const l=document.createElement("button");l.type="button",l.className="pe-kebab",l.setAttribute("aria-label",`Actions for ${o.name}`),l.title="Actions",l.textContent="\u22EE",s.append(r,n,l),we.appendChild(s)}}}const mo=(e,t)=>No(e.form.content).has(t)?`{{{${t}}}}`:`{{${t}}}`,Ks=e=>{const t=L.get(a.blockTab.peek());return!t||!tt.includes(e)?[]:[{header:mo(t,e)},{label:"Insert into the template",icon:"corner-down-right",action:()=>{const o=oe?.textarea;o&&(a.blockPart.value="html",o.focus(),o.setRangeText(mo(t,e),o.selectionStart,o.selectionEnd,"end"),o.dispatchEvent(new Event("input",{bubbles:!0})))}},{label:"Copy the placeholder",icon:"copy",action:()=>Ie(mo(t,e),"Placeholder")},{type:"divider"},{label:"Reset the sample",icon:"rotate-ccw",action:()=>{delete t.samples[e],tt=[],uo(),H()}}]};{const e=E.contextMenu(we,{cursor:"glyph",match:".pe-comp-prop",inherit:!1,density:"compact",items:t=>Ks(t.dataset.sample)});i(()=>e?.destroy?.()),we.addEventListener("click",t=>{const o=t.target.closest(".pe-kebab");o&&Ce(o)}),we.addEventListener("keydown",t=>{const o=t.target.closest(".pe-comp-prop");o&&t.key==="F10"&&t.shiftKey&&(t.preventDefault(),Ce(o))})}const ae={},Se=O("#component-preview"),xt=e=>{try{Se?.contentWindow?.postMessage(e,"*")}catch{}};let fo=Se.contentDocument?.readyState==="complete"&&/component-preview/.test(Se.contentDocument?.URL||""),Pt=!1,ot=null;const Ca=()=>{fo=!0,ot&&c()&&(xt({type:"mount",payload:ot}),Pt=!0),ot=null};Se.addEventListener("load",Ca),i(()=>Se.removeEventListener("load",Ca));const Us=e=>{if(!fo){ot=e;return}if(!Pt){Pt=!0,xt({type:"mount",payload:e});return}ot=e,fo=!1,Pt=!1,Se.src=Se.src};let Ot="";const bo=(e=!1)=>{const t=N.get(a.compTab.peek());if(!(!t||t.state!=="ok"||!t.js)){if(a.viewMode.peek()==="write"){t.previewStale=!0;return}!e&&Ot===t.name&&!t.previewStale||(t.previewStale=!1,Ot=t.name,Us({compiledJs:t.js,tagName:`dm-${t.name}`,props:t.previewProps}))}},at=e=>{const t=++e.seq;return e.state="compiling",a.compTab.peek()===e.name&&(a.compState.value="compiling"),e.compiling=(async()=>{let o;try{o=await h.components.compile(e.name,e.form.source)}catch(s){o={errors:[{type:"request",message:s.message||"Compile request failed."}]}}if(!(t!==e.seq||!c())){if(o.errors?.length?(e.state="error",e.errors=o.errors.map(s=>`[${s.type}] ${s.message}`).join(`
|
|
138
|
-
`),e.js=null):(e.state="ok",e.errors="",e.js=o.js),a.compTab.peek()!==e.name){e.previewStale=!0;return}a.compState.value=e.state,a.compErrors.value=e.errors,e.state==="ok"&&(yo(),bo(!0))}})().finally(()=>{e.compiling&&t===e.seq&&(e.compiling=null)}),e.compiling};let Rt=null,At=null;i(()=>clearTimeout(Rt));const xa=()=>{const e=N.get(a.compTab.peek());if(!e||!ae.template)return;a.compReady.value=!1;const t=ut(e.form.source);for(const o of zt)ae[o].setValue(t[o]),ae[o].textarea.readOnly=e.readOnly;a.compReadOnly.value=e.readOnly,a.compProject.value=e.form.project,qo(O("#comp-project"),e.form.project),a.compBundled.value=e.form.bundled,a.compState.value=e.state,a.compErrors.value=e.errors,a.compNote.value="",a.compReady.value=!0,yo(),e.state==="ok"?bo():e.state||at(e)},vo=()=>{a.compTab.peek()&&(a.compTab.value="",a.compReady.value=!1)},Pa={page:"details",block:"details",component:"details"};let $t="";i(M.effect(()=>{const e=Qo.value;e!==$t&&($t&&(Pa[$t]=a.dockTab.peek()),$t=e,e&&(a.dockTab.value=Pa[e]||"details",e==="page"&&a.dockTab.peek()==="history"&&a.dockOn.peek()&&m?.isEdit&&!Qe&&pe()))}));const go=async(e,{quiet:t=!1}={})=>{if(je.has(e))return je.get(e);if(N.has(e))return N.get(e);const o=(async()=>{try{const s=await h.components.get(e);if(!c()||!P.includes(X({kind:"component",id:e})))return null;const r=s.readOnly===!0||s.origin==="plugin",n={project:s.meta?.project||"",bundled:!!s.bundled,source:os(ut(s.source))},l={name:e,comp:s,saved:n,base:Fo({name:e,...n}),form:{...n},meta:s.meta||{},readOnly:r,state:"",errors:"",js:null,seq:0,compiling:null,previewProps:{},previewStale:!1};let g=null;try{g=S.get(_e(e))}catch{}const $=nr(g,l.base);if(t&&(!$.ok||$.stale||r))return null;const G=$o({kind:"component",id:e});if(t&&!G)return null;if($.ok&&!r){const Te=g.at?` (${qe(g.at)})`:"",Co=G&&!$.stale||await E.confirm($.stale?`You left unsaved changes to the component "${e}"${Te}, but it has been saved since. Restore your version anyway?`:`You left unsaved changes to the component "${e}"${Te}. Restore them?`);if(!c())return null;Co&&(l.form={project:String(g.project??""),bundled:g.bundled===!0,source:String(g.source)},G&&!$.stale&&E.toast(`Your unsaved changes to the component "${e}" are back.`,{type:"info"}))}return g&&J(_e(e)),N.set(e,l),ke(),l}catch(s){return c()&&a.compTab.peek()===e&&(a.compNote.value=`Could not open <dm-${e}>: ${s.message||"unknown error"}`),null}finally{je.delete(e)}})();return je.set(e,o),o},st=async e=>{if(!e||!le.has(e))return;const t=X({kind:"component",id:e});({ids:P}=Bo(P,t)),a.active.value=t,a.blockTab.value="",a.cssMode.peek()&&(a.cssMode.value=!1),a.viewMode.peek()==="preview"&&(a.viewMode.value="split"),a.compTab.value=e,te(),q(),z();let o=N.get(e);o||(a.compReady.value=!1,a.compReadOnly.value=!1,a.compState.value="",a.compNote.value=`Opening <dm-${e}>\u2026`,o=await go(e)),!(!o||!c()||a.compTab.peek()!==e)&&(xa(),q(),z(),ae[a.compPart.peek()]?.focus())},Hs=(e,t)=>{const o=N.get(a.compTab.peek());if(!o||!a.compReady.peek()||o.readOnly)return;const s=ut(o.form.source);s[e]=t,o.form.source=os(s),clearTimeout(Rt),At=o,Rt=setTimeout(()=>{At=null,ke(),at(o)},300)};i(M.effect(()=>{const e=a.compProject.value,t=a.compBundled.value,o=N.get(a.compTab.peek());!o||!a.compReady.peek()||o.readOnly||o.form.project===e&&o.form.bundled===t||(o.form.project=e,o.form.bundled=t,ke())}));const Ee=O("#pe-comp-props");let ho=[];const ko=e=>{Ee.replaceChildren();const t=document.createElement("p");t.className="pe-dock-none",t.textContent=e,Ee.appendChild(t)};function yo(){const e=N.get(a.compTab.peek());if(!e){ho=[],ko("Open a component to try its props.");return}const{rows:t,error:o}=as(ut(e.form.source).props,e.previewProps);if(ho=t,o){ko("The <props> block is not valid JSON - fix it to see the props here.");return}if(!t.length){e.previewProps={},ko("No props declared. Add them in the <props> block.");return}e.previewProps=Object.fromEntries(t.map(s=>[s.name,s.value])),Ee.replaceChildren();for(const s of t){const r=document.createElement("div");r.className="pe-comp-prop",r.tabIndex=0,r.dataset.prop=s.name;const n=document.createElement("label");n.className="pe-comp-prop-label",n.textContent=s.label,n.title=`${s.name} (${s.type})`;const l=s.type==="array"||s.type==="object"?document.createElement("textarea"):document.createElement("input");s.type==="boolean"?(l.type="checkbox",l.className="form-check",l.checked=ss(s.type,s.value)):(l.tagName==="INPUT"?l.type=s.type==="number"?"number":"text":l.rows=2,l.className="form-input form-input--sm pe-comp-prop-input",l.value=ss(s.type,s.value)),l.setAttribute("aria-label",s.label);const g=()=>{e.previewProps[s.name]=ir(s.type,s.type==="boolean"?l.checked:l.value),Ot===e.name&&xt({type:"update",payload:{props:e.previewProps}})};l.addEventListener("input",g),l.addEventListener("change",g);const $=document.createElement("button");$.type="button",$.className="pe-kebab",$.setAttribute("aria-label",`Actions for ${s.label}`),$.title="Actions",$.textContent="\u22EE",r.append(n,l,$),Ee.appendChild(r)}}const Ie=async(e,t)=>{try{await navigator.clipboard.writeText(e),E.toast(`${t} copied.`,{type:"success"})}catch{E.toast(e,{type:"info",duration:8e3})}},Js=e=>{const t=N.get(a.compTab.peek()),o=ho.find(n=>n.name===e);if(!t||!o)return[];const s=sr(o.name,o.type,t.previewProps[o.name]),r=`dm-${t.name}`;return[{header:o.label},{label:"Reset to its default",icon:"rotate-ccw",action:()=>{delete t.previewProps[o.name];const n=as(ut(t.form.source).props,{}).rows.find(l=>l.name===o.name);t.previewProps[o.name]=n?n.value:null,yo(),Ot===t.name&&xt({type:"update",payload:{props:t.previewProps}})}},{label:"Copy as an attribute",icon:"copy",disabled:!s,action:()=>Ie(s,"Attribute")},{label:"Copy the tag with this value",icon:"code",action:()=>Ie(`<${r}${s?` ${s}`:""}></${r}>`,"Tag")},{label:"Copy the prop name",icon:"copy",action:()=>Ie(o.name,"Name")},{type:"divider"},{label:"Edit in <props>",icon:"edit",action:()=>{a.compPart.value="props";const n=ae.props?.textarea;if(!n)return;const l=n.value.indexOf(`"${o.name}"`);n.focus(),l>=0&&n.setSelectionRange(l,l+o.name.length+2)}}]};{const e=E.contextMenu(Ee,{cursor:"glyph",match:".pe-comp-prop",inherit:!1,density:"compact",items:t=>Js(t.dataset.prop)});i(()=>e?.destroy?.()),Ee.addEventListener("click",t=>{const o=t.target.closest(".pe-kebab");o&&Ce(o)}),Ee.addEventListener("keydown",t=>{const o=t.target.closest(".pe-comp-prop");o&&t.key==="F10"&&t.shiftKey&&(t.preventDefault(),Ce(o))})}let Fe=!1;const Oa=()=>Ft()||"",Lt=async({project:e=Oa(),seed:t="",content:o=gr,css:s=""}={})=>{if(!Fe){Fe=!0;try{const n=await ls({kind:"block",projects:se,taken:[...be],project:e,name:t,check:Rn,register:i,create:async(l,g)=>{await h.blocks.put(l,Za({name:l,project:g,bundled:!1,content:o,css:s}))}});if(!c())return;if(!n){te();return}if(await _o(),!c())return;pt("#/blocks"),E.toast(`Created the block "${n}".`,{type:"success"}),Be(n)}finally{Fe=!1}}},nt=async({name:e="",source:t=ar,project:o=Oa()}={})=>{if(!Fe){Fe=!0;try{const s=await ls({kind:"component",projects:se,taken:[...le],project:o,name:e,register:i,check:(r,n)=>rr(r,{isNew:!0,taken:n}),create:async(r,n)=>{await h.components.put(r,{source:t,bundled:!1,meta:n?{project:n}:{}})}});if(!c())return;if(!s){te();return}if(await Ko(),!c())return;pt("#/components"),E.toast(`Created the component "${s}".`,{type:"success"}),st(s)}finally{Fe=!1}}},Ra=k.querySelector(".dm-plugin-body")||k,Ws=M.computed(()=>{a.blockRev.value,a.compRev.value,a.docRev.value,W(K()),a.base.value;const e=I(a.active.value),t=[...Re().map(s=>X({kind:"page",id:s.id})),...ge().map(s=>X({kind:"block",id:s})),...Ye().map(s=>X({kind:"component",id:s}))];let o=[];return e?.kind==="block"||e?.kind==="component"?o=[a.active.value]:e?.kind==="page"&&m&&(o=[a.active.value,...ge().filter(yt).map(s=>X({kind:"block",id:s}))]),er(t,o)}),Ys={...p,...a,dirty:ks,pageDirty:gs,activeDirty:ys,cssUnsaved:hs,hasPage:ws,activeKind:Xo,canView:Zo,viewHref:Ss,problem:Es,statusText:Ms,saveAll:Ws,dockKind:Qo,blockTagText:Ts,compStateText:Cs,compTagText:xs,anySelected:Ps,allSelected:Os,someSelected:Rs},rt=(e,t)=>Ue(e,t),wo={save:()=>io(!1),saveAllOpen:()=>io(!0),discard:async()=>{if(await Ea(),!c())return;const e=I(a.active.peek());if(e?.kind==="block"){const t=L.get(e.id);if(!t||!de(t)||!await E.confirm(`Discard the changes to "${e.id}" you have not saved?`))return;t.form={...t.saved},J(Ve(e.id)),Sa(),Le()}else if(e?.kind==="component"){const t=N.get(e.id);if(!t||!he(t)||!await E.confirm(`Discard the changes to the component "${e.id}" you have not saved?`))return;t.form={...t.saved},t.state="",J(_e(e.id)),xa(),ke()}else{if(!m||e?.kind==="page"&&e.id!==m.id||!(Wt()||ht())||!await E.confirm("Discard the changes to this page you have not saved?"))return;Ze(JSON.parse(a.base.peek())),p.cssOpened.peek()&&(p.css.value=ee.peek()),J(ze(m.id)),J(ft),Xe()}q(),z(),H()},newPage:()=>ue(""),newBlock:()=>Lt(),newComponent:()=>nt(),toggleSection:e=>{const t={here:"secHere",pages:"secPages",blocks:"secBlocks",components:"secComps"}[e];t&&(a[t].value=!a[t].peek(),rt(t,a[t].peek()))},toggleExplorer:()=>{a.explorerOn.value=!a.explorerOn.peek(),rt("explorer",a.explorerOn.peek())},toggleDock:()=>{a.dockOn.value=!a.dockOn.peek(),rt("dock",a.dockOn.peek()),a.dockOn.peek()&&a.dockTab.peek()==="history"&&!Qe&&pe()},showDock:e=>{a.dockTab.value=e,e==="history"&&m?.isEdit&&!Qe&&pe()},schemaChanged:()=>{a.seoSchemaNote.value=Po(p.seoSchema.peek()).error},insertSchemaExample:async e=>{const t=e?.target,o=t?.value||"";if(t&&(t.value=""),!o||p.seoSchema.peek().trim()&&!await E.confirm("Replace the structured data with the example?"))return;const s=p.urlPath.peek().trim()||m?.id||"/";p.seoSchema.value=mn(o,{title:p.seoTitle.peek().trim()||p.title.peek().trim(),description:p.seoDesc.peek().trim()||p.description.peek().trim(),url:`${location.origin}${s}`,siteName:Y?.title||Y?.seo?.defaultTitle||""}),a.seoSchemaNote.value=""},setBlockPart:e=>{a.blockPart.value=e==="css"?"css":"html",(e==="css"?me:oe)?.focus()},formatBlock:()=>{const e=a.blockPart.peek()==="css",t=e?me:oe;!t||!a.blockReady.peek()||Ho(Ke(t.textarea,e?"css":"html"))},copyShortcode:async()=>{const e=a.blockTab.peek();e&&await Ie(Nn(e),"Shortcode")},setCompPart:e=>{a.compPart.value=zt.includes(e)?e:"template",ae[a.compPart.peek()]?.focus()},copyComponent:()=>{const e=N.get(a.compTab.peek());e&&nt({name:Lo(e.name,[...le]),source:e.form.source})},setMode:e=>{a.cssMode.peek()&&(a.cssMode.value=!1),a.viewMode.value=jo(e),rt("viewMode",a.viewMode.peek()),e!=="write"&&(H(!0),bo())},toggleFullscreen:()=>{a.fullscreen.value=!a.fullscreen.peek(),rt("fullscreen",a.fullscreen.peek())},toggleCss:()=>{a.blockTab.peek()||a.compTab.peek()||(a.cssMode.peek()?(a.cssMode.value=!1,a.viewMode.value=jo(Pe().viewMode),Q.refresh()):(ia(),a.cssMode.value=!0,a.viewMode.value="split"))},formatMarkdown:()=>{Jt(),Ho(Ke(_,"md"))},toggleFold:()=>{a.folded.peek()?Q.unfoldAll():Q.foldAll(),a.folded.value=!a.folded.peek(),We.paint()},setWidth:e=>{a.liveWidth.value=e},refreshPreview:()=>{if(a.compTab.peek()){const e=N.get(a.compTab.peek());e&&at(e)}else H(!0)},share:async()=>{if(!m?.isEdit){E.toast("Save the page first - a share link needs a page to point at.",{type:"warning"});return}await br(m.id)},toggleAll:e=>{const t=!!e?.target?.checked;a.versions.peek().forEach(o=>{o.checked.value=t})},deleteSelected:async()=>{const e=a.versions.peek().filter(o=>o.checked.peek()).map(o=>o.filename),t=e.length;if(!(!t||!await E.confirm(`Delete ${t} version${t>1?"s":""}? This cannot be undone.`)))try{await h.versions.bulkDelete(m.id,e),E.toast(`${t} version${t>1?"s":""} deleted.`,{type:"success"}),await pe()}catch(o){E.toast("Delete failed: "+o.message,{type:"error"})}},saveNamed:async()=>{if(!m?.isEdit)return;const e=m;await vr(e.id)&&c()&&m===e&&await pe()},closeCompare:()=>{a.compare.value=null,Mt=null},restoreCompared:()=>ma(Mt)};Ge.querySelectorAll("[data-tip]").forEach(e=>E.tooltip(e,{content:e.getAttribute("data-tip"),position:"top"}));const Gs=M.applyBindings(Ys,Ra,{methods:wo});i(()=>Gs.dispose()),oe=zo(O('.pe-block-edit[data-part="html"]'),{ariaLabel:"Block template HTML",language:"html",onChange:e=>Ma("content",e)}),me=zo(O('.pe-block-edit[data-part="css"]'),{ariaLabel:"Block CSS",language:"css",placeholder:`/* Scoped to this block - e.g.
|
|
139
|
+
</span>`);Ge.prepend(Ls),Ge.before(O(".pe-block-bar")),Ge.before(O(".pe-comp-bar"));const aa=e=>(Array.isArray(e)?e:[]).map(t=>({value:t,label:t})),sa=O("#field-tags");let St=null;St=sa?E.pillbox(sa,{data:aa(Vt),value:[],creatable:!0,searchable:!0,placeholder:"Add tag\u2026",onChange:()=>{St&&(u.tags.value=[...St.getValue()])}}):null;const na=O("#field-admin-tags");let Et=null;Et=na?E.pillbox(na,{data:aa(T),value:[],creatable:!0,searchable:!0,placeholder:"Add admin tag\u2026",onChange:()=>{Et&&(u.adminTags.value=[...Et.getValue()])}}):null;const ra=()=>{a.bodyRev.value=a.bodyRev.peek()+1},Le=()=>{a.blockRev.value=a.blockRev.peek()+1},ke=()=>{a.compRev.value=a.compRev.peek()+1},Xe=()=>{a.docRev.value=a.docRev.peek()+1},ia=()=>{u.cssOpened.peek()||(u.css.peek()||(u.css.value=ee.peek()),u.cssOpened.value=!0,on(ve,{language:"css"}))},Ze=e=>{for(const t of Tr)u[t].value=e[t]==null?"":String(e[t]);for(const t of Mr)u[t].value=!!e[t];u.tags.value=Array.isArray(e.tags)?e.tags:[],St?.setValue(u.tags.peek()),Array.isArray(e.adminTags)&&(u.adminTags.value=e.adminTags),Et?.setValue(u.adminTags.peek()),qo(O("#field-visibility"),u.visibility.peek()),Q.unfoldAll(),a.folded.value=!1,gt=!0,V.value=e.body==null?"":String(e.body),gt=!1,Q.refresh(),Ko(),ra()},la=(e,t)=>({urlPath:t||"",title:e?.title||"",description:e?.description||"",layout:Ho(e?.layout||"default"),status:e?.status||"draft",sortOrder:String(e?.sortOrder??99),showInNav:!!e?.showInNav,sidebar:!!e?.sidebar,breadcrumbs:e?e.breadcrumbs!==!1:!0,bundled:!!e?.bundled,tags:Array.isArray(e?.tags)?e.tags:[],adminTags:Array.isArray(e?.adminTags)?e.adminTags:[],category:e?.category||"",visibility:typeof e?.visibility=="string"&&e.visibility?e.visibility:"public",project:Cn({isEdit:!!t,page:e,projects:se,fromHash:t?"":Ft()||"",urlPath:t||""}),theme:e?.theme||"",seoTitle:e?.seo?.title||"",seoDesc:e?.seo?.description||"",seoSchema:fn(e?.seo?.schema),dconfig:e?.dconfig?JSON.stringify(e.dconfig,null,2):"",body:e?.content||"",css:null}),ca=()=>{m&&(m.state=_(),m.at=Date.now())},da=e=>{m!==e&&(ca(),m=e,Ze(e.state),a.base.value=e.base,a.curId.value=e.id,e.at=Date.now(),Mt(),Xe())},Ns=()=>{ca(),m=null;const e=ms();Ze(e),a.base.value=W(e),a.curId.value=null,Mt(),Xe()};Ze(ms()),a.base.value=W(_());const J=e=>{try{S.remove?S.remove(e):S.set(e,null)}catch{}},pa=(e,t)=>({name:e.name,...e.form,base:e.base,at:t});p=()=>{try{for(const t of Ae())S.set(ze(t.id),Ka(t===m?Go():t.state,t.base));ht()&&S.set(ft,u.css.peek());const e=new Date().toISOString();for(const t of ge()){const o=L.get(t);S.set(He(t),{form:{...o.form},base:o.base,at:e})}for(const t of Ye())S.set(Ve(t),pa(N.get(t),e))}catch{}};const ua=e=>{y()&&(p(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",ua),i(()=>window.removeEventListener("beforeunload",ua));let Qe=!1,Tt=null;const Mt=()=>{Qe=!1,Tt=null,a.versions.value=[],a.compare.value=null,a.histError.value="",a.dockOn.peek()&&a.dockTab.peek()==="history"&&(m?.isEdit?pe():a.dockTab.value="details")},pe=async()=>{const e=m;if(e?.isEdit){Qe=!0,a.histLoading.value=!0,a.histError.value="";try{const t=(await h.versions.list(e.id)).versions||[];if(!c()||m!==e)return;a.versions.value=t.map(o=>({...o,when:qe(o.createdAt),author:o.author||"",label:o.label||"",who:[o.author,o.label].filter(Boolean).join(" - "),checked:M.observable(!1)}))}catch(t){m===e&&(a.histError.value="Failed to load versions: "+t.message)}finally{m===e&&(a.histLoading.value=!1)}}},oo=e=>a.versions.peek().find(t=>t.filename===e),ao=async e=>{const t=m;try{const o=await h.versions.get(t.id,e.filename);if(!c()||m!==t)return;Tt=e.filename,a.compare.value={label:rs(e),old:o.content,current:Ut()}}catch(o){E.toast("Failed to load version: "+o.message,{type:"error"})}},Ds=async()=>{const e=m;if(!e?.isEdit)return;const t=await h.pages.get(e.id).catch(()=>null);if(!c()||m!==e||!t)return;e.page=t;const o=la(t,e.id);e.base=W(o),e.savedAdminTags=JSON.stringify(o.adminTags),Ze(o),a.base.value=e.base,Mt(),a.dockOn.peek()&&a.dockTab.peek()==="history"&&pe(),U()},ma=async e=>{if(!(!e||!await E.confirm("Restore this version? The current page content will be overwritten (a pre-restore snapshot will be saved automatically).")))try{await h.versions.restore(m.id,e),E.toast("Page restored.",{type:"success"}),await Ds()}catch(t){E.toast("Restore failed: "+t.message,{type:"error"})}},js=async e=>{if(await E.confirm("Delete this version? This cannot be undone."))try{await h.versions.delete(m.id,e.filename),E.toast("Version deleted.",{type:"success"}),await pe()}catch(t){E.toast("Failed to delete: "+t.message,{type:"error"})}},Ne=new Map,Bs=e=>{if(!Ne.has(e)){const t=I(e);Ne.set(e,{id:e,kind:t.kind,kindText:t.kind==="page"?"Page":t.kind==="component"?"Component":"Block",label:M.observable(""),title:M.observable(""),active:M.observable(!1),dirty:M.observable(!1)})}return Ne.get(e)},fa=e=>{const t=e===m?u.title.peek():e?.loaded?e.state.title:D.find(o=>o.urlPath===e?.id)?.title;return String(t||"").trim()||e?.id||"New page"};let ba=!0,va="";const Is=()=>{if(ba)return;const e={ids:P,active:a.active.peek()},t=JSON.stringify(e);if(t!==va){va=t;try{S.set(ps,e)}catch{}}},q=()=>{const e=P.map(Bs);for(const t of e){const o=I(t.id);let s,r;if(o.kind==="page"){const l=K.get(o.id);s=fa(l),r=l?.loaded?Yt(l):xe(o),t.title.value=o.id?`${s} (${o.id})`:"New page"}else if(o.kind==="component"){const l=N.get(o.id);s=o.id,r=l?he(l):xe(o),t.title.value=`Component <dm-${o.id}>`}else{const l=L.get(o.id);s=o.id,r=l?de(l):Re.has(o.id)||xe(o),t.title.value=`Block ${o.id}`}t.label.peek()!==s&&(t.label.value=s),t.dirty.peek()!==r&&(t.dirty.value=r);const n=t.id===a.active.peek();t.active.peek()!==n&&(t.active.value=n)}e.map(t=>t.id).join("|")!==a.tabs.peek().map(t=>t.id).join("|")&&(a.tabs.value=e),Is()};let ye=new Set;try{const e=S.get(us);Array.isArray(e)&&(ye=new Set(e.filter(t=>typeof t=="string")))}catch{}const ga=new Map,so=e=>{let t=ga.get(e.key);return t?(t.label.peek()!==e.label&&(t.label.value=e.label),t.meta.peek()!==(e.meta||"")&&(t.meta.value=e.meta||""),t.status.peek()!==(e.status||"")&&(t.status.value=e.status||""),t.folder.peek()!==!!e.folder&&(t.folder.value=!!e.folder)):(t={...e,label:M.observable(e.label),meta:M.observable(e.meta||""),status:M.observable(e.status||""),folder:M.observable(!!e.folder),active:M.observable(!1),dirty:M.observable(!1),folded:M.observable(!1),title:""},ga.set(e.key,t)),t.title=e.kind==="block"||e.kind==="component"?e.meta?`${e.id} - ${e.meta}`:e.id:e.kind==="folder"?e.meta:`${e.label} (${e.meta})`,t},no=new Map,z=()=>{const e=a.filter.peek(),t=I(a.active.peek()),o=t?.kind==="page"?t.id:null,s=t?.kind==="block"?t.id:null,r=t?.kind==="component"?t.id:null,n=new Set(Ae().map(f=>f.id)),l=Gn(D,{filter:e,folded:ye}).map(so);for(const f of l){const C=f.kind==="page"&&f.id===o,B=f.kind==="page"&&(n.has(f.id)||!K.get(f.id)?.loaded&&xe({kind:"page",id:f.id})),fe=ye.has(f.id);f.active.peek()!==C&&(f.active.value=C),f.dirty.peek()!==B&&(f.dirty.value=B),f.folded.peek()!==fe&&(f.folded.value=fe)}const g=Vn(ie,e).map(so),$=f=>{const C=L.get(f);return C?de(C):Re.has(f)||xe({kind:"block",id:f})};for(const f of g){const C=f.id===s,B=$(f.id);f.active.peek()!==C&&(f.active.value=C),f.dirty.peek()!==B&&(f.dirty.value=B)}const G=Kn(Je,e).map(so),Me=f=>{const C=N.get(f);return C?he(C):xe({kind:"component",id:f})};for(const f of G){const C=f.id===r,B=Me(f.id);f.active.peek()!==C&&(f.active.value=C),f.dirty.peek()!==B&&(f.dirty.value=B)}const Co=m?Dn(kt,_t,be):[],za=(f,C,B)=>(no.has(f)||no.set(f,{key:f,id:C,label:B,kindText:"",title:"",active:M.observable(!1),dirty:M.observable(!1)}),no.get(f)),xo=Co.map(f=>{const C=za(`block:${f.name}`,f.name,f.name);C.kindText=f.footer?"Footer":"Block",C.title=`${f.name} - ${f.footer?"in the footer, on every page":"a block on this page"}`;const B=f.name===s,fe=$(f.name);return C.active.peek()!==B&&(C.active.value=B),C.dirty.peek()!==fe&&(C.dirty.value=fe),C});for(const f of ta){const C=za(`component:${f}`,f,f);C.kindText="Component",C.title=`<dm-${f}> - a component on this page`;const B=f===r,fe=Me(f);C.active.peek()!==B&&(C.active.value=B),C.dirty.peek()!==fe&&(C.dirty.value=fe),xo.push(C)}const Dt=(f,C)=>f.map(B=>B.key).join("|")===C.map(B=>B.key).join("|");Dt(l,a.pageRows.peek())||(a.pageRows.value=l),Dt(g,a.blockRows.peek())||(a.blockRows.value=g),Dt(G,a.compRows.peek())||(a.compRows.value=G),Dt(xo,a.thisPage.peek())||(a.thisPage.value=xo)},ha=async()=>{const e=await h.pages.list().catch(()=>null);!c()||!Array.isArray(e)||(D=e,z(),q())},te=()=>{const e=I(a.active.peek()),t=e?es(e):"/pages/new",o=window.location.hash.replace(/^#/,"");j.address=o.split("?")[0]===t?o:t,o.split("?")[0]!==t?history.replaceState({pe:1},"","#"+t):history.state?.pe||history.replaceState({pe:1},"",window.location.hash)},Fs=async e=>{if(e.loading)return e.loading;e.loading=(async()=>{let t=null;if(e.isEdit){if(t=await h.pages.get(e.id).catch(()=>null),!c())return!1;if(!t)return E.toast(`Page ${e.id} not found.`,{type:"error"}),!1}e.page=t;const o=la(t,e.id);e.state=o,e.base=W(o),e.savedAdminTags=JSON.stringify(o.adminTags),e.loaded=!0;let s=null;try{s=S.get(ze(e.id))}catch{}const r=xn(s),n=$o({kind:"page",id:e.id});if(r){J(ze(e.id));const l=W(r.state)!==e.base,g=Mn(r,e.base),$={...o,...r.state,adminTags:o.adminTags};if(l&&n&&!g)e.state=$,E.toast(`Your unsaved changes to ${e.id||"the new page"} are back.`,{type:"info"});else if(l){const G=r.at?` (${qe(r.at)})`:"",Me=g?" The saved page has changed since - restoring puts your version back over it (the saved one stays in History).":"";await E.confirm(`You left unsaved changes to ${e.id||"a new page"}${G}. Restore them?${Me}`)&&c()&&(e.state=$)}}return!0})();try{return await e.loading}finally{e.loading=null}},ka=e=>(K.has(e)||K.set(e,{kind:"page",id:e,isEdit:!!e,loaded:!1,page:null,state:null,base:"",savedAdminTags:"[]",at:0}),K.get(e)),ue=async e=>{const t=X({kind:"page",id:e});({ids:P}=Bo(P,t)),a.active.value=t,a.blockTab.value="",vo();const o=ka(e);if(q(),!o.loaded){a.previewStatus.value=`Opening ${e||"a new page"}\u2026`;const s=await Fs(o);if(!c()||!P.includes(t)||K.get(e)!==o)return;if(!s){ya(t);return}if(a.active.peek()!==t){q(),z();return}}da(o),te(),q(),z(),U(),Q.refresh(),V.focus()};w=async(e,t)=>{if(j.address=t,e.kind==="page"){ue(e.id);return}if(!e.id){(e.kind==="block"?Lt:nt)({project:Ft(t)||""});return}const o=e.kind==="block"?be:le;if(o.has(e.id)||await(e.kind==="block"?Vo:_o)(),!!c()){if(!o.has(e.id)){E.toast(`There is no ${e.kind} called "${e.id}".`,{type:"warning"}),te(),z();return}e.kind==="block"?Be(e.id):st(e.id)}};const ya=e=>{const t=a.active.peek(),o=_n(P,e,t);P=o.ids,Ne.delete(e);const s=I(e),r=o.active!==t?I(o.active):null;if(s.kind==="page"){if(K.delete(s.id),m?.id===s.id){const n=[...K.values()].filter(l=>l.loaded&&l.id!==s.id).sort((l,g)=>g.at-l.at)[0];n?da(n):Ns()}}else s.kind==="component"?(N.delete(s.id),a.compTab.peek()===s.id&&vo()):(L.delete(s.id),a.blockTab.peek()===s.id&&(a.blockTab.value="",a.blockReady.value=!1));if(a.active.value=o.active,r?.kind==="page"){ue(r.id);return}if(r?.kind==="block"){Be(r.id);return}if(r?.kind==="component"){st(r.id);return}te(),Xe(),Le(),ke(),q(),z(),U()},et=e=>{const t=I(e);if(!t||!P.includes(e))return;let o="";try{if(t.kind==="page"){const s=K.get(t.id);s&&Yt(s)&&(S.set(ze(s.id),Ka(s===m?_():s.state,s.base)),Ro({kind:"page",id:s.id}),o=fa(s))}else if(t.kind==="component"){const s=N.get(t.id);s&&he(s)&&(S.set(Ve(t.id),pa(s,new Date().toISOString())),Ro({kind:"component",id:t.id}),o=t.id)}else{const s=L.get(t.id);s&&de(s)&&(S.set(He(t.id),{form:{...s.form},base:s.base,at:new Date().toISOString()}),Ro({kind:"block",id:t.id}),o=t.id)}}catch{}ya(e),o&&E.toast(`Changes to "${o}" kept as a draft - back when you open it again.`,{type:"info"})},Ct=e=>{const t=I(e);t&&(t.kind==="page"?ue(t.id):t.kind==="component"?st(t.id):Be(t.id))},wa=new Set,zs=async e=>{const t=[];for(const o of e){const s=L.get(o);if(!s)continue;const r={...s.form};try{const n=Za(r,s.block?.meta);await h.blocks.put(o,n),s.block={...s.block,meta:n.meta},s.saved=r,s.base=Do(r),vt.set(o,new Date().toISOString()),c()&&J(He(o)),t.push(o)}catch(n){E.toast(`Block "${o}" not saved: ${n.message||"Unknown error"}`,{type:"error"})}}return t.forEach(o=>wa.add(o)),t.length&&(Le(),pt("#/blocks")),t},qs=async e=>{const t=e===m?_():e.state,o=Po(t.seoSchema).error;if(o)return E.toast(`${e.id||"The new page"} not saved - structured data: ${o}`,{type:"error"}),e===m&&(a.seoSchemaNote.value=o,a.dockOn.value=!0,a.dockTab.value="seo"),!1;const s=Gt(t,e,Xt(t)),r=e.id;try{if(e.isEdit){const n={frontmatter:s,body:t.body};t.urlPath!==e.id&&(n.newUrlPath=t.urlPath),await h.pages.update(e.id,n)}else await h.pages.create({urlPath:t.urlPath,frontmatter:s,body:t.body})}catch(n){return E.toast(`${e.id||"The new page"} not saved: ${n.message||"Unknown error"}`,{type:"error"}),!1}if(!c())return!0;if(e.savedAdminTags=JSON.stringify(t.adminTags),e.base=W(t),e===m?a.base.value=e.base:e.state=t,J(ze(r)),!e.isEdit||t.urlPath!==e.id){K.delete(r),e.id=t.urlPath,e.isEdit=!0,K.set(e.id,e);const n=X({kind:"page",id:r}),l=X({kind:"page",id:e.id});Ne.delete(n),{ids:P}=Qn(P,n,l,a.active.peek()),a.active.peek()===n&&(a.active.value=l),e===m&&(a.curId.value=e.id,te())}return!0},Hs=async e=>{const t=[];for(const o of e){const s=N.get(o);if(!s||s.readOnly)continue;if(Rt===s?(clearTimeout(At),Rt=null,ke(),at(s)):s.state||at(s),s.compiling&&await s.compiling,!c())return t;if(s.state!=="ok"){E.toast(`Component "${o}" not saved: ${s.state==="error"?"it does not compile - fix the errors first.":"it has not compiled yet - try again in a moment."}`,{type:"warning"});continue}const r={...s.form},n={...s.meta||{}};delete n.bundled,r.project?n.project=r.project:delete n.project;try{await h.components.put(o,{source:r.source,bundled:r.bundled,meta:n}),s.meta=n,s.saved=r,s.base=Fo({name:o,...r});const l=Je.find(g=>g.name===o);l&&(l.bundled=r.bundled,l.meta=n),c()&&J(Ve(o)),t.push(o)}catch(l){E.toast(`Component "${o}" not saved: ${l.message||"Unknown error"}`,{type:"error"})}}return t.length&&(ke(),pt("#/components")),t};let ro=!1;const io=async(e=!1)=>{if(a.saving.peek()||ro)return;ro=!0;let t,o,s=[];try{if(await Ea(),!c())return;const n=I(a.active.peek());if(lr().formatOnSave&&vs(n),e)t=Ae(),o=ge(),s=Ye();else if(n?.kind==="block")t=[],o=L.has(n.id)&&de(L.get(n.id))?[n.id]:[];else if(n?.kind==="component")t=[],o=[],s=N.has(n.id)&&he(N.get(n.id))?[n.id]:[];else if(n?.kind==="page"&&m)o=ge().filter(yt),t=!m.isEdit||Wt()||!o.length?[m]:[];else return;if(!t.length&&!o.length&&!s.length){E.toast("Nothing to save.",{type:"info"});return}for(const g of t){const $=Ao(g===m?_():g.state);if($.length){E.toast(`${g.id||"New page"}: ${$[0].text}`,{type:"warning"}),g!==m&&await ue(g.id),a.dockOn.value=!0,a.dockTab.value=$[0].field==="dconfig"?"dconfig":"details",Ke("dock",!0);return}}const l=Fn(o,Object.fromEntries(o.map(g=>[g,Qa(Ue.get(g),m?.id||"")])),wa);if(l&&(!await E.confirm(l)||!c()))return}finally{ro=!1}const r=t.length>0&&ht();a.saving.value=!0;try{let n=0;for(const $ of t)await qs($)&&n++;if(!c())return;if(r){const $=u.css.peek();await h.settings.saveCustomCss($),ee.value=$,J(ft)}const l=await zs(o);if(!c())return;const g=await Hs(s);if((n||l.length||g.length)&&E.toast(zn({pages:n,css:r,blocks:l,components:g}),{type:"success"}),Xe(),!c())return;q(),z(),n&&(pt("#/pages"),Mt(),ha())}catch(n){E.toast(`Save failed: ${n.message||"Unknown error"}`,{type:"error"})}finally{a.saving.value=!1}};let oe=null,me=null;const De=new Map,je=new Map,Sa=()=>{const e=L.get(a.blockTab.peek());!e||!oe||(a.blockReady.value=!1,oe.setValue(e.form.content),me.setValue(e.form.css),a.blockProject.value=e.form.project,qo(O("#block-project"),e.form.project),a.blockBundled.value=e.form.bundled,a.blockWhere.value=Rn({usage:Ue.get(e.form.name)})||"Where it is used could not be read.",a.blockNote.value="",a.blockReady.value=!0,uo())},Vs=e=>{const t=L.get(e);if(!t)return{};const o=t.form.content;return Object.fromEntries(ts(Ga(o),No(o),t.samples||{}).map(s=>[s.name,s.value]))};i(M.effect(()=>{const e=a.blockProject.value,t=a.blockBundled.value,o=L.get(a.blockTab.peek());!o||!a.blockReady.peek()||o.form.project===e&&o.form.bundled===t||(o.form.project=e,o.form.bundled=t,Le())}));const lo=async(e,{quiet:t=!1}={})=>{for(;De.has(e);)if(await De.get(e),L.has(e)||t)return L.get(e)||null;if(L.has(e))return L.get(e);const o=(async()=>{try{const s=await h.blocks.get(e);if(!c()||!t&&!P.includes(X({kind:"block",id:e})))return null;const r=Xa({...s,name:e}),n={block:s,saved:r,base:Do(r),form:{...r},samples:{}};let l=null;try{l=S.get(He(e))}catch{}const g=Ln(l,n.base);if(t&&g?.stale)return null;if($o({kind:"block",id:e}),g){const $=g.at?` (${qe(g.at)})`:"",G=!g.stale||await E.confirm(`You left unsaved changes to "${e}"${$}, but the block has been saved since. Restore your version anyway?`);if(!c())return null;G&&(n.form={...n.form,...g.form,name:e},g.stale||E.toast(`Your unsaved changes to "${e}" are back.`,{type:"info"}))}return l&&J(He(e)),L.set(e,n),Le(),n}catch(s){return c()&&a.blockTab.peek()===e&&(a.blockNote.value=`Could not open "${e}": ${s.message||"unknown error"}`),null}finally{De.delete(e)}})();return De.set(e,o),o},Ea=async()=>{for(;De.size||je.size;)await Promise.all([...De.values(),...je.values()])},Be=async e=>{if(!e||!be.has(e))return;const t=X({kind:"block",id:e});({ids:P}=Bo(P,t)),a.active.value=t,vo(),a.cssMode.peek()&&(a.cssMode.value=!1),a.viewMode.peek()==="preview"&&(a.viewMode.value="split"),a.blockTab.peek()!==e&&(a.blockReady.value=!1),a.blockTab.value=e,a.blockUses.value=m&&yt(e)?qn(Qa(Ue.get(e),m.id||"")):jn(Ue.get(e)),te(),q(),z();let o=L.get(e);o||(a.blockReady.value=!1,a.blockNote.value=`Opening ${e}\u2026`,o=await lo(e)),!(!o||!c()||a.blockTab.peek()!==e)&&(Sa(),q(),z(),Zt=e,U(),(a.blockPart.peek()==="css"?me:oe)?.focus())};let co=null;i(()=>clearTimeout(co));const Ta=(e,t)=>{const o=L.get(a.blockTab.peek());!o||!a.blockReady.peek()||(o.form[e]=t,clearTimeout(co),co=setTimeout(()=>{Le(),e==="content"&&uo()},120),U())},we=O("#pe-block-samples"),Ma=e=>{we.replaceChildren();const t=document.createElement("p");t.className="pe-dock-none",t.textContent=e,we.appendChild(t)};let tt=[],po=null;function uo(){const e=L.get(a.blockTab.peek());if(!e){tt=[],po=null,Ma("Open a block to see its placeholders.");return}const t=ts(Ga(e.form.content),No(e.form.content),e.samples);if(!(po===e&&t.map(o=>o.name).join("|")===tt.join("|"))){if(tt=t.map(o=>o.name),po=e,!t.length){Ma("No {{placeholders}} in the template yet.");return}we.replaceChildren();for(const o of t){const s=document.createElement("div");s.className="pe-comp-prop",s.tabIndex=0,s.dataset.sample=o.name;const r=document.createElement("label");r.className="pe-comp-prop-label",r.textContent=o.name,r.title=o.raw?`{{{${o.name}}}} - raw markup`:`{{${o.name}}}`;const n=document.createElement("input");n.type="text",n.className="form-input form-input--sm pe-comp-prop-input",n.value=o.value,n.setAttribute("aria-label",`Sample value for ${o.name}`),n.addEventListener("input",()=>{e.samples[o.name]=n.value,U()});const l=document.createElement("button");l.type="button",l.className="pe-kebab",l.setAttribute("aria-label",`Actions for ${o.name}`),l.title="Actions",l.textContent="\u22EE",s.append(r,n,l),we.appendChild(s)}}}const mo=(e,t)=>No(e.form.content).has(t)?`{{{${t}}}}`:`{{${t}}}`,_s=e=>{const t=L.get(a.blockTab.peek());return!t||!tt.includes(e)?[]:[{header:mo(t,e)},{label:"Insert into the template",icon:"corner-down-right",action:()=>{const o=oe?.textarea;o&&(a.blockPart.value="html",o.focus(),o.setRangeText(mo(t,e),o.selectionStart,o.selectionEnd,"end"),o.dispatchEvent(new Event("input",{bubbles:!0})))}},{label:"Copy the placeholder",icon:"copy",action:()=>Ie(mo(t,e),"Placeholder")},{type:"divider"},{label:"Reset the sample",icon:"rotate-ccw",action:()=>{delete t.samples[e],tt=[],uo(),U()}}]};{const e=E.contextMenu(we,{cursor:"glyph",match:".pe-comp-prop",inherit:!1,density:"compact",items:t=>_s(t.dataset.sample)});i(()=>e?.destroy?.()),we.addEventListener("click",t=>{const o=t.target.closest(".pe-kebab");o&&Ce(o)}),we.addEventListener("keydown",t=>{const o=t.target.closest(".pe-comp-prop");o&&t.key==="F10"&&t.shiftKey&&(t.preventDefault(),Ce(o))})}const ae={},Se=O("#component-preview"),xt=e=>{try{Se?.contentWindow?.postMessage(e,"*")}catch{}};let fo=Se.contentDocument?.readyState==="complete"&&/component-preview/.test(Se.contentDocument?.URL||""),Pt=!1,ot=null;const Ca=()=>{fo=!0,ot&&c()&&(xt({type:"mount",payload:ot}),Pt=!0),ot=null};Se.addEventListener("load",Ca),i(()=>Se.removeEventListener("load",Ca));const Ks=e=>{if(!fo){ot=e;return}if(!Pt){Pt=!0,xt({type:"mount",payload:e});return}ot=e,fo=!1,Pt=!1,Se.src=Se.src};let Ot="";const bo=(e=!1)=>{const t=N.get(a.compTab.peek());if(!(!t||t.state!=="ok"||!t.js)){if(a.viewMode.peek()==="write"){t.previewStale=!0;return}!e&&Ot===t.name&&!t.previewStale||(t.previewStale=!1,Ot=t.name,Ks({compiledJs:t.js,tagName:`dm-${t.name}`,props:t.previewProps}))}},at=e=>{const t=++e.seq;return e.state="compiling",a.compTab.peek()===e.name&&(a.compState.value="compiling"),e.compiling=(async()=>{let o;try{o=await h.components.compile(e.name,e.form.source)}catch(s){o={errors:[{type:"request",message:s.message||"Compile request failed."}]}}if(!(t!==e.seq||!c())){if(o.errors?.length?(e.state="error",e.errors=o.errors.map(s=>`[${s.type}] ${s.message}`).join(`
|
|
140
|
+
`),e.js=null):(e.state="ok",e.errors="",e.js=o.js),a.compTab.peek()!==e.name){e.previewStale=!0;return}a.compState.value=e.state,a.compErrors.value=e.errors,e.state==="ok"&&(yo(),bo(!0))}})().finally(()=>{e.compiling&&t===e.seq&&(e.compiling=null)}),e.compiling};let At=null,Rt=null;i(()=>clearTimeout(At));const xa=()=>{const e=N.get(a.compTab.peek());if(!e||!ae.template)return;a.compReady.value=!1;const t=ut(e.form.source);for(const o of zt)ae[o].setValue(t[o]),ae[o].textarea.readOnly=e.readOnly;a.compReadOnly.value=e.readOnly,a.compProject.value=e.form.project,qo(O("#comp-project"),e.form.project),a.compBundled.value=e.form.bundled,a.compState.value=e.state,a.compErrors.value=e.errors,a.compNote.value="",a.compReady.value=!0,yo(),e.state==="ok"?bo():e.state||at(e)},vo=()=>{a.compTab.peek()&&(a.compTab.value="",a.compReady.value=!1)},Pa={page:"details",block:"details",component:"details"};let $t="";i(M.effect(()=>{const e=Qo.value;e!==$t&&($t&&(Pa[$t]=a.dockTab.peek()),$t=e,e&&(a.dockTab.value=Pa[e]||"details",e==="page"&&a.dockTab.peek()==="history"&&a.dockOn.peek()&&m?.isEdit&&!Qe&&pe()))}));const go=async(e,{quiet:t=!1}={})=>{if(je.has(e))return je.get(e);if(N.has(e))return N.get(e);const o=(async()=>{try{const s=await h.components.get(e);if(!c()||!P.includes(X({kind:"component",id:e})))return null;const r=s.readOnly===!0||s.origin==="plugin",n={project:s.meta?.project||"",bundled:!!s.bundled,source:os(ut(s.source))},l={name:e,comp:s,saved:n,base:Fo({name:e,...n}),form:{...n},meta:s.meta||{},readOnly:r,state:"",errors:"",js:null,seq:0,compiling:null,previewProps:{},previewStale:!1};let g=null;try{g=S.get(Ve(e))}catch{}const $=nr(g,l.base);if(t&&(!$.ok||$.stale||r))return null;const G=$o({kind:"component",id:e});if(t&&!G)return null;if($.ok&&!r){const Me=g.at?` (${qe(g.at)})`:"",Co=G&&!$.stale||await E.confirm($.stale?`You left unsaved changes to the component "${e}"${Me}, but it has been saved since. Restore your version anyway?`:`You left unsaved changes to the component "${e}"${Me}. Restore them?`);if(!c())return null;Co&&(l.form={project:String(g.project??""),bundled:g.bundled===!0,source:String(g.source)},G&&!$.stale&&E.toast(`Your unsaved changes to the component "${e}" are back.`,{type:"info"}))}return g&&J(Ve(e)),N.set(e,l),ke(),l}catch(s){return c()&&a.compTab.peek()===e&&(a.compNote.value=`Could not open <dm-${e}>: ${s.message||"unknown error"}`),null}finally{je.delete(e)}})();return je.set(e,o),o},st=async e=>{if(!e||!le.has(e))return;const t=X({kind:"component",id:e});({ids:P}=Bo(P,t)),a.active.value=t,a.blockTab.value="",a.cssMode.peek()&&(a.cssMode.value=!1),a.viewMode.peek()==="preview"&&(a.viewMode.value="split"),a.compTab.value=e,te(),q(),z();let o=N.get(e);o||(a.compReady.value=!1,a.compReadOnly.value=!1,a.compState.value="",a.compNote.value=`Opening <dm-${e}>\u2026`,o=await go(e)),!(!o||!c()||a.compTab.peek()!==e)&&(xa(),q(),z(),ae[a.compPart.peek()]?.focus())},Us=(e,t)=>{const o=N.get(a.compTab.peek());if(!o||!a.compReady.peek()||o.readOnly)return;const s=ut(o.form.source);s[e]=t,o.form.source=os(s),clearTimeout(At),Rt=o,At=setTimeout(()=>{Rt=null,ke(),at(o)},300)};i(M.effect(()=>{const e=a.compProject.value,t=a.compBundled.value,o=N.get(a.compTab.peek());!o||!a.compReady.peek()||o.readOnly||o.form.project===e&&o.form.bundled===t||(o.form.project=e,o.form.bundled=t,ke())}));const Ee=O("#pe-comp-props");let ho=[];const ko=e=>{Ee.replaceChildren();const t=document.createElement("p");t.className="pe-dock-none",t.textContent=e,Ee.appendChild(t)};function yo(){const e=N.get(a.compTab.peek());if(!e){ho=[],ko("Open a component to try its props.");return}const{rows:t,error:o}=as(ut(e.form.source).props,e.previewProps);if(ho=t,o){ko("The <props> block is not valid JSON - fix it to see the props here.");return}if(!t.length){e.previewProps={},ko("No props declared. Add them in the <props> block.");return}e.previewProps=Object.fromEntries(t.map(s=>[s.name,s.value])),Ee.replaceChildren();for(const s of t){const r=document.createElement("div");r.className="pe-comp-prop",r.tabIndex=0,r.dataset.prop=s.name;const n=document.createElement("label");n.className="pe-comp-prop-label",n.textContent=s.label,n.title=`${s.name} (${s.type})`;const l=s.type==="array"||s.type==="object"?document.createElement("textarea"):document.createElement("input");s.type==="boolean"?(l.type="checkbox",l.className="form-check",l.checked=ss(s.type,s.value)):(l.tagName==="INPUT"?l.type=s.type==="number"?"number":"text":l.rows=2,l.className="form-input form-input--sm pe-comp-prop-input",l.value=ss(s.type,s.value)),l.setAttribute("aria-label",s.label);const g=()=>{e.previewProps[s.name]=ir(s.type,s.type==="boolean"?l.checked:l.value),Ot===e.name&&xt({type:"update",payload:{props:e.previewProps}})};l.addEventListener("input",g),l.addEventListener("change",g);const $=document.createElement("button");$.type="button",$.className="pe-kebab",$.setAttribute("aria-label",`Actions for ${s.label}`),$.title="Actions",$.textContent="\u22EE",r.append(n,l,$),Ee.appendChild(r)}}const Ie=async(e,t)=>{try{await navigator.clipboard.writeText(e),E.toast(`${t} copied.`,{type:"success"})}catch{E.toast(e,{type:"info",duration:8e3})}},Js=e=>{const t=N.get(a.compTab.peek()),o=ho.find(n=>n.name===e);if(!t||!o)return[];const s=sr(o.name,o.type,t.previewProps[o.name]),r=`dm-${t.name}`;return[{header:o.label},{label:"Reset to its default",icon:"rotate-ccw",action:()=>{delete t.previewProps[o.name];const n=as(ut(t.form.source).props,{}).rows.find(l=>l.name===o.name);t.previewProps[o.name]=n?n.value:null,yo(),Ot===t.name&&xt({type:"update",payload:{props:t.previewProps}})}},{label:"Copy as an attribute",icon:"copy",disabled:!s,action:()=>Ie(s,"Attribute")},{label:"Copy the tag with this value",icon:"code",action:()=>Ie(`<${r}${s?` ${s}`:""}></${r}>`,"Tag")},{label:"Copy the prop name",icon:"copy",action:()=>Ie(o.name,"Name")},{type:"divider"},{label:"Edit in <props>",icon:"edit",action:()=>{a.compPart.value="props";const n=ae.props?.textarea;if(!n)return;const l=n.value.indexOf(`"${o.name}"`);n.focus(),l>=0&&n.setSelectionRange(l,l+o.name.length+2)}}]};{const e=E.contextMenu(Ee,{cursor:"glyph",match:".pe-comp-prop",inherit:!1,density:"compact",items:t=>Js(t.dataset.prop)});i(()=>e?.destroy?.()),Ee.addEventListener("click",t=>{const o=t.target.closest(".pe-kebab");o&&Ce(o)}),Ee.addEventListener("keydown",t=>{const o=t.target.closest(".pe-comp-prop");o&&t.key==="F10"&&t.shiftKey&&(t.preventDefault(),Ce(o))})}let Fe=!1;const Oa=()=>Ft()||"",Lt=async({project:e=Oa(),seed:t="",content:o=gr,css:s=""}={})=>{if(!Fe){Fe=!0;try{const n=await ls({kind:"block",projects:se,taken:[...be],project:e,name:t,check:An,register:i,create:async(l,g)=>{await h.blocks.put(l,Za({name:l,project:g,bundled:!1,content:o,css:s}))}});if(!c())return;if(!n){te();return}if(await Vo(),!c())return;pt("#/blocks"),E.toast(`Created the block "${n}".`,{type:"success"}),Be(n)}finally{Fe=!1}}},nt=async({name:e="",source:t=ar,project:o=Oa()}={})=>{if(!Fe){Fe=!0;try{const s=await ls({kind:"component",projects:se,taken:[...le],project:o,name:e,register:i,check:(r,n)=>rr(r,{isNew:!0,taken:n}),create:async(r,n)=>{await h.components.put(r,{source:t,bundled:!1,meta:n?{project:n}:{}})}});if(!c())return;if(!s){te();return}if(await _o(),!c())return;pt("#/components"),E.toast(`Created the component "${s}".`,{type:"success"}),st(s)}finally{Fe=!1}}},Aa=k.querySelector(".dm-plugin-body")||k,Ws=M.computed(()=>{a.blockRev.value,a.compRev.value,a.docRev.value,W(_()),a.base.value;const e=I(a.active.value),t=[...Ae().map(s=>X({kind:"page",id:s.id})),...ge().map(s=>X({kind:"block",id:s})),...Ye().map(s=>X({kind:"component",id:s}))];let o=[];return e?.kind==="block"||e?.kind==="component"?o=[a.active.value]:e?.kind==="page"&&m&&(o=[a.active.value,...ge().filter(yt).map(s=>X({kind:"block",id:s}))]),er(t,o)}),Ys={...u,...a,dirty:ks,pageDirty:gs,activeDirty:ys,cssUnsaved:hs,hasPage:ws,activeKind:Xo,canView:Zo,viewHref:Ss,problem:Es,statusText:Ts,saveAll:Ws,dockKind:Qo,blockTagText:Ms,compStateText:Cs,compTagText:xs,anySelected:Ps,allSelected:Os,someSelected:As},rt=(e,t)=>Ke(e,t),wo={save:()=>io(!1),saveAllOpen:()=>io(!0),discard:async()=>{if(await Ea(),!c())return;const e=I(a.active.peek());if(e?.kind==="block"){const t=L.get(e.id);if(!t||!de(t)||!await E.confirm(`Discard the changes to "${e.id}" you have not saved?`))return;t.form={...t.saved},J(He(e.id)),Sa(),Le()}else if(e?.kind==="component"){const t=N.get(e.id);if(!t||!he(t)||!await E.confirm(`Discard the changes to the component "${e.id}" you have not saved?`))return;t.form={...t.saved},t.state="",J(Ve(e.id)),xa(),ke()}else{if(!m||e?.kind==="page"&&e.id!==m.id||!(Wt()||ht())||!await E.confirm("Discard the changes to this page you have not saved?"))return;Ze(JSON.parse(a.base.peek())),u.cssOpened.peek()&&(u.css.value=ee.peek()),J(ze(m.id)),J(ft),Xe()}q(),z(),U()},newPage:()=>ue(""),newBlock:()=>Lt(),newComponent:()=>nt(),toggleSection:e=>{const t={here:"secHere",pages:"secPages",blocks:"secBlocks",components:"secComps"}[e];t&&(a[t].value=!a[t].peek(),rt(t,a[t].peek()))},toggleExplorer:()=>{a.explorerOn.value=!a.explorerOn.peek(),rt("explorer",a.explorerOn.peek())},toggleDock:()=>{a.dockOn.value=!a.dockOn.peek(),rt("dock",a.dockOn.peek()),a.dockOn.peek()&&a.dockTab.peek()==="history"&&!Qe&&pe()},showDock:e=>{a.dockTab.value=e,e==="history"&&m?.isEdit&&!Qe&&pe()},schemaChanged:()=>{a.seoSchemaNote.value=Po(u.seoSchema.peek()).error},insertSchemaExample:async e=>{const t=e?.target,o=t?.value||"";if(t&&(t.value=""),!o||u.seoSchema.peek().trim()&&!await E.confirm("Replace the structured data with the example?"))return;const s=u.urlPath.peek().trim()||m?.id||"/";u.seoSchema.value=mn(o,{title:u.seoTitle.peek().trim()||u.title.peek().trim(),description:u.seoDesc.peek().trim()||u.description.peek().trim(),url:`${location.origin}${s}`,siteName:Y?.title||Y?.seo?.defaultTitle||""}),a.seoSchemaNote.value=""},setBlockPart:e=>{a.blockPart.value=e==="css"?"css":"html",(e==="css"?me:oe)?.focus()},formatBlock:()=>{const e=a.blockPart.peek()==="css",t=e?me:oe;!t||!a.blockReady.peek()||Uo(_e(t.textarea,e?"css":"html"))},copyShortcode:async()=>{const e=a.blockTab.peek();e&&await Ie(Nn(e),"Shortcode")},setCompPart:e=>{a.compPart.value=zt.includes(e)?e:"template",ae[a.compPart.peek()]?.focus()},copyComponent:()=>{const e=N.get(a.compTab.peek());e&&nt({name:Lo(e.name,[...le]),source:e.form.source})},setMode:e=>{a.cssMode.peek()&&(a.cssMode.value=!1),a.viewMode.value=jo(e),rt("viewMode",a.viewMode.peek()),e!=="write"&&(U(!0),bo())},toggleFullscreen:()=>{a.fullscreen.value=!a.fullscreen.peek(),rt("fullscreen",a.fullscreen.peek())},toggleCss:()=>{a.blockTab.peek()||a.compTab.peek()||(a.cssMode.peek()?(a.cssMode.value=!1,a.viewMode.value=jo(Pe().viewMode),Q.refresh()):(ia(),a.cssMode.value=!0,a.viewMode.value="split"))},formatMarkdown:()=>{Jt(),Uo(_e(V,"md"))},toggleFold:()=>{a.folded.peek()?Q.unfoldAll():Q.foldAll(),a.folded.value=!a.folded.peek(),We.paint()},setWidth:e=>{a.liveWidth.value=e},refreshPreview:()=>{if(a.compTab.peek()){const e=N.get(a.compTab.peek());e&&at(e)}else U(!0)},share:async()=>{if(!m?.isEdit){E.toast("Save the page first - a share link needs a page to point at.",{type:"warning"});return}await br(m.id)},toggleAll:e=>{const t=!!e?.target?.checked;a.versions.peek().forEach(o=>{o.checked.value=t})},deleteSelected:async()=>{const e=a.versions.peek().filter(o=>o.checked.peek()).map(o=>o.filename),t=e.length;if(!(!t||!await E.confirm(`Delete ${t} version${t>1?"s":""}? This cannot be undone.`)))try{await h.versions.bulkDelete(m.id,e),E.toast(`${t} version${t>1?"s":""} deleted.`,{type:"success"}),await pe()}catch(o){E.toast("Delete failed: "+o.message,{type:"error"})}},saveNamed:async()=>{if(!m?.isEdit)return;const e=m;await vr(e.id)&&c()&&m===e&&await pe()},closeCompare:()=>{a.compare.value=null,Tt=null},restoreCompared:()=>ma(Tt)};Ge.querySelectorAll("[data-tip]").forEach(e=>E.tooltip(e,{content:e.getAttribute("data-tip"),position:"top"}));const Gs=M.applyBindings(Ys,Aa,{methods:wo});i(()=>Gs.dispose()),oe=zo(O('.pe-block-edit[data-part="html"]'),{ariaLabel:"Block template HTML",language:"html",onChange:e=>Ta("content",e)}),me=zo(O('.pe-block-edit[data-part="css"]'),{ariaLabel:"Block CSS",language:"css",placeholder:`/* Scoped to this block - e.g.
|
|
139
141
|
color: var(--dm-primary);
|
|
140
|
-
h3 { font-size: 1.25rem; } */`,onChange:e=>
|
|
141
|
-
`).map((i,y)=>{const
|
|
142
|
+
h3 { font-size: 1.25rem; } */`,onChange:e=>Ta("css",e)}),i(()=>{oe.destroy(),me.destroy()});for(const e of zt)ae[e]=zo(O(`.pe-comp-edit[data-part="${e}"]`),{ariaLabel:`Component <${e}> block`,language:{template:"html",props:"json",script:"js",style:"css"}[e],onChange:t=>Us(e,t)});i(()=>{for(const e of zt)ae[e].destroy()});const Te=O(".pe-tabs-list"),Nt=e=>e.target.closest(".pe-tab")?.dataset.id||"",Ra=e=>{const t=Nt(e);t&&(e.target.closest(".pe-tab-close")?et(t):Ct(t))},$a=e=>{e.button===1&&Nt(e)&&(e.preventDefault(),et(Nt(e)))},La=e=>{const t=Nt(e);!t||e.target.closest(".pe-tab-close")||(e.key==="Enter"||e.key===" "?(e.preventDefault(),Ct(t)):e.key==="Delete"?(e.preventDefault(),et(t)):e.key==="F10"&&e.shiftKey&&(e.preventDefault(),Ce(e.target.closest(".pe-tab"))))};Te.addEventListener("click",Ra),Te.addEventListener("auxclick",$a),Te.addEventListener("keydown",La),i(()=>{Te.removeEventListener("click",Ra),Te.removeEventListener("auxclick",$a),Te.removeEventListener("keydown",La)});const So=e=>{for(const t of e)et(t)},Xs=async e=>{const t=I(e);if(t?.id)if(t.kind==="page")a.active.peek()!==e&&await ue(t.id),c()&&m?.id===t.id&&Ba();else if(t.kind==="block"){const s=(L.get(t.id)||await lo(t.id,{quiet:!0}))?.form||Xa(await h.blocks.get(t.id).catch(()=>null));c()&&Lt({seed:Lo(t.id,[...be]),content:s.content,css:s.css})}else{const s=(N.get(t.id)||await go(t.id,{quiet:!0}))?.form.source??(await h.components.get(t.id).catch(()=>null))?.source??"";c()&&nt({name:Lo(t.id,[...le]),source:s})}},Zs=e=>{const t=I(e);if(!t||!P.includes(e))return[];const o=P.indexOf(e),s=Ne.get(e)?.label.peek()||t.id,r=n=>{P=Wn(P,e,n),q()};return[{header:s},{label:"Close",icon:"x",action:()=>et(e)},{label:"Close others",icon:"x-circle",disabled:P.length<2,action:()=>So(Io(P,e,"others"))},{label:"Close to the right",icon:"chevrons-right",disabled:o>=P.length-1,action:()=>So(Io(P,e,"right"))},{label:"Close all",icon:"layers",action:()=>So(Io(P,e,"all"))},{type:"divider"},{label:"Move left",icon:"arrow-left",disabled:o===0,action:()=>r(-1)},{label:"Move right",icon:"arrow-right",disabled:o>=P.length-1,action:()=>r(1)},{type:"divider"},{label:t.kind==="page"?"Clone page\u2026":`Duplicate ${t.kind}\u2026`,icon:"copy",disabled:!t.id,action:()=>Xs(e)},{label:"Copy link",icon:"link",disabled:!t.id,action:()=>Ie(`${location.origin}${location.pathname}#${es(t)}`,"Link")}]};{const e=E.contextMenu(Te,{cursor:"glyph",match:".pe-tab",inherit:!1,density:"compact",items:t=>Zs(t.dataset.id)});i(()=>e?.destroy?.())}const Na=O(".pe-ex-scroll"),Da=e=>{const t=e.target.closest(".pe-ex-item"),o=t?.dataset.id||"";if(!o)return;const s=o.indexOf(":"),r=o.slice(0,s),n=o.slice(s+1),l=()=>{ye.has(n)?ye.delete(n):ye.add(n);try{S.set(us,[...ye])}catch{}z()};if(r==="folder"){l();return}if(r==="page"&&e.target.closest(".pe-ex-chev")&&t.classList.contains("is-folder")){l();return}r==="page"?ue(n):r==="block"?Be(n):r==="component"&&st(n)};Na.addEventListener("click",Da),i(()=>Na.removeEventListener("click",Da));let Eo=null;i(()=>clearTimeout(Eo)),V.addEventListener("input",()=>{Q.refresh(),ce.scrollTop=V.scrollTop,!gt&&(clearTimeout(Eo),Eo=setTimeout(ra,120),U())}),V.addEventListener("scroll",()=>{ce.scrollTop=V.scrollTop}),ve.addEventListener("scroll",()=>{ce.scrollTop=ve.scrollTop}),i(M.effect(()=>{for(const e of Object.keys(u))e!=="css"&&e!=="cssOpened"&&u[e].value;a.bodyRev.value,U()})),i(M.effect(()=>{a.bodyRev.value,a.docRev.value;const e=m?Ut():"";kt=m?$n(e,bt.map(t=>t.name),bt.filter(t=>t.shortTag).map(t=>t.name)):[],ta=m?Jn(e,le):[],wt(),z()})),i(M.effect(()=>{a.blockRev.value,a.compRev.value,a.docRev.value,a.active.value,a.filter.value,u.title.value,q(),z()})),i(M.effect(()=>{ce.hidden=!!(a.blockTab.value||a.compTab.value)}));let To=null;i(()=>clearTimeout(To)),i(M.effect(()=>{const e=u.css.value;a.cssMode.value&&(Kt.paint(),Cr(ce,e,ve),clearTimeout(To),To=setTimeout(oa,400))}));{const e=O(".pe-version-list"),t=E.contextMenu(e,{cursor:"glyph",match:"tr[data-file]",inherit:!1,density:"compact",items:o=>{const s=oo(o.dataset.file);return s?[{header:rs(s)},{label:"Show beside the editor",icon:"columns",action:()=>ao(s)},{label:"Restore this version\u2026",icon:"rotate-ccw",action:()=>ma(s.filename)},{type:"divider"},{label:"Delete\u2026",icon:"trash",danger:!0,action:()=>js(s)}]:[]}});i(()=>t?.destroy?.()),e.addEventListener("click",o=>{const s=o.target.closest("tr[data-file]");if(!s||o.target.matches("input"))return;const r=o.target.closest(".pe-kebab");if(r){Ce(r);return}const n=oo(s.dataset.file);n&&ao(n)}),e.addEventListener("keydown",o=>{const s=o.target.closest("tr[data-file]");if(s){if(o.key==="F10"&&o.shiftKey)o.preventDefault(),Ce(s);else if(o.key==="Enter"&&o.target===s){const r=oo(s.dataset.file);r&&ao(r)}}})}xr(O("#editor-body"),O("#editor-divider"),i),ln({image:e=>(a.cssMode.value=!1,Pr(e)),scribe:e=>pn(e),card:e=>en.open(e,{onMediaBrowse:()=>h.media.list().catch(()=>[])}),timeline:e=>tn.open(e,{onPreview:async t=>{try{return await h.pages.preview(t)}catch{return null}},onListCollections:()=>h.collections.list().catch(()=>[]),onGetCollection:t=>h.collections.get(t).catch(()=>null)})}),to.onEffects(e=>nn.open(e)),to.onHelp(()=>Ha()),to.onTutorial(e=>un(e));const ja=e=>{if(!c())return;const t=or(e);t&&(e.preventDefault(),t==="save"?io(!1):t==="layout"?wo.setMode(Yn(a.viewMode.peek())):wo.toggleExplorer())};document.addEventListener("keydown",ja),i(()=>document.removeEventListener("keydown",ja));const it=k.querySelector(".dm-plugin-banner-name");i(M.effect(()=>{const e=a.curId.value,t=Xo.value,o=a.blockTab.value||a.compTab.value,s=t==="block"?"Blocks":t==="component"?"Components":"Pages",r=t==="block"||t==="component"?o:e===null?"Editor":Tn(!!e,u.title.value,e);if(!c()||(document.title=`${r} - Domma CMS`,!it))return;const n=it.querySelector(".dm-plugin-banner-parent"),l=it.lastChild;n&&l&&l.nodeType===3&&it.querySelector(".dm-plugin-banner-sep")?(n.textContent=s,l.textContent=r):it.textContent=`${s} \u203A ${r}`})),dt(d,{id:"page-editor-back",icon:"arrow-left",title:"Back to Pages",onClick:()=>R.navigate("/pages")}),dt(d,{id:"page-editor-help",icon:"help-circle",title:"Editor reference",onClick:()=>Ha()});const Qs=dt(d,{id:"page-editor-view",icon:"external-link",title:"View on the site",onClick:()=>{m?.isEdit&&window.open(u.urlPath.peek().trim()||m.id,"_blank","noopener")}}),Ba=()=>{if(!m?.isEdit||a.saving.peek()||!c())return;const e=m,t=_(),o=Ao({...t,urlPath:e.id});if(o.length){E.toast(o[0].text,{type:"warning"});return}const s=vn({page:e.page,frontmatter:{...Gt(t,e,Xt(t)),adminTags:t.adminTags},body:t.body,source:e.id,pages:D,onCloned:async r=>{c()&&(await ha(),c()&&ue(r))}});i(()=>s.close())},Mo=dt(d,{id:"page-editor-clone",icon:"copy",title:"Clone page",onClick:Ba});i(M.effect(()=>{const e=Zo.value;for(const t of[Qs,Mo])t&&(t.disabled=!e);Mo&&(Mo.title=e?"Clone page":"Open a saved page to clone it")})),dt(d,{id:"page-editor-settings",icon:"settings",title:"Editor settings - font, size, spacing",onClick:()=>{Yo=fr(Jo,Wo)}}),i(qa(Aa,{position:"bottom"})),Domma.icons.scan();let Ia={ids:[],active:""};try{Ia=Zn(S.get(ps))}catch{}const lt=Ua(b),ct=tr(lt,Ia,history.state?.pe===1);P=ct.ids.filter(e=>{const t=I(e);return t.kind==="page"||(t.kind==="component"?le:be).has(t.id)}),ba=!1;for(const e of P){const t=I(e);t.kind==="page"&&ka(t.id)}q(),z(),wt();for(const e of Re)lo(e,{quiet:!0}).then(()=>{c()&&(q(),z())});for(const e of P){const t=I(e);t.kind==="component"&&e!==ct.active&&xe(t)&&go(t.id,{quiet:!0}).then(()=>{c()&&(q(),z())})}const Fa=lt&&!lt.id&<.kind!=="page";ct.active&&P.includes(ct.active)?await Ct(ct.active):P.length?await Ct(P[0]):Fa||te(),Fa&&c()&&(await(lt.kind==="block"?Lt:nt)({project:Ft(b)||""}),c()&&te())}};function qo(d,b){!d||typeof b!="string"||!b||[...d.options].some(v=>v.value===b)||(d.append(Object.assign(document.createElement("option"),{value:b,textContent:`${b} (custom)`})),d.value=b)}function Cr(d,b,v){d.replaceChildren(...String(b).split(`
|
|
143
|
+
`).map((i,y)=>{const p=document.createElement("span");p.className="editor-line-number-row";const w=document.createElement("span");w.className="fold-toggle fold-toggle--empty";const k=document.createElement("span");return k.className="editor-line-num",k.textContent=String(y+1),p.append(w,k),p})),d.scrollTop=v.scrollTop}function xr(d,b,v){if(!d||!b)return;const i=15,y=85,p=c=>Math.min(y,Math.max(i,c));let w=p(parseFloat(Pe().splitRatio)||50);const k=c=>{d.style.setProperty("--dm-editor-split",w+"%"),b.setAttribute("aria-valuenow",String(Math.round(w))),c&&Ke("splitRatio",w)};k(!1);const x=c=>{const A=d.getBoundingClientRect();A.width&&(w=p((c.clientX-A.left)/A.width*100)),k(!1)},j=()=>{document.removeEventListener("pointermove",x),document.removeEventListener("pointerup",j),d.classList.remove("is-resizing"),b.classList.remove("is-dragging"),k(!0)};v(j),b.addEventListener("pointerdown",c=>{window.matchMedia("(max-width: 768px)").matches||(c.preventDefault(),d.classList.add("is-resizing"),b.classList.add("is-dragging"),document.addEventListener("pointermove",x),document.addEventListener("pointerup",j))}),b.addEventListener("dblclick",()=>{w=50,k(!0)}),b.addEventListener("keydown",c=>{const A=c.shiftKey?10:2;let H=w;if(c.key==="ArrowLeft")H=w-A;else if(c.key==="ArrowRight")H=w+A;else if(c.key==="Home")H=i;else if(c.key==="End")H=y;else if(c.key==="Enter"||c.key===" ")H=50;else return;c.preventDefault(),w=p(H),k(!0)})}async function Pr(d){const b=d.selectionStart,v=d.selectionEnd,i=await bn({title:"Upload or insert an image"});if(!i||!d.isConnected)return;let y=i.split("/").pop().split("?")[0];try{y=decodeURIComponent(y)}catch{}const p=y.replace(/[\\[\]]/g,"\\$&"),w=i.replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/ /g,"%20");d.setSelectionRange(b,v),sn(d,``),d.dispatchEvent(new Event("input",{bubbles:!0}))}function Or(d,b,v){const i=Object.entries(b||{});return d?(d.replaceChildren(...i.map(([y,p])=>new Option(p?.label||y,y))),i.some(([y])=>y===v)?v:i[0]?.[0]||v):v}async function Ar(d,b){if(!d)return;let v=[];try{const x=await h.get("/collections/roles/entries?limit=100");v=Array.isArray(x)?x:x?.entries||[]}catch{}const i=v.map(x=>({name:x.data?.name,label:x.data?.label||x.data?.name,level:x.data?.level??99})).filter(x=>x.name&&x.level!==0).sort((x,j)=>j.level-x.level),y=(x,j)=>Object.assign(document.createElement("option"),{value:x,textContent:j}),p=()=>{typeof b=="string"&&b&&![...d.options].some(x=>x.value===b)&&d.append(y(b,`${b} (custom)`))};if(!i.length)return p();const w=document.createElement("optgroup");w.label="Role and above",i.forEach(x=>w.append(y(x.name,`${x.label} and above`)));const k=document.createElement("optgroup");k.label="Role only",i.forEach(x=>k.append(y(`=${x.name}`,`${x.label} only`))),d.replaceChildren(y("public","Public - everyone"),w,k,y("private","Private - super-admin only")),p()}
|
package/docs/configuration.md
CHANGED
|
@@ -1544,10 +1544,21 @@ step Ctrl+Z undoes. The toolbar's format button does the same.
|
|
|
1544
1544
|
code keeps its own shape within that. The renderer takes the indent off before
|
|
1545
1545
|
anything else (`unindentShortTags()` in `markdown.js`: a tag line loses all of
|
|
1546
1546
|
it, a container's content the indent its lines share), so it never reaches the
|
|
1547
|
-
page - and a page written flat is read exactly as before.
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
`<style
|
|
1547
|
+
page - and a page written flat is read exactly as before. HTML blocks in the
|
|
1548
|
+
body (a run of lines starting with a block tag such as `<div>` or `<p>`, up to
|
|
1549
|
+
the next blank line or short tag line) are laid out as block HTML is, below; a
|
|
1550
|
+
run holding `<pre>`, `<textarea>`, a script, a style or a fence is left as written.
|
|
1551
|
+
- **Block and component HTML**: every block element (`div`, `p`, `li`, `h2`,
|
|
1552
|
+
`section`, a custom element…) on a line of its own, its content one level in,
|
|
1553
|
+
and `{{#if}}` / `{{else}}` / `{{/if}}` written on their own lines the same.
|
|
1554
|
+
Inline content - text, `<a>`, `<strong>`, `<span>` - is never split or joined:
|
|
1555
|
+
it keeps the lines it was written on (a line inside an open inline tag goes one
|
|
1556
|
+
deeper), so no space appears or goes where the page would show it. An element
|
|
1557
|
+
holding only inline content stays on one line if it was written on one. Tags get
|
|
1558
|
+
one space between attributes, and a tag wider than 120 columns an attribute a line.
|
|
1559
|
+
`<pre>` and `<textarea>` keep every character; a `<script>` or `<style>` is
|
|
1560
|
+
formatted as JS or CSS. A stray closing tag stays where it was; nothing is dropped.
|
|
1561
|
+
- **JS**: re-indented by nesting only; the code itself is never rewritten.
|
|
1551
1562
|
- **CSS** (blocks, components, the page's custom CSS): one declaration a line,
|
|
1552
1563
|
`prop: value;`, a blank line between rules.
|
|
1553
1564
|
- **JSON** (component props): parsed and printed; invalid JSON is reported, not changed.
|
|
@@ -1557,14 +1568,15 @@ browser with the rest of the editor's settings: indent with spaces or tabs, the
|
|
|
1557
1568
|
indent size (2, 4 or 8 - also how wide a tab shows), *Keep a file's own
|
|
1558
1569
|
indentation* (on: a block, component or CSS already in tabs or fours keeps them;
|
|
1559
1570
|
the page body always takes the setting), *Auto-indent*, *Carry lists and quotes
|
|
1560
|
-
on*, *Indent inside short tags*, *Line up tables when formatting*,
|
|
1561
|
-
*Format on save* (off by default: Save formats the tab on show first; text that
|
|
1571
|
+
on*, *Indent inside short tags*, *Line up tables when formatting*,
|
|
1572
|
+
*Lay out HTML in the page body*, and *Format on save* (off by default: Save formats the tab on show first; text that
|
|
1562
1573
|
cannot be formatted is saved as it is).
|
|
1563
1574
|
|
|
1564
1575
|
While typing, **Enter** keeps the line's indentation. In the body it carries a
|
|
1565
1576
|
list or quote on (numbers count up, a task box comes back empty) and Enter on an
|
|
1566
1577
|
empty item ends the list; Shift+Enter is a plain new line. After an opening short
|
|
1567
|
-
tag the next line goes one deeper; after a closing one it stays level
|
|
1578
|
+
tag the next line goes one deeper; after a closing one it stays level; after an opening
|
|
1579
|
+
block HTML tag (`<div>`, `<ul>`…) one deeper too. In code it goes one
|
|
1568
1580
|
deeper after `{`, `(`, `[`, an opening tag or `{{#if}}`, and with the caret
|
|
1569
1581
|
between a pair the closer moves to its own line. **Tab / Shift+Tab** indent or
|
|
1570
1582
|
outdent every selected line when the selection spans lines.
|