@epa-wg/custom-element-dist 0.0.35 → 0.0.37
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/.ai/mcp/mcp.json +0 -0
- package/.claude/settings.local.json +4 -1
- package/.storybook/preview.ts +7 -1
- package/.yarn/install-state.gz +0 -0
- package/README.md +5 -5
- package/dist/{custom-element-BzDjIYMe.js → custom-element-BqBcmDiN.js} +5 -2
- package/dist/custom-element-bundle.cjs +1 -1
- package/dist/custom-element-bundle.js +2 -2
- package/dist/{custom-element-Bssk9jRy.cjs → custom-element-jpOyXHF6.cjs} +1 -1
- package/dist/demo/for-each.html +213 -0
- package/package.json +4 -4
- package/public/demo/for-each.html +213 -0
- package/src/custom-element/custom-element.js +3 -0
- package/src/custom-element/demo/for-each.html +213 -0
- package/src/custom-element/ide/web-types-dce.json +1 -1
- package/src/custom-element/ide/web-types-xsl.json +1 -1
- package/src/custom-element/index.html +2 -1
- package/src/material/theme/colors-native.html +32 -1
- package/src/mocks/versions.mock.ts +1 -1
- package/src/stories/__screenshots__/http-request.test.ts/http-request-http-request-headers-and-response-status-and-headers-1.png +0 -0
- package/src/stories/__screenshots__/http-request.test.ts/http-request-http-request-with-delayed--5-seconds-response-1.png +0 -0
- package/src/stories/__screenshots__/http-request.test.ts/http-request-http-request-with-error-1.png +0 -0
- package/src/stories/__screenshots__/http-request.test.ts/http-request-url-and-slice-1.png +0 -0
- package/src/stories/__screenshots__/http-request.test.ts/http-request-url-change-1.png +0 -0
- package/src/stories/__screenshots__/slots.test.stories.ts/slots-slots-TemplateWithAttributesAndCondition-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-BooleanAndCondition-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-BooleanOrCondition-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseNoAttribute-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseOtherwise-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseSecondWhen-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-ChooseWhenOtherwise-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-IfFalse-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-IfNotExists-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-IfTrue-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleIfOrderingIssue-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-MultipleInstances-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NestedConditions-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NestedConditionsInactive-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NumericComparison-1.png +0 -0
- package/src/stories/__screenshots__/xslt-conditionals.test.stories.ts/xslt-conditionals-xslt-conditionals-NumericComparisonLow-1.png +0 -0
- package/src/stories/__screenshots__/xslt-for-each.test.stories.ts/xslt-for-each-xslt-for-each-MultipleIfOrderingIssue-1.png +0 -0
- package/src/stories/__screenshots__/xslt-if.test.stories.ts/xslt-if-xslt-if-MultipleIfOrderingIssue-1.png +0 -0
- package/src/stories/attributes.test.stories.ts +2 -0
- package/src/stories/dom-merge.test.stories.ts +1 -0
- package/src/stories/external-template.test.stories.ts +5 -3
- package/src/stories/http-request.stories.ts +2 -1
- package/src/stories/module-url.test.stories.ts +1 -0
- package/src/stories/slice-events.test.stories.ts +3 -0
- package/src/stories/xslt-for-each.test.stories.ts +99 -1
- package/storybook-static/assets/{Color-F6OSRLHC-DeDlDLjU.js → Color-F6OSRLHC-FZZzFn7T.js} +1 -1
- package/storybook-static/assets/{Configure-CH_tIP5N.js → Configure-DyfktOJO.js} +1 -1
- package/storybook-static/assets/{DocsRenderer-CFRXHY34-Bc9EPsUI.js → DocsRenderer-CFRXHY34-5isVpCzj.js} +2 -2
- package/storybook-static/assets/{attributes.test.stories-BtamFQkF.js → attributes.test.stories-CrDC-RXf.js} +4 -3
- package/storybook-static/assets/{css.test.stories-BfNxLgwr.js → css.test.stories-ChWnZJwa.js} +1 -1
- package/storybook-static/assets/{custom-element-CnmjNo0g.js → custom-element-wuk8gYiP.js} +1 -1
- package/storybook-static/assets/{dom-merge.test.stories-DxnitrLK.js → dom-merge.test.stories-DkarPqD_.js} +2 -2
- package/storybook-static/assets/{external-template.test.stories-BTsww7B0.js → external-template.test.stories-DCboR8sG.js} +17 -16
- package/storybook-static/assets/{form.test.stories-DNJFtPJb.js → form.test.stories-BjeeUu0b.js} +1 -1
- package/storybook-static/assets/handlers-B7UMnC7v.js +291 -0
- package/storybook-static/assets/{http-request.stories-DgrBNle8.js → http-request.stories-WIldq1MC.js} +2 -2
- package/storybook-static/assets/{iframe-DiVWehoI.js → iframe-CBHPj1E5.js} +2 -2
- package/storybook-static/assets/{index-w6iX3YlR.js → index-BL0FQnAE.js} +3 -3
- package/storybook-static/assets/{index-CdEbhcV9.js → index-CzwPLrca.js} +1 -1
- package/storybook-static/assets/{local-storage.test.stories-Hwq80yUr.js → local-storage.test.stories-DLMK0p2s.js} +1 -1
- package/storybook-static/assets/{location-element.test.stories-mEhZzm7x.js → location-element.test.stories-BroqoLMS.js} +1 -1
- package/storybook-static/assets/{module-url.test.stories-Bj46iT0V.js → module-url.test.stories-B-0dibET.js} +2 -2
- package/storybook-static/assets/{preview-BjbXcJci.js → preview-BG24UPL5.js} +2 -2
- package/storybook-static/assets/preview-C1KnQPMW.js +50 -0
- package/storybook-static/assets/{set-url.test.stories-hzxLcqmm.js → set-url.test.stories-Dhq4YQyr.js} +1 -1
- package/storybook-static/assets/{slice-events.test.stories-DVyXFRU1.js → slice-events.test.stories-BZJGIFku.js} +17 -15
- package/storybook-static/assets/{slots.test.stories-CS544nS4.js → slots.test.stories-DKivHwZH.js} +1 -1
- package/storybook-static/assets/{version-select.test.stories-D36nfYBq.js → version-select.test.stories-Dntyd7qb.js} +1 -1
- package/storybook-static/assets/{xslt-conditionals.test.stories-BS1PTIHe.js → xslt-conditionals.test.stories-Iq5iQNRj.js} +1 -1
- package/storybook-static/assets/{xslt-for-each.test.stories-CtPS20RK.js → xslt-for-each.test.stories-BMygBmj8.js} +132 -12
- package/storybook-static/assets/{xslt-if.test.stories-DcHrAMSY.js → xslt-if.test.stories-CVrFWdAX.js} +1 -1
- package/storybook-static/demo/for-each.html +213 -0
- package/storybook-static/iframe.html +1 -1
- package/storybook-static/index.json +1 -1
- package/storybook-static/project.json +1 -1
- package/vite.config.js +2 -1
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -12
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -176
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/coverage.svg +0 -10
- package/coverage/src/custom-element/coverage.svg +0 -10
- package/coverage/src/custom-element/custom-element.js/coverage.svg +0 -10
- package/coverage/src/custom-element/custom-element.js.html +0 -3034
- package/coverage/src/custom-element/http-request.js/coverage.svg +0 -10
- package/coverage/src/custom-element/http-request.js.html +0 -373
- package/coverage/src/custom-element/index.html +0 -176
- package/coverage/src/custom-element/local-storage.js/coverage.svg +0 -10
- package/coverage/src/custom-element/local-storage.js.html +0 -361
- package/coverage/src/custom-element/location-element.js/coverage.svg +0 -10
- package/coverage/src/custom-element/location-element.js.html +0 -412
- package/coverage/src/custom-element/module-url.js/coverage.svg +0 -10
- package/coverage/src/custom-element/module-url.js.html +0 -187
- package/coverage/src/index.html +0 -116
- package/coverage/src/material/theme/colors.js/coverage.svg +0 -10
- package/coverage/src/material/theme/colors.js.html +0 -217
- package/coverage/src/material/theme/coverage.svg +0 -10
- package/coverage/src/material/theme/index.html +0 -116
- package/coverage/src/mocks/coverage.svg +0 -10
- package/coverage/src/mocks/handlers.ts/coverage.svg +0 -10
- package/coverage/src/mocks/handlers.ts.html +0 -196
- package/coverage/src/mocks/index.html +0 -116
- package/coverage/src/stories/coverage.svg +0 -10
- package/coverage/src/stories/frame.canvas.ts/coverage.svg +0 -10
- package/coverage/src/stories/frame.canvas.ts.html +0 -175
- package/coverage/src/stories/http-request.stories.ts/coverage.svg +0 -10
- package/coverage/src/stories/http-request.stories.ts.html +0 -817
- package/coverage/src/stories/index.html +0 -146
- package/coverage/src/stories/testStoryBook.ts/coverage.svg +0 -10
- package/coverage/src/stories/testStoryBook.ts.html +0 -169
- package/coverage/src/sum.ts/coverage.svg +0 -10
- package/coverage/src/sum.ts.html +0 -94
- package/storybook-static/assets/handlers-Dvg8CAeR.js +0 -470
- package/storybook-static/assets/preview-CfuT8gak.js +0 -50
package/.ai/mcp/mcp.json
ADDED
|
File without changes
|
package/.storybook/preview.ts
CHANGED
|
@@ -2,7 +2,13 @@ import {initialize, mswLoader} from 'msw-storybook-addon';
|
|
|
2
2
|
|
|
3
3
|
import {handlers} from "../src/mocks/handlers";
|
|
4
4
|
|
|
5
|
-
initialize({
|
|
5
|
+
initialize({
|
|
6
|
+
onUnhandledRequest: 'bypass',
|
|
7
|
+
serviceWorker: {
|
|
8
|
+
url: './mockServiceWorker.js',
|
|
9
|
+
},
|
|
10
|
+
quiet: true, // Suppress MSW warnings in console
|
|
11
|
+
});// SB
|
|
6
12
|
|
|
7
13
|
const preview = {
|
|
8
14
|
parameters: {
|
package/.yarn/install-state.gz
CHANGED
|
Binary file
|
package/README.md
CHANGED
|
@@ -27,8 +27,8 @@ CDN version of StoryBook.
|
|
|
27
27
|
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
|
|
28
28
|
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element-dist.svg
|
|
29
29
|
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element-dist
|
|
30
|
-
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
31
|
-
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
32
|
-
[sb-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
33
|
-
[bundle-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
34
|
-
[cem-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
30
|
+
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/coverage/src/custom-element/coverage.svg
|
|
31
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/coverage/src/custom-element/index.html
|
|
32
|
+
[sb-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/storybook-static/index.html
|
|
33
|
+
[bundle-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/dist/custom-element-bundle.js
|
|
34
|
+
[cem-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.37/src/material/components.html
|
|
@@ -412,8 +412,11 @@ const $e = (e) => [...e?.matchAll(/([^{}]*)(\{)([^}]+)}([^{}]*)/g)].map((t) => `
|
|
|
412
412
|
for (; e.firstChild; )
|
|
413
413
|
t.append(e.firstChild);
|
|
414
414
|
const l = "if,choose,for-each".includes(e.localName) ? (() => {
|
|
415
|
-
const a =
|
|
416
|
-
|
|
415
|
+
const a = e.parentElement;
|
|
416
|
+
if (!a || a.childNodes.length === 1)
|
|
417
|
+
return t;
|
|
418
|
+
const n = C("span");
|
|
419
|
+
return n.append(t), n;
|
|
417
420
|
})() : t;
|
|
418
421
|
if (e.parentElement)
|
|
419
422
|
e.parentElement.replaceChild(l, e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./custom-element-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./custom-element-jpOyXHF6.cjs"),l=require("./http-request-DSaowcG1.cjs"),t=require("./local-storage-78EivJ_B.cjs"),a=require("./location-element-DRB7hCwA.cjs");exports.CustomElement=e.CustomElement;exports.appendByDceId=e.appendByDceId;exports.assureSlices=e.assureSlices;exports.assureUID=e.assureUID;exports.assureUnique=e.assureUnique;exports.cloneAs=e.cloneAs;exports.createXsltFromDom=e.createXsltFromDom;exports.deepEqual=e.deepEqual;exports.default=e.CustomElement;exports.evalCurly=e.evalCurly;exports.event2slice=e.event2slice;exports.merge=e.merge;exports.mergeAttr=e.mergeAttr;exports.mix=e.mix;exports.obj2node=e.obj2node;exports.sanitizeBlankText=e.sanitizeBlankText;exports.tagUid=e.tagUid;exports.toXsl=e.toXsl;exports.xPath=e.xPath;exports.xPathDefaults=e.xPathDefaults;exports.xhrTemplate=e.xhrTemplate;exports.xml2dom=e.xml2dom;exports.xmlString=e.xmlString;exports.xslTags=e.xslTags;exports.HttpRequestElement=l.HttpRequestElement;exports.LocalStorageElement=t.LocalStorageElement;exports.localStorageSetItem=t.localStorageSetItem;exports.localStorage_clear=t.localStorage_clear;exports.localStorage_removeItem=t.localStorage_removeItem;exports.localStorage_setItem=t.localStorage_setItem;exports.LocationElement=a.LocationElement;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as e } from "./custom-element-
|
|
2
|
-
import { j as o, f as l, l as r, i as m, c, b as n, e as x, n as p, g, k as i, h as u, m as d, o as f, s as S, t as E, u as I, q as h, p as q, d as D, x as L, a as b, r as v } from "./custom-element-
|
|
1
|
+
import { C as e } from "./custom-element-BqBcmDiN.js";
|
|
2
|
+
import { j as o, f as l, l as r, i as m, c, b as n, e as x, n as p, g, k as i, h as u, m as d, o as f, s as S, t as E, u as I, q as h, p as q, d as D, x as L, a as b, r as v } from "./custom-element-BqBcmDiN.js";
|
|
3
3
|
import { H as T } from "./http-request-DTCzZ1gc.js";
|
|
4
4
|
import { L as _, c as j, b as k, a as y, l as A } from "./local-storage-DzmNKzgN.js";
|
|
5
5
|
import { L as H } from "./location-element-FJlONi2n.js";
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
<xsl:with-param name="defaultvalue"/>
|
|
90
90
|
</xsl:call-template>
|
|
91
91
|
</xsl:variable>
|
|
92
|
-
</xsl:stylesheet>`);o.importStylesheet(n);const v=o.transformToFragment(y,document),u=(i,r)=>i.querySelector(r),w=u(x,'template[mode="payload"]');if(!v)return console.error("transformation error",{xml:y.outerHTML,xsl:U(n)});if(v.firstElementChild.localName!=="dce-root"){const i=v.ownerDocument.createElement("dce-root");[...v.childNodes].forEach(r=>i.append(r)),v.append(i)}[...v.querySelectorAll("[test]")].forEach(i=>{const r=d(i,"test"),f=r.replace(/hasBoolAttribute\((.*?)\)/g,(g,h,b,T,P)=>{const L=h.substring(1);return`(not($${L} = 'false') and ($${L} = '' or $${L} = '${L}' or $${L} = 'true' ))`});r!==f&&i.setAttribute("test",f)}),[...v.querySelectorAll("dce-root>attribute")].forEach(i=>{K(i,"namespace,name,select");const r=te(i,"xsl:param"),f=d(i,"name");if(t.push(f),i.childNodes.length&&(l[f]=i.textContent),w.append(r),i.hasAttribute("select")){a[f]=d(i,"select"),K(r,"select,name");let g=d(i,"select").split("??"),h;if(g?.length>1){r.removeAttribute("select");const b=u(x,'template[match="ignore"]>choose').cloneNode(!0);F(b.firstElementChild).append(D(b,"{"+g[0]+"}")),b.firstElementChild.setAttribute("test",g[0]);for(let T=1;T<g.length-1;T++){const P=b.firstElementChild.cloneNode(!0);F(P).append(D(b,"{"+g[T]+"}")),P.setAttribute("test",g[T]),b.insertBefore(P,b.lastElementChild)}F(b.lastElementChild).append(D(b,"{"+g[g.length-1]+"}")),r.append(b),h=b.cloneNode(!0)}else h=te(i,"xsl:value-of");h.removeAttribute("name"),i.append(h),i.removeAttribute("select")}else K(r,"name"),r.setAttribute("select","/datadom/attributes/"+f),l[f]||i.remove()}),[...v.querySelectorAll("[value]")].filter(i=>i.getAttribute("value").match(/\{(.*)\?\?(.*)\}/g)).forEach(i=>{const r=d(i,"value");r&&i.setAttribute("value",Ne(r))});for(const i of v.childNodes)w.append(x.importNode(i,!0));[...w.getElementsByTagName("xsl:template")].forEach(i=>w.ownerDocument.documentElement.append(i));const O=u(x,'call-template[name="slot"]'),H=i=>{const r=O.cloneNode(!0),f=d(i,"name");f&&r.firstElementChild.setAttribute("select",`'${f}'`);for(let g of i.childNodes)r.lastElementChild.append(g);return r};z(w,"slot",i=>i.parentNode.replaceChild(H(i),i));const p=le(x);return ee(p,{declaredAttributes:t,hardcodedAttributes:l,exposedAttributes:a}),p}async function be(e){return await new Promise((t,l)=>{const a=new XMLHttpRequest;a.open("GET",e),a.responseType="document",a.onload=()=>{a.readyState===a.DONE&&a.status===200?t(a.responseXML?.body||a.responseXML||C("div",a.responseText)):l(`${a.statusText} - ${e}`)},a.addEventListener("error",n=>l(n)),a.send()})}function ye(e,s,t=!1){if(e===s)return!0;if(typeof e!="object"||e===null||typeof s!="object"||s===null||Object.keys(e).length!==Object.keys(s).length)return t;for(let l in e)if(!(l in s)||!ye(e[l],s[l]))return t;return!0}const ge=e=>e.split("|").map(s=>s.trim()).filter(s=>s),Ae=(e,s)=>ge(s).map(t=>{let l=e.ownerDocument,a=n=>(e.append(n),n);if(t.includes("/")){const n=[],o=l.evaluate(t,e);for(let y;y=o.iterateNext();)n.push(y);return n}return[...e.childNodes].find(n=>n.localName===t)||a(C(t,"",l))}).flat();function ne(e,s,t,l){if(!t.sliceProcessed)return t.sliceProcessed=1,Ae(e,s??"").map(a=>{const n=e.ownerDocument,o=t.sliceEventSource,y=t.sliceElement,x=()=>[...a.childNodes].filter(u=>u.nodeType===3||u.localName==="value"||u.localName==="form-data").map(u=>u.remove());o.getAttributeNames().map(u=>a.setAttribute(u,d(o,u))),[...a.childNodes].filter(u=>u.localName==="event").map(u=>u.remove()),"validationMessage"in o&&a.setAttribute("validation-message",o.validationMessage),t.type==="init"&&x(),a.append(M(t,"event",n));const v=(o.type==="checkbox"||o.type==="radio")&&!o.checked;if(y.hasAttribute("slice-value")){o.value===void 0?a.removeAttribute("value"):a.setAttribute("value",o.value);const u=v?"":I(d(y,"slice-value"),a);x(),a.append(D(n,u))}else{if("elements"in o)return x(),a.append(M(new FormData(o),"value",a.ownerDocument)),a;const u=v?"":o.value??d(o,"value");if(x(),u==null)[...a.childNodes].filter(w=>w.localName!=="event").map(w=>w.remove()),a.removeAttribute("value");else{const w=De(u)?D(n,u):M(u,"value",a.ownerDocument);a.append(w),a.setAttribute("value",u)}}return a})}function z(e,s,t){e.querySelectorAll&&[...e.querySelectorAll(s)].forEach(t)}const je=async(e,s)=>{if(!e||!e.trim())return[s];if(e.startsWith("#"))return(t=>{const l=t.querySelectorAll(e);return[...l.length?l:t.getRootNode().querySelectorAll(e)]})(s.parentElement);try{const[t,l]=e.split("#");if(e.charAt(0)===".")e=new URL(t,s.closest("[base]")?.getAttribute("base")||location).href;else try{e=(void 0)(t),l&&(e+="#"+l)}catch(n){console.error(n.message)}const a=await be(e);if(s.setAttributeNS("xml","base",e),l){const n=a.querySelectorAll("#"+l);return n.length?[...n]:(console.error("template not found",e+"#"+l),[s])}return[a]}catch{return[s]}};function ae(e,s){for(let n of e.attributes)try{const o=n.name;if(o.startsWith("xmlns"))continue;n.namespaceURI?(!s.hasAttributeNS(n.namespaceURI,o)||s.getAttributeNS(n.namespaceURI,o)!==n.value)&&s.setAttributeNS(n.namespaceURI,o,n.value):(!s.hasAttribute(o)||s.getAttribute(o)!==n.value)&&s.setAttribute(n.name,n.value),n.name==="value"&&(s.value=n.value)}catch(o){console.warn("attribute assignment error",o?.message||o)}const t=s.dceExportedAttributes,l=s.getAttribute("dce-exported-attributes"),a=l?new Set(l.split(" ")):null;for(let n of s.getAttributeNames())!e.hasAttribute(n)&&!t?.has(n)&&!a?.has(n)&&s.removeAttribute(n)}function ie(e,s=0){const t={};for(const l of e.childNodes){const a=d(l,"data-dce-id")||l.dceId||0;if(!t[a])a?t[a]=1:(t[a]=l.dceId=++s,l.setAttribute&&l.setAttribute("data-dce-id",l.dceId));else{const n=l.dceId=a+"-"+t[a]++;l.setAttribute&&l.setAttribute("data-dce-id",n)}l.childNodes.length&&ie(l)}}function ve(e,s,t){t=1*t;for(let l of e.childNodes)if((l.dceId??l.getAttribute("data-dce-id")*1)>t)return e.insertBefore(s,l);e.append(s)}function re(e,s){if(e.firstElementChild?.localName==="dce-root"&&s[0]?.localName!=="dce-root")return;if(!s.length)return e.firstElementChild?.localName!=="dce-root"&&de(e);const t={};for(let l of e.childNodes)t[l.dceId],me(l)?(l.data.trim(),t[l.dceId||0]=l):t[d(l,"data-dce-id")||0]=l;for(let l of[...s]){const a=d(l,"data-dce-id")||l.dceId,n=t[a];n?(me(l)?n.nodeValue!==l.nodeValue&&(n.nodeValue=l.nodeValue):(ae(l,n),(n.childNodes.length||l.childNodes.length)&&re(n,l.childNodes)),delete t[a]):ve(e,l,a)}for(let l of Object.values(t))l.localName!=="dce-root"&&l.remove()}function Ee(e,s){return e.hasAttribute(s)||e.setAttribute(s,crypto.randomUUID()),e.getAttribute(s)}const Ne=e=>[...e?.matchAll(/([^{}]*)(\{)([^}]+)}([^{}]*)/g)].map(t=>`${t[1]}{${W(t[3])}}${t[4]}`).join(""),W=e=>{if(!e.trim())return e;const s=e.split("??"),t=s.shift(),l=W(s.join("??"));return s.length?`concat( ${t} , substring( ${l} , (1+string-length( ${l} )) * string-length( ${t} ) ) )`:e},I=(e,s)=>{const t=e.split("??");if(t.length>1)return I(t[0],s)||I(t[1],s);e=W(e);const l=s.ownerDocument.evaluate(e,s);switch(l.resultType){case XPathResult.NUMBER_TYPE:return l.numberValue;case XPathResult.STRING_TYPE:return l.stringValue;case XPathResult.BOOLEAN_TYPE:return l.booleanValue}let a="";for(let n;n=l.iterateNext();)a+=n.textContent;return a},we="stylesheet,transform,import,include,strip-space,preserve-space,output,key,decimal-format,namespace-alias,value-of,copy-of,number,apply-templates,apply-imports,for-each,sort,if,choose,when,otherwise,attribute-set,call-template,with-param,variable,param,text,processing-instruction,element,attribute,comment,copy,message,fallback".split(","),Te=(e,s)=>{const t=C("xsl:"+e.localName);for(let a of e.attributes)t.setAttribute(a.name,a.value);for(;e.firstChild;)t.append(e.firstChild);const l="if,choose,for-each".includes(e.localName)?(()=>{const a=C("span");return
|
|
92
|
+
</xsl:stylesheet>`);o.importStylesheet(n);const v=o.transformToFragment(y,document),u=(i,r)=>i.querySelector(r),w=u(x,'template[mode="payload"]');if(!v)return console.error("transformation error",{xml:y.outerHTML,xsl:U(n)});if(v.firstElementChild.localName!=="dce-root"){const i=v.ownerDocument.createElement("dce-root");[...v.childNodes].forEach(r=>i.append(r)),v.append(i)}[...v.querySelectorAll("[test]")].forEach(i=>{const r=d(i,"test"),f=r.replace(/hasBoolAttribute\((.*?)\)/g,(g,h,b,T,P)=>{const L=h.substring(1);return`(not($${L} = 'false') and ($${L} = '' or $${L} = '${L}' or $${L} = 'true' ))`});r!==f&&i.setAttribute("test",f)}),[...v.querySelectorAll("dce-root>attribute")].forEach(i=>{K(i,"namespace,name,select");const r=te(i,"xsl:param"),f=d(i,"name");if(t.push(f),i.childNodes.length&&(l[f]=i.textContent),w.append(r),i.hasAttribute("select")){a[f]=d(i,"select"),K(r,"select,name");let g=d(i,"select").split("??"),h;if(g?.length>1){r.removeAttribute("select");const b=u(x,'template[match="ignore"]>choose').cloneNode(!0);F(b.firstElementChild).append(D(b,"{"+g[0]+"}")),b.firstElementChild.setAttribute("test",g[0]);for(let T=1;T<g.length-1;T++){const P=b.firstElementChild.cloneNode(!0);F(P).append(D(b,"{"+g[T]+"}")),P.setAttribute("test",g[T]),b.insertBefore(P,b.lastElementChild)}F(b.lastElementChild).append(D(b,"{"+g[g.length-1]+"}")),r.append(b),h=b.cloneNode(!0)}else h=te(i,"xsl:value-of");h.removeAttribute("name"),i.append(h),i.removeAttribute("select")}else K(r,"name"),r.setAttribute("select","/datadom/attributes/"+f),l[f]||i.remove()}),[...v.querySelectorAll("[value]")].filter(i=>i.getAttribute("value").match(/\{(.*)\?\?(.*)\}/g)).forEach(i=>{const r=d(i,"value");r&&i.setAttribute("value",Ne(r))});for(const i of v.childNodes)w.append(x.importNode(i,!0));[...w.getElementsByTagName("xsl:template")].forEach(i=>w.ownerDocument.documentElement.append(i));const O=u(x,'call-template[name="slot"]'),H=i=>{const r=O.cloneNode(!0),f=d(i,"name");f&&r.firstElementChild.setAttribute("select",`'${f}'`);for(let g of i.childNodes)r.lastElementChild.append(g);return r};z(w,"slot",i=>i.parentNode.replaceChild(H(i),i));const p=le(x);return ee(p,{declaredAttributes:t,hardcodedAttributes:l,exposedAttributes:a}),p}async function be(e){return await new Promise((t,l)=>{const a=new XMLHttpRequest;a.open("GET",e),a.responseType="document",a.onload=()=>{a.readyState===a.DONE&&a.status===200?t(a.responseXML?.body||a.responseXML||C("div",a.responseText)):l(`${a.statusText} - ${e}`)},a.addEventListener("error",n=>l(n)),a.send()})}function ye(e,s,t=!1){if(e===s)return!0;if(typeof e!="object"||e===null||typeof s!="object"||s===null||Object.keys(e).length!==Object.keys(s).length)return t;for(let l in e)if(!(l in s)||!ye(e[l],s[l]))return t;return!0}const ge=e=>e.split("|").map(s=>s.trim()).filter(s=>s),Ae=(e,s)=>ge(s).map(t=>{let l=e.ownerDocument,a=n=>(e.append(n),n);if(t.includes("/")){const n=[],o=l.evaluate(t,e);for(let y;y=o.iterateNext();)n.push(y);return n}return[...e.childNodes].find(n=>n.localName===t)||a(C(t,"",l))}).flat();function ne(e,s,t,l){if(!t.sliceProcessed)return t.sliceProcessed=1,Ae(e,s??"").map(a=>{const n=e.ownerDocument,o=t.sliceEventSource,y=t.sliceElement,x=()=>[...a.childNodes].filter(u=>u.nodeType===3||u.localName==="value"||u.localName==="form-data").map(u=>u.remove());o.getAttributeNames().map(u=>a.setAttribute(u,d(o,u))),[...a.childNodes].filter(u=>u.localName==="event").map(u=>u.remove()),"validationMessage"in o&&a.setAttribute("validation-message",o.validationMessage),t.type==="init"&&x(),a.append(M(t,"event",n));const v=(o.type==="checkbox"||o.type==="radio")&&!o.checked;if(y.hasAttribute("slice-value")){o.value===void 0?a.removeAttribute("value"):a.setAttribute("value",o.value);const u=v?"":I(d(y,"slice-value"),a);x(),a.append(D(n,u))}else{if("elements"in o)return x(),a.append(M(new FormData(o),"value",a.ownerDocument)),a;const u=v?"":o.value??d(o,"value");if(x(),u==null)[...a.childNodes].filter(w=>w.localName!=="event").map(w=>w.remove()),a.removeAttribute("value");else{const w=De(u)?D(n,u):M(u,"value",a.ownerDocument);a.append(w),a.setAttribute("value",u)}}return a})}function z(e,s,t){e.querySelectorAll&&[...e.querySelectorAll(s)].forEach(t)}const je=async(e,s)=>{if(!e||!e.trim())return[s];if(e.startsWith("#"))return(t=>{const l=t.querySelectorAll(e);return[...l.length?l:t.getRootNode().querySelectorAll(e)]})(s.parentElement);try{const[t,l]=e.split("#");if(e.charAt(0)===".")e=new URL(t,s.closest("[base]")?.getAttribute("base")||location).href;else try{e=(void 0)(t),l&&(e+="#"+l)}catch(n){console.error(n.message)}const a=await be(e);if(s.setAttributeNS("xml","base",e),l){const n=a.querySelectorAll("#"+l);return n.length?[...n]:(console.error("template not found",e+"#"+l),[s])}return[a]}catch{return[s]}};function ae(e,s){for(let n of e.attributes)try{const o=n.name;if(o.startsWith("xmlns"))continue;n.namespaceURI?(!s.hasAttributeNS(n.namespaceURI,o)||s.getAttributeNS(n.namespaceURI,o)!==n.value)&&s.setAttributeNS(n.namespaceURI,o,n.value):(!s.hasAttribute(o)||s.getAttribute(o)!==n.value)&&s.setAttribute(n.name,n.value),n.name==="value"&&(s.value=n.value)}catch(o){console.warn("attribute assignment error",o?.message||o)}const t=s.dceExportedAttributes,l=s.getAttribute("dce-exported-attributes"),a=l?new Set(l.split(" ")):null;for(let n of s.getAttributeNames())!e.hasAttribute(n)&&!t?.has(n)&&!a?.has(n)&&s.removeAttribute(n)}function ie(e,s=0){const t={};for(const l of e.childNodes){const a=d(l,"data-dce-id")||l.dceId||0;if(!t[a])a?t[a]=1:(t[a]=l.dceId=++s,l.setAttribute&&l.setAttribute("data-dce-id",l.dceId));else{const n=l.dceId=a+"-"+t[a]++;l.setAttribute&&l.setAttribute("data-dce-id",n)}l.childNodes.length&&ie(l)}}function ve(e,s,t){t=1*t;for(let l of e.childNodes)if((l.dceId??l.getAttribute("data-dce-id")*1)>t)return e.insertBefore(s,l);e.append(s)}function re(e,s){if(e.firstElementChild?.localName==="dce-root"&&s[0]?.localName!=="dce-root")return;if(!s.length)return e.firstElementChild?.localName!=="dce-root"&&de(e);const t={};for(let l of e.childNodes)t[l.dceId],me(l)?(l.data.trim(),t[l.dceId||0]=l):t[d(l,"data-dce-id")||0]=l;for(let l of[...s]){const a=d(l,"data-dce-id")||l.dceId,n=t[a];n?(me(l)?n.nodeValue!==l.nodeValue&&(n.nodeValue=l.nodeValue):(ae(l,n),(n.childNodes.length||l.childNodes.length)&&re(n,l.childNodes)),delete t[a]):ve(e,l,a)}for(let l of Object.values(t))l.localName!=="dce-root"&&l.remove()}function Ee(e,s){return e.hasAttribute(s)||e.setAttribute(s,crypto.randomUUID()),e.getAttribute(s)}const Ne=e=>[...e?.matchAll(/([^{}]*)(\{)([^}]+)}([^{}]*)/g)].map(t=>`${t[1]}{${W(t[3])}}${t[4]}`).join(""),W=e=>{if(!e.trim())return e;const s=e.split("??"),t=s.shift(),l=W(s.join("??"));return s.length?`concat( ${t} , substring( ${l} , (1+string-length( ${l} )) * string-length( ${t} ) ) )`:e},I=(e,s)=>{const t=e.split("??");if(t.length>1)return I(t[0],s)||I(t[1],s);e=W(e);const l=s.ownerDocument.evaluate(e,s);switch(l.resultType){case XPathResult.NUMBER_TYPE:return l.numberValue;case XPathResult.STRING_TYPE:return l.stringValue;case XPathResult.BOOLEAN_TYPE:return l.booleanValue}let a="";for(let n;n=l.iterateNext();)a+=n.textContent;return a},we="stylesheet,transform,import,include,strip-space,preserve-space,output,key,decimal-format,namespace-alias,value-of,copy-of,number,apply-templates,apply-imports,for-each,sort,if,choose,when,otherwise,attribute-set,call-template,with-param,variable,param,text,processing-instruction,element,attribute,comment,copy,message,fallback".split(","),Te=(e,s)=>{const t=C("xsl:"+e.localName);for(let a of e.attributes)t.setAttribute(a.name,a.value);for(;e.firstChild;)t.append(e.firstChild);const l="if,choose,for-each".includes(e.localName)?(()=>{const a=e.parentElement;if(!a||a.childNodes.length===1)return t;const n=C("span");return n.append(t),n})():t;if(e.parentElement)e.parentElement.replaceChild(l,e);else{const a=e.parentElement||s,n=[...a.childNodes];n.forEach((o,y)=>{o===e&&(n[y]=l)}),a.replaceChildren(...n)}};class Se extends HTMLElement{static observedAttributes=["src","tag","hidden"];async connectedCallback(){this.firstElementChild&&this.firstElementChild.localName!=="template"&&console.log(`custom-element used without template wrapping content
|
|
93
93
|
`,this.outerHTML);const s=await je(d(this,"src"),this),t=d(this,"tag"),l=t||"dce-"+crypto.randomUUID();for(const p of s)z(p.templateNode||p.content||p,"style",i=>{const r=i.closest("slot"),f=r?`slot[name="${r.name}"]`:"";i.innerHTML=`${l} ${f}{${i.innerHTML}}`,this.append(i)});const a=s.map(p=>xe(p)),n=a.map((p,i)=>{i=new XSLTProcessor;try{i.importStylesheet(p)}catch(r){console.error(r,U(p))}return i});Object.defineProperty(this,"xsltString",{get:()=>a.map(p=>U(p)).join(`
|
|
94
94
|
`)});const o=this,y=[...this.templateNode.querySelectorAll("[slice]")],x=y.map(p=>d(p,"slice")).filter(p=>!p.includes("/")).filter((p,i,r)=>r.indexOf(p)===i).map(ge).flat(),{declaredAttributes:v,hardcodedAttributes:u,exposedAttributes:w}=a[0],oe=new Set([...Object.keys(u),...Object.keys(w)]);class O extends HTMLElement{static get observedAttributes(){return v}#e=0;get dceExportedAttributes(){return oe}connectedCallback(){let i=se(this.childNodes);if(this.firstElementChild?.tagName==="TEMPLATE"){this.firstElementChild!==this.lastElementChild&&console.error("payload should have TEMPLATE as only child",this.outerHTML);const c=this.firstElementChild;c.remove(),i=se(c.content.childNodes);for(const E of i)if(E.localName==="style"){const m=Ee(this,"data-dce-style");E.innerHTML=`${l}[data-dce-style="${m}"]{${E.innerHTML}}`,c.insertAdjacentElement("beforebegin",E)}else E.nodeType===1?c.insertAdjacentElement("beforebegin",E):E.nodeType===3&&c.insertAdjacentText("beforebegin",E.data)}const r=X("<datadom/>").documentElement,f=(c,E="")=>(m=>(E&&m.append(D(r,E)),m))(r.ownerDocument.createElement(c)),g=_(r,"payload",i,Le);pe(g),fe(g),this.innerHTML="";const h=_(r,"attributes",this.attributes,c=>f(c.nodeName,c.value)),b=c=>this.hasAttribute(c)||[...h.children].find(E=>E.localName===c);ae(this,h),Object.keys(u).map(c=>b(c)||h.append(f(c,u[c]))),Object.keys(w).map(c=>b(c)||h.append(f(c))),_(r,"dataset",Object.keys(this.dataset),c=>f(c,this.dataset[c]));const T=_(r,"slice",x,c=>f(c,"")),P=c=>I(c,T);this.xml=r;const L=[],ce=()=>{const c={};for(let E;E=L.pop();){const m=d(E.sliceElement,"slice");c[m]||(ne(T,m,E),c[m]=E)}Object.keys(c).length!==0&&B()};let Y;this.onSlice=c=>{L.push(c),Y||(Y=setTimeout(()=>{ce(),Y=0},1))};const B=this.transform=()=>{if(this.#e)debugger;this.#e=1;const c=()=>{n.map((A,S)=>{const V=A.transformToFragment(r.ownerDocument,document);return V||console.error(`XSLT transformation error. xsl:
|
|
95
95
|
`,U(a[S]),`
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
3
|
+
<head>
|
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
|
+
<title>for-each - Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg"/>
|
|
7
|
+
|
|
8
|
+
<script type="module" src="../custom-element.js"></script>
|
|
9
|
+
<style>
|
|
10
|
+
@import "./demo.css";
|
|
11
|
+
|
|
12
|
+
table {
|
|
13
|
+
border-collapse: collapse;
|
|
14
|
+
margin: 1rem 0;
|
|
15
|
+
}
|
|
16
|
+
th, td {
|
|
17
|
+
border: 1px solid #ccc;
|
|
18
|
+
padding: 0.5rem;
|
|
19
|
+
}
|
|
20
|
+
th {
|
|
21
|
+
background: #f0f0f0;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
|
|
27
|
+
<nav>
|
|
28
|
+
<a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
|
|
29
|
+
<h3>for-each loop</h3>
|
|
30
|
+
<p>The <code><for-each></code> element iterates over a node-set selected by XPath expression
|
|
31
|
+
and renders its content for each node.</p>
|
|
32
|
+
<p><b>XHTML namespace use</b><br/>
|
|
33
|
+
HTML elements like <code><table></code>, <code><tr></code>, <code><td></code>
|
|
34
|
+
have strict content model rules - only specific child elements are permitted.
|
|
35
|
+
For example, <code><table></code> only allows <code><thead></code>,
|
|
36
|
+
<code><tbody></code>, <code><tr></code> as children; <code><tr></code>
|
|
37
|
+
only allows <code><th></code> or <code><td></code>.<br/>
|
|
38
|
+
When the browser parses HTML, it moves non-permitted elements (like <code><for-each></code>)
|
|
39
|
+
outside the table before JavaScript runs.<br/>
|
|
40
|
+
Using <code>xhtml:</code> namespace prefix (e.g., <code><xhtml:table></code>,
|
|
41
|
+
<code><xhtml:tr></code>) prevents the browser from recognizing these as standard HTML
|
|
42
|
+
elements during initial parsing, preserving the template structure for DCE to process correctly.
|
|
43
|
+
See examples 4 and 6.
|
|
44
|
+
</p>
|
|
45
|
+
</nav>
|
|
46
|
+
|
|
47
|
+
<html-demo-element legend="1. Simple for-each"
|
|
48
|
+
description="Loop over inline XML data and render each item">
|
|
49
|
+
<template>
|
|
50
|
+
<custom-element>
|
|
51
|
+
<template>
|
|
52
|
+
<xsl:variable name="fruits">
|
|
53
|
+
<item>Apple</item>
|
|
54
|
+
<item>Banana</item>
|
|
55
|
+
<item>Cherry</item>
|
|
56
|
+
</xsl:variable>
|
|
57
|
+
<ul>
|
|
58
|
+
<for-each select="exsl:node-set($fruits)/*">
|
|
59
|
+
<li>{.}</li>
|
|
60
|
+
</for-each>
|
|
61
|
+
</ul>
|
|
62
|
+
</template>
|
|
63
|
+
</custom-element>
|
|
64
|
+
</template>
|
|
65
|
+
</html-demo-element>
|
|
66
|
+
|
|
67
|
+
<html-demo-element legend="2. for-each with position()"
|
|
68
|
+
description="Using position() to number items in the loop">
|
|
69
|
+
<template>
|
|
70
|
+
<custom-element>
|
|
71
|
+
<template>
|
|
72
|
+
<xsl:variable name="colors">
|
|
73
|
+
<color hex="#ff0000">Red</color>
|
|
74
|
+
<color hex="#00ff00">Green</color>
|
|
75
|
+
<color hex="#0000ff">Blue</color>
|
|
76
|
+
</xsl:variable>
|
|
77
|
+
<for-each select="exsl:node-set($colors)/*">
|
|
78
|
+
<div style="padding: 0.5rem; background: {@hex}; color: white;">
|
|
79
|
+
{position()}. {.}
|
|
80
|
+
</div>
|
|
81
|
+
</for-each>
|
|
82
|
+
</template>
|
|
83
|
+
</custom-element>
|
|
84
|
+
</template>
|
|
85
|
+
</html-demo-element>
|
|
86
|
+
|
|
87
|
+
<html-demo-element legend="3. Conditional for-each"
|
|
88
|
+
description="Initially empty, items shown when checkbox is checked">
|
|
89
|
+
<template>
|
|
90
|
+
<custom-element>
|
|
91
|
+
<template>
|
|
92
|
+
<xsl:variable name="items">
|
|
93
|
+
<item>First</item>
|
|
94
|
+
<item>Second</item>
|
|
95
|
+
<item>Third</item>
|
|
96
|
+
</xsl:variable>
|
|
97
|
+
<label>
|
|
98
|
+
<input type="checkbox" slice="show-items" value="yes"/>
|
|
99
|
+
Show items
|
|
100
|
+
</label>
|
|
101
|
+
<variable name="show" select="//show-items = 'yes'"></variable>
|
|
102
|
+
<div>
|
|
103
|
+
BEFORE
|
|
104
|
+
<for-each select="exsl:node-set($items)/*[$show]">
|
|
105
|
+
<span style="margin: 0 0.25rem; padding: 0.25rem; background: #e0e0ff;">
|
|
106
|
+
{position()}:{.}
|
|
107
|
+
</span>
|
|
108
|
+
</for-each>
|
|
109
|
+
AFTER
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
112
|
+
</custom-element>
|
|
113
|
+
</template>
|
|
114
|
+
</html-demo-element>
|
|
115
|
+
|
|
116
|
+
<html-demo-element legend="4. Nested for-each (Table)"
|
|
117
|
+
description="Nested loops to render table rows and cells">
|
|
118
|
+
<template>
|
|
119
|
+
<custom-element>
|
|
120
|
+
<template>
|
|
121
|
+
<xsl:variable name="table-data">
|
|
122
|
+
<row><cell>A1</cell><cell>A2</cell><cell>A3</cell></row>
|
|
123
|
+
<row><cell>B1</cell><cell>B2</cell><cell>B3</cell></row>
|
|
124
|
+
<row><cell>C1</cell><cell>C2</cell><cell>C3</cell></row>
|
|
125
|
+
</xsl:variable>
|
|
126
|
+
<variable name="rows" select="exsl:node-set($table-data)/*"></variable>
|
|
127
|
+
<xhtml:table>
|
|
128
|
+
<xhtml:thead>
|
|
129
|
+
<xhtml:tr>
|
|
130
|
+
<xhtml:th>Col 1</xhtml:th>
|
|
131
|
+
<xhtml:th>Col 2</xhtml:th>
|
|
132
|
+
<xhtml:th>Col 3</xhtml:th>
|
|
133
|
+
</xhtml:tr>
|
|
134
|
+
</xhtml:thead>
|
|
135
|
+
<xhtml:tbody>
|
|
136
|
+
<for-each select="$rows">
|
|
137
|
+
<xhtml:tr>
|
|
138
|
+
<for-each select="*">
|
|
139
|
+
<xhtml:td>{.}</xhtml:td>
|
|
140
|
+
</for-each>
|
|
141
|
+
</xhtml:tr>
|
|
142
|
+
</for-each>
|
|
143
|
+
</xhtml:tbody>
|
|
144
|
+
</xhtml:table>
|
|
145
|
+
</template>
|
|
146
|
+
</custom-element>
|
|
147
|
+
</template>
|
|
148
|
+
</html-demo-element>
|
|
149
|
+
|
|
150
|
+
<html-demo-element legend="5. for-each with attributes"
|
|
151
|
+
description="Access element attributes within the loop">
|
|
152
|
+
<template>
|
|
153
|
+
<custom-element>
|
|
154
|
+
<template>
|
|
155
|
+
<xsl:variable name="users">
|
|
156
|
+
<user id="1" role="admin">Alice</user>
|
|
157
|
+
<user id="2" role="editor">Bob</user>
|
|
158
|
+
<user id="3" role="viewer">Charlie</user>
|
|
159
|
+
</xsl:variable>
|
|
160
|
+
<for-each select="exsl:node-set($users)/*">
|
|
161
|
+
<div style="padding: 0.5rem; margin: 0.25rem 0; border-left: 3px solid #007bff;">
|
|
162
|
+
<strong>#{@id}</strong> {.}
|
|
163
|
+
<em>({@role})</em>
|
|
164
|
+
</div>
|
|
165
|
+
</for-each>
|
|
166
|
+
</template>
|
|
167
|
+
</custom-element>
|
|
168
|
+
</template>
|
|
169
|
+
</html-demo-element>
|
|
170
|
+
|
|
171
|
+
<html-demo-element legend="6. Dynamic table with toggle"
|
|
172
|
+
description="Table rows appear/disappear based on checkbox state">
|
|
173
|
+
<template>
|
|
174
|
+
<custom-element>
|
|
175
|
+
<template>
|
|
176
|
+
<xsl:variable name="products">
|
|
177
|
+
<product price="10">Widget</product>
|
|
178
|
+
<product price="25">Gadget</product>
|
|
179
|
+
<product price="15">Gizmo</product>
|
|
180
|
+
</xsl:variable>
|
|
181
|
+
<variable name="items" select="exsl:node-set($products)/*"></variable>
|
|
182
|
+
<label>
|
|
183
|
+
<input type="checkbox" slice="show-products" value="yes"/>
|
|
184
|
+
Show products
|
|
185
|
+
</label>
|
|
186
|
+
<variable name="visible" select="//show-products = 'yes'"></variable>
|
|
187
|
+
<xhtml:table>
|
|
188
|
+
<xhtml:thead>
|
|
189
|
+
<xhtml:tr>
|
|
190
|
+
<xhtml:th>#</xhtml:th>
|
|
191
|
+
<xhtml:th>Product</xhtml:th>
|
|
192
|
+
<xhtml:th>Price</xhtml:th>
|
|
193
|
+
</xhtml:tr>
|
|
194
|
+
</xhtml:thead>
|
|
195
|
+
<xhtml:tbody>
|
|
196
|
+
<for-each select="$items[$visible]">
|
|
197
|
+
<xhtml:tr>
|
|
198
|
+
<xhtml:td>{position()}</xhtml:td>
|
|
199
|
+
<xhtml:td>{.}</xhtml:td>
|
|
200
|
+
<xhtml:td>${@price}</xhtml:td>
|
|
201
|
+
</xhtml:tr>
|
|
202
|
+
</for-each>
|
|
203
|
+
</xhtml:tbody>
|
|
204
|
+
</xhtml:table>
|
|
205
|
+
</template>
|
|
206
|
+
</custom-element>
|
|
207
|
+
</template>
|
|
208
|
+
</html-demo-element>
|
|
209
|
+
|
|
210
|
+
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
211
|
+
|
|
212
|
+
</body>
|
|
213
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epa-wg/custom-element-dist",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"tt": "vitest --coverage.enabled --coverage.all --no-file-parallelism --watch --browser.headless=false src/stories/external-template.test.stories.ts "
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@epa-wg/custom-element": "0.0.
|
|
22
|
+
"@epa-wg/custom-element": "0.0.37"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@storybook/addon-essentials": "8.5.3",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@vitest/coverage-istanbul": "3.0.5",
|
|
36
36
|
"coverage-svg": "0.0.3",
|
|
37
37
|
"lit": "3.2.1",
|
|
38
|
-
"msw": "2.7
|
|
39
|
-
"msw-storybook-addon": "2.0.
|
|
38
|
+
"msw": "2.12.7",
|
|
39
|
+
"msw-storybook-addon": "2.0.6",
|
|
40
40
|
"playwright": "1.50.1",
|
|
41
41
|
"storybook": "8.5.3",
|
|
42
42
|
"typescript": "5.7.3",
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
3
|
+
<head>
|
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
|
+
<title>for-each - Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg"/>
|
|
7
|
+
|
|
8
|
+
<script type="module" src="../custom-element.js"></script>
|
|
9
|
+
<style>
|
|
10
|
+
@import "./demo.css";
|
|
11
|
+
|
|
12
|
+
table {
|
|
13
|
+
border-collapse: collapse;
|
|
14
|
+
margin: 1rem 0;
|
|
15
|
+
}
|
|
16
|
+
th, td {
|
|
17
|
+
border: 1px solid #ccc;
|
|
18
|
+
padding: 0.5rem;
|
|
19
|
+
}
|
|
20
|
+
th {
|
|
21
|
+
background: #f0f0f0;
|
|
22
|
+
}
|
|
23
|
+
</style>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
|
|
27
|
+
<nav>
|
|
28
|
+
<a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
|
|
29
|
+
<h3>for-each loop</h3>
|
|
30
|
+
<p>The <code><for-each></code> element iterates over a node-set selected by XPath expression
|
|
31
|
+
and renders its content for each node.</p>
|
|
32
|
+
<p><b>XHTML namespace use</b><br/>
|
|
33
|
+
HTML elements like <code><table></code>, <code><tr></code>, <code><td></code>
|
|
34
|
+
have strict content model rules - only specific child elements are permitted.
|
|
35
|
+
For example, <code><table></code> only allows <code><thead></code>,
|
|
36
|
+
<code><tbody></code>, <code><tr></code> as children; <code><tr></code>
|
|
37
|
+
only allows <code><th></code> or <code><td></code>.<br/>
|
|
38
|
+
When the browser parses HTML, it moves non-permitted elements (like <code><for-each></code>)
|
|
39
|
+
outside the table before JavaScript runs.<br/>
|
|
40
|
+
Using <code>xhtml:</code> namespace prefix (e.g., <code><xhtml:table></code>,
|
|
41
|
+
<code><xhtml:tr></code>) prevents the browser from recognizing these as standard HTML
|
|
42
|
+
elements during initial parsing, preserving the template structure for DCE to process correctly.
|
|
43
|
+
See examples 4 and 6.
|
|
44
|
+
</p>
|
|
45
|
+
</nav>
|
|
46
|
+
|
|
47
|
+
<html-demo-element legend="1. Simple for-each"
|
|
48
|
+
description="Loop over inline XML data and render each item">
|
|
49
|
+
<template>
|
|
50
|
+
<custom-element>
|
|
51
|
+
<template>
|
|
52
|
+
<xsl:variable name="fruits">
|
|
53
|
+
<item>Apple</item>
|
|
54
|
+
<item>Banana</item>
|
|
55
|
+
<item>Cherry</item>
|
|
56
|
+
</xsl:variable>
|
|
57
|
+
<ul>
|
|
58
|
+
<for-each select="exsl:node-set($fruits)/*">
|
|
59
|
+
<li>{.}</li>
|
|
60
|
+
</for-each>
|
|
61
|
+
</ul>
|
|
62
|
+
</template>
|
|
63
|
+
</custom-element>
|
|
64
|
+
</template>
|
|
65
|
+
</html-demo-element>
|
|
66
|
+
|
|
67
|
+
<html-demo-element legend="2. for-each with position()"
|
|
68
|
+
description="Using position() to number items in the loop">
|
|
69
|
+
<template>
|
|
70
|
+
<custom-element>
|
|
71
|
+
<template>
|
|
72
|
+
<xsl:variable name="colors">
|
|
73
|
+
<color hex="#ff0000">Red</color>
|
|
74
|
+
<color hex="#00ff00">Green</color>
|
|
75
|
+
<color hex="#0000ff">Blue</color>
|
|
76
|
+
</xsl:variable>
|
|
77
|
+
<for-each select="exsl:node-set($colors)/*">
|
|
78
|
+
<div style="padding: 0.5rem; background: {@hex}; color: white;">
|
|
79
|
+
{position()}. {.}
|
|
80
|
+
</div>
|
|
81
|
+
</for-each>
|
|
82
|
+
</template>
|
|
83
|
+
</custom-element>
|
|
84
|
+
</template>
|
|
85
|
+
</html-demo-element>
|
|
86
|
+
|
|
87
|
+
<html-demo-element legend="3. Conditional for-each"
|
|
88
|
+
description="Initially empty, items shown when checkbox is checked">
|
|
89
|
+
<template>
|
|
90
|
+
<custom-element>
|
|
91
|
+
<template>
|
|
92
|
+
<xsl:variable name="items">
|
|
93
|
+
<item>First</item>
|
|
94
|
+
<item>Second</item>
|
|
95
|
+
<item>Third</item>
|
|
96
|
+
</xsl:variable>
|
|
97
|
+
<label>
|
|
98
|
+
<input type="checkbox" slice="show-items" value="yes"/>
|
|
99
|
+
Show items
|
|
100
|
+
</label>
|
|
101
|
+
<variable name="show" select="//show-items = 'yes'"></variable>
|
|
102
|
+
<div>
|
|
103
|
+
BEFORE
|
|
104
|
+
<for-each select="exsl:node-set($items)/*[$show]">
|
|
105
|
+
<span style="margin: 0 0.25rem; padding: 0.25rem; background: #e0e0ff;">
|
|
106
|
+
{position()}:{.}
|
|
107
|
+
</span>
|
|
108
|
+
</for-each>
|
|
109
|
+
AFTER
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
112
|
+
</custom-element>
|
|
113
|
+
</template>
|
|
114
|
+
</html-demo-element>
|
|
115
|
+
|
|
116
|
+
<html-demo-element legend="4. Nested for-each (Table)"
|
|
117
|
+
description="Nested loops to render table rows and cells">
|
|
118
|
+
<template>
|
|
119
|
+
<custom-element>
|
|
120
|
+
<template>
|
|
121
|
+
<xsl:variable name="table-data">
|
|
122
|
+
<row><cell>A1</cell><cell>A2</cell><cell>A3</cell></row>
|
|
123
|
+
<row><cell>B1</cell><cell>B2</cell><cell>B3</cell></row>
|
|
124
|
+
<row><cell>C1</cell><cell>C2</cell><cell>C3</cell></row>
|
|
125
|
+
</xsl:variable>
|
|
126
|
+
<variable name="rows" select="exsl:node-set($table-data)/*"></variable>
|
|
127
|
+
<xhtml:table>
|
|
128
|
+
<xhtml:thead>
|
|
129
|
+
<xhtml:tr>
|
|
130
|
+
<xhtml:th>Col 1</xhtml:th>
|
|
131
|
+
<xhtml:th>Col 2</xhtml:th>
|
|
132
|
+
<xhtml:th>Col 3</xhtml:th>
|
|
133
|
+
</xhtml:tr>
|
|
134
|
+
</xhtml:thead>
|
|
135
|
+
<xhtml:tbody>
|
|
136
|
+
<for-each select="$rows">
|
|
137
|
+
<xhtml:tr>
|
|
138
|
+
<for-each select="*">
|
|
139
|
+
<xhtml:td>{.}</xhtml:td>
|
|
140
|
+
</for-each>
|
|
141
|
+
</xhtml:tr>
|
|
142
|
+
</for-each>
|
|
143
|
+
</xhtml:tbody>
|
|
144
|
+
</xhtml:table>
|
|
145
|
+
</template>
|
|
146
|
+
</custom-element>
|
|
147
|
+
</template>
|
|
148
|
+
</html-demo-element>
|
|
149
|
+
|
|
150
|
+
<html-demo-element legend="5. for-each with attributes"
|
|
151
|
+
description="Access element attributes within the loop">
|
|
152
|
+
<template>
|
|
153
|
+
<custom-element>
|
|
154
|
+
<template>
|
|
155
|
+
<xsl:variable name="users">
|
|
156
|
+
<user id="1" role="admin">Alice</user>
|
|
157
|
+
<user id="2" role="editor">Bob</user>
|
|
158
|
+
<user id="3" role="viewer">Charlie</user>
|
|
159
|
+
</xsl:variable>
|
|
160
|
+
<for-each select="exsl:node-set($users)/*">
|
|
161
|
+
<div style="padding: 0.5rem; margin: 0.25rem 0; border-left: 3px solid #007bff;">
|
|
162
|
+
<strong>#{@id}</strong> {.}
|
|
163
|
+
<em>({@role})</em>
|
|
164
|
+
</div>
|
|
165
|
+
</for-each>
|
|
166
|
+
</template>
|
|
167
|
+
</custom-element>
|
|
168
|
+
</template>
|
|
169
|
+
</html-demo-element>
|
|
170
|
+
|
|
171
|
+
<html-demo-element legend="6. Dynamic table with toggle"
|
|
172
|
+
description="Table rows appear/disappear based on checkbox state">
|
|
173
|
+
<template>
|
|
174
|
+
<custom-element>
|
|
175
|
+
<template>
|
|
176
|
+
<xsl:variable name="products">
|
|
177
|
+
<product price="10">Widget</product>
|
|
178
|
+
<product price="25">Gadget</product>
|
|
179
|
+
<product price="15">Gizmo</product>
|
|
180
|
+
</xsl:variable>
|
|
181
|
+
<variable name="items" select="exsl:node-set($products)/*"></variable>
|
|
182
|
+
<label>
|
|
183
|
+
<input type="checkbox" slice="show-products" value="yes"/>
|
|
184
|
+
Show products
|
|
185
|
+
</label>
|
|
186
|
+
<variable name="visible" select="//show-products = 'yes'"></variable>
|
|
187
|
+
<xhtml:table>
|
|
188
|
+
<xhtml:thead>
|
|
189
|
+
<xhtml:tr>
|
|
190
|
+
<xhtml:th>#</xhtml:th>
|
|
191
|
+
<xhtml:th>Product</xhtml:th>
|
|
192
|
+
<xhtml:th>Price</xhtml:th>
|
|
193
|
+
</xhtml:tr>
|
|
194
|
+
</xhtml:thead>
|
|
195
|
+
<xhtml:tbody>
|
|
196
|
+
<for-each select="$items[$visible]">
|
|
197
|
+
<xhtml:tr>
|
|
198
|
+
<xhtml:td>{position()}</xhtml:td>
|
|
199
|
+
<xhtml:td>{.}</xhtml:td>
|
|
200
|
+
<xhtml:td>${@price}</xhtml:td>
|
|
201
|
+
</xhtml:tr>
|
|
202
|
+
</for-each>
|
|
203
|
+
</xhtml:tbody>
|
|
204
|
+
</xhtml:table>
|
|
205
|
+
</template>
|
|
206
|
+
</custom-element>
|
|
207
|
+
</template>
|
|
208
|
+
</html-demo-element>
|
|
209
|
+
|
|
210
|
+
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
211
|
+
|
|
212
|
+
</body>
|
|
213
|
+
</html>
|
|
@@ -682,6 +682,9 @@ export const toXsl = (el, defParent) => {
|
|
|
682
682
|
while(el.firstChild)
|
|
683
683
|
x.append(el.firstChild);
|
|
684
684
|
const replacement = 'if,choose,for-each'.includes(el.localName) ? (() => {
|
|
685
|
+
const parent = el.parentElement;
|
|
686
|
+
if( !parent || parent.childNodes.length ===1 )
|
|
687
|
+
return x;
|
|
685
688
|
const span = create('span');
|
|
686
689
|
span.append(x);
|
|
687
690
|
return span;
|