domma-cms 1.8.42 → 1.8.44

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 CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.44] - 2026-10-23
4
+
5
+ - **Blocks with empty fields no longer show raw HTML.** A block placeholder on its own line with nothing to fill it (`{{bio}}` when there is no bio) left a blank line, which ended the block's HTML in the Markdown, and what followed showed on the page as code - the About page's team card printed its contact links as raw tags. Such a line is now dropped when it fills empty (`fillTemplateLines()` in `markdown.js`), for collection displays and block short tags alike; a template's own blank lines stay, since they are how it hands a Markdown value to marked.
6
+ - **Inline code on an indented HTML line shows again.** `<code>` inside an HTML line indented four or more spaces came out as `SC1:0` - the code-region scrub stored the line holding the code's placeholder and restored it only once. Restore now restores what it brings back too.
7
+
8
+ ## [1.8.43] - 2026-10-23
9
+
10
+ - **What is inside a short tag is indented too.** Shift+Alt+F now indents the content of `[grid]`, `[col]`, `[card]`, `[tabs]` and the other container short tags by how deeply it nests, not only the tag lines, and Enter after an opening tag goes one deeper. A nested list or fenced code keeps its shape inside. The renderer takes the nesting indent off before anything else (a container's content loses the indent its lines share), so four spaces inside a card is no longer a code block - and a page written flat reads exactly as before (checked across the fleet's 1,700 pages).
11
+
3
12
  ## [1.8.42] - 2026-10-23
4
13
 
5
14
  - **Format with Shift+Alt+F in the editor workspace.** The page body is tidied: trailing spaces off, runs of blank lines down to one, pipe tables lined up, and the lines holding only a container short tag (`[grid]`, `[col]`, `[card]`, `[tabs]`...) indented by how deeply they nest - the content between them stays at the margin, and the renderer drops a tag line's indent before parsing (`unindentShortTags()` in `markdown.js`), so the indent never reaches the page. Block and component HTML and JS are re-indented (never rewritten), CSS is laid out one declaration a line, JSON one value a line. One Ctrl+Z undoes it; the toolbar's format buttons do the same (`admin/js/lib/code-format.js`).
