@panphora/clayjs 0.2.1 → 0.4.1
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 +103 -7
- package/clay-data.js +1 -1
- package/clay-internals.js +19 -0
- package/clay.js +19 -3
- package/package.json +5 -2
- package/sap.js +5 -5
- package/src/attrs/onaftersave.js +12 -1
- package/src/attrs/refetch-on-save.js +4 -4
- package/src/attrs/save-freeze.js +47 -19
- package/src/core/admin-contenteditable.js +2 -2
- package/src/core/admin-inputs.js +2 -2
- package/src/core/admin-onclick.js +2 -2
- package/src/core/admin-resources.js +23 -14
- package/src/core/autosave.js +11 -1
- package/src/core/edit-mode.js +2 -2
- package/src/core/host-attrs.js +46 -0
- package/src/core/is-edit-mode.js +14 -6
- package/src/core/persist.js +12 -2
- package/src/core/save-core.js +199 -290
- package/src/core/save.js +121 -82
- package/src/core/snapshot.js +89 -36
- package/src/core/unsaved-warning.js +8 -2
- package/src/dom/all.js +4 -29
- package/src/dom/form-data.js +1 -1
- package/src/dom/nearest.js +11 -9
- package/src/internals/index.js +69 -0
- package/src/lib/cache-bust.js +10 -0
- package/src/lib/cookie.js +50 -15
- package/src/lib/extension-noise.js +5 -1
- package/src/lib/mutation.js +65 -18
- package/src/lib/region-policy.js +17 -2
- package/src/lib/root-attrs.js +45 -0
- package/src/lib/throttle.js +25 -13
- package/src/loader.js +18 -24
- package/src/options/options.js +1 -3
- package/src/plugins/demo.js +7 -1
- package/src/plugins/undo.js +3 -3
- package/src/sync/live-sync.js +77 -76
- package/src/ui/dialogs.js +10 -1
- package/src/ui/index.js +0 -10
- package/src/utils/debounce.js +24 -7
- package/src/vendor/control-serialize.vendor.js +2 -1
- package/src/vendor/hyper-undo.vendor.js +1 -1
- package/src/vendor/hypercms.vendor.js +29 -16
- package/src/vendor/richclay.vendor.js +29 -22
package/README.md
CHANGED
|
@@ -21,7 +21,24 @@ query params on the script URL:
|
|
|
21
21
|
|
|
22
22
|
- `?plugins=` — add optional plugins: `sync`, `cms` (richclay, indicator, sortable, undo load by default in edit mode).
|
|
23
23
|
- `?exclude=` — drop a default plugin.
|
|
24
|
-
- `?editmode=false` — force view mode (URL param wins over
|
|
24
|
+
- `?editmode=false` — force view mode (URL param wins over everything below).
|
|
25
|
+
|
|
26
|
+
## Host attributes
|
|
27
|
+
|
|
28
|
+
A host can put these on `<html>` in the response it serves. They are ephemeral:
|
|
29
|
+
the host injects them and strips them back out of whatever gets saved, so they
|
|
30
|
+
never reach the file on disk.
|
|
31
|
+
|
|
32
|
+
- `savetoken="…"` — the per-document save credential. clayjs posts to
|
|
33
|
+
`/_/save/{token}` and sends no cookies, because the token is the credential.
|
|
34
|
+
A token also implies edit mode, which is the only such signal a sandboxed
|
|
35
|
+
document can see. `htmlclaytoken` is the older spelling of the same thing.
|
|
36
|
+
- `clay-save-transport="desktop-json-v1"` — send the save as
|
|
37
|
+
`{content, snapshotHtml, userDriven}` JSON instead of plain text. Only declare
|
|
38
|
+
it on a host whose save lane reads that envelope.
|
|
39
|
+
|
|
40
|
+
Edit mode is decided in this order: the `?editmode` param, then
|
|
41
|
+
`window.clayEditMode`, then a save token, then the platform's owner cookie.
|
|
25
42
|
|
|
26
43
|
## Readiness
|
|
27
44
|
|
|
@@ -33,11 +50,64 @@ await clay.ready; // or: document.addEventListener("clay:ready", ...)
|
|
|
33
50
|
clay.save();
|
|
34
51
|
```
|
|
35
52
|
|
|
36
|
-
Edit mode exposes `clay.save()` (+ `clay.save.force()`), `clay.getHTML()`, `clay.
|
|
53
|
+
Edit mode exposes `clay.save()` (+ `clay.save.force()`), `clay.getHTML()`, `clay.addDocumentTransform(fn)`,
|
|
37
54
|
`clay.onSnapshot(fn)`, `clay.toggleEditMode()`, `clay.isEditMode`, `clay.isOwner`, `clay.Mutation`,
|
|
38
|
-
`clay.cacheBust(el)`, plus `clay.undo` / `clay.cms` / `clay.morph`
|
|
39
|
-
mode keeps only the always-available members (`toggleEditMode`, `isEditMode`, `isOwner`,
|
|
40
|
-
`Mutation`, `ready`); edit-only members are simply absent.
|
|
55
|
+
`clay.region`, `clay.cacheBust(el)`, plus `clay.undo` / `clay.cms` / `clay.morph` / `clay.RichClay`
|
|
56
|
+
when those plugins load. View mode keeps only the always-available members (`toggleEditMode`, `isEditMode`, `isOwner`,
|
|
57
|
+
`Mutation`, `region`, `ready`); edit-only members are simply absent.
|
|
58
|
+
|
|
59
|
+
## API
|
|
60
|
+
|
|
61
|
+
Three tiers. The first two are a promise; the third is not.
|
|
62
|
+
|
|
63
|
+
| Tier | What it is | Promise |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `clay.*` from `clay.js` | the everyday surface | stable |
|
|
66
|
+
| `clay.*` from a satellite (`clay-ui`, `clay-utils`, `clay-dom`, `clay-events`, `clay-options`, `clay-internals`) | opt-in, one script tag each | stable |
|
|
67
|
+
| anything else under `src/` | reachable by direct import, because `src/` ships | **may change in any release** |
|
|
68
|
+
|
|
69
|
+
The contract starts at **0.3.0**: no name below changes without a major version.
|
|
70
|
+
|
|
71
|
+
**`clay.js`** — `ready`, `save()`, `save.force()`, `getHTML()`, `addDocumentTransform(fn)`, `onSnapshot(fn)`,
|
|
72
|
+
`toggleEditMode()`, `isEditMode`, `isOwner`, `Mutation`, `region`, `cacheBust(el)`, plus `undo` / `cms` / `morph` /
|
|
73
|
+
`RichClay` when those plugins load. View mode keeps only the always-available members, as above.
|
|
74
|
+
|
|
75
|
+
`addDocumentTransform(fn)` runs your callback over a detached clone whenever the page
|
|
76
|
+
prepares to save AND whenever it checks whether anything changed. Keep it pure and
|
|
77
|
+
repeatable: it is a transform, not a "a save is happening" event.
|
|
78
|
+
|
|
79
|
+
`region` is the region-policy model: `resolveRegionPolicy`, `isInert`, `skipForPolicy`,
|
|
80
|
+
`strictestPolicy`, the `PERSIST` and `REGION_ATTRS` token constants, and the
|
|
81
|
+
`STRIP_FROM_SAVE`, `FREEZE_SELECTOR` and `STRIP_FROM_COMPARISON` selectors.
|
|
82
|
+
`clay.internals.region` is a different shape, narrower in aim, built for snapshot work.
|
|
83
|
+
|
|
84
|
+
**Satellites** — one script tag each, and each resolves its own `clay.loaded.*` promise. `clay-ui` adds
|
|
85
|
+
`toast`, `toastPersistent`, `ask`, `confirm`, `tell`, `snippet`, `modal`; `clay-utils` adds `clay.utils`
|
|
86
|
+
(`throttle`, `debounce`, `cookie`, `slugify`, `copyToClipboard`); `clay-internals` adds `clay.internals`,
|
|
87
|
+
below. `clay-events`, `clay-dom`, `clay-options` and `all.js` add HTML attributes and DOM helpers rather
|
|
88
|
+
than members on `clay`.
|
|
89
|
+
|
|
90
|
+
**`clay.internals`** — the pieces the library builds itself out of, for code that needs to sit inside the
|
|
91
|
+
save lifecycle rather than call it. Lower level than `clay.*` deliberately: it assumes you know the
|
|
92
|
+
lifecycle.
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<script src="https://clayjs.com/clay-internals.js"></script>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- `captureSnapshot()`, `captureForSave()` — the snapshot pipeline, read side.
|
|
99
|
+
`captureSnapshot` gives you the clone before any stripping; `captureForSave` gives you the
|
|
100
|
+
bytes a save would send.
|
|
101
|
+
- `addDocumentTransform(fn)` — the same registry as `clay.addDocumentTransform`. Core only
|
|
102
|
+
publishes that name in edit mode, so reach for this one from a view-mode page or from the
|
|
103
|
+
satellite with no core loaded.
|
|
104
|
+
- `region.addRegionToken(el, token)`, `region.resolveRegionPolicy(node)`, `region.isInert(node)`,
|
|
105
|
+
`region.isSnapshotRemoved(el)`, `region.PERSIST`, `region.REGION_ATTRS`, and
|
|
106
|
+
`region.selectors.stripFromSave` / `.stripFromComparison` / `.snapshotRemove` / `.freeze` — write your
|
|
107
|
+
own attribute without hardcoding our selectors.
|
|
108
|
+
- `save.saveHtml(html, cb, opts)`, `save.replacePageWith(url, cb)`, `save.isSaveInProgress()` — the save
|
|
109
|
+
lane under `clay.save`. **`saveHtml` writes the bytes you hand it straight to the file**, bypassing the
|
|
110
|
+
snapshot pipeline entirely; check `isSaveInProgress()` first.
|
|
41
111
|
|
|
42
112
|
## Regions
|
|
43
113
|
|
|
@@ -54,6 +124,32 @@ Add `autosave` to `<html>` to save automatically on change.
|
|
|
54
124
|
## Develop
|
|
55
125
|
|
|
56
126
|
```bash
|
|
57
|
-
npm test
|
|
58
|
-
npm run
|
|
127
|
+
npm test # jest unit suite
|
|
128
|
+
npm run test:conformance # byte-for-byte fixture gate, in a real browser
|
|
129
|
+
npm run dev # stub save server on :4601 for the tests/fixtures pages
|
|
59
130
|
```
|
|
131
|
+
|
|
132
|
+
## Deploy
|
|
133
|
+
|
|
134
|
+
`public/` is what wrangler serves to clayjs.com. It is a build output: gitignored,
|
|
135
|
+
disposable, and rebuilt from scratch every time.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm run build # rebuild public/ from source
|
|
139
|
+
npm run deploy # rebuild, then wrangler deploy
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Never edit `public/` by hand, and never copy a file into it. Its contents are
|
|
143
|
+
**derived**:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
public/ = package.json "files" (minus NOTICE, which nothing requests)
|
|
147
|
+
+ website/* (flattened to the root, so /docs.html works)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
That derivation is the point. `files` is the list npm publishes, so it is already
|
|
151
|
+
the line you edit to ship a new satellite, and deriving from it means a file cannot
|
|
152
|
+
reach npm and miss the site. Before this script existed the mirror was hand-copied,
|
|
153
|
+
and it drifted exactly that way: `src/core/host-attrs.js` never made it across, and
|
|
154
|
+
since `loader.js` imports `is-edit-mode.js`, which imports it, the deployed
|
|
155
|
+
`clay.js` could not boot at all.
|
package/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 k=Object.defineProperty;var lt=Object.getOwnPropertyDescriptor;var ct=Object.getOwnPropertyNames;var ft=Object.prototype.hasOwnProperty;var K=(t,e)=>{for(var n in e)k(t,n,{get:e[n],enumerable:!0})},ut=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of ct(e))!ft.call(t,r)&&r!==n&&k(t,r,{get:()=>e[r],enumerable:!(o=lt(e,r))||o.enumerable});return t};var at=t=>ut(k({},"__esModule",{value:!0}),t);var wt={};K(wt,{applyData:()=>X,default:()=>It,engine:()=>P,extractData:()=>G});var C=["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"],B=new Set(C),Y=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),Q=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var j={};K(j,{EmptyListInsert:()=>I,MAX_RULE_DEPTH:()=>A,MaxRuleDepthExceeded:()=>E,RuleTargetReadOnly:()=>w,RulesParseError:()=>S,ShapeMismatch:()=>b,UnknownRulesVersion:()=>N});var S=class extends Error{constructor(e,n){super(e),this.name="RulesParseError",this.cause=n}},N=class extends Error{constructor(e){super(`unknown rules version: ${e}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=e}},A=20,E=class extends Error{constructor(e){super(`rule depth exceeded ${A} at path: ${e.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=e}},b=class extends Error{constructor(e){super(`shape mismatch: ${e.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=e}},I=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}},w=class extends Error{constructor(e){super(`cannot write to read-only DOM property "${e}"`),this.name="RuleTargetReadOnly",this.target=e}};function g(t,e,n,o={}){return U(t,e,n,{depth:0,path:[]},o)}function U(t,e,n,o,r){if(o.depth>A)throw new E(o.path);if(typeof n=="string")return ht(t,e,n,r);if(Array.isArray(n)){let[i,c]=n;return t.find(e,i,r).map((l,a)=>U(t,l,c,{depth:o.depth+1,path:[...o.path,a]},r))}if(typeof n=="object"&&n!==null){let i={};for(let[c,s]of Object.entries(n))i[c]=U(t,e,s,{depth:o.depth+1,path:[...o.path,c]},r);return i}return null}function ht(t,e,n,o){if(n.endsWith("[]")){let i=n.slice(0,-2);return t.find(e,i,o).map(c=>t.text(c))}if(n.startsWith("@"))return Z(t,e,n.slice(1));if(n.includes("@")){let i=n.lastIndexOf("@"),c=n.slice(0,i),s=n.slice(i+1),l=c?t.find(e,c,o):[e];return l.length===0?null:Z(t,l[0],s)}if(n===".")return t.text(e);let r=t.find(e,n,o);return r.length===0?null:t.text(r[0])}function Z(t,e,n){if(B.has(n)){let r=t.prop(e,n);return r==null?null:String(r)}let o=t.attr(e,n);return o||null}var dt=.5;function q(t,e,n,o,r,i,c,s={}){let l=t.find(e,n,s);if(r.length===0){l.forEach(h=>t.remove(h));return}let a=r.length>l.length,u=l[0]||null;if(a&&!u&&(u=Et(t,e,n,s),!u))throw new I(i.path);let d=l.map(h=>pt(t,h,o,s)),f=null;if(u){f=t.clone(u),s.templateAttr&&t.removeAttr(f,s.templateAttr);let h=t.stripIds(f);h>0&&console.warn(`[hyper-html-api] stripped ${h} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let H=mt(r,d,o),R=l[0]||u,L=t.parent(R),it=l.length>0?gt(t,L,R):0,z=new Set,W=r.map((h,m)=>{let p=H[m];if(p>=0)return z.add(p),l[p];let O=t.clone(f);return t.stripIds(O),O});l.forEach((h,m)=>{z.has(m)||t.remove(h)}),W.forEach((h,m)=>{let p=it+m;t.children(L).findIndex(st=>t.sameNode(st,h))!==p&&t.insertAt(L,h,p)}),W.forEach((h,m)=>{if(o===null){let p=r[m],O=p==null?"":String(p);t.text(h)!==O&&t.text(h,O)}else{let p=c(t,h,o,r[m],{depth:i.depth+1,path:[...i.path,m]},s);p&&p!==h&&(W[m]=p)}})}function pt(t,e,n,o){return n===null?t.text(e):g(t,e,n,o)}function mt(t,e,n){let o=new Array(t.length).fill(-1),r=new Set;return t.forEach((i,c)=>{let s=-1,l=-1;e.forEach((a,u)=>{if(r.has(u))return;let d=yt(i,a,n),f=d===l&&s>=0?Math.abs(u-c)<Math.abs(s-c):!1;(d>l||f)&&(l=d,s=u)}),l>=dt&&(o[c]=s,r.add(s))}),o}function yt(t,e,n){if(n===null)return t===e?1:0;let o=Object.keys(n||{});if(o.length===0)return 0;let r=0;for(let i of o)JSON.stringify(t?.[i])===JSON.stringify(e?.[i])&&r++;return r/o.length}function gt(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 Et(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 c of i)if(t.attr(c,o.templateAttr)!=null)return c;r=t.parent(r)}return null}var tt=new Set(["checked","selected","disabled","readOnly","paused"]);function T(t,e,n,o,r={}){let i=[];if(v(n,o,[],i),i.length)throw new b(i);$(t,e,n,o,{depth:0,path:[]},r)}function $(t,e,n,o,r,i={}){if(r.depth>A)throw new E(r.path);if(o===void 0)return e;if(typeof n=="string")return Rt(t,e,n,o,r,i);if(Array.isArray(n)){let[c,s]=n;return q(t,e,c,s,o,r,$,i),e}if(typeof n=="object"&&n!==null){for(let[c,s]of Object.entries(n)){let l=$(t,e,s,o==null?o:o[c],{depth:r.depth+1,path:[...r.path,c]},i);l&&l!==e&&(e=l)}return e}return e}function Rt(t,e,n,o,r,i){if(n.endsWith("[]")){let s=n.slice(0,-2);return q(t,e,s,null,o,r,$,i),e}if(n.startsWith("@"))return et(t,e,n.slice(1),o);if(n.includes("@")){let s=n.lastIndexOf("@"),l=n.slice(0,s),a=n.slice(s+1),u=l?t.find(e,l,i):[e];return u.length===0||et(t,u[0],a,o),e}if(n===".")return t.text(e,o==null?"":String(o)),e;let c=t.find(e,n,i);return c.length===0||t.text(c[0],o==null?"":String(o)),e}function et(t,e,n,o){if(Q.has(n))throw new w(n);if(n==="outerHTML"){let r=o==null?"":String(o);return t.replaceWith(e,r)}return Y.has(n)?(t.prop(e,n,Ot(n,o)),e):(t.attr(e,n,o==null?"":String(o)),e)}function Ot(t,e){return e==null?tt.has(t)?!1:"":tt.has(t)?!!e:e}function v(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:_([...n,i]),expected:"scalar",got:M(r)})}):o.push({path:_(n),expected:"array",got:M(e)});return}e!==null&&typeof e=="object"&&o.push({path:_(n),expected:"scalar",got:M(e)});return}if(Array.isArray(t)){if(!Array.isArray(e)){o.push({path:_(n),expected:"array",got:M(e)});return}let r=t[1];e.forEach((i,c)=>v(r,i,[...n,c],o));return}if(typeof t=="object"&&t!==null){if(e===null||Array.isArray(e)||typeof e!="object"){o.push({path:_(n),expected:"object",got:M(e)});return}for(let[r,i]of Object.entries(t))v(i,e[r],[...n,r],o)}}}function M(t){return t===null?"null":Array.isArray(t)?"array":typeof t}function _(t){return t.join(".")}function J(t){try{return JSON.parse(t)}catch(e){throw new S(`Invalid strict JSON: ${e.message}`,e)}}function D(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=[],c=0;for(;c<r.length;){let s=r[c];if(/\s/.test(s)){c++;continue}if("{}".includes(s)){i.push({type:s,value:s}),c++;continue}if(s==="["){let d=!1,f=c+1;for(;f<r.length&&/\s/.test(r[f]);)f++;if(f<r.length&&/[a-zA-Z_]/.test(r[f])&&(d=!0),!d){i.push({type:s,value:s}),c++;continue}}if(s==="]"){i.push({type:s,value:s}),c++;continue}if(s===":"){i.push({type:e.COLON,value:s}),c++;continue}if(s===","){i.push({type:e.COMMA,value:s}),c++;continue}if(s==='"'||s==="'"){let d=s,f=c+1;for(;f<r.length&&r[f]!==d;)r[f]==="\\"&&f++,f++;i.push({type:e.STRING,value:r.substring(c+1,f),quoted:!0,sourceQuote:d}),c=f+1;continue}let l=c,a;for(;l<r.length&&!/[{},]/.test(r[l]);)if(r[l]===":"){let d=[":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"],f=!1;for(let H of d){let R=H.substring(1);if(r.substring(l+1,l+1+R.length)===R){f=!0,l+=R.length;break}}if(!f)break}else if(r[l]==="["){for(l++;l<r.length&&r[l]!=="]";){if(r[l]==='"'||r[l]==="'"){let d=r[l];for(l++;l<r.length&&r[l]!==d;)r[l]==="\\"&&l++,l++}l++}l<r.length&&r[l]==="]"&&l++}else l++;a=r.substring(c,l);let u=e.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(a)?u=e.NUMBER:a==="true"||a==="false"||a==="null"?u=e.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(a)&&(u=e.SELECTOR),i.push({type:u,value:a,quoted:!1}),c=l}return i}function o(r){let i="";for(let c=0;c<r.length;c++){let s=r[c];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[c+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,(a,u)=>u.length%2===0?u+'\\"':a)),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 S("Invalid extraction rules syntax: "+r.message,r)}}var St="1",nt=/^[a-zA-Z0-9_-]+$/;function x(t,e,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!nt.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${nt})`);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],c=t.attr(i,"data-rules-version");if(c!==St)throw new N(c);return{rules:D(t.text(i)),tagNode:i}}function V(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 x(t,o,n)}return null}function rt(t,e,n,o){let r=V(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:c}=r;return{rules:i,tagNode:c,get:()=>g(t,e,i,o),set:s=>T(t,e,i,s,o)}}function Tt(t){return t&&t.nodeType===1&&t.tagName==="SCRIPT"&&t.hasAttribute&&t.hasAttribute("data-rules-name")}function xt(t){return t?(t.nodeType===9||t.nodeType===11,t):null}var Nt={find(t,e,n={}){let o=xt(t);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(e));n.includeRulesTag||(r=r.filter(s=>!Tt(s)));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 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}},y=Nt;var P={extract:(t,e,n)=>g(y,t,e,n),apply:(t,e,n,o)=>T(y,t,e,n,o),findRulesIn:(t,e)=>x(y,t,e),findRules:(t,e)=>V(y,t,e),bind:(t,e,n)=>rt(y,t,e,n),parseStrict:J,parseRelaxed:D,errors:j,DOM_PROPERTIES:C},F=t=>!!t&&typeof t.nodeType=="number";function ot(t){let e=t&&t.ownerDocument?t.ownerDocument:t,n=y.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 x(y,e).rules}function G(t,e){let n=F(t)?t:document,o=F(t)?e:t;return o===void 0?g(y,n,ot(n)):P.bind(n,o).get()}function X(t,e,n){if(!F(t))throw new Error("hyper-html-api: applyData(root, data, source?) needs a DOM root as the first argument.");return n===void 0?T(y,t,ot(t),e):P.bind(t,n).set(e),t}var bt={engine:P,extractData:G,applyData:X},It=bt;return at(wt);})();
|
|
5
|
+
var hyperHtmlApiData=(()=>{var U=Object.defineProperty;var pt=Object.getOwnPropertyDescriptor;var dt=Object.getOwnPropertyNames;var mt=Object.prototype.hasOwnProperty;var tt=(t,e)=>{for(var n in e)U(t,n,{get:e[n],enumerable:!0})},gt=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of dt(e))!mt.call(t,r)&&r!==n&&U(t,r,{get:()=>e[r],enumerable:!(o=pt(e,r))||o.enumerable});return t};var yt=t=>gt(U({},"__esModule",{value:!0}),t);var jt={};tt(jt,{applyData:()=>Y,default:()=>Ct,engine:()=>L,extractData:()=>K});var j=["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"],q=new Set(j),et=new Set(["textContent","innerText","innerHTML","value","checked","selected","disabled","readOnly","type","id","className","title"]),nt=new Set(["tagName","nodeName","nodeType","nodeValue","childElementCount","classList","baseURI","documentURI","contentType","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","currentSrc","duration","paused","dataset"]);var $={};tt($,{EmptyListInsert:()=>w,MAX_RULE_DEPTH:()=>O,MaxRuleDepthExceeded:()=>y,RuleTargetReadOnly:()=>M,RulesParseError:()=>A,ShapeMismatch:()=>N,UnknownRulesVersion:()=>b});var A=class extends Error{constructor(e,n){super(e),this.name="RulesParseError",this.cause=n}},b=class extends Error{constructor(e){super(`unknown rules version: ${e}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=e}},O=20,y=class extends Error{constructor(e){super(`rule depth exceeded ${O} at path: ${e.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=e}},N=class extends Error{constructor(e){super(`shape mismatch: ${e.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=e}},w=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}},M=class extends Error{constructor(e){super(`cannot write to read-only DOM property "${e}"`),this.name="RuleTargetReadOnly",this.target=e}};function m(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 v(t){let e=m(t);return e===-1?{selector:t,prop:null}:{selector:t.slice(0,e),prop:t.slice(e+1)||null}}function g(t,e,n,o={}){return J(t,e,n,{depth:0,path:[]},o)}function J(t,e,n,o,r){if(o.depth>O)throw new y(o.path);if(typeof n=="string")return Et(t,e,n,r);if(Array.isArray(n)){let[i,c]=n;return t.find(e,i,r).map((l,f)=>J(t,l,c,{depth:o.depth+1,path:[...o.path,f]},r))}if(typeof n=="object"&&n!==null){let i={};for(let[c,s]of Object.entries(n))i[c]=J(t,e,s,{depth:o.depth+1,path:[...o.path,c]},r);return i}return null}function Et(t,e,n,o){if(n.endsWith("[]")){let c=n.slice(0,-2);return t.find(e,c,o).map(s=>t.text(s))}if(n.startsWith("@"))return rt(t,e,n.slice(1));let r=m(n);if(r!==-1){let c=n.slice(0,r),s=n.slice(r+1),l=c?t.find(e,c,o):[e];return l.length===0?null:rt(t,l[0],s)}if(n===".")return t.text(e);let i=t.find(e,n,o);return i.length===0?null:t.text(i[0])}function rt(t,e,n){if(q.has(n)){let r=t.prop(e,n);return r==null?null:String(r)}let o=t.attr(e,n);return o||null}var Rt=.5;function F(t,e,n,o,r,i,c,s={}){let l=t.find(e,n,s);if(r.length===0){l.forEach(p=>t.remove(p));return}let f=r.length>l.length,u=l[0]||null;if(f&&!u&&(u=xt(t,e,n,s),!u))throw new w(i.path);let a=l.map(p=>At(t,p,o,s)),h=null;if(u){h=t.clone(u),s.templateAttr&&t.removeAttr(h,s.templateAttr);let p=t.stripIds(h);p>0&&console.warn(`[hyper-html-api] stripped ${p} id attribute(s) from cloned template at "${i.path.join(".")||"(root)"}"`)}let k=Ot(r,a,o),E=l[0]||u,T=t.parent(E),Q=l.length>0?it(t,T,E):0,ht=Tt(t,l),Z=new Set,W=[],C=r.map((p,I)=>{let R=k[I];if(R>=0)return Z.add(R),W.push(!1),l[R];W.push(!0);let B=t.clone(h);return t.stripIds(B),B});if(l.forEach((p,I)=>{Z.has(I)||t.remove(p)}),ht){C.forEach((p,I)=>{let R=Q+I;t.children(T).findIndex(at=>t.sameNode(at,p))!==R&&t.insertAt(T,p,R)}),ot(t,C,o,r,i,c,s);return}It(t,C,W,T,Q),ot(t,C,o,r,i,c,s)}function ot(t,e,n,o,r,i,c){e.forEach((s,l)=>{if(n===null){let f=o[l],u=f==null?"":String(f);t.text(s)!==u&&t.text(s,u)}else{let f=i(t,s,n,o[l],{depth:r.depth+1,path:[...r.path,l]},c);f&&f!==s&&(e[l]=f)}})}function At(t,e,n,o){return n===null?t.text(e):g(t,e,n,o)}function Ot(t,e,n){let o=new Array(t.length).fill(-1),r=new Set;return t.forEach((i,c)=>{let s=-1,l=-1;e.forEach((f,u)=>{if(r.has(u))return;let a=St(i,f,n),h=a===l&&s>=0?Math.abs(u-c)<Math.abs(s-c):!1;(a>l||h)&&(l=a,s=u)}),l>=Rt&&(o[c]=s,r.add(s))}),o}function St(t,e,n){if(n===null)return t===e?1:0;let o=Object.keys(n||{});if(o.length===0)return 0;let r=0;for(let i of o)JSON.stringify(t?.[i])===JSON.stringify(e?.[i])&&r++;return r/o.length}function it(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 xt(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 c of i)if(t.attr(c,o.templateAttr)!=null)return c;r=t.parent(r)}return null}function Tt(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 c=o.findIndex(s=>t.sameNode(s,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 It(t,e,n,o,r){let i=null,c=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 f=i?it(t,l,i)+1:c++;t.insertAt(l,e[s],f),i=e[s]}}var st=new Set(["checked","selected","disabled","readOnly","paused"]);function S(t,e,n,o,r={}){let i=[];if(V(n,o,[],i),i.length)throw new N(i);H(t,e,n,o,{depth:0,path:[]},r)}function H(t,e,n,o,r,i={}){if(r.depth>O)throw new y(r.path);if(o===void 0)return e;if(typeof n=="string")return bt(t,e,n,o,r,i);if(Array.isArray(n)){let[c,s]=n;return F(t,e,c,s,o,r,H,i),e}if(typeof n=="object"&&n!==null){for(let[c,s]of Object.entries(n)){let l=H(t,e,s,o==null?o:o[c],{depth:r.depth+1,path:[...r.path,c]},i);l&&l!==e&&(e=l)}return e}return e}function bt(t,e,n,o,r,i){if(n.endsWith("[]")){let l=n.slice(0,-2);return F(t,e,l,null,o,r,H,i),e}if(n.startsWith("@"))return lt(t,e,n.slice(1),o);let c=m(n);if(c!==-1){let l=n.slice(0,c),f=n.slice(c+1),u=l?t.find(e,l,i):[e];return u.length===0||lt(t,u[0],f,o),e}if(n===".")return t.text(e,o==null?"":String(o)),e;let s=t.find(e,n,i);return s.length===0||t.text(s[0],o==null?"":String(o)),e}function lt(t,e,n,o){if(nt.has(n))throw new M(n);if(n==="outerHTML"){let r=o==null?"":String(o);return t.replaceWith(e,r)}return et.has(n)?(t.prop(e,n,Nt(n,o)),e):(t.attr(e,n,o==null?"":String(o)),e)}function Nt(t,e){return e==null?st.has(t)?!1:"":st.has(t)?!!e:e}function V(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:D([...n,i]),expected:"scalar",got:_(r)})}):o.push({path:D(n),expected:"array",got:_(e)});return}e!==null&&typeof e=="object"&&o.push({path:D(n),expected:"scalar",got:_(e)});return}if(Array.isArray(t)){if(!Array.isArray(e)){o.push({path:D(n),expected:"array",got:_(e)});return}let r=t[1];e.forEach((i,c)=>V(r,i,[...n,c],o));return}if(typeof t=="object"&&t!==null){if(e===null||Array.isArray(e)||typeof e!="object"){o.push({path:D(n),expected:"object",got:_(e)});return}for(let[r,i]of Object.entries(t))V(i,e[r],[...n,r],o)}}}function _(t){return t===null?"null":Array.isArray(t)?"array":typeof t}function D(t){return t.join(".")}function G(t){try{return JSON.parse(t)}catch(e){throw new A(`Invalid strict JSON: ${e.message}`,e)}}function P(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=[],c=0;for(;c<r.length;){let s=r[c];if(/\s/.test(s)){c++;continue}if("{}".includes(s)){i.push({type:s,value:s}),c++;continue}if(s==="["){let a=!1,h=c+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}),c++;continue}}if(s==="]"){i.push({type:s,value:s}),c++;continue}if(s===":"){i.push({type:e.COLON,value:s}),c++;continue}if(s===","){i.push({type:e.COMMA,value:s}),c++;continue}if(s==='"'||s==="'"){let a=s,h=c+1;for(;h<r.length&&r[h]!==a;)r[h]==="\\"&&h++,h++;i.push({type:e.STRING,value:r.substring(c+1,h),quoted:!0,sourceQuote:a}),c=h+1;continue}let l=c,f;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 k of a){let E=k.substring(1);if(r.substring(l+1,l+1+E.length)===E){h=!0,l+=E.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++;f=r.substring(c,l);let u=e.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(f)?u=e.NUMBER:f==="true"||f==="false"||f==="null"?u=e.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(f)&&(u=e.SELECTOR),i.push({type:u,value:f,quoted:!1}),c=l}return i}function o(r){let i="";for(let c=0;c<r.length;c++){let s=r[c];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[c+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,(f,u)=>u.length%2===0?u+'\\"':f)),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 A("Invalid extraction rules syntax: "+r.message,r)}}var wt="1",ct=/^[a-zA-Z0-9_-]+$/;function x(t,e,n){let o;if(n===void 0)o="script[data-rules-name]";else{if(typeof n!="string"||!ct.test(n))throw new Error(`hyper-html-api: invalid rules token ${JSON.stringify(n)} (must match ${ct})`);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],c=t.attr(i,"data-rules-version");if(c!==wt)throw new b(c);return{rules:P(t.text(i)),tagNode:i}}function X(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 x(t,o,n)}return null}function ft(t,e,n,o){let r=X(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:c}=r;return{rules:i,tagNode:c,get:()=>g(t,e,i,o),set:s=>S(t,e,i,s,o)}}function _t(t){return t&&t.nodeType===1&&t.tagName==="SCRIPT"&&t.hasAttribute&&t.hasAttribute("data-rules-name")}function Dt(t){return t?(t.nodeType===9||t.nodeType===11,t):null}var Pt={find(t,e,n={}){let o=Dt(t);if(!o||!o.querySelectorAll)return[];let r=Array.from(o.querySelectorAll(e));n.includeRulesTag||(r=r.filter(s=>!_t(s)));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 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}},d=Pt;var L={extract:(t,e,n)=>g(d,t,e,n),apply:(t,e,n,o)=>S(d,t,e,n,o),findRulesIn:(t,e)=>x(d,t,e),findRules:(t,e)=>X(d,t,e),bind:(t,e,n)=>ft(d,t,e,n),parseStrict:G,parseRelaxed:P,ruleAttrIndex:m,splitRule:v,errors:$,DOM_PROPERTIES:j},z=t=>!!t&&typeof t.nodeType=="number";function ut(t){let e=t&&t.ownerDocument?t.ownerDocument:t,n=d.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 x(d,e).rules}function K(t,e){let n=z(t)?t:document,o=z(t)?e:t;return o===void 0?g(d,n,ut(n)):L.bind(n,o).get()}function Y(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?S(d,t,ut(t),e):L.bind(t,n).set(e),t}var Lt={engine:L,extractData:K,applyData:Y},Ct=Lt;return yt(jt);})();
|
|
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
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* clay-internals.js — clayjs satellite: clay.internals = the supported low-level surface (snapshot, region policy, save lane). https://clayjs.com */
|
|
2
|
+
(function () {
|
|
3
|
+
var clay = window.clay = window.clay || {};
|
|
4
|
+
clay.loaded = clay.loaded || {};
|
|
5
|
+
|
|
6
|
+
var script = document.currentScript;
|
|
7
|
+
if (!script || !script.src) {
|
|
8
|
+
console.error("clay-internals: could not determine my own URL (load me with a classic <script src=...>, not type=\"module\")");
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
var url = new URL(script.src, location.href);
|
|
12
|
+
var base = url.href.slice(0, url.href.lastIndexOf("/"));
|
|
13
|
+
|
|
14
|
+
// No DOM gate: nothing here touches document.body at import time, unlike clay-ui.
|
|
15
|
+
clay.loaded.internals = import(base + "/src/internals/index.js")
|
|
16
|
+
.catch(function (err) { console.error("clay-internals failed to load:", err); throw err; });
|
|
17
|
+
// Mark handled: a blocked satellite must not emit an unhandled rejection.
|
|
18
|
+
clay.loaded.internals.catch(function () {});
|
|
19
|
+
})();
|
package/clay.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* clayjs bootstrap. https://clayjs.com */
|
|
2
2
|
(function () {
|
|
3
3
|
// Suppress every vendored bundle's window auto-export; the loader assembles
|
|
4
|
-
// window.clay
|
|
4
|
+
// window.clay explicitly.
|
|
5
5
|
window.__hyperclayNoAutoExport = true;
|
|
6
6
|
|
|
7
7
|
// Merge into any window.clay a satellite already created; never replace it.
|
|
@@ -11,10 +11,18 @@
|
|
|
11
11
|
// resolves the ORIGINAL `ready` promise via the stashed resolver.
|
|
12
12
|
if (clay.__booted) return;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
clay.ready = new Promise(function (
|
|
14
|
+
function mintReady() {
|
|
15
|
+
clay.ready = new Promise(function (res, rej) {
|
|
16
|
+
clay.__readyResolve = res;
|
|
17
|
+
clay.__readyReject = rej;
|
|
18
|
+
});
|
|
19
|
+
// Nobody may be awaiting a failed boot's promise, and an unhandled rejection
|
|
20
|
+
// in the console is noise on top of the error we already logged.
|
|
21
|
+
clay.ready.catch(function () {});
|
|
16
22
|
}
|
|
17
23
|
|
|
24
|
+
if (!clay.ready) mintReady();
|
|
25
|
+
|
|
18
26
|
var script = document.currentScript;
|
|
19
27
|
if (!script || !script.src) {
|
|
20
28
|
console.error("clayjs: could not determine my own URL (load me with a classic <script src=...>, not type=\"module\")");
|
|
@@ -29,5 +37,13 @@
|
|
|
29
37
|
.catch(function (err) {
|
|
30
38
|
clay.__booted = false;
|
|
31
39
|
console.error("clayjs failed to load:", err);
|
|
40
|
+
// Settle the promise so `await clay.ready` fails loudly instead of hanging
|
|
41
|
+
// forever with nothing to catch. Then mint a fresh one: a promise settles
|
|
42
|
+
// once, so without this the corrected retry tag would call __readyResolve on
|
|
43
|
+
// an already-rejected promise and every later await would keep throwing even
|
|
44
|
+
// though the retry succeeded.
|
|
45
|
+
var reject = clay.__readyReject;
|
|
46
|
+
mintReady();
|
|
47
|
+
if (reject) reject(err);
|
|
32
48
|
});
|
|
33
49
|
})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panphora/clayjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "clayjs: malleable HTML files. Save lifecycle for self-saving HTML.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"clay.js",
|
|
14
14
|
"clay-ui.js",
|
|
15
|
+
"clay-internals.js",
|
|
15
16
|
"clay-events.js",
|
|
16
17
|
"clay-options.js",
|
|
17
18
|
"clay-dom.js",
|
|
@@ -31,7 +32,9 @@
|
|
|
31
32
|
"test:conformance": "UPDATE_GOLDENS=0 web-test-runner",
|
|
32
33
|
"conformance:update": "UPDATE_GOLDENS=1 web-test-runner",
|
|
33
34
|
"prepublishOnly": "npm test && npm run test:conformance",
|
|
34
|
-
"dev": "node tests/stub-server.mjs"
|
|
35
|
+
"dev": "node tests/stub-server.mjs",
|
|
36
|
+
"build": "node build.js",
|
|
37
|
+
"deploy": "node build.js && wrangler deploy && git rev-parse HEAD > .deploy"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
40
|
"@esm-bundle/chai": "^4.3.4-fix.0",
|