@epa-wg/custom-element 0.0.21 → 0.0.23
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/demo/a.html +38 -41
- package/demo/b.html +13 -0
- package/demo/data-slices.html +32 -0
- package/demo/form.html +240 -0
- package/demo/s.xml +11 -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.23/coverage/src/custom-element/coverage.svg
|
|
352
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.23/coverage/src/custom-element/index.html
|
|
353
|
+
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-dist@0.0.23/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.23",
|
|
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
|
}
|
package/demo/a.html
CHANGED
|
@@ -1,63 +1,60 @@
|
|
|
1
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
|
-
xmlns:html="http://www.w3.org/1999/xhtml">
|
|
2
|
+
<html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
4
3
|
<head>
|
|
5
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
6
|
-
<title>
|
|
5
|
+
<title>Data slices - Declarative Custom Element implementation demo</title>
|
|
7
6
|
<link rel="icon" href="./wc-square.svg"/>
|
|
7
|
+
|
|
8
8
|
<script type="module" src="../http-request.js"></script>
|
|
9
|
-
<script type="module" src="../local-storage.js"></script>
|
|
10
9
|
<script type="module" src="../custom-element.js"></script>
|
|
11
|
-
|
|
12
10
|
<style>
|
|
13
11
|
@import "./demo.css";
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
table {
|
|
20
|
-
min-width: 16rem;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
td {
|
|
24
|
-
border-bottom: 1px solid silver;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
tfoot td {
|
|
28
|
-
border-bottom: none;
|
|
13
|
+
label {
|
|
14
|
+
display: flex;
|
|
29
15
|
}
|
|
30
16
|
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
label:has(input[type="text"],input[type="password"],input:not([type]) ) {
|
|
18
|
+
flex-direction: column;
|
|
33
19
|
}
|
|
34
20
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
font-weight: bolder;
|
|
38
|
-
font-family: sans-serif;
|
|
21
|
+
nav {
|
|
22
|
+
max-width: 32em;
|
|
39
23
|
}
|
|
40
24
|
</style>
|
|
25
|
+
<!-- https://github.com/mdn/learning-area/blob/main/html/forms/form-validation/custom-error-message.html
|
|
26
|
+
todo: apply setCustomValidity( warningStr )
|
|
27
|
+
-->
|
|
28
|
+
|
|
41
29
|
</head>
|
|
42
30
|
<body>
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
<fieldset>
|
|
33
|
+
<legend><b style="color:green">green</b> in instance style can be overridden in payload as <i
|
|
34
|
+
style="color:red">red</i> in 1st instance
|
|
35
|
+
</legend>
|
|
36
|
+
<custom-element tag="dce-3">
|
|
37
|
+
<template>
|
|
38
|
+
<u>
|
|
39
|
+
<slot>is green</slot>
|
|
40
|
+
</u>
|
|
52
41
|
</template>
|
|
42
|
+
<style>dce-3 {
|
|
43
|
+
color: green
|
|
44
|
+
}</style>
|
|
53
45
|
</custom-element>
|
|
54
|
-
<
|
|
55
|
-
<dce-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
</
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
46
|
+
<u>should be</u> <i style="color:red">red</i>:
|
|
47
|
+
<dce-3 id="dce32">
|
|
48
|
+
<template>
|
|
49
|
+
<style> color:red; </style>
|
|
50
|
+
<u>red</u>
|
|
51
|
+
</template>
|
|
52
|
+
</dce-3> <br/>
|
|
53
|
+
should be GREEN:
|
|
54
|
+
<dce-3 id="dce31">green</dce-3>
|
|
55
|
+
</fieldset>
|
|
56
|
+
|
|
57
|
+
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
58
|
+
|
|
62
59
|
</body>
|
|
63
60
|
</html>
|
package/demo/b.html
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<dce-root data-dce-id="1" xmlns="http://www.w3.org/1999/xhtml" xmlns:dce="urn:schemas-epa-wg:dce"
|
|
3
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml"><u data-dce-id="2" xmlns="">
|
|
4
|
+
<dce-text data-dce-id="3">
|
|
5
|
+
<xhtml:span xmlns:xsl="http://www.w3.org/1999/XSL/Transform" slot=""/>
|
|
6
|
+
<xhtml:style xmlns:xsl="http://www.w3.org/1999/XSL/Transform" slot="" title="ABC">
|
|
7
|
+
dce-3[data-dce-style="54f96d52-ce70-435d-83c4-b421357d9a17"]{ color:red; }
|
|
8
|
+
</xhtml:style>
|
|
9
|
+
<xhtml:span xmlns:xsl="http://www.w3.org/1999/XSL/Transform" slot=""/>
|
|
10
|
+
<xhtml:u xmlns:xsl="http://www.w3.org/1999/XSL/Transform" slot="">red</xhtml:u>
|
|
11
|
+
<xhtml:span xmlns:xsl="http://www.w3.org/1999/XSL/Transform" slot=""/>
|
|
12
|
+
</dce-text>
|
|
13
|
+
</u></dce-root>
|
package/demo/data-slices.html
CHANGED
|
@@ -178,6 +178,38 @@
|
|
|
178
178
|
</template>
|
|
179
179
|
</html-demo-element>
|
|
180
180
|
|
|
181
|
+
|
|
182
|
+
<html-demo-element legend="10. multiple slices by same field"
|
|
183
|
+
description="same element value sets s1 and s2 slice">
|
|
184
|
+
<template>
|
|
185
|
+
<custom-element>
|
|
186
|
+
<template>
|
|
187
|
+
<input slice="s1|s2"
|
|
188
|
+
slice-event="input"
|
|
189
|
+
data-testid="f1"
|
|
190
|
+
/><br/>
|
|
191
|
+
Type to update s1 and s2 slices <br/>
|
|
192
|
+
slice <code>s1: {//slice/s1}</code><br/>
|
|
193
|
+
slice <code>s2: {//slice/s2}</code><br/>
|
|
194
|
+
</template>
|
|
195
|
+
</custom-element>
|
|
196
|
+
</template>
|
|
197
|
+
</html-demo-element>
|
|
198
|
+
|
|
199
|
+
<html-demo-element legend="11. slices and attribute"
|
|
200
|
+
description="initial attribute value should be smile as emoji and :) on blur from input it should be updated from value">
|
|
201
|
+
<template>
|
|
202
|
+
<custom-element>
|
|
203
|
+
<template>
|
|
204
|
+
<attribute name="emotion">😃</attribute>
|
|
205
|
+
<input slice="/datadom/attributes/emotion | s1"/>
|
|
206
|
+
Type and unfocus to update emotion attribute: {emotion}
|
|
207
|
+
and slice: {//slice/s1}
|
|
208
|
+
</template>
|
|
209
|
+
</custom-element>
|
|
210
|
+
</template>
|
|
211
|
+
</html-demo-element>
|
|
212
|
+
|
|
181
213
|
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
182
214
|
|
|
183
215
|
</body>
|
package/demo/form.html
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
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>Forms - Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg"/>
|
|
7
|
+
|
|
8
|
+
<script type="module" src="../local-storage.js"></script>
|
|
9
|
+
<script type="module" src="../custom-element.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
@import "./demo.css";
|
|
12
|
+
|
|
13
|
+
label {
|
|
14
|
+
display: flex;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
label:has(input[type="text"],input[type="password"],input:not([type]) ) {
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
nav {
|
|
22
|
+
max-width: 32em;
|
|
23
|
+
}
|
|
24
|
+
</style>
|
|
25
|
+
<!-- https://github.com/mdn/learning-area/blob/main/html/forms/form-validation/custom-error-message.html
|
|
26
|
+
todo: apply setCustomValidity( warningStr )
|
|
27
|
+
-->
|
|
28
|
+
|
|
29
|
+
</head>
|
|
30
|
+
<body>
|
|
31
|
+
|
|
32
|
+
<nav>
|
|
33
|
+
<a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
|
|
34
|
+
|
|
35
|
+
<p> <b>formData</b><br/>
|
|
36
|
+
The values of named form fields are populated into the <b>slice</b> as <b>form-data</b> on <var>change</var>
|
|
37
|
+
or <var>submit</var> event. The field values can be used in form validation via <var>custom-validity</var>
|
|
38
|
+
attribute
|
|
39
|
+
and in condition to enabling the form parts
|
|
40
|
+
<a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData">formData MDN</a>
|
|
41
|
+
</p>
|
|
42
|
+
<details>
|
|
43
|
+
<summary>slice to form-data mapping</summary>
|
|
44
|
+
<html-demo-element>
|
|
45
|
+
<template>
|
|
46
|
+
<datadom hidden>
|
|
47
|
+
<slice>
|
|
48
|
+
<signin-form>
|
|
49
|
+
<form-data>
|
|
50
|
+
<username>QWE</username>
|
|
51
|
+
<password>ASD</password>
|
|
52
|
+
</form-data>
|
|
53
|
+
</signin-form>
|
|
54
|
+
</slice>
|
|
55
|
+
</datadom>
|
|
56
|
+
</template>
|
|
57
|
+
</html-demo-element>
|
|
58
|
+
</details>
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
<p> <b> custom-validity attribute </b><br/>
|
|
62
|
+
applied on the form itself or on the form field.<br/>
|
|
63
|
+
The value is an XPath over DCE <var>datadom</var>. When evaluated as <u>boolean</u>, it would enable(true) or
|
|
64
|
+
disable(false)
|
|
65
|
+
the form submission, acting as form validation mechanism.<br>
|
|
66
|
+
Alternatively, the value can be evaluated as a <u>string</u> which would be treated as an error and can be used
|
|
67
|
+
as
|
|
68
|
+
validation error message set as <var>@validation-message</var> attribute on the form slice.
|
|
69
|
+
Look for <var>email-form/@validation-message</var> example on the page.<br/>
|
|
70
|
+
</p>
|
|
71
|
+
<p> When <var>custom-validity</var> attribute is set on the field, its XPath evaluated value is propagated to
|
|
72
|
+
<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage">
|
|
73
|
+
validationMessage property</a>. Which would be shown via browser system popup as the field validation error.
|
|
74
|
+
</p>
|
|
75
|
+
<p> <var>@validation-message</var> is set either by <var>custom-validity</var> attribute or by browser as system message.
|
|
76
|
+
By default, it is shown as popup on the field validation. But also is available for template as a string via
|
|
77
|
+
form field attribute. Like in <var>email-form/@validation-message</var>.
|
|
78
|
+
|
|
79
|
+
</p>
|
|
80
|
+
|
|
81
|
+
<a href="https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation">Form Validation MDN</a>
|
|
82
|
+
</nav>
|
|
83
|
+
|
|
84
|
+
<html-demo-element legend="1. Simple validation"
|
|
85
|
+
description="custom-validity boolean value prevents submission, username length switches Next to 'Sign In' button ">
|
|
86
|
+
<ol>
|
|
87
|
+
<li> Click Next, observe the warning</li>
|
|
88
|
+
<li> Fill input with 10+ characters</li>
|
|
89
|
+
<li> Click Next, the password and "Sign In" button should appear</li>
|
|
90
|
+
</ol>
|
|
91
|
+
<template>
|
|
92
|
+
<custom-element>
|
|
93
|
+
<template>
|
|
94
|
+
<form slice="signin-form"
|
|
95
|
+
custom-validity="
|
|
96
|
+
string-length(/datadom/slice/signin-form/form-data/username) > 10
|
|
97
|
+
and string-length(//form-data/password) > 3 "
|
|
98
|
+
>
|
|
99
|
+
<label> Email
|
|
100
|
+
<input name="username" autocomplete="username" placeholder="Email, phone, or username"
|
|
101
|
+
required="">
|
|
102
|
+
</label>
|
|
103
|
+
<variable name="showpassword" select="string-length(//form-data/username) > 10 "></variable>
|
|
104
|
+
<if test="not($showpassword)">
|
|
105
|
+
<button slice="confirm" slice-event="click" slice-value="'password'">Next</button>
|
|
106
|
+
</if>
|
|
107
|
+
<if test="$showpassword">
|
|
108
|
+
<label>Enter password: <input name="password" type="password" required> </label>
|
|
109
|
+
<button>Sign In</button>
|
|
110
|
+
</if>
|
|
111
|
+
username {//username}
|
|
112
|
+
</form>
|
|
113
|
+
</template>
|
|
114
|
+
</custom-element>
|
|
115
|
+
</template>
|
|
116
|
+
</html-demo-element>
|
|
117
|
+
|
|
118
|
+
<html-demo-element legend="2. Form life cycle demo"
|
|
119
|
+
description="form-data in the form slice is the source of truth">
|
|
120
|
+
|
|
121
|
+
<template>
|
|
122
|
+
<custom-element>
|
|
123
|
+
<template>
|
|
124
|
+
<form slice="signin-form"
|
|
125
|
+
custom-validity="
|
|
126
|
+
string-length(/datadom/slice/signin-form/form-data/username) > 9
|
|
127
|
+
and ( ( //confirm-by = 'sms' )
|
|
128
|
+
or ( //confirm-by = 'email' )
|
|
129
|
+
or ( //confirm-by = 'password' and string-length(//form-data/password) > 3 )
|
|
130
|
+
)
|
|
131
|
+
"
|
|
132
|
+
>
|
|
133
|
+
<!-- form validity should be based on form-data -->
|
|
134
|
+
<variable name="warn">
|
|
135
|
+
<if test="string-length(//username-slice) < 9 ">
|
|
136
|
+
Should be 10 or more symbols.
|
|
137
|
+
<!-- updated by slice on input event -->
|
|
138
|
+
</if>
|
|
139
|
+
<if test="//form-data/confirm-by = 'sms'">
|
|
140
|
+
Message and Data Rates may apply.
|
|
141
|
+
<!-- updated by form change by radio select -->
|
|
142
|
+
</if>
|
|
143
|
+
</variable>
|
|
144
|
+
<label> Enter your email, phone, or user name
|
|
145
|
+
<input name="username" autocomplete="username"
|
|
146
|
+
placeholder="Email, phone, or username"
|
|
147
|
+
custom-validity="( string-length(//username-slice) > 9 ) ?? 'should be 10+ symbols'"
|
|
148
|
+
slice-event="input"
|
|
149
|
+
slice="username-slice"
|
|
150
|
+
required
|
|
151
|
+
/>
|
|
152
|
+
</label>
|
|
153
|
+
<var> {$warn} </var>
|
|
154
|
+
<fieldset>
|
|
155
|
+
<legend>Confirm by</legend>
|
|
156
|
+
<label><input type="radio" name="confirm-by" value="email"/> email </label>
|
|
157
|
+
<label><input type="radio" name="confirm-by" value="sms"/> text to phone </label>
|
|
158
|
+
<label><input type="radio" name="confirm-by" value="password"/> password </label>
|
|
159
|
+
<if test="/datadom/slice/signin-form/form-data/confirm-by = 'password'">
|
|
160
|
+
<label>Enter password: <input type="password" NAME="password"
|
|
161
|
+
custom-validity="( string-length(//form-data/password) > 3 ) ?? 'password is too short'"
|
|
162
|
+
/></label>
|
|
163
|
+
</if>
|
|
164
|
+
<if test="not(//confirm-by)">
|
|
165
|
+
Please select the auth method
|
|
166
|
+
</if>
|
|
167
|
+
</fieldset>
|
|
168
|
+
<section>
|
|
169
|
+
<button>Sign In</button>
|
|
170
|
+
</section>
|
|
171
|
+
</form>
|
|
172
|
+
//username-slice {//username-slice}<br/>
|
|
173
|
+
//username {//username}<br/>
|
|
174
|
+
//confirm-by {//confirm-by}<br/>
|
|
175
|
+
//password {//password}
|
|
176
|
+
</template>
|
|
177
|
+
</custom-element>
|
|
178
|
+
</template>
|
|
179
|
+
</html-demo-element>
|
|
180
|
+
|
|
181
|
+
<html-demo-element legend="3. read system validity message"
|
|
182
|
+
description="validationMessage propagated into slice as 'validation-message' attribute ">
|
|
183
|
+
<ol>
|
|
184
|
+
<li> type in input field</li>
|
|
185
|
+
<li> delete input field content</li>
|
|
186
|
+
<li> observe the warning in string bellow input</li>
|
|
187
|
+
<li> Click Next observe the system warning in dropdown and in string bellow input</li>
|
|
188
|
+
</ol>
|
|
189
|
+
<template>
|
|
190
|
+
<custom-element>
|
|
191
|
+
<template>
|
|
192
|
+
<form slice="email-form">
|
|
193
|
+
<label> Email
|
|
194
|
+
<input slice="username" slice-event="input" placeholder="non-empty" required>
|
|
195
|
+
</label>
|
|
196
|
+
<if test="//username/@validation-message">
|
|
197
|
+
<var>{//username/@validation-message}</var>
|
|
198
|
+
</if>
|
|
199
|
+
<button>Next</button>
|
|
200
|
+
<p>{//email-form/@validation-message}</p>
|
|
201
|
+
</form>
|
|
202
|
+
</template>
|
|
203
|
+
</custom-element>
|
|
204
|
+
</template>
|
|
205
|
+
</html-demo-element>
|
|
206
|
+
|
|
207
|
+
<html-demo-element legend="4. form validity message"
|
|
208
|
+
description="@validation-message propagated into form slice and ">
|
|
209
|
+
<ol>
|
|
210
|
+
<li> type up to 3 chars in input field</li>
|
|
211
|
+
<li> observe the slice value change</li>
|
|
212
|
+
<li> click next</li>
|
|
213
|
+
<li> observe the warning bellow the button</li>
|
|
214
|
+
</ol>
|
|
215
|
+
<template>
|
|
216
|
+
<custom-element>
|
|
217
|
+
<template>
|
|
218
|
+
<form slice="email-form"
|
|
219
|
+
custom-validity=" string-length(//slice/username) > 3 ??
|
|
220
|
+
concat('should be more than 3 characters, now is ',string-length(//slice/username) ) "
|
|
221
|
+
>
|
|
222
|
+
<label> Email
|
|
223
|
+
<input name="email" slice="username" slice-event="input" placeholder="non-empty" required/>
|
|
224
|
+
</label>
|
|
225
|
+
<if test="//username/@validation-message">
|
|
226
|
+
<var>{//username/@validation-message}</var>
|
|
227
|
+
</if>
|
|
228
|
+
<button>Next</button>
|
|
229
|
+
<p>//email-form/@validation-message: {//email-form/@validation-message} </p>
|
|
230
|
+
<p>//slice/username: {//slice/username} </p>
|
|
231
|
+
</form>
|
|
232
|
+
</template>
|
|
233
|
+
</custom-element>
|
|
234
|
+
</template>
|
|
235
|
+
</html-demo-element>
|
|
236
|
+
|
|
237
|
+
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
238
|
+
|
|
239
|
+
</body>
|
|
240
|
+
</html>
|
package/demo/s.xml
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<br />
|
|
13
|
-
undefined
|
|
14
|
-
</div>
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<datadom>
|
|
3
|
+
<slice>
|
|
4
|
+
<signin-form>
|
|
5
|
+
<form-data>
|
|
6
|
+
<username>QWE</username>
|
|
7
|
+
<password>ASD</password>
|
|
8
|
+
</form-data>
|
|
9
|
+
</signin-form>
|
|
10
|
+
</slice>
|
|
11
|
+
</datadom>
|
package/demo/s.xslt
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
1
2
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
2
3
|
xmlns:dce="urn:schemas-epa-wg:dce" xmlns:exsl="http://exslt.org/common" version="1.0"
|
|
3
4
|
exclude-result-prefixes="exsl">
|
|
@@ -14,56 +15,39 @@
|
|
|
14
15
|
</xsl:template>
|
|
15
16
|
<xsl:template mode="payload" match="attributes">
|
|
16
17
|
<dce-root xmlns="http://www.w3.org/1999/xhtml" xmlns:xhtml="http://www.w3.org/1999/xhtml" data-dce-id="1">
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
<button xmlns="" data-dce-id="5">
|
|
28
|
-
<xsl:value-of select="@name">
|
|
29
|
-
</xsl:value-of>
|
|
30
|
-
</button>
|
|
31
|
-
</xsl:for-each>
|
|
32
|
-
<xsl:for-each xmlns:xsl="http://www.w3.org/1999/XSL/Transform" select="//slice/s/value/*">
|
|
33
|
-
<ul xmlns="" data-dce-id="6">
|
|
34
|
-
<var data-testid="request-section" data-dce-id="7">
|
|
35
|
-
<dce-text data-dce-id="8">
|
|
36
|
-
<xsl:value-of select="name(.)"/>
|
|
37
|
-
</dce-text>
|
|
38
|
-
</var>
|
|
39
|
-
<xsl:for-each select="@*">
|
|
40
|
-
<div data-dce-id="9">
|
|
41
|
-
<var data-dce-id="10">@<xsl:value-of select="local-name(.)"/>
|
|
42
|
-
</var>
|
|
43
|
-
<dce-text data-dce-id="11">
|
|
44
|
-
=
|
|
45
|
-
</dce-text>
|
|
46
|
-
<code data-testid="attr-{local-name(.)}" data-dce-id="12">
|
|
47
|
-
<xsl:value-of select="."/>
|
|
48
|
-
</code>
|
|
49
|
-
</div>
|
|
50
|
-
</xsl:for-each>
|
|
51
|
-
</ul>
|
|
52
|
-
</xsl:for-each>
|
|
18
|
+
<u xmlns="" data-dce-id="2">
|
|
19
|
+
<dce-text data-dce-id="3">
|
|
20
|
+
<xsl:call-template name="slot">
|
|
21
|
+
<xsl:with-param name="slotname" select="''"/>
|
|
22
|
+
<xsl:with-param name="defaultvalue">
|
|
23
|
+
<dce-text xmlns="" data-dce-id="4">is green</dce-text>
|
|
24
|
+
</xsl:with-param>
|
|
25
|
+
</xsl:call-template>
|
|
26
|
+
</dce-text>
|
|
27
|
+
</u>
|
|
53
28
|
</dce-root>
|
|
54
29
|
</xsl:template>
|
|
55
30
|
<xsl:template match="/">
|
|
56
31
|
<xsl:apply-templates mode="payload" select="/datadom/attributes"/>
|
|
57
32
|
</xsl:template>
|
|
33
|
+
|
|
34
|
+
<xsl:template match="@*|node()" mode="copy-html">
|
|
35
|
+
<xsl:copy><xsl:apply-templates select="@*|node()" mode="copy-html"/></xsl:copy>
|
|
36
|
+
</xsl:template>
|
|
37
|
+
<xsl:template match="node()[starts-with(name(),'xhtml:')]" mode="copy-html">
|
|
38
|
+
<xsl:element name="{local-name()}"><xsl:apply-templates select="@*|node()" mode="copy-html"/></xsl:element>
|
|
39
|
+
</xsl:template>
|
|
40
|
+
|
|
41
|
+
|
|
58
42
|
<xsl:template name="slot">
|
|
59
43
|
<xsl:param name="slotname"/>
|
|
60
44
|
<xsl:param name="defaultvalue"/>
|
|
61
45
|
<xsl:choose>
|
|
62
46
|
<xsl:when test="//payload/*[@slot=$slotname]">
|
|
63
|
-
<xsl:copy-
|
|
47
|
+
<xsl:apply-templates mode="copy-html" select="//payload/*[@slot=$slotname]"/>
|
|
64
48
|
</xsl:when>
|
|
65
49
|
<xsl:otherwise>
|
|
66
|
-
<xsl:copy-
|
|
50
|
+
<xsl:apply-templates mode="copy-html" select="$defaultvalue"/>
|
|
67
51
|
</xsl:otherwise>
|
|
68
52
|
</xsl:choose>
|
|
69
53
|
</xsl:template>
|
package/demo/s1.xslt
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml"
|
|
3
|
+
xmlns:dce="urn:schemas-epa-wg:dce" xmlns:exsl="http://exslt.org/common" version="1.0"
|
|
4
|
+
exclude-result-prefixes="exsl">
|
|
5
|
+
<xsl:template match="ignore">
|
|
6
|
+
<xsl:choose>
|
|
7
|
+
<xsl:when test="//attr">
|
|
8
|
+
<xsl:value-of select="//attr"/>
|
|
9
|
+
</xsl:when>
|
|
10
|
+
<xsl:otherwise>
|
|
11
|
+
<xsl:value-of select="def"/>
|
|
12
|
+
</xsl:otherwise>
|
|
13
|
+
</xsl:choose>
|
|
14
|
+
<xsl:value-of select="."/>
|
|
15
|
+
</xsl:template>
|
|
16
|
+
<xsl:template mode="payload" match="attributes">
|
|
17
|
+
<dce-root xmlns="http://www.w3.org/1999/xhtml" xmlns:xhtml="http://www.w3.org/1999/xhtml" data-dce-id="1">
|
|
18
|
+
<u xmlns="" data-dce-id="2">
|
|
19
|
+
<dce-text data-dce-id="3">
|
|
20
|
+
<xsl:call-template name="slot">
|
|
21
|
+
<xsl:with-param name="slotname" select="''"/>
|
|
22
|
+
<xsl:with-param name="defaultvalue">
|
|
23
|
+
<dce-text xmlns="" data-dce-id="4">is green</dce-text>
|
|
24
|
+
</xsl:with-param>
|
|
25
|
+
</xsl:call-template>
|
|
26
|
+
</dce-text>
|
|
27
|
+
</u>
|
|
28
|
+
</dce-root>
|
|
29
|
+
</xsl:template>
|
|
30
|
+
<xsl:template match="/">
|
|
31
|
+
<xsl:apply-templates mode="payload" select="/datadom/attributes"/>
|
|
32
|
+
</xsl:template>
|
|
33
|
+
|
|
34
|
+
<xsl:template match="@*|node()" mode="copy-html">
|
|
35
|
+
<xsl:copy><xsl:apply-templates select="@*|node()" mode="copy-html"/></xsl:copy>
|
|
36
|
+
</xsl:template>
|
|
37
|
+
<xsl:template match="node()[starts-with(name(),'xhtml:')]" mode="copy-html">
|
|
38
|
+
<xsl:element name="{local-name()}"><xsl:apply-templates select="@*|node()" mode="copy-html"/></xsl:element>
|
|
39
|
+
</xsl:template>
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
<xsl:template name="slot">
|
|
43
|
+
<xsl:param name="slotname"/>
|
|
44
|
+
<xsl:param name="defaultvalue"/>
|
|
45
|
+
<xsl:choose>
|
|
46
|
+
<xsl:when test="//payload/*[@slot=$slotname]">
|
|
47
|
+
<xsl:apply-templates mode="copy-html" select="//payload/*[@slot=$slotname]"/>
|
|
48
|
+
</xsl:when>
|
|
49
|
+
<xsl:otherwise>
|
|
50
|
+
<xsl:apply-templates mode="copy-html" select="$defaultvalue"/>
|
|
51
|
+
</xsl:otherwise>
|
|
52
|
+
</xsl:choose>
|
|
53
|
+
</xsl:template>
|
|
54
|
+
<xsl:variable name="js-injected-body">
|
|
55
|
+
<xsl:call-template name="slot">
|
|
56
|
+
<xsl:with-param name="slotname" select="''"/>
|
|
57
|
+
<xsl:with-param name="defaultvalue"/>
|
|
58
|
+
</xsl:call-template>
|
|
59
|
+
</xsl:variable>
|
|
60
|
+
</xsl:stylesheet>
|
package/ide/customData-dce.json
CHANGED
|
@@ -27,6 +27,19 @@
|
|
|
27
27
|
}
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
|
+
{
|
|
31
|
+
"name": "custom-validity",
|
|
32
|
+
"description": {
|
|
33
|
+
"kind": "markdown",
|
|
34
|
+
"value": "XPath expression to return either boolean or error string to be shown by browser native UI on form validation event. Unless value is true, prevents the form submission."
|
|
35
|
+
},
|
|
36
|
+
"references": [
|
|
37
|
+
{
|
|
38
|
+
"name": "Demo",
|
|
39
|
+
"url": "https://unpkg.com/@epa-wg/custom-element/demo/form.html"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
30
43
|
{
|
|
31
44
|
"name": "slice-value",
|
|
32
45
|
"description": {
|
|
@@ -109,4 +122,4 @@
|
|
|
109
122
|
]
|
|
110
123
|
}
|
|
111
124
|
]
|
|
112
|
-
}
|
|
125
|
+
}
|
package/ide/web-types-dce.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json.schemastore.org/web-types",
|
|
3
3
|
"name": "@epa-wg/custom-element",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.23",
|
|
5
5
|
"js-types-syntax": "typescript",
|
|
6
6
|
"description-markup": "markdown",
|
|
7
7
|
"contributions": {
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
"description": "Defines the event name on which `value` would be synchronized with DCE slice\n\nOn: any component with `value` and associated change event",
|
|
18
18
|
"doc-url": "https://unpkg.com/@epa-wg/custom-element/demo/dom-merge.html"
|
|
19
19
|
},
|
|
20
|
+
{
|
|
21
|
+
"name": "custom-validity",
|
|
22
|
+
"description": "XPath expression to return either boolean or error string to be shown by browser native UI on form validation event. Unless value is true, prevents the form submission.",
|
|
23
|
+
"doc-url": "https://unpkg.com/@epa-wg/custom-element/demo/form.html"
|
|
24
|
+
},
|
|
20
25
|
{
|
|
21
26
|
"name": "slice-value",
|
|
22
27
|
"description": "XPath expression to populate into the slice",
|
package/ide/web-types-xsl.json
CHANGED
package/index.html
CHANGED
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
<a href="./demo/scoped-css.html" >scoped CSS </a> |
|
|
36
36
|
<a href="./demo/parameters.html" >attributes </a> |
|
|
37
37
|
<a href="./demo/data-slices.html" >data slices/events </a> |
|
|
38
|
+
<a href="./demo/form.html" >Form validation </a> |
|
|
38
39
|
<a href="./demo/dom-merge.html" >DOM merge on dynamic update </a>
|
|
39
40
|
</section>
|
|
40
41
|
</nav>
|
package/package.json
CHANGED