@panphora/clayjs 1.1.0 → 1.3.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 +4 -1
- package/THIRD-PARTY-NOTICES.md +10 -0
- package/dist/clay.standalone.js +21751 -13942
- package/entries/clay-data.js +1 -1
- package/package.json +7 -2
- package/packed-contract.json +17 -0
- package/src/attrs/save-freeze.js +10 -18
- package/src/core/admin-contenteditable.js +5 -6
- package/src/core/etag.js +17 -4
- package/src/core/host-attrs.js +52 -2
- package/src/core/is-edit-mode.js +14 -5
- package/src/core/persist.js +5 -10
- package/src/core/save-conflict-notice.js +22 -27
- package/src/core/save-core.js +326 -26
- package/src/core/save.js +19 -4
- package/src/core/snapshot.js +148 -15
- package/src/core/source-map.js +817 -0
- package/src/core/stale-host-notice.js +95 -0
- package/src/core/unsaved-warning.js +3 -0
- package/src/dom/dom-helpers.js +5 -1
- package/src/lib/content-dom.js +108 -0
- package/src/lib/hostile-css.js +49 -0
- package/src/lib/mutation.js +26 -3
- package/src/lib/region-capabilities.js +69 -0
- package/src/lib/region-policy.js +18 -13
- package/src/lib/root-attrs.js +52 -13
- package/src/loader-logic.js +25 -4
- package/src/loader.js +4 -0
- package/src/plugins/demo.js +3 -0
- package/src/plugins/sortable.js +6 -1
- package/src/plugins/source.js +326 -0
- package/src/plugins/wire.js +248 -47
- package/src/sync/live-sync.js +275 -63
- package/src/sync/presence.js +303 -0
- package/src/sync/section-notice.js +230 -0
- package/src/sync/splice-merge.js +7 -10
- package/src/sync/stream.js +190 -0
- package/src/vendor/hyper-morph.vendor.js +2 -2
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +438 -45
- package/src/vendor/parse5.vendor.js +3 -0
- package/src/vendor/quickcrop.vendor.js +1 -1
- package/src/vendor/richclay.vendor.js +22 -15
package/entries/clay-data.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// hyper-html-api/dist/hyper-html-api.engine.min.js via hyper-html-api
|
|
3
3
|
// `npm run copy-to-clayjs`. Edit the hyper-html-api source and re-run.
|
|
4
4
|
(function () {
|
|
5
|
-
var hyperHtmlApiData=(()=>{var q=Object.defineProperty;var Rt=Object.getOwnPropertyDescriptor;var At=Object.getOwnPropertyNames;var Ot=Object.prototype.hasOwnProperty;var nt=(t,e)=>{for(var n in e)q(t,n,{get:e[n],enumerable:!0})},wt=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of At(e))!Ot.call(t,r)&&r!==n&&q(t,r,{get:()=>e[r],enumerable:!(o=Rt(e,r))||o.enumerable});return t};var St=t=>wt(q({},"__esModule",{value:!0}),t);var vt={};nt(vt,{applyData:()=>et,default:()=>Ut,engine:()=>k,extractData:()=>tt});var W=["textContent","innerText","innerHTML","outerHTML","value","checked","selected","disabled","readOnly","type","tagName","nodeName","nodeType","nodeValue","childElementCount","id","className","classList","baseURI","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","dataset","currentSrc","duration","paused","title","documentURI","contentType"],F=new Set(W),rt=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),ot=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var B={};nt(B,{EmptyListInsert:()=>P,MAX_RULE_DEPTH:()=>b,MaxRuleDepthExceeded:()=>S,RuleTargetReadOnly:()=>j,RulesParseError:()=>T,ShapeMismatch:()=>D,UnknownRulesVersion:()=>_});var T=class extends Error{constructor(e,n){super(e),this.name="RulesParseError",this.cause=n}},_=class extends Error{constructor(e){super(`unknown rules version: ${e}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=e}},b=20,S=class extends Error{constructor(e){super(`rule depth exceeded ${b} at path: ${e.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=e}},D=class extends Error{constructor(e){super(`shape mismatch: ${e.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=e}},P=class extends Error{constructor(e){super(`cannot add items to empty list at "${e.join(".")}" \u2014 no sibling to clone as template. Seed the list with a hidden item first.`),this.name="EmptyListInsert",this.path=e}},j=class extends Error{constructor(e){super(`cannot write to read-only DOM property "${e}"`),this.name="RuleTargetReadOnly",this.target=e}};function A(t){let e=0,n=null,o=-1;for(let r=0;r<t.length;r++){let i=t[r];i==="\\"?r++:n?i===n&&(n=null):i==='"'||i==="'"?n=i:i==="["||i==="("?e++:i==="]"||i===")"?e>0&&e--:i==="@"&&e===0&&(o=r)}return o}function K(t){let e=A(t);return e===-1?{selector:t,prop:null}:{selector:t.slice(0,e),prop:t.slice(e+1)||null}}function O(t,e,n,o={}){return G(t,e,n,{depth:0,path:[]},o)}function G(t,e,n,o,r){if(o.depth>b)throw new S(o.path);if(typeof n=="string")return xt(t,e,n,o,r);if(Array.isArray(n)){let[i,f]=n,s=t.find(e,i,r);return st(r,o,s),s.map((l,c)=>G(t,l,f,{depth:o.depth+1,path:[...o.path,c]},r))}if(typeof n=="object"&&n!==null){let i={};for(let[f,s]of Object.entries(n))i[f]=G(t,e,s,{depth:o.depth+1,path:[...o.path,f]},r);return i}return null}function xt(t,e,n,o,r){if(n.endsWith("[]")){let s=n.slice(0,-2),l=t.find(e,s,r);return st(r,o,l),l.map(c=>t.text(c))}if(n.startsWith("@"))return it(t,e,n.slice(1));let i=A(n);if(i!==-1){let s=n.slice(0,i),l=n.slice(i+1),c=s?t.find(e,s,r):[e];return c.length===0?null:it(t,c[0],l)}if(n===".")return t.text(e);let f=t.find(e,n,r);return f.length===0?null:t.text(f[0])}function st(t,e,n){if(typeof t.onRowsRead=="function")try{t.onRowsRead(e.path.slice(),n)}catch(o){console.warn(`[hyper-html-api] onRowsRead threw at "${e.path.join(".")||"(root)"}"`,o)}}function it(t,e,n){if(F.has(n)){let r=t.prop(e,n);return r==null?null:String(r)}let o=t.attr(e,n);return o||null}function ct(t,e,n,o){let r=t.length,i=e.length,f=new Array(r).fill(-1);if(o){let u=new Set;for(let d=0;d<r;d++){let g=o[d];!(g>=0&&g<i)||u.has(g)||(f[d]=g,u.add(g))}}if(r===0||i===0)return f;let s=t.map(u=>lt(u,n)),l=e.map(u=>lt(u,n)),c=new Array(i).fill(!1);for(let u of f)u>=0&&(c[u]=!0);let p=new Map;l.forEach((u,d)=>{c[d]||p.set(u,p.has(u)?-1:d)});let a=new Map;s.forEach((u,d)=>{f[d]>=0||a.set(u,(a.get(u)||0)+1)}),s.forEach((u,d)=>{if(f[d]>=0||a.get(u)!==1)return;let g=p.get(u);g===void 0||g===-1||c[g]||(f[d]=g,c[g]=!0)});let h=[];for(let u=0;u<r;u++)f[u]<0&&h.push(u);let E=[];for(let u=0;u<i;u++)c[u]||E.push(u);if(h.length===0||E.length===0)return f;let y=r*i+1,w=(u,d)=>Tt(t[u],e[d],n)*y+Math.abs(u-d);for(let[u,d]of bt(h,E,w))f[u]=d;return f}var ut=t=>typeof t=="object"&&t!==null;function lt(t,e){if(!ut(e))return t==null?" null":String(t);let n=Object.keys(e);return JSON.stringify(n.map(o=>{let r=JSON.stringify(t?.[o]);return r===void 0?" undef":r}))}function Tt(t,e,n){if(!ut(n))return t===e?0:1;let o=Object.keys(n);if(o.length===0)return 0;let r=0;for(let i of o){let f=JSON.stringify(t?.[i]),s=JSON.stringify(e?.[i]);f!==s&&r++}return r}function bt(t,e,n){return t.length<=e.length?ft(t,e,n,!1):ft(e,t,(o,r)=>n(r,o),!0)}function ft(t,e,n,o){let r=t.length,i=e.length,f=[];for(let a=0;a<=r;a++)f.push(new Float64Array(i+1).fill(1/0));let s=[];for(let a=0;a<=r;a++)s.push(new Uint8Array(i+1));for(let a=0;a<=i;a++)f[r][a]=0;for(let a=r-1;a>=0;a--)for(let h=i-1;h>=0;h--){let E=n(t[a],e[h])+f[a+1][h+1],y=f[a][h+1];E<=y?(f[a][h]=E,s[a][h]=1):f[a][h]=y}let l=[],c=0,p=0;for(;c<r&&p<i;)s[c][p]&&(l.push(o?[e[p],t[c]]:[t[c],e[p]]),c++),p++;return l}function X(t,e,n,o,r,i,f,s={}){let l=t.find(e,n,s);if(r.length===0){l.forEach(m=>t.remove(m)),V(s,"onRowsApplied",i.path,[]);return}let c=r.length>l.length,p=l[0]||null;if(c&&!p&&(p=_t(t,e,n,s),!p))throw new P(i.path);let a=l.map(m=>Mt(t,m,o,s)),h=null;if(c&&p){h=t.clone(p),s.templateAttr&&t.removeAttr(h,s.templateAttr);let m=t.stripIds(h);m>0&&console.warn(`[hyper-html-api] stripped ${m} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let E=ct(r,a,o,Nt(t,l,r,i,s)),y=l[0]||p,w=t.parent(y),u=l.length>0?at(t,w,y):0,d=Dt(t,l),g=new Set,v=[],H=r.map((m,M)=>{let x=E[M];if(x>=0)return g.add(x),v.push(!1),l[x];v.push(!0);let J=t.clone(h);return t.stripIds(J),J});l.forEach((m,M)=>{g.has(M)||t.remove(m)}),d?H.forEach((m,M)=>{let x=u+M;t.children(w).findIndex(Et=>t.sameNode(Et,m))!==x&&t.insertAt(w,m,x)}):Pt(t,H,v,w,u),It(t,H,o,r,i,f,s),V(s,"onRowsApplied",i.path,H)}function V(t,e,n,o){if(typeof t[e]=="function")try{return t[e](n.slice(),o)}catch(r){console.warn(`[hyper-html-api] ${e} threw at "${n.join(".")||"(root)"}"`,r);return}}function Nt(t,e,n,o,r){let i=V(r,"identifyRows",o.path,n);if(!Array.isArray(i))return null;let f=new Array(n.length).fill(-1),s=new Set;for(let l=0;l<n.length;l++)if(i[l]){for(let c=0;c<e.length;c++)if(!(s.has(c)||!t.sameNode(e[c],i[l]))){f[l]=c,s.add(c);break}}return f}function It(t,e,n,o,r,i,f){e.forEach((s,l)=>{if(n===null){let c=o[l],p=c==null?"":String(c);t.text(s)!==p&&t.text(s,p)}else{let c=i(t,s,n,o[l],{depth:r.depth+1,path:[...r.path,l]},f);c&&c!==s&&(e[l]=c)}})}function Mt(t,e,n,o){return n===null?t.text(e):O(t,e,n,o.onRowsRead?{...o,onRowsRead:void 0}:o)}function at(t,e,n){let o=t.children(e);for(let r=0;r<o.length;r++)if(t.sameNode(o[r],n))return r;return-1}function _t(t,e,n,o){if(!o.templateAttr)return null;let r=e;for(;r;){let i=t.find(r,n,{includeRulesTag:!1,templateAttr:null});for(let f of i)if(t.attr(f,o.templateAttr)!=null)return f;r=t.parent(r)}return null}function Dt(t,e){if(e.length<=1)return!0;let n=t.parent(e[0]);if(!n)return!1;let o=t.children(n),r=[];for(let i of e){let f=o.findIndex(s=>t.sameNode(s,i));if(f===-1)return!1;r.push(f)}return r.sort((i,f)=>i-f),r[r.length-1]-r[0]===r.length-1}function Pt(t,e,n,o,r){let i=null,f=r;for(let s=0;s<e.length;s++){if(!n[s]){i=e[s];continue}let l=i?t.parent(i):o;if(!l)continue;let c=i?at(t,l,i)+1:f++;t.insertAt(l,e[s],c),i=e[s]}}var ht=new Set(["checked","selected","disabled","readOnly","paused"]);function N(t,e,n,o,r={}){let i=[];if(z(n,o,[],i),i.length)throw new D(i);U(t,e,n,o,{depth:0,path:[]},r)}function U(t,e,n,o,r,i={}){if(r.depth>b)throw new S(r.path);if(o===void 0)return e;if(typeof n=="string")return jt(t,e,n,o,r,i);if(Array.isArray(n)){let[f,s]=n;return X(t,e,f,s,o,r,U,i),e}if(typeof n=="object"&&n!==null){for(let[f,s]of Object.entries(n)){let l=U(t,e,s,o==null?o:o[f],{depth:r.depth+1,path:[...r.path,f]},i);l&&l!==e&&(e=l)}return e}return e}function jt(t,e,n,o,r,i){if(n.endsWith("[]")){let l=n.slice(0,-2);return X(t,e,l,null,o,r,U,i),e}if(n.startsWith("@"))return dt(t,e,n.slice(1),o);let f=A(n);if(f!==-1){let l=n.slice(0,f),c=n.slice(f+1),p=l?t.find(e,l,i):[e];return p.length===0||dt(t,p[0],c,o),e}if(n===".")return pt(t,e,o),e;let s=t.find(e,n,i);return s.length===0||pt(t,s[0],o),e}function pt(t,e,n){let o=n==null?"":String(n);t.text(e)!==o&&t.text(e,o)}function dt(t,e,n,o){if(ot.has(n))throw new j(n);if(n==="outerHTML"){let r=o==null?"":String(o);return t.replaceWith(e,r)}return rt.has(n)?(t.prop(e,n,Ct(n,o)),e):(t.attr(e,n,o==null?"":String(o)),e)}function Ct(t,e){return e==null?ht.has(t)?!1:"":ht.has(t)?e==="false"?!1:!!e:e}function z(t,e,n,o){if(e!==void 0){if(typeof t=="string"){if(t.endsWith("[]")){Array.isArray(e)?e.forEach((r,i)=>{typeof r=="object"&&r!==null&&o.push({path:L([...n,i]),expected:"scalar",got:C(r)})}):o.push({path:L(n),expected:"array",got:C(e)});return}e!==null&&typeof e=="object"&&o.push({path:L(n),expected:"scalar",got:C(e)});return}if(Array.isArray(t)){if(!Array.isArray(e)){o.push({path:L(n),expected:"array",got:C(e)});return}let r=t[1];e.forEach((i,f)=>z(r,i,[...n,f],o));return}if(typeof t=="object"&&t!==null){if(e===null||Array.isArray(e)||typeof e!="object"){o.push({path:L(n),expected:"object",got:C(e)});return}for(let[r,i]of Object.entries(t))z(i,e[r],[...n,r],o)}}}function C(t){return t===null?"null":Array.isArray(t)?"array":typeof t}function L(t){return t.join(".")}function Q(t){try{return JSON.parse(t)}catch(e){throw new T(`Invalid strict JSON: ${e.message}`,e)}}function $(t){try{return JSON.parse(t)}catch{}let e={BRACE_OPEN:"{",BRACE_CLOSE:"}",BRACKET_OPEN:"[",BRACKET_CLOSE:"]",COLON:":",COMMA:",",STRING:"STRING",SELECTOR:"SELECTOR",IDENTIFIER:"IDENTIFIER",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN"};function n(r){let i=[],f=0;for(;f<r.length;){let s=r[f];if(/\s/.test(s)){f++;continue}if("{}".includes(s)){i.push({type:s,value:s}),f++;continue}if(s==="["){let a=!1,h=f+1;for(;h<r.length&&/\s/.test(r[h]);)h++;if(h<r.length&&/[a-zA-Z_]/.test(r[h])&&(a=!0),!a){i.push({type:s,value:s}),f++;continue}}if(s==="]"){i.push({type:s,value:s}),f++;continue}if(s===":"){i.push({type:e.COLON,value:s}),f++;continue}if(s===","){i.push({type:e.COMMA,value:s}),f++;continue}if(s==='"'||s==="'"){let a=s,h=f+1;for(;h<r.length&&r[h]!==a;)r[h]==="\\"&&h++,h++;i.push({type:e.STRING,value:r.substring(f+1,h),quoted:!0,sourceQuote:a}),f=h+1;continue}let l=f,c;for(;l<r.length&&!/[{},]/.test(r[l]);)if(r[l]===":"){let a=[":first",":last",":nth-child",":nth-of-type",":first-child",":last-child",":first-of-type",":last-of-type",":only-child",":only-of-type",":hover",":focus",":active",":visited",":disabled",":enabled",":checked",":empty",":root",":target",":not",":before",":after",":nth-last-child",":nth-last-of-type"],h=!1;for(let E of a){let y=E.substring(1);if(r.substring(l+1,l+1+y.length)===y){h=!0,l+=y.length;break}}if(!h)break}else if(r[l]==="["){for(l++;l<r.length&&r[l]!=="]";){if(r[l]==='"'||r[l]==="'"){let a=r[l];for(l++;l<r.length&&r[l]!==a;)r[l]==="\\"&&l++,l++}l++}l<r.length&&r[l]==="]"&&l++}else l++;c=r.substring(f,l);let p=e.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(c)?p=e.NUMBER:c==="true"||c==="false"||c==="null"?p=e.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(c)&&(p=e.SELECTOR),i.push({type:p,value:c,quoted:!1}),f=l}return i}function o(r){let i="";for(let f=0;f<r.length;f++){let s=r[f];if("{}".includes(s.type)||"[]".includes(s.type)){i+=s.value;continue}if(s.type===e.COLON){i+=s.value;continue}if(s.type===e.COMMA){let l=r[f+1];if(l&&(l.type==="}"||l.type==="]"))continue;i+=s.value;continue}if(s.type===e.STRING&&s.quoted){let l=s.value;s.sourceQuote==="'"&&(l=l.replace(/\\'/g,"'"),l=l.replace(/(\\*)"/g,(c,p)=>p.length%2===0?p+'\\"':c)),i+=`"${l}"`;continue}if(s.type===e.NUMBER||s.type===e.BOOLEAN){i+=s.value;continue}if(s.type===e.SELECTOR||s.type===e.IDENTIFIER){i+=`"${s.value}"`;continue}i+=`"${s.value}"`}return i}try{let r=n(t),i=o(r);return JSON.parse(i)}catch(r){throw new T("Invalid extraction rules syntax: "+r.message,r)}}var Lt="1",gt=/^[a-zA-Z0-9_-]+$/;function I(t,e,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!gt.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${gt})`);o=`script[data-rules-name~="${n}"]`}let r=t.find(e,o,{includeRulesTag:!0});if(r.length===0)return null;n!==void 0&&r.length>1&&console.warn(`hyper-html-api: ${r.length} rules tags match data-rules-name~="${n}"; using the first.`);let i=r[0],f=t.attr(i,"data-rules-version");if(f!==Lt)throw new _(f);return{rules:$(t.text(i)),tagNode:i}}function Y(t,e,n){if(n&&typeof n=="object")return{rules:n,tagNode:null};if(typeof n=="string"){let o=e&&e.ownerDocument?e.ownerDocument:e;return I(t,o,n)}return null}function mt(t,e,n,o){let r=Y(t,e,n);if(!r){let s=typeof n=="string"?`data-rules-name~="${n}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${s}`)}let{rules:i,tagNode:f}=r;return{rules:i,tagNode:f,get:()=>O(t,e,i,o),set:s=>N(t,e,i,s,o)}}function kt(t){return t&&t.nodeType===1&&t.tagName==="SCRIPT"&&t.hasAttribute&&t.hasAttribute("data-rules-name")}function Ht(t){return t?(t.nodeType===9||t.nodeType===11,t):null}var Wt={find(t,e,n={}){let o=Ht(t);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(e));n.includeRulesTag||(r=r.filter(s=>!kt(s)));let i=[];n.skip&&i.push(n.skip);let f=n.templateAttr===null?null:n.templateAttr||"cms-template";if(f&&i.push("["+f+"]"),i.length){let s=i.join(", ");r=r.filter(l=>!l.closest||!l.closest(s))}return r},parent(t){return t?t.parentElement:null},children(t){return t?Array.from(t.children):[]},text(t,e){if(e===void 0)return(t.textContent||"").trim();t.textContent=e},attr(t,e,n){if(n===void 0)return t.hasAttribute&&t.hasAttribute(e)?t.getAttribute(e):null;t.setAttribute(e,n)},removeAttr(t,e){t&&t.removeAttribute&&t.removeAttribute(e)},prop(t,e,n){if(n===void 0){let o=t?t[e]:void 0;return o!==void 0?o:null}t[e]=n},clone(t){return t.cloneNode(!0)},insertAt(t,e,n){let o=t.children[n]||null;t.insertBefore(e,o)},remove(t){t&&t.parentNode&&t.parentNode.removeChild(t)},replaceWith(t,e){if(!t||!t.parentNode)throw new Error("dom.replaceWith: node has no parent");let o=t.ownerDocument.createElement("template");o.innerHTML=e;let r=o.content.firstElementChild;if(!r)throw new Error("dom.replaceWith: html did not parse to an element");return t.parentNode.replaceChild(r,t),r},stripIds(t){let e=0;return t.id&&(t.removeAttribute("id"),e++),(t.querySelectorAll?t.querySelectorAll("[id]"):[]).forEach(o=>{o.removeAttribute("id"),e++}),e},sameNode(t,e){return t===e}},R=Wt;var k={extract:(t,e,n)=>O(R,t,e,n),apply:(t,e,n,o)=>N(R,t,e,n,o),findRulesIn:(t,e)=>I(R,t,e),findRules:(t,e)=>Y(R,t,e),bind:(t,e,n)=>mt(R,t,e,n),parseStrict:Q,parseRelaxed:$,ruleAttrIndex:A,splitRule:K,errors:B,DOM_PROPERTIES:W},Z=t=>!!t&&typeof t.nodeType=="number";function yt(t){let e=t&&t.ownerDocument?t.ownerDocument:t,n=R.find(e,"script[data-rules-name]",{includeRulesTag:!0});if(n.length===0)throw new Error('hyper-html-api: no rules tag found. Add <script type="application/json" data-rules-name="\u2026" data-rules-version="1"> or pass rules.');if(n.length>1)throw new Error('hyper-html-api: multiple rules tags found; pass a name, e.g. extractData("api").');return I(R,e).rules}function tt(t,e){let n=Z(t)?t:document,o=Z(t)?e:t;return o===void 0?O(R,n,yt(n)):k.bind(n,o).get()}function et(t,e,n){if(!Z(t))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?N(R,t,yt(t),e):k.bind(t,n).set(e),t}var Bt={engine:k,extractData:tt,applyData:et},Ut=Bt;return St(vt);})();
|
|
5
|
+
var hyperHtmlApiData=(()=>{var K=Object.defineProperty;var Ie=Object.getOwnPropertyDescriptor;var je=Object.getOwnPropertyNames;var Pe=Object.prototype.hasOwnProperty;var fe=(e,t)=>{for(var n in t)K(e,n,{get:t[n],enumerable:!0})},De=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of je(t))!Pe.call(e,r)&&r!==n&&K(e,r,{get:()=>t[r],enumerable:!(o=Ie(t,r))||o.enumerable});return e};var Le=e=>De(K({},"__esModule",{value:!0}),e);var tt={};fe(tt,{applyData:()=>se,default:()=>et,engine:()=>z,extractData:()=>le});var F=["textContent","innerText","innerHTML","outerHTML","value","checked","selected","disabled","readOnly","type","tagName","nodeName","nodeType","nodeValue","childElementCount","id","className","classList","baseURI","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","dataset","currentSrc","duration","paused","title","documentURI","contentType"],G=new Set(F),ue=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),X=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var V={};fe(V,{EmptyListInsert:()=>k,MAX_RULE_DEPTH:()=>j,MaxRuleDepthExceeded:()=>C,RuleTargetReadOnly:()=>$,RulesParseError:()=>I,ShapeMismatch:()=>v,UnknownRulesVersion:()=>_});var I=class extends Error{constructor(t,n){super(t),this.name="RulesParseError",this.cause=n}},_=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},j=20,C=class extends Error{constructor(t){super(`rule depth exceeded ${j} at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},v=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},k=class extends Error{constructor(t){super(`cannot add items to empty list at "${t.join(".")}" \u2014 no sibling to clone as template. Seed the list with a hidden item first.`),this.name="EmptyListInsert",this.path=t}},$=class extends Error{constructor(t){super(`cannot write to read-only DOM property "${t}"`),this.name="RuleTargetReadOnly",this.target=t}};function b(e){let t=0,n=null,o=-1;for(let r=0;r<e.length;r++){let i=e[r];i==="\\"?r++:n?i===n&&(n=null):i==='"'||i==="'"?n=i:i==="["||i==="("?t++:i==="]"||i===")"?t>0&&t--:i==="@"&&t===0&&(o=r)}return o}function Y(e){let t=b(e);return t===-1?{selector:e,prop:null}:{selector:e.slice(0,t),prop:e.slice(t+1)||null}}function N(e,t,n,o={}){if(Object.prototype.hasOwnProperty.call(o,"exclude")&&e.semanticExclude===!1)throw new Error("This adapter does not support semantic exclude queries; omit exclude or use the DOM adapter.");return Q(e,t,n,{depth:0,path:[]},o)}function Q(e,t,n,o,r){if(o.depth>j)throw new C(o.path);if(typeof n=="string")return _e(e,t,n,o,r);if(Array.isArray(n)){let[i,c]=n,l=e.find(t,i,r);return de(r,o,l),l.map((s,u)=>Q(e,s,c,{depth:o.depth+1,path:[...o.path,u]},r))}if(typeof n=="object"&&n!==null){let i={};for(let[c,l]of Object.entries(n))i[c]=Q(e,t,l,{depth:o.depth+1,path:[...o.path,c]},r);return i}return null}function _e(e,t,n,o,r){if(n.endsWith("[]")){let l=n.slice(0,-2),s=e.find(t,l,r);return de(r,o,s),s.map(u=>e.text(u))}if(n.startsWith("@"))return ae(e,t,n.slice(1));let i=b(n);if(i!==-1){let l=n.slice(0,i),s=n.slice(i+1),u=l?e.find(t,l,r):[t];return u.length===0?null:ae(e,u[0],s)}if(n===".")return e.text(t);let c=e.find(t,n,r);return c.length===0?null:e.text(c[0])}function de(e,t,n){if(typeof e.onRowsRead=="function")try{e.onRowsRead(t.path.slice(),n)}catch(o){console.warn(`[hyper-html-api] onRowsRead threw at "${t.path.join(".")||"(root)"}"`,o)}}function ae(e,t,n){if(G.has(n)){let r=e.prop(t,n);return r==null?null:String(r)}let o=e.attr(t,n);return o||null}function me(e,t,n,o){let r=e.length,i=t.length,c=new Array(r).fill(-1);if(o){let f=new Set;for(let h=0;h<r;h++){let y=o[h];!(y>=0&&y<i)||f.has(y)||(c[h]=y,f.add(y))}}if(r===0||i===0)return c;let l=e.map(f=>he(f,n)),s=t.map(f=>he(f,n)),u=new Array(i).fill(!1);for(let f of c)f>=0&&(u[f]=!0);let a=new Map;s.forEach((f,h)=>{u[h]||a.set(f,a.has(f)?-1:h)});let g=new Map;l.forEach((f,h)=>{c[h]>=0||g.set(f,(g.get(f)||0)+1)}),l.forEach((f,h)=>{if(c[h]>=0||g.get(f)!==1)return;let y=a.get(f);y===void 0||y===-1||u[y]||(c[h]=y,u[y]=!0)});let d=[];for(let f=0;f<r;f++)c[f]<0&&d.push(f);let x=[];for(let f=0;f<i;f++)u[f]||x.push(f);if(d.length===0||x.length===0)return c;let m=r*i+1,p=(f,h)=>ve(e[f],t[h],n)*m+Math.abs(f-h);for(let[f,h]of ke(d,x,p))c[f]=h;return c}var ye=e=>typeof e=="object"&&e!==null;function he(e,t){if(!ye(t))return e==null?" null":String(e);let n=Object.keys(t);return JSON.stringify(n.map(o=>{let r=JSON.stringify(e?.[o]);return r===void 0?" undef":r}))}function ve(e,t,n){if(!ye(n))return e===t?0:1;let o=Object.keys(n);if(o.length===0)return 0;let r=0;for(let i of o){let c=JSON.stringify(e?.[i]),l=JSON.stringify(t?.[i]);c!==l&&r++}return r}function ke(e,t,n){return e.length<=t.length?pe(e,t,n,!1):pe(t,e,(o,r)=>n(r,o),!0)}function pe(e,t,n,o){let r=e.length,i=t.length,c=[];for(let g=0;g<=r;g++)c.push(new Float64Array(i+1).fill(1/0));let l=[];for(let g=0;g<=r;g++)l.push(new Uint8Array(i+1));for(let g=0;g<=i;g++)c[r][g]=0;for(let g=r-1;g>=0;g--)for(let d=i-1;d>=0;d--){let x=n(e[g],t[d])+c[g+1][d+1],m=c[g][d+1];x<=m?(c[g][d]=x,l[g][d]=1):c[g][d]=m}let s=[],u=0,a=0;for(;u<r&&a<i;)l[u][a]&&(s.push(o?[t[a],e[u]]:[e[u],t[a]]),u++),a++;return s}function ee(e,t,n,o,r,i,c,l={}){let s=e.find(t,n,l);if(r.length===0){s.forEach(E=>e.remove(E)),Z(l,"onRowsApplied",i.path,[]);return}let u=r.length>s.length,a=s[0]||null;if(u&&!a&&(a=Be(e,t,n,l),!a))throw new k(i.path);let g=s.map(E=>We(e,E,o,l)),d=null;if(u&&a){d=e.clone(a),l.templateAttr&&e.removeAttr(d,l.templateAttr);let E=e.stripIds(d);E>0&&console.warn(`[hyper-html-api] stripped ${E} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let x=me(r,g,o,$e(e,s,r,i,l)),m=s[0]||a,p=e.parent(m),f=s.length>0?ge(e,p,m):0,h=qe(e,s),y=new Set,A=[],O=r.map((E,w)=>{let T=x[w];if(T>=0)return y.add(T),A.push(!1),s[T];A.push(!0);let S=e.clone(d);return e.stripIds(S),S});s.forEach((E,w)=>{y.has(w)||e.remove(E)}),h?O.forEach((E,w)=>{let T=f+w;e.children(p).findIndex(Me=>e.sameNode(Me,E))!==T&&e.insertAt(p,E,T)}):Ue(e,O,A,p,f),He(e,O,o,r,i,c,l),Z(l,"onRowsApplied",i.path,O)}function Z(e,t,n,o){if(typeof e[t]=="function")try{return e[t](n.slice(),o)}catch(r){console.warn(`[hyper-html-api] ${t} threw at "${n.join(".")||"(root)"}"`,r);return}}function $e(e,t,n,o,r){let i=Z(r,"identifyRows",o.path,n);if(!Array.isArray(i))return null;let c=new Array(n.length).fill(-1),l=new Set;for(let s=0;s<n.length;s++)if(i[s]){for(let u=0;u<t.length;u++)if(!(l.has(u)||!e.sameNode(t[u],i[s]))){c[s]=u,l.add(u);break}}return c}function He(e,t,n,o,r,i,c){t.forEach((l,s)=>{if(n===null){let u=o[s],a=u==null?"":String(u);e.text(l)!==a&&e.text(l,a)}else{let u=i(e,l,n,o[s],{depth:r.depth+1,path:[...r.path,s]},c);u&&u!==l&&(t[s]=u)}})}function We(e,t,n,o){return n===null?e.text(t):N(e,t,n,o.onRowsRead?{...o,onRowsRead:void 0}:o)}function ge(e,t,n){let o=e.children(t);for(let r=0;r<o.length;r++)if(e.sameNode(o[r],n))return r;return-1}function Be(e,t,n,o){if(!o.templateAttr)return null;let r=t;for(;r;){let i=e.find(r,n,{includeRulesTag:!1,templateAttr:null});for(let c of i)if(e.attr(c,o.templateAttr)!=null)return c;r=e.parent(r)}return null}function qe(e,t){if(t.length<=1)return!0;let n=e.parent(t[0]);if(!n)return!1;let o=e.children(n),r=[];for(let i of t){let c=o.findIndex(l=>e.sameNode(l,i));if(c===-1)return!1;r.push(c)}return r.sort((i,c)=>i-c),r[r.length-1]-r[0]===r.length-1}function Ue(e,t,n,o,r){let i=null,c=r;for(let l=0;l<t.length;l++){if(!n[l]){i=t[l];continue}let s=i?e.parent(i):o;if(!s)continue;let u=i?ge(e,s,i)+1:c++;e.insertAt(s,t[l],u),i=t[l]}}var Ee=new Set(["checked","selected","disabled","readOnly","paused"]);function P(e,t,n,o,r={}){if(Object.prototype.hasOwnProperty.call(r,"exclude")&&e.semanticExclude===!1)throw new Error("This adapter does not support semantic exclude queries; omit exclude or use the DOM adapter.");let i=[];if(te(n,o,[],i),i.length)throw new v(i);J(e,t,n,o,{depth:0,path:[]},r)}function J(e,t,n,o,r,i={}){if(r.depth>j)throw new C(r.path);if(o===void 0)return t;if(typeof n=="string")return ze(e,t,n,o,r,i);if(Array.isArray(n)){let[c,l]=n;return ee(e,t,c,l,o,r,J,i),t}if(typeof n=="object"&&n!==null){for(let[c,l]of Object.entries(n)){let s=J(e,t,l,o==null?o:o[c],{depth:r.depth+1,path:[...r.path,c]},i);s&&s!==t&&(t=s)}return t}return t}function ze(e,t,n,o,r,i){if(n.endsWith("[]")){let s=n.slice(0,-2);return ee(e,t,s,null,o,r,J,i),t}if(n.startsWith("@"))return we(e,t,n.slice(1),o);let c=b(n);if(c!==-1){let s=n.slice(0,c),u=n.slice(c+1),a=s?e.find(t,s,i):[t];return a.length===0||we(e,a[0],u,o),t}if(n===".")return Te(e,t,o),t;let l=e.find(t,n,i);return l.length===0||Te(e,l[0],o),t}function Te(e,t,n){let o=n==null?"":String(n);e.text(t)!==o&&e.text(t,o)}function we(e,t,n,o){if(X.has(n))throw new $(n);if(n==="outerHTML"){let i=o==null?"":String(o);return e.replaceWith(t,i)}if(ue.has(n)){let i=Fe(n,o);return e.prop(t,n)!==i&&e.prop(t,n,i),t}let r=o==null?"":String(o);return e.attr(t,n)!==r&&e.attr(t,n,r),t}function Fe(e,t){return t==null?Ee.has(e)?!1:"":Ee.has(e)?t==="false"?!1:!!t:t}function te(e,t,n,o){if(t!==void 0){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((r,i)=>{typeof r=="object"&&r!==null&&o.push({path:W([...n,i]),expected:"scalar",got:H(r)})}):o.push({path:W(n),expected:"array",got:H(t)});return}t!==null&&typeof t=="object"&&o.push({path:W(n),expected:"scalar",got:H(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){o.push({path:W(n),expected:"array",got:H(t)});return}let r=e[1];t.forEach((i,c)=>te(r,i,[...n,c],o));return}if(typeof e=="object"&&e!==null){if(t===null||Array.isArray(t)||typeof t!="object"){o.push({path:W(n),expected:"object",got:H(t)});return}for(let[r,i]of Object.entries(e))te(i,t[r],[...n,r],o)}}}function H(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function W(e){return e.join(".")}function ne(e){try{return JSON.parse(e)}catch(t){throw new I(`Invalid strict JSON: ${t.message}`,t)}}function B(e){try{return JSON.parse(e)}catch{}let t={BRACE_OPEN:"{",BRACE_CLOSE:"}",BRACKET_OPEN:"[",BRACKET_CLOSE:"]",COLON:":",COMMA:",",STRING:"STRING",SELECTOR:"SELECTOR",IDENTIFIER:"IDENTIFIER",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN"};function n(r){let i=[],c=0;for(;c<r.length;){let l=r[c];if(/\s/.test(l)){c++;continue}if("{}".includes(l)){i.push({type:l,value:l}),c++;continue}if(l==="["){let g=!1,d=c+1;for(;d<r.length&&/\s/.test(r[d]);)d++;if(d<r.length&&/[a-zA-Z_]/.test(r[d])&&(g=!0),!g){i.push({type:l,value:l}),c++;continue}}if(l==="]"){i.push({type:l,value:l}),c++;continue}if(l===":"){i.push({type:t.COLON,value:l}),c++;continue}if(l===","){i.push({type:t.COMMA,value:l}),c++;continue}if(l==='"'||l==="'"){let g=l,d=c+1;for(;d<r.length&&r[d]!==g;)r[d]==="\\"&&d++,d++;i.push({type:t.STRING,value:r.substring(c+1,d),quoted:!0,sourceQuote:g}),c=d+1;continue}let s=c,u;for(;s<r.length&&!/[{},]/.test(r[s]);)if(r[s]===":"){let g=[":first",":last",":nth-child",":nth-of-type",":first-child",":last-child",":first-of-type",":last-of-type",":only-child",":only-of-type",":hover",":focus",":active",":visited",":disabled",":enabled",":checked",":empty",":root",":target",":not",":before",":after",":nth-last-child",":nth-last-of-type"],d=!1;for(let x of g){let m=x.substring(1);if(r.substring(s+1,s+1+m.length)===m){d=!0,s+=m.length;break}}if(!d)break}else if(r[s]==="["){for(s++;s<r.length&&r[s]!=="]";){if(r[s]==='"'||r[s]==="'"){let g=r[s];for(s++;s<r.length&&r[s]!==g;)r[s]==="\\"&&s++,s++}s++}s<r.length&&r[s]==="]"&&s++}else s++;u=r.substring(c,s);let a=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(u)?a=t.NUMBER:u==="true"||u==="false"||u==="null"?a=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(u)&&(a=t.SELECTOR),i.push({type:a,value:u,quoted:!1}),c=s}return i}function o(r){let i="";for(let c=0;c<r.length;c++){let l=r[c];if("{}".includes(l.type)||"[]".includes(l.type)){i+=l.value;continue}if(l.type===t.COLON){i+=l.value;continue}if(l.type===t.COMMA){let s=r[c+1];if(s&&(s.type==="}"||s.type==="]"))continue;i+=l.value;continue}if(l.type===t.STRING&&l.quoted){let s=l.value;l.sourceQuote==="'"&&(s=s.replace(/\\'/g,"'"),s=s.replace(/(\\*)"/g,(u,a)=>a.length%2===0?a+'\\"':u)),i+=`"${s}"`;continue}if(l.type===t.NUMBER||l.type===t.BOOLEAN){i+=l.value;continue}if(l.type===t.SELECTOR||l.type===t.IDENTIFIER){i+=`"${l.value}"`;continue}i+=`"${l.value}"`}return i}try{let r=n(e),i=o(r);return JSON.parse(i)}catch(r){throw new I("Invalid extraction rules syntax: "+r.message,r)}}var Ve="1",Oe=/^[a-zA-Z0-9_-]+$/;function D(e,t,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!Oe.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${Oe})`);o=`script[data-rules-name~="${n}"]`}let r=e.find(t,o,{includeRulesTag:!0});if(r.length===0)return null;n!==void 0&&r.length>1&&console.warn(`hyper-html-api: ${r.length} rules tags match data-rules-name~="${n}"; using the first.`);let i=r[0],c=e.attr(i,"data-rules-version");if(c!==Ve)throw new _(c);return{rules:B(e.text(i)),tagNode:i}}function re(e,t,n){if(n&&typeof n=="object")return{rules:n,tagNode:null};if(typeof n=="string"){let o=t&&t.ownerDocument?t.ownerDocument:t;return D(e,o,n)}return null}var Ae=Object.freeze({data:Object.freeze({tokens:["no-data"],bundles:["editor-ui"]}),save:Object.freeze({tokens:["no-save"],bundles:["editor-ui"]}),snapshot:Object.freeze({tokens:["no-snapshot"],bundles:["editor-ui"]}),watch:Object.freeze({tokens:["no-watch"],bundles:["editor-ui"]}),undo:Object.freeze({tokens:["no-undo"],bundles:["editor-ui"]}),history:Object.freeze({tokens:[],bundles:["editor-ui"]})}),Ke=Object.freeze({"editor-ui":Object.freeze(["no-data","no-save","no-snapshot","no-watch","no-undo"])}),Dt=Object.freeze(["no-save","no-snapshot","no-trigger-autosave","no-dirty","no-watch","no-undo","no-data","freeze","editor-ui"]);function oe(e,t){if(!e||e.nodeType!==1)return!1;let n=e.getAttribute?.("clay");return!!(n&&n.split(/\s+/).includes(t)||e.hasAttribute?.(t))}function Ge(e,t){if(oe(e,t))return!0;for(let[n,o]of Object.entries(Ke))if(o.includes(t)&&oe(e,n))return!0;return!1}function q(e){let t=Ae[e];if(!t)throw new Error(`Unknown region capability: ${e}`);return[...t.tokens,...t.bundles].flatMap(n=>[`[clay~="${n}"]`,`[${n}]`]).join(", ")}function Xe(e,t){let n=e&&e.nodeType===1?e:e?.parentElement;for(;n&&n.nodeType===1;){let o=Ae[t];if(!o)throw new Error(`Unknown region capability: ${t}`);if(o.tokens.some(r=>Ge(n,r))||o.bundles.some(r=>oe(n,r)))return n;n=n.parentElement}return null}function xe(e,t){return!!Xe(e,t)}var Ye=/:(?:focus(?:-within|-visible)?|hover|active|visited|defined)\b/i;function Re(e,t){if(!/^(INPUT|TEXTAREA|SELECT|OPTION)$/.test(e.tagName||""))return;let n=(e.getAttribute?.("type")||"").toLowerCase();if("value"in e&&"value"in t&&e.tagName!=="OPTION"&&n!=="checkbox"&&n!=="radio"&&(t.value=e.value),"checked"in e&&"checked"in t&&(t.checked=e.checked),"selected"in e&&"selected"in t&&(t.selected=e.selected),e.tagName==="SELECT")for(let o=0;o<e.options.length;o++)t.options[o].selected=e.options[o].selected;"indeterminate"in e&&"indeterminate"in t&&(t.indeterminate=e.indeterminate)}function Se(e,t,n,o){if(o)return!!e.closest?.(t);let r=e;for(;r?.nodeType===1;){if(r.matches(t))return!0;if(r===n)break;r=r.parentElement}return!1}function be(e,t,n,o,r,i,c,l){if(e.nodeType===1&&((c?xe(e,n):Se(e,o,i,!1))||r&&Se(e,r,i,c)))return null;let s=t.importNode(e,!1);l.cloneToLive.set(s,e),l.liveToClone.set(e,s);let u=e.nodeType===1&&e.tagName==="TEMPLATE"?e.content:e,a=s.nodeType===1&&s.tagName==="TEMPLATE"?s.content:s;u!==e&&(l.cloneToLive.set(a,u),l.liveToClone.set(u,a));for(let g of u.childNodes||[]){let d=be(g,t,n,o,r,i,c,l);d&&(a.appendChild(d),g.nodeType===1&&Re(g,d))}return e.nodeType===1&&Re(e,s),s}function U(e,{capability:t="data",exclude:n=null,inherit:o=!0}={}){if(!e)throw new TypeError("createContentView requires a DOM context");let r=e.nodeType===9?e:e.ownerDocument;if(!r?.implementation?.createHTMLDocument)throw new TypeError("createContentView requires an HTML DOM implementation");let i=r.implementation.createHTMLDocument(""),c=new WeakMap,l=new WeakMap,s=e.nodeType===9?e.documentElement:e;n&&i.documentElement.matches(n);let u=q(t),a=be(s,i,t,u,n,s,o,{cloneToLive:c,liveToClone:l});e.nodeType===9&&a&&(i.replaceChild(a,i.documentElement),l.set(e,i),c.set(i,e));let g=d=>{if(Ye.test(d))throw new Error(`Filtered content queries do not support stateful selector: ${d}`)};return{root:a,document:i,capability:t,selector:q(t),cloneToLive:c,liveToClone:l,original(d){return c.get(d)||null},cloneOf(d){return l.get(d)||null},query(d,x=a){return g(d),Array.from(x.querySelectorAll(d),m=>c.get(m)||m)},text(d=a){return(d===a?a:l.get(d))?.textContent||""},html(d=a){return(d===a?a:l.get(d))?.innerHTML??""},clone(d=a){let x=d===a?a:l.get(d);return x?i.importNode(x,!0):null}}}function Ne(e){return e&&e.nodeType===1&&e.tagName==="SCRIPT"&&e.hasAttribute&&e.hasAttribute("data-rules-name")}function Qe(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var R={semanticExclude:!0,find(e,t,n={}){let o=Qe(e);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(t));n.includeRulesTag||(r=r.filter(l=>!Ne(l)));let i=[];n.skip&&i.push(n.skip);let c=n.templateAttr===null?null:n.templateAttr||"cms-template";if(c&&i.push("["+c+"]"),i.length){let l=i.join(", ");r=r.filter(s=>!s.closest||!s.closest(l))}return r},parent(e){return e?e.parentElement:null},children(e){return e?Array.from(e.children):[]},text(e,t){if(t===void 0)return(e.textContent||"").trim();e.textContent=t},attr(e,t,n){if(n===void 0)return e.hasAttribute&&e.hasAttribute(t)?e.getAttribute(t):null;e.setAttribute(t,n)},removeAttr(e,t){e&&e.removeAttribute&&e.removeAttribute(t)},prop(e,t,n){if(n===void 0){let o=e?e[t]:void 0;return o!==void 0?o:null}e[t]=n},clone(e){return e.cloneNode(!0)},insertAt(e,t,n){let o=e.children[n]||null;e.insertBefore(t,o)},remove(e){e&&e.parentNode&&e.parentNode.removeChild(e)},replaceWith(e,t){if(!e||!e.parentNode)throw new Error("dom.replaceWith: node has no parent");let o=e.ownerDocument.createElement("template");o.innerHTML=t;let r=o.content.firstElementChild;if(!r)throw new Error("dom.replaceWith: html did not parse to an element");return e.parentNode.replaceChild(r,e),r},stripIds(e){let t=0;return e.id&&(e.removeAttribute("id"),t++),(e.querySelectorAll?e.querySelectorAll("[id]"):[]).forEach(o=>{o.removeAttribute("id"),t++}),t},sameNode(e,t){return e===t}};function M(e,t={}){if(t.exclude===null)return R;let n=[q("data"),t.exclude].filter(Boolean).join(", "),o=e.nodeType===9?e:e.ownerDocument||e,r=e.nodeType===9?e.documentElement:e;if(!t._write&&!r?.matches?.(n)&&!r?.querySelector?.(n)&&!o?.querySelector?.(n))return R;let i=e.nodeType===9||!e.isConnected?e:e.ownerDocument,c=e.nodeType===9?e:e.ownerDocument,l=null,s=()=>l||(l=U(i,{capability:"data",exclude:t.exclude||null})),u=m=>{let p=s();return m===e?p.cloneOf(e):p.cloneOf(m)||m},a=m=>l?.original(m)||m,g=(m,p)=>{s().liveToClone.set(m,p),s().cloneToLive.set(p,m);let f=m.childNodes||[],h=p.childNodes||[];for(let y=0;y<Math.min(f.length,h.length);y++)g(f[y],h[y])},d=(m,p,f,h)=>{let y=Array.from(m.childNodes).filter(T=>l.cloneOf(T)),O=y[0];for(;O&&y.includes(O);)O=O.nextSibling;for(let T of y)T.remove();if(f==="innerHTML"){let T=c.createElement("template");T.innerHTML=h;for(let S of Array.from(T.content.childNodes))m.insertBefore(S,O||null)}else m.insertBefore(c.createTextNode(h),O||null);let E=U(m,{capability:"data",exclude:t.exclude||null});p.replaceChildren(...Array.from(E.root?.childNodes||[]));let w=T=>{let S=E.original(T);S&&(l.liveToClone.set(S,T),l.cloneToLive.set(T,S));for(let ce of Array.from(T.childNodes||[]))w(ce)};for(let T of Array.from(p.childNodes))w(T)},x={...R,find(m,p,f={}){let h=u(m);if(!h?.querySelectorAll)return[];let y=s().query(p,h);f.includeRulesTag||(y=y.filter(E=>!Ne(E)));let A=[];f.skip&&A.push(f.skip);let O=f.templateAttr===null?null:f.templateAttr||"cms-template";if(O&&A.push(`[${O}]`),A.length){let E=A.join(", ");y=y.filter(w=>!w.closest?.(E))}return y},parent(m){let p=u(m)?.parentElement;return p?a(p):null},children(m){return Array.from(u(m)?.children||[],a)},text(m,p){if(p===void 0){let y=a(m);return!y?.matches?.(n)&&!y?.querySelector?.(n)?R.text(y):(u(m)?.textContent||"").trim()}let f=a(m);if(!f?.matches?.(n)&&!f?.querySelector?.(n)&&!l){R.text(f,p);return}let h=s().cloneOf(f);h?d(f,h,"textContent",p):R.text(f,p)},attr(m,p,f){let h=a(m);if(f===void 0)return R.attr(h,p);R.attr(h,p,f);let y=l?.cloneOf(h);y&&(R.attr(y,p,f),U(h,{capability:"data",exclude:t.exclude||null}).root===null&&(y.remove(),l.liveToClone.delete(h),l.cloneToLive.delete(y)))},removeAttr(m,p){let f=a(m);R.removeAttr(f,p);let h=l?.cloneOf(f);h&&R.removeAttr(h,p)},prop(m,p,f){let h=a(m);if(f===void 0)return p==="innerHTML"||p==="outerHTML"||p==="textContent"||p==="innerText"?R.prop(u(h),p):R.prop(h,p);let y=p==="innerHTML"||p==="textContent"||p==="innerText",A=y?s().cloneOf(h):l?.cloneOf(h);A&&y?d(h,A,p,f):(R.prop(h,p,f),A&&R.prop(A,p,f))},clone(m){let p=u(m);return p===m?R.clone(m):c.importNode(p,!0)},insertAt(m,p,f){let h=a(m),A=x.children(h)[f]||(()=>{for(let w=h.children.length-1;w>=0;w--){let T=h.children[w];if(s().cloneOf(T))return T.nextElementSibling}return h.firstElementChild})(),O=a(p);h.insertBefore(O,A||null);let E=s().cloneOf(h);if(E){let w=s().cloneOf(O);w||(w=c.importNode(O,!0),g(O,w));let T=Array.from(E.children);E.insertBefore(w,T[f]||null)}},remove(m){let p=a(m),f=s().cloneOf(p);R.remove(p),f&&R.remove(f)},replaceWith(m,p){let f=a(m),h=s().cloneOf(f),y=R.replaceWith(f,p);if(h){let A=U(y,{capability:"data",exclude:t.exclude||null});if(!A.root)h.remove();else{h.replaceWith(A.root);let O=E=>{let w=A.original(E);w&&(l.liveToClone.set(w,E),l.cloneToLive.set(E,w));for(let T of Array.from(E.childNodes||[]))O(T)};O(A.root)}}return y}};return x}var L=R;var z={extract:(e,t,n={})=>N(M(e,n),e,t,n),apply:(e,t,n,o={})=>P(M(e,{...o,_write:!0}),e,t,n,o),findRulesIn:(e,t)=>D(L,e,t),findRules:(e,t)=>re(L,e,t),bind:(e,t,n={})=>{let o=re(L,e,t);if(!o){let r=typeof t=="string"?`data-rules-name~="${t}"`:"the provided rules object";throw new Error(`hyper-html-api: could not resolve rules for ${r}`)}return{...o,get:()=>N(M(e,n),e,o.rules,n),set:r=>P(M(e,{...n,_write:!0}),e,o.rules,r,n)}},parseStrict:ne,parseRelaxed:B,ruleAttrIndex:b,splitRule:Y,errors:V,DOM_PROPERTIES:F},ie=e=>!!e&&typeof e.nodeType=="number";function Ce(e){let t=e&&e.ownerDocument?e.ownerDocument:e,n=L.find(t,"script[data-rules-name]",{includeRulesTag:!0});if(n.length===0)throw new Error('hyper-html-api: no rules tag found. Add <script type="application/json" data-rules-name="\u2026" data-rules-version="1"> or pass rules.');if(n.length>1)throw new Error('hyper-html-api: multiple rules tags found; pass a name, e.g. extractData("api").');return D(L,t).rules}function le(e,t){let n=ie(e)?e:document,o=ie(e)?t:e;return o===void 0?N(M(n),n,Ce(n)):z.bind(n,o).get()}function se(e,t,n){if(!ie(e))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?P(M(e),e,Ce(e),t):z.bind(e,n).set(t),e}var Ze={engine:z,extractData:le,applyData:se},et=Ze;return Le(tt);})();
|
|
6
6
|
window.clay = window.clay || {};
|
|
7
7
|
window.clay.extractData = hyperHtmlApiData.extractData;
|
|
8
8
|
// clayjs-level sugar: applyData(data) writes into the whole document, matching
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panphora/clayjs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "clayjs: malleable HTML files. Save lifecycle for self-saving HTML.",
|
|
6
6
|
"license": "MIT-0",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"./*": "./entries/*"
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
39
|
+
"packed-contract.json",
|
|
39
40
|
"entries/",
|
|
40
41
|
"dist/",
|
|
41
42
|
"THIRD-PARTY-NOTICES.md",
|
|
@@ -54,7 +55,10 @@
|
|
|
54
55
|
"prepublishOnly": "npm test && npm run test:conformance && npm run test:standalone",
|
|
55
56
|
"dev": "node tests/stub-server.mjs",
|
|
56
57
|
"build": "node build.js",
|
|
57
|
-
"
|
|
58
|
+
"propagate:foundation": "node scripts/propagate-foundation.mjs",
|
|
59
|
+
"check:foundation": "node scripts/propagate-foundation.mjs --check",
|
|
60
|
+
"deploy": "node build.js && wrangler deploy && git rev-parse HEAD > .deploy",
|
|
61
|
+
"build:parse5": "node scripts/build-parse5-vendor.mjs"
|
|
58
62
|
},
|
|
59
63
|
"devDependencies": {
|
|
60
64
|
"@esm-bundle/chai": "^4.3.4-fix.0",
|
|
@@ -64,6 +68,7 @@
|
|
|
64
68
|
"esbuild": "^0.28.2",
|
|
65
69
|
"jest": "^29.7.0",
|
|
66
70
|
"jest-environment-jsdom": "^29.7.0",
|
|
71
|
+
"parse5": "^7.3.0",
|
|
67
72
|
"playwright": "1.62.1"
|
|
68
73
|
},
|
|
69
74
|
"hyper": {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"load": [
|
|
3
|
+
"@panphora/clayjs/entries/all.js",
|
|
4
|
+
"@panphora/clayjs/entries/clay.js",
|
|
5
|
+
"@panphora/clayjs/entries/clay-data.js",
|
|
6
|
+
"@panphora/clayjs/entries/clay-dom.js",
|
|
7
|
+
"@panphora/clayjs/entries/clay-events.js",
|
|
8
|
+
"@panphora/clayjs/entries/clay-internals.js",
|
|
9
|
+
"@panphora/clayjs/entries/clay-options.js",
|
|
10
|
+
"@panphora/clayjs/entries/clay-ui.js",
|
|
11
|
+
"@panphora/clayjs/entries/clay-utils.js",
|
|
12
|
+
"@panphora/clayjs/entries/sap.js",
|
|
13
|
+
"@panphora/clayjs/clay.standalone.js"
|
|
14
|
+
],
|
|
15
|
+
"members": ["THIRD-PARTY-NOTICES.md"],
|
|
16
|
+
"families": ["./entries/*", "./dist/*", "./src/*"]
|
|
17
|
+
}
|
package/src/attrs/save-freeze.js
CHANGED
|
@@ -54,29 +54,21 @@ let pending = new WeakMap();
|
|
|
54
54
|
|
|
55
55
|
// Phase 2. The clone is a verbatim cloneNode of the live root and nothing has been
|
|
56
56
|
// stripped from it yet, so pairing by position is sound HERE and nowhere else.
|
|
57
|
-
function freezeSnapshot(clone) {
|
|
57
|
+
function freezeSnapshot(clone, provenance) {
|
|
58
58
|
pending = new WeakMap();
|
|
59
59
|
|
|
60
|
-
const liveElements = document.querySelectorAll(FREEZE_SELECTOR);
|
|
61
60
|
const cloneElements = clone.querySelectorAll(FREEZE_SELECTOR);
|
|
62
61
|
|
|
63
|
-
log('freezing clone
|
|
62
|
+
log('freezing clone:', cloneElements.length);
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
for (let i = 0; i < cloneElements.length; i++) {
|
|
74
|
-
if (!originals.has(liveElements[i])) continue;
|
|
75
|
-
const original = originals.get(liveElements[i]);
|
|
76
|
-
pending.set(cloneElements[i], original);
|
|
77
|
-
if (cloneElements[i].innerHTML !== original) {
|
|
78
|
-
log('element', i, '— restoring original');
|
|
79
|
-
cloneElements[i].innerHTML = original;
|
|
64
|
+
for (const cloneElement of cloneElements) {
|
|
65
|
+
const liveElement = provenance.original(cloneElement);
|
|
66
|
+
if (!liveElement || !originals.has(liveElement)) continue;
|
|
67
|
+
const original = originals.get(liveElement);
|
|
68
|
+
pending.set(cloneElement, original);
|
|
69
|
+
if (cloneElement.innerHTML !== original) {
|
|
70
|
+
log('restoring original');
|
|
71
|
+
cloneElement.innerHTML = original;
|
|
80
72
|
}
|
|
81
73
|
}
|
|
82
74
|
}
|
|
@@ -8,7 +8,7 @@ export function disableContentEditableBeforeSave () {
|
|
|
8
8
|
addDocumentTransform(docElem => {
|
|
9
9
|
docElem.querySelectorAll(SELECTOR).forEach(resource => {
|
|
10
10
|
const originalValue = resource.getAttribute("contenteditable");
|
|
11
|
-
resource.setAttribute("inert-contenteditable", originalValue);
|
|
11
|
+
resource.setAttribute("inert-contenteditable", originalValue === null ? "true" : originalValue);
|
|
12
12
|
resource.removeAttribute("contenteditable");
|
|
13
13
|
});
|
|
14
14
|
});
|
|
@@ -26,17 +26,16 @@ export function enableContentEditableForAdminOnPageLoad () {
|
|
|
26
26
|
// incoming document the same way boot activates the live one.
|
|
27
27
|
export function enableContentEditable(root = document) {
|
|
28
28
|
root.querySelectorAll(SELECTOR).forEach(el => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
el.setAttribute("contenteditable", val);
|
|
29
|
+
const val = el.getAttribute("inert-contenteditable");
|
|
30
|
+
el.setAttribute("contenteditable", ["", "false", "plaintext-only"].includes(val) ? val : "true");
|
|
32
31
|
el.removeAttribute("inert-contenteditable");
|
|
33
32
|
});
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
export function disableContentEditable() {
|
|
37
36
|
document.querySelectorAll(SELECTOR).forEach(el => {
|
|
38
|
-
const val = el.getAttribute("contenteditable")
|
|
39
|
-
el.setAttribute("inert-contenteditable", val);
|
|
37
|
+
const val = el.getAttribute("contenteditable");
|
|
38
|
+
el.setAttribute("inert-contenteditable", val === null ? "true" : val);
|
|
40
39
|
el.removeAttribute("contenteditable");
|
|
41
40
|
});
|
|
42
41
|
}
|
package/src/core/etag.js
CHANGED
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
* - an accepted save replaces it with the one that response carried, and clears
|
|
16
16
|
* it when a response carries none: after our own write, any stamp still held
|
|
17
17
|
* here is known to describe bytes the host has stopped storing,
|
|
18
|
-
* - a disk-sourced live-sync frame
|
|
19
|
-
* the file changed under a tab that never saved.
|
|
18
|
+
* - a disk-sourced live-sync frame replaces it with the stamp that frame
|
|
19
|
+
* carried, because the file changed under a tab that never saved. A frame
|
|
20
|
+
* with no stamp on it falls back to clearing and asking the host.
|
|
20
21
|
*
|
|
21
22
|
* A peer's SNAPSHOT does not move it. §10 relays never write to disk, so the
|
|
22
23
|
* stamp is still true after one lands, and treating one as a disk change would
|
|
@@ -99,8 +100,19 @@ export async function seedEtag({ fresh = false, clearIfMissing = fresh } = {}) {
|
|
|
99
100
|
// A disk-sourced frame is the one live-sync outcome that changes the file under a
|
|
100
101
|
// tab which did not save it. Holding the old stamp would refuse this tab's next
|
|
101
102
|
// save against bytes it has already morphed to and is looking at, so the stamp
|
|
102
|
-
//
|
|
103
|
-
//
|
|
103
|
+
// has to move.
|
|
104
|
+
//
|
|
105
|
+
// The frame's own stamp is the right one, and live-sync has already taken it as
|
|
106
|
+
// part of applying the frame's content. Nothing is left to do here: this listener
|
|
107
|
+
// exists for the frames that carry no stamp.
|
|
108
|
+
//
|
|
109
|
+
// Asking the host is the fallback and not the rule, because discovery answers
|
|
110
|
+
// about whatever is on disk when the ANSWER is built, which is a later moment
|
|
111
|
+
// than the frame. If a second write lands in between, the reply describes bytes
|
|
112
|
+
// this tab has never seen, and adopting it makes the next save overwrite that
|
|
113
|
+
// write silently. The frames without a stamp are an old host, and the fetch
|
|
114
|
+
// fallback for a change too large to send, whose body is the served page rather
|
|
115
|
+
// than anything the host stamped.
|
|
104
116
|
//
|
|
105
117
|
// A frame that live-sync HELD is deliberately not covered, because it never
|
|
106
118
|
// dispatches this event. That tab has unsaved local edits and has not seen the
|
|
@@ -108,6 +120,7 @@ export async function seedEtag({ fresh = false, clearIfMissing = fresh } = {}) {
|
|
|
108
120
|
if (isEditMode) {
|
|
109
121
|
document.addEventListener("clay:sync-applied", (event) => {
|
|
110
122
|
if (event.detail?.source !== "disk") return;
|
|
123
|
+
if (typeof event.detail.etag === "string" && event.detail.etag) return;
|
|
111
124
|
forgetEtag();
|
|
112
125
|
seedEtag({ fresh: true });
|
|
113
126
|
});
|
package/src/core/host-attrs.js
CHANGED
|
@@ -7,7 +7,33 @@
|
|
|
7
7
|
* cannot drift between the edit-mode ladder and the save lane.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { SAVE_TOKEN_ATTRS } from "../lib/root-attrs.js";
|
|
10
|
+
import { SAVE_TOKEN_ATTRS, LEGACY_SAVE_TOKEN_ATTRS } from "../lib/root-attrs.js";
|
|
11
|
+
|
|
12
|
+
let warnedAboutLegacyToken = false;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Say so, once, when this response carries only the pre-rename save token.
|
|
16
|
+
*
|
|
17
|
+
* Dropping the old spelling is a deliberate break (see root-attrs.js), and its failure
|
|
18
|
+
* mode is the kind worth spending five lines on: the host that serves the old name also
|
|
19
|
+
* sets the edit-mode cookie, so the page stays editable and every save 404s. Without
|
|
20
|
+
* this the reader sees a working page that quietly keeps nothing. With it the console
|
|
21
|
+
* names the cause and the fix, which is the whole difference between a break and a bug.
|
|
22
|
+
*/
|
|
23
|
+
function warnAboutLegacyToken() {
|
|
24
|
+
if (warnedAboutLegacyToken) return;
|
|
25
|
+
const carries = LEGACY_SAVE_TOKEN_ATTRS.some(
|
|
26
|
+
(attr) => document.documentElement.getAttribute(attr)
|
|
27
|
+
);
|
|
28
|
+
if (!carries) return;
|
|
29
|
+
warnedAboutLegacyToken = true;
|
|
30
|
+
console.warn(
|
|
31
|
+
"[clay] This page was served with the pre-1.9.0 save token (" +
|
|
32
|
+
LEGACY_SAVE_TOKEN_ATTRS.join(", ") +
|
|
33
|
+
"), which this version no longer accepts. Saving will fail until the host is " +
|
|
34
|
+
"updated. If this is HTML Clay, upgrade it to 1.9.0 or newer."
|
|
35
|
+
);
|
|
36
|
+
}
|
|
11
37
|
|
|
12
38
|
/**
|
|
13
39
|
* The per-document save token this response carries, or null.
|
|
@@ -24,13 +50,37 @@ export function saveToken() {
|
|
|
24
50
|
const value = document.documentElement.getAttribute(attr);
|
|
25
51
|
if (value) return value;
|
|
26
52
|
}
|
|
53
|
+
warnAboutLegacyToken();
|
|
27
54
|
return null;
|
|
28
55
|
}
|
|
29
56
|
|
|
30
57
|
/**
|
|
31
|
-
* True when the host handed this response a save token
|
|
58
|
+
* True when the host handed this response a save token this version accepts.
|
|
59
|
+
*
|
|
60
|
+
* Only `savetoken` counts. A response carrying nothing but the pre-rename spelling is
|
|
61
|
+
* FALSE here and true from `servedStaleToken()`, which is the whole point of the pair.
|
|
62
|
+
*
|
|
32
63
|
* @returns {boolean}
|
|
33
64
|
*/
|
|
34
65
|
export function hasSaveToken() {
|
|
35
66
|
return saveToken() !== null;
|
|
36
67
|
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* True when this response carries ONLY the pre-rename save token.
|
|
71
|
+
*
|
|
72
|
+
* That combination means one thing: the host is older than the rename and cannot be
|
|
73
|
+
* saved to by this version. It is worth its own name because two separate things act
|
|
74
|
+
* on it. Edit mode goes off, so the page does not offer editing it cannot keep, and
|
|
75
|
+
* stale-host-notice.js says why on the page, since the console line reaches a
|
|
76
|
+
* developer and nobody else.
|
|
77
|
+
*
|
|
78
|
+
* @returns {boolean}
|
|
79
|
+
*/
|
|
80
|
+
export function servedStaleToken() {
|
|
81
|
+
if (typeof document === "undefined") return false;
|
|
82
|
+
if (saveToken() !== null) return false;
|
|
83
|
+
return LEGACY_SAVE_TOKEN_ATTRS.some(
|
|
84
|
+
(attr) => document.documentElement.getAttribute(attr)
|
|
85
|
+
);
|
|
86
|
+
}
|
package/src/core/is-edit-mode.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import cookie from "../lib/cookie.js";
|
|
2
2
|
import query from "../lib/query.js";
|
|
3
|
-
import { hasSaveToken } from "./host-attrs.js";
|
|
3
|
+
import { hasSaveToken, servedStaleToken } from "./host-attrs.js";
|
|
4
4
|
|
|
5
5
|
// Edit-mode precedence: an explicit ?editmode=true|false URL param wins, then an
|
|
6
6
|
// opt-in window.clayEditMode global (with the legacy window.__hyperclayEditMode
|
|
7
7
|
// still honored as a fallback for older standalone embedders — htmlclay itself
|
|
8
|
-
// uses
|
|
8
|
+
// uses its injected save token plus the admin cookie, not this global), then
|
|
9
9
|
// a save token the host put on the root, then the isAdminOfCurrentResource cookie. The
|
|
10
10
|
// global is for standalone uses (demos, htmlclay, any self-saving file) that are
|
|
11
11
|
// always editable and have no owner cookie; setting it before clayjs loads turns
|
|
@@ -25,11 +25,20 @@ if (typeof window !== "undefined") {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// A host older than the save-token rename takes edit mode off the table, above every
|
|
29
|
+
// rung below it. Such a host still sets the owner cookie, so without this the page
|
|
30
|
+
// would look fully editable while every save 404s against a route that no longer
|
|
31
|
+
// matches: an editable page that keeps nothing is worse than a read-only one. Only an
|
|
32
|
+
// explicit ?editmode=true outranks it, because that is a person at the keyboard asking
|
|
33
|
+
// for it this load, not a decision baked into the document by an author who could not
|
|
34
|
+
// have known. stale-host-notice.js puts the reason on the page.
|
|
28
35
|
const isEditMode = query.editmode
|
|
29
36
|
? query.editmode === "true" // takes precedence over the global, token and cookie
|
|
30
|
-
:
|
|
31
|
-
?
|
|
32
|
-
:
|
|
37
|
+
: servedStaleToken()
|
|
38
|
+
? false
|
|
39
|
+
: forcedEditMode != null
|
|
40
|
+
? forcedEditMode
|
|
41
|
+
: hasSaveToken() || Boolean(cookie.get("isAdminOfCurrentResource"));
|
|
33
42
|
|
|
34
43
|
const isOwner = Boolean(cookie.get("isAdminOfCurrentResource"));
|
|
35
44
|
|
package/src/core/persist.js
CHANGED
|
@@ -86,18 +86,13 @@ export default function enablePersistentFormInputValues(filterBySelector = PERSI
|
|
|
86
86
|
// programmatically without firing an input event, and resolves textarea
|
|
87
87
|
// data-value into real textContent). Matched by index per selector; another
|
|
88
88
|
// hook mutating the clone could diverge the lists, hence the per-type loops.
|
|
89
|
-
onSnapshot((doc) => {
|
|
89
|
+
onSnapshot((doc, provenance) => {
|
|
90
90
|
const finalize = (selector) => {
|
|
91
|
-
const live = document.querySelectorAll(selector);
|
|
92
91
|
const cloned = doc.querySelectorAll(selector);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
console.warn('[persist] live/clone counts differ for', selector, '— skipping');
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
cloned.forEach((c, i) => finalizeControlForSave(c, live[i]));
|
|
92
|
+
cloned.forEach((control) => {
|
|
93
|
+
const live = provenance.original(control);
|
|
94
|
+
if (live) finalizeControlForSave(control, live);
|
|
95
|
+
});
|
|
101
96
|
};
|
|
102
97
|
finalize(inputSelector);
|
|
103
98
|
finalize(textareaSelector);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isEditMode } from "./is-edit-mode.js";
|
|
2
2
|
import onDomReady from "../lib/dom-ready.js";
|
|
3
|
+
import { style, set, make } from "../lib/hostile-css.js";
|
|
3
4
|
|
|
4
5
|
// The page's only word on a refused save. Without it a document whose host said no
|
|
5
6
|
// looks exactly like one that is saving fine, while autosave sits suspended: the
|
|
@@ -33,31 +34,6 @@ let armTimer = null, armed = false, busy = false;
|
|
|
33
34
|
|
|
34
35
|
const still = () => !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
35
36
|
|
|
36
|
-
// Every declaration goes on as !important, and this is the whole reason the notice
|
|
37
|
-
// survives a stranger's page. A plain inline style loses to an author rule that
|
|
38
|
-
// carries !important, and `button { ... !important }` is a thing real pages do: the
|
|
39
|
-
// first browser run of this module had both controls repainted in the host's colours
|
|
40
|
-
// and font. Only an inline !important outranks an author !important.
|
|
41
|
-
function style(el, rules) {
|
|
42
|
-
for (const rule of rules) {
|
|
43
|
-
const at = rule.indexOf(":");
|
|
44
|
-
el.style.setProperty(rule.slice(0, at).trim(), rule.slice(at + 1).trim(), "important");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Same reason: a later assignment must be able to beat the !important one already
|
|
49
|
-
// sitting on the element, and a plain style.foo = x silently cannot.
|
|
50
|
-
function set(el, prop, value) {
|
|
51
|
-
el.style.setProperty(prop, value, "important");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function make(tag, rules, text) {
|
|
55
|
-
const el = document.createElement(tag);
|
|
56
|
-
style(el, rules);
|
|
57
|
-
if (text) el.textContent = text;
|
|
58
|
-
return el;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
37
|
// all:initial first, because a page restyling every button is the normal case, not
|
|
62
38
|
// the adversarial one. Everything the control needs is restated after it.
|
|
63
39
|
function button(label, rules) {
|
|
@@ -171,8 +147,27 @@ function onKeydown(e) {
|
|
|
171
147
|
function show(e) {
|
|
172
148
|
if (!root) build();
|
|
173
149
|
set(root, "display", "flex");
|
|
174
|
-
const
|
|
175
|
-
|
|
150
|
+
const named = SOURCES[e?.detail?.changedBy];
|
|
151
|
+
// Reassurance first, then the fact. What a person needs to know at this moment
|
|
152
|
+
// is that nothing of theirs is gone and nothing is about to be overwritten; the
|
|
153
|
+
// detail of what happened is the second half of the sentence, not the first.
|
|
154
|
+
// "Saving is paused" led here once and read as a failure, which it is not: the
|
|
155
|
+
// page is holding a version, and the two buttons below are the whole decision.
|
|
156
|
+
//
|
|
157
|
+
// An earlier save of this tab's timed out and the host could not say what became
|
|
158
|
+
// of it, so this refusal may be answering that write rather than anybody else's.
|
|
159
|
+
// Saying so is the whole reason the stamp is kept across a timeout instead of
|
|
160
|
+
// quietly reconciled. A host that NAMED the writer, or that answered the question
|
|
161
|
+
// with a receipt, knows better than this guess, so the name wins.
|
|
162
|
+
if (!named && e?.detail?.afterTimeout) {
|
|
163
|
+
line.textContent =
|
|
164
|
+
"This page changed elsewhere, possibly by your own save that timed out. " +
|
|
165
|
+
"Your edits here are safe, and nothing will be overwritten until you choose.";
|
|
166
|
+
} else {
|
|
167
|
+
line.textContent =
|
|
168
|
+
`This page changed ${named || "elsewhere"}. ` +
|
|
169
|
+
"Your edits here are safe, and nothing will be overwritten until you choose.";
|
|
170
|
+
}
|
|
176
171
|
keep.textContent = "Keep mine";
|
|
177
172
|
set(keep, "opacity", "1");
|
|
178
173
|
busy = false;
|