@@ -1,42 +1,44 @@
1
- let E=" ";export const DEFAULT_CODE_PREFS=Object.freeze({indent:"spaces",size:2,detect:!0,autoIndent:!0,continueLists:!0,shortTags:!0,tables:!0,formatOnSave:!1}),INDENT_SIZES=Object.freeze([2,4,8]);export function cleanCodePrefs(t={}){const e=DEFAULT_CODE_PREFS,n=s=>typeof t?.[s]=="boolean"?t[s]:e[s];return{indent:t?.indent==="tabs"?"tabs":"spaces",size:INDENT_SIZES.includes(Number(t?.size))?Number(t.size):e.size,detect:n("detect"),autoIndent:n("autoIndent"),continueLists:n("continueLists"),shortTags:n("shortTags"),tables:n("tables"),formatOnSave:n("formatOnSave")}}let S=cleanCodePrefs();export function setCodePrefs(t){S=cleanCodePrefs(t)}export const codePrefs=()=>S,prefUnit=()=>S.indent==="tabs"?" ":" ".repeat(S.size),unitFor=t=>S.detect?detectIndent(t,prefUnit()):prefUnit();export function detectIndent(t,e=" "){const n=String(t).split(`
2
- `).filter(l=>l.trim()),s=n.filter(l=>l.startsWith(" ")).length,i=n.filter(l=>l.startsWith(" ")).length;if(s>i)return" ";const r=n.map(l=>l.match(/^ */)[0].length).filter(l=>l>0);return r.length?r.filter(l=>l%4===2).length>r.length/5?" ":e===" ".repeat(8)&&r.every(l=>l%8===0)?e:" ":e}export function isFormatKey(t){return!t||!t.altKey||!t.shiftKey||t.ctrlKey||t.metaKey?!1:t.code==="KeyF"||String(t.key||"").toLowerCase()==="f"}export function formatCode(t,e){const n=String(t??"").replace(/\r\n?/g,`
3
- `);E=e==="md"?prefUnit():unitFor(n);try{switch(e){case"json":return{text:formatJson(n)};case"css":return{text:formatCss(n)};case"js":return{text:formatJs(n)};case"html":return{text:formatHtml(n)};case"md":return{text:formatMarkdown(n)};default:return{error:"Nothing to format here."}}}catch(s){return{error:s.message||"Could not format this."}}}export function formatJson(t){if(!t.trim())return t;try{JSON.parse(t)}catch(i){throw new Error(`Not valid JSON: ${i.message}`)}let e="",n=0;const s=()=>`
4
- `+E.repeat(n);for(let i=0;i<t.length;i++){const r=t[i];if(r==='"'){let o=i+1;for(;t[o]!=='"';)o+=t[o]==="\\"?2:1;e+=t.slice(i,o+1),i=o}else if(r==="{"||r==="["){const o=r==="{"?"}":"]",l=t.slice(i+1).search(/\S/);if(t[i+1+l]===o){e+=r+o,i+=l+1;continue}n++,e+=r+s()}else r==="}"||r==="]"?(n--,e+=s()+r):r===","?e+=","+s():r===":"?e+=": ":/\s/.test(r)||(e+=r)}return e+(t.endsWith(`
1
+ let b=" ";export const DEFAULT_CODE_PREFS=Object.freeze({indent:"spaces",size:2,detect:!0,autoIndent:!0,continueLists:!0,shortTags:!0,tables:!0,formatOnSave:!1}),INDENT_SIZES=Object.freeze([2,4,8]);export function cleanCodePrefs(t={}){const e=DEFAULT_CODE_PREFS,n=s=>typeof t?.[s]=="boolean"?t[s]:e[s];return{indent:t?.indent==="tabs"?"tabs":"spaces",size:INDENT_SIZES.includes(Number(t?.size))?Number(t.size):e.size,detect:n("detect"),autoIndent:n("autoIndent"),continueLists:n("continueLists"),shortTags:n("shortTags"),tables:n("tables"),formatOnSave:n("formatOnSave")}}let w=cleanCodePrefs();export function setCodePrefs(t){w=cleanCodePrefs(t)}export const codePrefs=()=>w,prefUnit=()=>w.indent==="tabs"?" ":" ".repeat(w.size),unitFor=t=>w.detect?detectIndent(t,prefUnit()):prefUnit();export function detectIndent(t,e=" "){const n=String(t).split(`
2
+ `).filter(i=>i.trim()),s=n.filter(i=>i.startsWith(" ")).length,r=n.filter(i=>i.startsWith(" ")).length;if(s>r)return" ";const o=n.map(i=>i.match(/^ */)[0].length).filter(i=>i>0);return o.length?o.filter(i=>i%4===2).length>o.length/5?" ":e===" ".repeat(8)&&o.every(i=>i%8===0)?e:" ":e}export function isFormatKey(t){return!t||!t.altKey||!t.shiftKey||t.ctrlKey||t.metaKey?!1:t.code==="KeyF"||String(t.key||"").toLowerCase()==="f"}export function formatCode(t,e){const n=String(t??"").replace(/\r\n?/g,`
3
+ `);b=e==="md"?prefUnit():unitFor(n);try{switch(e){case"json":return{text:formatJson(n)};case"css":return{text:formatCss(n)};case"js":return{text:formatJs(n)};case"html":return{text:formatHtml(n)};case"md":return{text:formatMarkdown(n)};default:return{error:"Nothing to format here."}}}catch(s){return{error:s.message||"Could not format this."}}}export function formatJson(t){if(!t.trim())return t;try{JSON.parse(t)}catch(r){throw new Error(`Not valid JSON: ${r.message}`)}let e="",n=0;const s=()=>`
4
+ `+b.repeat(n);for(let r=0;r<t.length;r++){const o=t[r];if(o==='"'){let l=r+1;for(;t[l]!=='"';)l+=t[l]==="\\"?2:1;e+=t.slice(r,l+1),r=l}else if(o==="{"||o==="["){const l=o==="{"?"}":"]",i=t.slice(r+1).search(/\S/);if(t[r+1+i]===l){e+=o+l,r+=i+1;continue}n++,e+=o+s()}else o==="}"||o==="]"?(n--,e+=s()+o):o===","?e+=","+s():o===":"?e+=": ":/\s/.test(o)||(e+=o)}return e+(t.endsWith(`
5
5
  `)?`
6
- `:"")}export function formatCss(t){if(!t.trim())return t;if(/\{\{\{?\s*[#/^\w]/.test(t))throw new Error("This CSS has {{placeholders}} in it - left as it is.");const e=[];let n=0,s="",i=!1,r="",o=!1,l=0;const c=()=>E.repeat(n),a=f=>{i&&e.length&&e[e.length-1]!==""&&!e[e.length-1].endsWith("{")&&e.push(""),i=!1,e.push(f)},h=()=>{o&&n===0?(i=!0,o=!1):(r.match(/\n/g)||[]).length>=2&&(i=!0),r=""},d=f=>{const m=f.match(/^(--[\w-]+|[-\w]+)\s*:\s*([\s\S]*)$/);return!m||f.startsWith("@")?f:`${m[1]}: ${m[2]}`},u=f=>{const m=s.trim();if(s="",!!m){if(f==="{"){const g=m.startsWith("@")?[m]:M(m,",");g.forEach((p,x)=>a(c()+p.trim()+(x<g.length-1?",":" {")));return}a(c()+d(m)+";")}};for(let f=0;f<t.length;f++){const m=t[f];if(m==="/"&&t[f+1]==="*"){const g=t.indexOf("*/",f+2),p=g<0?t.length:g+2,x=t.slice(f,p);if(s.trim())s+=x;else{h();const w=x.split(`
7
- `);a(c()+w[0]),e.push(...w.slice(1))}f=p-1;continue}if(m==='"'||m==="'"){s.trim()||h();let g=f+1;for(;g<t.length&&t[g]!==m&&t[g]!==`
8
- `;)g+=t[g]==="\\"?2:1;s+=t.slice(f,g+1),f=g;continue}if(/\s/.test(m)){s.trim()?s.endsWith(" ")||(s+=" "):r+=m;continue}if(s.trim()||h(),m==="("?l++:m===")"&&(l=Math.max(0,l-1)),l===0&&m==="{"){u("{"),n++,r="";continue}if(l===0&&m===";"){u(";");continue}if(l===0&&m==="}"){if(u(";"),n--,n<0)throw new Error("There is a } with no { before it.");i=!1,e.push(c()+"}"),r="",n===0&&(o=!0);continue}s+=m}if(s.trim()&&u(";"),n!==0)throw new Error(`${n} { left without a closing }.`);return e.join(`
6
+ `:"")}export function formatCss(t){if(!t.trim())return t;if(/\{\{\{?\s*[#/^\w]/.test(t))throw new Error("This CSS has {{placeholders}} in it - left as it is.");const e=[];let n=0,s="",r=!1,o="",l=!1,i=0;const c=()=>b.repeat(n),a=u=>{r&&e.length&&e[e.length-1]!==""&&!e[e.length-1].endsWith("{")&&e.push(""),r=!1,e.push(u)},f=()=>{l&&n===0?(r=!0,l=!1):(o.match(/\n/g)||[]).length>=2&&(r=!0),o=""},p=u=>{const m=u.match(/^(--[\w-]+|[-\w]+)\s*:\s*([\s\S]*)$/);return!m||u.startsWith("@")?u:`${m[1]}: ${m[2]}`},h=u=>{const m=s.trim();if(s="",!!m){if(u==="{"){const d=m.startsWith("@")?[m]:A(m,",");d.forEach((x,g)=>a(c()+x.trim()+(g<d.length-1?",":" {")));return}a(c()+p(m)+";")}};for(let u=0;u<t.length;u++){const m=t[u];if(m==="/"&&t[u+1]==="*"){const d=t.indexOf("*/",u+2),x=d<0?t.length:d+2,g=t.slice(u,x);if(s.trim())s+=g;else{f();const E=g.split(`
7
+ `);a(c()+E[0]),e.push(...E.slice(1))}u=x-1;continue}if(m==='"'||m==="'"){s.trim()||f();let d=u+1;for(;d<t.length&&t[d]!==m&&t[d]!==`
8
+ `;)d+=t[d]==="\\"?2:1;s+=t.slice(u,d+1),u=d;continue}if(/\s/.test(m)){s.trim()?s.endsWith(" ")||(s+=" "):o+=m;continue}if(s.trim()||f(),m==="("?i++:m===")"&&(i=Math.max(0,i-1)),i===0&&m==="{"){h("{"),n++,o="";continue}if(i===0&&m===";"){h(";");continue}if(i===0&&m==="}"){if(h(";"),n--,n<0)throw new Error("There is a } with no { before it.");r=!1,e.push(c()+"}"),o="",n===0&&(l=!0);continue}s+=m}if(s.trim()&&h(";"),n!==0)throw new Error(`${n} { left without a closing }.`);return e.join(`
9
9
  `)+`
10
- `}function M(t,e){const n=[];let s=0,i=null,r="";for(const o of t){if(i)o===i&&(i=null);else if(o==='"'||o==="'")i=o;else if("([{".includes(o))s++;else if(")]}".includes(o))s--;else if(o===e&&s===0){n.push(r),r="";continue}r+=o}return n.push(r),n}const j=/(^|[(,=:[!&|?{};+\-*%<>~^]|\b(?:return|typeof|case|do|else|in|of|new|delete|void|throw|yield|await))\s*$/;function A(t,e,n){let s=0;if(e.str){let i=0;for(;i<t.length&&t[i]!==e.str;)i+=t[i]==="\\"?2:1;if(i>=t.length){t.endsWith("\\")||(e.str=null);return}e.str=null,s=i+1}for(;s<t.length;){const i=e.stack[e.stack.length-1];if(e.comment){const o=t.indexOf("*/",s);if(o<0)return;e.comment=!1,s=o+2;continue}if(i==="`"){const o=t[s];if(o==="\\"){s+=2;continue}if(o==="`"){e.stack.pop(),s++;continue}if(o==="$"&&t[s+1]==="{"){e.stack.push("${"),s+=2;continue}s++;continue}const r=t[s];if(r==="/"&&t[s+1]==="/")return;if(r==="/"&&t[s+1]==="*"){e.comment=!0,s+=2;continue}if(r==='"'||r==="'"){let o=s+1;for(;o<t.length&&t[o]!==r;)o+=t[o]==="\\"?2:1;if(o>=t.length&&t.endsWith("\\")){e.str=r;return}s=o+1;continue}if(r==="`"){e.stack.push("`"),s++;continue}if(r==="/"&&j.test(t.slice(0,s))){let o=s+1,l=!1;for(;o<t.length;){const c=t[o];if(c==="\\"){o+=2;continue}if(c==="[")l=!0;else if(c==="]")l=!1;else if(c==="/"&&!l)break;o++}s=o+1;continue}if(r==="}"&&i==="${"){e.stack.pop(),s++;continue}r==="{"&&e.stack.length?e.stack.push("{"):r==="}"&&i==="{"&&e.stack.pop(),"{[(".includes(r)?n(r,s,!0):"}])".includes(r)&&n(r,s,!1),s++}}function b(t){return t.replace(/(["'`])(?:\\.|(?!\1).)*\1/g,'""').replace(/\/\*.*?(\*\/|$)/g,"").replace(/\/\/.*$/,"").trimEnd()}export function formatJs(t,e=0){const n=t.split(`
11
- `),s={comment:!1,str:null,stack:[]},i=[],r=[];let o="";const l=()=>{const c=i[i.length-1];return c?c.at+1+(c.sw&&c.inCase?1:0):0};if(n.forEach((c,a)=>{const h=s.stack[s.stack.length-1]==="`"||!!s.str,d=s.comment,u=c.trim();let f=c;if(h)f=c;else if(!u)f="";else if(d)f=E.repeat(e+l())+(u.startsWith("*")?" ":"")+u;else{const g=Math.min(i.length,(u.match(/^[}\])]+/)||[""])[0].length),p=i[i.length-1],x=/^(case\b.*|default\s*):/.test(u);let w;g?w=i[i.length-g].at:p?.sw&&x?w=p.at+1:w=l();const $=b(u),W=/^(\.(?!\.\.)|\?\.|[+\-*/%]|&&|\|\||\?\?|\?(?!\.)|:(?!:))/.test($)&&!x||/(=>|[^=!<>]=|[+\-*/%]|&&|\|\||\?\?|\?)$/.test(o)&&!g&&!/^[{[(]/.test($),T=$.startsWith("/")&&j.test(o);W&&!T&&!/^[}\])]/.test(u)&&w++,f=E.repeat(e+w)+u}r.push(f);const m=Math.round(f.match(/^[ \t]*/)[0].length/E.length)-e;if(h||d||u){const g=i[i.length-1];A(c,s,(p,x,w)=>{if(w){const $=p==="{"&&/\bswitch\s*\(.*\)\s*$/.test(b(c.slice(0,x)));i.push({at:h||d?l():m,sw:$,inCase:!1})}else i.pop()}),g?.sw&&!h&&!d&&/^(case\b.*|default\s*):/.test(u)&&(g.inCase=!0),!h&&!d&&(o=b(u))}}),s.comment||s.str||s.stack.some(c=>c!=="{"))throw new Error("A comment, string or template is left open.");return r.join(`
12
- `)}const O=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),R=new Set(["pre","textarea","script","style"]);export function formatHtml(t){const e=t.split(`
13
- `),n=[],s=[];let i="text",r=null,o=null;const l=a=>{const h=a.lines.join(`
14
- `);let d=null;try{const u=(a.open.match(/\btype\s*=\s*["']?([^"'\s>]*)/i)||[])[1]||"";a.name==="script"&&(!u||/module|javascript|ecmascript/i.test(u))?d=formatJs(h,a.level+1):a.name==="style"&&(d=N(formatCss(z(h)).replace(/\n$/,""),a.level+1))}catch{d=null}s.push(...(d??h).split(`
15
- `))},c=(a,h,d)=>{for(;h<a.length;){if(i==="comment"){const u=a.indexOf("-->",h);if(u<0)return;i="text",h=u+3;continue}if(i==="tag"){const u=a[h];if(r.text+=u,h++,r.q){u===r.q&&(r.q=null);continue}if(u==='"'||u==="'"){r.q=u;continue}if(u!==">")continue;i="text";const f=r;if(r=null,O.has(f.name)||/\/\s*>$/.test(f.text))continue;if(R.has(f.name)){const m=new RegExp(`</${f.name}\\s*>`,"i").exec(a.slice(h));if(m){h+=m.index+m[0].length;continue}o={name:f.name,level:f.level,open:f.text,lines:[]},i="raw";return}n.push(f.name);continue}if(a.startsWith("<!--",h)){i="comment",h+=4;continue}if(a.startsWith("{{",h)){const u=a.indexOf("}}",h+2);if(u<0)return;const f=a.slice(h+2,u).trim();/^#\w+/.test(f)?n.push("#"+f.match(/^#(\w+)/)[1]):/^\/\w+/.test(f)&&v(n,"#"+f.slice(1).trim()),h=u+2;continue}if(a[h]==="<"&&a[h+1]==="/"){const u=/^<\/([a-zA-Z][\w:-]*)\s*>/.exec(a.slice(h));if(u){v(n,u[1].toLowerCase()),h+=u[0].length;continue}}if(a[h]==="<"&&/[a-zA-Z]/.test(a[h+1]||"")){const u=/^<([a-zA-Z][\w:-]*)/.exec(a.slice(h))[1];i="tag",r={name:u.toLowerCase(),level:d,text:"<"+u,q:null},h+=1+u.length;continue}h++}};for(const a of e){const h=a.trim();if(i==="raw"){const f=new RegExp(`</${o.name}\\s*>`,"i").exec(a);if(!f){o.lines.push(a);continue}const m=o;if(o=null,i="text",m.name==="pre"||m.name==="textarea")s.push(...m.lines,a);else{const g=a.slice(0,f.index);g.trim()&&m.lines.push(g),m.lines.some(p=>p.trim())?l(m):s.push(...m.lines),s.push(E.repeat(m.level)+a.slice(f.index).trim())}c(a,f.index+f[0].length,m.level);continue}if(i==="comment"||i==="tag"&&r.q){i==="tag"&&(r.text+=`
16
- `),s.push(a),c(a,0,r?.level??0);continue}if(!h){s.push("");continue}let d;if(i==="tag")d=/^\/?>/.test(h)?r.level:r.level+1,r.text+=`
17
- `;else{let f=0;const m=/(?:<\/[a-zA-Z][\w:-]*\s*>|\{\{\s*\/\w+\s*\}\}|\{\{\s*else\b[^}]*\}\})\s*/y;for(let g=0;;){m.lastIndex=g;const p=m.exec(h);if(!p||(f++,/^\{\{\s*else/.test(p[0])))break;g=m.lastIndex}d=Math.max(0,n.length-f)}const u=E.repeat(d)+h;s.push(u),c(u,d*E.length,d)}return o&&s.push(...o.lines),s.join(`
18
- `)}function v(t,e){const n=t.lastIndexOf(e);n>=0&&(t.length=n)}function z(t){const e=t.split(`
19
- `),n=e.filter(i=>i.trim()).map(i=>i.match(/^[ \t]*/)[0].length),s=n.length?Math.min(...n):0;return e.map(i=>i.slice(Math.min(s,i.match(/^[ \t]*/)[0].length))).join(`
20
- `).replace(/^\n+|\n+$/g,"")}function N(t,e){return t.split(`
21
- `).map(n=>n&&E.repeat(e)+n).join(`
22
- `)}export const SHORT_TAG_CONTAINERS=new Set(["grid","row","col","card","box","header","footer","tabs","tab","accordion","item","carousel","slide","timeline","event","hero","banner","slideover","center","listgroup","table","dconfig","reveal","animate","pulse","shake","scramble","ripple","breathe","ambient","twinkle","fireworks","scribe","wait","render","redraw"]);export function shortTagLine(t){const e=String(t).trim().match(/^\[(\/?)([a-z][\w-]*)(?:\s[^\]]*)?\]$/i);return!e||!SHORT_TAG_CONTAINERS.has(e[2].toLowerCase())||!e[1]&&/\/\]$/.test(t.trim())?null:{name:e[2].toLowerCase(),close:!!e[1]}}function _(t){const e=[...t],n=new Set;let s=null,i=!1;t.forEach((l,c)=>{if(s){n.add(c);const h=l.match(/^ {0,3}(`{3,}|~{3,})\s*$/);h&&h[1][0]===s[0]&&h[1].length>=s.length&&(s=null);return}if(i||/^\s*<pre[\s>]/i.test(l)){n.add(c),i=!/<\/pre\s*>/i.test(l);return}const a=l.match(/^ {0,3}(`{3,}|~{3,})/);a&&(s=a[1],n.add(c))});const r=(l,c)=>{let a=0;const h=new RegExp(`\\[(\\/?)${l}(?:[\\s\\]])`,"gi");for(let d=c;d<t.length;d++)if(!n.has(d))for(const u of t[d].matchAll(h))if(!u[1])a++;else{if(a===0)return!0;a--}return!1},o=[];return t.forEach((l,c)=>{if(n.has(c))return;const a=shortTagLine(l);if(a)if(a.close){const h=o.lastIndexOf(a.name);if(h<0)return;o.length=h,e[c]=E.repeat(o.length)+l.trim()}else r(a.name,c+1)&&(e[c]=E.repeat(o.length)+l.trim(),o.push(a.name))}),e}export function formatMarkdown(t){if(!t.trim())return t;const e=t.split(`
23
- `),n=[];let s=null,i=!1;const r=l=>/^( {4}|\t)/.test(l),o=l=>{for(let c=l+1;c<e.length;c++)if(e[c].trim())return e[c];return""};for(let l=0;l<e.length;l++){const c=e[l];if(s){n.push(c);const f=c.match(/^ {0,3}(`{3,}|~{3,})\s*$/);f&&f[1][0]===s[0]&&f[1].length>=s.length&&(s=null);continue}if(i||/^\s*<pre[\s>]/i.test(c)){n.push(c),i=!/<\/pre\s*>/i.test(c);continue}const a=c.match(/^ {0,3}(`{3,}|~{3,})/);if(a){s=a[1],n.push(c.trimEnd());continue}if(S.tables&&q(e,l)){let f=l+2;for(;f<e.length&&/\|/.test(e[f])&&e[f].trim();)f++;n.push(...B(e.slice(l,f))),l=f-1;continue}if(!c.trim()){const f=n.length?n[n.length-1]:"",m=[...n].reverse().find(g=>g.trim())||"";if(!f.trim()&&!(r(m)&&r(o(l))))continue;n.push("");continue}if(r(c)){n.push(c);continue}const h=c.match(/[ \t]*$/)[0],d=c.slice(0,c.length-h.length),u=/ {2,}$/.test(h)&&(e[l+1]||"").trim()&&!/^\s*#/.test(d);n.push(u?d+" ":d)}for(;n.length&&!n[0].trim();)n.shift();for(;n.length&&!n[n.length-1].trim();)n.pop();return(S.shortTags?_(n):n).join(`
10
+ `}function A(t,e){const n=[];let s=0,r=null,o="";for(const l of t){if(r)l===r&&(r=null);else if(l==='"'||l==="'")r=l;else if("([{".includes(l))s++;else if(")]}".includes(l))s--;else if(l===e&&s===0){n.push(o),o="";continue}o+=l}return n.push(o),n}const j=/(^|[(,=:[!&|?{};+\-*%<>~^]|\b(?:return|typeof|case|do|else|in|of|new|delete|void|throw|yield|await))\s*$/;function R(t,e,n){let s=0;if(e.str){let r=0;for(;r<t.length&&t[r]!==e.str;)r+=t[r]==="\\"?2:1;if(r>=t.length){t.endsWith("\\")||(e.str=null);return}e.str=null,s=r+1}for(;s<t.length;){const r=e.stack[e.stack.length-1];if(e.comment){const l=t.indexOf("*/",s);if(l<0)return;e.comment=!1,s=l+2;continue}if(r==="`"){const l=t[s];if(l==="\\"){s+=2;continue}if(l==="`"){e.stack.pop(),s++;continue}if(l==="$"&&t[s+1]==="{"){e.stack.push("${"),s+=2;continue}s++;continue}const o=t[s];if(o==="/"&&t[s+1]==="/")return;if(o==="/"&&t[s+1]==="*"){e.comment=!0,s+=2;continue}if(o==='"'||o==="'"){let l=s+1;for(;l<t.length&&t[l]!==o;)l+=t[l]==="\\"?2:1;if(l>=t.length&&t.endsWith("\\")){e.str=o;return}s=l+1;continue}if(o==="`"){e.stack.push("`"),s++;continue}if(o==="/"&&j.test(t.slice(0,s))){let l=s+1,i=!1;for(;l<t.length;){const c=t[l];if(c==="\\"){l+=2;continue}if(c==="[")i=!0;else if(c==="]")i=!1;else if(c==="/"&&!i)break;l++}s=l+1;continue}if(o==="}"&&r==="${"){e.stack.pop(),s++;continue}o==="{"&&e.stack.length?e.stack.push("{"):o==="}"&&r==="{"&&e.stack.pop(),"{[(".includes(o)?n(o,s,!0):"}])".includes(o)&&n(o,s,!1),s++}}function $(t){return t.replace(/(["'`])(?:\\.|(?!\1).)*\1/g,'""').replace(/\/\*.*?(\*\/|$)/g,"").replace(/\/\/.*$/,"").trimEnd()}export function formatJs(t,e=0){const n=t.split(`
11
+ `),s={comment:!1,str:null,stack:[]},r=[],o=[];let l="";const i=()=>{const c=r[r.length-1];return c?c.at+1+(c.sw&&c.inCase?1:0):0};if(n.forEach((c,a)=>{const f=s.stack[s.stack.length-1]==="`"||!!s.str,p=s.comment,h=c.trim();let u=c;if(f)u=c;else if(!h)u="";else if(p)u=b.repeat(e+i())+(h.startsWith("*")?" ":"")+h;else{const d=Math.min(r.length,(h.match(/^[}\])]+/)||[""])[0].length),x=r[r.length-1],g=/^(case\b.*|default\s*):/.test(h);let E;d?E=r[r.length-d].at:x?.sw&&g?E=x.at+1:E=i();const S=$(h),C=/^(\.(?!\.\.)|\?\.|[+\-*/%]|&&|\|\||\?\?|\?(?!\.)|:(?!:))/.test(S)&&!g||/(=>|[^=!<>]=|[+\-*/%]|&&|\|\||\?\?|\?)$/.test(l)&&!d&&!/^[{[(]/.test(S),W=S.startsWith("/")&&j.test(l);C&&!W&&!/^[}\])]/.test(h)&&E++,u=b.repeat(e+E)+h}o.push(u);const m=Math.round(u.match(/^[ \t]*/)[0].length/b.length)-e;if(f||p||h){const d=r[r.length-1];R(c,s,(x,g,E)=>{if(E){const S=x==="{"&&/\bswitch\s*\(.*\)\s*$/.test($(c.slice(0,g)));r.push({at:f||p?i():m,sw:S,inCase:!1})}else r.pop()}),d?.sw&&!f&&!p&&/^(case\b.*|default\s*):/.test(h)&&(d.inCase=!0),!f&&!p&&(l=$(h))}}),s.comment||s.str||s.stack.some(c=>c!=="{"))throw new Error("A comment, string or template is left open.");return o.join(`
12
+ `)}const O=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),z=new Set(["pre","textarea","script","style"]);export function formatHtml(t){const e=t.split(`
13
+ `),n=[],s=[];let r="text",o=null,l=null;const i=a=>{const f=a.lines.join(`
14
+ `);let p=null;try{const h=(a.open.match(/\btype\s*=\s*["']?([^"'\s>]*)/i)||[])[1]||"";a.name==="script"&&(!h||/module|javascript|ecmascript/i.test(h))?p=formatJs(f,a.level+1):a.name==="style"&&(p=_(formatCss(N(f)).replace(/\n$/,""),a.level+1))}catch{p=null}s.push(...(p??f).split(`
15
+ `))},c=(a,f,p)=>{for(;f<a.length;){if(r==="comment"){const h=a.indexOf("-->",f);if(h<0)return;r="text",f=h+3;continue}if(r==="tag"){const h=a[f];if(o.text+=h,f++,o.q){h===o.q&&(o.q=null);continue}if(h==='"'||h==="'"){o.q=h;continue}if(h!==">")continue;r="text";const u=o;if(o=null,O.has(u.name)||/\/\s*>$/.test(u.text))continue;if(z.has(u.name)){const m=new RegExp(`</${u.name}\\s*>`,"i").exec(a.slice(f));if(m){f+=m.index+m[0].length;continue}l={name:u.name,level:u.level,open:u.text,lines:[]},r="raw";return}n.push(u.name);continue}if(a.startsWith("<!--",f)){r="comment",f+=4;continue}if(a.startsWith("{{",f)){const h=a.indexOf("}}",f+2);if(h<0)return;const u=a.slice(f+2,h).trim();/^#\w+/.test(u)?n.push("#"+u.match(/^#(\w+)/)[1]):/^\/\w+/.test(u)&&I(n,"#"+u.slice(1).trim()),f=h+2;continue}if(a[f]==="<"&&a[f+1]==="/"){const h=/^<\/([a-zA-Z][\w:-]*)\s*>/.exec(a.slice(f));if(h){I(n,h[1].toLowerCase()),f+=h[0].length;continue}}if(a[f]==="<"&&/[a-zA-Z]/.test(a[f+1]||"")){const h=/^<([a-zA-Z][\w:-]*)/.exec(a.slice(f))[1];r="tag",o={name:h.toLowerCase(),level:p,text:"<"+h,q:null},f+=1+h.length;continue}f++}};for(const a of e){const f=a.trim();if(r==="raw"){const u=new RegExp(`</${l.name}\\s*>`,"i").exec(a);if(!u){l.lines.push(a);continue}const m=l;if(l=null,r="text",m.name==="pre"||m.name==="textarea")s.push(...m.lines,a);else{const d=a.slice(0,u.index);d.trim()&&m.lines.push(d),m.lines.some(x=>x.trim())?i(m):s.push(...m.lines),s.push(b.repeat(m.level)+a.slice(u.index).trim())}c(a,u.index+u[0].length,m.level);continue}if(r==="comment"||r==="tag"&&o.q){r==="tag"&&(o.text+=`
16
+ `),s.push(a),c(a,0,o?.level??0);continue}if(!f){s.push("");continue}let p;if(r==="tag")p=/^\/?>/.test(f)?o.level:o.level+1,o.text+=`
17
+ `;else{let u=0;const m=/(?:<\/[a-zA-Z][\w:-]*\s*>|\{\{\s*\/\w+\s*\}\}|\{\{\s*else\b[^}]*\}\})\s*/y;for(let d=0;;){m.lastIndex=d;const x=m.exec(f);if(!x||(u++,/^\{\{\s*else/.test(x[0])))break;d=m.lastIndex}p=Math.max(0,n.length-u)}const h=b.repeat(p)+f;s.push(h),c(h,p*b.length,p)}return l&&s.push(...l.lines),s.join(`
18
+ `)}function I(t,e){const n=t.lastIndexOf(e);n>=0&&(t.length=n)}function N(t){const e=t.split(`
19
+ `),n=e.filter(r=>r.trim()).map(r=>r.match(/^[ \t]*/)[0].length),s=n.length?Math.min(...n):0;return e.map(r=>r.slice(Math.min(s,r.match(/^[ \t]*/)[0].length))).join(`
20
+ `).replace(/^\n+|\n+$/g,"")}function _(t,e){return t.split(`
21
+ `).map(n=>n&&b.repeat(e)+n).join(`
22
+ `)}export const SHORT_TAG_CONTAINERS=new Set(["grid","row","col","card","box","header","footer","tabs","tab","accordion","item","carousel","slide","timeline","event","hero","banner","slideover","center","listgroup","table","dconfig","reveal","animate","pulse","shake","scramble","ripple","breathe","ambient","twinkle","fireworks","scribe","wait","render","redraw"]);export function shortTagLine(t){const e=String(t).trim().match(/^\[(\/?)([a-z][\w-]*)(?:\s[^\]]*)?\]$/i);return!e||!SHORT_TAG_CONTAINERS.has(e[2].toLowerCase())||!e[1]&&/\/\]$/.test(t.trim())?null:{name:e[2].toLowerCase(),close:!!e[1]}}export function shortTagLayout(t){const e=t.map(()=>({tag:!1,depth:0,block:-1,fence:!1})),n=new Set;let s=null;t.forEach((i,c)=>{if(s){n.add(c);const f=i.match(/^\s*(`{3,}|~{3,})\s*$/);f&&f[1][0]===s[0]&&f[1].length>=s.length&&(s=null);return}const a=i.match(/^\s*(`{3,}|~{3,})/);a&&(s=a[1])});const r=(i,c)=>{let a=0;const f=new RegExp(`\\[(\\/?)${i}(?:[\\s\\]])`,"gi");for(let p=c;p<t.length;p++)if(!n.has(p))for(const h of t[p].matchAll(f))if(!h[1])a++;else{if(a===0)return!0;a--}return!1},o=[];t.forEach((i,c)=>{const a=o[o.length-1];if(e[c].depth=o.length,e[c].block=a?a.at:-1,n.has(c)){e[c].fence=!0;return}const f=shortTagLine(i);if(f)if(f.close){const p=o.map(h=>h.name).lastIndexOf(f.name);if(p<0)return;o.length=p,Object.assign(e[c],{tag:!0,depth:o.length})}else r(f.name,c+1)&&(e[c].tag=!0,o.push({name:f.name,at:c}))});const l=new Map;return t.forEach((i,c)=>{const a=e[c];if(a.tag||a.fence||a.block<0||!i.trim())return;const f=i.match(/^[ \t]*/)[0].length;l.set(a.block,Math.min(l.get(a.block)??1/0,f))}),e.map((i,c)=>{const a=t[c].match(/^[ \t]*/)[0].length,f=i.tag?a:i.block<0?0:Math.min(a,l.get(i.block)??0);return{...i,cut:f}})}function F(t){const e=shortTagLayout(t);return t.map((n,s)=>e[s].cut?n.slice(e[s].cut):n)}function q(t){const e=shortTagLayout(t);return t.map((n,s)=>{const r=e[s];return r.tag?b.repeat(r.depth)+n.trim():!r.depth||!n.trim()?n:b.repeat(r.depth)+n})}export function formatMarkdown(t){if(!t.trim())return t;const e=w.shortTags?F(t.split(`
23
+ `)):t.split(`
24
+ `),n=[];let s=null,r=!1;const o=i=>/^( {4}|\t)/.test(i),l=i=>{for(let c=i+1;c<e.length;c++)if(e[c].trim())return e[c];return""};for(let i=0;i<e.length;i++){const c=e[i];if(s){n.push(c);const u=c.match(/^ {0,3}(`{3,}|~{3,})\s*$/);u&&u[1][0]===s[0]&&u[1].length>=s.length&&(s=null);continue}if(r||/^\s*<pre[\s>]/i.test(c)){n.push(c),r=!/<\/pre\s*>/i.test(c);continue}const a=c.match(/^ {0,3}(`{3,}|~{3,})/);if(a){s=a[1],n.push(c.trimEnd());continue}if(w.tables&&K(e,i)){let u=i+2;for(;u<e.length&&/\|/.test(e[u])&&e[u].trim();)u++;n.push(...Z(e.slice(i,u))),i=u-1;continue}if(!c.trim()){const u=n.length?n[n.length-1]:"",m=[...n].reverse().find(d=>d.trim())||"";if(!u.trim()&&!(o(m)&&o(l(i))))continue;n.push("");continue}if(o(c)){n.push(c);continue}const f=c.match(/[ \t]*$/)[0],p=c.slice(0,c.length-f.length),h=/ {2,}$/.test(f)&&(e[i+1]||"").trim()&&!/^\s*#/.test(p);n.push(h?p+" ":p)}for(;n.length&&!n[0].trim();)n.shift();for(;n.length&&!n[n.length-1].trim();)n.pop();return(w.shortTags?q(n):n).join(`
24
25
  `)+`
25
- `}const F=/^\s*:?-+:?\s*$/;function k(t){let e=t.trim();e.startsWith("|")&&(e=e.slice(1)),e.endsWith("|")&&!e.endsWith("\\|")&&(e=e.slice(0,-1));const n=[];let s="";for(let i=0;i<e.length;i++){if(e[i]==="\\"&&e[i+1]==="|"){s+="\\|",i++;continue}if(e[i]==="|"){n.push(s.trim()),s="";continue}s+=e[i]}return n.push(s.trim()),n}function q(t,e){const n=t[e],s=t[e+1];if(!n||!s||!n.includes("|")||!s.includes("|")||/^\s{4,}/.test(n))return!1;const i=k(s);if(!(i.length>0&&i.every(r=>F.test(r))&&k(n).length===i.length))return!1;for(let r=e+2;r<t.length&&t[r].includes("|")&&t[r].trim();r++)if(k(t[r]).length>i.length)return!1;return!0}function B(t){const e=t[0].match(/^\s*/)[0],n=t.map(k),s=Math.max(...n.map(l=>l.length)),i=n[1].map(l=>l.startsWith(":")&&l.endsWith(":")?"c":l.endsWith(":")?"r":l.startsWith(":")?"l":""),r=l=>[...l].length,o=Array.from({length:s},(l,c)=>Math.max(3,...n.map((a,h)=>h===1?3:r(a[c]??""))));return n.map((l,c)=>{const a=Array.from({length:s},(h,d)=>{const u=o[d];if(c===1){const g=i[d]||"",p="-".repeat(u-(g==="c"?2:g?1:0));return g==="c"?`:${p}:`:g==="r"?`${p}:`:g==="l"?`:${p}`:p}const f=l[d]??"",m=u-r(f);return i[d]==="r"?" ".repeat(m)+f:i[d]==="c"?" ".repeat(Math.floor(m/2))+f+" ".repeat(Math.ceil(m/2)):f+" ".repeat(m)});return`${e}| ${a.join(" | ")} |`})}const y=(t,e)=>t.lastIndexOf(`
26
- `,e-1)+1,C=(t,e)=>{const n=t.indexOf(`
27
- `,e);return n<0?t.length:n};export function enterEdit(t,e,n,s){const i=y(t,e),r=t.slice(i,C(t,e)),o=t.slice(i,e),l=t.slice(n,C(t,n)),c=(o.match(/^[ \t]*/)||[""])[0],a=(p,x=p.length)=>({start:e,end:n,text:p,selStart:e+x,selEnd:e+x});if(s==="md"||!s){if(shortTagLine(r)&&e===n&&!l.trim()&&!I(t,i))return a(`
28
- `);if(S.continueLists&&!I(t,i)){const p=o.match(/^([ \t]*)((?:>[ \t]?)+)?([ \t]*)([-*+]|(\d+)([.)]))?([ \t]+)(\[[ xX]\][ \t]+)?/),x=p?.[2]||"",w=p?.[4]||"",$=/^\s*([-*_])(\s*\1){2,}\s*$/.test(r);if(p&&(x||w)&&!$&&p[0].length<=o.length){if(!r.slice(p[0].length).trim()&&e===n&&e>=i+p[0].length)return{start:i,end:C(t,e),text:p[1],selStart:i+p[1].length,selEnd:i+p[1].length};if(e>=i+p[0].length-(p[7]?.length||0)){const T=p[5]?`${Number(p[5])+1}${p[6]}`:w,L=`
29
- `+p[1]+x+(p[3]||"")+(w?T+(p[7]||" ")+(p[8]?"[ ] ":""):p[7]||"");return a(L)}}}return a(`
30
- `+(S.autoIndent?c:""))}if(!S.autoIndent)return a(`
31
- `);const h=(s==="html"?o:b(o)).trimEnd().slice(-1),d=l.trimStart()[0]||"",u={"{":"}","[":"]","(":")"};let f=!!u[h],m=f&&d===u[h];if(s==="html"||s==="css"){const p=o.match(/<([a-zA-Z][\w:-]*)(?:\s[^<>]*)?>\s*$/);p&&!O.has(p[1].toLowerCase())&&!/\/\s*>\s*$/.test(o)&&(f=!0,m=new RegExp(`^\\s*</${p[1]}\\s*>`,"i").test(l)),/\{\{\s*#\w+[^}]*\}\}\s*$/.test(o)&&(f=!0,m=/^\s*\{\{\s*\//.test(l))}if(!f)return a(`
32
- `+c);const g=`
33
- `+c+unitFor(t);if(m){const p=(t.slice(n).match(/^[ \t]*/)||[""])[0].length;return{start:e,end:n+p,text:g+`
34
- `+c,selStart:e+g.length,selEnd:e+g.length}}return a(g)}function I(t,e){let n=null;for(const s of t.slice(0,e).split(`
35
- `)){const i=s.match(/^\s*(`{3,}|~{3,})/);i&&(n?i[1][0]===n[0]&&i[1].length>=n.length&&!s.trim().slice(i[1].length).trim()&&(n=null):n=i[1])}return!!n}export function indentEdit(t,e,n,s,i=" "){const r=y(t,e),o=n>e&&t[n-1]===`
36
- `?n-1:n,l=C(t,o);if(!t.slice(e,n).includes(`
37
- `)&&!(s&&e===n))return null;const c=t.slice(r,l),a=c.split(`
38
- `),h=a.map(u=>s?u.startsWith(i)?u.slice(i.length):u.startsWith(" ")?u.slice(2):u.startsWith(" ")?u.slice(1):u.replace(/^ /,""):u.trim()?i+u:u),d=h.join(`
39
- `);if(d===c)return null;if(e===n){const u=a[0].length-h[0].length,f=Math.max(r,e-u);return{start:r,end:l,text:d,selStart:f,selEnd:f}}return{start:r,end:l,text:d,selStart:r,selEnd:r+d.length}}export function closerEdit(t,e,n,s,i=""){if(e!==n)return null;const r=y(t,e);let o=t.slice(r,e),l=s;if(i==="html"&&s==="/"&&/^[ \t]*<$/.test(o))o=o.slice(0,-1),l="</";else if(!"}])".includes(s))return null;if(!S.autoIndent)return null;const c=unitFor(t);if(!o||o.trim()||!o.endsWith(c))return null;const a=o.slice(0,-c.length),h=r+a.length+l.length;return{start:r,end:e,text:a+l,selStart:h,selEnd:h}}export const tabUnit=(t,e)=>e==="md"?prefUnit():unitFor(t);export function changedSpan(t,e){let n=0;const s=Math.min(t.length,e.length);for(;n<s&&t[n]===e[n];)n++;let i=0;for(;i<s-n&&t[t.length-1-i]===e[e.length-1-i];)i++;return{start:n,end:t.length-i,text:e.slice(n,e.length-i)}}export function caretAfterFormat(t,e,n){const s=t.slice(0,n).split(`
40
- `).length-1,i=t.split(`
41
- `)[s]??"",r=n-y(t,n),o=Math.max(0,r-i.match(/^[ \t]*/)[0].length),l=e.split(`
42
- `),c=Math.min(s,l.length-1);let a=0;for(let u=0;u<c;u++)a+=l[u].length+1;const h=l[c],d=h.match(/^[ \t]*/)[0].length;return a+Math.min(h.length,d+o)}export function applyEdit(t,e){const{start:n,end:s,text:i}=e;let r=!1;if(typeof document<"u"&&typeof document.execCommand=="function"){t.focus(),t.setSelectionRange(n,s);try{r=i?document.execCommand("insertText",!1,i):n===s||document.execCommand("delete")}catch{r=!1}}r||(t.value=t.value.slice(0,n)+i+t.value.slice(s),t.dispatchEvent(new Event("input",{bubbles:!0}))),t.setSelectionRange(e.selStart,e.selEnd)}export function formatTextarea(t,e){const n=t.value,s=formatCode(n,e);if(s.error)return s;if(s.text===n)return{text:n,unchanged:!0};const i=caretAfterFormat(n,s.text,t.selectionStart),r=changedSpan(n,s.text),o=t.scrollTop;return applyEdit(t,{...r,selStart:i,selEnd:i}),t.scrollTop=o,s}
26
+ `}const B=/^\s*:?-+:?\s*$/;function k(t){let e=t.trim();e.startsWith("|")&&(e=e.slice(1)),e.endsWith("|")&&!e.endsWith("\\|")&&(e=e.slice(0,-1));const n=[];let s="";for(let r=0;r<e.length;r++){if(e[r]==="\\"&&e[r+1]==="|"){s+="\\|",r++;continue}if(e[r]==="|"){n.push(s.trim()),s="";continue}s+=e[r]}return n.push(s.trim()),n}function K(t,e){const n=t[e],s=t[e+1];if(!n||!s||!n.includes("|")||!s.includes("|")||/^\s{4,}/.test(n))return!1;const r=k(s);if(!(r.length>0&&r.every(o=>B.test(o))&&k(n).length===r.length))return!1;for(let o=e+2;o<t.length&&t[o].includes("|")&&t[o].trim();o++)if(k(t[o]).length>r.length)return!1;return!0}function Z(t){const e=t[0].match(/^\s*/)[0],n=t.map(k),s=Math.max(...n.map(i=>i.length)),r=n[1].map(i=>i.startsWith(":")&&i.endsWith(":")?"c":i.endsWith(":")?"r":i.startsWith(":")?"l":""),o=i=>[...i].length,l=Array.from({length:s},(i,c)=>Math.max(3,...n.map((a,f)=>f===1?3:o(a[c]??""))));return n.map((i,c)=>{const a=Array.from({length:s},(f,p)=>{const h=l[p];if(c===1){const d=r[p]||"",x="-".repeat(h-(d==="c"?2:d?1:0));return d==="c"?`:${x}:`:d==="r"?`${x}:`:d==="l"?`:${x}`:x}const u=i[p]??"",m=h-o(u);return r[p]==="r"?" ".repeat(m)+u:r[p]==="c"?" ".repeat(Math.floor(m/2))+u+" ".repeat(Math.ceil(m/2)):u+" ".repeat(m)});return`${e}| ${a.join(" | ")} |`})}const y=(t,e)=>t.lastIndexOf(`
27
+ `,e-1)+1,T=(t,e)=>{const n=t.indexOf(`
28
+ `,e);return n<0?t.length:n};export function enterEdit(t,e,n,s){const r=y(t,e),o=t.slice(r,T(t,e)),l=t.slice(r,e),i=t.slice(n,T(t,n)),c=(l.match(/^[ \t]*/)||[""])[0],a=(x,g=x.length)=>({start:e,end:n,text:x,selStart:e+g,selEnd:e+g});if(s==="md"||!s){const x=shortTagLine(o);if(x&&e===n&&!i.trim()&&!L(t,r))return!w.shortTags||!w.autoIndent?a(`
29
+ `):a(`
30
+ `+c+(x.close?"":prefUnit()));if(w.continueLists&&!L(t,r)){const g=l.match(/^([ \t]*)((?:>[ \t]?)+)?([ \t]*)([-*+]|(\d+)([.)]))?([ \t]+)(\[[ xX]\][ \t]+)?/),E=g?.[2]||"",S=g?.[4]||"",C=/^\s*([-*_])(\s*\1){2,}\s*$/.test(o);if(g&&(E||S)&&!C&&g[0].length<=l.length){if(!o.slice(g[0].length).trim()&&e===n&&e>=r+g[0].length)return{start:r,end:T(t,e),text:g[1],selStart:r+g[1].length,selEnd:r+g[1].length};if(e>=r+g[0].length-(g[7]?.length||0)){const M=g[5]?`${Number(g[5])+1}${g[6]}`:S,v=`
31
+ `+g[1]+E+(g[3]||"")+(S?M+(g[7]||" ")+(g[8]?"[ ] ":""):g[7]||"");return a(v)}}}return a(`
32
+ `+(w.autoIndent?c:""))}if(!w.autoIndent)return a(`
33
+ `);const f=(s==="html"?l:$(l)).trimEnd().slice(-1),p=i.trimStart()[0]||"",h={"{":"}","[":"]","(":")"};let u=!!h[f],m=u&&p===h[f];if(s==="html"||s==="css"){const x=l.match(/<([a-zA-Z][\w:-]*)(?:\s[^<>]*)?>\s*$/);x&&!O.has(x[1].toLowerCase())&&!/\/\s*>\s*$/.test(l)&&(u=!0,m=new RegExp(`^\\s*</${x[1]}\\s*>`,"i").test(i)),/\{\{\s*#\w+[^}]*\}\}\s*$/.test(l)&&(u=!0,m=/^\s*\{\{\s*\//.test(i))}if(!u)return a(`
34
+ `+c);const d=`
35
+ `+c+unitFor(t);if(m){const x=(t.slice(n).match(/^[ \t]*/)||[""])[0].length;return{start:e,end:n+x,text:d+`
36
+ `+c,selStart:e+d.length,selEnd:e+d.length}}return a(d)}function L(t,e){let n=null;for(const s of t.slice(0,e).split(`
37
+ `)){const r=s.match(/^\s*(`{3,}|~{3,})/);r&&(n?r[1][0]===n[0]&&r[1].length>=n.length&&!s.trim().slice(r[1].length).trim()&&(n=null):n=r[1])}return!!n}export function indentEdit(t,e,n,s,r=" "){const o=y(t,e),l=n>e&&t[n-1]===`
38
+ `?n-1:n,i=T(t,l);if(!t.slice(e,n).includes(`
39
+ `)&&!(s&&e===n))return null;const c=t.slice(o,i),a=c.split(`
40
+ `),f=a.map(h=>s?h.startsWith(r)?h.slice(r.length):h.startsWith(" ")?h.slice(2):h.startsWith(" ")?h.slice(1):h.replace(/^ /,""):h.trim()?r+h:h),p=f.join(`
41
+ `);if(p===c)return null;if(e===n){const h=a[0].length-f[0].length,u=Math.max(o,e-h);return{start:o,end:i,text:p,selStart:u,selEnd:u}}return{start:o,end:i,text:p,selStart:o,selEnd:o+p.length}}export function closerEdit(t,e,n,s,r=""){if(e!==n)return null;const o=y(t,e);let l=t.slice(o,e),i=s;if(r==="html"&&s==="/"&&/^[ \t]*<$/.test(l))l=l.slice(0,-1),i="</";else if(!"}])".includes(s))return null;if(!w.autoIndent)return null;const c=unitFor(t);if(!l||l.trim()||!l.endsWith(c))return null;const a=l.slice(0,-c.length),f=o+a.length+i.length;return{start:o,end:e,text:a+i,selStart:f,selEnd:f}}export const tabUnit=(t,e)=>e==="md"?prefUnit():unitFor(t);export function changedSpan(t,e){let n=0;const s=Math.min(t.length,e.length);for(;n<s&&t[n]===e[n];)n++;let r=0;for(;r<s-n&&t[t.length-1-r]===e[e.length-1-r];)r++;return{start:n,end:t.length-r,text:e.slice(n,e.length-r)}}export function caretAfterFormat(t,e,n){const s=t.slice(0,n).split(`
42
+ `).length-1,r=t.split(`
43
+ `)[s]??"",o=n-y(t,n),l=Math.max(0,o-r.match(/^[ \t]*/)[0].length),i=e.split(`
44
+ `),c=Math.min(s,i.length-1);let a=0;for(let h=0;h<c;h++)a+=i[h].length+1;const f=i[c],p=f.match(/^[ \t]*/)[0].length;return a+Math.min(f.length,p+l)}export function applyEdit(t,e){const{start:n,end:s,text:r}=e;let o=!1;if(typeof document<"u"&&typeof document.execCommand=="function"){t.focus(),t.setSelectionRange(n,s);try{o=r?document.execCommand("insertText",!1,r):n===s||document.execCommand("delete")}catch{o=!1}}o||(t.value=t.value.slice(0,n)+r+t.value.slice(s),t.dispatchEvent(new Event("input",{bubbles:!0}))),t.setSelectionRange(e.selStart,e.selEnd)}export function formatTextarea(t,e){const n=t.value,s=formatCode(n,e);if(s.error)return s;if(s.text===n)return{text:n,unchanged:!0};const r=caretAfterFormat(n,s.text,t.selectionStart),o=changedSpan(n,s.text),l=t.scrollTop;return applyEdit(t,{...o,selStart:r,selEnd:r}),t.scrollTop=l,s}
@@ -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 Va}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 _a}from"../lib/editor-type.js";import{getProjectFromHash as Ft}from"../lib/project-context.js";import{attachSmoothCaret as Ka,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 Ua,problems as Ro,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 Ao,takeHeld as $o,wireHeldRouter as On}from"../lib/editor-hop.js";import{hopTarget as Ha}from"../lib/editor-hop-arrange.js";import{checkNewName as Rn,copyName as Lo,usageText as An}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 Ve,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 Vn,blockRows as _n,cleanLayout as jo,closeTab as Kn,componentRows as Un,componentStatusText as Hn,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 _e,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 Vt,formatTextarea as Ke,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=`
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 Va}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 _a}from"../lib/editor-type.js";import{getProjectFromHash as Ft}from"../lib/project-context.js";import{attachSmoothCaret as Ka,getCaretPreference as Sn,setCaretPreference as En}from"../lib/smooth-caret.js";import{SCREEN as Oo,bannerSection as Mn,draftIsStale as Tn,draftKey as ze,initialProject as Cn,makeDraft as Ua,problems as Ro,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 Ao,takeHeld as $o,wireHeldRouter as On}from"../lib/editor-hop.js";import{hopTarget as Ha}from"../lib/editor-hop-arrange.js";import{checkNewName as Rn,copyName as Lo,usageText as An}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 Ve,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 Vn,blockRows as _n,cleanLayout as jo,closeTab as Kn,componentRows as Un,componentStatusText as Hn,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 _e,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 Vt,formatTextarea as Ke,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>
@@ -68,8 +68,8 @@ import{api as h}from"../api.js";import{CardBuilder as en}from"../lib/card-builde
68
68
  <span data-help="Enter keeps the line's indentation, and in code goes one deeper after { ( [ or an opening tag; a closing } or &lt;/ typed on an empty line steps back."></span></label>
69
69
  <label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="continueLists.value"> Carry lists and quotes on
70
70
  <span data-help="Enter on a list item starts the next one (numbers count up, a task box comes back empty); Enter on an empty item ends the list. Shift+Enter is always a plain new line."></span></label>
71
- <label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="shortTags.value"> Indent short tags when formatting
72
- <span data-help="Shift+Alt+F indents the lines that hold only a short tag - [grid], [col], [card]\u2026 - by how deeply they nest. The content between them stays at the margin. The site never shows the indent."></span></label>
71
+ <label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="shortTags.value"> Indent inside short tags
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
74
  <label class="pe-settings-switch"><input type="checkbox" class="form-switch" data-model="formatOnSave.value"> Format on save
75
75
  <span data-help="Save formats the tab you are on first, as Shift+Alt+F would. Ctrl+Z still undoes it."></span></label>
@@ -122,7 +122,7 @@ The quick brown fox - 0O 1lI {} [] () =&gt; ==
122
122
  .pe-new [hidden] { display: none !important; }
123
123
  .pe-new-err { display: block; margin-top: .3rem; color: var(--dm-danger); font-size: var(--dm-text-xs); }
124
124
  .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 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,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||""),Ts=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":""),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)),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==="<"?"&lt;":"&amp;")+"</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(`
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==="<"?"&lt;":"&amp;")+"</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(`
126
126
  <span class="pe-toolbar-extras" style="display:contents">
