@epa-wg/custom-element-dist 0.0.22 → 0.0.24

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.
Files changed (94) hide show
  1. package/README.md +4 -4
  2. package/coverage/coverage-final.json +13 -15
  3. package/coverage/index.html +30 -30
  4. package/coverage/src/custom-element/coverage.svg +1 -1
  5. package/coverage/src/custom-element/custom-element.js/coverage.svg +1 -1
  6. package/coverage/src/custom-element/custom-element.js.html +336 -312
  7. package/coverage/src/custom-element/http-request.js.html +10 -10
  8. package/coverage/src/custom-element/index.html +19 -49
  9. package/coverage/src/custom-element/local-storage.js.html +5 -5
  10. package/coverage/src/custom-element/location-element.js.html +1 -1
  11. package/coverage/src/index.html +1 -1
  12. package/coverage/src/mocks/handlers.ts.html +1 -1
  13. package/coverage/src/mocks/index.html +1 -1
  14. package/coverage/src/stories/attributes.test.stories.ts/coverage.svg +1 -1
  15. package/coverage/src/stories/attributes.test.stories.ts.html +85 -91
  16. package/coverage/src/stories/coverage.svg +1 -1
  17. package/coverage/src/stories/css.test.stories.ts/coverage.svg +1 -1
  18. package/coverage/src/stories/css.test.stories.ts.html +75 -78
  19. package/coverage/src/stories/dom-merge.test.stories.ts/coverage.svg +1 -1
  20. package/coverage/src/stories/dom-merge.test.stories.ts.html +302 -74
  21. package/coverage/src/stories/external-template.test.stories.ts/coverage.svg +1 -1
  22. package/coverage/src/stories/external-template.test.stories.ts.html +154 -154
  23. package/coverage/src/stories/form.test.stories.ts/coverage.svg +1 -1
  24. package/coverage/src/stories/form.test.stories.ts.html +83 -86
  25. package/coverage/src/stories/http-request.stories.ts.html +1 -1
  26. package/coverage/src/stories/index.html +104 -104
  27. package/coverage/src/stories/local-storage.test.stories.ts/coverage.svg +1 -1
  28. package/coverage/src/stories/local-storage.test.stories.ts.html +444 -444
  29. package/coverage/src/stories/location-element.test.stories.ts/coverage.svg +1 -1
  30. package/coverage/src/stories/location-element.test.stories.ts.html +96 -96
  31. package/coverage/src/stories/slice-events.test.stories.ts/coverage.svg +1 -1
  32. package/coverage/src/stories/slice-events.test.stories.ts.html +141 -141
  33. package/coverage/src/stories/slots.test.stories.ts/coverage.svg +1 -1
  34. package/coverage/src/stories/slots.test.stories.ts.html +120 -123
  35. package/coverage/src/stories/{renderPlay.ts.html → testStoryBook.ts.html} +45 -24
  36. package/coverage/src/sum.ts.html +1 -1
  37. package/dist/{custom-element-N-sWiqGK.cjs → custom-element-BDK7dcJN.cjs} +8 -8
  38. package/dist/{custom-element-BISbI4SU.js → custom-element-DqtzLkTG.js} +74 -66
  39. package/dist/custom-element-bundle.cjs +1 -1
  40. package/dist/custom-element-bundle.js +23 -22
  41. package/package.json +3 -3
  42. package/src/custom-element/custom-element.js +9 -1
  43. package/src/custom-element/demo/form.html +92 -46
  44. package/src/custom-element/demo/s.xml +9 -17
  45. package/src/custom-element/ide/web-types-dce.json +1 -1
  46. package/src/custom-element/ide/web-types-xsl.json +1 -1
  47. package/src/stories/attributes.test.stories.ts +9 -11
  48. package/src/stories/css.test.stories.ts +6 -7
  49. package/src/stories/dom-merge.test.stories.ts +81 -5
  50. package/src/stories/external-template.test.stories.ts +6 -6
  51. package/src/stories/form.test.stories.ts +6 -7
  52. package/src/stories/local-storage.test.stories.ts +7 -7
  53. package/src/stories/location-element.test.stories.ts +6 -6
  54. package/src/stories/slice-events.test.stories.ts +6 -6
  55. package/src/stories/slots.test.stories.ts +6 -7
  56. package/src/stories/testStoryBook.ts +28 -0
  57. package/storybook-static/assets/{Color-PRSJMWNM-e4s261EJ.js → Color-PRSJMWNM-y4ZsI1hY.js} +1 -1
  58. package/storybook-static/assets/{Configure-DWut7txe.js → Configure-CyLVkwlf.js} +1 -1
  59. package/storybook-static/assets/{DocsRenderer-K4EAMTCU-CaXVGjCl.js → DocsRenderer-K4EAMTCU-VRGUwRrq.js} +2 -2
  60. package/storybook-static/assets/{WithTooltip-KJL26V4Q--B8vdnMi.js → WithTooltip-KJL26V4Q-xdXH9Ztt.js} +1 -1
  61. package/storybook-static/assets/{attributes.test.stories-IuwazrdL.js → attributes.test.stories-BckCcyrF.js} +3 -2
  62. package/storybook-static/assets/{css.test.stories-D9WaxrEv.js → css.test.stories-B-QcObCF.js} +1 -1
  63. package/storybook-static/assets/{custom-element-BV8-hRQS.js → custom-element-BIxkVg7K.js} +5 -5
  64. package/storybook-static/assets/dom-merge.test.stories-CjXhjTQY.js +258 -0
  65. package/storybook-static/assets/{external-template.test.stories-Bpr_wxBo.js → external-template.test.stories-BBqyi0az.js} +1 -1
  66. package/storybook-static/assets/{form.test.stories-3tURbEdv.js → form.test.stories-DsIo1B4n.js} +1 -1
  67. package/storybook-static/assets/{formatter-2WMMO6ZP-SJtgH3vM.js → formatter-2WMMO6ZP-CThVcQxM.js} +1 -1
  68. package/storybook-static/assets/{http-request.stories-8K_qSs8C.js → http-request.stories-sXA_Y-VM.js} +1 -1
  69. package/storybook-static/assets/{iframe-CM82WlGY.js → iframe-DcDTQOmA.js} +2 -2
  70. package/storybook-static/assets/{index-DNL-IEpS.js → index-CUFHd5VD.js} +1 -1
  71. package/storybook-static/assets/{index-CEZitmnt.js → index-DPPi9iZu.js} +5 -5
  72. package/storybook-static/assets/{index-D1MP-Zis.js → index-VWixWKZ7.js} +1 -1
  73. package/storybook-static/assets/{local-storage.test.stories-CtisAQBB.js → local-storage.test.stories-Cs2v3QTS.js} +1 -1
  74. package/storybook-static/assets/{location-element.test.stories-5O_t_m4Y.js → location-element.test.stories-WkrQDzJJ.js} +1 -1
  75. package/storybook-static/assets/{preview-5Y0XiZgz.js → preview-p-Bwze-K.js} +2 -2
  76. package/storybook-static/assets/{slice-events.test.stories-BSXCLIA5.js → slice-events.test.stories-BRBBc0JT.js} +1 -1
  77. package/storybook-static/assets/{slots.test.stories-B1vqfHmN.js → slots.test.stories-r-i91k3y.js} +1 -1
  78. package/storybook-static/assets/{syntaxhighlighter-BP7B2CQK-BWFH_0wQ.js → syntaxhighlighter-BP7B2CQK-OnioRcs9.js} +1 -1
  79. package/storybook-static/iframe.html +1 -1
  80. package/storybook-static/index.json +1 -1
  81. package/storybook-static/project.json +1 -1
  82. package/tsconfig.json +31 -21
  83. package/coverage/src/custom-element/custom-element1-1.js/coverage.svg +0 -10
  84. package/coverage/src/custom-element/custom-element1-1.js.html +0 -2374
  85. package/coverage/src/custom-element/custom-element1.js/coverage.svg +0 -10
  86. package/coverage/src/custom-element/custom-element1.js.html +0 -2374
  87. package/src/custom-element/custom-element1-1.js +0 -763
  88. package/src/custom-element/custom-element1.js +0 -763
  89. package/src/custom-element/custom-element1.js0 +0 -750
  90. package/src/custom-element/custom-element2.js0 +0 -759
  91. package/src/custom-element/custom-element3.js0 +0 -763
  92. package/src/stories/renderPlay.ts +0 -21
  93. package/storybook-static/assets/dom-merge.test.stories-BhbNeum_.js +0 -137
  94. /package/coverage/src/stories/{renderPlay.ts → testStoryBook.ts}/coverage.svg +0 -0
