@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,750 +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
- <xsl:template name="slot" >
188
- <xsl:param name="slotname" />
189
- <xsl:param name="defaultvalue" />
190
- <xsl:choose>
191
- <xsl:when test="//payload/*[@slot=$slotname]">
192
- <xsl:copy-of select="//payload/*[@slot=$slotname]"/>
193
- </xsl:when>
194
- <xsl:otherwise>
195
- <xsl:copy-of select="$defaultvalue"/>
196
- </xsl:otherwise>
197
- </xsl:choose>
198
- </xsl:template>
199
- <xsl:variable name="js-injected-body">
200
- <xsl:call-template name="slot" >
201
- <xsl:with-param name="slotname" select="''"/>
202
- <xsl:with-param name="defaultvalue"/>
203
- </xsl:call-template>
204
- </xsl:variable>
205
- </xsl:stylesheet>`
206
- );
207
-
208
- sanitizeProcessor.importStylesheet( sanitizeXsl );
209
-
210
- const fr = sanitizeProcessor.transformToFragment(tc, document)
211
- , $ = (e,css) => e.querySelector(css)
212
- , payload = $( xslDom, 'template[mode="payload"]');
213
- if( !fr )
214
- return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
215
- const params = [];
216
- [...fr.querySelectorAll('dce-root>attribute')].forEach( a=>
217
- {
218
- const p = cloneAs(a,'xsl:param')
219
- , name = attr(a,'name');
220
- payload.append(p);
221
- let select = attr(p,'select')?.split('??')
222
- if( !select)
223
- { select = ['//'+name, `'${p.textContent}'`];
224
- emptyNode(p);
225
- p.setAttribute('name',name);
226
- }
227
- let val;
228
- if( select?.length>1 ){
229
- p.removeAttribute('select');
230
- const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
231
- emptyNode(c.firstElementChild).append( createText(c,'{'+select[0]+'}'));
232
- emptyNode(c.lastElementChild ).append( createText(c,'{'+select[1]+'}'));
233
- c.firstElementChild.setAttribute('test',select[0]);
234
- p.append(c);
235
- val = c.cloneNode(true);
236
- }else
237
- val=cloneAs(a,'xsl:value-of');
238
- val.removeAttribute('name');
239
- a.append(val);
240
- a.removeAttribute('select');
241
- params.push(p)
242
- });
243
- [...fr.querySelectorAll('[value]')].filter(el=>el.getAttribute('value').match( /\{(.*)\?\?(.*)\}/g )).forEach(el=>
244
- { const v = attr(el,'value');
245
- if(v)
246
- el.setAttribute('value', evalCurly(v));
247
- });
248
- for( const c of fr.childNodes )
249
- payload.append(xslDom.importNode(c,true))
250
-
251
- const embeddedTemplates = [...payload.querySelectorAll('template')];
252
- embeddedTemplates.forEach(t=>payload.ownerDocument.documentElement.append(t));
253
-
254
- const slotCall = $(xslDom,'call-template[name="slot"]')
255
- , slot2xsl = s =>
256
- { const v = slotCall.cloneNode(true)
257
- , name = attr(s,'name') || '';
258
- name && v.firstElementChild.setAttribute('select',`'${ name }'`)
259
- for( let c of s.childNodes)
260
- v.lastElementChild.append(c)
261
- return v
262
- }
263
-
264
- forEach$( payload,'slot', s => s.parentNode.replaceChild( slot2xsl(s), s ) )
265
-
266
- const ret = tagUid(xslDom)
267
- ret.params = params;
268
- return ret;
269
- }
270
- export async function
271
- xhrTemplate(src)
272
- {
273
- const dom = await new Promise((resolve,reject)=>
274
- { const xhr = new XMLHttpRequest();
275
- xhr.open("GET", src);
276
- xhr.responseType = "document";
277
- // xhr.overrideMimeType("text/xml");
278
- xhr.onload = () =>
279
- { if( xhr.readyState === xhr.DONE && xhr.status === 200 )
280
- resolve( xhr.responseXML || create('div', xhr.responseText ) )
281
- reject(xhr.statusText)
282
- };
283
- xhr.addEventListener("error", ev=>reject(ev) );
284
-
285
- xhr.send();
286
- })
287
- return dom
288
- }
289
- export function
290
- deepEqual(a, b, O=false)
291
- {
292
- if( a === b )
293
- return true;
294
-
295
- if( (typeof a !== "object" || a === null) || (typeof b !== "object" || b === null)
296
- || Object.keys(a).length !== Object.keys(b).length )
297
- return O;
298
-
299
- for( let k in a )
300
- if( !(k in b) || !deepEqual( a[k], b[k] ) )
301
- return O
302
- return true;
303
- }
304
- export const
305
- assureSlices = ( root, names) =>
306
- names.split('|').filter(s=>s).map(n=>n.trim()).map( xp =>
307
- { const append = n=> (root.append(n),n);
308
- if(xp.includes('/'))
309
- { const ret = [], r = root.ownerDocument.evaluate( xp, root );
310
- for( let n; n = r.iterateNext(); )
311
- ret.push( n )
312
- return ret
313
- }
314
-
315
- return [...root.childNodes].find(n=>n.localName === xp) || append( create(xp,'',root.ownerDocument) );
316
- }).flat();
317
-
318
- /**
319
- *
320
- * @param x slice node
321
- * @param sliceNames slice name, xPath in /datadom/slice/
322
- * @param ev Event obj
323
- * @param dce
324
- */
325
- export function
326
- event2slice( x, sliceNames, ev, dce )
327
- {
328
- if( ev.sliceProcessed )
329
- return
330
- ev.sliceProcessed = 1;
331
- // evaluate slices[]
332
- // inject @attributes
333
- // inject event
334
- // evaluate slice-value
335
- // slice[i] = slice-value
336
- return assureSlices( x, sliceNames ?? '' ).map( s =>
337
- {
338
- const d = x.ownerDocument
339
- , el = ev.sliceEventSource
340
- , sel = ev.sliceElement
341
- , cleanSliceValue = ()=>[...s.childNodes].filter(n=>n.nodeType===3 || n.localName==='value' || n.localName==='form-data').map(n=>n.remove());
342
- el.getAttributeNames().map( a => s.setAttribute( a, attr(el,a) ) );
343
- [...s.childNodes].filter(n=>n.localName==='event').map(n=>n.remove());
344
- if( 'validationMessage' in el )
345
- s.setAttribute('validation-message', el.validationMessage);
346
- ev.type==='init' && cleanSliceValue();
347
- s.append( obj2node( ev, 'event', d ) );
348
- if( sel.hasAttribute('slice-value') )
349
- { if( el.value === undefined)
350
- s.removeAttribute('value')
351
- else
352
- s.setAttribute('value', el.value );
353
- const v = xPath( attr( sel, 'slice-value'),s );
354
- cleanSliceValue();
355
- s.append( createText( d, v ) );
356
- }else
357
- { if( 'elements' in el )
358
- { cleanSliceValue();
359
- s.append( obj2node(new FormData(el),'value', s.ownerDocument) )
360
- return s
361
- }
362
- const v = el.value ?? attr( sel, 'value' ) ;
363
- cleanSliceValue();
364
- if( v === null || v === undefined )
365
- [...s.childNodes].filter(n=>n.localName!=='event').map(n=>n.remove());
366
- else
367
- if( isString(v) )
368
- s.append( createText( d, v) );
369
- else
370
- s.append( obj2node(v,'value',s.ownerDocument) )
371
- }
372
- return s
373
- })
374
- }
375
-
376
- function forEach$( el, css, cb){
377
- if( el.querySelectorAll )
378
- [...el.querySelectorAll(css)].forEach(cb)
379
- }
380
- const loadTemplateRoots = async ( src, dce )=>
381
- {
382
- if( !src || !src.trim() )
383
- return [dce]
384
- if( src.startsWith('#') )
385
- return ( n =>
386
- { if(!n) return []
387
- const a = n.querySelectorAll(src)
388
- if( a.length )
389
- return [...a]
390
- const r = n.getRootNode();
391
- return r===n ? []: getByHashId(r)
392
- })(dce.parentElement)
393
- try
394
- { // todo cache
395
- const dom = await xhrTemplate(src)
396
- const hash = new URL(src, location).hash
397
- if( hash )
398
- { const ret = dom.querySelectorAll(hash);
399
- if( ret.length )
400
- return [...ret]
401
- return [dce]
402
- }
403
- return [dom]
404
- }catch (error){ return [dce]}
405
- }
406
- export function mergeAttr( from, to )
407
- { if( isText(from) )
408
- {
409
- if( !isText(to) ){ debugger }
410
- return
411
- }
412
- for( let a of from.attributes)
413
- { a.namespaceURI? to.setAttributeNS( a.namespaceURI, a.name, a.value ) : to.setAttribute( a.name, a.value )
414
- if( a.name === 'value')
415
- to.value = a.value
416
- }
417
- }
418
- export function assureUnique(n, id=0)
419
- {
420
- const m = {}
421
- for( const e of n.childNodes )
422
- {
423
- const a = attr(e,'data-dce-id') || e.dceId || 0;
424
- if( !m[a] )
425
- { if( !a )
426
- { m[a] = e.dceId = ++id;
427
- if( e.setAttribute )
428
- e.setAttribute('data-dce-id', e.dceId )
429
- }else
430
- m[a] = 1;
431
- }else
432
- { const v = e.dceId = a + '-' + m[a]++;
433
- if( e.setAttribute )
434
- e.setAttribute('data-dce-id', v )
435
- }
436
- e.childNodes.length && assureUnique(e)
437
- }
438
- }
439
- export function merge( parent, fromArr )
440
- {
441
- if(!fromArr.length)
442
- return removeChildren(parent);
443
- const id2old = {};
444
- for( let c of parent.childNodes)
445
- { ASSERT( !id2old[c.dceId] );
446
- if( isText(c) )
447
- { ASSERT( c.data.trim() );
448
- id2old[c.dceId || 0] = c;
449
- } else
450
- id2old[attr(c, 'data-dce-id') || 0] = c;
451
- }
452
- for( let e of [...fromArr] )
453
- { const k = attr(e, 'data-dce-id') || e.dceId;
454
- const o = id2old[ k ];
455
- if( o )
456
- { if( isText(e) )
457
- { if( o.nodeValue !== e.nodeValue )
458
- o.nodeValue = e.nodeValue;
459
- }else
460
- { mergeAttr(e,o)
461
- if( o.childNodes.length || e.childNodes.length )
462
- merge(o, e.childNodes)
463
- }
464
- delete id2old[ k ]
465
- }else
466
- parent.append( e )
467
- }
468
- for( let v of Object.values(id2old) )
469
- v.remove();
470
- }
471
- export function assureUID(n,attr)
472
- { if( !n.hasAttribute(attr) )
473
- n.setAttribute(attr, crypto.randomUUID());
474
- return n.getAttribute(attr)
475
- }
476
- export const evalCurly = s =>
477
- { const exp = [...s?.matchAll( /([^{}]*)(\{)([^}]+)}([^{}]*)/g ) ].map(l=>`${l[1]}{${ xPathDefaults(l[3] )}}${l[4]}`);
478
- return exp.join('');
479
- }
480
- export const xPathDefaults = x=>
481
- { if(!x.trim())
482
- return x;
483
- const xx = x.split('??')
484
- , a = xx.shift()
485
- , b = xPathDefaults(xx.join('??'));
486
-
487
- return xx.length ? `concat( ${a} , substring( ${b} , (1+string-length( ${b} )) * string-length( ${a} ) ) )`: x
488
- // return xx.length ? `${a}|(${xPathDefaults(xx.join('??'))})[not(${a})]`: a
489
- }
490
- export const xPath = (x,root)=>
491
- {
492
- const xx = x.split('??');
493
- if( xx.length > 1 )
494
- return xPath(xx[0], root) || xPath(xx[1], root);
495
-
496
- x = xPathDefaults(x);
497
-
498
- const it = root.ownerDocument.evaluate(x, root);
499
- switch( it.resultType )
500
- { case XPathResult.NUMBER_TYPE: return it.numberValue;
501
- case XPathResult.STRING_TYPE: return it.stringValue;
502
- case XPathResult.BOOLEAN_TYPE: return it.booleanValue;
503
- }
504
-
505
- let ret = '';
506
- for( let n ;n=it.iterateNext(); )
507
- ret += n.textContent;
508
- return ret
509
- }
510
- 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(',');
511
- export const toXsl = (el, defParent) => {
512
- const x = create('xsl:'+el.localName);
513
- for( let a of el.attributes )
514
- x.setAttribute( a.name, a.value );
515
- while(el.firstChild)
516
- x.append(el.firstChild);
517
- if( el.parentElement )
518
- el.parentElement.replaceChild( x, el );
519
- else
520
- { const p = (el.parentElement || defParent)
521
- , arr = [...p.childNodes];
522
- arr.forEach((n, i) => {
523
- if (n === el)
524
- arr[i] = x;
525
- });
526
- p.replaceChildren(...arr);
527
- }
528
- };
529
-
530
- export class
531
- CustomElement extends HTMLElement
532
- {
533
- static observedAttributes = ['src','tag','hidden'];
534
- async connectedCallback()
535
- {
536
- const templateRoots = await loadTemplateRoots( attr( this, 'src' ), this )
537
- , tag = attr( this, 'tag' )
538
- , tagName = tag ? tag : 'dce-'+crypto.randomUUID();
539
-
540
- for( const t of templateRoots )
541
- forEach$(t.templateNode||t.content||t, 'style',s=>{
542
- const slot = s.closest('slot');
543
- const sName = slot ? `slot[name="${slot.name}"]`:'';
544
- s.innerHTML = `${tagName} ${sName}{${s.innerHTML}}`;
545
- this.append(s);
546
- })
547
- const templateDocs = templateRoots.map( n => createXsltFromDom( n ) )
548
- , xp = templateDocs.map( (td, p) =>{ p = new XSLTProcessor(); p.importStylesheet( td ); return p })
549
-
550
- Object.defineProperty( this, "xsltString", { get: ()=>templateDocs.map( td => xmlString(td) ).join('\n') });
551
-
552
- const dce = this
553
- , sliceNodes = [...this.templateNode.querySelectorAll('[slice]')]
554
- , sliceNames = sliceNodes.map(e=>attr(e,'slice')).filter(n=>!n.includes('/')).filter((v, i, a)=>a.indexOf(v) === i)
555
- , declaredAttributes = templateDocs.reduce( (ret,t) => { if( t.params ) ret.push( ...t.params ); return ret; }, [] );
556
-
557
- class DceElement extends HTMLElement
558
- {
559
- static get observedAttributes(){ return declaredAttributes.map( a=>attr(a,'name')); }
560
- #inTransform = 0;
561
- connectedCallback()
562
- { let payload = this.childNodes;
563
- if( this.firstElementChild?.tagName === 'TEMPLATE' )
564
- {
565
- const t = this.firstElementChild;
566
- t.remove();
567
- payload = t.content.childNodes;
568
-
569
- for( const n of [...t.content.childNodes] )
570
- if( n.localName === 'style' ){
571
- const id = assureUID(this,'data-dce-style')
572
- n.innerHTML= `${tagName}[data-dce-style="${id}"]{${n.innerHTML}}`;
573
- t.insertAdjacentElement('beforebegin',n);
574
- }else
575
- if(n.nodeType===1)
576
- t.insertAdjacentElement('beforebegin',n);
577
- else if(n.nodeType===3)
578
- t.insertAdjacentText('beforebegin',n.data);
579
- }
580
- const x = xml2dom( `<datadom
581
- xmlns:xsl="${ XSL_NS_URL }"
582
- xmlns:xhtml="${ HTML_NS_URL }"
583
- xmlns:dce="urn:schemas-epa-wg:dce"
584
- />` ).documentElement;
585
- const createXmlNode = ( tag, t = '' ) => ( e =>
586
- { if( t )
587
- e.append( createText( x, t ))
588
- return e;
589
- })(x.ownerDocument.createElement( tag ))
590
- payload = [...payload].map(n=>x.ownerDocument.importNode(n,true));
591
- injectData( x, 'payload' , payload , assureSlot );
592
- this.innerHTML='';
593
- const attrsRoot = injectData( x, 'attributes' , this.attributes, e => createXmlNode( e.nodeName, e.value ) );
594
- injectData( x, 'dataset', Object.keys( this.dataset ), k => createXmlNode( k, this.dataset[ k ] ) );
595
- const sliceRoot = injectData( x, 'slice', sliceNames, k => createXmlNode( k, '' ) )
596
- , sliceXPath = x => xPath(x, sliceRoot);
597
- this.xml = x;
598
-
599
- const sliceEvents=[];
600
- const applySlices = ()=>
601
- { const processed = {}
602
-
603
- for(let ev; ev = sliceEvents.pop(); )
604
- { const s = attr( ev.sliceElement, 'slice');
605
- if( processed[s] )
606
- continue;
607
- event2slice( sliceRoot, s, ev, this );
608
- processed[s] = ev;
609
- }
610
- Object.keys(processed).length !== 0 && transform();
611
- }
612
- let timeoutID;
613
-
614
- this.onSlice = ev=>
615
- { sliceEvents.push(ev);
616
- if( !timeoutID )
617
- timeoutID = setTimeout(()=>
618
- { applySlices();
619
- timeoutID =0;
620
- },1);
621
- };
622
- const transform = this.transform = ()=>
623
- { if(this.#inTransform){ debugger }
624
- this.#inTransform = 1;
625
-
626
- const ff = xp.map( (p,i) =>
627
- { const f = p.transformToFragment(x.ownerDocument, document)
628
- if( !f )
629
- console.error( "XSLT transformation error. xsl:\n", xmlString(templateDocs[i]), '\nxml:\n', xmlString(x) );
630
- return f
631
- });
632
- ff.map( f =>
633
- { if( !f )
634
- return;
635
- assureUnique(f);
636
- merge( this, f.childNodes )
637
- })
638
-
639
- DceElement.observedAttributes.map( a =>
640
- { let v = attr(this.firstElementChild,a);
641
- if( v !== attr(this,a) )
642
- { this.setAttribute( a, v );
643
- this.#applyAttribute( a, v );
644
- }
645
- })
646
-
647
- forEach$( this,'[slice],[slice-event]', el =>
648
- { if( !el.dceInitialized )
649
- { el.dceInitialized = 1;
650
- let evs = attr(el,'slice-event');
651
- if( attr(el,'custom-validity') )
652
- evs += ' change submit';
653
-
654
- [...new Set((evs || 'change') .split(' '))]
655
- .forEach( t=> (el.localName==='slice'? el.parentElement : el)
656
- .addEventListener( t, ev=>
657
- { ev.sliceElement = el;
658
- ev.sliceEventSource = ev.currentTarget || ev.target;
659
- const slices = event2slice( sliceRoot, attr( ev.sliceElement, 'slice')||'', ev, this );
660
-
661
- forEach$(this,'[custom-validity]',el =>
662
- { if( !el.setCustomValidity )
663
- return;
664
- const x = attr( el, 'custom-validity' );
665
- try
666
- { const v = x && xPath( x, attrsRoot );
667
- el.setCustomValidity( v === true? '': v === false ? 'invalid' : v );
668
- }catch(err)
669
- { console.error(err, 'xPath', x) }
670
- })
671
- const x = attr(el,'custom-validity')
672
- , v = x && xPath( x, attrsRoot )
673
- , msg = v === true? '' : v;
674
- if( x )
675
- { el.setCustomValidity ? el.setCustomValidity( msg ) : ( el.validationMessage = msg );
676
- slices.map( s => s.setAttribute('validation-message', msg ) );
677
- if( ev.type === 'submit' )
678
- { if( v === true )
679
- return;
680
- setTimeout(transform,1)
681
- if( !!v === v )
682
- { v || ev.preventDefault();
683
- return v;
684
- }
685
- if( v )
686
- { ev.preventDefault();
687
- return !1
688
- }
689
- return ;
690
- }else
691
- setTimeout(transform,1)
692
- }
693
- this.onSlice(ev);
694
- } ));
695
- if( !evs || evs.includes('init') )
696
- { if( el.hasAttribute('slice-value') || el.hasAttribute('value') || el.value )
697
- this.onSlice({type:'init', target: el, sliceElement:el, sliceEventSource:el })
698
- else
699
- el.value = sliceXPath( attr(el,'slice') )
700
- }
701
- }
702
- });
703
- this.#inTransform = 0;
704
- };
705
- transform();
706
- applySlices();
707
- }
708
- #applyAttribute(name, newValue)
709
- { let a = this.xml.querySelector(`attributes>${name}`);
710
- if( a )
711
- emptyNode(a).append( createText(a,newValue) );
712
- else
713
- { a = create( name, newValue, this.xml );
714
- this.xml.querySelector('attributes').append( a );
715
- }
716
- }
717
- attributeChangedCallback(name, oldValue, newValue)
718
- { if( !this.xml || this.#inTransform )
719
- return;
720
- this.#applyAttribute(name, newValue);
721
- this.transform(); // needs throttling
722
- }
723
-
724
- get dce(){ return dce }
725
- }
726
- const registerTag = tag =>
727
- {
728
- if( window.customElements.get(tag) !== DceElement )
729
- window.customElements.define( tag, DceElement);
730
- };
731
- if(tag)
732
- registerTag(tag);
733
- else
734
- { const t = tagName;
735
- this.setAttribute('tag', t );
736
- registerTag(t);
737
- const el = document.createElement(t);
738
- this.getAttributeNames().forEach(a=>el.setAttribute(a,this.getAttribute(a)));
739
- el.append(...[...this.childNodes].filter( e => e.localName!=='style') );
740
- this.append(el);
741
- }
742
- }
743
- get templateNode(){ return this.firstElementChild?.tagName === 'TEMPLATE'? this.firstElementChild.content : this }
744
- get dce(){ return this }
745
-
746
- get xslt(){ return xml2dom( this.xsltString ) }
747
- }
748
-
749
- window.customElements.define( 'custom-element', CustomElement );
750
- export default CustomElement;