127
127
  <button type="button" class="editor-view-btn" data-tip="Edit Custom CSS" data-on-click="toggleCss"
128
128
  data-bind-class="cssMode.value && 'active'"><span>CSS</span></button>
@@ -134,8 +134,8 @@ The quick brown fox - 0O 1lI {} [] () =&gt; ==
134
134
  <span class="pe-fold-icon" hidden data-bind-hidden="!folded.value"><span data-icon="chevrons-right" data-icon-size="10"></span></span>
135
135
  </button>
136
136
  <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 Tr)p[t].value=e[t]==null?"":String(e[t]);for(const t of Mr)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(),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(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,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: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,Mt(),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),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,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=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=>(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"),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=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 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),H())},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,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 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(_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:Ts,saveAll:Ws,dockKind:Qo,blockTagText:Ms,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,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,Ra,{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.
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
139
  color: var(--dm-primary);
140
- 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=>Hs(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||"",Aa=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",Aa),Te.addEventListener("auxclick",$a),Te.addEventListener("keydown",La),i(()=>{Te.removeEventListener("click",Aa),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)),_.addEventListener("input",()=>{Q.refresh(),ce.scrollTop=_.scrollTop,!gt&&(clearTimeout(Eo),Eo=setTimeout(ra,120),H())}),_.addEventListener("scroll",()=>{ce.scrollTop=_.scrollTop}),ve.addEventListener("scroll",()=>{ce.scrollTop=ve.scrollTop}),i(M.effect(()=>{for(const e of Object.keys(p))e!=="css"&&e!=="cssOpened"&&p[e].value;a.bodyRev.value,H()})),i(M.effect(()=>{a.bodyRev.value,a.docRev.value;const e=m?Ht():"";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,p.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=p.css.value;a.cssMode.value&&(Ut.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(()=>Va()),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,p.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:()=>Va()});const Qs=dt(d,{id:"page-editor-view",icon:"external-link",title:"View on the site",onClick:()=>{m?.isEdit&&window.open(p.urlPath.peek().trim()||m.id,"_blank","noopener")}}),Ba=()=>{if(!m?.isEdit||a.saving.peek()||!c())return;const e=m,t=K(),o=Ro({...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(Ra,{position:"bottom"})),Domma.icons.scan();let Ia={ids:[],active:""};try{Ia=Zn(S.get(ps))}catch{}const lt=Ha(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 Ae)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&&lt.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(`
140
+ h3 { font-size: 1.25rem; } */`,onChange:e=>Ma("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=>Hs(e,t)});i(()=>{for(const e of zt)ae[e].destroy()});const Me=O(".pe-tabs-list"),Nt=e=>e.target.closest(".pe-tab")?.dataset.id||"",Aa=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"))))};Me.addEventListener("click",Aa),Me.addEventListener("auxclick",$a),Me.addEventListener("keydown",La),i(()=>{Me.removeEventListener("click",Aa),Me.removeEventListener("auxclick",$a),Me.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(Me,{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)),_.addEventListener("input",()=>{Q.refresh(),ce.scrollTop=_.scrollTop,!gt&&(clearTimeout(Eo),Eo=setTimeout(ra,120),H())}),_.addEventListener("scroll",()=>{ce.scrollTop=_.scrollTop}),ve.addEventListener("scroll",()=>{ce.scrollTop=ve.scrollTop}),i(M.effect(()=>{for(const e of Object.keys(p))e!=="css"&&e!=="cssOpened"&&p[e].value;a.bodyRev.value,H()})),i(M.effect(()=>{a.bodyRev.value,a.docRev.value;const e=m?Ht():"";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,p.title.value,q(),z()})),i(M.effect(()=>{ce.hidden=!!(a.blockTab.value||a.compTab.value)}));let Mo=null;i(()=>clearTimeout(Mo)),i(M.effect(()=>{const e=p.css.value;a.cssMode.value&&(Ut.paint(),Cr(ce,e,ve),clearTimeout(Mo),Mo=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(()=>Va()),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":Mn(!!e,p.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:()=>Va()});const Qs=dt(d,{id:"page-editor-view",icon:"external-link",title:"View on the site",onClick:()=>{m?.isEdit&&window.open(p.urlPath.peek().trim()||m.id,"_blank","noopener")}}),Ba=()=>{if(!m?.isEdit||a.saving.peek()||!c())return;const e=m,t=K(),o=Ro({...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())},To=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,To])t&&(t.disabled=!e);To&&(To.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(Ra,{position:"bottom"})),Domma.icons.scan();let Ia={ids:[],active:""};try{Ia=Zn(S.get(ps))}catch{}const lt=Ha(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 Ae)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&&lt.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(`
141
141
  `).map((i,y)=>{const u=document.createElement("span");u.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),u.append(w,k),u})),d.scrollTop=v.scrollTop}function xr(d,b,v){if(!d||!b)return;const i=15,y=85,u=c=>Math.min(y,Math.max(i,c));let w=u(parseFloat(Pe().splitRatio)||50);const k=c=>{d.style.setProperty("--dm-editor-split",w+"%"),b.setAttribute("aria-valuenow",String(Math.round(w))),c&&Ue("splitRatio",w)};k(!1);const x=c=>{const A=d.getBoundingClientRect();A.width&&(w=u((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 V=w;if(c.key==="ArrowLeft")V=w-A;else if(c.key==="ArrowRight")V=w+A;else if(c.key==="Home")V=i;else if(c.key==="End")V=y;else if(c.key==="Enter"||c.key===" ")V=50;else return;c.preventDefault(),w=u(V),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 u=y.replace(/[\\[\]]/g,"\\$&"),w=i.replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/ /g,"%20");d.setSelectionRange(b,v),sn(d,`![${u}](${w})`),d.dispatchEvent(new Event("input",{bubbles:!0}))}function Or(d,b,v){const i=Object.entries(b||{});return d?(d.replaceChildren(...i.map(([y,u])=>new Option(u?.label||y,y))),i.some(([y])=>y===v)?v:i[0]?.[0]||v):v}async function Rr(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}),u=()=>{typeof b=="string"&&b&&![...d.options].some(x=>x.value===b)&&d.append(y(b,`${b} (custom)`))};if(!i.length)return u();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")),u()}
@@ -1538,11 +1538,13 @@ step Ctrl+Z undoes. The toolbar's format button does the same.
1538
1538
  more text stays), runs of blank lines down to one, pipe tables lined up.
1539
1539
  Indentation is never changed - four spaces would turn text into a code block -
1540
1540
  and fenced code is left exactly as written. Folded shortcodes are unfolded first.
1541
- The exception is a line holding only a container short tag (`[grid]`, `[col]`,
1542
- `[card]`, `[tabs]`, `[tab]`…, `SHORT_TAG_CONTAINERS`): those lines are indented
1543
- by nesting, so the structure reads at a glance. The content between them stays
1544
- at the margin. The renderer takes a tag line's indent off before anything else
1545
- (`unindentShortTags()` in `markdown.js`), so the indent never reaches the page.
1541
+ The exception is the container short tags (`[grid]`, `[col]`, `[card]`, `[tabs]`,
1542
+ `[tab]`…, `SHORT_TAG_CONTAINERS`): their lines and the content inside them are
1543
+ indented by nesting, so the structure reads at a glance; a nested list or fenced
1544
+ code keeps its own shape within that. The renderer takes the indent off before
1545
+ anything else (`unindentShortTags()` in `markdown.js`: a tag line loses all of
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.
1546
1548
  - **Block and component HTML, JS**: re-indented by nesting only; the code itself
1547
1549
  is never rewritten. `<pre>` and `<textarea>` keep their lines; a `<script>` or
1548
1550
  `<style>` inside HTML is indented as JS or CSS.
@@ -1555,14 +1557,14 @@ browser with the rest of the editor's settings: indent with spaces or tabs, the
1555
1557
  indent size (2, 4 or 8 - also how wide a tab shows), *Keep a file's own
1556
1558
  indentation* (on: a block, component or CSS already in tabs or fours keeps them;
1557
1559
  the page body always takes the setting), *Auto-indent*, *Carry lists and quotes
1558
- on*, *Indent short tags when formatting*, *Line up tables when formatting*, and
1560
+ on*, *Indent inside short tags*, *Line up tables when formatting*, and
1559
1561
  *Format on save* (off by default: Save formats the tab on show first; text that
1560
1562
  cannot be formatted is saved as it is).
1561
1563
 
1562
1564
  While typing, **Enter** keeps the line's indentation. In the body it carries a
1563
1565
  list or quote on (numbers count up, a task box comes back empty) and Enter on an
1564
- empty item ends the list; Shift+Enter is a plain new line. After a short tag line, the
1565
- next line starts at the margin, where content belongs. In code it goes one
1566
+ 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. In code it goes one
1566
1568
  deeper after `{`, `(`, `[`, an opening tag or `{{#if}}`, and with the caret
1567
1569
  between a pair the closer moves to its own line. **Tab / Shift+Tab** indent or
1568
1570
  outdent every selected line when the selection spans lines.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domma-cms",
3
- "version": "1.8.42",
3
+ "version": "1.8.44",
4
4
  "description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
5
5
  "type": "module",
6
6
  "main": "server/server.js",
@@ -423,10 +423,29 @@ export function buildBlockStyleTag(blockName, css) {
423
423
  * @param {object} e - Collection entry { id, data, meta }
424
424
  * @returns {string}
425
425
  */
426
+ /**
427
+ * A filled block goes into Markdown as HTML, and a blank line ends an HTML block:
428
+ * what follows, indented, marked then shows as code - raw tags on the page. A
429
+ * placeholder alone on its line with nothing to fill it (` {{bio}}` with no
430
+ * bio) made exactly that blank line, so such a line goes. The template's OWN
431
+ * blank lines stay: they are how a template hands a Markdown value to marked.
432
+ * Each line is filled by itself, in one pass as before.
433
+ */
434
+ function fillTemplateLines(template, fill) {
435
+ const PLACEHOLDER = /\{\{\{(\w+)\}\}\}|\{\{([\w_]+)(?::([^{}]+))?\}\}/g;
436
+ const out = [];
437
+ for (const line of template.split('\n')) {
438
+ const filled = line.replace(PLACEHOLDER, fill);
439
+ if (!filled.trim() && line.trim() && /\{\{/.test(line)) continue;
440
+ out.push(filled);
441
+ }
442
+ return out.join('\n');
443
+ }
444
+
426
445
  function interpolateBlockTemplate(blockTemplate, e) {
427
446
  // One pass: a raw value put in (pre-rendered HTML) is never read again for
428
447
  // placeholders - text that shows "{{title}}" keeps it.
429
- return blockTemplate.replace(/\{\{\{(\w+)\}\}\}|\{\{([\w_]+)(?::([^{}]+))?\}\}/g, (_, raw, key, fmt) => {
448
+ return fillTemplateLines(blockTemplate, (_, raw, key, fmt) => {
430
449
  // Entry values never carry a shortcode into the page (inertShortcodes);
431
450
  // the template's own markup is untouched.
432
451
  if (raw !== undefined) return inertShortcodes(String(e.data?.[raw] ?? ''));
@@ -510,7 +529,7 @@ function renderCollectionBlocks(entries, blockTemplate, emptyMsg, ctaOpts, cols,
510
529
  function renderBlockFromAttrs(tmpl, attrs, blockName = '') {
511
530
  // Triple-brace raw pass-through and `{{field}}` (optional `:format`, e.g. `{{date:DD MMM YYYY}}`)
512
531
  // in one pass, so a raw value is never read again for placeholders.
513
- const rendered = tmpl.replace(/\{\{\{(\w+)\}\}\}|\{\{([\w_]+)(?::([^{}]+))?\}\}/g, (_, rawKey, key, fmt) => {
532
+ const rendered = fillTemplateLines(tmpl, (_, rawKey, key, fmt) => {
514
533
  if (rawKey !== undefined) return String(attrs[rawKey] ?? '');
515
534
  const raw = attrs[key] ?? '';
516
535
  if (fmt) {
@@ -1858,25 +1877,92 @@ export function parseShortcodeAttrs(attrStr) {
1858
1877
  let scrubCallId = 0;
1859
1878
 
1860
1879
  /**
1861
- * The container short tags whose own lines the editor's format indents by nesting
1862
- * (SHORT_TAG_CONTAINERS in admin/js/lib/code-format.js - keep the two lists the same;
1863
- * tests/admin/code-format.test.js checks). Their processors replace only the tag, so
1864
- * the indent before it would stay in front of the HTML, and marked reads four
1865
- * spaces as a code block. A line holding nothing but one of these tags loses its
1866
- * indent here, before anything else runs, so the indent is only ever for the reader.
1880
+ * The container short tags the editor's format indents by nesting, with the
1881
+ * content inside them (SHORT_TAG_CONTAINERS in admin/js/lib/code-format.js -
1882
+ * keep the two lists the same; tests/admin/code-format.test.js checks). Their
1883
+ * processors replace only the tag, and marked reads four spaces as a code
1884
+ * block, so before anything else runs the indent comes off again: a tag line
1885
+ * loses all of it, and the content of each container loses the indent its
1886
+ * lines share - a page written flat is untouched, and what is indented further
1887
+ * (a nested list, code) keeps the difference. The indent is only ever for the reader.
1867
1888
  */
1868
1889
  export const SHORT_TAG_CONTAINERS = Object.freeze([
1869
1890
  'grid', 'row', 'col', 'card', 'box', 'header', 'footer', 'tabs', 'tab', 'accordion', 'item', 'carousel', 'slide',
1870
1891
  'timeline', 'event', 'hero', 'banner', 'slideover', 'center', 'listgroup', 'table', 'dconfig', 'reveal', 'animate',
1871
1892
  'pulse', 'shake', 'scramble', 'ripple', 'breathe', 'ambient', 'twinkle', 'fireworks', 'scribe', 'wait', 'render', 'redraw'
1872
1893
  ]);
1873
- const INDENTED_SHORT_TAG = new RegExp(`^[ \\t]+(?=\\[\\/?(?:${SHORT_TAG_CONTAINERS.join('|')})(?:\\s[^\\]\\n]*)?\\][ \\t]*$)`, 'gim');
1894
+ const CONTAINER_SET = new Set(SHORT_TAG_CONTAINERS);
1895
+
1896
+ /** A line that is one container short tag and nothing else: {name, close} or null. */
1897
+ function shortTagOf(line) {
1898
+ const t = line.trim();
1899
+ const m = t.match(/^\[(\/?)([a-z][\w-]*)(?:\s[^\]]*)?\]$/i);
1900
+ if (!m || !CONTAINER_SET.has(m[2].toLowerCase()) || (!m[1] && /\/\]$/.test(t))) return null;
1901
+ return {name: m[2].toLowerCase(), close: Boolean(m[1])};
1902
+ }
1903
+
1904
+ /** Each line's indent as written, and how much of it is nesting (removed by unindentShortTags). */
1905
+ export function shortTagLayout(lines) {
1906
+ const info = lines.map(() => ({tag: false, depth: 0, block: -1, fence: false}));
1907
+ const fenced = new Set();
1908
+ let fence = null;
1909
+ lines.forEach((line, i) => {
1910
+ if (fence) { fenced.add(i); const c = line.match(/^\s*(`{3,}|~{3,})\s*$/); if (c && c[1][0] === fence[0] && c[1].length >= fence.length) fence = null; return; }
1911
+ const f = line.match(/^\s*(`{3,}|~{3,})/);
1912
+ if (f) fence = f[1];
1913
+ });
1914
+ const hasCloser = (name, from) => {
1915
+ let depth = 0;
1916
+ const re = new RegExp(`\\[(\\/?)${name}(?:[\\s\\]])`, 'gi');
1917
+ for (let j = from; j < lines.length; j++) {
1918
+ if (fenced.has(j)) continue;
1919
+ for (const m of lines[j].matchAll(re)) {
1920
+ if (!m[1]) depth++;
1921
+ else if (depth === 0) return true;
1922
+ else depth--;
1923
+ }
1924
+ }
1925
+ return false;
1926
+ };
1927
+ const stack = [];
1928
+ lines.forEach((line, i) => {
1929
+ const top = stack[stack.length - 1];
1930
+ info[i].depth = stack.length;
1931
+ info[i].block = top ? top.at : -1;
1932
+ if (fenced.has(i)) { info[i].fence = true; return; }
1933
+ const t = shortTagOf(line);
1934
+ if (!t) return;
1935
+ if (t.close) {
1936
+ const at = stack.map(x => x.name).lastIndexOf(t.name);
1937
+ if (at < 0) return;
1938
+ stack.length = at;
1939
+ Object.assign(info[i], {tag: true, depth: stack.length});
1940
+ } else if (hasCloser(t.name, i + 1)) {
1941
+ info[i].tag = true;
1942
+ stack.push({name: t.name, at: i});
1943
+ }
1944
+ });
1945
+ // What the content of each container shares (fenced lines follow their fence's line).
1946
+ const shared = new Map();
1947
+ lines.forEach((line, i) => {
1948
+ const x = info[i];
1949
+ if (x.tag || x.fence || x.block < 0 || !line.trim()) return;
1950
+ const w = line.match(/^[ \t]*/)[0].length;
1951
+ shared.set(x.block, Math.min(shared.get(x.block) ?? Infinity, w));
1952
+ });
1953
+ return info.map((x, i) => {
1954
+ const own = lines[i].match(/^[ \t]*/)[0].length;
1955
+ const cut = x.tag ? own : x.block < 0 ? 0 : Math.min(own, shared.get(x.block) ?? 0);
1956
+ return {...x, cut};
1957
+ });
1958
+ }
1874
1959
 
1875
- /** A short tag line's indent off (above); fenced code keeps its own. */
1960
+ /** The nesting indent off every short tag line and the content inside (above). */
1876
1961
  export function unindentShortTags(markdown) {
1877
- if (!/^[ \t]+\[/m.test(markdown)) return markdown;
1878
- const {scrubbed, restore} = scrubCodeRegions(markdown);
1879
- return restore(scrubbed.replace(INDENTED_SHORT_TAG, ''));
1962
+ if (!/^[ \t]+\S/m.test(markdown) || !/\[\/?[a-z]/i.test(markdown)) return markdown;
1963
+ const lines = markdown.split('\n');
1964
+ const layout = shortTagLayout(lines);
1965
+ return lines.map((l, i) => (layout[i].cut ? l.slice(layout[i].cut) : l)).join('\n');
1880
1966
  }
1881
1967
 
1882
1968
  export function scrubCodeRegions(markdown, preserveIndented = false) {
@@ -1900,7 +1986,10 @@ export function scrubCodeRegions(markdown, preserveIndented = false) {
1900
1986
  // Inline code spans (single or multiple backticks, non-greedy)
1901
1987
  scrubbed = scrubbed.replace(/`+[^`\n]+`+/g, placeholder);
1902
1988
 
1903
- const restore = (s) => s.replace(new RegExp(`\\x02SC${callId}:(\\d+)\\x03`, 'g'), (_, i) => store[parseInt(i, 10)]);
1989
+ // A stored region can hold an earlier placeholder of this same call - an indented
1990
+ // line (preserveIndented) holding an inline <code> - so what comes back is
1991
+ // restored too. Restoring it once left "SC1:0" on the page.
1992
+ const restore = (s) => s.replace(new RegExp(`\\x02SC${callId}:(\\d+)\\x03`, 'g'), (_, i) => restore(store[parseInt(i, 10)]));
1904
1993
  return {scrubbed, restore};
1905
1994
  }
1906
1995