@collidecreatives/edit-mode 0.1.0 → 0.2.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/README.md +12 -0
- package/dist/browser.global.js +9 -2
- package/dist/browser.global.js.map +1 -1
- package/dist/index.cjs +270 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +270 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,6 +56,8 @@ initClientEditMode({
|
|
|
56
56
|
queryParam: "edit",
|
|
57
57
|
queryValue: "true",
|
|
58
58
|
sessionKey: "collide-edit-mode",
|
|
59
|
+
storageKey: "collide-edit-mode:draft",
|
|
60
|
+
autoSave: true,
|
|
59
61
|
brandName: "Edit Mode",
|
|
60
62
|
accentColour: "#1e40af",
|
|
61
63
|
editableSelector: "h1,h2,h3,h4,h5,h6,p,li,blockquote,figcaption,label,legend,dt,dd,th,td,a,button",
|
|
@@ -64,6 +66,16 @@ initClientEditMode({
|
|
|
64
66
|
});
|
|
65
67
|
```
|
|
66
68
|
|
|
69
|
+
## Navigation while editing
|
|
70
|
+
|
|
71
|
+
Internal links are rewritten to keep `?edit=true` when clients move around the site.
|
|
72
|
+
Link text is editable. To visit a link while edit mode is on:
|
|
73
|
+
|
|
74
|
+
- select the link and use **Open link** in the panel, or
|
|
75
|
+
- `Ctrl`/`⌘`-click the link.
|
|
76
|
+
|
|
77
|
+
Drafts auto-save before navigation, on each edit, and when the page is hidden.
|
|
78
|
+
|
|
67
79
|
## Opt out in templates
|
|
68
80
|
|
|
69
81
|
```html
|
package/dist/browser.global.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
"use strict";var CollideEditMode=(()=>{var
|
|
2
|
-
`),document.head.appendChild(e),e}function
|
|
1
|
+
"use strict";var CollideEditMode=(()=>{var w=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var K=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var R=(t,e)=>{for(var n in e)w(t,n,{get:e[n],enumerable:!0})},V=(t,e,n,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of K(e))!H.call(t,a)&&a!==n&&w(t,a,{get:()=>e[a],enumerable:!(i=P(e,a))||i.enumerable});return t};var U=t=>V(w({},"__esModule",{value:!0}),t);var ce={};R(ce,{initClientEditMode:()=>y});var j="h1,h2,h3,h4,h5,h6,p,li,blockquote,figcaption,label,legend,dt,dd,th,td,a,button",B="[data-no-edit],[data-edit-mode-skip],form,input,textarea,select,option,script,style,svg,canvas,iframe,.cem-edit-banner,.cem-panel,.cem-toast",F=new Set(["IMG","PICTURE","SVG","VIDEO","CANVAS","IFRAME","SCRIPT","STYLE"]),A=1,z={queryParam:"edit",queryValue:"true",sessionKey:"collide-edit-mode",brandName:"Edit Mode",accentColour:"#1e40af",editableSelector:j,skipSelector:B,autoSave:!0};function J(){return typeof window<"u"&&typeof document<"u"}function G(t){if(t.enabled!==void 0)return t.enabled;let n=new URL(window.location.href).searchParams.get(t.queryParam);return(t.queryValue===null?n!==null:n===t.queryValue)||window.sessionStorage.getItem(t.sessionKey)==="1"}function Y(t){let e=document.createElement("style");return e.dataset.editModeStyle="true",e.textContent=[`.cem-edit-banner{position:fixed;top:0;left:0;right:0;z-index:2147483640;background:${t};color:#fff;display:flex;align-items:center;justify-content:center;gap:8px;padding:8px 92px 8px 16px;font:13px/1.4 system-ui,-apple-system,sans-serif;box-shadow:0 1px 8px rgba(0,0,0,.18)}`,".cem-edit-banner kbd{background:rgba(255,255,255,.18);padding:0 4px;border-radius:3px;font-size:11px}",".cem-exit-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.15);border:1px solid rgba(255,255,255,.25);color:#fff;padding:4px 10px;border-radius:5px;font:12px system-ui,-apple-system,sans-serif;cursor:pointer;white-space:nowrap}",".cem-exit-btn:hover,.cem-exit-btn:focus-visible{background:rgba(255,255,255,.25);outline:none}","[contenteditable=true]{cursor:text!important}","[contenteditable=true]:hover{outline:2px dashed rgba(59,130,246,.5)!important;outline-offset:2px}","[contenteditable=true]:focus{outline:2px solid #3b82f6!important;outline-offset:2px;background:rgba(59,130,246,.04)}",".cem-panel{position:fixed;right:16px;bottom:16px;z-index:2147483640;background:#fff;color:#111827;border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,.22);padding:10px;display:grid;gap:8px;width:min(320px,calc(100vw - 32px));font:13px/1.4 system-ui,-apple-system,sans-serif}",".cem-panel-actions{display:flex;gap:8px;flex-wrap:wrap}",".cem-copy-btn,.cem-download-btn,.cem-open-link-btn{border:0;border-radius:8px;padding:9px 12px;font:600 13px system-ui,-apple-system,sans-serif;cursor:pointer;white-space:nowrap}",`.cem-copy-btn{background:${t};color:#fff;flex:1}`,".cem-download-btn,.cem-open-link-btn{background:#f3f4f6;color:#111827;border:1px solid #e5e7eb}",".cem-open-link-btn[hidden]{display:none}",".cem-copy-btn:hover,.cem-download-btn:hover,.cem-open-link-btn:hover{filter:brightness(.97)}",".cem-status{color:#4b5563;font-size:12px;min-height:17px}",".cem-toast{position:fixed;bottom:116px;right:16px;z-index:2147483641;background:#065f46;color:#fff;padding:10px 18px;border-radius:8px;font:14px system-ui,-apple-system,sans-serif;box-shadow:0 2px 12px rgba(0,0,0,.3);transition:opacity .3s}","@media(max-width:520px){.cem-edit-banner{justify-content:flex-start;text-align:left}.cem-panel{left:16px;right:16px;width:auto}}"].join(`
|
|
2
|
+
`),document.head.appendChild(e),e}function v(t){document.querySelector(".cem-toast")?.remove();let e=document.createElement("div");e.className="cem-toast",e.textContent=t,document.body.appendChild(e),window.setTimeout(()=>{e.style.opacity="0",window.setTimeout(()=>e.parentNode?.removeChild(e),300)},2500)}function D(t,e){let n=document.createElement("textarea");n.value=t,n.style.position="fixed",n.style.left="-9999px",document.body.appendChild(n),n.select();try{document.execCommand("copy")}catch{}document.body.removeChild(n),v(e)}function Q(){try{let t="__cem_storage_test__";return window.localStorage.setItem(t,"1"),window.localStorage.removeItem(t),window.localStorage}catch{try{return window.sessionStorage}catch{return null}}}function W(t){return`${t.storageKey||`${t.sessionKey}:draft`}:${window.location.origin}${window.location.pathname}`}function X(t,e){if(t.closest(e)||!(t.textContent?.trim()??""))return!1;let i=Array.from(t.children);return!(i.length>0&&i.every(a=>F.has(a.tagName)))}function Z(t){if(t.dataset.editId)return`data-edit-id:${t.dataset.editId}`;if(t.id)return`id:${t.id}`;let e=[],n=t;for(;n&&n!==document.body&&n!==document.documentElement;){let i=n.parentElement;if(!i)break;let a=n.tagName,d=Array.from(i.children).filter(c=>c.tagName===a).indexOf(n)+1;e.unshift(`${n.tagName.toLowerCase()}:nth-of-type(${d})`),n=i}return e.join(" > ")}function ee(t){let e="",n=t.parentElement;for(;n&&n!==document.body&&n!==document.documentElement;){if(n.id){e=`#${n.id}`;break}let d=n.getAttribute("data-section");if(d){e=d;break}if(n.tagName==="SECTION"){let c=n.querySelector("h1,h2,h3");if(c?.textContent){e=c.textContent.trim().slice(0,40);break}}if(["HEADER","FOOTER","MAIN","NAV"].includes(n.tagName)){e=n.tagName.toLowerCase();break}n=n.parentElement}let i=t.tagName.toLowerCase(),a=t.dataset.editOriginal||t.textContent?.trim()||"",s=a.slice(0,40)+(a.length>40?"...":"");return`${e?`${e} > `:""}${i}: "${s}"`}function te(t,e){document.querySelectorAll("a[href]").forEach(n=>{let i=n.getAttribute("href");if(!(!i||/^(https?:|mailto:|tel:|javascript:)/i.test(i)))try{let a=new URL(i,window.location.href);if(a.origin!==window.location.origin)return;a.searchParams.set(t,e??"1");let s=a.hash;a.hash="",n.setAttribute("href",`${a.pathname}${a.search}${s}`)}catch{}})}function I(t){return{site:window.location.hostname,page:window.location.pathname,pageTitle:document.title,url:window.location.href,timestamp:new Date().toISOString(),changes:t}}function ne(t,e){if(!t)return null;try{let n=t.getItem(e);if(!n)return null;let i=JSON.parse(n);return i?.version===A&&Array.isArray(i.changes)?i:null}catch{return null}}function oe(t,e,n){if(!t)return!1;try{return t.setItem(e,JSON.stringify(n)),!0}catch{return!1}}function ae(t,e){let n=new Blob([e],{type:"application/json"}),i=URL.createObjectURL(n),a=document.createElement("a");a.href=i,a.download=t,a.style.display="none",document.body.appendChild(a),a.click(),a.remove(),window.setTimeout(()=>URL.revokeObjectURL(i),1e3)}function ie(t=new Date){return t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function re(t){document.querySelectorAll(t.editableSelector).forEach(e=>{if(!X(e,t.skipSelector))return;let n=e.textContent?.trim()??"";e.contentEditable="true",e.dataset.editOriginal||(e.dataset.editOriginal=n),e.dataset.editKey||(e.dataset.editKey=Z(e))})}function se(t,e){if(!t)return 0;let n=new Map(t.changes.map(a=>[a.key,a])),i=0;return document.querySelectorAll(e).forEach(a=>{let s=a.dataset.editKey;if(!s)return;let d=n.get(s);d&&a.dataset.editOriginal===d.original&&(a.textContent=d.new,i+=1)}),i}function q(t){let e=[];return document.querySelectorAll(t).forEach(n=>{if(!n.isContentEditable&&n.contentEditable!=="true")return;let i=n.dataset.editOriginal,a=n.dataset.editKey;if(i===void 0||!a)return;let s=n.textContent?.trim()??"";i!==s&&e.push({key:a,path:ee(n),tag:n.tagName,original:i,new:s})}),e}function x(t){return q(t).map(({key:e,...n})=>n)}function y(t={}){if(!J())return{active:!1,getChanges:()=>[],destroy:()=>{}};let e={...z,...t};if(!G(e))return{active:!1,getChanges:()=>[],destroy:()=>{}};if(window.__COLLIDE_EDIT_MODE_ACTIVE)return{active:!0,getChanges:()=>x(e.editableSelector),destroy:()=>{}};window.__COLLIDE_EDIT_MODE_ACTIVE=!0,window.sessionStorage.setItem(e.sessionKey,"1");let n=Q(),i=W(e),a=Y(e.accentColour),s=document.createElement("div");s.className="cem-edit-banner",s.innerHTML=`\u270F\uFE0F <strong>${e.brandName}</strong> <span>Click text to edit. Press <kbd>Esc</kbd> when done.</span>`;let d=document.createElement("button");d.className="cem-exit-btn",d.type="button",d.textContent="Exit",s.appendChild(d),document.body.prepend(s);let c=document.createElement("div");c.className="cem-panel",c.innerHTML=`
|
|
3
|
+
<div class="cem-panel-actions">
|
|
4
|
+
<button class="cem-copy-btn" type="button">\u{1F4CB} Copy Changes</button>
|
|
5
|
+
<button class="cem-download-btn" type="button">Download backup</button>
|
|
6
|
+
<button class="cem-open-link-btn" type="button" hidden>Open link</button>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="cem-status" aria-live="polite">Auto-save ready</div>
|
|
9
|
+
`,document.body.appendChild(c);let h=c.querySelector(".cem-copy-btn"),$=c.querySelector(".cem-download-btn"),f=c.querySelector(".cem-open-link-btn"),C=c.querySelector(".cem-status"),u=null;document.querySelectorAll("[data-reveal]").forEach(o=>o.classList.add("is-visible")),te(e.queryParam,e.queryValue),re(e);let b=se(ne(n,i),e.editableSelector),_=()=>({version:A,page:window.location.pathname,url:window.location.href,updatedAt:new Date().toISOString(),changes:q(e.editableSelector)}),g=o=>{let r=x(e.editableSelector).length;h&&(h.textContent=r>0?`\u{1F4CB} Copy Changes (${r})`:"\u{1F4CB} Copy Changes"),f&&(f.hidden=!u,f.textContent=u?`Open ${u.hostname||"link"}`:"Open link"),C&&(C.textContent=o||`Auto-saved ${ie()} \u2022 ${r} change${r===1?"":"s"} \u2022 Links: edit text or Ctrl/\u2318-click to open`)},l=()=>{let o=_(),r=e.autoSave!==!1&&oe(n,i,o);return g(r||e.autoSave===!1?void 0:"\u26A0\uFE0F Auto-save unavailable \u2014 use Download backup"),o},N=()=>{let o=document.activeElement;return!(o instanceof HTMLElement)||!o.isContentEditable&&o.contentEditable!=="true"?!1:(o.blur(),window.getSelection()?.removeAllRanges(),l(),!0)},S=o=>{o.key==="Escape"&&N()&&(o.preventDefault(),o.stopPropagation())},k=o=>{let r=o.target;if(!(r instanceof Element))return;let p=r.closest("a[href]");if(p&&!p.closest(".cem-panel")&&!p.closest(".cem-edit-banner")){if(u=p,g("Link selected \u2014 edit the text, use Open link, or Ctrl/\u2318-click to visit it"),o.metaKey||o.ctrlKey||o.altKey){l();return}o.preventDefault();return}let m=r.closest("button");m&&!m.closest(".cem-panel")&&!m.closest(".cem-edit-banner")&&(o.preventDefault(),o.stopImmediatePropagation())},L=o=>{let r=o.target;r instanceof Element&&(u=r.closest("a[href]"),g(u?"Link selected \u2014 edit the text or use Open link to navigate":void 0))},M=()=>l(),T=()=>l(),O=()=>{document.visibilityState==="hidden"&&l()};return document.addEventListener("keydown",S),document.addEventListener("click",k,!0),document.addEventListener("focusin",L),document.addEventListener("input",M),window.addEventListener("pagehide",T),document.addEventListener("visibilitychange",O),h?.addEventListener("click",()=>{let o=l(),r=I(o.changes);t.onCopy?.(r);let p=t.mapPayload?t.mapPayload(r):r,m=JSON.stringify(p,null,2),E=`\u2713 Copied ${o.changes.length} change${o.changes.length!==1?"s":""} to clipboard`;navigator.clipboard?.writeText?navigator.clipboard.writeText(m).then(()=>v(E)).catch(()=>D(m,E)):D(m,E)}),$?.addEventListener("click",()=>{let o=l(),r=I(o.changes),p=new Date().toISOString().slice(0,10);ae(`edit-mode-${window.location.hostname}-${p}.json`,JSON.stringify(r,null,2)),v("\u2713 Backup downloaded")}),f?.addEventListener("click",()=>{u?.href&&(l(),window.location.href=u.href)}),d.addEventListener("click",()=>{l(),window.sessionStorage.removeItem(e.sessionKey);let o=new URL(window.location.href);o.searchParams.delete(e.queryParam),window.location.href=o.toString()}),l(),b>0&&g(`Restored ${b} saved edit${b===1?"":"s"} \u2022 Auto-save on`),{active:!0,getChanges:()=>x(e.editableSelector),destroy:()=>{l(),document.removeEventListener("keydown",S),document.removeEventListener("click",k,!0),document.removeEventListener("focusin",L),document.removeEventListener("input",M),window.removeEventListener("pagehide",T),document.removeEventListener("visibilitychange",O),s.remove(),c.remove(),a.remove(),document.querySelectorAll(e.editableSelector).forEach(o=>{o.dataset.editOriginal!==void 0&&(o.contentEditable="false",delete o.dataset.editOriginal,delete o.dataset.editKey)}),window.__COLLIDE_EDIT_MODE_ACTIVE=!1}}}var de={initClientEditMode:y};if(typeof window<"u"){window.CollideEditMode=de;let t=document.currentScript,e={};t?.dataset.brandName&&(e.brandName=t.dataset.brandName),t?.dataset.queryParam&&(e.queryParam=t.dataset.queryParam),t?.dataset.queryValue&&(e.queryValue=t.dataset.queryValue),t?.dataset.sessionKey&&(e.sessionKey=t.dataset.sessionKey),t?.dataset.accentColour&&(e.accentColour=t.dataset.accentColour),t?.dataset.editableSelector&&(e.editableSelector=t.dataset.editableSelector),t?.dataset.skipSelector&&(e.skipSelector=t.dataset.skipSelector),y(e)}return U(ce);})();
|
|
3
10
|
//# sourceMappingURL=browser.global.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/browser.ts","../src/index.ts"],"sourcesContent":["import { initClientEditMode } from \"./index\";\nimport type { EditModeInstance, EditModeOptions } from \"./types\";\n\nconst api = { initClientEditMode };\n\nif (typeof window !== \"undefined\") {\n window.CollideEditMode = api;\n\n const script = document.currentScript as HTMLScriptElement | null;\n const options: EditModeOptions = {};\n\n if (script?.dataset.brandName) options.brandName = script.dataset.brandName;\n if (script?.dataset.queryParam) options.queryParam = script.dataset.queryParam;\n if (script?.dataset.queryValue) options.queryValue = script.dataset.queryValue;\n if (script?.dataset.sessionKey) options.sessionKey = script.dataset.sessionKey;\n if (script?.dataset.accentColour) options.accentColour = script.dataset.accentColour;\n if (script?.dataset.editableSelector) options.editableSelector = script.dataset.editableSelector;\n if (script?.dataset.skipSelector) options.skipSelector = script.dataset.skipSelector;\n\n initClientEditMode(options);\n}\n\nexport { initClientEditMode };\nexport type { EditModeInstance, EditModeOptions };\n","import type { EditModeChange, EditModeInstance, EditModeOptions, EditModePayload } from \"./types\";\n\nexport type { EditModeChange, EditModeInstance, EditModeOptions, EditModePayload } from \"./types\";\n\nconst DEFAULT_EDITABLE_SELECTOR =\n \"h1,h2,h3,h4,h5,h6,p,li,blockquote,figcaption,label,legend,dt,dd,th,td,a,button\";\n\nconst DEFAULT_SKIP_SELECTOR =\n \"[data-no-edit],[data-edit-mode-skip],form,input,textarea,select,option,script,style,svg,canvas,iframe,.cem-edit-banner,.cem-copy-btn,.cem-toast\";\n\nconst SKIP_CHILD_TAGS = new Set([\"IMG\", \"PICTURE\", \"SVG\", \"VIDEO\", \"CANVAS\", \"IFRAME\", \"SCRIPT\", \"STYLE\"]);\n\nconst defaults = {\n queryParam: \"edit\",\n queryValue: \"true\" as string | null,\n sessionKey: \"collide-edit-mode\",\n brandName: \"Edit Mode\",\n accentColour: \"#1e40af\",\n editableSelector: DEFAULT_EDITABLE_SELECTOR,\n skipSelector: DEFAULT_SKIP_SELECTOR,\n};\n\nfunction hasDom() {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\nfunction shouldEnable(options: Required<Omit<EditModeOptions, \"enabled\" | \"onCopy\" | \"mapPayload\">> & Pick<EditModeOptions, \"enabled\">) {\n if (options.enabled !== undefined) return options.enabled;\n\n const url = new URL(window.location.href);\n const queryValue = url.searchParams.get(options.queryParam);\n const queryMatches =\n options.queryValue === null ? queryValue !== null : queryValue === options.queryValue;\n\n return queryMatches || window.sessionStorage.getItem(options.sessionKey) === \"1\";\n}\n\nfunction addStyles(accentColour: string) {\n const style = document.createElement(\"style\");\n style.dataset.editModeStyle = \"true\";\n style.textContent = [\n `.cem-edit-banner{position:fixed;top:0;left:0;right:0;z-index:2147483640;background:${accentColour};color:#fff;text-align:center;padding:7px 56px 7px 16px;font-size:13px;font-family:system-ui,-apple-system,sans-serif;line-height:1.4}`,\n \".cem-edit-banner kbd{background:rgba(255,255,255,0.15);padding:0 4px;border-radius:3px;font-size:11px}\",\n \".cem-exit-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.25);color:#fff;padding:3px 10px;border-radius:4px;font-size:12px;cursor:pointer;font-family:inherit;white-space:nowrap}\",\n \".cem-exit-btn:hover{background:rgba(255,255,255,0.25)}\",\n \"[contenteditable=true]{cursor:text!important}\",\n \"[contenteditable=true]:hover{outline:2px dashed rgba(59,130,246,0.5)!important;outline-offset:2px}\",\n \"[contenteditable=true]:focus{outline:2px solid #3b82f6!important;outline-offset:2px;background:rgba(59,130,246,0.04)}\",\n `.cem-copy-btn{position:fixed;bottom:80px;right:16px;z-index:2147483640;background:${accentColour};color:#fff;border:none;border-radius:8px;padding:10px 18px;font-size:14px;font-weight:600;font-family:system-ui,-apple-system,sans-serif;cursor:pointer;box-shadow:0 2px 12px rgba(0,0,0,0.3);transition:transform .15s,opacity .15s;white-space:nowrap}`,\n \".cem-copy-btn:hover{transform:scale(1.05)}\",\n \".cem-copy-btn:active{transform:scale(.97)}\",\n \".cem-toast{position:fixed;bottom:132px;right:16px;z-index:2147483641;background:#065f46;color:#fff;padding:10px 18px;border-radius:8px;font-size:14px;font-family:system-ui,-apple-system,sans-serif;box-shadow:0 2px 12px rgba(0,0,0,0.3);transition:opacity .3s}\",\n \"@media(min-width:768px){.cem-copy-btn{bottom:24px;right:24px}.cem-toast{bottom:76px;right:24px}}\",\n ].join(\"\\n\");\n document.head.appendChild(style);\n return style;\n}\n\nfunction showToast(message: string) {\n document.querySelector(\".cem-toast\")?.remove();\n const toast = document.createElement(\"div\");\n toast.className = \"cem-toast\";\n toast.textContent = message;\n document.body.appendChild(toast);\n window.setTimeout(() => {\n toast.style.opacity = \"0\";\n window.setTimeout(() => toast.parentNode?.removeChild(toast), 300);\n }, 2500);\n}\n\nfunction fallbackCopy(text: string, label: string) {\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n document.body.appendChild(textarea);\n textarea.select();\n try {\n document.execCommand(\"copy\");\n } catch {\n // Ignore: the JSON remains visible via devtools and caller onCopy still runs.\n }\n document.body.removeChild(textarea);\n showToast(label);\n}\n\nfunction isEditableElement(el: Element, skipSelector: string) {\n if (el.closest(skipSelector)) return false;\n\n const text = el.textContent?.trim() ?? \"\";\n if (!text) return false;\n\n const children = Array.from(el.children);\n if (children.length > 0 && children.every((child) => SKIP_CHILD_TAGS.has(child.tagName))) {\n return false;\n }\n\n return true;\n}\n\nfunction getEditPath(el: HTMLElement) {\n let context = \"\";\n let current = el.parentElement;\n\n while (current && current !== document.body && current !== document.documentElement) {\n if (current.id) {\n context = `#${current.id}`;\n break;\n }\n\n const section = current.getAttribute(\"data-section\");\n if (section) {\n context = section;\n break;\n }\n\n if (current.tagName === \"SECTION\") {\n const heading = current.querySelector(\"h1,h2,h3\");\n if (heading?.textContent) {\n context = heading.textContent.trim().slice(0, 40);\n break;\n }\n }\n\n if ([\"HEADER\", \"FOOTER\", \"MAIN\", \"NAV\"].includes(current.tagName)) {\n context = current.tagName.toLowerCase();\n break;\n }\n\n current = current.parentElement;\n }\n\n const tag = el.tagName.toLowerCase();\n const text = el.dataset.editOriginal || el.textContent?.trim() || \"\";\n const snippet = text.slice(0, 40) + (text.length > 40 ? \"...\" : \"\");\n return `${context ? `${context} > ` : \"\"}${tag}: \"${snippet}\"`;\n}\n\nfunction rewriteLinks(queryParam: string, queryValue: string | null) {\n document.querySelectorAll<HTMLAnchorElement>(\"a[href]\").forEach((anchor) => {\n const href = anchor.getAttribute(\"href\");\n if (!href || /^(https?:|mailto:|tel:|javascript:)/i.test(href)) return;\n\n try {\n const url = new URL(href, window.location.href);\n if (url.origin !== window.location.origin) return;\n\n url.searchParams.set(queryParam, queryValue ?? \"1\");\n const hash = url.hash;\n url.hash = \"\";\n anchor.setAttribute(\"href\", `${url.pathname}${url.search}${hash}`);\n } catch {\n // Leave unusual hrefs unchanged.\n }\n });\n}\n\nexport function initClientEditMode(options: EditModeOptions = {}): EditModeInstance {\n if (!hasDom()) {\n return { active: false, getChanges: () => [], destroy: () => undefined };\n }\n\n const config = { ...defaults, ...options };\n\n if (!shouldEnable(config)) {\n return { active: false, getChanges: () => [], destroy: () => undefined };\n }\n\n if (window.__COLLIDE_EDIT_MODE_ACTIVE) {\n return { active: true, getChanges: () => collectChanges(config.editableSelector), destroy: () => undefined };\n }\n\n window.__COLLIDE_EDIT_MODE_ACTIVE = true;\n window.sessionStorage.setItem(config.sessionKey, \"1\");\n\n const style = addStyles(config.accentColour);\n\n const banner = document.createElement(\"div\");\n banner.className = \"cem-edit-banner\";\n banner.innerHTML = `✏️ <strong>${config.brandName}</strong> — Click any text to edit. Press <kbd>Esc</kbd> to finish editing.`;\n\n const exitButton = document.createElement(\"button\");\n exitButton.className = \"cem-exit-btn\";\n exitButton.textContent = \"✕ Exit\";\n exitButton.addEventListener(\"click\", () => {\n window.sessionStorage.removeItem(config.sessionKey);\n const url = new URL(window.location.href);\n url.searchParams.delete(config.queryParam);\n window.location.href = url.toString();\n });\n banner.appendChild(exitButton);\n document.body.prepend(banner);\n\n document.querySelectorAll(\"[data-reveal]\").forEach((el) => el.classList.add(\"is-visible\"));\n rewriteLinks(config.queryParam, config.queryValue);\n\n const initEditable = () => {\n document.querySelectorAll<HTMLElement>(config.editableSelector).forEach((el) => {\n if (!isEditableElement(el, config.skipSelector)) return;\n const text = el.textContent?.trim() ?? \"\";\n el.contentEditable = \"true\";\n if (!el.dataset.editOriginal) el.dataset.editOriginal = text;\n });\n };\n initEditable();\n\n const blockButtonClicks = (event: MouseEvent) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n const button = target.closest(\"button\");\n if (button && !button.classList.contains(\"cem-copy-btn\") && !button.closest(\".cem-edit-banner\")) {\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n };\n document.addEventListener(\"click\", blockButtonClicks, true);\n\n const copyButton = document.createElement(\"button\");\n copyButton.className = \"cem-copy-btn\";\n document.body.appendChild(copyButton);\n\n const updateCounter = () => {\n const count = collectChanges(config.editableSelector).length;\n copyButton.textContent = count > 0 ? `📋 Copy Changes (${count})` : \"📋 Copy Changes\";\n };\n\n document.addEventListener(\"input\", updateCounter);\n updateCounter();\n\n copyButton.addEventListener(\"click\", () => {\n const changes = collectChanges(config.editableSelector);\n const payload: EditModePayload = {\n site: window.location.hostname,\n page: window.location.pathname,\n pageTitle: document.title,\n url: window.location.href,\n timestamp: new Date().toISOString(),\n changes,\n };\n\n options.onCopy?.(payload);\n\n const copyPayload = options.mapPayload ? options.mapPayload(payload) : payload;\n const json = JSON.stringify(copyPayload, null, 2);\n const label = `✓ Copied ${changes.length} change${changes.length !== 1 ? \"s\" : \"\"} to clipboard`;\n\n if (navigator.clipboard?.writeText) {\n navigator.clipboard.writeText(json).then(() => showToast(label)).catch(() => fallbackCopy(json, label));\n } else {\n fallbackCopy(json, label);\n }\n });\n\n return {\n active: true,\n getChanges: () => collectChanges(config.editableSelector),\n destroy: () => {\n document.removeEventListener(\"click\", blockButtonClicks, true);\n document.removeEventListener(\"input\", updateCounter);\n banner.remove();\n copyButton.remove();\n style.remove();\n document.querySelectorAll<HTMLElement>(config.editableSelector).forEach((el) => {\n if (el.dataset.editOriginal !== undefined) {\n el.contentEditable = \"false\";\n delete el.dataset.editOriginal;\n }\n });\n window.__COLLIDE_EDIT_MODE_ACTIVE = false;\n },\n };\n}\n\nfunction collectChanges(editableSelector: string): EditModeChange[] {\n const changes: EditModeChange[] = [];\n\n document.querySelectorAll<HTMLElement>(editableSelector).forEach((el) => {\n if (!el.isContentEditable && el.contentEditable !== \"true\") return;\n const original = el.dataset.editOriginal;\n if (original === undefined) return;\n\n const current = el.textContent?.trim() ?? \"\";\n if (original !== current) {\n changes.push({\n path: getEditPath(el),\n tag: el.tagName,\n original,\n new: current,\n });\n }\n });\n\n return changes;\n}\n"],"mappings":"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","names":["browser_exports","__export","initClientEditMode","DEFAULT_EDITABLE_SELECTOR","DEFAULT_SKIP_SELECTOR","SKIP_CHILD_TAGS","defaults","hasDom","shouldEnable","options","queryValue","addStyles","accentColour","style","showToast","message","toast","fallbackCopy","text","label","textarea","isEditableElement","el","skipSelector","children","child","getEditPath","context","current","section","heading","tag","snippet","rewriteLinks","queryParam","anchor","href","url","hash","initClientEditMode","config","collectChanges","banner","exitButton","blockButtonClicks","event","target","button","copyButton","updateCounter","count","changes","payload","copyPayload","json","editableSelector","original","api","initClientEditMode","script","options"]}
|
|
1
|
+
{"version":3,"sources":["../src/browser.ts","../src/index.ts"],"sourcesContent":["import { initClientEditMode } from \"./index\";\nimport type { EditModeInstance, EditModeOptions } from \"./types\";\n\nconst api = { initClientEditMode };\n\nif (typeof window !== \"undefined\") {\n window.CollideEditMode = api;\n\n const script = document.currentScript as HTMLScriptElement | null;\n const options: EditModeOptions = {};\n\n if (script?.dataset.brandName) options.brandName = script.dataset.brandName;\n if (script?.dataset.queryParam) options.queryParam = script.dataset.queryParam;\n if (script?.dataset.queryValue) options.queryValue = script.dataset.queryValue;\n if (script?.dataset.sessionKey) options.sessionKey = script.dataset.sessionKey;\n if (script?.dataset.accentColour) options.accentColour = script.dataset.accentColour;\n if (script?.dataset.editableSelector) options.editableSelector = script.dataset.editableSelector;\n if (script?.dataset.skipSelector) options.skipSelector = script.dataset.skipSelector;\n\n initClientEditMode(options);\n}\n\nexport { initClientEditMode };\nexport type { EditModeInstance, EditModeOptions };\n","import type { EditModeChange, EditModeInstance, EditModeOptions, EditModePayload } from \"./types\";\n\nexport type { EditModeChange, EditModeInstance, EditModeOptions, EditModePayload } from \"./types\";\n\nconst DEFAULT_EDITABLE_SELECTOR =\n \"h1,h2,h3,h4,h5,h6,p,li,blockquote,figcaption,label,legend,dt,dd,th,td,a,button\";\n\nconst DEFAULT_SKIP_SELECTOR =\n \"[data-no-edit],[data-edit-mode-skip],form,input,textarea,select,option,script,style,svg,canvas,iframe,.cem-edit-banner,.cem-panel,.cem-toast\";\n\nconst SKIP_CHILD_TAGS = new Set([\"IMG\", \"PICTURE\", \"SVG\", \"VIDEO\", \"CANVAS\", \"IFRAME\", \"SCRIPT\", \"STYLE\"]);\nconst DRAFT_VERSION = 1;\n\ntype Config = Required<\n Omit<EditModeOptions, \"enabled\" | \"onCopy\" | \"mapPayload\" | \"storageKey\" | \"autoSave\">\n> &\n Pick<EditModeOptions, \"enabled\" | \"storageKey\" | \"autoSave\">;\n\ntype DraftChange = EditModeChange & {\n key: string;\n};\n\ntype Draft = {\n version: number;\n page: string;\n url: string;\n updatedAt: string;\n changes: DraftChange[];\n};\n\nconst defaults = {\n queryParam: \"edit\",\n queryValue: \"true\" as string | null,\n sessionKey: \"collide-edit-mode\",\n brandName: \"Edit Mode\",\n accentColour: \"#1e40af\",\n editableSelector: DEFAULT_EDITABLE_SELECTOR,\n skipSelector: DEFAULT_SKIP_SELECTOR,\n autoSave: true,\n};\n\nfunction hasDom() {\n return typeof window !== \"undefined\" && typeof document !== \"undefined\";\n}\n\nfunction shouldEnable(options: Config) {\n if (options.enabled !== undefined) return options.enabled;\n\n const url = new URL(window.location.href);\n const queryValue = url.searchParams.get(options.queryParam);\n const queryMatches =\n options.queryValue === null ? queryValue !== null : queryValue === options.queryValue;\n\n return queryMatches || window.sessionStorage.getItem(options.sessionKey) === \"1\";\n}\n\nfunction addStyles(accentColour: string) {\n const style = document.createElement(\"style\");\n style.dataset.editModeStyle = \"true\";\n style.textContent = [\n `.cem-edit-banner{position:fixed;top:0;left:0;right:0;z-index:2147483640;background:${accentColour};color:#fff;display:flex;align-items:center;justify-content:center;gap:8px;padding:8px 92px 8px 16px;font:13px/1.4 system-ui,-apple-system,sans-serif;box-shadow:0 1px 8px rgba(0,0,0,.18)}`,\n \".cem-edit-banner kbd{background:rgba(255,255,255,.18);padding:0 4px;border-radius:3px;font-size:11px}\",\n \".cem-exit-btn{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:rgba(255,255,255,.15);border:1px solid rgba(255,255,255,.25);color:#fff;padding:4px 10px;border-radius:5px;font:12px system-ui,-apple-system,sans-serif;cursor:pointer;white-space:nowrap}\",\n \".cem-exit-btn:hover,.cem-exit-btn:focus-visible{background:rgba(255,255,255,.25);outline:none}\",\n \"[contenteditable=true]{cursor:text!important}\",\n \"[contenteditable=true]:hover{outline:2px dashed rgba(59,130,246,.5)!important;outline-offset:2px}\",\n \"[contenteditable=true]:focus{outline:2px solid #3b82f6!important;outline-offset:2px;background:rgba(59,130,246,.04)}\",\n `.cem-panel{position:fixed;right:16px;bottom:16px;z-index:2147483640;background:#fff;color:#111827;border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,.22);padding:10px;display:grid;gap:8px;width:min(320px,calc(100vw - 32px));font:13px/1.4 system-ui,-apple-system,sans-serif}`,\n \".cem-panel-actions{display:flex;gap:8px;flex-wrap:wrap}\",\n `.cem-copy-btn,.cem-download-btn,.cem-open-link-btn{border:0;border-radius:8px;padding:9px 12px;font:600 13px system-ui,-apple-system,sans-serif;cursor:pointer;white-space:nowrap}`,\n `.cem-copy-btn{background:${accentColour};color:#fff;flex:1}`,\n \".cem-download-btn,.cem-open-link-btn{background:#f3f4f6;color:#111827;border:1px solid #e5e7eb}\",\n \".cem-open-link-btn[hidden]{display:none}\",\n \".cem-copy-btn:hover,.cem-download-btn:hover,.cem-open-link-btn:hover{filter:brightness(.97)}\",\n \".cem-status{color:#4b5563;font-size:12px;min-height:17px}\",\n \".cem-toast{position:fixed;bottom:116px;right:16px;z-index:2147483641;background:#065f46;color:#fff;padding:10px 18px;border-radius:8px;font:14px system-ui,-apple-system,sans-serif;box-shadow:0 2px 12px rgba(0,0,0,.3);transition:opacity .3s}\",\n \"@media(max-width:520px){.cem-edit-banner{justify-content:flex-start;text-align:left}.cem-panel{left:16px;right:16px;width:auto}}\",\n ].join(\"\\n\");\n document.head.appendChild(style);\n return style;\n}\n\nfunction showToast(message: string) {\n document.querySelector(\".cem-toast\")?.remove();\n const toast = document.createElement(\"div\");\n toast.className = \"cem-toast\";\n toast.textContent = message;\n document.body.appendChild(toast);\n window.setTimeout(() => {\n toast.style.opacity = \"0\";\n window.setTimeout(() => toast.parentNode?.removeChild(toast), 300);\n }, 2500);\n}\n\nfunction fallbackCopy(text: string, label: string) {\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.style.position = \"fixed\";\n textarea.style.left = \"-9999px\";\n document.body.appendChild(textarea);\n textarea.select();\n try {\n document.execCommand(\"copy\");\n } catch {\n // Ignore: the download button and autosaved draft still protect the work.\n }\n document.body.removeChild(textarea);\n showToast(label);\n}\n\nfunction getStorage() {\n try {\n const testKey = \"__cem_storage_test__\";\n window.localStorage.setItem(testKey, \"1\");\n window.localStorage.removeItem(testKey);\n return window.localStorage;\n } catch {\n try {\n return window.sessionStorage;\n } catch {\n return null;\n }\n }\n}\n\nfunction getDraftKey(config: Config) {\n const base = config.storageKey || `${config.sessionKey}:draft`;\n return `${base}:${window.location.origin}${window.location.pathname}`;\n}\n\nfunction isEditableElement(el: Element, skipSelector: string) {\n if (el.closest(skipSelector)) return false;\n\n const text = el.textContent?.trim() ?? \"\";\n if (!text) return false;\n\n const children = Array.from(el.children);\n if (children.length > 0 && children.every((child) => SKIP_CHILD_TAGS.has(child.tagName))) {\n return false;\n }\n\n return true;\n}\n\nfunction getElementKey(el: HTMLElement) {\n if (el.dataset.editId) return `data-edit-id:${el.dataset.editId}`;\n if (el.id) return `id:${el.id}`;\n\n const parts: string[] = [];\n let current: Element | null = el;\n\n while (current && current !== document.body && current !== document.documentElement) {\n const parentElement: HTMLElement | null = current.parentElement;\n if (!parentElement) break;\n\n const currentTag = current.tagName;\n const siblings = Array.from(parentElement.children).filter((child) => child.tagName === currentTag);\n const index = siblings.indexOf(current) + 1;\n parts.unshift(`${current.tagName.toLowerCase()}:nth-of-type(${index})`);\n current = parentElement;\n }\n\n return parts.join(\" > \");\n}\n\nfunction getEditPath(el: HTMLElement) {\n let context = \"\";\n let current = el.parentElement;\n\n while (current && current !== document.body && current !== document.documentElement) {\n if (current.id) {\n context = `#${current.id}`;\n break;\n }\n\n const section = current.getAttribute(\"data-section\");\n if (section) {\n context = section;\n break;\n }\n\n if (current.tagName === \"SECTION\") {\n const heading = current.querySelector(\"h1,h2,h3\");\n if (heading?.textContent) {\n context = heading.textContent.trim().slice(0, 40);\n break;\n }\n }\n\n if ([\"HEADER\", \"FOOTER\", \"MAIN\", \"NAV\"].includes(current.tagName)) {\n context = current.tagName.toLowerCase();\n break;\n }\n\n current = current.parentElement;\n }\n\n const tag = el.tagName.toLowerCase();\n const text = el.dataset.editOriginal || el.textContent?.trim() || \"\";\n const snippet = text.slice(0, 40) + (text.length > 40 ? \"...\" : \"\");\n return `${context ? `${context} > ` : \"\"}${tag}: \"${snippet}\"`;\n}\n\nfunction rewriteLinks(queryParam: string, queryValue: string | null) {\n document.querySelectorAll<HTMLAnchorElement>(\"a[href]\").forEach((anchor) => {\n const href = anchor.getAttribute(\"href\");\n if (!href || /^(https?:|mailto:|tel:|javascript:)/i.test(href)) return;\n\n try {\n const url = new URL(href, window.location.href);\n if (url.origin !== window.location.origin) return;\n\n url.searchParams.set(queryParam, queryValue ?? \"1\");\n const hash = url.hash;\n url.hash = \"\";\n anchor.setAttribute(\"href\", `${url.pathname}${url.search}${hash}`);\n } catch {\n // Leave unusual hrefs unchanged.\n }\n });\n}\n\nfunction buildPayload(changes: EditModeChange[]): EditModePayload {\n return {\n site: window.location.hostname,\n page: window.location.pathname,\n pageTitle: document.title,\n url: window.location.href,\n timestamp: new Date().toISOString(),\n changes,\n };\n}\n\nfunction loadDraft(storage: Storage | null, key: string): Draft | null {\n if (!storage) return null;\n\n try {\n const raw = storage.getItem(key);\n if (!raw) return null;\n const draft = JSON.parse(raw) as Draft;\n return draft?.version === DRAFT_VERSION && Array.isArray(draft.changes) ? draft : null;\n } catch {\n return null;\n }\n}\n\nfunction saveDraft(storage: Storage | null, key: string, draft: Draft) {\n if (!storage) return false;\n\n try {\n storage.setItem(key, JSON.stringify(draft));\n return true;\n } catch {\n return false;\n }\n}\n\nfunction downloadText(filename: string, text: string) {\n const blob = new Blob([text], { type: \"application/json\" });\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n anchor.style.display = \"none\";\n document.body.appendChild(anchor);\n anchor.click();\n anchor.remove();\n window.setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nfunction formatTime(date = new Date()) {\n return date.toLocaleTimeString([], { hour: \"2-digit\", minute: \"2-digit\" });\n}\n\nfunction initEditableElements(config: Config) {\n document.querySelectorAll<HTMLElement>(config.editableSelector).forEach((el) => {\n if (!isEditableElement(el, config.skipSelector)) return;\n\n const text = el.textContent?.trim() ?? \"\";\n el.contentEditable = \"true\";\n if (!el.dataset.editOriginal) el.dataset.editOriginal = text;\n if (!el.dataset.editKey) el.dataset.editKey = getElementKey(el);\n });\n}\n\nfunction applyDraft(draft: Draft | null, editableSelector: string) {\n if (!draft) return 0;\n\n const edits = new Map(draft.changes.map((change) => [change.key, change]));\n let restored = 0;\n\n document.querySelectorAll<HTMLElement>(editableSelector).forEach((el) => {\n const key = el.dataset.editKey;\n if (!key) return;\n\n const saved = edits.get(key);\n if (!saved) return;\n\n // Avoid stomping over changed templates. Restore only when the original still matches.\n if (el.dataset.editOriginal !== saved.original) return;\n\n el.textContent = saved.new;\n restored += 1;\n });\n\n return restored;\n}\n\nfunction collectDraftChanges(editableSelector: string): DraftChange[] {\n const changes: DraftChange[] = [];\n\n document.querySelectorAll<HTMLElement>(editableSelector).forEach((el) => {\n if (!el.isContentEditable && el.contentEditable !== \"true\") return;\n const original = el.dataset.editOriginal;\n const key = el.dataset.editKey;\n if (original === undefined || !key) return;\n\n const current = el.textContent?.trim() ?? \"\";\n if (original !== current) {\n changes.push({\n key,\n path: getEditPath(el),\n tag: el.tagName,\n original,\n new: current,\n });\n }\n });\n\n return changes;\n}\n\nfunction collectChanges(editableSelector: string): EditModeChange[] {\n return collectDraftChanges(editableSelector).map(({ key: _key, ...change }) => change);\n}\n\nexport function initClientEditMode(options: EditModeOptions = {}): EditModeInstance {\n if (!hasDom()) {\n return { active: false, getChanges: () => [], destroy: () => undefined };\n }\n\n const config: Config = { ...defaults, ...options };\n\n if (!shouldEnable(config)) {\n return { active: false, getChanges: () => [], destroy: () => undefined };\n }\n\n if (window.__COLLIDE_EDIT_MODE_ACTIVE) {\n return { active: true, getChanges: () => collectChanges(config.editableSelector), destroy: () => undefined };\n }\n\n window.__COLLIDE_EDIT_MODE_ACTIVE = true;\n window.sessionStorage.setItem(config.sessionKey, \"1\");\n\n const storage = getStorage();\n const draftKey = getDraftKey(config);\n const style = addStyles(config.accentColour);\n\n const banner = document.createElement(\"div\");\n banner.className = \"cem-edit-banner\";\n banner.innerHTML = `✏️ <strong>${config.brandName}</strong> <span>Click text to edit. Press <kbd>Esc</kbd> when done.</span>`;\n\n const exitButton = document.createElement(\"button\");\n exitButton.className = \"cem-exit-btn\";\n exitButton.type = \"button\";\n exitButton.textContent = \"Exit\";\n banner.appendChild(exitButton);\n document.body.prepend(banner);\n\n const panel = document.createElement(\"div\");\n panel.className = \"cem-panel\";\n panel.innerHTML = `\n <div class=\"cem-panel-actions\">\n <button class=\"cem-copy-btn\" type=\"button\">📋 Copy Changes</button>\n <button class=\"cem-download-btn\" type=\"button\">Download backup</button>\n <button class=\"cem-open-link-btn\" type=\"button\" hidden>Open link</button>\n </div>\n <div class=\"cem-status\" aria-live=\"polite\">Auto-save ready</div>\n `;\n document.body.appendChild(panel);\n\n const copyButton = panel.querySelector<HTMLButtonElement>(\".cem-copy-btn\");\n const downloadButton = panel.querySelector<HTMLButtonElement>(\".cem-download-btn\");\n const openLinkButton = panel.querySelector<HTMLButtonElement>(\".cem-open-link-btn\");\n const status = panel.querySelector<HTMLElement>(\".cem-status\");\n let activeLink: HTMLAnchorElement | null = null;\n\n document.querySelectorAll(\"[data-reveal]\").forEach((el) => el.classList.add(\"is-visible\"));\n rewriteLinks(config.queryParam, config.queryValue);\n initEditableElements(config);\n\n const restoredCount = applyDraft(loadDraft(storage, draftKey), config.editableSelector);\n\n const makeDraft = (): Draft => ({\n version: DRAFT_VERSION,\n page: window.location.pathname,\n url: window.location.href,\n updatedAt: new Date().toISOString(),\n changes: collectDraftChanges(config.editableSelector),\n });\n\n const updateUi = (message?: string) => {\n const count = collectChanges(config.editableSelector).length;\n if (copyButton) copyButton.textContent = count > 0 ? `📋 Copy Changes (${count})` : \"📋 Copy Changes\";\n if (openLinkButton) {\n openLinkButton.hidden = !activeLink;\n openLinkButton.textContent = activeLink ? `Open ${activeLink.hostname || \"link\"}` : \"Open link\";\n }\n if (status) {\n status.textContent =\n message ||\n `Auto-saved ${formatTime()} • ${count} change${count === 1 ? \"\" : \"s\"} • Links: edit text or Ctrl/⌘-click to open`;\n }\n };\n\n const persistDraft = () => {\n const draft = makeDraft();\n const saved = config.autoSave !== false && saveDraft(storage, draftKey, draft);\n updateUi(saved || config.autoSave === false ? undefined : \"⚠️ Auto-save unavailable — use Download backup\");\n return draft;\n };\n\n const finishEditing = () => {\n const activeElement = document.activeElement;\n if (!(activeElement instanceof HTMLElement)) return false;\n if (!activeElement.isContentEditable && activeElement.contentEditable !== \"true\") return false;\n\n activeElement.blur();\n window.getSelection()?.removeAllRanges();\n persistDraft();\n return true;\n };\n\n const finishEditingOnEscape = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\") return;\n if (!finishEditing()) return;\n\n event.preventDefault();\n event.stopPropagation();\n };\n\n const handleDocumentClick = (event: MouseEvent) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n const anchor = target.closest<HTMLAnchorElement>(\"a[href]\");\n if (anchor && !anchor.closest(\".cem-panel\") && !anchor.closest(\".cem-edit-banner\")) {\n activeLink = anchor;\n updateUi(\"Link selected — edit the text, use Open link, or Ctrl/⌘-click to visit it\");\n\n if (event.metaKey || event.ctrlKey || event.altKey) {\n persistDraft();\n return;\n }\n\n event.preventDefault();\n return;\n }\n\n const button = target.closest(\"button\");\n if (button && !button.closest(\".cem-panel\") && !button.closest(\".cem-edit-banner\")) {\n event.preventDefault();\n event.stopImmediatePropagation();\n }\n };\n\n const handleFocusIn = (event: FocusEvent) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n\n activeLink = target.closest<HTMLAnchorElement>(\"a[href]\");\n updateUi(activeLink ? \"Link selected — edit the text or use Open link to navigate\" : undefined);\n };\n\n const handleInput = () => persistDraft();\n const handlePageHide = () => persistDraft();\n const handleVisibilityChange = () => {\n if (document.visibilityState === \"hidden\") persistDraft();\n };\n\n document.addEventListener(\"keydown\", finishEditingOnEscape);\n document.addEventListener(\"click\", handleDocumentClick, true);\n document.addEventListener(\"focusin\", handleFocusIn);\n document.addEventListener(\"input\", handleInput);\n window.addEventListener(\"pagehide\", handlePageHide);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n copyButton?.addEventListener(\"click\", () => {\n const draft = persistDraft();\n const payload = buildPayload(draft.changes);\n options.onCopy?.(payload);\n\n const copyPayload = options.mapPayload ? options.mapPayload(payload) : payload;\n const json = JSON.stringify(copyPayload, null, 2);\n const label = `✓ Copied ${draft.changes.length} change${draft.changes.length !== 1 ? \"s\" : \"\"} to clipboard`;\n\n if (navigator.clipboard?.writeText) {\n navigator.clipboard.writeText(json).then(() => showToast(label)).catch(() => fallbackCopy(json, label));\n } else {\n fallbackCopy(json, label);\n }\n });\n\n downloadButton?.addEventListener(\"click\", () => {\n const draft = persistDraft();\n const payload = buildPayload(draft.changes);\n const date = new Date().toISOString().slice(0, 10);\n downloadText(`edit-mode-${window.location.hostname}-${date}.json`, JSON.stringify(payload, null, 2));\n showToast(\"✓ Backup downloaded\");\n });\n\n openLinkButton?.addEventListener(\"click\", () => {\n if (!activeLink?.href) return;\n\n persistDraft();\n window.location.href = activeLink.href;\n });\n\n exitButton.addEventListener(\"click\", () => {\n persistDraft();\n window.sessionStorage.removeItem(config.sessionKey);\n const url = new URL(window.location.href);\n url.searchParams.delete(config.queryParam);\n window.location.href = url.toString();\n });\n\n persistDraft();\n if (restoredCount > 0) updateUi(`Restored ${restoredCount} saved edit${restoredCount === 1 ? \"\" : \"s\"} • Auto-save on`);\n\n return {\n active: true,\n getChanges: () => collectChanges(config.editableSelector),\n destroy: () => {\n persistDraft();\n document.removeEventListener(\"keydown\", finishEditingOnEscape);\n document.removeEventListener(\"click\", handleDocumentClick, true);\n document.removeEventListener(\"focusin\", handleFocusIn);\n document.removeEventListener(\"input\", handleInput);\n window.removeEventListener(\"pagehide\", handlePageHide);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n banner.remove();\n panel.remove();\n style.remove();\n document.querySelectorAll<HTMLElement>(config.editableSelector).forEach((el) => {\n if (el.dataset.editOriginal !== undefined) {\n el.contentEditable = \"false\";\n delete el.dataset.editOriginal;\n delete el.dataset.editKey;\n }\n });\n window.__COLLIDE_EDIT_MODE_ACTIVE = false;\n },\n };\n}\n"],"mappings":"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","names":["browser_exports","__export","initClientEditMode","DEFAULT_EDITABLE_SELECTOR","DEFAULT_SKIP_SELECTOR","SKIP_CHILD_TAGS","DRAFT_VERSION","defaults","hasDom","shouldEnable","options","queryValue","addStyles","accentColour","style","showToast","message","toast","fallbackCopy","text","label","textarea","getStorage","testKey","getDraftKey","config","isEditableElement","el","skipSelector","children","child","getElementKey","parts","current","parentElement","currentTag","index","getEditPath","context","section","heading","tag","snippet","rewriteLinks","queryParam","anchor","href","url","hash","buildPayload","changes","loadDraft","storage","key","raw","draft","saveDraft","downloadText","filename","blob","formatTime","date","initEditableElements","applyDraft","editableSelector","edits","change","restored","saved","collectDraftChanges","original","collectChanges","_key","initClientEditMode","draftKey","banner","exitButton","panel","copyButton","downloadButton","openLinkButton","status","activeLink","restoredCount","makeDraft","updateUi","count","persistDraft","finishEditing","activeElement","finishEditingOnEscape","event","handleDocumentClick","target","button","handleFocusIn","handleInput","handlePageHide","handleVisibilityChange","payload","copyPayload","json","api","initClientEditMode","script","options"]}
|