@@ -1,759 +0,0 @@
1
- const XSL_NS_URL = 'http://www.w3.org/1999/XSL/Transform'
2
- , HTML_NS_URL = 'http://www.w3.org/1999/xhtml'
3
- , EXSL_NS_URL = 'http://exslt.org/common'
4
- , DCE_NS_URL ="urn:schemas-epa-wg:dce";
5
-
6
- // const log = x => console.debug( new XMLSerializer().serializeToString( x ) );
7
-
8
- const attr = (el, attr)=> el.getAttribute?.(attr)
9
- , isText = e => e.nodeType === 3
10
- , isString = s => typeof s === 'string'
11
- , isNode = e => e && typeof e.nodeType === 'number'
12
- , create = ( tag, t = '', d=document ) => ( e => ((t && e.append(createText(d.ownerDocument||d, t))),e) )((d.ownerDocument || d ).createElement( tag ))
13
- , createText = ( d, t) => (d.ownerDocument || d ).createTextNode( t )
14
- , removeChildren = n => { while(n.firstChild) n.firstChild.remove(); return n; }
15
- , emptyNode = n => { n.getAttributeNames().map( a => n.removeAttribute(a) ); return removeChildren(n); }
16
- , xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
17
- , xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) )
18
- , cloneAs = (p,tag) =>
19
- { const px = p.ownerDocument.createElementNS(p.namespaceURI,tag);
20
- for( let a of p.attributes)
21
- px.setAttribute(a.name, a.value);
22
- while( p.firstChild )
23
- px.append(p.firstChild);
24
- return px;
25
- };
26
-
27
- function
28
- ASSERT(x)
29
- {
30
- // if(!x)
31
- // debugger
32
- }
33
- export function
34
- xml2dom( xmlString )
35
- {
36
- return new DOMParser().parseFromString( xmlString, "application/xml" )
37
- }
38
- export function
39
- xmlString(doc){ return new XMLSerializer().serializeToString( doc ) }
40
-
41
- function
42
- injectData( root, sectionName, arr, cb )
43
- { const create = ( tag ) => root.ownerDocument.createElement( tag );
44
- const inject = ( tag, parent, s ) =>
45
- { parent.append( s = create( tag ) );
46
- return s;
47
- };
48
- const l = inject( sectionName, root );
49
- [ ...arr ].forEach( e => l.append( cb( e ) ) );
50
- return l;
51
- }
52
-
53
- function
54
- assureSlot( e )
55
- {
56
- if( !e.slot )
57
- {
58
- if( !e.setAttribute )
59
- e = create( 'span', e.textContent.replaceAll( '\n', '' ) );
60
- e.setAttribute( 'slot', '' )
61
- }
62
- return e;
63
- }
64
-
65
- export function
66
- obj2node( o, tag, doc )
67
- { const t = typeof o;
68
- if( t === 'string' )
69
- return create(tag,o,doc);
70
- if( t === 'number' )
71
- return create(tag,''+o,doc);
72
-
73
- if( o instanceof Array )
74
- { const ret = create('array','',doc);
75
- o.map( ae => ret.append( obj2node(ae,tag,doc)) );
76
- return ret
77
- }
78
- if( o instanceof FormData )
79
- { const ret = create('form-data','',doc);
80
- for( const p of o )
81
- ret.append( obj2node(p[1],p[0],doc) );
82
- return ret
83
- }
84
- const ret = create(tag,'',doc);
85
- for( let k in o )
86
- if( isNode(o[k]) || typeof o[k] ==='function' || o[k] instanceof Window )
87
- continue
88
- else
89
- if( typeof o[k] !== "object" )
90
- ret.setAttribute(k, o[k] );
91
- else
92
- ret.append(obj2node(o[k], k, doc))
93
- return ret;
94
- }
95
- export function
96
- tagUid( node )
97
- { // {} to xsl:value-of
98
- forEach$(node,'*',d => [...d.childNodes].filter( e=>e.nodeType === 3 ).forEach( e=>
99
- { if( e.parentNode.localName === 'style' )
100
- return;
101
- const m = e.data.matchAll( /{([^}]*)}/g );
102
- if(m)
103
- { let l = 0
104
- , txt = t => createText(e,t||'')
105
- , tt = [];
106
- [...m].forEach(t=>
107
- { if( t.index > l )
108
- tt.push( txt( t.input.substring( l, t.index ) ))
109
- const v = node.querySelector('value-of').cloneNode();
110
- v.setAttribute('select', t[1] );
111
- tt.push(v);
112
- l = t.index+t[0].length;
113
- })
114
- if( l < e.data.length)
115
- tt.push( txt( e.data.substring(l,e.data.length) ));
116
- if( tt.length )
117
- { for( let t of tt )
118
- d.insertBefore(t,e);
119
- d.removeChild(e);
120
- }
121
- }
122
- }));
123
-
124
- if( 'all' in node ) {
125
- let i= 1;
126
- for( let e of node.all )
127
- e.setAttribute && !e.tagName.startsWith('xsl:') && e.setAttribute('data-dce-id', '' + i++)
128
- }
129
- return node
130
- }
131
- export function
132
- createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
133
- {
134
- if( templateNode.tagName === S || templateNode.documentElement?.tagName === S )
135
- return tagUid(templateNode)
136
- const sanitizeXsl = xml2dom(`<xsl:stylesheet version="1.0" xmlns:xsl="${ XSL_NS_URL }" xmlns:xhtml="${ HTML_NS_URL }" xmlns:exsl="${EXSL_NS_URL}" exclude-result-prefixes="exsl" >
137
- <xsl:output method="xml" />
138
- <xsl:template match="/"><dce-root xmlns="${ HTML_NS_URL }"><xsl:apply-templates select="*"/></dce-root></xsl:template>
139
- <xsl:template match="*[name()='template']"><xsl:apply-templates mode="sanitize" select="*|text()"/></xsl:template>
140
- <xsl:template match="*"><xsl:apply-templates mode="sanitize" select="*|text()"/></xsl:template>
141
- <xsl:template match="*[name()='svg']|*[name()='math']"><xsl:apply-templates mode="sanitize" select="."/></xsl:template>
142
- <xsl:template mode="sanitize" match="*[count(text())=1 and count(*)=0]"><xsl:copy><xsl:apply-templates mode="sanitize" select="@*"/><xsl:value-of select="text()"></xsl:value-of></xsl:copy></xsl:template>
143
- <xsl:template mode="sanitize" match="xhtml:*[count(text())=1 and count(*)=0]"><xsl:element name="{local-name()}"><xsl:apply-templates mode="sanitize" select="@*"/><xsl:value-of select="text()"></xsl:value-of></xsl:element></xsl:template>
144
- <xsl:template mode="sanitize" match="*|@*"><xsl:copy><xsl:apply-templates mode="sanitize" select="*|@*|text()"/></xsl:copy></xsl:template>
145
- <xsl:template mode="sanitize" match="text()[normalize-space(.) = '']"/>
146
- <xsl:template mode="sanitize" match="text()"><dce-text><xsl:copy/></dce-text></xsl:template>
147
- <xsl:template mode="sanitize" match="xsl:value-of|*[name()='slot']"><dce-text><xsl:copy><xsl:apply-templates mode="sanitize" select="*|@*|text()"/></xsl:copy></dce-text></xsl:template>
148
- <xsl:template mode="sanitize" match="xhtml:*"><xsl:element name="{local-name()}"><xsl:apply-templates mode="sanitize" select="*|@*|text()"/></xsl:element></xsl:template>
149
- </xsl:stylesheet>`)
150
- const sanitizeProcessor = new XSLTProcessor()
151
- , tc = (n =>
152
- {
153
- forEach$(n,'script', s=> s.remove() );
154
- const xslRoot = n.content ?? n.firstElementChild?.content ?? n.body ?? n;
155
- xslTags.forEach( tag => forEach$( xslRoot, tag, el=>toXsl(el,xslRoot) ) );
156
- const e = n.firstElementChild?.content || n.content
157
- , asXmlNode = r => {
158
- const d = xml2dom( '<xhtml/>' )
159
- , n = d.importNode(r, true);
160
- d.replaceChild(n,d.documentElement);
161
- return xslHtmlNs(n);
162
- };
163
- if( e )
164
- { const t = create('div');
165
- [ ...e.childNodes ].map( c => t.append(c.cloneNode(true)) )
166
- return asXmlNode(t)
167
- }
168
- return asXmlNode(n.documentElement || n.body || n)
169
- })(templateNode)
170
- , xslDom = xml2dom(
171
- `<xsl:stylesheet version="1.0"
172
- xmlns:xsl="${ XSL_NS_URL }"
173
- xmlns:xhtml="${ HTML_NS_URL }"
174
- xmlns:dce="urn:schemas-epa-wg:dce"
175
- xmlns:exsl="http://exslt.org/common"
176
- exclude-result-prefixes="exsl"
177
- >
178
- <xsl:template match="ignore">
179
- <xsl:choose>
180
- <xsl:when test="//attr">{//attr}</xsl:when>
181
- <xsl:otherwise>{def}</xsl:otherwise>
182
- </xsl:choose><xsl:value-of select="."></xsl:value-of></xsl:template>
183
- <xsl:template mode="payload" match="attributes"></xsl:template>
184
- <xsl:template match="/">
185
- <xsl:apply-templates mode="payload" select="/datadom/attributes"/>
186
- </xsl:template>
187
-
188
- <xsl:template match="@*|node()" mode="copy-html">
189
- <xsl:copy><xsl:apply-templates select="@*|node()" mode="copy-html"/></xsl:copy>
190
- </xsl:template>
191
- <xsl:template match="node()[starts-with(name(),'xhtml:')]" mode="copy-html">
192
- <xsl:element name="{local-name()}"><xsl:apply-templates select="@*|node()" mode="copy-html"/></xsl:element>
193
- </xsl:template>
194
-
195
-
196
- <xsl:template name="slot" >
197
- <xsl:param name="slotname" />
198
- <xsl:param name="defaultvalue" />
199
- <xsl:choose>
200
- <xsl:when test="//payload/*[@slot=$slotname]">
201
- <xsl:apply-templates mode="copy-html" select="//payload/*[@slot=$slotname]"/>
202
- </xsl:when>
203
- <xsl:otherwise>
204
- <xsl:apply-templates mode="copy-html" select="$defaultvalue"/>
205
- </xsl:otherwise>
206
- </xsl:choose>
207
- </xsl:template>
208
- <xsl:variable name="js-injected-body">
209
- <xsl:call-template name="slot" >
210
- <xsl:with-param name="slotname" select="''"/>
211
- <xsl:with-param name="defaultvalue"/>
212
- </xsl:call-template>
213
- </xsl:variable>
214
- </xsl:stylesheet>`
215
- );
216
-
217
- sanitizeProcessor.importStylesheet( sanitizeXsl );
218
-
219
- const fr = sanitizeProcessor.transformToFragment(tc, document)
220
- , $ = (e,css) => e.querySelector(css)
221
- , payload = $( xslDom, 'template[mode="payload"]');
222
- if( !fr )
223
- return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
224
- const params = [];
225
- [...fr.querySelectorAll('dce-root>attribute')].forEach( a=>
226
- {
227
- const p = cloneAs(a,'xsl:param')
228
- , name = attr(a,'name');
229
- payload.append(p);
230
- let select = attr(p,'select')?.split('??')
231
- if( !select)
232
- { select = ['//'+name, `'${p.textContent}'`];
233
- emptyNode(p);
234
- p.setAttribute('name',name);
235
- }
236
- let val;
237
- if( select?.length>1 ){
238
- p.removeAttribute('select');
239
- const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
240
- emptyNode(c.firstElementChild).append( createText(c,'{'+select[0]+'}'));
241
- emptyNode(c.lastElementChild ).append( createText(c,'{'+select[1]+'}'));
242
- c.firstElementChild.setAttribute('test',select[0]);
243
- p.append(c);
244
- val = c.cloneNode(true);
245
- }else
246
- val=cloneAs(a,'xsl:value-of');
247
- val.removeAttribute('name');
248
- a.append(val);
249
- a.removeAttribute('select');
250
- params.push(p)
251
- });
252
- [...fr.querySelectorAll('[value]')].filter(el=>el.getAttribute('value').match( /\{(.*)\?\?(.*)\}/g )).forEach(el=>
253
- { const v = attr(el,'value');
254
- if(v)
255
- el.setAttribute('value', evalCurly(v));
256
- });
257
- for( const c of fr.childNodes )
258
- payload.append(xslDom.importNode(c,true))
259
-
260
- const embeddedTemplates = [...payload.querySelectorAll('template')];
261
- embeddedTemplates.forEach(t=>payload.ownerDocument.documentElement.append(t));
262
-
263
- const slotCall = $(xslDom,'call-template[name="slot"]')
264
- , slot2xsl = s =>
265
- { const v = slotCall.cloneNode(true)
266
- , name = attr(s,'name') || '';
267
- name && v.firstElementChild.setAttribute('select',`'${ name }'`)
268
- for( let c of s.childNodes)
269
- v.lastElementChild.append(c)
270
- return v
271
- }
272
-
273
- forEach$( payload,'slot', s => s.parentNode.replaceChild( slot2xsl(s), s ) )
274
-
275
- const ret = tagUid(xslDom)
276
- ret.params = params;
277
- return ret;
278
- }
279
- export async function
280
- xhrTemplate(src)
281
- {
282
- const dom = await new Promise((resolve,reject)=>
283
- { const xhr = new XMLHttpRequest();
284
- xhr.open("GET", src);
285
- xhr.responseType = "document";
286
- // xhr.overrideMimeType("text/xml");
287
- xhr.onload = () =>
288
- { if( xhr.readyState === xhr.DONE && xhr.status === 200 )
289
- resolve( xhr.responseXML || create('div', xhr.responseText ) )
290
- reject(xhr.statusText)
291
- };
292
- xhr.addEventListener("error", ev=>reject(ev) );
293
-
294
- xhr.send();
295
- })
296
- return dom
297
- }
298
- export function
299
- deepEqual(a, b, O=false)
300
- {
301
- if( a === b )
302
- return true;
303
-
304
- if( (typeof a !== "object" || a === null) || (typeof b !== "object" || b === null)
305
- || Object.keys(a).length !== Object.keys(b).length )
306
- return O;
307
-
308
- for( let k in a )
309
- if( !(k in b) || !deepEqual( a[k], b[k] ) )
310
- return O
311
- return true;
312
- }
313
- export const
314
- assureSlices = ( root, names) =>
315
- names.split('|').filter(s=>s).map(n=>n.trim()).map( xp =>
316
- { const append = n=> (root.append(n),n);
317
- if(xp.includes('/'))
318
- { const ret = [], r = root.ownerDocument.evaluate( xp, root );
319
- for( let n; n = r.iterateNext(); )
320
- ret.push( n )
321
- return ret
322
- }
323
-
324
- return [...root.childNodes].find(n=>n.localName === xp) || append( create(xp,'',root.ownerDocument) );
325
- }).flat();
326
-
327
- /**
328
- *
329
- * @param x slice node
330
- * @param sliceNames slice name, xPath in /datadom/slice/
331
- * @param ev Event obj
332
- * @param dce
333
- */
334
- export function
335
- event2slice( x, sliceNames, ev, dce )
336
- {
337
- if( ev.sliceProcessed )
338
- return
339
- ev.sliceProcessed = 1;
340
- // evaluate slices[]
341
- // inject @attributes
342
- // inject event
343
- // evaluate slice-value
344
- // slice[i] = slice-value
345
- return assureSlices( x, sliceNames ?? '' ).map( s =>
346
- {
347
- const d = x.ownerDocument
348
- , el = ev.sliceEventSource
349
- , sel = ev.sliceElement
350
- , cleanSliceValue = ()=>[...s.childNodes].filter(n=>n.nodeType===3 || n.localName==='value' || n.localName==='form-data').map(n=>n.remove());
351
- el.getAttributeNames().map( a => s.setAttribute( a, attr(el,a) ) );
352
- [...s.childNodes].filter(n=>n.localName==='event').map(n=>n.remove());
353
- if( 'validationMessage' in el )
354
- s.setAttribute('validation-message', el.validationMessage);
355
- ev.type==='init' && cleanSliceValue();
356
- s.append( obj2node( ev, 'event', d ) );
357
- if( sel.hasAttribute('slice-value') )
358
- { if( el.value === undefined)
359
- s.removeAttribute('value')
360
- else
361
- s.setAttribute('value', el.value );
362
- const v = xPath( attr( sel, 'slice-value'),s );
363
- cleanSliceValue();
364
- s.append( createText( d, v ) );
365
- }else
366
- { if( 'elements' in el )
367
- { cleanSliceValue();
368
- s.append( obj2node(new FormData(el),'value', s.ownerDocument) )
369
- return s
370
- }
371
- const v = el.value ?? attr( sel, 'value' ) ;
372
- cleanSliceValue();
373
- if( v === null || v === undefined )
374
- [...s.childNodes].filter(n=>n.localName!=='event').map(n=>n.remove());
375
- else
376
- if( isString(v) )
377
- s.append( createText( d, v) );
378
- else
379
- s.append( obj2node(v,'value',s.ownerDocument) )
380
- }
381
- return s
382
- })
383
- }
384
-
385
- function forEach$( el, css, cb){
386
- if( el.querySelectorAll )
387
- [...el.querySelectorAll(css)].forEach(cb)
388
- }
389
- const loadTemplateRoots = async ( src, dce )=>
390
- {
391
- if( !src || !src.trim() )
392
- return [dce]
393
- if( src.startsWith('#') )
394
- return ( n =>
395
- { if(!n) return []
396
- const a = n.querySelectorAll(src)
397
- if( a.length )
398
- return [...a]
399
- const r = n.getRootNode();
400
- return r===n ? []: getByHashId(r)
401
- })(dce.parentElement)
402
- try
403
- { // todo cache
404
- const dom = await xhrTemplate(src)
405
- const hash = new URL(src, location).hash
406
- if( hash )
407
- { const ret = dom.querySelectorAll(hash);
408
- if( ret.length )
409
- return [...ret]
410
- return [dce]
411
- }
412
- return [dom]
413
- }catch (error){ return [dce]}
414
- }
415
- export function mergeAttr( from, to )
416
- { if( isText(from) )
417
- {
418
- if( !isText(to) ){ debugger }
419
- return
420
- }
421
- for( let a of from.attributes)
422
- { a.namespaceURI? to.setAttributeNS( a.namespaceURI, a.name, a.value ) : to.setAttribute( a.name, a.value )
423
- if( a.name === 'value')
424
- to.value = a.value
425
- }
426
- }
427
- export function assureUnique(n, id=0)
428
- {
429
- const m = {}
430
- for( const e of n.childNodes )
431
- {
432
- const a = attr(e,'data-dce-id') || e.dceId || 0;
433
- if( !m[a] )
434
- { if( !a )
435
- { m[a] = e.dceId = ++id;
436
- if( e.setAttribute )
437
- e.setAttribute('data-dce-id', e.dceId )
438
- }else
439
- m[a] = 1;
440
- }else
441
- { const v = e.dceId = a + '-' + m[a]++;
442
- if( e.setAttribute )
443
- e.setAttribute('data-dce-id', v )
444
- }
445
- e.childNodes.length && assureUnique(e)
446
- }
447
- }
448
- export function merge( parent, fromArr )
449
- {
450
- if(!fromArr.length)
451
- return removeChildren(parent);
452
- const id2old = {};
453
- for( let c of parent.childNodes)
454
- { ASSERT( !id2old[c.dceId] );
455
- if( isText(c) )
456
- { ASSERT( c.data.trim() );
457
- id2old[c.dceId || 0] = c;
458
- } else
459
- id2old[attr(c, 'data-dce-id') || 0] = c;
460
- }
461
- for( let e of [...fromArr] )
462
- { const k = attr(e, 'data-dce-id') || e.dceId;
463
- const o = id2old[ k ];
464
- if( o )
465
- { if( isText(e) )
466
- { if( o.nodeValue !== e.nodeValue )
467
- o.nodeValue = e.nodeValue;
468
- }else
469
- { mergeAttr(e,o)
470
- if( o.childNodes.length || e.childNodes.length )
471
- merge(o, e.childNodes)
472
- }
473
- delete id2old[ k ]
474
- }else
475
- parent.append( e )
476
- }
477
- for( let v of Object.values(id2old) )
478
- v.remove();
479
- }
480
- export function assureUID(n,attr)
481
- { if( !n.hasAttribute(attr) )
482
- n.setAttribute(attr, crypto.randomUUID());
483
- return n.getAttribute(attr)
484
- }
485
- export const evalCurly = s =>
486
- { const exp = [...s?.matchAll( /([^{}]*)(\{)([^}]+)}([^{}]*)/g ) ].map(l=>`${l[1]}{${ xPathDefaults(l[3] )}}${l[4]}`);
487
- return exp.join('');
488
- }
489
- export const xPathDefaults = x=>
490
- { if(!x.trim())
491
- return x;
492
- const xx = x.split('??')
493
- , a = xx.shift()
494
- , b = xPathDefaults(xx.join('??'));
495
-
496
- return xx.length ? `concat( ${a} , substring( ${b} , (1+string-length( ${b} )) * string-length( ${a} ) ) )`: x
497
- // return xx.length ? `${a}|(${xPathDefaults(xx.join('??'))})[not(${a})]`: a
498
- }
499
- export const xPath = (x,root)=>
500
- {
501
- const xx = x.split('??');
502
- if( xx.length > 1 )
503
- return xPath(xx[0], root) || xPath(xx[1], root);
504
-
505
- x = xPathDefaults(x);
506
-
507
- const it = root.ownerDocument.evaluate(x, root);
508
- switch( it.resultType )
509
- { case XPathResult.NUMBER_TYPE: return it.numberValue;
510
- case XPathResult.STRING_TYPE: return it.stringValue;
511
- case XPathResult.BOOLEAN_TYPE: return it.booleanValue;
512
- }
513
-
514
- let ret = '';
515
- for( let n ;n=it.iterateNext(); )
516
- ret += n.textContent;
517
- return ret
518
- }
519
- export const xslTags = 'stylesheet,transform,import,include,strip-space,preserve-space,output,key,decimal-format,namespace-alias,template,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(',');
520
- export const toXsl = (el, defParent) => {
521
- const x = create('xsl:'+el.localName);
522
- for( let a of el.attributes )
523
- x.setAttribute( a.name, a.value );
524
- while(el.firstChild)
525
- x.append(el.firstChild);
526
- if( el.parentElement )
527
- el.parentElement.replaceChild( x, el );
528
- else
529
- { const p = (el.parentElement || defParent)
530
- , arr = [...p.childNodes];
531
- arr.forEach((n, i) => {
532
- if (n === el)
533
- arr[i] = x;
534
- });
535
- p.replaceChildren(...arr);
536
- }
537
- };
538
-
539
- export class
540
- CustomElement extends HTMLElement
541
- {
542
- static observedAttributes = ['src','tag','hidden'];
543
- async connectedCallback()
544
- {
545
- const templateRoots = await loadTemplateRoots( attr( this, 'src' ), this )
546
- , tag = attr( this, 'tag' )
547
- , tagName = tag ? tag : 'dce-'+crypto.randomUUID();
548
-
549
- for( const t of templateRoots )
550
- forEach$(t.templateNode||t.content||t, 'style',s=>{
551
- const slot = s.closest('slot');
552
- const sName = slot ? `slot[name="${slot.name}"]`:'';
553
- s.innerHTML = `${tagName} ${sName}{${s.innerHTML}}`;
554
- this.append(s);
555
- })
556
- const templateDocs = templateRoots.map( n => createXsltFromDom( n ) )
557
- , xp = templateDocs.map( (td, p) =>{ p = new XSLTProcessor(); p.importStylesheet( td ); return p })
558
-
559
- Object.defineProperty( this, "xsltString", { get: ()=>templateDocs.map( td => xmlString(td) ).join('\n') });
560
-
561
- const dce = this
562
- , sliceNodes = [...this.templateNode.querySelectorAll('[slice]')]
563
- , sliceNames = sliceNodes.map(e=>attr(e,'slice')).filter(n=>!n.includes('/')).filter((v, i, a)=>a.indexOf(v) === i)
564
- , declaredAttributes = templateDocs.reduce( (ret,t) => { if( t.params ) ret.push( ...t.params ); return ret; }, [] );
565
-
566
- class DceElement extends HTMLElement
567
- {
568
- static get observedAttributes(){ return declaredAttributes.map( a=>attr(a,'name')); }
569
- #inTransform = 0;
570
- connectedCallback()
571
- { let payload = this.childNodes;
572
- if( this.firstElementChild?.tagName === 'TEMPLATE' )
573
- {
574
- const t = this.firstElementChild;
575
- t.remove();
576
- payload = t.content.childNodes;
577
-
578
- for( const n of [...t.content.childNodes] )
579
- if( n.localName === 'style' ){
580
- const id = assureUID(this,'data-dce-style')
581
- n.innerHTML= `${tagName}[data-dce-style="${id}"]{${n.innerHTML}}`;
582
- t.insertAdjacentElement('beforebegin',n);
583
- }else
584
- if(n.nodeType===1)
585
- t.insertAdjacentElement('beforebegin',n);
586
- else if(n.nodeType===3)
587
- t.insertAdjacentText('beforebegin',n.data);
588
- }
589
- const x = xml2dom( `<datadom
590
- xmlns:xsl="${ XSL_NS_URL }"
591
- xmlns:xhtml="${ HTML_NS_URL }"
592
- xmlns:dce="urn:schemas-epa-wg:dce"
593
- />` ).documentElement;
594
- const createXmlNode = ( tag, t = '' ) => ( e =>
595
- { if( t )
596
- e.append( createText( x, t ))
597
- return e;
598
- })(x.ownerDocument.createElement( tag ))
599
- payload = [...payload].map(n=>x.ownerDocument.importNode(n,true));
600
- injectData( x, 'payload' , payload , assureSlot );
601
- this.innerHTML='';
602
- const attrsRoot = injectData( x, 'attributes' , this.attributes, e => createXmlNode( e.nodeName, e.value ) );
603
- injectData( x, 'dataset', Object.keys( this.dataset ), k => createXmlNode( k, this.dataset[ k ] ) );
604
- const sliceRoot = injectData( x, 'slice', sliceNames, k => createXmlNode( k, '' ) )
605
- , sliceXPath = x => xPath(x, sliceRoot);
606
- this.xml = x;
607
-
608
- const sliceEvents=[];
609
- const applySlices = ()=>
610
- { const processed = {}
611
-
612
- for(let ev; ev = sliceEvents.pop(); )
613
- { const s = attr( ev.sliceElement, 'slice');
614
- if( processed[s] )
615
- continue;
616
- event2slice( sliceRoot, s, ev, this );
617
- processed[s] = ev;
618
- }
619
- Object.keys(processed).length !== 0 && transform();
620
- }
621
- let timeoutID;
622
-
623
- this.onSlice = ev=>
624
- { sliceEvents.push(ev);
625
- if( !timeoutID )
626
- timeoutID = setTimeout(()=>
627
- { applySlices();
628
- timeoutID =0;
629
- },1);
630
- };
631
- const transform = this.transform = ()=>
632
- { if(this.#inTransform){ debugger }
633
- this.#inTransform = 1;
634
-
635
- const ff = xp.map( (p,i) =>
636
- { const f = p.transformToFragment(x.ownerDocument, document)
637
- if( !f )
638
- console.error( "XSLT transformation error. xsl:\n", xmlString(templateDocs[i]), '\nxml:\n', xmlString(x) );
639
- return f
640
- });
641
- ff.map( f =>
642
- { if( !f )
643
- return;
644
- assureUnique(f);
645
- merge( this, f.childNodes )
646
- })
647
-
648
- DceElement.observedAttributes.map( a =>
649
- { let v = attr(this.firstElementChild,a);
650
- if( v !== attr(this,a) )
651
- { this.setAttribute( a, v );
652
- this.#applyAttribute( a, v );
653
- }
654
- })
655
-
656
- forEach$( this,'[slice],[slice-event]', el =>
657
- { if( !el.dceInitialized )
658
- { el.dceInitialized = 1;
659
- let evs = attr(el,'slice-event');
660
- if( attr(el,'custom-validity') )
661
- evs += ' change submit';
662
-
663
- [...new Set((evs || 'change') .split(' '))]
664
- .forEach( t=> (el.localName==='slice'? el.parentElement : el)
665
- .addEventListener( t, ev=>
666
- { ev.sliceElement = el;
667
- ev.sliceEventSource = ev.currentTarget || ev.target;
668
- const slices = event2slice( sliceRoot, attr( ev.sliceElement, 'slice')||'', ev, this );
669
-
670
- forEach$(this,'[custom-validity]',el =>
671
- { if( !el.setCustomValidity )
672
- return;
673
- const x = attr( el, 'custom-validity' );
674
- try
675
- { const v = x && xPath( x, attrsRoot );
676
- el.setCustomValidity( v === true? '': v === false ? 'invalid' : v );
677
- }catch(err)
678
- { console.error(err, 'xPath', x) }
679
- })
680
- const x = attr(el,'custom-validity')
681
- , v = x && xPath( x, attrsRoot )
682
- , msg = v === true? '' : v;
683
- if( x )
684
- { el.setCustomValidity ? el.setCustomValidity( msg ) : ( el.validationMessage = msg );
685
- slices.map( s => s.setAttribute('validation-message', msg ) );
686
- if( ev.type === 'submit' )
687
- { if( v === true )
688
- return;
689
- setTimeout(transform,1)
690
- if( !!v === v )
691
- { v || ev.preventDefault();
692
- return v;
693
- }
694
- if( v )
695
- { ev.preventDefault();
696
- return !1
697
- }
698
- return ;
699
- }else
700
- setTimeout(transform,1)
701
- }
702
- this.onSlice(ev);
703
- } ));
704
- if( !evs || evs.includes('init') )
705
- { if( el.hasAttribute('slice-value') || el.hasAttribute('value') || el.value )
706
- this.onSlice({type:'init', target: el, sliceElement:el, sliceEventSource:el })
707
- else
708
- el.value = sliceXPath( attr(el,'slice') )
709
- }
710
- }
711
- });
712
- this.#inTransform = 0;
713
- };
714
- transform();
715
- applySlices();
716
- }
717
- #applyAttribute(name, newValue)
718
- { let a = this.xml.querySelector(`attributes>${name}`);
719
- if( a )
720
- emptyNode(a).append( createText(a,newValue) );
721
- else
722
- { a = create( name, newValue, this.xml );
723
- this.xml.querySelector('attributes').append( a );
724
- }
725
- }
726
- attributeChangedCallback(name, oldValue, newValue)
727
- { if( !this.xml || this.#inTransform )
728
- return;
729
- this.#applyAttribute(name, newValue);
730
- this.transform(); // needs throttling
731
- }
732
-
733
- get dce(){ return dce }
734
- }
735
- const registerTag = tag =>
736
- {
737
- if( window.customElements.get(tag) !== DceElement )
738
- window.customElements.define( tag, DceElement);
739
- };
740
- if(tag)
741
- registerTag(tag);
742
- else
743
- { const t = tagName;
744
- this.setAttribute('tag', t );
745
- registerTag(t);
746
- const el = document.createElement(t);
747
- this.getAttributeNames().forEach(a=>el.setAttribute(a,this.getAttribute(a)));
748
- el.append(...[...this.childNodes].filter( e => e.localName!=='style') );
749
- this.append(el);
750
- }
751
- }
752
- get templateNode(){ return this.firstElementChild?.tagName === 'TEMPLATE'? this.firstElementChild.content : this }
753
- get dce(){ return this }
754
-
755
- get xslt(){ return xml2dom( this.xsltString ) }
756
- }
757
-
758
- window.customElements.define( 'custom-element', CustomElement );
759
- export default CustomElement;