@panphora/clayjs 0.2.1 → 0.4.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 +99 -7
- package/clay-internals.js +19 -0
- package/clay.js +18 -2
- 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 +8 -1
- 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 +64 -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/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/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,60 @@ 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`, `skipForPolicy`, and the token
|
|
80
|
+
constants), the same shape `clay.internals.region` exposes.
|
|
81
|
+
|
|
82
|
+
**Satellites** — one script tag each, and each resolves its own `clay.loaded.*` promise. `clay-ui` adds
|
|
83
|
+
`toast`, `toastPersistent`, `ask`, `confirm`, `tell`, `snippet`, `modal`; `clay-utils` adds `clay.utils`
|
|
84
|
+
(`throttle`, `debounce`, `cookie`, `slugify`, `copyToClipboard`); `clay-internals` adds `clay.internals`,
|
|
85
|
+
below. `clay-events`, `clay-dom`, `clay-options` and `all.js` add HTML attributes and DOM helpers rather
|
|
86
|
+
than members on `clay`.
|
|
87
|
+
|
|
88
|
+
**`clay.internals`** — the pieces the library builds itself out of, for code that needs to sit inside the
|
|
89
|
+
save lifecycle rather than call it. Lower level than `clay.*` deliberately: it assumes you know the
|
|
90
|
+
lifecycle.
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<script src="https://clayjs.com/clay-internals.js"></script>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
- `captureSnapshot()`, `captureForSave()` — the snapshot pipeline, read side.
|
|
97
|
+
`captureSnapshot` gives you the clone before any stripping; `captureForSave` gives you the
|
|
98
|
+
bytes a save would send. Register your own transform with `clay.addDocumentTransform(fn)`
|
|
99
|
+
from core.
|
|
100
|
+
- `region.addRegionToken(el, token)`, `region.resolveRegionPolicy(node)`, `region.isInert(node)`,
|
|
101
|
+
`region.isSnapshotRemoved(el)`, `region.PERSIST`, `region.REGION_ATTRS`, and
|
|
102
|
+
`region.selectors.stripFromSave` / `.stripFromComparison` / `.snapshotRemove` / `.freeze` — write your
|
|
103
|
+
own attribute without hardcoding our selectors.
|
|
104
|
+
- `save.saveHtml(html, cb, opts)`, `save.replacePageWith(url, cb)`, `save.isSaveInProgress()` — the save
|
|
105
|
+
lane under `clay.save`. **`saveHtml` writes the bytes you hand it straight to the file**, bypassing the
|
|
106
|
+
snapshot pipeline entirely; check `isSaveInProgress()` first.
|
|
41
107
|
|
|
42
108
|
## Regions
|
|
43
109
|
|
|
@@ -54,6 +120,32 @@ Add `autosave` to `<html>` to save automatically on change.
|
|
|
54
120
|
## Develop
|
|
55
121
|
|
|
56
122
|
```bash
|
|
57
|
-
npm test
|
|
58
|
-
npm run
|
|
123
|
+
npm test # jest unit suite
|
|
124
|
+
npm run test:conformance # byte-for-byte fixture gate, in a real browser
|
|
125
|
+
npm run dev # stub save server on :4601 for the tests/fixtures pages
|
|
59
126
|
```
|
|
127
|
+
|
|
128
|
+
## Deploy
|
|
129
|
+
|
|
130
|
+
`public/` is what wrangler serves to clayjs.com. It is a build output: gitignored,
|
|
131
|
+
disposable, and rebuilt from scratch every time.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npm run build # rebuild public/ from source
|
|
135
|
+
npm run deploy # rebuild, then wrangler deploy
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Never edit `public/` by hand, and never copy a file into it. Its contents are
|
|
139
|
+
**derived**:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
public/ = package.json "files" (minus NOTICE, which nothing requests)
|
|
143
|
+
+ website/* (flattened to the root, so /docs.html works)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
That derivation is the point. `files` is the list npm publishes, so it is already
|
|
147
|
+
the line you edit to ship a new satellite, and deriving from it means a file cannot
|
|
148
|
+
reach npm and miss the site. Before this script existed the mirror was hand-copied,
|
|
149
|
+
and it drifted exactly that way: `src/core/host-attrs.js` never made it across, and
|
|
150
|
+
since `loader.js` imports `is-edit-mode.js`, which imports it, the deployed
|
|
151
|
+
`clay.js` could not boot at all.
|
|
@@ -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
|
@@ -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.0",
|
|
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"
|
|
35
38
|
},
|
|
36
39
|
"devDependencies": {
|
|
37
40
|
"@esm-bundle/chai": "^4.3.4-fix.0",
|
package/sap.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// GENERATED — do not edit. Vendored from sapjs/dist/sap.min.js via sapjs
|
|
2
2
|
// `npm run copy-to-clayjs`. Edit the sapjs source and re-run.
|
|
3
3
|
(function () {
|
|
4
|
-
var Sap=(()=>{var
|
|
5
|
-
${t}`:`"use strict"; return (${t});`;r={fn:new Function(...
|
|
6
|
-
`+(e[0]==="W"?"sap \u26A0 ":"sap \u2717 ")+e+" "+s];return
|
|
7
|
-
`)),f}error(e,n,r={}){let s=this.block(e,n,r);return this.errors.push(s),s}warn(e,n,r={}){let s=this.block(e,n,r);return this.warnings.push(s),s}report(){return{ok:this.errors.length===0&&!this.halted,app:this.appName,halted:this.halted,haltReason:this.haltReason,errors:this.errors.slice(),warnings:this.warnings.slice()}}};function Y(t,e){t&&t.getAttribute("sap-error")!==e&&t.setAttribute("sap-error",e)}function St(t){t&&t.hasAttribute("sap-error")&&t.removeAttribute("sap-error")}function ft(t,e){let n=null,r=3;for(let s of e){let f=je(t,s);f<r&&(r=f,n=s)}return n}function je(t,e){let n=t.length,r=e.length,s=Array.from({length:n+1},(f,u)=>[u,...new Array(r).fill(0)]);for(let f=0;f<=r;f++)s[0][f]=f;for(let f=1;f<=n;f++)for(let u=1;u<=r;u++)s[f][u]=Math.min(s[f-1][u]+1,s[f][u-1]+1,s[f-1][u-1]+(t[f-1]===e[u-1]?0:1));return s[n][r]}var j=null,$t=!1,X=null;function Zt(t){let e=null;return{kind:"hub",subscribe(n){let r=t.onAnyChange({debounce:0,require:"observed"},n);typeof r=="function"&&(e=r)},suppress(n){t.pause();try{return n()}finally{t.resume()}},teardown(){if(e){try{e()}catch{}e=null}}}}function Ve(){let t=null;return{kind:"native",subscribe(e){t=new MutationObserver(r=>e(Ue(r)));let n=typeof document<"u"&&document.body||typeof document<"u"&&document.documentElement;n&&t.observe(n,{childList:!0,subtree:!0,attributes:!0,characterData:!0})},suppress(e){let n=typeof window<"u"&&window.hyperclay&&window.hyperclay.undo;n&&n.pause&&n.pause();try{return e()}finally{t&&t.takeRecords(),n&&n.resume&&n.resume()}},teardown(){t&&(t.disconnect(),t=null)}}}function Ue(t){let e=[];for(let n of t)if(n.type==="attributes"){let r=n.target;r&&r.nodeType===1&&!xt(r)&&e.push({type:"attribute",element:r})}else if(n.type==="characterData"){let r=n.target&&n.target.parentElement;r&&!xt(r)&&e.push({type:"characterData",element:r})}else if(n.type==="childList"){for(let r of n.addedNodes)if(!(r.nodeType!==1||xt(r))&&(e.push({type:"add",element:r}),r.querySelectorAll))for(let s of r.querySelectorAll("*"))xt(s)||e.push({type:"add",element:s});for(let r of n.removedNodes)r.nodeType===1&&e.push({type:"remove",element:r,parent:n.target})}return e}function xt(t){return!!(t.closest&&t.closest("[sap-ignore],[template]"))}function Ge(t,e){t.pruneDisconnected();let n=new Set,r=!1;for(let s of e){let f=s.type==="remove"?s.parent:s.element,u=f&&t.appFor(f);u&&n.add(u),s.type==="add"&&s.element&&s.element.nodeType===1&&s.element.hasAttribute&&s.element.hasAttribute("sap")&&!(t.isRegistered&&t.isRegistered(s.element))&&(r=!0)}r&&t.remountIfPresent();for(let s of n)s.root.isConnected&&t.schedule(s,"mutation")}function te(t){if(j)return j.suppress(t);let e=typeof window<"u"&&window.hyperclay&&window.hyperclay.undo;if(e&&e.pause&&e.resume){e.pause();try{return t()}finally{e.resume()}}return t()}function Lt(t,e){$t=!0,j=t,t.subscribe(n=>Ge(e,n))}function Ct(t){if($t||typeof window>"u"||typeof document>"u")return;let e=window,n=e.hyperclay&&e.hyperclay.Mutation;if(n&&typeof n.onAnyChange=="function"){Lt(Zt(n),t);return}typeof MutationObserver=="function"&&(Lt(Ve(),t),X=function(){let s=e.hyperclay&&e.hyperclay.Mutation;s&&(document.removeEventListener("hyperclay:mutation-ready",X),X=null,j&&j.teardown(),$t=!1,Lt(Zt(s),t))},document.addEventListener("hyperclay:mutation-ready",X))}function ee(){if(j)try{j.teardown()}catch{}X&&typeof document<"u"&&document.removeEventListener("hyperclay:mutation-ready",X),j=null,$t=!1,X=null}var oe=new Set(At);function rt(t,e={}){if(e.breaker){t.diag.error("E26",t.root,{problem:"recompute loop halted after 50 passes; recent triggers: "+(t._breakerRing||[]).join(", ")}),Y(t.root,"loop");return}te(()=>Ye(t,e))}function Ye(t,e){let n=t.root,r={},s=[],f=[],u=[],T=[],E=[],y=new Set;t.diag.errors=[];let l={root:r,state:r,item:null,ownerEl:n,projection:!1};function w(o,i){let h=o.getAttribute(i.name);return h==null&&(h=i.default!=null?i.default:i.type==="num"?"0":i.type==="bool"?"false":"",E.push({el:o,name:i.name,value:mt(G(h,i.type),i.type)})),G(h,i.type)}function k(o,i){let h=F(o.getAttribute("state")||"");o._sapStateDecls=h;for(let p of h){if(p.type==="string"&&oe.has(p.name)&&typeof o[p.name]=="boolean"){i[p.name]=o.hasAttribute(p.name);continue}if(p.transient){i[p.name]=ht(o,p);continue}i[p.name]=w(o,p)}}function L(o,i){if(!o.hasAttribute("bind"))return;let h=o.getAttribute("bind"),p=i.item||i.state,v=R(o);v.kind==="radio"?(h in p||(p[h]=""),o.checked&&(p[h]=o.value)):p[h]=v.read(),o.hasAttribute("transient")&&(o.removeAttribute("value"),o.removeAttribute("checked"))}function b(o,i){for(let h of o.attributes){let p=h.name,v=h.value;if(p.startsWith("calc:"))s.push({owner:i.item||i.state,ownerEl:i.ownerEl,name:p.slice(5),entry:D(v),el:o,ctx:i});else if(p==="text"||p.startsWith("text:"))f.push({el:o,kind:"text",fmt:p.includes(":")?p.slice(5):null,entry:D(v),ctx:i});else if(p==="show")f.push({el:o,kind:"show",entry:D(v),ctx:i});else if(p.startsWith("attr:"))f.push({el:o,kind:"attr",arg:p.slice(5),entry:D(v),ctx:i});else if(p.startsWith("class:"))f.push({el:o,kind:"class",arg:p.slice(6),entry:D(v),ctx:i});else if(p.startsWith("css:"))f.push({el:o,kind:"css",arg:p.slice(4),entry:D(v),ctx:i});else if(p==="effect")u.push({el:o,entry:D(v,!0),ctx:i});else if(p==="invalid")T.push({el:o,entry:D(v),ctx:i});else if(p.startsWith("show-when:")||p.startsWith("option:")){let N=p.slice(p.indexOf(":")+1);y.add(N),f.push({el:o,kind:"when",match:"show",field:N,values:v.split("|"),ctx:i})}else if(p.startsWith("hide-when:")){let N=p.slice(p.indexOf(":")+1);y.add(N),f.push({el:o,kind:"when",match:"hide",field:N,values:v.split("|"),ctx:i})}else if(p.startsWith("option-not:")){let N=p.slice(p.indexOf(":")+1);y.add(N),f.push({el:o,kind:"when",match:"show-not",field:N,values:v.split("|"),ctx:i})}}i.projection&&o.hasAttribute("bind")&&f.push({el:o,kind:"projection",field:o.getAttribute("bind"),ctx:i})}function g(o,i,h){Z(i,"row"),Object.defineProperty(o,"$key",{value:i.id,enumerable:!1}),Object.defineProperty(o,"$index",{value:h,enumerable:!1}),Object.defineProperty(o,"$el",{value:i,enumerable:!1})}function a(o,i,h){k(o,i),o._sapScope=i,!h.projection&&o.hasAttribute("bind")&&L(o,h),b(o,h),o.hasAttribute("items")?x(o,i,h):A(o,i,h)}function A(o,i,h){W(o,(p,v)=>{v?p.hasAttribute("scope")?S(p,i,h):p.hasAttribute("items")?(b(p,h),x(p,i,h)):p.hasAttribute("detail")&&M(p,i,h):(h.projection||L(p,h),b(p,h))})}function S(o,i,h){let p=o.getAttribute("scope"),v={};i[p]=v;let N={root:h.root,state:v,item:null,ownerEl:o,projection:h.projection};a(o,v,N)}function x(o,i,h){let p=o.getAttribute("items"),v=[];i[p]=v,o._sapList=v,O(o).forEach((N,ot)=>{let C={};g(C,N,ot);let q={root:h.root,state:h.state,item:C,ownerEl:N,projection:h.projection};a(N,C,q),v.push(C)})}function $(o,i){let h=String(o).split("."),p=i.state;for(let v of h)p=p?.[v];if(p===void 0){p=i.root;for(let v of h)p=p?.[v]}return p}function M(o,i,h){for(let Q of F(o.getAttribute("state")||""))Q.name in i||(i[Q.name]=w(o,Q));o._sapScope=i;let p=o.getAttribute("detail")||"",v=/^([\w.]+)\s+by\s+(.+)$/.exec(p);if(!v){o.hidden=!0,o._sapDetailRow=null;return}let N=v[1],ot=v[2].trim(),C=$(N,h),q;try{q=H(D(ot),{state:i,item:h.item,el:o,root:h.root})}catch{q=void 0}let J=Array.isArray(C)?C.find(Q=>Q&&String(Q.$key)===String(q)):null;if(o._sapDetailRow=J?J.$el:null,!J){o.hidden||(o.hidden=!0);return}o.hidden&&(o.hidden=!1);let Ot={root:h.root,state:i,item:J,ownerEl:J.$el,projection:!0};b(o,Ot),A(o,J,Ot)}if(a(n,r,l),E.length&&y.size)for(let o of E)y.has(o.name)&&o.el.getAttribute(o.name)==null&&o.el.setAttribute(o.name,o.value);let m=new Map;for(let o of s){let i=m.get(o.owner);i||(i={ownerEl:o.ownerEl,list:[]},m.set(o.owner,i)),i.list.push(o)}let d=[...m.values()].sort((o,i)=>re(i.ownerEl)-re(o.ownerEl));for(let o of d){let i;try{i=Vt(o.list)}catch(h){t.diag.error("E07",o.list[0].el,{problem:h.message}),i=o.list}for(let h of i)try{h.owner[h.name]=H(h.entry,{state:h.ctx.state,item:h.ctx.item,el:h.el,root:h.ctx.root}),St(h.el)}catch(p){h.owner[h.name]=void 0,t.diag.error("E24",h.el,{attr:"calc:"+h.name,expr:h.entry.src,problem:String(p.message)}),Y(h.el,p.sapCode||"E24")}}let c=0;for(let o of f)c+=Je(o,t);for(let o of u)Qe(o,t);for(let o of T)Ze(o);t._state=r,t._stats={fields:Object.keys(r).filter(o=>typeof r[o]!="function").length,calcs:s.length,paints:f.length,lists:m.size,writes:c},t._lastPass={trigger:e.trigger||"refresh",writes:c},t._debug&&console.log(`sap pass \xB7 trigger: ${t._lastPass.trigger} \xB7 writes ${c}/${f.length}`)}function Xe(t){return t.kind==="text"?t.fmt?"text:"+t.fmt:"text":t.kind==="attr"?"attr:"+t.arg:t.kind==="class"?"class:"+t.arg:t.kind==="css"?"css:"+t.arg:t.kind==="when"?(t.match==="hide"?"hide-when:":t.match==="show-not"?"option-not:":"show-when:")+t.field:t.kind}function Mt(t,e,n,r){let s=t;for(;s&&s.nodeType===1;){if(s.hasAttribute&&s.hasAttribute(e)){let f=n.includes(s.getAttribute(e));if(r?!f:f)return!0}s=s.parentElement}return!1}function Ke(t,e){if(t===t.ownerDocument.activeElement)return 0;let n=R(t),r=n.read(),s=e??"";return String(r)!==String(s)?(n.write(s,{silent:!0}),1):0}function Je(t,e){if(t.kind==="projection")return Ke(t.el,t.ctx.item?t.ctx.item[t.field]:"");if(t.kind==="when")return ne(t,null);let n={state:t.ctx.state,item:t.ctx.item,el:t.el,root:t.ctx.root};try{let r=H(t.entry,n),s=ne(t,r);return St(t.el),s}catch(r){return e.diag.error(r.sapCode==="E22"?"E22":"E24",t.el,{attr:Xe(t),expr:t.entry&&t.entry.src,problem:String(r.message)}),Y(t.el,r.sapCode||"E24"),0}}function ne(t,e){let n=t.el;switch(t.kind){case"text":{let r=t.fmt!=null?qt(t.fmt,e):e==null?"":String(e);return n.textContent!==r?(n.textContent=r,1):0}case"show":{let r=!e;return n.hidden!==r?(n.hidden=r,1):0}case"when":{let r=typeof window<"u"&&window.hyperclay&&window.hyperclay.optionVisibility;if(r&&r._started)return n._sapWhen&&n.hidden?(n.hidden=!1,n._sapWhen=!1,1):0;let s;t.match==="hide"?s=!Mt(n,t.field,t.values,!1):t.match==="show-not"?s=Mt(n,t.field,t.values,!0):s=Mt(n,t.field,t.values,!1),n._sapWhen=!0;let f=!s;return n.hidden!==f?(n.hidden=f,1):0}case"attr":{let r=t.arg;if(oe.has(r)){let f=n.hasAttribute(r);return e&&!f?(n.setAttribute(r,""),1):!e&&f?(n.removeAttribute(r),1):0}let s=typeof e=="boolean"?String(e):e==null?"":String(e);return n.getAttribute(r)!==s?(n.setAttribute(r,s),1):0}case"class":{let r=!!e;return n.classList.contains(t.arg)!==r?(n.classList.toggle(t.arg,r),1):0}case"css":{let r=e==null?"":String(e);return n.style.getPropertyValue("--"+t.arg)!==r?(n.style.setProperty("--"+t.arg,r),1):0}default:return 0}}function Qe(t,e){try{H(t.entry,{state:t.ctx.state,item:t.ctx.item,el:t.el,root:t.ctx.root}),St(t.el)}catch(n){e.diag.error("E24",t.el,{attr:"effect",expr:t.entry&&t.entry.src,problem:String(n.message)}),Y(t.el,"E24")}}function Ze(t){let e="";try{let n=H(t.entry,{state:t.ctx.state,item:t.ctx.item,el:t.el,root:t.ctx.root});e=typeof n=="string"?n:""}catch{e=""}typeof t.el.setCustomValidity=="function"&&t.el.setCustomValidity(e)}function re(t){let e=0,n=t;for(;n&&!(n.hasAttribute&&n.hasAttribute("sap"));)n=n.parentElement,e++;return e}var tn=new Set(At),se=new Set(["calc","text","attr","class","css","set","move","sort","option","option-not","show-when","hide-when","editmode"]),en=new Set(["show-when","hide-when","option","option-not"]),nn=/\b(?:state|item|root)\.|===|!==|&&|\|\||[()]|^\s*!/,ie=new Set(["sap","scope","items","item","template","bind","show","effect","invalid","detail","state","transient","confirm","default","persist","sortable","trigger-add","trigger-remove","trigger-reset","sap-ignore","sap-error","no-save","no-watch","no-undo","no-trigger-autosave","freeze","mutations-ignore","save-remove","save-ignore","save-freeze"]);function rn(t){return t.tagName==="INPUT"||t.tagName==="SELECT"||t.tagName==="TEXTAREA"}function Rt(t){return t.hasAttribute("bind")}function on(t,e){e(t);for(let r of t.children)n(r);function n(r){if(r.nodeType===1&&!((r.hasAttribute("sap-ignore")||r.hasAttribute("template"))&&r.hasAttribute("sap-ignore"))){e(r);for(let s of r.children)n(s)}}}function kt(t,e){let n=!1,r=(u,T,E)=>{e.error(u,T,E),n=!0},s=t.ownerDocument.createTreeWalker(t,4),f;for(;f=s.nextNode();)if(/\{\{.*\}\}/.test(f.nodeValue||"")){r("E02",f.parentElement||t,{problem:"moustaches in text content are not a Sap feature",fix:'move the expression onto the element: text="state.x"'});break}return on(t,u=>{let T=u.closest&&u.closest("[detail]");for(let E of[...u.attributes]){let y=E.name,l=Qt(y);if(l){r("E01",u,{attr:y,expr:E.value,problem:`"${y}" is a foreign-dialect attribute; Sap has no ${y.split(/[:=]/)[0]} directive`,fix:l+" \u2014 or wrap the subtree in sap-ignore if intentional"});continue}if(y.includes(":")){let w=y.slice(0,y.indexOf(":"));if(se.has(w)){if(en.has(w)&&nn.test(E.value)){let k=y.slice(y.indexOf(":")+1);e.warn("W04",u,{attr:y,expr:E.value,problem:`${w}: compares the "${k}" attribute against a literal value, not a JS expression`,fix:`use show="${E.value}" for an expression, or a literal like ${w}:${k}="overview"`})}}else{let k=ft(w,[...se]);e.warn("W03",u,{attr:y,problem:`unknown "${w}:" attribute`,didYouMean:k?`${k}:`:null})}}else if(!ie.has(y)&&!ct.has(y)&&!tn.has(y)&&!/^(data-|aria-|on)/.test(y)&&!(y in u)){let w=ft(y,[...ie]);w&&e.warn("W03",u,{attr:y,problem:`unknown "${y}" attribute`,didYouMean:w})}y==="attr:hidden"&&e.warn("W03",u,{attr:y,problem:"attr:hidden paints the wrong attribute",fix:'use show="expr"'}),(y==="attr:value"||y==="attr:checked"||y==="attr:selected")&&Rt(u)&&r("E30",u,{attr:y,problem:"attr: on a bound control collides with persist ownership",fix:"remove it; bind owns this attribute"}),y==="effect"&&Rt(u)&&/\b(value|checked)\s*=[^=]/.test(E.value)&&r("E30",u,{attr:y,expr:E.value,problem:"effect writes value/checked on a bound control (writes a stale value with no synthetic event)",fix:"write through onclick + Sap(this) instead"}),(y==="text"||y.startsWith("text:")||y==="show")&&rn(u)&&(y==="show"||r("E18",u,{attr:y,problem:"paint belongs on output elements, not form controls",fix:"move the paint to an <output> or <span>"}))}if(u.hasAttribute("state")){let E=F(u.getAttribute("state")),y=new Set;for(let l of E)l.name.includes("-")&&r("E08",u,{attr:"state",problem:`field "${l.name}" is not a valid identifier (the hyphen parses as subtraction)`,fix:`rename to ${l.name.replace(/-/g,"")}`}),y.has(l.name)&&r("E04",u,{attr:"state",problem:`field "${l.name}" is declared twice in one scope`}),y.add(l.name),vt.has(l.name)&&r("E05",u,{attr:"state",problem:`"${l.name}" is a reserved Sap word`}),ct.has(l.name)&&r("E06",u,{attr:"state",problem:`"${l.name}" is a global HTML attribute name; pick another field name`}),l.name==="open"&&u.tagName==="DIALOG"&&r("E33",u,{attr:"state",problem:"dialog open is transient",fix:"use showModal() \u2014 declare state= only on <details> or popovers"})}if(Rt(u)){if(u.hasAttribute("-"),u.tagName==="INPUT"){let E=(u.getAttribute("type")||"text").toLowerCase();E==="file"&&r("E32",u,{attr:"bind",problem:"files never serialize into an HTML file",fix:"use no-save + effect instead of bind"}),E==="password"&&!u.hasAttribute("transient")&&r("E31",u,{attr:"bind",problem:"a password must never serialize into a world-readable file",fix:"add transient to the password input"})}else if(u.tagName!=="SELECT"&&u.tagName!=="TEXTAREA"){let E=u.getAttribute("contenteditable");!(E!=null&&E!=="false")&&u.children.length>0&&r("E20",u,{attr:"bind",problem:"bind on a container element is not a control; a write would overwrite its children",fix:"bind a control (input/select/textarea), a contenteditable, or an empty text leaf"})}}if(u.hasAttribute("transient")&&u.hasAttribute("persist")&&r("E34",u,{problem:"transient and persist are opposite: persist forces the live value into the saved bytes, leaking exactly what transient drops",fix:"remove one \u2014 transient to keep it out of the file, or persist to save it"}),u.hasAttribute("item")&&!u.hasAttribute("template")){let E=u.parentElement;(!E||!E.hasAttribute("items"))&&r("E10",u,{problem:"an [item] must be a direct child of an [items] list",fix:'wrap it in a container with items="name"'})}if(u.hasAttribute("items")&&T&&r("E17",u,{attr:"items",problem:"nested items inside a detail panel is a v1 mount error (nested collections ship in v1.1)"}),u.hasAttribute("items")){let E=t.querySelector(`[trigger-add="${u.getAttribute("items")}"]`);!pt(u)&&O(u).length===0&&E&&r("E17",u,{attr:"items",problem:`trigger-add targets items="${u.getAttribute("items")}" but it has no [item template] to clone`})}}),n&&(e.halted=!0,e.haltReason=e.errors[0]?e.errors[0].code:"halt",Y(t,e.haltReason)),!n}var ae="sap-styles",ue="[item][template]{display:none!important}[hidden]{display:none!important}[sap-error]{outline:2px solid #e5484d;outline-offset:1px}",Dt=new WeakSet;function sn(t){if(Dt.has(t))return;let e=t.defaultView,n=e&&e.CSSStyleSheet;if(n&&"adoptedStyleSheets"in t)try{let r=new n;r.replaceSync(ue),t.adoptedStyleSheets=[...t.adoptedStyleSheets,r],Dt.add(t);return}catch{}if(!t.getElementById(ae)){let r=t.createElement("style");r.id=ae,r.textContent=ue,(t.head||t.documentElement).appendChild(r)}Dt.add(t)}var an=0;function ce(){return typeof performance<"u"&&performance.now?performance.now():0}function It(t){let e=t.id||t.getAttribute("sap")||`app-${an++}`,n=new nt(e),r={root:t,name:e,diag:n,_state:null,_stats:null,_lastPass:null,_passes:0,_broken:!1,_mountMs:0,_mountWrites:0};if(!kt(t,n))return r.halted=!0,r;sn(t.ownerDocument);for(let u of t.querySelectorAll("textarea[data-value]"))wt(u);let f=ce();return rt(r,{trigger:"mount"}),r._mountMs=ce()-f,r._mountWrites=r._stats?r._stats.writes:0,r._mountWrites>0&&n.warn("W30",t,{problem:`${r._mountWrites} paint(s) ran at mount; the saved file was out of sync with its declared state`,fix:"re-save once so the file mounts clean (a settled file writes nothing)"}),r}function un(t,e){let n=null;return W(t,r=>{!n&&r.getAttribute("scope")===e&&(n=r)}),n}function fe(t,e,n){let r=I(t)||e;for(;r;){for(let s of F(r.getAttribute("state")||""))if(s.name===n)return{el:r,decl:s};if(r.hasAttribute("sap"))break;r=I(r.parentElement)}return null}function cn(t){return typeof t=="number"?"num":typeof t=="boolean"?"bool":"string"}function le(t){function e(b){let g=t.appFor(b);if(!g)return null;let a=it(b);if(a)return a._sapDetailRow?{ctxEl:a._sapDetailRow,appRec:g,isRow:!0}:{ctxEl:I(a.parentElement)||g.root,appRec:g,isRow:!1};let A=dt(b);if(A&&A.hasAttribute("item"))return{ctxEl:A,appRec:g,isRow:!0};let S=I(b)||g.root;return{ctxEl:S,appRec:g,isRow:S.hasAttribute("item")}}function n(b){let g=typeof b=="string"?document.querySelector(b):b;if(!g||g.nodeType!==1)return null;let a=e(g);return a?L(a.ctxEl,a.appRec,a.isRow):null}function r(b,g,a){let A=tt(b,a);if(A)return R(A).read();let S=st(b,a);if(S)return O(S).map(m=>L(m,g,!0));let x=un(b,a);if(x)return L(x,g,!1);let $=fe(b,g.root,a);if($)return $.decl.transient?ht($.el,$.decl):G($.el.getAttribute(a),$.decl.type);let M=b._sapScope;return M?M[a]:void 0}function s(b,g,a,A,S){A.transient?Tt(b,A,a):b.setAttribute(g,mt(a,A.type)),t.schedule(S,"set:"+g)}function f(b,g){let a=new Set,A=I(b)||g;for(;A;){for(let S of F(A.getAttribute("state")||""))a.add(S.name);if(A.hasAttribute("sap"))break;A=I(A.parentElement)}return W(b,S=>{let x=S.getAttribute("bind");x&&a.add(x)}),a}function u(b,g,a,A){let S=tt(b,a);if(S){R(S).write(A);return}let x=b;for(;x;){for(let h of x.attributes)if(h.name==="calc:"+a){g.diag.error("E16",x,{attr:"calc:"+a,problem:`"${a}" is a computed field; computed fields are read-only`});return}if(x.hasAttribute("sap"))break;x=x.parentElement}let $=fe(b,g.root,a);if($){s($.el,a,A,$.decl,g);return}let M=f(b,g.root);M.delete(a);let m=a.length>=4?ft(a,[...M]):null;if(m){g.diag.error("E12",b,{key:a,problem:`unknown state key "${a}"`,didYouMean:m});return}if(vt.has(a)||ct.has(a)){g.diag.error("E15",b,{key:a,problem:`cannot write undeclared field "${a}" \u2014 it is a reserved/global name and cannot become state`,fix:"pick a different field name, or declare it explicitly in a state= attribute"});return}let d=g.root,c=cn(A),o=d.getAttribute("state")||"",i=c==="string"?a:`${a}:${c}`;d.setAttribute("state",o?`${o} ${i}`:i),s(d,a,A,{name:a,type:c,transient:!1},g)}function T(b){let g=a=>{a.id&&(a.id="",Z(a,"row")),a.hasAttribute("sap-error")&&a.removeAttribute("sap-error")};b.id="",Z(b,"row"),b.querySelectorAll("[id]").forEach(g)}function E(b,g,a){let A=at(g.root,b,a);if(!A)return g.diag.error("E17",b,{problem:`cannot resolve a list named "${a}" from here`}),null;let S=pt(A);if(!S)return g.diag.error("E17",A,{problem:`items="${a}" has no [item template] to clone`}),null;let x=S.cloneNode(!0);return x.removeAttribute("template"),T(x),A.appendChild(x),t.schedule(g,"trigger-add:"+a),L(x,g,!0)}function y(b,g){W(b,a=>{if(a.hasAttribute("bind")){let A=R(a),S=a.getAttribute("default");A.kind==="checkbox"||A.kind==="radio"?A.write(S!=null?S===""||S==="true"||a.value===S:a.hasAttribute("checked")):A.write(S??(a.getAttribute("value")||""))}});for(let a of F(b.getAttribute("state")||"")){let A=a.default!=null?a.default:a.type==="num"?"0":a.type==="bool"?"false":"";a.transient?Tt(b,a,G(A,a.type)):b.setAttribute(a.name,A)}t.schedule(g,"trigger-reset")}function l(b,g){if(!b.isConnected)throw new Error("stale row handle: $remove() on a removed row");b.remove(),t.schedule(g,"trigger-remove")}function w(b,g,a){if(!b.isConnected)throw new Error("stale row handle: $move() on a removed row");let A=null;if(a&&a.nodeType===1?A=a:typeof a=="string"&&(A=at(g.root,b,a)),!A){g.diag.error("E17",b,{problem:`$move() cannot resolve target "${a}"`});return}t.moveInto(A,b),t.schedule(g,"trigger-move")}function k(b){let g=b.parentElement;return g?O(g).indexOf(b):-1}function L(b,g,a){let A={get $el(){return b},get $key(){return Z(b,a?"row":"scope")},get $index(){return k(b)},$add(x){return E(b,g,x)},$reset(){return y(b,g),S},$remove(){l(b,g)},$move(x){w(b,g,x)},get $appRec(){return g}},S=new Proxy(A,{get(x,$){return typeof $=="symbol"||$[0]==="$"?x[$]:r(b,g,$)},set(x,$,M){return typeof $=="string"&&$[0]==="$"?(x[$]=M,!0):(u(b,g,$,M),!0)},has(x,$){return typeof $=="string"&&$[0]==="$"?$ in x:r(b,g,$)!==void 0}});return S}return{Sap:n,contextElFor:e,readField:r,writeField:u,makeProxy:L}}var fn=["trigger-add","trigger-remove","trigger-reset"];function ln(t){if(t.nodeType!==1)return!1;for(let e of t.attributes){let n=e.name;if(n.startsWith("set:")||n.startsWith("move:")||n.startsWith("sort:")||fn.includes(n))return!0}return!1}function dn(t,e){let n=t,r=e.parentElement;for(;n&&n!==r;){if(n.nodeType===1&&ln(n)&&!(n.tagName==="FORM"&&n.hasAttribute("trigger-add")))return n;n=n.parentElement}return null}function de(t,e){let{Sap:n}=e;function r(m,d){let c=null,o=it(m);if(o&&o._sapDetailRow)c=o._sapDetailRow._sapScope||null;else{let p=dt(m);p&&p.hasAttribute("item")&&(c=p._sapScope||null)}return{state:(I(m)||d.root)._sapScope||d._state||{},item:c,el:m,root:d._state||{}}}function s(m,d,c){if(!m.hasAttribute("confirm")){c();return}let o=m.getAttribute("confirm"),i=o,h=D(o);if(!h.error)try{let N=H(h,r(m,d));(typeof N=="string"||typeof N=="number")&&(i=String(N))}catch{}let p=Yt();if(!p){window.confirm(i)&&c();return}if(m._sapGatePending)return;m._sapGatePending=!0;let v=()=>{m._sapGatePending=!1};p(i,()=>{v(),c()}).catch(v)}function f(m,d){for(let c of m.attributes){if(!c.name.startsWith("set:"))continue;let o=c.name.slice(4),i=D(c.value);if(i.error){d.diag.error("E08",m,{attr:c.name,expr:c.value,problem:String(i.error.message)});continue}let h;try{h=H(i,r(m,d))}catch(v){d.diag.error("E24",m,{attr:c.name,expr:c.value,problem:String(v.message)});continue}let p=n(m);p&&(p[o]=h)}}function u(m,d){let c=m.closest("[item]");if(!c)return;let o=O(c.parentElement),i=o.indexOf(c);d==="up"&&i>0?t.placeBefore(c,o[i-1]):d==="down"&&i<o.length-1&&t.placeBefore(o[i+1],c)}function T(m,d,c){if(d)return at(c.root,m,d);let o=m;for(;o;){if(o.hasAttribute&&o.hasAttribute("items"))return o;o=o.parentElement}let i=I(m)||c.root,h=[];return W(i,p=>{p.hasAttribute("items")&&h.push(p)}),h[0]||null}function E(m,d){let c=m==null||m==="",o=d==null||d==="";if(c&&o)return 0;if(c)return 1;if(o)return-1;let i=Number(m),h=Number(d);return!Number.isNaN(i)&&!Number.isNaN(h)?i-h:String(m)<String(d)?-1:String(m)>String(d)?1:0}function y(m,d,c,o){let i=T(m,c,o);if(!i){o.diag.error("E17",m,{attr:"sort:"+d,problem:`no items list resolvable for sort:${d}`});return}let h=O(i),p=C=>C._sapScope?C._sapScope[d]:void 0,v=[...h].sort((C,q)=>E(p(C),p(q))),ot=v.every((C,q)=>C===h[q])?[...v].reverse():v;for(let C of ot)t.moveInto(i,C);t.schedule(o,"sort:"+d)}function l(m){if(!m||m.hidden)return;let d=m.querySelector("[bind]:not([type=hidden]), [contenteditable]");d&&typeof d.focus=="function"&&d.focus()}function w(m,d){s(m,d,()=>{let c=n(m);for(let o of[...m.attributes]){let i=o.name;if(i==="trigger-remove")c&&c.$remove();else if(i==="trigger-reset")c&&c.$reset();else if(i==="trigger-add"){let h=c&&c.$add(o.value);h&&l(h.$el)}else i==="move:up"?(u(m,"up"),t.schedule(d,"move:up")):i==="move:down"?(u(m,"down"),t.schedule(d,"move:down")):i.startsWith("move:to")?c&&c.$move(o.value):i.startsWith("sort:")&&y(m,i.slice(5),o.value,d)}[...m.attributes].some(o=>o.name.startsWith("set:"))&&f(m,d)})}function k(m){let d=m.target;if(!d||d.nodeType!==1)return;let c=t.appFor(d);if(!c)return;let o=dn(d,c.root);o&&w(o,c)}function L(m){let d=R(m),c=m.getAttribute("default");d.kind==="checkbox"?d.write(c===""||c==="true"):d.write(c??"")}function b(m,d,c){let o=n(m);if(!o)return;let i=o.$add(c);if(!i)return;let h=[];W(m,p=>{p.hasAttribute("bind")&&h.push(p)});for(let p of h){let v=tt(i.$el,p.getAttribute("bind"));v&&R(v).write(R(p).read())}h.forEach(L),h.length?typeof h[0].focus=="function"&&h[0].focus():l(i.$el)}function g(m){let d=m.target;if(!d||!d.hasAttribute||!d.hasAttribute("trigger-add"))return;let c=t.appFor(d);c&&(m.preventDefault(),s(d,c,()=>b(d,c,d.getAttribute("trigger-add"))))}function a(m){let d=m.target,c=t.appFor(d);c&&setTimeout(()=>{d.querySelectorAll("[bind]").forEach(o=>{o.dispatchEvent(new Event("input",{bubbles:!0})),o.dispatchEvent(new Event("change",{bubbles:!0}))}),t.schedule(c,"reset")},0)}function A(m){let d=t.appFor(m.target);d&&t.schedule(d,"toggle")}function S(m){let d=m.target;if(!d||d.nodeType!==1)return;let c=t.appFor(d);if(!c)return;d.hasAttribute("persist")&&!yt(d)&&et(d);let o=it(d);if(o&&o._sapDetailRow&&d.hasAttribute("bind")){let i=tt(o._sapDetailRow,d.getAttribute("bind"));if(i&&i!==d){R(i).write(R(d).read());return}}t.schedule(c,m.type+" "+(d.id||d.tagName.toLowerCase()))}function x(m){let d=m.detail||{};for(let c of[d.from,d.to,m.target]){if(!c||c.nodeType!==1)continue;let o=t.appFor(c);o&&t.schedule(o,"sorted")}}function $(m){if(m.key!=="ArrowUp"&&m.key!=="ArrowDown")return;let d=m.target;if(!d||d.nodeType!==1||d.tagName!=="INPUT"||!d.hasAttribute("bind")||!d.hasAttribute("step"))return;let c=(d.getAttribute("type")||"text").toLowerCase();if(c!=="text"&&c!=="tel"&&c!=="search"||!t.appFor(d))return;m.preventDefault();let i=P(d.getAttribute("step"))||1,h=m.key==="ArrowUp"?1:-1,p=P(d.value)+i*(m.shiftKey?10:1)*h,v=d.getAttribute("min"),N=d.getAttribute("max");v!==null&&v!==""&&p<P(v)&&(p=P(v)),N!==null&&N!==""&&p>P(N)&&(p=P(N)),R(d).write(String(Number(p.toFixed(2))))}function M(m=document){m.addEventListener("click",k),m.addEventListener("submit",g),m.addEventListener("reset",a),m.addEventListener("toggle",A,!0),m.addEventListener("input",S),m.addEventListener("change",S),m.addEventListener("clay:sorted",x),m.addEventListener("keydown",$)}return{install:M}}var pe=/^(set:|move:|sort:|trigger-add$|trigger-remove$|trigger-reset$)/;function Wt(t){return`${t.tagName.toLowerCase()}[sap]`}function pn(t){let e=0;for(let n of t.querySelectorAll("*"))for(let r of n.attributes)if(pe.test(r.name)){e++;break}for(let n of t.attributes)if(pe.test(n.name)){e++;break}return e}function me(t){let e=[],n=r=>{for(let s of r.attributes){let f=s.name;(f.startsWith("calc:")||f==="text"||f.startsWith("text:")||f==="show"||f.startsWith("attr:")||f.startsWith("class:")||f.startsWith("css:")||f==="effect"||f==="invalid"||f.startsWith("set:")||f==="detail")&&e.push({el:r,attr:f,src:s.value})}};n(t);for(let r of t.querySelectorAll("*"))n(r);return e}function he(t){function e(l){let w=l._stats||{},k=l.root;return{root:Wt(k),fields:w.fields||0,calcs:w.calcs||0,paints:w.paints||0,actions:pn(k),lists:(k.hasAttribute("items")?1:0)+k.querySelectorAll("[items]").length,rows:k.querySelectorAll("[item]:not([template])").length,warnings:l.diag.warnings.length,errors:l.diag.errors.length,mountWrites:l._mountWrites||0,ms:Math.round((l._mountMs||0)*10)/10,passes:l._passes||0,lastPass:l._lastPass||null,ok:l.diag.errors.length===0&&!l.halted}}function n(){let l=t.apps().map(e);return{ok:l.every(w=>w.ok),apps:l}}function r(l){let w=e(l);return w.ok?`sap \u2713 ${w.root} \xB7 fields ${w.fields} \xB7 calcs ${w.calcs} \xB7 paints ${w.paints} \xB7 actions ${w.actions} \xB7 lists ${w.lists} \xB7 rows ${w.rows} \xB7 warnings ${w.warnings} \xB7 mount writes ${w.mountWrites} \xB7 ${w.ms}ms`:`sap \u2717 ${w.root} \xB7 errors ${w.errors} \xB7 warnings ${w.warnings} \xB7 ${w.ms}ms`}function s(){for(let l of t.apps()){let w=r(l);l.diag.errors.length||l.halted?console.error(w):console.log(w)}}function f(){let l=[],w=[];for(let k of t.apps())l.push(...k.diag.errors),w.push(...k.diag.warnings);return{ok:l.length===0,errors:l,warnings:w,counts:{errors:l.length,warnings:w.length}}}function u(l){return l?typeof l=="string"?document.querySelector(l):l.nodeType===1?l:null:null}function T(l,w){let k=u(l);if(!k)return console.warn("sap why: element not found"),null;let L=[`sap why <${k.tagName.toLowerCase()}> \u2014 ${Et(k)}`],b=[...k.attributes].filter(a=>/^(bind|text|show|effect|invalid|detail|calc:|text:|attr:|class:|css:|set:|state|items|scope)/.test(a.name));for(let a of b)L.push(` ${a.name}="${a.value}"`);let g=k;for(;g&&!g._sapScope;)g=g.parentElement;if(g&&g._sapScope){let a=g._sapScope,A=w?[w]:Object.keys(a);L.push(" reads:");for(let S of A){let x=a[S];typeof x!="function"&&L.push(` ${S} = ${JSON.stringify(Array.isArray(x)?`[${x.length} rows]`:x)}`)}}return L.push(" serialization: textContent and value/checked attributes save with the file; reads live from properties"),console.log(L.join(`
|
|
8
|
-
`)),null}function E(l){let w=l===void 0?!0:!!l;for(let k of t.apps())k._debug=w;return console.log(`sap debug ${w?"on":"off"} \u2014 per-pass headers will ${w?"":"no longer "}log`),w}function y(){let l=[],w=0;for(let a of t.apps()){let A=a.root,S=
|
|
4
|
+
var Sap=(()=>{var _t=Object.defineProperty;var Se=Object.getOwnPropertyDescriptor;var xe=Object.getOwnPropertyNames;var $e=Object.prototype.hasOwnProperty;var ke=(t,e)=>{for(var n in e)_t(t,n,{get:e[n],enumerable:!0})},Ne=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of xe(e))!$e.call(t,s)&&s!==n&&_t(t,s,{get:()=>e[s],enumerable:!(r=Se(e,s))||r.enumerable});return t};var Te=t=>Ne(_t({},"__esModule",{value:!0}),t);var kn={};ke(kn,{Sap:()=>_,default:()=>$n,mount:()=>Ee,mountAll:()=>dt,runtime:()=>K});function zt(t){let e=!1,n=new Set,r=[];function s(l){l&&(r.push(l),r.length>8&&r.shift())}function u(l,w){s(w),!l._broken&&(n.add(l),!e&&(e=!0,queueMicrotask(c)))}function c(){e=!1;let l=[...n];n.clear();for(let w of l)T(w)}function T(l){if(!l._broken){if(l._passes=(l._passes||0)+1,l._passes>50){l._broken=!0,l._breakerRing=r.slice(),t(l,{breaker:!0});return}l._resetArmed||(l._resetArmed=!0,setTimeout(()=>{l._passes=0,l._resetArmed=!1},0)),t(l)}}function E(l,w){s(w),T(l)}function y(l){l._broken=!1,l._passes=0}return{schedule:u,runNow:E,rearm:y,ring:r}}var _e=0;function Z(t,e="sap"){return t.id||(t.id=`${e}-${(_e++).toString(36)}`),t.id}function Le(t){return t.hasAttribute("scope")||t.hasAttribute("items")||t.hasAttribute("detail")}function Ce(t){return t.hasAttribute("sap-ignore")||t.hasAttribute("template")}function F(t,e){for(let r of t.children)n(r);function n(r){if(r.nodeType!==1||Ce(r))return;let s=Le(r);if(e(r,s),!s)for(let u of r.children)n(u)}}function I(t){let e=t;for(;e;){if(e.hasAttribute("sap")||e.hasAttribute("scope")||e.hasAttribute("item")||e.hasAttribute("detail"))return e;e=e.parentElement}return null}function pt(t){let e=t;for(;e;){if(e.hasAttribute("detail")||e.hasAttribute("item"))return e;e=e.parentElement}return null}function at(t){let e=t;for(;e;){if(e.hasAttribute("detail"))return e;e=e.parentElement}return null}function tt(t,e){let n=null;return F(t,r=>{!n&&r.getAttribute("bind")===e&&(n=r)}),n}function it(t,e){let n=null;return F(t,r=>{!n&&r.getAttribute("items")===e&&(n=r)}),n}function O(t){return[...t.children].filter(e=>e.hasAttribute("item")&&!e.hasAttribute("template"))}function mt(t){return[...t.children].find(e=>e.hasAttribute("item")&&e.hasAttribute("template"))||null}function P(t){let e=[];if(!t)return e;for(let n of t.trim().split(/\s+/)){if(!n)continue;let r=n,s,u=r.indexOf("=");u>=0&&(s=r.slice(u+1),r=r.slice(0,u));let c=r.split(":"),T=c[0],E="string",y=!1;for(let l of c.slice(1))l==="num"?E="num":l==="bool"?E="bool":l==="transient"&&(y=!0);e.push({name:T,type:E,default:s,transient:y})}return e}function G(t,e){if(e==="num"){if(t==null||t==="")return 0;let n=Number(t);return Number.isNaN(n)?0:n}return e==="bool"?t==="true"||t===""||t==="1":t??""}function ht(t,e){return e==="bool"?t?"true":"false":t==null?"":String(t)}function bt(t,e){let n=t._sapTransient||(t._sapTransient={});if(!(e.name in n)){let r=t.getAttribute(e.name);r==null&&(r=e.default!=null?e.default:e.type==="num"?"0":e.type==="bool"?"false":""),n[e.name]=G(r,e.type)}return t.hasAttribute(e.name)&&t.removeAttribute(e.name),n[e.name]}function Lt(t,e,n){(t._sapTransient||(t._sapTransient={}))[e.name]=n,t.hasAttribute(e.name)&&t.removeAttribute(e.name)}function ut(t,e,n){let r=String(n).split("."),s=r[r.length-1];if(r.length===1){let T=Me(e,s);return T||(t.getAttribute("items")===s?t:t.querySelector(`[items="${s}"]`))}let u=r[r.length-2],c=[...t.querySelectorAll(`[scope="${u}"]`)].find(T=>it(T,s));return c?it(c,s):null}function Me(t,e){let n=I(t);for(;n;){if(n.getAttribute("items")===e)return n;let r=it(n,e);if(r)return r;n=I(n.parentElement)}return null}function B(t){if(typeof t=="number")return t;if(t==null||t==="")return 0;let e=Number(typeof t=="string"?t.replace(/[$,%\s]/g,""):t);return Number.isNaN(e)?0:e}function gt(t,e){return Array.isArray(t)?e==null?t:t.map(n=>typeof e=="function"?e(n):n?.[e]):[]}function Ht(t,e){return gt(t,e).reduce((n,r)=>n+B(r),0)}function De(t,e){return Array.isArray(t)?e==null?t.length:t.reduce((n,r)=>n+(e(r)?1:0),0):0}function Re(t,e){let n=gt(t,e);return n.length?Ht(t,e)/n.length:0}function Ie(t,e){let n=gt(t,e).filter(r=>r!=null&&r!=="");return n.length?n.every(r=>typeof r=="number"||!Number.isNaN(Number(r)))?Math.min(...n.map(Number)):n.reduce((r,s)=>String(r)<=String(s)?r:s):0}function We(t,e){let n=gt(t,e).filter(r=>r!=null&&r!=="");return n.length?n.every(r=>typeof r=="number"||!Number.isNaN(Number(r)))?Math.max(...n.map(Number)):n.reduce((r,s)=>String(r)>=String(s)?r:s):0}function Fe(t,e,n){let r=B(t)===1?e:n??e+"s";return`${t} ${r}`}function Pe(t,e){let n=new Date(t),r=new Date(e);return Number.isNaN(+n)||Number.isNaN(+r)?0:Math.round((r-n)/864e5)}function H(t){return typeof t=="number"?t:Number(t)}var ct={usd:t=>"$"+H(t).toLocaleString("en-US",{maximumFractionDigits:0}),usd2:t=>"$"+H(t).toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}),pct:t=>Math.round(H(t))+"%",pct1:t=>H(t).toFixed(1)+"%",int:t=>Math.round(H(t)).toLocaleString("en-US"),num:t=>H(t).toLocaleString("en-US"),num2:t=>H(t).toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}),compact:t=>H(t).toLocaleString("en-US",{notation:"compact"}),date:t=>{let e=new Date(t);return Number.isNaN(+e)?String(t):e.toLocaleDateString("en-US")},clock:t=>{let e=H(t),n=Math.floor(e/100),r=n%10,s=Math.floor(n/10)%60;return`${Math.floor(n/600)}:${String(s).padStart(2,"0")}.${r}`}},Oe=new Set(["usd","usd2","pct","pct1","int","num","num2","compact","clock"]);function jt(t,e){if(!t)return e==null?"":String(e);let n=ct[t];if(typeof n!="function"){let r=new Error(`unknown format "${t}"`);throw r.sapCode="E22",r}if(Oe.has(t)){let r=typeof e=="number"?e:Number(e);if(!Number.isFinite(r)){let s=new Error(`format "${t}" received ${typeof e=="string"?`"${e}"`:e}`);throw s.sapCode="E22",s}}return n(e)}function Ut(){return[ct,B,Ht,De,Re,Ie,We,Fe,Pe]}var Be=["state","item","el","root","fmt","num","sum","count","avg","min","max","plural","days"],wt=new Map,Vt=/\bstate\.([a-z][a-z0-9_]*)/g,Yt=/\bitem\.([a-z][a-z0-9_]*)/g;function qe(t){let e=new Set,n=new Set,r;for(Vt.lastIndex=0;r=Vt.exec(t);)e.add(r[1]);for(Yt.lastIndex=0;r=Yt.exec(t);)n.add(r[1]);return{state:e,item:n}}function R(t,e=!1){let n=(e?"!":"")+t,r=wt.get(n);if(r)return r;wt.size>512&&wt.clear();try{let s=e?`"use strict";
|
|
5
|
+
${t}`:`"use strict"; return (${t});`;r={fn:new Function(...Be,s),src:t,statement:e,deps:qe(t),error:null}}catch(s){r={fn:null,src:t,statement:e,deps:{state:new Set,item:new Set},error:s}}return wt.set(n,r),r}function j(t,e){if(t.error)throw t.error;return t.fn(e.state,e.item,e.el??null,e.root,...Ut())}function Gt(t){let e=new Map;for(let c of t)e.set(c.name,c);let n=[],r=new Map,s=[];function u(c){let T=r.get(c.name);if(T!==1){if(T===0){let E=[...s.slice(s.indexOf(c.name)),c.name].join(" -> "),y=new Error(`calc: cycle: ${E}`);throw y.sapCode="E07",y.cycle=E,y}r.set(c.name,0),s.push(c.name);for(let E of c.entry.deps.state){let y=e.get(E);y&&y!==c&&u(y)}for(let E of c.entry.deps.item){let y=e.get(E);y&&y!==c&&u(y)}s.pop(),r.set(c.name,1),n.push(c)}}for(let c of t)u(c);return n}function Xt(t){return(t.getAttribute("type")||"text").toLowerCase()}function et(t){let e=t.tagName;if(e==="INPUT"){let n=Xt(t);n==="checkbox"||n==="radio"?t.checked?t.setAttribute("checked",""):t.removeAttribute("checked"):t.setAttribute("value",t.value);return}if(e==="TEXTAREA"){t.setAttribute("data-value",t.value);return}if(e==="SELECT"){let n=t.options;for(let r=0;r<n.length;r++)n[r].selected?n[r].setAttribute("selected",""):n[r].removeAttribute("selected")}}function Kt(t,e=t){let n=t.tagName;if(n==="INPUT"){let r=Xt(t);r==="checkbox"||r==="radio"?e.checked?t.setAttribute("checked",""):t.removeAttribute("checked"):t.setAttribute("value",e.value);return}if(n==="TEXTAREA"){t.textContent=e.value,t.removeAttribute("data-value");return}if(n==="SELECT"){let r=t.options,s=e.options;for(let u=0;u<r.length;u++)s[u]&&s[u].selected?r[u].setAttribute("selected",""):r[u].removeAttribute("selected")}}function yt(t){t.tagName!=="TEXTAREA"||!t.hasAttribute("data-value")||t!==t.ownerDocument.activeElement&&(t.textContent=t.getAttribute("data-value"),t.removeAttribute("data-value"))}function W(t){if(typeof window>"u")return null;let e=window.clay,n=window.hyperclay;return t==="consent"?e?.confirm||n?.consent||null:e?.[t]||n?.[t]||null}var Ct=["clay:mutation-ready","hyperclay:mutation-ready"],ze=["clay:sync-applied","hyperclay:livesync-applied"];function At(t,e,n){let r=null,s=u=>{r!==null&&r!==u.type||(r=u.type,queueMicrotask(()=>{r=null}),n(u))};for(let u of e)t.addEventListener(u,s);return()=>{for(let u of e)t.removeEventListener(u,s)}}function vt(t){let e=W("region");return!e||typeof e.resolveRegionPolicy!="function"||typeof e.skipForPolicy!="function"?!1:e.skipForPolicy(e.resolveRegionPolicy(t),void 0,["no-save","freeze"])}function Jt(){let t=W("consent");return typeof t=="function"?t:null}function Qt(t,e){if(typeof e!="function")throw new Error("Sap.batch(label, fn): fn must be a function");let n=W("undo");n&&n.flush&&n.flush();let r=e();if(r&&typeof r.then=="function")throw new Error("Sap.batch fn must be synchronous (it returned a promise)");return n&&n.commitCaptured&&n.commitCaptured(t),r}function Zt(t){if(typeof window>"u"||typeof document>"u")return;let e=()=>{let r=!1;for(let s of t.apps())s.root.isConnected?t.runNow(s,"platform"):r=!0;r&&(t.pruneDisconnected(),t.remountIfPresent())};At(document,ze,e);let n=W("undo");n&&typeof n.on=="function"?(n.on("undo",e),n.on("redo",e)):At(document,Ct,()=>{let r=W("undo");r&&typeof r.on=="function"&&(r.on("undo",e),r.on("redo",e))})}function He(t){let e=t.tagName;if(e==="INPUT"){let n=(t.getAttribute("type")||"text").toLowerCase();return n==="checkbox"?"checkbox":n==="radio"?"radio":n==="number"||n==="range"?"number":n==="hidden"?"hidden":"text"}return e==="TEXTAREA"?"text":e==="SELECT"?t.multiple?"select-multiple":"select-one":"leaf"}function je(t){if(t.validity&&t.validity.badInput)return t.hasAttribute("value")?Number(t.getAttribute("value"))||0:t._sapLastGood??0;if(t.value==="")return 0;let e=Number(t.value);return Number.isNaN(e)?t._sapLastGood??0:(t._sapLastGood=e,e)}function Ue(t,e){switch(e){case"checkbox":return t.checked;case"radio":return t.checked?t.value:void 0;case"number":return je(t);case"select-one":return t.value;case"select-multiple":return[...t.selectedOptions].map(n=>n.value);case"hidden":case"text":return t.value;case"leaf":return t.textContent;default:return t.value}}function Ve(t,e,n){switch(e){case"checkbox":t.checked=!!n;break;case"radio":t.checked=String(t.value)===String(n);break;case"number":case"text":case"hidden":t.value=n==null?"":String(n);break;case"select-one":t.value=n==null?"":String(n);break;case"select-multiple":{let r=new Set((Array.isArray(n)?n:[n]).map(String));for(let s of t.options)s.selected=r.has(s.value);break}case"leaf":t.textContent=n==null?"":String(n);break;default:t.value=n==null?"":String(n)}}function te(t){if(t.hasAttribute("transient")){t.removeAttribute("value"),t.removeAttribute("checked"),t.removeAttribute("data-value");return}vt(t)||et(t)}function Ye(t){t.dispatchEvent(new Event("input",{bubbles:!0})),t.dispatchEvent(new Event("change",{bubbles:!0}))}function D(t){let e=He(t);return{el:t,kind:e,read(){return Ue(t,e)},write(n,r={}){Ve(t,e,n),r.noMirror||te(t),r.silent||Ye(t)},mirror(){te(t)}}}var Mt={E01:{slug:"foreign-dialect",behavior:"HALT"},E02:{slug:"moustaches-in-text",behavior:"HALT"},E04:{slug:"duplicate-declaration",behavior:"HALT"},E05:{slug:"reserved-name",behavior:"HALT"},E06:{slug:"global-html-name",behavior:"HALT"},E07:{slug:"calc-cycle",behavior:"ERR"},E08:{slug:"expression-syntax",behavior:"HALT"},E10:{slug:"orphan-item",behavior:"HALT"},E12:{slug:"unknown-state-key",behavior:"ERR"},E15:{slug:"write-to-undeclared-key",behavior:"ERR"},E16:{slug:"write-to-computed-field",behavior:"ERR"},E17:{slug:"unresolvable-action-target",behavior:"HALT"},E18:{slug:"paint-on-form-control",behavior:"HALT"},E20:{slug:"bind-on-non-control",behavior:"HALT"},E22:{slug:"format-type",behavior:"ERR"},E24:{slug:"runtime-expression-throw",behavior:"ERR"},E26:{slug:"circuit-breaker",behavior:"HALT"},E30:{slug:"attr-on-bound-control",behavior:"HALT"},E31:{slug:"password-without-transient",behavior:"HALT"},E32:{slug:"file-bind",behavior:"HALT"},E33:{slug:"dialog-state-open",behavior:"HALT"},E34:{slug:"transient-persist-collision",behavior:"HALT"},W03:{slug:"unknown-colon-attribute",behavior:"WARN"},W04:{slug:"expression-in-when",behavior:"WARN"},W30:{slug:"nonzero-mount-writes",behavior:"WARN"}},Et=["disabled","readonly","required","checked","selected","multiple","open","inert","autofocus","novalidate","hidden"],ft=new Set(["title","style","hidden","lang","dir","translate","class","id","nonce","autofocus","tabindex","contenteditable","spellcheck","draggable","role","slot","part","name","value","type","itemscope","itemtype","itemid","itemprop","itemref"]),St=new Set(["sap","scope","items","item","template","bind","calc","text","show","attr","set","trigger","move","sort","detail","effect","invalid","confirm","transient","default","persist","sortable","editmode"]);function xt(t){if(!t||t.nodeType!==1)return"?";if(t.id)return`${t.tagName.toLowerCase()}#${t.id}`;let e=[],n=t,r=0;for(;n&&n.nodeType===1&&r<4;){let s=n.tagName.toLowerCase();if(n.hasAttribute("sap"))s+="[sap]";else if(n.parentElement){let u=[...n.parentElement.children].filter(c=>c.tagName===n.tagName);u.length>1&&(s+=`:nth-of-type(${u.indexOf(n)+1})`)}if(e.unshift(s),n.hasAttribute("sap"))break;n=n.parentElement,r++}return e.join(" > ")}function ee(t){let e=t.toLowerCase();return/^x-text$|^x-html$/.test(e)?'use text="state.x" (Sap paints text only)':/^x-show$|^v-show$|^v-if$/.test(e)?'use show="expr" (toggles native hidden)':/^x-model$|^v-model$/.test(e)?'use bind="field"':/^@|^x-on:|^v-on:|^on:/.test(e)?"use native onclick + Sap(this) (no event directive)":/^:|^x-bind:class$|^v-bind:class$/.test(e)?'use class:NAME="expr" or attr:NAME="expr"':/^x-for$|^v-for$/.test(e)?'use items="name" on the container and item template on the row':/^x-data$/.test(e)?"declare state with state= / bind / items (no JS state object)":/^x-init$/.test(e)?"use a <script> or onclick + Sap(this)":/^bind:/.test(e)?'use bind="field"; one-way paint is attr:NAME="expr"':/^x-/.test(e)||/^v-/.test(e)?"this is a foreign-dialect attribute; Sap has no x-/v- attributes":null}var nt=class{constructor(e){this.appName=e,this.errors=[],this.warnings=[],this.halted=!1,this.haltReason=null}block(e,n,r={}){let s=(Mt[e]||{}).slug||"error",u={code:e,slug:s,el:xt(n),attr:r.attr||null,expr:r.expr||null,key:r.key||null,problem:r.problem||"",didYouMean:r.didYouMean||null,fix:r.fix||null,phase:r.phase||"runtime"},c=[`
|
|
6
|
+
`+(e[0]==="W"?"sap \u26A0 ":"sap \u2717 ")+e+" "+s];return c.push(` at ${u.el}${u.attr?` \u2014 ${u.attr}="${u.expr??""}"`:""}`),u.problem&&c.push(` problem: ${u.problem}`),u.didYouMean&&c.push(` did you mean: ${u.didYouMean}`),u.fix&&c.push(` fix: ${u.fix}`),console.error(c.join(`
|
|
7
|
+
`)),u}error(e,n,r={}){let s=this.block(e,n,r);return this.errors.push(s),s}warn(e,n,r={}){let s=this.block(e,n,r);return this.warnings.push(s),s}report(){return{ok:this.errors.length===0&&!this.halted,app:this.appName,halted:this.halted,haltReason:this.haltReason,errors:this.errors.slice(),warnings:this.warnings.slice()}}};function X(t,e){t&&t.getAttribute("sap-error")!==e&&t.setAttribute("sap-error",e)}function $t(t){t&&t.hasAttribute("sap-error")&&t.removeAttribute("sap-error")}function lt(t,e){let n=null,r=3;for(let s of e){let u=Ge(t,s);u<r&&(r=u,n=s)}return n}function Ge(t,e){let n=t.length,r=e.length,s=Array.from({length:n+1},(u,c)=>[c,...new Array(r).fill(0)]);for(let u=0;u<=r;u++)s[0][u]=u;for(let u=1;u<=n;u++)for(let c=1;c<=r;c++)s[u][c]=Math.min(s[u-1][c]+1,s[u][c-1]+1,s[u-1][c-1]+(t[u-1]===e[c-1]?0:1));return s[n][r]}var U=null,Nt=!1,rt=null;function ne(t){let e=null;return{kind:"hub",subscribe(n){let r=t.onAnyChange({debounce:0,require:"observed"},n);typeof r=="function"&&(e=r)},suppress(n){t.pause();try{return n()}finally{t.resume()}},teardown(){if(e){try{e()}catch{}e=null}}}}function Xe(){let t=null;return{kind:"native",subscribe(e){t=new MutationObserver(r=>e(Ke(r)));let n=typeof document<"u"&&document.body||typeof document<"u"&&document.documentElement;n&&t.observe(n,{childList:!0,subtree:!0,attributes:!0,characterData:!0})},suppress(e){let n=W("undo");n&&n.pause&&n.pause();try{return e()}finally{t&&t.takeRecords(),n&&n.resume&&n.resume()}},teardown(){t&&(t.disconnect(),t=null)}}}function Ke(t){let e=[];for(let n of t)if(n.type==="attributes"){let r=n.target;r&&r.nodeType===1&&!kt(r)&&e.push({type:"attribute",element:r})}else if(n.type==="characterData"){let r=n.target&&n.target.parentElement;r&&!kt(r)&&e.push({type:"characterData",element:r})}else if(n.type==="childList"){for(let r of n.addedNodes)if(!(r.nodeType!==1||kt(r))&&(e.push({type:"add",element:r}),r.querySelectorAll))for(let s of r.querySelectorAll("*"))kt(s)||e.push({type:"add",element:s});for(let r of n.removedNodes)r.nodeType===1&&e.push({type:"remove",element:r,parent:n.target})}return e}function kt(t){return!!(t.closest&&t.closest("[sap-ignore],[template]"))}function Je(t,e){t.pruneDisconnected();let n=new Set,r=!1;for(let s of e){let u=s.type==="remove"?s.parent:s.element,c=u&&t.appFor(u);c&&n.add(c),s.type==="add"&&s.element&&s.element.nodeType===1&&s.element.hasAttribute&&s.element.hasAttribute("sap")&&!(t.isRegistered&&t.isRegistered(s.element))&&(r=!0)}r&&t.remountIfPresent();for(let s of n)s.root.isConnected&&t.schedule(s,"mutation")}function re(t){if(U)return U.suppress(t);let e=W("undo");if(e&&e.pause&&e.resume){e.pause();try{return t()}finally{e.resume()}}return t()}function Dt(t,e){Nt=!0,U=t,t.subscribe(n=>Je(e,n))}function Rt(t){if(Nt||typeof window>"u"||typeof document>"u")return;let e=W("Mutation");if(e&&typeof e.onAnyChange=="function"){Dt(ne(e),t);return}typeof MutationObserver=="function"&&(Dt(Xe(),t),rt=At(document,Ct,function(){let r=W("Mutation");r&&(rt(),rt=null,U&&U.teardown(),Nt=!1,Dt(ne(r),t))}))}function oe(){if(U)try{U.teardown()}catch{}rt&&typeof document<"u"&&rt(),U=null,Nt=!1,rt=null}var ae=new Set(Et);function ot(t,e={}){if(e.breaker){t.diag.error("E26",t.root,{problem:"recompute loop halted after 50 passes; recent triggers: "+(t._breakerRing||[]).join(", ")}),X(t.root,"loop");return}re(()=>Qe(t,e))}function Qe(t,e){let n=t.root,r={},s=[],u=[],c=[],T=[],E=[],y=new Set;t.diag.errors=[];let l={root:r,state:r,item:null,ownerEl:n,projection:!1};function w(o,i){let h=o.getAttribute(i.name);return h==null&&(h=i.default!=null?i.default:i.type==="num"?"0":i.type==="bool"?"false":"",E.push({el:o,name:i.name,value:ht(G(h,i.type),i.type)})),G(h,i.type)}function k(o,i){let h=P(o.getAttribute("state")||"");o._sapStateDecls=h;for(let p of h){if(p.type==="string"&&ae.has(p.name)&&typeof o[p.name]=="boolean"){i[p.name]=o.hasAttribute(p.name);continue}if(p.transient){i[p.name]=bt(o,p);continue}i[p.name]=w(o,p)}}function L(o,i){if(!o.hasAttribute("bind"))return;let h=o.getAttribute("bind"),p=i.item||i.state,v=D(o);v.kind==="radio"?(h in p||(p[h]=""),o.checked&&(p[h]=o.value)):p[h]=v.read(),o.hasAttribute("transient")&&(o.removeAttribute("value"),o.removeAttribute("checked"))}function b(o,i){for(let h of o.attributes){let p=h.name,v=h.value;if(p.startsWith("calc:"))s.push({owner:i.item||i.state,ownerEl:i.ownerEl,name:p.slice(5),entry:R(v),el:o,ctx:i});else if(p==="text"||p.startsWith("text:"))u.push({el:o,kind:"text",fmt:p.includes(":")?p.slice(5):null,entry:R(v),ctx:i});else if(p==="show")u.push({el:o,kind:"show",entry:R(v),ctx:i});else if(p.startsWith("attr:"))u.push({el:o,kind:"attr",arg:p.slice(5),entry:R(v),ctx:i});else if(p.startsWith("class:"))u.push({el:o,kind:"class",arg:p.slice(6),entry:R(v),ctx:i});else if(p.startsWith("css:"))u.push({el:o,kind:"css",arg:p.slice(4),entry:R(v),ctx:i});else if(p==="effect")c.push({el:o,entry:R(v,!0),ctx:i});else if(p==="invalid")T.push({el:o,entry:R(v),ctx:i});else if(p.startsWith("show-when:")||p.startsWith("option:")){let N=p.slice(p.indexOf(":")+1);y.add(N),u.push({el:o,kind:"when",match:"show",field:N,values:v.split("|"),ctx:i})}else if(p.startsWith("hide-when:")){let N=p.slice(p.indexOf(":")+1);y.add(N),u.push({el:o,kind:"when",match:"hide",field:N,values:v.split("|"),ctx:i})}else if(p.startsWith("option-not:")){let N=p.slice(p.indexOf(":")+1);y.add(N),u.push({el:o,kind:"when",match:"show-not",field:N,values:v.split("|"),ctx:i})}}i.projection&&o.hasAttribute("bind")&&u.push({el:o,kind:"projection",field:o.getAttribute("bind"),ctx:i})}function g(o,i,h){Z(i,"row"),Object.defineProperty(o,"$key",{value:i.id,enumerable:!1}),Object.defineProperty(o,"$index",{value:h,enumerable:!1}),Object.defineProperty(o,"$el",{value:i,enumerable:!1})}function a(o,i,h){k(o,i),o._sapScope=i,!h.projection&&o.hasAttribute("bind")&&L(o,h),b(o,h),o.hasAttribute("items")?x(o,i,h):A(o,i,h)}function A(o,i,h){F(o,(p,v)=>{v?p.hasAttribute("scope")?S(p,i,h):p.hasAttribute("items")?(b(p,h),x(p,i,h)):p.hasAttribute("detail")&&M(p,i,h):(h.projection||L(p,h),b(p,h))})}function S(o,i,h){let p=o.getAttribute("scope"),v={};i[p]=v;let N={root:h.root,state:v,item:null,ownerEl:o,projection:h.projection};a(o,v,N)}function x(o,i,h){let p=o.getAttribute("items"),v=[];i[p]=v,o._sapList=v,O(o).forEach((N,st)=>{let C={};g(C,N,st);let z={root:h.root,state:h.state,item:C,ownerEl:N,projection:h.projection};a(N,C,z),v.push(C)})}function $(o,i){let h=String(o).split("."),p=i.state;for(let v of h)p=p?.[v];if(p===void 0){p=i.root;for(let v of h)p=p?.[v]}return p}function M(o,i,h){for(let Q of P(o.getAttribute("state")||""))Q.name in i||(i[Q.name]=w(o,Q));o._sapScope=i;let p=o.getAttribute("detail")||"",v=/^([\w.]+)\s+by\s+(.+)$/.exec(p);if(!v){o.hidden=!0,o._sapDetailRow=null;return}let N=v[1],st=v[2].trim(),C=$(N,h),z;try{z=j(R(st),{state:i,item:h.item,el:o,root:h.root})}catch{z=void 0}let J=Array.isArray(C)?C.find(Q=>Q&&String(Q.$key)===String(z)):null;if(o._sapDetailRow=J?J.$el:null,!J){o.hidden||(o.hidden=!0);return}o.hidden&&(o.hidden=!1);let qt={root:h.root,state:i,item:J,ownerEl:J.$el,projection:!0};b(o,qt),A(o,J,qt)}if(a(n,r,l),E.length&&y.size)for(let o of E)y.has(o.name)&&o.el.getAttribute(o.name)==null&&o.el.setAttribute(o.name,o.value);let m=new Map;for(let o of s){let i=m.get(o.owner);i||(i={ownerEl:o.ownerEl,list:[]},m.set(o.owner,i)),i.list.push(o)}let d=[...m.values()].sort((o,i)=>ie(i.ownerEl)-ie(o.ownerEl));for(let o of d){let i;try{i=Gt(o.list)}catch(h){t.diag.error("E07",o.list[0].el,{problem:h.message}),i=o.list}for(let h of i)try{h.owner[h.name]=j(h.entry,{state:h.ctx.state,item:h.ctx.item,el:h.el,root:h.ctx.root}),$t(h.el)}catch(p){h.owner[h.name]=void 0,t.diag.error("E24",h.el,{attr:"calc:"+h.name,expr:h.entry.src,problem:String(p.message)}),X(h.el,p.sapCode||"E24")}}let f=0;for(let o of u)f+=en(o,t);for(let o of c)nn(o,t);for(let o of T)rn(o);t._state=r,t._stats={fields:Object.keys(r).filter(o=>typeof r[o]!="function").length,calcs:s.length,paints:u.length,lists:m.size,writes:f},t._lastPass={trigger:e.trigger||"refresh",writes:f},t._debug&&console.log(`sap pass \xB7 trigger: ${t._lastPass.trigger} \xB7 writes ${f}/${u.length}`)}function Ze(t){return t.kind==="text"?t.fmt?"text:"+t.fmt:"text":t.kind==="attr"?"attr:"+t.arg:t.kind==="class"?"class:"+t.arg:t.kind==="css"?"css:"+t.arg:t.kind==="when"?(t.match==="hide"?"hide-when:":t.match==="show-not"?"option-not:":"show-when:")+t.field:t.kind}function It(t,e,n,r){let s=t;for(;s&&s.nodeType===1;){if(s.hasAttribute&&s.hasAttribute(e)){let u=n.includes(s.getAttribute(e));if(r?!u:u)return!0}s=s.parentElement}return!1}function tn(t,e){if(t===t.ownerDocument.activeElement)return 0;let n=D(t),r=n.read(),s=e??"";return String(r)!==String(s)?(n.write(s,{silent:!0}),1):0}function en(t,e){if(t.kind==="projection")return tn(t.el,t.ctx.item?t.ctx.item[t.field]:"");if(t.kind==="when")return se(t,null);let n={state:t.ctx.state,item:t.ctx.item,el:t.el,root:t.ctx.root};try{let r=j(t.entry,n),s=se(t,r);return $t(t.el),s}catch(r){return e.diag.error(r.sapCode==="E22"?"E22":"E24",t.el,{attr:Ze(t),expr:t.entry&&t.entry.src,problem:String(r.message)}),X(t.el,r.sapCode||"E24"),0}}function se(t,e){let n=t.el;switch(t.kind){case"text":{let r=t.fmt!=null?jt(t.fmt,e):e==null?"":String(e);return n.textContent!==r?(n.textContent=r,1):0}case"show":{let r=!e;return n.hidden!==r?(n.hidden=r,1):0}case"when":{let r=W("optionVisibility");if(r&&r._started)return n._sapWhen&&n.hidden?(n.hidden=!1,n._sapWhen=!1,1):0;let s;t.match==="hide"?s=!It(n,t.field,t.values,!1):t.match==="show-not"?s=It(n,t.field,t.values,!0):s=It(n,t.field,t.values,!1),n._sapWhen=!0;let u=!s;return n.hidden!==u?(n.hidden=u,1):0}case"attr":{let r=t.arg;if(ae.has(r)){let u=n.hasAttribute(r);return e&&!u?(n.setAttribute(r,""),1):!e&&u?(n.removeAttribute(r),1):0}let s=typeof e=="boolean"?String(e):e==null?"":String(e);return n.getAttribute(r)!==s?(n.setAttribute(r,s),1):0}case"class":{let r=!!e;return n.classList.contains(t.arg)!==r?(n.classList.toggle(t.arg,r),1):0}case"css":{let r=e==null?"":String(e);return n.style.getPropertyValue("--"+t.arg)!==r?(n.style.setProperty("--"+t.arg,r),1):0}default:return 0}}function nn(t,e){try{j(t.entry,{state:t.ctx.state,item:t.ctx.item,el:t.el,root:t.ctx.root}),$t(t.el)}catch(n){e.diag.error("E24",t.el,{attr:"effect",expr:t.entry&&t.entry.src,problem:String(n.message)}),X(t.el,"E24")}}function rn(t){let e="";try{let n=j(t.entry,{state:t.ctx.state,item:t.ctx.item,el:t.el,root:t.ctx.root});e=typeof n=="string"?n:""}catch{e=""}typeof t.el.setCustomValidity=="function"&&t.el.setCustomValidity(e)}function ie(t){let e=0,n=t;for(;n&&!(n.hasAttribute&&n.hasAttribute("sap"));)n=n.parentElement,e++;return e}var on=new Set(Et),ue=new Set(["calc","text","attr","class","css","set","move","sort","option","option-not","show-when","hide-when","editmode"]),sn=new Set(["show-when","hide-when","option","option-not"]),an=/\b(?:state|item|root)\.|===|!==|&&|\|\||[()]|^\s*!/,ce=new Set(["sap","scope","items","item","template","bind","show","effect","invalid","detail","state","transient","confirm","default","persist","sortable","trigger-add","trigger-remove","trigger-reset","sap-ignore","sap-error","no-save","no-watch","no-undo","no-trigger-autosave","freeze","mutations-ignore","save-remove","save-ignore","save-freeze"]);function un(t){return t.tagName==="INPUT"||t.tagName==="SELECT"||t.tagName==="TEXTAREA"}function Wt(t){return t.hasAttribute("bind")}function cn(t,e){e(t);for(let r of t.children)n(r);function n(r){if(r.nodeType===1&&!((r.hasAttribute("sap-ignore")||r.hasAttribute("template"))&&r.hasAttribute("sap-ignore"))){e(r);for(let s of r.children)n(s)}}}function Tt(t,e){let n=!1,r=(c,T,E)=>{e.error(c,T,E),n=!0},s=t.ownerDocument.createTreeWalker(t,4),u;for(;u=s.nextNode();)if(/\{\{.*\}\}/.test(u.nodeValue||"")){r("E02",u.parentElement||t,{problem:"moustaches in text content are not a Sap feature",fix:'move the expression onto the element: text="state.x"'});break}return cn(t,c=>{let T=c.closest&&c.closest("[detail]");for(let E of[...c.attributes]){let y=E.name,l=ee(y);if(l){r("E01",c,{attr:y,expr:E.value,problem:`"${y}" is a foreign-dialect attribute; Sap has no ${y.split(/[:=]/)[0]} directive`,fix:l+" \u2014 or wrap the subtree in sap-ignore if intentional"});continue}if(y.includes(":")){let w=y.slice(0,y.indexOf(":"));if(ue.has(w)){if(sn.has(w)&&an.test(E.value)){let k=y.slice(y.indexOf(":")+1);e.warn("W04",c,{attr:y,expr:E.value,problem:`${w}: compares the "${k}" attribute against a literal value, not a JS expression`,fix:`use show="${E.value}" for an expression, or a literal like ${w}:${k}="overview"`})}}else{let k=lt(w,[...ue]);e.warn("W03",c,{attr:y,problem:`unknown "${w}:" attribute`,didYouMean:k?`${k}:`:null})}}else if(!ce.has(y)&&!ft.has(y)&&!on.has(y)&&!/^(data-|aria-|on)/.test(y)&&!(y in c)){let w=lt(y,[...ce]);w&&e.warn("W03",c,{attr:y,problem:`unknown "${y}" attribute`,didYouMean:w})}y==="attr:hidden"&&e.warn("W03",c,{attr:y,problem:"attr:hidden paints the wrong attribute",fix:'use show="expr"'}),(y==="attr:value"||y==="attr:checked"||y==="attr:selected")&&Wt(c)&&r("E30",c,{attr:y,problem:"attr: on a bound control collides with persist ownership",fix:"remove it; bind owns this attribute"}),y==="effect"&&Wt(c)&&/\b(value|checked)\s*=[^=]/.test(E.value)&&r("E30",c,{attr:y,expr:E.value,problem:"effect writes value/checked on a bound control (writes a stale value with no synthetic event)",fix:"write through onclick + Sap(this) instead"}),(y==="text"||y.startsWith("text:")||y==="show")&&un(c)&&(y==="show"||r("E18",c,{attr:y,problem:"paint belongs on output elements, not form controls",fix:"move the paint to an <output> or <span>"}))}if(c.hasAttribute("state")){let E=P(c.getAttribute("state")),y=new Set;for(let l of E)l.name.includes("-")&&r("E08",c,{attr:"state",problem:`field "${l.name}" is not a valid identifier (the hyphen parses as subtraction)`,fix:`rename to ${l.name.replace(/-/g,"")}`}),y.has(l.name)&&r("E04",c,{attr:"state",problem:`field "${l.name}" is declared twice in one scope`}),y.add(l.name),St.has(l.name)&&r("E05",c,{attr:"state",problem:`"${l.name}" is a reserved Sap word`}),ft.has(l.name)&&r("E06",c,{attr:"state",problem:`"${l.name}" is a global HTML attribute name; pick another field name`}),l.name==="open"&&c.tagName==="DIALOG"&&r("E33",c,{attr:"state",problem:"dialog open is transient",fix:"use showModal() \u2014 declare state= only on <details> or popovers"})}if(Wt(c)){if(c.hasAttribute("-"),c.tagName==="INPUT"){let E=(c.getAttribute("type")||"text").toLowerCase();E==="file"&&r("E32",c,{attr:"bind",problem:"files never serialize into an HTML file",fix:"use no-save + effect instead of bind"}),E==="password"&&!c.hasAttribute("transient")&&r("E31",c,{attr:"bind",problem:"a password must never serialize into a world-readable file",fix:"add transient to the password input"})}else if(c.tagName!=="SELECT"&&c.tagName!=="TEXTAREA"){let E=c.getAttribute("contenteditable");!(E!=null&&E!=="false")&&c.children.length>0&&r("E20",c,{attr:"bind",problem:"bind on a container element is not a control; a write would overwrite its children",fix:"bind a control (input/select/textarea), a contenteditable, or an empty text leaf"})}}if(c.hasAttribute("transient")&&c.hasAttribute("persist")&&r("E34",c,{problem:"transient and persist are opposite: persist forces the live value into the saved bytes, leaking exactly what transient drops",fix:"remove one \u2014 transient to keep it out of the file, or persist to save it"}),c.hasAttribute("item")&&!c.hasAttribute("template")){let E=c.parentElement;(!E||!E.hasAttribute("items"))&&r("E10",c,{problem:"an [item] must be a direct child of an [items] list",fix:'wrap it in a container with items="name"'})}if(c.hasAttribute("items")&&T&&r("E17",c,{attr:"items",problem:"nested items inside a detail panel is a v1 mount error (nested collections ship in v1.1)"}),c.hasAttribute("items")){let E=t.querySelector(`[trigger-add="${c.getAttribute("items")}"]`);!mt(c)&&O(c).length===0&&E&&r("E17",c,{attr:"items",problem:`trigger-add targets items="${c.getAttribute("items")}" but it has no [item template] to clone`})}}),n&&(e.halted=!0,e.haltReason=e.errors[0]?e.errors[0].code:"halt",X(t,e.haltReason)),!n}var fe="sap-styles",le="[item][template]{display:none!important}[hidden]{display:none!important}[sap-error]{outline:2px solid #e5484d;outline-offset:1px}",Ft=new WeakSet;function fn(t){if(Ft.has(t))return;let e=t.defaultView,n=e&&e.CSSStyleSheet;if(n&&"adoptedStyleSheets"in t)try{let r=new n;r.replaceSync(le),t.adoptedStyleSheets=[...t.adoptedStyleSheets,r],Ft.add(t);return}catch{}if(!t.getElementById(fe)){let r=t.createElement("style");r.id=fe,r.textContent=le,(t.head||t.documentElement).appendChild(r)}Ft.add(t)}var ln=0;function de(){return typeof performance<"u"&&performance.now?performance.now():0}function Pt(t){let e=t.id||t.getAttribute("sap")||`app-${ln++}`,n=new nt(e),r={root:t,name:e,diag:n,_state:null,_stats:null,_lastPass:null,_passes:0,_broken:!1,_mountMs:0,_mountWrites:0};if(!Tt(t,n))return r.halted=!0,r;fn(t.ownerDocument);for(let c of t.querySelectorAll("textarea[data-value]"))yt(c);let u=de();return ot(r,{trigger:"mount"}),r._mountMs=de()-u,r._mountWrites=r._stats?r._stats.writes:0,r._mountWrites>0&&n.warn("W30",t,{problem:`${r._mountWrites} paint(s) ran at mount; the saved file was out of sync with its declared state`,fix:"re-save once so the file mounts clean (a settled file writes nothing)"}),r}function dn(t,e){let n=null;return F(t,r=>{!n&&r.getAttribute("scope")===e&&(n=r)}),n}function pe(t,e,n){let r=I(t)||e;for(;r;){for(let s of P(r.getAttribute("state")||""))if(s.name===n)return{el:r,decl:s};if(r.hasAttribute("sap"))break;r=I(r.parentElement)}return null}function pn(t){return typeof t=="number"?"num":typeof t=="boolean"?"bool":"string"}function me(t){function e(b){let g=t.appFor(b);if(!g)return null;let a=at(b);if(a)return a._sapDetailRow?{ctxEl:a._sapDetailRow,appRec:g,isRow:!0}:{ctxEl:I(a.parentElement)||g.root,appRec:g,isRow:!1};let A=pt(b);if(A&&A.hasAttribute("item"))return{ctxEl:A,appRec:g,isRow:!0};let S=I(b)||g.root;return{ctxEl:S,appRec:g,isRow:S.hasAttribute("item")}}function n(b){let g=typeof b=="string"?document.querySelector(b):b;if(!g||g.nodeType!==1)return null;let a=e(g);return a?L(a.ctxEl,a.appRec,a.isRow):null}function r(b,g,a){let A=tt(b,a);if(A)return D(A).read();let S=it(b,a);if(S)return O(S).map(m=>L(m,g,!0));let x=dn(b,a);if(x)return L(x,g,!1);let $=pe(b,g.root,a);if($)return $.decl.transient?bt($.el,$.decl):G($.el.getAttribute(a),$.decl.type);let M=b._sapScope;return M?M[a]:void 0}function s(b,g,a,A,S){A.transient?Lt(b,A,a):b.setAttribute(g,ht(a,A.type)),t.schedule(S,"set:"+g)}function u(b,g){let a=new Set,A=I(b)||g;for(;A;){for(let S of P(A.getAttribute("state")||""))a.add(S.name);if(A.hasAttribute("sap"))break;A=I(A.parentElement)}return F(b,S=>{let x=S.getAttribute("bind");x&&a.add(x)}),a}function c(b,g,a,A){let S=tt(b,a);if(S){D(S).write(A);return}let x=b;for(;x;){for(let h of x.attributes)if(h.name==="calc:"+a){g.diag.error("E16",x,{attr:"calc:"+a,problem:`"${a}" is a computed field; computed fields are read-only`});return}if(x.hasAttribute("sap"))break;x=x.parentElement}let $=pe(b,g.root,a);if($){s($.el,a,A,$.decl,g);return}let M=u(b,g.root);M.delete(a);let m=a.length>=4?lt(a,[...M]):null;if(m){g.diag.error("E12",b,{key:a,problem:`unknown state key "${a}"`,didYouMean:m});return}if(St.has(a)||ft.has(a)){g.diag.error("E15",b,{key:a,problem:`cannot write undeclared field "${a}" \u2014 it is a reserved/global name and cannot become state`,fix:"pick a different field name, or declare it explicitly in a state= attribute"});return}let d=g.root,f=pn(A),o=d.getAttribute("state")||"",i=f==="string"?a:`${a}:${f}`;d.setAttribute("state",o?`${o} ${i}`:i),s(d,a,A,{name:a,type:f,transient:!1},g)}function T(b){let g=a=>{a.id&&(a.id="",Z(a,"row")),a.hasAttribute("sap-error")&&a.removeAttribute("sap-error")};b.id="",Z(b,"row"),b.querySelectorAll("[id]").forEach(g)}function E(b,g,a){let A=ut(g.root,b,a);if(!A)return g.diag.error("E17",b,{problem:`cannot resolve a list named "${a}" from here`}),null;let S=mt(A);if(!S)return g.diag.error("E17",A,{problem:`items="${a}" has no [item template] to clone`}),null;let x=S.cloneNode(!0);return x.removeAttribute("template"),T(x),A.appendChild(x),t.schedule(g,"trigger-add:"+a),L(x,g,!0)}function y(b,g){F(b,a=>{if(a.hasAttribute("bind")){let A=D(a),S=a.getAttribute("default");A.kind==="checkbox"||A.kind==="radio"?A.write(S!=null?S===""||S==="true"||a.value===S:a.hasAttribute("checked")):A.write(S??(a.getAttribute("value")||""))}});for(let a of P(b.getAttribute("state")||"")){let A=a.default!=null?a.default:a.type==="num"?"0":a.type==="bool"?"false":"";a.transient?Lt(b,a,G(A,a.type)):b.setAttribute(a.name,A)}t.schedule(g,"trigger-reset")}function l(b,g){if(!b.isConnected)throw new Error("stale row handle: $remove() on a removed row");b.remove(),t.schedule(g,"trigger-remove")}function w(b,g,a){if(!b.isConnected)throw new Error("stale row handle: $move() on a removed row");let A=null;if(a&&a.nodeType===1?A=a:typeof a=="string"&&(A=ut(g.root,b,a)),!A){g.diag.error("E17",b,{problem:`$move() cannot resolve target "${a}"`});return}t.moveInto(A,b),t.schedule(g,"trigger-move")}function k(b){let g=b.parentElement;return g?O(g).indexOf(b):-1}function L(b,g,a){let A={get $el(){return b},get $key(){return Z(b,a?"row":"scope")},get $index(){return k(b)},$add(x){return E(b,g,x)},$reset(){return y(b,g),S},$remove(){l(b,g)},$move(x){w(b,g,x)},get $appRec(){return g}},S=new Proxy(A,{get(x,$){return typeof $=="symbol"||$[0]==="$"?x[$]:r(b,g,$)},set(x,$,M){return typeof $=="string"&&$[0]==="$"?(x[$]=M,!0):(c(b,g,$,M),!0)},has(x,$){return typeof $=="string"&&$[0]==="$"?$ in x:r(b,g,$)!==void 0}});return S}return{Sap:n,contextElFor:e,readField:r,writeField:c,makeProxy:L}}var mn=["trigger-add","trigger-remove","trigger-reset"];function hn(t){if(t.nodeType!==1)return!1;for(let e of t.attributes){let n=e.name;if(n.startsWith("set:")||n.startsWith("move:")||n.startsWith("sort:")||mn.includes(n))return!0}return!1}function bn(t,e){let n=t,r=e.parentElement;for(;n&&n!==r;){if(n.nodeType===1&&hn(n)&&!(n.tagName==="FORM"&&n.hasAttribute("trigger-add")))return n;n=n.parentElement}return null}function he(t,e){let{Sap:n}=e;function r(m,d){let f=null,o=at(m);if(o&&o._sapDetailRow)f=o._sapDetailRow._sapScope||null;else{let p=pt(m);p&&p.hasAttribute("item")&&(f=p._sapScope||null)}return{state:(I(m)||d.root)._sapScope||d._state||{},item:f,el:m,root:d._state||{}}}function s(m,d,f){if(!m.hasAttribute("confirm")){f();return}let o=m.getAttribute("confirm"),i=o,h=R(o);if(!h.error)try{let N=j(h,r(m,d));(typeof N=="string"||typeof N=="number")&&(i=String(N))}catch{}let p=Jt();if(!p){window.confirm(i)&&f();return}if(m._sapGatePending)return;m._sapGatePending=!0;let v=()=>{m._sapGatePending=!1};p(i,()=>{v(),f()}).catch(v)}function u(m,d){for(let f of m.attributes){if(!f.name.startsWith("set:"))continue;let o=f.name.slice(4),i=R(f.value);if(i.error){d.diag.error("E08",m,{attr:f.name,expr:f.value,problem:String(i.error.message)});continue}let h;try{h=j(i,r(m,d))}catch(v){d.diag.error("E24",m,{attr:f.name,expr:f.value,problem:String(v.message)});continue}let p=n(m);p&&(p[o]=h)}}function c(m,d){let f=m.closest("[item]");if(!f)return;let o=O(f.parentElement),i=o.indexOf(f);d==="up"&&i>0?t.placeBefore(f,o[i-1]):d==="down"&&i<o.length-1&&t.placeBefore(o[i+1],f)}function T(m,d,f){if(d)return ut(f.root,m,d);let o=m;for(;o;){if(o.hasAttribute&&o.hasAttribute("items"))return o;o=o.parentElement}let i=I(m)||f.root,h=[];return F(i,p=>{p.hasAttribute("items")&&h.push(p)}),h[0]||null}function E(m,d){let f=m==null||m==="",o=d==null||d==="";if(f&&o)return 0;if(f)return 1;if(o)return-1;let i=Number(m),h=Number(d);return!Number.isNaN(i)&&!Number.isNaN(h)?i-h:String(m)<String(d)?-1:String(m)>String(d)?1:0}function y(m,d,f,o){let i=T(m,f,o);if(!i){o.diag.error("E17",m,{attr:"sort:"+d,problem:`no items list resolvable for sort:${d}`});return}let h=O(i),p=C=>C._sapScope?C._sapScope[d]:void 0,v=[...h].sort((C,z)=>E(p(C),p(z))),st=v.every((C,z)=>C===h[z])?[...v].reverse():v;for(let C of st)t.moveInto(i,C);t.schedule(o,"sort:"+d)}function l(m){if(!m||m.hidden)return;let d=m.querySelector("[bind]:not([type=hidden]), [contenteditable]");d&&typeof d.focus=="function"&&d.focus()}function w(m,d){s(m,d,()=>{let f=n(m);for(let o of[...m.attributes]){let i=o.name;if(i==="trigger-remove")f&&f.$remove();else if(i==="trigger-reset")f&&f.$reset();else if(i==="trigger-add"){let h=f&&f.$add(o.value);h&&l(h.$el)}else i==="move:up"?(c(m,"up"),t.schedule(d,"move:up")):i==="move:down"?(c(m,"down"),t.schedule(d,"move:down")):i.startsWith("move:to")?f&&f.$move(o.value):i.startsWith("sort:")&&y(m,i.slice(5),o.value,d)}[...m.attributes].some(o=>o.name.startsWith("set:"))&&u(m,d)})}function k(m){let d=m.target;if(!d||d.nodeType!==1)return;let f=t.appFor(d);if(!f)return;let o=bn(d,f.root);o&&w(o,f)}function L(m){let d=D(m),f=m.getAttribute("default");d.kind==="checkbox"?d.write(f===""||f==="true"):d.write(f??"")}function b(m,d,f){let o=n(m);if(!o)return;let i=o.$add(f);if(!i)return;let h=[];F(m,p=>{p.hasAttribute("bind")&&h.push(p)});for(let p of h){let v=tt(i.$el,p.getAttribute("bind"));v&&D(v).write(D(p).read())}h.forEach(L),h.length?typeof h[0].focus=="function"&&h[0].focus():l(i.$el)}function g(m){let d=m.target;if(!d||!d.hasAttribute||!d.hasAttribute("trigger-add"))return;let f=t.appFor(d);f&&(m.preventDefault(),s(d,f,()=>b(d,f,d.getAttribute("trigger-add"))))}function a(m){let d=m.target,f=t.appFor(d);f&&setTimeout(()=>{d.querySelectorAll("[bind]").forEach(o=>{o.dispatchEvent(new Event("input",{bubbles:!0})),o.dispatchEvent(new Event("change",{bubbles:!0}))}),t.schedule(f,"reset")},0)}function A(m){let d=t.appFor(m.target);d&&t.schedule(d,"toggle")}function S(m){let d=m.target;if(!d||d.nodeType!==1)return;let f=t.appFor(d);if(!f)return;d.hasAttribute("persist")&&!vt(d)&&et(d);let o=at(d);if(o&&o._sapDetailRow&&d.hasAttribute("bind")){let i=tt(o._sapDetailRow,d.getAttribute("bind"));if(i&&i!==d){D(i).write(D(d).read());return}}t.schedule(f,m.type+" "+(d.id||d.tagName.toLowerCase()))}function x(m){let d=m.detail||{};for(let f of[d.from,d.to,m.target]){if(!f||f.nodeType!==1)continue;let o=t.appFor(f);o&&t.schedule(o,"sorted")}}function $(m){if(m.key!=="ArrowUp"&&m.key!=="ArrowDown")return;let d=m.target;if(!d||d.nodeType!==1||d.tagName!=="INPUT"||!d.hasAttribute("bind")||!d.hasAttribute("step"))return;let f=(d.getAttribute("type")||"text").toLowerCase();if(f!=="text"&&f!=="tel"&&f!=="search"||!t.appFor(d))return;m.preventDefault();let i=B(d.getAttribute("step"))||1,h=m.key==="ArrowUp"?1:-1,p=B(d.value)+i*(m.shiftKey?10:1)*h,v=d.getAttribute("min"),N=d.getAttribute("max");v!==null&&v!==""&&p<B(v)&&(p=B(v)),N!==null&&N!==""&&p>B(N)&&(p=B(N)),D(d).write(String(Number(p.toFixed(2))))}function M(m=document){m.addEventListener("click",k),m.addEventListener("submit",g),m.addEventListener("reset",a),m.addEventListener("toggle",A,!0),m.addEventListener("input",S),m.addEventListener("change",S),m.addEventListener("clay:sorted",x),m.addEventListener("keydown",$)}return{install:M}}var be=/^(set:|move:|sort:|trigger-add$|trigger-remove$|trigger-reset$)/;function Ot(t){return`${t.tagName.toLowerCase()}[sap]`}function gn(t){let e=0;for(let n of t.querySelectorAll("*"))for(let r of n.attributes)if(be.test(r.name)){e++;break}for(let n of t.attributes)if(be.test(n.name)){e++;break}return e}function ge(t){let e=[],n=r=>{for(let s of r.attributes){let u=s.name;(u.startsWith("calc:")||u==="text"||u.startsWith("text:")||u==="show"||u.startsWith("attr:")||u.startsWith("class:")||u.startsWith("css:")||u==="effect"||u==="invalid"||u.startsWith("set:")||u==="detail")&&e.push({el:r,attr:u,src:s.value})}};n(t);for(let r of t.querySelectorAll("*"))n(r);return e}function we(t){function e(l){let w=l._stats||{},k=l.root;return{root:Ot(k),fields:w.fields||0,calcs:w.calcs||0,paints:w.paints||0,actions:gn(k),lists:(k.hasAttribute("items")?1:0)+k.querySelectorAll("[items]").length,rows:k.querySelectorAll("[item]:not([template])").length,warnings:l.diag.warnings.length,errors:l.diag.errors.length,mountWrites:l._mountWrites||0,ms:Math.round((l._mountMs||0)*10)/10,passes:l._passes||0,lastPass:l._lastPass||null,ok:l.diag.errors.length===0&&!l.halted}}function n(){let l=t.apps().map(e);return{ok:l.every(w=>w.ok),apps:l}}function r(l){let w=e(l);return w.ok?`sap \u2713 ${w.root} \xB7 fields ${w.fields} \xB7 calcs ${w.calcs} \xB7 paints ${w.paints} \xB7 actions ${w.actions} \xB7 lists ${w.lists} \xB7 rows ${w.rows} \xB7 warnings ${w.warnings} \xB7 mount writes ${w.mountWrites} \xB7 ${w.ms}ms`:`sap \u2717 ${w.root} \xB7 errors ${w.errors} \xB7 warnings ${w.warnings} \xB7 ${w.ms}ms`}function s(){for(let l of t.apps()){let w=r(l);l.diag.errors.length||l.halted?console.error(w):console.log(w)}}function u(){let l=[],w=[];for(let k of t.apps())l.push(...k.diag.errors),w.push(...k.diag.warnings);return{ok:l.length===0,errors:l,warnings:w,counts:{errors:l.length,warnings:w.length}}}function c(l){return l?typeof l=="string"?document.querySelector(l):l.nodeType===1?l:null:null}function T(l,w){let k=c(l);if(!k)return console.warn("sap why: element not found"),null;let L=[`sap why <${k.tagName.toLowerCase()}> \u2014 ${xt(k)}`],b=[...k.attributes].filter(a=>/^(bind|text|show|effect|invalid|detail|calc:|text:|attr:|class:|css:|set:|state|items|scope)/.test(a.name));for(let a of b)L.push(` ${a.name}="${a.value}"`);let g=k;for(;g&&!g._sapScope;)g=g.parentElement;if(g&&g._sapScope){let a=g._sapScope,A=w?[w]:Object.keys(a);L.push(" reads:");for(let S of A){let x=a[S];typeof x!="function"&&L.push(` ${S} = ${JSON.stringify(Array.isArray(x)?`[${x.length} rows]`:x)}`)}}return L.push(" serialization: textContent and value/checked attributes save with the file; reads live from properties"),console.log(L.join(`
|
|
8
|
+
`)),null}function E(l){let w=l===void 0?!0:!!l;for(let k of t.apps())k._debug=w;return console.log(`sap debug ${w?"on":"off"} \u2014 per-pass headers will ${w?"":"no longer "}log`),w}function y(){let l=[],w=0;for(let a of t.apps()){let A=a.root,S=Ot(A);w++;let x=new nt(a.name);Tt(A,x);for(let f of x.errors)l.push({code:f.code,severity:"error",message:`${S}: ${f.code} ${f.slug} at ${f.el}`});for(let f of x.warnings)l.push({code:f.code,severity:"warn",message:`${S}: ${f.code} ${f.slug} at ${f.el}`});w++,ot(a,{trigger:"doctor-dryrun"});let $=a._stats?a._stats.writes:0;$>0&&l.push({code:"W30",severity:"warn",message:`${S}: dry recompute wrote ${$} cells on a quiet page; an element is stale or non-idempotent`}),w++;let M=ge(A).map(f=>f.src).join(" \0 "),m=[];for(let f of[A,...A.querySelectorAll("[state]")])for(let o of P(f.getAttribute("state")||""))m.push(o.name);for(let f of m)new RegExp(`(state|item)\\.${f}\\b`).test(M)||l.push({code:"I33",severity:"info",message:`${S}: field "${f}" is declared but read nowhere (dead state)`});w++;let d=new Map;for(let f of A.querySelectorAll("[id]"))d.set(f.id,(d.get(f.id)||0)+1);for(let[f,o]of d)o>1&&l.push({code:"W32",severity:"warn",message:`${S}: duplicate id "${f}" (${o} elements) \u2014 clone/edit collision`});w++;for(let f of ge(A))f.src.length>120&&l.push({code:"I33",severity:"info",message:`${S}: ${f.attr} expression is ${f.src.length} chars; consider a calc: field`});w++;for(let f of A.querySelectorAll("[text], [text\\:num]")){let o=f.textContent||"";/\.\d{5,}/.test(o)&&l.push({code:"I33",severity:"info",message:`${S}: ${xt(f)} paints >4 decimals; consider text:FMT`})}}let k=l.filter(a=>a.severity==="error").length,L=l.filter(a=>a.severity==="warn").length,b=l.filter(a=>a.severity==="info").length;console.log(`sap doctor \xB7 ${t.apps().map(a=>Ot(a.root)).join(", ")} \xB7 errors ${k} \xB7 warnings ${L} \xB7 info ${b} \xB7 ${w} checks \xB7 0ms`);for(let a of l)(a.severity==="error"?console.error:a.severity==="warn"?console.warn:console.info)(` ${a.severity==="error"?"\u2717":a.severity==="warn"?"\u26A0":"\xB7"} ${a.message}`);return l}return{status:n,report:u,why:T,debug:E,doctor:y,greenLine:r,printGreenLines:s,REGISTRY:Mt}}var wn="0.2.0",q=new Map,V=[],Bt=zt(ot);function yn(t){let e=t;for(;e;){if(e.nodeType===1&&e.hasAttribute&&e.hasAttribute("sap"))return q.get(e)||null;e=e.parentNode&&e.parentNode.host?e.parentNode.host:e.parentElement}return null}function An(){for(let t=V.length-1;t>=0;t--){let e=V[t];e.root.isConnected||(q.delete(e.root),V.splice(t,1))}}function vn(t,e){if(t.moveBefore)try{t.moveBefore(e,null);return}catch{}t.appendChild(e)}function En(t,e){let n=e.parentElement;if(n){if(n.moveBefore)try{n.moveBefore(t,e);return}catch{}n.insertBefore(t,e)}}var K={apps:()=>V.slice(),appFor:yn,isRegistered:t=>q.has(t),pruneDisconnected:An,schedule:(t,e)=>Bt.schedule(t,e),runNow:(t,e)=>Bt.runNow(t,e),moveInto:vn,placeBefore:En,remountIfPresent:()=>dt()},Ae=me(K),Sn=he(K,Ae),Y=we(K),ye=!1;function ve(){ye||(ye=!0,Sn.install(document),Zt(K))}function dt(t=document){ve(),Rt(K);let e=t.querySelectorAll("[sap]"),n=[];for(let r of e){if(q.has(r))continue;let s=Pt(r);q.set(r,s),V.push(s),n.push(s)}for(let r of n){let s=Y.greenLine(r);r.diag.errors.length||r.halted?console.error(s):console.log(s)}return n}function Ee(t){if(ve(),Rt(K),!t)return dt();let e=typeof t=="string"?document.querySelector(t):t;if(!e)return null;if(q.has(e))return q.get(e);let n=Pt(e);q.set(e,n),V.push(n);let r=Y.greenLine(n);return n.diag.errors.length||n.halted?console.error(r):console.log(r),n}var _=Ae.Sap;_.version=wn;_.refresh=function(){for(let e of V)e.root.isConnected&&Bt.runNow(e,"refresh")};_.batch=Qt;_.status=Y.status;_.report=Y.report;_.why=Y.why;_.debug=Y.debug;_.doctor=Y.doctor;_.greenLine=Y.greenLine;_.formats=ct;_.serializeControlToAttributes=et;_.finalizeControlForSave=Kt;_.rehydrateControlFromAttributes=yt;_.mount=Ee;_.config=function(e={}){return e.formats&&Object.assign(ct,e.formats),_};_._registry=q;_._reset=function(){q.clear(),V.length=0,oe()};function xn(){typeof document>"u"||(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>dt()):dt())}xn();typeof window<"u"&&(window.Sap=_);var $n=_;return Te(kn);})();
|
|
9
9
|
if (typeof window !== 'undefined' && Sap && Sap.default) window.Sap = Sap.default;
|
|
10
10
|
var sapDefault = Sap.default;
|
|
11
11
|
window.clay = window.clay || {};
|
package/src/attrs/onaftersave.js
CHANGED
|
@@ -5,9 +5,20 @@
|
|
|
5
5
|
* Only fires on 'clay:save-saved' events (not on error/offline).
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* <span onaftersave="this.innerText = event.detail.msg"></span>
|
|
8
|
+
* <span clay="no-trigger-autosave" onaftersave="this.innerText = event.detail.msg"></span>
|
|
9
9
|
* <link href="styles.css" onaftersave="cacheBust(this)">
|
|
10
10
|
*
|
|
11
|
+
* MARK WHAT YOU MUTATE `no-trigger-autosave`.
|
|
12
|
+
* These handlers run after the save baseline has been taken, so anything they write
|
|
13
|
+
* to the live DOM reads as a change the user made and leaves the page permanently
|
|
14
|
+
* dirty: autosave loops, and the close-tab warning never clears. The token strips
|
|
15
|
+
* the element from every comparison capture, which is what stops that.
|
|
16
|
+
* `cacheBust()` marks its own target, so the second example needs nothing. A handler
|
|
17
|
+
* that mutates some OTHER element has to mark that element itself.
|
|
18
|
+
*
|
|
19
|
+
* (The alternative — re-reading the whole live DOM after handlers run — is what
|
|
20
|
+
* clayjs used to do, and it silently discarded anything typed during a save.)
|
|
21
|
+
*
|
|
11
22
|
* The event.detail object contains:
|
|
12
23
|
* - status: 'saved'
|
|
13
24
|
* - msg: string (e.g., 'Saved')
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { addRegionToken } from '../lib/region-policy.js';
|
|
2
|
+
|
|
1
3
|
function swapElement(el) {
|
|
2
4
|
const attr = el.hasAttribute('href') ? 'href' : el.hasAttribute('src') ? 'src' : null;
|
|
3
5
|
if (!attr) return;
|
|
@@ -12,10 +14,8 @@ function swapElement(el) {
|
|
|
12
14
|
newEl.setAttribute(name, value);
|
|
13
15
|
}
|
|
14
16
|
newEl.setAttribute(attr, isSameOrigin ? url.pathname + url.search : url.href);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
tokens.add("no-undo");
|
|
18
|
-
newEl.setAttribute("clay", Array.from(tokens).join(" "));
|
|
17
|
+
addRegionToken(newEl, "no-trigger-autosave");
|
|
18
|
+
addRegionToken(newEl, "no-undo");
|
|
19
19
|
|
|
20
20
|
el.insertAdjacentElement('afterend', newEl);
|
|
21
21
|
|