@epa-wg/custom-element 0.0.21 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/bin/xslDtd2Ide.mjs +1 -1
- package/custom-element.d.ts +4 -0
- package/custom-element.js +103 -42
- package/custom-element1-1.js +763 -0
- package/custom-element1.js +763 -0
- package/demo/a.html +38 -41
- package/demo/b.html +13 -0
- package/demo/data-slices.html +32 -0
- package/demo/form.html +193 -0
- package/demo/s.xml +19 -14
- package/demo/s.xslt +22 -38
- package/demo/s1.xslt +60 -0
- package/ide/customData-dce.json +14 -1
- package/ide/web-types-dce.json +6 -1
- package/ide/web-types-xsl.json +1 -1
- package/index.html +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -348,9 +348,9 @@ within template
|
|
|
348
348
|
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
|
|
349
349
|
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
|
|
350
350
|
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element
|
|
351
|
-
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
352
|
-
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
353
|
-
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.
|
|
351
|
+
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.22/coverage/src/custom-element/coverage.svg
|
|
352
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.22/coverage/src/custom-element/index.html
|
|
353
|
+
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.22/storybook-static/index.html?path=/story/welcome--introduction
|
|
354
354
|
[sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
|
|
355
355
|
[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
|
|
356
356
|
[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
|
package/bin/xslDtd2Ide.mjs
CHANGED
|
@@ -116,7 +116,7 @@ writeFileSync( '.././ide/customData-xsl.json', JSON.stringify( vsCode, undefined
|
|
|
116
116
|
const intelliJ = {
|
|
117
117
|
"$schema": "http://json.schemastore.org/web-types",
|
|
118
118
|
"name": "@epa-wg/custom-element",
|
|
119
|
-
"version": "0.0.
|
|
119
|
+
"version": "0.0.22",
|
|
120
120
|
"js-types-syntax": "typescript",
|
|
121
121
|
"description-markup": "markdown",
|
|
122
122
|
"contributions": {
|
package/custom-element.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export function log(x: any): void;
|
|
2
2
|
export function deepEqual(a: any, b:any): boolean|0;
|
|
3
|
+
export function xml2dom(xmlString:string): Document;
|
|
4
|
+
export function xmlString(doc:Node|Document): string;
|
|
5
|
+
export function obj2node(o:any, tag:string, doc:Document): HTMLElement;
|
|
6
|
+
export function tagUid(node:HTMLElement): HTMLElement;
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* @summary Declarative Custom Element as W3C proposal PoC with native(XSLT) based templating
|
package/custom-element.js
CHANGED
|
@@ -13,7 +13,6 @@ const attr = (el, attr)=> el.getAttribute?.(attr)
|
|
|
13
13
|
, createText = ( d, t) => (d.ownerDocument || d ).createTextNode( t )
|
|
14
14
|
, removeChildren = n => { while(n.firstChild) n.firstChild.remove(); return n; }
|
|
15
15
|
, emptyNode = n => { n.getAttributeNames().map( a => n.removeAttribute(a) ); return removeChildren(n); }
|
|
16
|
-
, createNS = ( ns, tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElementNS( ns, tag ))
|
|
17
16
|
, xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
|
|
18
17
|
, xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) )
|
|
19
18
|
, cloneAs = (p,tag) =>
|
|
@@ -23,7 +22,7 @@ const attr = (el, attr)=> el.getAttribute?.(attr)
|
|
|
23
22
|
while( p.firstChild )
|
|
24
23
|
px.append(p.firstChild);
|
|
25
24
|
return px;
|
|
26
|
-
}
|
|
25
|
+
};
|
|
27
26
|
|
|
28
27
|
function
|
|
29
28
|
ASSERT(x)
|
|
@@ -66,17 +65,22 @@ assureSlot( e )
|
|
|
66
65
|
export function
|
|
67
66
|
obj2node( o, tag, doc )
|
|
68
67
|
{ const t = typeof o;
|
|
69
|
-
if( t === 'function'){debugger}
|
|
70
68
|
if( t === 'string' )
|
|
71
69
|
return create(tag,o,doc);
|
|
72
70
|
if( t === 'number' )
|
|
73
71
|
return create(tag,''+o,doc);
|
|
74
72
|
|
|
75
73
|
if( o instanceof Array )
|
|
76
|
-
{ const ret = create('array');
|
|
74
|
+
{ const ret = create('array','',doc);
|
|
77
75
|
o.map( ae => ret.append( obj2node(ae,tag,doc)) );
|
|
78
76
|
return ret
|
|
79
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
|
+
}
|
|
80
84
|
const ret = create(tag,'',doc);
|
|
81
85
|
for( let k in o )
|
|
82
86
|
if( isNode(o[k]) || typeof o[k] ==='function' || o[k] instanceof Window )
|
|
@@ -91,13 +95,14 @@ obj2node( o, tag, doc )
|
|
|
91
95
|
export function
|
|
92
96
|
tagUid( node )
|
|
93
97
|
{ // {} to xsl:value-of
|
|
94
|
-
forEach$(node,'*',d => [...d.childNodes]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
forEach$(node,'*',d => [...d.childNodes]
|
|
99
|
+
.filter( e => e.nodeType === 3 && e.parentNode.localName !== 'style' && e.data )
|
|
100
|
+
.forEach( e=>
|
|
101
|
+
{ const s = e.data,
|
|
102
|
+
m = s.matchAll( /{([^}]*)}/g );
|
|
98
103
|
if(m)
|
|
99
104
|
{ let l = 0
|
|
100
|
-
, txt = t => createText(e,t
|
|
105
|
+
, txt = t => createText(e,t)
|
|
101
106
|
, tt = [];
|
|
102
107
|
[...m].forEach(t=>
|
|
103
108
|
{ if( t.index > l )
|
|
@@ -107,8 +112,8 @@ tagUid( node )
|
|
|
107
112
|
tt.push(v);
|
|
108
113
|
l = t.index+t[0].length;
|
|
109
114
|
})
|
|
110
|
-
if( l <
|
|
111
|
-
tt.push( txt(
|
|
115
|
+
if( l < s.length)
|
|
116
|
+
tt.push( txt( s.substring(l,s.length) ));
|
|
112
117
|
if( tt.length )
|
|
113
118
|
{ for( let t of tt )
|
|
114
119
|
d.insertBefore(t,e);
|
|
@@ -250,7 +255,7 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
|
|
|
250
255
|
const slotCall = $(xslDom,'call-template[name="slot"]')
|
|
251
256
|
, slot2xsl = s =>
|
|
252
257
|
{ const v = slotCall.cloneNode(true)
|
|
253
|
-
, name = attr(s,'name')
|
|
258
|
+
, name = attr(s,'name');
|
|
254
259
|
name && v.firstElementChild.setAttribute('select',`'${ name }'`)
|
|
255
260
|
for( let c of s.childNodes)
|
|
256
261
|
v.lastElementChild.append(c)
|
|
@@ -297,16 +302,20 @@ deepEqual(a, b, O=false)
|
|
|
297
302
|
return O
|
|
298
303
|
return true;
|
|
299
304
|
}
|
|
305
|
+
const splitSliceNames = v => v.split('|').map( s=>s.trim() ).filter(s=>s);
|
|
306
|
+
|
|
300
307
|
export const
|
|
301
308
|
assureSlices = ( root, names) =>
|
|
302
|
-
names
|
|
303
|
-
{
|
|
304
|
-
|
|
309
|
+
splitSliceNames(names).map( xp =>
|
|
310
|
+
{ let d = root.ownerDocument
|
|
311
|
+
, append = n=> (root.append(n),n);
|
|
312
|
+
if(xp.includes('/'))
|
|
313
|
+
{ const ret = [], r = d.evaluate( xp, root );
|
|
305
314
|
for( let n; n = r.iterateNext(); )
|
|
306
315
|
ret.push( n )
|
|
307
316
|
return ret
|
|
308
317
|
}
|
|
309
|
-
return [...root.childNodes].find(n=>n.localName === xp) || create(xp);
|
|
318
|
+
return [...root.childNodes].find(n=>n.localName === xp) || append( create(xp,'',d) );
|
|
310
319
|
}).flat();
|
|
311
320
|
|
|
312
321
|
/**
|
|
@@ -319,19 +328,24 @@ assureSlices = ( root, names) =>
|
|
|
319
328
|
export function
|
|
320
329
|
event2slice( x, sliceNames, ev, dce )
|
|
321
330
|
{
|
|
331
|
+
if( ev.sliceProcessed )
|
|
332
|
+
return
|
|
333
|
+
ev.sliceProcessed = 1;
|
|
322
334
|
// evaluate slices[]
|
|
323
335
|
// inject @attributes
|
|
324
336
|
// inject event
|
|
325
337
|
// evaluate slice-value
|
|
326
338
|
// slice[i] = slice-value
|
|
327
|
-
assureSlices(x,sliceNames).map( s =>
|
|
339
|
+
return assureSlices( x, sliceNames ?? '' ).map( s =>
|
|
328
340
|
{
|
|
329
341
|
const d = x.ownerDocument
|
|
330
342
|
, el = ev.sliceEventSource
|
|
331
343
|
, sel = ev.sliceElement
|
|
332
|
-
, cleanSliceValue = ()=>[...s.childNodes].filter(n=>n.nodeType===3 || n.localName==='value').map(n=>n.remove());
|
|
344
|
+
, cleanSliceValue = ()=>[...s.childNodes].filter(n=>n.nodeType===3 || n.localName==='value' || n.localName==='form-data').map(n=>n.remove());
|
|
333
345
|
el.getAttributeNames().map( a => s.setAttribute( a, attr(el,a) ) );
|
|
334
346
|
[...s.childNodes].filter(n=>n.localName==='event').map(n=>n.remove());
|
|
347
|
+
if( 'validationMessage' in el )
|
|
348
|
+
s.setAttribute('validation-message', el.validationMessage);
|
|
335
349
|
ev.type==='init' && cleanSliceValue();
|
|
336
350
|
s.append( obj2node( ev, 'event', d ) );
|
|
337
351
|
if( sel.hasAttribute('slice-value') )
|
|
@@ -343,7 +357,12 @@ event2slice( x, sliceNames, ev, dce )
|
|
|
343
357
|
cleanSliceValue();
|
|
344
358
|
s.append( createText( d, v ) );
|
|
345
359
|
}else
|
|
346
|
-
{
|
|
360
|
+
{ if( 'elements' in el )
|
|
361
|
+
{ cleanSliceValue();
|
|
362
|
+
s.append( obj2node(new FormData(el),'value', s.ownerDocument) )
|
|
363
|
+
return s
|
|
364
|
+
}
|
|
365
|
+
const v = el.value ?? attr( sel, 'value' ) ;
|
|
347
366
|
cleanSliceValue();
|
|
348
367
|
if( v === null || v === undefined )
|
|
349
368
|
[...s.childNodes].filter(n=>n.localName!=='event').map(n=>n.remove());
|
|
@@ -353,6 +372,7 @@ event2slice( x, sliceNames, ev, dce )
|
|
|
353
372
|
else
|
|
354
373
|
s.append( obj2node(v,'value',s.ownerDocument) )
|
|
355
374
|
}
|
|
375
|
+
return s
|
|
356
376
|
})
|
|
357
377
|
}
|
|
358
378
|
|
|
@@ -360,7 +380,6 @@ function forEach$( el, css, cb){
|
|
|
360
380
|
if( el.querySelectorAll )
|
|
361
381
|
[...el.querySelectorAll(css)].forEach(cb)
|
|
362
382
|
}
|
|
363
|
-
const getByHashId = ( n, id )=> ( p => n===p? null: (p && ( p.querySelector(id) || getByHashId(p,id) ) ))( n.getRootNode() )
|
|
364
383
|
const loadTemplateRoots = async ( src, dce )=>
|
|
365
384
|
{
|
|
366
385
|
if( !src || !src.trim() )
|
|
@@ -388,12 +407,7 @@ const loadTemplateRoots = async ( src, dce )=>
|
|
|
388
407
|
}catch (error){ return [dce]}
|
|
389
408
|
}
|
|
390
409
|
export function mergeAttr( from, to )
|
|
391
|
-
{
|
|
392
|
-
{
|
|
393
|
-
if( !isText(to) ){ debugger }
|
|
394
|
-
return
|
|
395
|
-
}
|
|
396
|
-
for( let a of from.attributes)
|
|
410
|
+
{ for( let a of from.attributes)
|
|
397
411
|
{ a.namespaceURI? to.setAttributeNS( a.namespaceURI, a.name, a.value ) : to.setAttribute( a.name, a.value )
|
|
398
412
|
if( a.name === 'value')
|
|
399
413
|
to.value = a.value
|
|
@@ -472,12 +486,18 @@ export const xPathDefaults = x=>
|
|
|
472
486
|
// return xx.length ? `${a}|(${xPathDefaults(xx.join('??'))})[not(${a})]`: a
|
|
473
487
|
}
|
|
474
488
|
export const xPath = (x,root)=>
|
|
475
|
-
{
|
|
489
|
+
{
|
|
490
|
+
const xx = x.split('??');
|
|
491
|
+
if( xx.length > 1 )
|
|
492
|
+
return xPath(xx[0], root) || xPath(xx[1], root);
|
|
493
|
+
|
|
494
|
+
x = xPathDefaults(x);
|
|
476
495
|
|
|
477
496
|
const it = root.ownerDocument.evaluate(x, root);
|
|
478
497
|
switch( it.resultType )
|
|
479
498
|
{ case XPathResult.NUMBER_TYPE: return it.numberValue;
|
|
480
499
|
case XPathResult.STRING_TYPE: return it.stringValue;
|
|
500
|
+
case XPathResult.BOOLEAN_TYPE: return it.booleanValue;
|
|
481
501
|
}
|
|
482
502
|
|
|
483
503
|
let ret = '';
|
|
@@ -529,7 +549,10 @@ CustomElement extends HTMLElement
|
|
|
529
549
|
|
|
530
550
|
const dce = this
|
|
531
551
|
, sliceNodes = [...this.templateNode.querySelectorAll('[slice]')]
|
|
532
|
-
, sliceNames = sliceNodes.map(e=>attr(e,'slice'))
|
|
552
|
+
, sliceNames = sliceNodes.map(e=>attr(e,'slice'))
|
|
553
|
+
.filter(n=>!n.includes('/'))
|
|
554
|
+
.filter((v, i, a)=>a.indexOf(v) === i)
|
|
555
|
+
.map(splitSliceNames).flat()
|
|
533
556
|
, declaredAttributes = templateDocs.reduce( (ret,t) => { if( t.params ) ret.push( ...t.params ); return ret; }, [] );
|
|
534
557
|
|
|
535
558
|
class DceElement extends HTMLElement
|
|
@@ -540,6 +563,8 @@ CustomElement extends HTMLElement
|
|
|
540
563
|
{ let payload = this.childNodes;
|
|
541
564
|
if( this.firstElementChild?.tagName === 'TEMPLATE' )
|
|
542
565
|
{
|
|
566
|
+
if( this.firstElementChild !== this.lastElementChild )
|
|
567
|
+
{ console.error('payload should have TEMPLATE as only child', this.outerHTML ) }
|
|
543
568
|
const t = this.firstElementChild;
|
|
544
569
|
t.remove();
|
|
545
570
|
payload = t.content.childNodes;
|
|
@@ -563,7 +588,7 @@ CustomElement extends HTMLElement
|
|
|
563
588
|
})(x.ownerDocument.createElement( tag ))
|
|
564
589
|
injectData( x, 'payload' , payload , assureSlot );
|
|
565
590
|
this.innerHTML='';
|
|
566
|
-
injectData( x, 'attributes' , this.attributes, e => createXmlNode( e.nodeName, e.value ) );
|
|
591
|
+
const attrsRoot = injectData( x, 'attributes' , this.attributes, e => createXmlNode( e.nodeName, e.value ) );
|
|
567
592
|
injectData( x, 'dataset', Object.keys( this.dataset ), k => createXmlNode( k, this.dataset[ k ] ) );
|
|
568
593
|
const sliceRoot = injectData( x, 'slice', sliceNames, k => createXmlNode( k, '' ) )
|
|
569
594
|
, sliceXPath = x => xPath(x, sliceRoot);
|
|
@@ -585,14 +610,12 @@ CustomElement extends HTMLElement
|
|
|
585
610
|
let timeoutID;
|
|
586
611
|
|
|
587
612
|
this.onSlice = ev=>
|
|
588
|
-
{
|
|
589
|
-
ev.sliceEventSource = ev.currentTarget || ev.target;
|
|
590
|
-
sliceEvents.push(ev);
|
|
613
|
+
{ sliceEvents.push(ev);
|
|
591
614
|
if( !timeoutID )
|
|
592
615
|
timeoutID = setTimeout(()=>
|
|
593
616
|
{ applySlices();
|
|
594
617
|
timeoutID =0;
|
|
595
|
-
},
|
|
618
|
+
},1);
|
|
596
619
|
};
|
|
597
620
|
const transform = this.transform = ()=>
|
|
598
621
|
{ if(this.#inTransform){ debugger }
|
|
@@ -619,20 +642,58 @@ CustomElement extends HTMLElement
|
|
|
619
642
|
}
|
|
620
643
|
})
|
|
621
644
|
|
|
622
|
-
forEach$( this,'[slice]', el =>
|
|
645
|
+
forEach$( this,'[slice],[slice-event]', el =>
|
|
623
646
|
{ if( !el.dceInitialized )
|
|
624
647
|
{ el.dceInitialized = 1;
|
|
625
|
-
|
|
626
|
-
(
|
|
627
|
-
|
|
648
|
+
let evs = attr(el,'slice-event');
|
|
649
|
+
if( attr(el,'custom-validity') )
|
|
650
|
+
evs += ' change submit';
|
|
651
|
+
|
|
652
|
+
[...new Set((evs || 'change') .split(' '))]
|
|
628
653
|
.forEach( t=> (el.localName==='slice'? el.parentElement : el)
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
654
|
+
.addEventListener( t, ev=>
|
|
655
|
+
{ ev.sliceElement = el;
|
|
656
|
+
ev.sliceEventSource = ev.currentTarget || ev.target;
|
|
657
|
+
const slices = event2slice( sliceRoot, attr( ev.sliceElement, 'slice'), ev, this );
|
|
658
|
+
|
|
659
|
+
forEach$(this,'[custom-validity]',el =>
|
|
660
|
+
{ if( !el.setCustomValidity )
|
|
661
|
+
return;
|
|
662
|
+
const x = attr( el, 'custom-validity' );
|
|
663
|
+
try
|
|
664
|
+
{ const v = x && xPath( x, attrsRoot );
|
|
665
|
+
el.setCustomValidity( v === true? '': v === false ? 'invalid' : v );
|
|
666
|
+
}catch(err)
|
|
667
|
+
{ console.error(err, 'xPath', x) }
|
|
668
|
+
})
|
|
669
|
+
const x = attr(el,'custom-validity')
|
|
670
|
+
, v = x && xPath( x, attrsRoot )
|
|
671
|
+
, msg = v === true? '' : v;
|
|
672
|
+
|
|
673
|
+
if( x )
|
|
674
|
+
{ el.setCustomValidity ? el.setCustomValidity( msg ) : ( el.validationMessage = msg );
|
|
675
|
+
slices.map( s => s.setAttribute('validation-message', msg ) );
|
|
676
|
+
if( ev.type === 'submit' )
|
|
677
|
+
{ if( v === true )
|
|
678
|
+
return;
|
|
679
|
+
setTimeout(transform,1)
|
|
680
|
+
if( !!v === v )
|
|
681
|
+
{ v || ev.preventDefault();
|
|
682
|
+
return v;
|
|
683
|
+
}
|
|
684
|
+
if( v )
|
|
685
|
+
{ ev.preventDefault();
|
|
686
|
+
return !1
|
|
687
|
+
}
|
|
688
|
+
return ;
|
|
689
|
+
}else
|
|
690
|
+
setTimeout(transform,1)
|
|
691
|
+
}
|
|
692
|
+
this.onSlice(ev);
|
|
693
|
+
} ));
|
|
633
694
|
if( !evs || evs.includes('init') )
|
|
634
695
|
{ if( el.hasAttribute('slice-value') || el.hasAttribute('value') || el.value )
|
|
635
|
-
this.onSlice({type:'init', target: el, sliceElement:el })
|
|
696
|
+
this.onSlice({type:'init', target: el, sliceElement:el, sliceEventSource:el })
|
|
636
697
|
else
|
|
637
698
|
el.value = sliceXPath( attr(el,'slice') )
|
|
638
699
|
}
|