domma-cms 0.92.1 → 0.94.0
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/CLAUDE.md +5 -3
- package/admin/css/admin.css +1 -1
- package/admin/js/app.js +2 -2
- package/admin/js/lib/action-editor-arrange.js +1 -1
- package/admin/js/lib/api-tokens-arrange.js +2 -2
- package/admin/js/lib/block-editor-arrange.js +1 -1
- package/admin/js/lib/blocks-arrange.js +1 -1
- package/admin/js/lib/collection-entries-arrange.js +1 -1
- package/admin/js/lib/components-arrange.js +1 -1
- package/admin/js/lib/dashboard-arrange.js +1 -1
- package/admin/js/lib/dates.js +1 -0
- package/admin/js/lib/forms-arrange.js +1 -1
- package/admin/js/lib/media-arrange.js +1 -1
- package/admin/js/lib/notifications-arrange.js +1 -1
- package/admin/js/lib/pages-arrange.js +1 -1
- package/admin/js/lib/related.js +1 -1
- package/admin/js/lib/timeline-builder.js +2 -2
- package/admin/js/templates/action-editor.html +6 -5
- package/admin/js/templates/actions-list.html +1 -1
- package/admin/js/templates/contacts.html +1 -1
- package/admin/js/templates/docs/api-actions.html +86 -60
- package/admin/js/templates/docs/api-authentication.html +159 -123
- package/admin/js/templates/docs/api-builder.html +197 -0
- package/admin/js/templates/docs/api-collections.html +199 -259
- package/admin/js/templates/docs/api-external.html +225 -0
- package/admin/js/templates/docs/api-forms.html +268 -0
- package/admin/js/templates/docs/api-layouts.html +70 -45
- package/admin/js/templates/docs/api-media.html +57 -80
- package/admin/js/templates/docs/api-navigation.html +66 -22
- package/admin/js/templates/docs/api-pages.html +109 -129
- package/admin/js/templates/docs/api-plugins.html +123 -61
- package/admin/js/templates/docs/api-scaffold.html +185 -0
- package/admin/js/templates/docs/api-settings.html +72 -64
- package/admin/js/templates/docs/api-users.html +74 -107
- package/admin/js/templates/docs/api-views.html +68 -54
- package/admin/js/templates/docs/components-howto.html +20 -17
- package/admin/js/templates/docs/components-reference.html +13 -16
- package/admin/js/templates/docs/components-rules.html +7 -6
- package/admin/js/templates/docs/components-walkthrough.html +19 -19
- package/admin/js/templates/docs/tutorial-crud.html +71 -40
- package/admin/js/templates/docs/tutorial-forms.html +51 -35
- package/admin/js/templates/docs/tutorial-plugin.html +132 -56
- package/admin/js/templates/docs/usage-actions.html +61 -15
- package/admin/js/templates/docs/usage-collections.html +108 -0
- package/admin/js/templates/docs/usage-cta-shortcode.html +14 -3
- package/admin/js/templates/docs/usage-dconfig.html +0 -3
- package/admin/js/templates/docs/usage-editions.html +213 -0
- package/admin/js/templates/docs/usage-media.html +22 -6
- package/admin/js/templates/docs/usage-navigation.html +74 -18
- package/admin/js/templates/docs/usage-pages.html +60 -20
- package/admin/js/templates/docs/usage-plugins.html +89 -17
- package/admin/js/templates/docs/usage-shortcodes.html +123 -70
- package/admin/js/templates/docs/usage-site-settings.html +50 -18
- package/admin/js/templates/docs/usage-tools.html +73 -0
- package/admin/js/templates/docs/usage-users-roles.html +99 -20
- package/admin/js/templates/docs/usage-views.html +36 -19
- package/admin/js/templates/documentation.html +153 -32
- package/admin/js/templates/page-editor.html +0 -5
- package/admin/js/templates/plugin-guide.html +15 -0
- package/admin/js/templates/plugin-guides.html +21 -0
- package/admin/js/templates/pro-docs.html +53 -234
- package/admin/js/templates/tutorials.html +5 -4
- package/admin/js/views/actions-list.js +3 -3
- package/admin/js/views/analytics.js +5 -5
- package/admin/js/views/api-endpoint-editor.js +2 -2
- package/admin/js/views/block-editor.js +4 -4
- package/admin/js/views/blocks.js +4 -4
- package/admin/js/views/collection-editor.js +4 -4
- package/admin/js/views/collection-entries.js +7 -7
- package/admin/js/views/component-editor.js +2 -2
- package/admin/js/views/contacts.js +22 -20
- package/admin/js/views/context-menu-editor.js +5 -5
- package/admin/js/views/doc-pages.js +1 -1
- package/admin/js/views/form-editor.js +4 -4
- package/admin/js/views/form-submissions.js +2 -2
- package/admin/js/views/index.js +1 -1
- package/admin/js/views/media.js +3 -3
- package/admin/js/views/menu-editor.js +13 -13
- package/admin/js/views/menu-locations.js +2 -2
- package/admin/js/views/my-profile.js +1 -1
- package/admin/js/views/page-editor.js +8 -8
- package/admin/js/views/plugin-guides.js +5 -0
- package/admin/js/views/project-detail.js +2 -2
- package/admin/js/views/project-settings.js +1 -1
- package/admin/js/views/role-editor.js +4 -4
- package/admin/js/views/search.js +2 -2
- package/admin/js/views/seo.js +17 -17
- package/admin/js/views/settings.js +3 -3
- package/admin/js/views/theme.js +3 -3
- package/admin/js/views/user-editor.js +1 -1
- package/admin/js/views/users.js +2 -2
- package/admin/js/views/view-editor.js +1 -1
- package/bin/cli.js +13 -13
- package/bin/lib/node-version.js +29 -0
- package/package.json +1 -1
- package/plugins/_lib/admin/mail/compose-window.js +3 -2
- package/plugins/_lib/admin/mail/reader-view.js +7 -6
- package/plugins/_lib/admin/mail/scheduling.js +4 -2
- package/plugins/_lib/admin/mail/templates.js +4 -4
- package/plugins/_lib/admin/ui/dates.js +85 -0
- package/plugins/blog/CLAUDE.md +31 -22
- package/plugins/blog/admin/views/blog.js +3 -2
- package/plugins/blog/admin/views/comments.js +2 -1
- package/plugins/blog/admin/views/post-editor.js +4 -4
- package/plugins/blog/blocks/blog-card-row.html +1 -1
- package/plugins/blog/blocks/blog-card.html +2 -2
- package/plugins/blog/blocks/blog-post-classic.html +2 -2
- package/plugins/blog/blocks/blog-post-essay.html +2 -2
- package/plugins/blog/blocks/blog-post-feature.html +2 -2
- package/plugins/blog/blocks/blog-post-minimal.html +2 -2
- package/plugins/blog/blocks/blog-post-sidebar.html +2 -2
- package/plugins/blog/blocks/blog-post-split.html +2 -2
- package/plugins/blog/docs/guide.md +205 -0
- package/plugins/blog/lib/layouts.js +3 -3
- package/plugins/blog/lib/page.js +2 -1
- package/plugins/blog/plugin.js +3 -3
- package/plugins/blog/plugin.json +4 -4
- package/plugins/blog/tests/layouts.test.js +6 -0
- package/plugins/feedback/CLAUDE.md +22 -3
- package/plugins/feedback/admin/lib/kit.js +6 -7
- package/plugins/feedback/admin/views/feedback.js +79 -10
- package/plugins/feedback/admin/views/send.js +28 -6
- package/plugins/feedback/docs/guide.md +95 -0
- package/plugins/feedback/lib/receiver.js +9 -2
- package/plugins/feedback/lib/sender.js +3 -2
- package/plugins/feedback/plugin.js +54 -6
- package/plugins/feedback/plugin.json +4 -4
- package/plugins/feedback/tests/api.test.js +74 -2
- package/plugins/free-tier.lock.json +49 -44
- package/plugins/mail-reader/CLAUDE.md +33 -18
- package/plugins/mail-reader/docs/guide.md +147 -0
- package/plugins/mail-reader/plugin.json +1 -1
- package/plugins/security/CLAUDE.md +4 -1
- package/plugins/security/admin/views/security.js +5 -5
- package/plugins/security/docs/guide.md +170 -0
- package/plugins/security/plugin.js +2 -1
- package/plugins/security/plugin.json +2 -1
- package/plugins/shopping-cart/CLAUDE.md +7 -1
- package/plugins/shopping-cart/admin/lib/kit.js +5 -2
- package/plugins/shopping-cart/admin/views/orders.js +4 -4
- package/plugins/shopping-cart/admin/views/overview.js +2 -2
- package/plugins/shopping-cart/docs/guide.md +191 -0
- package/plugins/shopping-cart/lib/render.js +2 -1
- package/plugins/shopping-cart/plugin.json +3 -3
- package/public/js/collection-browser.js +2 -2
- package/public/js/site.js +1 -1
- package/scripts/gen-instance-secret.js +3 -1
- package/scripts/setup.js +3 -1
- package/server/middleware/auth.js +2 -1
- package/server/routes/api/actions.js +47 -27
- package/server/routes/api/blocks.js +2 -1
- package/server/routes/api/collections.js +16 -52
- package/server/routes/api/contacts.js +66 -3
- package/server/routes/api/documentation.js +42 -0
- package/server/routes/api/notifications.js +3 -2
- package/server/routes/api/users.js +10 -6
- package/server/server.js +16 -1
- package/server/services/actions.js +110 -34
- package/server/services/adapterRegistry.js +169 -16
- package/server/services/adapters/FileAdapter.js +25 -0
- package/server/services/adapters/MongoAdapter.js +23 -0
- package/server/services/collections.js +104 -1
- package/server/services/connectionManager.js +12 -0
- package/server/services/dates.js +81 -0
- package/server/services/docs.js +13 -2
- package/server/services/markdown.js +75 -26
- package/server/services/notification-sources.js +6 -5
- package/server/services/passwordReset.js +2 -1
- package/server/services/permissionRegistry.js +3 -2
- package/server/services/pluginGuides.js +255 -0
- package/server/services/pluginInstaller.js +54 -13
- package/server/services/plugins.js +29 -1
- package/server/services/presetCollections.js +31 -5
- package/server/services/renderer.js +2 -2
- package/server/services/sidebarBadges.js +3 -1
- package/server/services/tools.js +4 -2
- package/server/templates/page.html +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{api as
|
|
1
|
+
import{api as de}from"../api.js";import{addBannerAction as je}from"../lib/plugin-chrome.js";import{helpPopovers as qe}from"../lib/help-popover.js";import{onceClosed as st,openMenuAt as Ne}from"../lib/tool-kit.js";import{makeIconInput as it}from"/admin/js/lib/shortcode-modal.js";import{makePageInput as rt}from"/admin/js/lib/page-picker.js";import{ACCENTS as ct,ACTION_ARG as K,ACTION_GROUPS as lt,EDITABLE_TYPES as dt,NEEDS_TARGET as ut,SELF_DISABLING as mt,checkMenu as pt,duplicateItem as vt,formFromMenu as Re,insertItem as ft,itemForm as ht,itemFromForm as Fe,itemRow as bt,moveItem as yt,newItem as gt,previewItems as xt,previewable as Pe,recordFromForm as kt,removeItem as Y,slugify as wt,snapshot as ue,splitList as Q,themeFromForm as Et}from"../lib/context-menu-editor-arrange.js";import{fmtDateTime as Mt}from"../lib/dates.js";const St=/^\/context-menus\/(new|edit\/[^/?#]+)\/?(\?.*)?$/,N=c=>`context-menu-editor.draft.${c||"new"}`,At=`
|
|
2
2
|
<div class="cmx-row" data-index="{{index}}" tabindex="0" data-bind-class="cls">
|
|
3
3
|
<span class="cmx-icon" aria-hidden="true" data-name="{{icon}}"></span>
|
|
4
4
|
<span class="cmx-type">{{typeLabel}}</span>
|
|
@@ -9,7 +9,7 @@ import{api as ue}from"../api.js";import{addBannerAction as qe}from"../lib/plugin
|
|
|
9
9
|
<button type="button" class="cmx-down" data-bind-disabled="last" aria-label="Move down" title="Move down (Alt+\u2193)">\u2193</button>
|
|
10
10
|
</span>
|
|
11
11
|
<button type="button" class="cmx-kebab" aria-label="Actions for {{text}}" title="Actions">\u22EE</button>
|
|
12
|
-
</div>`,
|
|
12
|
+
</div>`,Tt='<span class="cmx-chip" data-bind-class="cls">{{text}}</span>',It="<small>{{text}}</small>";function C(c){return String(c??"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Lt(c){const u=document.createElement("template");return u.innerHTML=c.trim(),u.content.firstElementChild}let X=null;function me(){if(X){try{X.destroy()}catch{}X=null}const c=document.getElementById("ctx-preview");if(c&&E.contextMenu&&E.contextMenu.registry)for(const u of E.contextMenu.registry(c))try{u.destroy()}catch{}}function pe(c,u){const l=c.querySelector(".dm-plugin-banner-name");if(!l)return;const L=l.querySelector(".dm-plugin-banner-sep");if(L){for(;L.nextSibling;)L.nextSibling.remove();l.appendChild(document.createTextNode(u))}}let k=null,He=!1;const Z=c=>String(c||"").split("?")[0].replace(/\/$/,"");function Ct(){He||!window.R?.use||(He=!0,R.use((c,u,l)=>!(St.test(u?.path||"")&&Z(c?.path)!==Z(u?.path))||!k?.dirty()?l():E.confirm("This context menu has unsaved changes. Leave anyway? They are kept as a draft for your next visit.").then(w=>{w?l():history.replaceState(null,"",`#${u.path}`)})),M.subscribe("router:afterChange",({to:c}={})=>{if(k&&Z(c?.path)!==k.path){const u=k;k=null,u.dispose()}}))}export const contextMenuEditorView={templateUrl:"/admin/js/templates/context-menu-editor.html",async onMount(c){if(Ct(),k){const e=k;k=null,e.dispose()}me();const u=[],l=e=>(u.push(e),e);let L=!1;const w=c.get(0),m=w.querySelector(".cmx")||w,B=()=>!L&&m.isConnected,ve=location.hash.match(/^#\/context-menus\/edit\/([^?#]+)/),p=ve?decodeURIComponent(ve[1]):null,h=!p,Ke=Z(location.hash.replace(/^#/,""));let g=null;if(!h){const e=E.loader(w,{type:"dots"});try{g=await de.contextMenus.get(p)}catch(n){e.destroy(),E.toast(`Could not load "${p}": ${n.message||n}`,{type:"error"});return}if(e.destroy(),!m.isConnected)return}const O=Re(g),r={};for(const[e,n]of Object.entries(O))r[e]=M.observable(n);const _=()=>Object.fromEntries(Object.keys(r).map(e=>[e,r[e].peek()])),fe=()=>Object.fromEntries(Object.keys(r).map(e=>[e,r[e].value])),s=M.observable(Array.isArray(g?.items)?g.items:[]),U=M.observable(ue(O,s.peek())),z=M.computed(()=>ue(fe(),s.value)!==U.value),G=M.observable(!1),V=M.observable(!1),F=M.observable([]),$=M.computed(()=>pt(fe(),s.value,{isNew:h})),Be=M.computed(()=>{const e=$.value.errors;if(V.value)return e;const n={};for(const t of Object.keys(e))t!=="items"&&String(r[t]?.value??"").trim()&&(n[t]=e[t]);return n}),he=M.computed(()=>{const e=V.value?$.value.errors:{};return{binding:!!(e.name||e.slug||e.selector),items:!!e.items||$.value.itemErrors.some(Boolean),appearance:!!(e.opacity||e.accent)}});let ee=!h;l(M.effect(()=>{const e=r.name.value;ee||(r.slug.value=wt(e))}));const te=M.observable([]);l(M.effect(()=>{const e=s.value,n=$.value.itemErrors;te.value=e.map((t,i)=>({...bt(t,i,e.length,n[i]||""),key:`${i}:${JSON.stringify(t)}`}))}));const x=m.querySelector("#ctx-items");l(M.effect(()=>{te.value,requestAnimationFrame(()=>{x?.isConnected&&(x.querySelectorAll(".cmx-icon[data-name]").forEach(e=>{const n=e.dataset.name;if(!n||e.dataset.drawn===n)return;e.dataset.drawn=n;const t=document.createElement("span");t.setAttribute("data-icon",n),t.setAttribute("data-icon-size","14"),e.replaceChildren(t)}),I.scan(x))})}));const _e=M.computed(()=>{const e=[];e.push(r.enabled.value?{text:"On",cls:"is-ok"}:{text:"Off",cls:"is-warn"});const n=Q(r.pages.value).length,t=Q(r.projects.value).length;e.push({text:n||t?`${n+t} scope rule${n+t===1?"":"s"}`:"Site-wide",cls:""});const i=s.value.filter(o=>!["divider","header"].includes(o?.type||"item")).length;return e.push({text:`${i} item${i===1?"":"s"} to click`,cls:i?"":"is-danger"}),r.selector.value.trim()&&e.push({text:r.selector.value.trim(),cls:""}),e});let ne=null;function Ue(){if(!B())return;me();const e=s.peek();if(!Pe(e))return;const n=Et(_());X=E.contextMenu("#ctx-preview",{cursor:"glyph",items:xt(e),inherit:!1,accent:n.accent,transition:n.transition,density:n.density,radius:n.radius,shadow:n.shadow,opacity:n.opacity})}l(M.effect(()=>{s.value,r.accent.value,r.transition.value,r.density.value,r.radius.value,r.shadow.value,r.opacity.value,clearTimeout(ne),ne=setTimeout(Ue,120)})),l(()=>{clearTimeout(ne),me()});const ze=M.computed(()=>Pe(s.value)?"Right-click here to try the menu":"Add an item to try the menu here"),ae=e=>be(e),A=e=>{s.value=e};function P(e){requestAnimationFrame(()=>x?.querySelector(`.cmx-row[data-index="${e}"]`)?.focus())}function D(e,n){n<0||n>=s.peek().length||(A(yt(s.peek(),e,n)),P(n))}function j(e,n=s.peek().length){const t=gt(e);A(ft(s.peek(),n,t)),e!=="divider"&&be(n,{isAdd:!0})}function Ge(e){const n=s.peek(),t=n[e];if(!t)return[];const i=t.type||"item";return[{header:i==="divider"?"Divider":t.text||"(no text)"},{label:i==="divider"?"Change\u2026":"Edit\u2026",icon:"edit",action:()=>ae(e)},{type:"divider"},{label:"Move up",icon:"arrow-up",disabled:e===0,action:()=>D(e,e-1)},{label:"Move down",icon:"arrow-down",disabled:e===n.length-1,action:()=>D(e,e+1)},{label:"Duplicate",icon:"copy",action:()=>{A(vt(s.peek(),e)),P(e+1)}},{label:"Add below",icon:"plus",submenu:[{label:"Item",action:()=>j("item",e+1)},{label:"Heading",action:()=>j("header",e+1)},{label:"Divider",action:()=>j("divider",e+1)}]},{type:"divider"},{label:"Remove",icon:"trash",danger:!0,action:()=>{A(Y(s.peek(),e)),P(Math.max(0,e-1))}}]}let v=null;function be(e,{isAdd:n=!1}={}){const t=s.peek()[e];if(!t)return;if(v)try{v.so.close(!0)}catch{}const i=ht(t),o={};for(const[a,d]of Object.entries(i))o[a]=M.observable(d);const J=()=>Object.fromEntries(Object.keys(o).map(a=>[a,o[a].peek()])),Xe=JSON.stringify(i),se=()=>JSON.stringify(J())!==Xe,Ae=!dt.includes(i.type),ie=Array.isArray(t.submenu)&&t.submenu.length,Te={...o,locked:Ae,notLocked:!Ae,hasSub:ie,subText:ie?`Opens a submenu of ${t.submenu.length} - kept as it is (edit it in the file).`:"",isItem:M.computed(()=>o.type.value!=="divider"&&o.type.value!=="header"),hasText:M.computed(()=>o.type.value!=="divider"),showAction:M.computed(()=>o.type.value!=="divider"&&o.type.value!=="header"&&!ie),argLabel:M.computed(()=>K[o.action.value]?.label||""),note:M.computed(()=>mt[o.action.value]||ut[o.action.value]||""),problem:M.computed(()=>{const a=Fe(Object.fromEntries(Object.keys(o).map(d=>[d,o[d].value])),t);return a.type==="divider"?"":String(a.text||"").trim()?K[a.action?.type]?.required&&!String(a.action?.[K[a.action.type].key]||"").trim()?`Needs a ${K[a.action.type].label.toLowerCase()}.`:"":"Needs text."})},y=E.slideover({title:n?"New item":i.type==="divider"?"Divider":`Edit ${C(i.text||"item")}`,size:"sm",position:"right"}),Ze=lt.map(a=>`<optgroup label="${C(a.label)}">${Object.entries(a.actions).map(([d,W])=>`<option value="${C(d)}">${C(W)}</option>`).join("")}</optgroup>`).join(""),T=Lt(`
|
|
13
13
|
<div class="cmx-form">
|
|
14
14
|
<div data-bind-hidden="locked">
|
|
15
15
|
<label class="form-label" for="cmx-i-type">Type
|
|
@@ -27,11 +27,11 @@ import{api as ue}from"../api.js";import{addBannerAction as qe}from"../lib/plugin
|
|
|
27
27
|
<label class="form-label" for="cmx-i-icon">Icon <small class="cmx-hint-inline">(optional)</small></label>
|
|
28
28
|
<div class="cmx-icon-mount"></div>
|
|
29
29
|
</div>
|
|
30
|
-
<p class="cmx-note" data-bind-hidden="!hasSub">${C(
|
|
30
|
+
<p class="cmx-note" data-bind-hidden="!hasSub">${C(Te.subText)}</p>
|
|
31
31
|
<div data-bind-hidden="!showAction.value">
|
|
32
32
|
<label class="form-label" for="cmx-i-action">Does
|
|
33
33
|
<span data-help-title="What it does" data-help="A fixed set of actions, on purpose: nothing typed here runs as script on your pages. Some grey themselves out when they do not apply to the click - the note under the choice says when."></span></label>
|
|
34
|
-
<select id="cmx-i-action" class="form-select" data-model="action.value">${
|
|
34
|
+
<select id="cmx-i-action" class="form-select" data-model="action.value">${Ze}</select>
|
|
35
35
|
<small class="cmx-hint" data-bind-hidden="!note.value" data-bind-text="note.value"></small>
|
|
36
36
|
</div>
|
|
37
37
|
<div data-bind-hidden="!argLabel.value || !showAction.value">
|
|
@@ -51,4 +51,4 @@ import{api as ue}from"../api.js";import{addBannerAction as qe}from"../lib/plugin
|
|
|
51
51
|
<button type="button" class="btn btn-sm btn-ghost" data-on-click="cancel">Cancel</button>
|
|
52
52
|
<button type="button" class="btn btn-sm btn-primary" data-on-click="done"><span data-icon="check" data-icon-size="13"></span> Done</button>
|
|
53
53
|
</div>
|
|
54
|
-
</div>`),
|
|
54
|
+
</div>`),q=it("edit",i.icon);q.input.id="cmx-i-icon",q.input.classList.add("form-input");const Ie=()=>{o.icon.value=q.input.value};q.input.addEventListener("input",Ie),T.querySelector(".cmx-icon-mount").appendChild(q.el);const re=T.querySelector(".cmx-arg-mount");let f=null;const ce=()=>{o.arg.value=f.value};function Le(){f?.removeEventListener("input",ce),re.replaceChildren();const a=K[o.action.peek()];if(!a){f=null;return}if(a.key==="url"){const d=rt(a.placeholder,o.arg.peek());f=d.input,re.appendChild(d.el)}else f=document.createElement("input"),f.type="text",f.className="form-input",f.placeholder=a.placeholder,f.value=o.arg.peek(),re.appendChild(f);f.id="cmx-i-arg",f.addEventListener("input",ce)}let Ce=o.action.peek();const et=M.effect(()=>{const a=o.action.value;a!==Ce&&(Ce=a,o.arg.value="",Le())});Le();const Oe=()=>{const a=Fe(J(),t),d=[...s.peek()],W=d.indexOf(t);W!==-1&&(d[W]=a,A(d))};let H=!1,le=!1;const $e={done:()=>{Oe(),H=!0,y.close(),P(e)},cancel:()=>y.close(),remove:()=>{const a=s.peek().indexOf(t);a!==-1&&A(Y(s.peek(),a)),H=!0,y.close()}};y.element.appendChild(T);const tt=qe(T),nt=M.applyBindings(Te,T,{methods:$e}),at=a=>{(a.ctrlKey||a.metaKey)&&a.key==="Enter"&&(a.preventDefault(),$e.done())};T.addEventListener("keydown",at);const De={so:y,dirty:se,apply:Oe};v=De,st(y,()=>{et(),nt.dispose(),tt(),q.input.removeEventListener("input",Ie),f?.removeEventListener("input",ce),v===De&&(v=null)});const ot=y.close.bind(y);y.close=async a=>{if(!H&&a!==!0&&se()){if(le)return;le=!0;const d=await E.confirm("Discard the changes to this item?");if(le=!1,!d)return}if(!H&&n&&a!==!0&&!se()){const d=s.peek().indexOf(t);d!==-1&&A(Y(s.peek(),d))}return H=!0,ot()},I.scan(T),y.open(),requestAnimationFrame(()=>T.querySelector(i.type==="divider"?"#cmx-i-type":"#cmx-i-text")?.focus())}l(()=>{if(v){const e=v;e.dirty()&&e.apply();try{e.so.close(!0)}catch{}}});async function oe(){if(G.peek())return;V.value=!0,F.value=[];const e=$.peek();if(!e.ok){const t=Object.keys(e.errors).length;E.toast(`Not saved yet - ${t===1?"one thing needs":`${t} things need`} fixing (marked in red).`,{type:"warning"});const i=he.peek(),o=i.binding?0:i.items?1:i.appearance?2:-1;o>=0&&We?.activate?.(o);return}G.value=!0;const n=kt(_(),s.peek());try{if(h)await de.contextMenus.create(n);else{const t=await de.contextMenus.update(p,n);t?.items&&(s.value=t.items)}if(!B())return;U.value=ue(_(),s.peek());try{S.remove?S.remove(N(p)):S.set(N(p),null)}catch{}window.dispatchEvent(new CustomEvent("dm:sidebar-count",{detail:{url:"#/context-menus"}})),h?(E.toast("Context menu created.",{type:"success"}),location.hash="#/context-menus"):(E.toast("Context menu saved.",{type:"success"}),pe(w,r.name.peek()||p))}catch(t){F.value=String(t.message||t).split("; ").map((i,o)=>({key:String(o),text:i})),m.querySelector(".cmx-alert")?.scrollIntoView({behavior:"smooth",block:"nearest"})}finally{G.value=!1}}function Ve(){E.confirm("Throw away your unsaved changes to this menu?").then(e=>{if(!e||!B())return;const n=Re(g);for(const[t,i]of Object.entries(n))r[t].value=i;s.value=Array.isArray(g?.items)?g.items:[],F.value=[]})}m.querySelector("#ctx-items").innerHTML=At,m.querySelector(".cmx-chips").innerHTML=Tt,m.querySelector(".cmx-server-errors").innerHTML=It;const ye=m.querySelector("#ctx-accent");if(O.accent&&!ct.includes(O.accent)&&ye){const e=document.createElement("option");e.value=O.accent,e.textContent=`Custom (${O.accent})`,ye.appendChild(e)}const Je={...r,items:s,rows:te,chips:_e,dirty:z,saving:G,err:Be,tabBad:he,serverErrors:F,isNew:h,notNew:!h,previewText:ze,serverError:M.computed(()=>F.value.length>0),saveText:M.computed(()=>h?"Create menu":"Save"),problemText:M.computed(()=>V.value&&!$.value.ok?" - some need fixing before they can be saved":""),scopeText:M.computed(()=>{const e=Q(r.pages.value),n=Q(r.projects.value);return!e.length&&!n.length?"Site-wide: every page carries this menu.":`Only ${[e.length&&`pages matching ${e.join(", ")}`,n.length&&`pages in ${n.join(", ")}`].filter(Boolean).join(", or ")}.`})},We=E.tabs(m.querySelector("#ctx-tabs"),{tabSelector:".tab-item",panelSelector:".tab-panel"}),Ye=M.applyBindings(Je,m,{methods:{save:()=>oe(),discard:()=>Ve(),addItem:()=>j("item"),addHeader:()=>j("header"),addDivider:()=>j("divider")}});l(()=>Ye.dispose()),l(qe(m,{position:"bottom"}));const ge=m.querySelector("#ctx-slug"),xe=()=>{ee=!0};ge?.addEventListener("input",xe),l(()=>ge?.removeEventListener("input",xe));const Qe=E.contextMenu(x,{cursor:"glyph",match:".cmx-row",inherit:!1,density:"compact",items:e=>Ge(Number(e.dataset.index))});l(()=>Qe?.destroy?.());const ke=e=>{const n=e.target.closest(".cmx-row");if(!n)return;const t=Number(n.dataset.index);if(e.target.closest(".cmx-kebab")){Ne(e.target.closest(".cmx-kebab"));return}if(e.target.closest(".cmx-up")){D(t,t-1);return}if(e.target.closest(".cmx-down")){D(t,t+1);return}ae(t)},we=e=>{const n=e.target.closest(".cmx-row");if(!n||e.target!==n)return;const t=Number(n.dataset.index);e.key==="F10"&&e.shiftKey?(e.preventDefault(),Ne(n)):e.key==="Enter"?(e.preventDefault(),ae(t)):e.altKey&&e.key==="ArrowUp"?(e.preventDefault(),D(t,t-1)):e.altKey&&e.key==="ArrowDown"?(e.preventDefault(),D(t,t+1)):e.key==="Delete"&&(e.preventDefault(),A(Y(s.peek(),t)),P(Math.max(0,t-1)))};x.addEventListener("click",ke),x.addEventListener("keydown",we),l(()=>{x.removeEventListener("click",ke),x.removeEventListener("keydown",we)}),h?pe(w,"New menu"):pe(w,g?.name||p),je(c,{id:"ctx-editor-back",icon:"arrow-left",title:"All context menus",onClick:()=>{location.hash="#/context-menus"}}),je(c,{id:"ctx-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>oe()});const Ee=e=>{!(e.ctrlKey||e.metaKey)||e.key!=="s"||v||(e.preventDefault(),e.stopImmediatePropagation(),oe())};document.addEventListener("keydown",Ee,!0),l(()=>document.removeEventListener("keydown",Ee,!0));const Me=()=>{if(z.peek())try{S.set(N(p),{form:_(),items:s.peek(),base:U.peek(),at:new Date().toISOString()})}catch{}},Se=e=>{v?.dirty()&&v.apply(),z.peek()&&(Me(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",Se),l(()=>window.removeEventListener("beforeunload",Se)),k={path:Ke,dirty:()=>z.peek()||!!v?.dirty(),dispose(){if(L=!0,v){const e=v;e.dirty()&&e.apply();try{e.so.close(!0)}catch{}}Me(),u.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(m);let b=null;try{b=S.get(N(p))}catch{}if(b?.form){try{S.remove?S.remove(N(p)):S.set(N(p),null)}catch{}const e=b.base&&b.base!==U.peek(),n=b.at?` (${Mt(b.at)})`:"",t=h?"the new context menu you started":`"${C(g?.name||p)}"`,i=e?`You left unsaved changes to ${t}${n}, but it has been saved since. Restore your version anyway?`:`You left unsaved changes to ${t}${n}. Restore them?`;if(await E.confirm(i)&&B()){for(const[o,J]of Object.entries(b.form))r[o]&&o!==(h?"":"slug")&&(r[o].value=J);h&&b.form.slug&&(ee=!0),Array.isArray(b.items)&&(s.value=b.items)}}}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mountScaffolder as i}from"../lib/crud-tutorial.js";function t(o,
|
|
1
|
+
import{mountScaffolder as i}from"../lib/crud-tutorial.js";function t(o,s){return{templateUrl:`/admin/js/templates/docs/${o}.html`,async onMount(e){typeof s=="function"&&s(e),Domma.icons.scan(),Domma.syntax.scan()}}}export const docViews={tutorialCrud:t("tutorial-crud",o=>{const s=o.find("#tutorial-scaffolder-mount").get(0);s&&i(s,null,null)}),tutorialPlugin:t("tutorial-plugin"),tutorialForms:t("tutorial-forms"),componentsReference:t("components-reference"),componentsHowto:t("components-howto"),componentsWalkthrough:t("components-walkthrough"),componentsRules:t("components-rules")};const a=["pages","media","navigation","dconfig","shortcodes","site-settings","plugins","users-roles","views","actions","cta-shortcode","editions","collections","tools"],c=["authentication","pages","settings","layouts","navigation","media","users","plugins","collections","views","actions","forms","scaffold","external","builder"],n=o=>o.split("-").map(s=>s.charAt(0).toUpperCase()+s.slice(1)).join("");for(const o of a)docViews["usage"+n(o)]=t(`usage-${o}`);for(const o of c)docViews["apiRef"+n(o)]=t(`api-${o}`);
|