@epa-wg/custom-element 0.0.17 → 0.0.19
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/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.vscode/settings.json +25 -0
- package/README.md +49 -18
- package/bin/xslDtd2Ide.mjs +160 -0
- package/custom-element.d.ts +1 -1
- package/custom-element.js +220 -59
- package/demo/a.html +44 -10
- package/demo/data-slices.html +185 -0
- package/demo/demo.css +1 -0
- package/demo/dom-merge.html +1 -1
- package/demo/external-template.html +1 -0
- package/demo/hex-grid-dce.html +13 -13
- package/demo/http-request.html +19 -17
- package/demo/local-storage.html +3 -3
- package/demo/location-element.html +16 -11
- package/demo/parameters.html +21 -3
- package/demo/s.xml +6 -1
- package/demo/s.xslt +8 -10
- package/demo/z.html +61 -49
- package/http-request.js +2 -1
- package/ide/IDE.md +31 -0
- package/ide/customData-dce.json +112 -0
- package/ide/customData-xsl.json +1018 -0
- package/{web-types.json → ide/web-types-dce.json} +42 -1
- package/ide/web-types-xsl.json +867 -0
- package/index.html +7 -5
- package/package.json +4 -2
- package/request.html +2 -2
package/custom-element.js
CHANGED
|
@@ -7,12 +7,22 @@ const XSL_NS_URL = 'http://www.w3.org/1999/XSL/Transform'
|
|
|
7
7
|
|
|
8
8
|
const attr = (el, attr)=> el.getAttribute?.(attr)
|
|
9
9
|
, isText = e => e.nodeType === 3
|
|
10
|
-
,
|
|
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 ))
|
|
11
13
|
, createText = ( d, t) => (d.ownerDocument || d ).createTextNode( t )
|
|
12
|
-
, emptyNode = n=> { while(n.firstChild) n.firstChild.remove(); return n; }
|
|
14
|
+
, emptyNode = n => { while(n.firstChild) n.firstChild.remove(); n.getAttributeNames().map( a => n.removeAttribute(a) ); return n; }
|
|
13
15
|
, createNS = ( ns, tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElementNS( ns, tag ))
|
|
14
16
|
, xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
|
|
15
|
-
, xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(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
|
+
}
|
|
16
26
|
|
|
17
27
|
function
|
|
18
28
|
ASSERT(x)
|
|
@@ -82,6 +92,30 @@ Json2Xml( o, tag )
|
|
|
82
92
|
ret.push("/>");
|
|
83
93
|
return ret.join('\n');
|
|
84
94
|
}
|
|
95
|
+
|
|
96
|
+
export function
|
|
97
|
+
obj2node( o, tag, doc )
|
|
98
|
+
{
|
|
99
|
+
if( typeof o === 'function'){debugger}
|
|
100
|
+
if( typeof o === 'string' )
|
|
101
|
+
return create(tag,o,doc);
|
|
102
|
+
|
|
103
|
+
if( o instanceof Array )
|
|
104
|
+
{ const ret = create('array');
|
|
105
|
+
o.map( ae => ret.append( obj2node(ae,tag,doc)) );
|
|
106
|
+
return ret
|
|
107
|
+
}
|
|
108
|
+
const ret = create(tag,'',doc);
|
|
109
|
+
for( let k in o )
|
|
110
|
+
if( isNode(o[k]) || typeof o[k] ==='function' || o[k] instanceof Window )
|
|
111
|
+
continue
|
|
112
|
+
else
|
|
113
|
+
if( typeof o[k] !== "object" )
|
|
114
|
+
ret.setAttribute(k, o[k] );
|
|
115
|
+
else
|
|
116
|
+
ret.append(obj2node(o[k], k, doc))
|
|
117
|
+
return ret;
|
|
118
|
+
}
|
|
85
119
|
export function
|
|
86
120
|
tagUid( node )
|
|
87
121
|
{ // {} to xsl:value-of
|
|
@@ -123,7 +157,7 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
|
|
|
123
157
|
{
|
|
124
158
|
if( templateNode.tagName === S || templateNode.documentElement?.tagName === S )
|
|
125
159
|
return tagUid(templateNode)
|
|
126
|
-
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" >
|
|
160
|
+
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" >
|
|
127
161
|
<xsl:output method="xml" />
|
|
128
162
|
<xsl:template match="/"><dce-root xmlns="${ HTML_NS_URL }"><xsl:apply-templates select="*"/></dce-root></xsl:template>
|
|
129
163
|
<xsl:template match="*[name()='template']"><xsl:apply-templates mode="sanitize" select="*|text()"/></xsl:template>
|
|
@@ -141,6 +175,8 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
|
|
|
141
175
|
, tc = (n =>
|
|
142
176
|
{
|
|
143
177
|
forEach$(n,'script', s=> s.remove() );
|
|
178
|
+
const xslRoot = n.content ?? n.firstElementChild?.content ?? n.body ?? n;
|
|
179
|
+
xslTags.forEach( tag => forEach$( xslRoot, tag, el=>toXsl(el,xslRoot) ) );
|
|
144
180
|
const e = n.firstElementChild?.content || n.content
|
|
145
181
|
, asXmlNode = r => {
|
|
146
182
|
const d = xml2dom( '<xhtml/>' )
|
|
@@ -202,24 +238,38 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
|
|
|
202
238
|
if( !fr )
|
|
203
239
|
return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
|
|
204
240
|
const params = [];
|
|
205
|
-
[...fr.querySelectorAll('dce-root>
|
|
206
|
-
{
|
|
241
|
+
[...fr.querySelectorAll('dce-root>attribute')].forEach( a=>
|
|
242
|
+
{
|
|
243
|
+
const p = cloneAs(a,'xsl:param')
|
|
244
|
+
, name = attr(a,'name');
|
|
245
|
+
payload.append(p);
|
|
207
246
|
let select = attr(p,'select')?.split('??')
|
|
208
247
|
if( !select)
|
|
209
|
-
{ select = ['//'+
|
|
248
|
+
{ select = ['//'+name, `'${p.textContent}'`];
|
|
210
249
|
emptyNode(p);
|
|
250
|
+
p.setAttribute('name',name);
|
|
211
251
|
}
|
|
212
|
-
|
|
252
|
+
let val;
|
|
253
|
+
if( select?.length>1 ){
|
|
213
254
|
p.removeAttribute('select');
|
|
214
255
|
const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
|
|
215
|
-
c.firstElementChild.setAttribute('test',select[0]);
|
|
216
256
|
emptyNode(c.firstElementChild).append( createText(c,'{'+select[0]+'}'));
|
|
217
257
|
emptyNode(c.lastElementChild ).append( createText(c,'{'+select[1]+'}'));
|
|
218
|
-
|
|
219
|
-
|
|
258
|
+
c.firstElementChild.setAttribute('test',select[0]);
|
|
259
|
+
p.append(c);
|
|
260
|
+
val = c.cloneNode(true);
|
|
261
|
+
}else
|
|
262
|
+
val=cloneAs(a,'xsl:value-of');
|
|
263
|
+
val.removeAttribute('name');
|
|
264
|
+
a.append(val);
|
|
265
|
+
a.removeAttribute('select');
|
|
220
266
|
params.push(p)
|
|
221
267
|
});
|
|
222
|
-
|
|
268
|
+
[...fr.querySelectorAll('[value]')].filter(el=>el.getAttribute('value').match( /\{(.*)\?\?(.*)\}/g )).forEach(el=>
|
|
269
|
+
{ const v = attr(el,'value');
|
|
270
|
+
if(v)
|
|
271
|
+
el.setAttribute('value', evalCurly(v));
|
|
272
|
+
});
|
|
223
273
|
for( const c of fr.childNodes )
|
|
224
274
|
payload.append(xslDom.importNode(c,true))
|
|
225
275
|
|
|
@@ -276,18 +326,57 @@ deepEqual(a, b, O=false)
|
|
|
276
326
|
return O
|
|
277
327
|
return true;
|
|
278
328
|
}
|
|
279
|
-
|
|
329
|
+
export const
|
|
330
|
+
assureSlices = ( root, names) =>
|
|
331
|
+
names.split('|').map(n=>n.trim()).map( xp =>
|
|
332
|
+
{ if(xp.includes('/'))
|
|
333
|
+
{ const ret = [], r = root.ownerDocument.evaluate( xp, root );
|
|
334
|
+
for( let n; n = r.iterateNext(); )
|
|
335
|
+
ret.push( n )
|
|
336
|
+
return ret
|
|
337
|
+
}
|
|
338
|
+
return [...root.childNodes].find(n=>n.localName === xp) || create(xp);
|
|
339
|
+
}).flat();
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
*
|
|
343
|
+
* @param x slice node
|
|
344
|
+
* @param sliceNames slice name, xPath in /datadom/slice/
|
|
345
|
+
* @param ev Event obj
|
|
346
|
+
* @param dce
|
|
347
|
+
*/
|
|
280
348
|
export function
|
|
281
|
-
|
|
349
|
+
event2slice( x, sliceNames, ev, dce )
|
|
282
350
|
{
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
x.
|
|
351
|
+
// evaluate slices[]
|
|
352
|
+
// inject @attributes
|
|
353
|
+
// inject event
|
|
354
|
+
// evaluate slice-value
|
|
355
|
+
// slice[i] = slice-value
|
|
356
|
+
assureSlices(x,sliceNames).map( s =>
|
|
357
|
+
{
|
|
358
|
+
const d = x.ownerDocument
|
|
359
|
+
, el = ev.sliceEventSource
|
|
360
|
+
, sel = ev.sliceElement
|
|
361
|
+
, cleanSliceValue = ()=>[...s.childNodes].filter(n=>n.nodeType===3 || n.localName==='value').map(n=>n.remove());
|
|
362
|
+
el.getAttributeNames().map( a => s.setAttribute( a, attr(el,a) ) );
|
|
363
|
+
[...s.childNodes].filter(n=>n.localName==='event').map(n=>n.remove());
|
|
364
|
+
ev.type==='init' && cleanSliceValue();
|
|
365
|
+
s.append( obj2node( ev, 'event', d ) );
|
|
366
|
+
if( sel.hasAttribute('slice-value') )
|
|
367
|
+
{ s.setAttribute('value', el.value );
|
|
368
|
+
const v = xPath( attr( sel, 'slice-value'),s );
|
|
369
|
+
cleanSliceValue();
|
|
370
|
+
s.append( createText( d, v ) );
|
|
371
|
+
}else
|
|
372
|
+
{ const v = el.value || attr( sel, 'value' ) ;
|
|
373
|
+
cleanSliceValue();
|
|
374
|
+
if( isString(v) )
|
|
375
|
+
s.append( createText( d, v) );
|
|
376
|
+
else
|
|
377
|
+
s.append( obj2node(v,'value',s.ownerDocument) )
|
|
378
|
+
}
|
|
379
|
+
})
|
|
291
380
|
}
|
|
292
381
|
|
|
293
382
|
function forEach$( el, css, cb){
|
|
@@ -328,7 +417,10 @@ export function mergeAttr( from, to )
|
|
|
328
417
|
return
|
|
329
418
|
}
|
|
330
419
|
for( let a of from.attributes)
|
|
331
|
-
|
|
420
|
+
{ a.namespaceURI? to.setAttributeNS( a.namespaceURI, a.name, a.value ) : to.setAttribute( a.name, a.value )
|
|
421
|
+
if( a.name === 'value')
|
|
422
|
+
to.value = a.value
|
|
423
|
+
}
|
|
332
424
|
}
|
|
333
425
|
export function assureUnique(n, id=0)
|
|
334
426
|
{
|
|
@@ -370,7 +462,7 @@ export function merge( parent, fromArr )
|
|
|
370
462
|
{ if( o.nodeValue !== e.nodeValue )
|
|
371
463
|
o.nodeValue = e.nodeValue;
|
|
372
464
|
}else
|
|
373
|
-
{ mergeAttr(o
|
|
465
|
+
{ mergeAttr(e,o)
|
|
374
466
|
if( o.childNodes.length || e.childNodes.length )
|
|
375
467
|
merge(o, e.childNodes)
|
|
376
468
|
}
|
|
@@ -383,6 +475,54 @@ export function assureUID(n,attr)
|
|
|
383
475
|
n.setAttribute(attr, crypto.randomUUID());
|
|
384
476
|
return n.getAttribute(attr)
|
|
385
477
|
}
|
|
478
|
+
export const evalCurly = s =>
|
|
479
|
+
{ const exp = [...s?.matchAll( /([^{}]*)(\{)([^}]+)}([^{}]*)/g ) ].map(l=>`${l[1]}{${ xPathDefaults(l[3] )}}${l[4]}`);
|
|
480
|
+
return exp.join('');
|
|
481
|
+
}
|
|
482
|
+
export const xPathDefaults = x=>
|
|
483
|
+
{ if(!x.trim())
|
|
484
|
+
return x;
|
|
485
|
+
const xx = x.split('??')
|
|
486
|
+
, a = xx.shift()
|
|
487
|
+
, b = xPathDefaults(xx.join('??'));
|
|
488
|
+
|
|
489
|
+
return xx.length ? `concat( ${a} , substring( ${b} , (1+string-length( ${b} )) * string-length( ${a} ) ) )`: x
|
|
490
|
+
// return xx.length ? `${a}|(${xPathDefaults(xx.join('??'))})[not(${a})]`: a
|
|
491
|
+
}
|
|
492
|
+
export const xPath = (x,root)=>
|
|
493
|
+
{ x = xPathDefaults(x);
|
|
494
|
+
|
|
495
|
+
const it = root.ownerDocument.evaluate(x, root);
|
|
496
|
+
switch( it.resultType )
|
|
497
|
+
{ case XPathResult.NUMBER_TYPE: return it.numberValue;
|
|
498
|
+
case XPathResult.STRING_TYPE: return it.stringValue;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
let ret = '';
|
|
502
|
+
for( let n ;n=it.iterateNext(); )
|
|
503
|
+
ret += n.textContent;
|
|
504
|
+
return ret
|
|
505
|
+
}
|
|
506
|
+
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(',');
|
|
507
|
+
export const toXsl = (el, defParent) => {
|
|
508
|
+
const x = create('xsl:'+el.localName);
|
|
509
|
+
for( let a of el.attributes )
|
|
510
|
+
x.setAttribute( a.name, a.value );
|
|
511
|
+
while(el.firstChild)
|
|
512
|
+
x.append(el.firstChild);
|
|
513
|
+
if( el.parentElement )
|
|
514
|
+
el.parentElement.replaceChild( x, el );
|
|
515
|
+
else
|
|
516
|
+
{ const p = (el.parentElement || defParent)
|
|
517
|
+
, arr = [...p.childNodes];
|
|
518
|
+
arr.forEach((n, i) => {
|
|
519
|
+
if (n === el)
|
|
520
|
+
arr[i] = x;
|
|
521
|
+
});
|
|
522
|
+
p.replaceChildren(...arr);
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
|
|
386
526
|
export class
|
|
387
527
|
CustomElement extends HTMLElement
|
|
388
528
|
{
|
|
@@ -405,19 +545,23 @@ CustomElement extends HTMLElement
|
|
|
405
545
|
|
|
406
546
|
Object.defineProperty( this, "xsltString", { get: ()=>templateDocs.map( td => xmlString(td) ).join('\n') });
|
|
407
547
|
|
|
408
|
-
const dce = this
|
|
409
|
-
|
|
548
|
+
const dce = this
|
|
549
|
+
, sliceNodes = [...this.templateNode.querySelectorAll('[slice]')]
|
|
550
|
+
, sliceNames = sliceNodes.map(e=>attr(e,'slice')).filter(n=>!n.includes('/')).filter((v, i, a)=>a.indexOf(v) === i)
|
|
551
|
+
, declaredAttributes = templateDocs.reduce( (ret,t) => { if( t.params ) ret.push( ...t.params ); return ret; }, [] );
|
|
552
|
+
|
|
410
553
|
class DceElement extends HTMLElement
|
|
411
554
|
{
|
|
412
|
-
static get observedAttributes()
|
|
413
|
-
|
|
414
|
-
{ if( t.params ) ret.push( ...t.params.map(e=>attr(e,'name')) );
|
|
415
|
-
return ret;
|
|
416
|
-
}, [] );
|
|
417
|
-
}
|
|
555
|
+
static get observedAttributes(){ return declaredAttributes.map( a=>attr(a,'name')); }
|
|
556
|
+
#inTransform = 0;
|
|
418
557
|
connectedCallback()
|
|
419
|
-
{
|
|
420
|
-
|
|
558
|
+
{ let payload = this.childNodes;
|
|
559
|
+
if( this.firstElementChild?.tagName === 'TEMPLATE' )
|
|
560
|
+
{
|
|
561
|
+
const t = this.firstElementChild;
|
|
562
|
+
t.remove();
|
|
563
|
+
payload = t.content.childNodes;
|
|
564
|
+
|
|
421
565
|
for( const n of [...t.content.childNodes] )
|
|
422
566
|
if( n.localName === 'style' ){
|
|
423
567
|
const id = assureUID(this,'data-dce-style')
|
|
@@ -428,9 +572,6 @@ CustomElement extends HTMLElement
|
|
|
428
572
|
t.insertAdjacentElement('beforebegin',n);
|
|
429
573
|
else if(n.nodeType===3)
|
|
430
574
|
t.insertAdjacentText('beforebegin',n.data);
|
|
431
|
-
|
|
432
|
-
t.remove();
|
|
433
|
-
|
|
434
575
|
}
|
|
435
576
|
const x = xml2dom( '<datadom/>' ).documentElement;
|
|
436
577
|
const createXmlNode = ( tag, t = '' ) => ( e =>
|
|
@@ -438,11 +579,12 @@ CustomElement extends HTMLElement
|
|
|
438
579
|
e.append( createText( x, t ))
|
|
439
580
|
return e;
|
|
440
581
|
})(x.ownerDocument.createElement( tag ))
|
|
441
|
-
injectData( x, 'payload' ,
|
|
582
|
+
injectData( x, 'payload' , payload , assureSlot );
|
|
442
583
|
this.innerHTML='';
|
|
443
584
|
injectData( x, 'attributes' , this.attributes, e => createXmlNode( e.nodeName, e.value ) );
|
|
444
585
|
injectData( x, 'dataset', Object.keys( this.dataset ), k => createXmlNode( k, this.dataset[ k ] ) );
|
|
445
|
-
const sliceRoot = injectData( x, 'slice', sliceNames, k => createXmlNode( k, '' ) )
|
|
586
|
+
const sliceRoot = injectData( x, 'slice', sliceNames, k => createXmlNode( k, '' ) )
|
|
587
|
+
, sliceXPath = x => xPath(x, sliceRoot);
|
|
446
588
|
this.xml = x;
|
|
447
589
|
|
|
448
590
|
const sliceEvents=[];
|
|
@@ -450,10 +592,10 @@ CustomElement extends HTMLElement
|
|
|
450
592
|
{ const processed = {}
|
|
451
593
|
|
|
452
594
|
for(let ev; ev = sliceEvents.pop(); )
|
|
453
|
-
{ const s = attr( ev.
|
|
595
|
+
{ const s = attr( ev.sliceElement, 'slice');
|
|
454
596
|
if( processed[s] )
|
|
455
597
|
continue;
|
|
456
|
-
|
|
598
|
+
event2slice( sliceRoot, s, ev, this );
|
|
457
599
|
processed[s] = ev;
|
|
458
600
|
}
|
|
459
601
|
Object.keys(processed).length !== 0 && transform();
|
|
@@ -462,10 +604,7 @@ CustomElement extends HTMLElement
|
|
|
462
604
|
|
|
463
605
|
this.onSlice = ev=>
|
|
464
606
|
{ ev.stopPropagation?.();
|
|
465
|
-
|
|
466
|
-
if( deepEqual( ev.detail, [...sliceRoot.children].find( e=>e.localName === s )?.data ) )
|
|
467
|
-
return
|
|
468
|
-
|
|
607
|
+
ev.sliceEventSource = ev.currentTarget || ev.target;
|
|
469
608
|
sliceEvents.push(ev);
|
|
470
609
|
if( !timeoutID )
|
|
471
610
|
timeoutID = setTimeout(()=>
|
|
@@ -474,7 +613,9 @@ CustomElement extends HTMLElement
|
|
|
474
613
|
},10);
|
|
475
614
|
};
|
|
476
615
|
const transform = this.transform = ()=>
|
|
477
|
-
{
|
|
616
|
+
{ if(this.#inTransform){ debugger }
|
|
617
|
+
this.#inTransform = 1;
|
|
618
|
+
|
|
478
619
|
const ff = xp.map( (p,i) =>
|
|
479
620
|
{ const f = p.transformToFragment(x.ownerDocument, document)
|
|
480
621
|
if( !f )
|
|
@@ -487,35 +628,55 @@ CustomElement extends HTMLElement
|
|
|
487
628
|
assureUnique(f);
|
|
488
629
|
merge( this, f.childNodes )
|
|
489
630
|
})
|
|
490
|
-
|
|
491
|
-
|
|
631
|
+
|
|
632
|
+
DceElement.observedAttributes.map( a =>
|
|
633
|
+
{ let v = attr(this.firstElementChild,a);
|
|
634
|
+
if( v !== attr(this,a) )
|
|
635
|
+
{ this.setAttribute( a, v );
|
|
636
|
+
this.#applyAttribute( a, v );
|
|
637
|
+
}
|
|
638
|
+
})
|
|
492
639
|
|
|
493
640
|
forEach$( this,'[slice]', el =>
|
|
494
641
|
{ if( !el.dceInitialized )
|
|
495
642
|
{ el.dceInitialized = 1;
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
643
|
+
const evs = attr(el,'slice-event');
|
|
644
|
+
(evs || 'change')
|
|
645
|
+
.split(' ')
|
|
646
|
+
.forEach( t=> (el.localName==='slice'? el.parentElement : el)
|
|
647
|
+
.addEventListener( t, ev=>
|
|
648
|
+
{ ev.sliceElement = el;
|
|
649
|
+
this.onSlice(ev)
|
|
650
|
+
} ));
|
|
651
|
+
if( !evs || evs.includes('init') )
|
|
652
|
+
{ if( el.hasAttribute('slice-value') || el.hasAttribute('value') || el.value )
|
|
653
|
+
this.onSlice({type:'init', target: el, sliceElement:el })
|
|
654
|
+
else
|
|
655
|
+
el.value = sliceXPath( attr(el,'slice') )
|
|
656
|
+
}
|
|
499
657
|
}
|
|
500
|
-
})
|
|
658
|
+
});
|
|
659
|
+
this.#inTransform = 0;
|
|
501
660
|
};
|
|
502
661
|
transform();
|
|
503
662
|
applySlices();
|
|
504
663
|
}
|
|
505
|
-
|
|
506
|
-
{
|
|
507
|
-
return;
|
|
508
|
-
let a = this.xml.querySelector(`attributes>${name}`);
|
|
664
|
+
#applyAttribute(name, newValue)
|
|
665
|
+
{ let a = this.xml.querySelector(`attributes>${name}`);
|
|
509
666
|
if( a )
|
|
510
|
-
emptyNode(a).append( createText(a,newValue));
|
|
667
|
+
emptyNode(a).append( createText(a,newValue) );
|
|
511
668
|
else
|
|
512
669
|
{ a = create( name, newValue, this.xml );
|
|
513
|
-
a.append( createText(a,newValue) );
|
|
514
670
|
this.xml.querySelector('attributes').append( a );
|
|
515
671
|
}
|
|
516
|
-
|
|
672
|
+
}
|
|
673
|
+
attributeChangedCallback(name, oldValue, newValue)
|
|
674
|
+
{ if( !this.xml || this.#inTransform )
|
|
675
|
+
return;
|
|
676
|
+
this.#applyAttribute(name, newValue);
|
|
517
677
|
this.transform(); // needs throttling
|
|
518
678
|
}
|
|
679
|
+
|
|
519
680
|
get dce(){ return dce }
|
|
520
681
|
}
|
|
521
682
|
if(tag)
|
package/demo/a.html
CHANGED
|
@@ -4,24 +4,58 @@
|
|
|
4
4
|
<head>
|
|
5
5
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
6
6
|
<title>custom-element Declarative Custom Element implementation demo</title>
|
|
7
|
-
<link rel="icon" href="./wc-square.svg"
|
|
8
|
-
<script type="module" src="../
|
|
7
|
+
<link rel="icon" href="./wc-square.svg"/>
|
|
8
|
+
<script type="module" src="../http-request.js"></script>
|
|
9
9
|
<script type="module" src="../custom-element.js"></script>
|
|
10
10
|
|
|
11
11
|
<style>
|
|
12
12
|
@import "./demo.css";
|
|
13
13
|
|
|
14
|
-
button{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
button {
|
|
15
|
+
background: forestgreen;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
table {
|
|
19
|
+
min-width: 16rem;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
td {
|
|
23
|
+
border-bottom: 1px solid silver;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
tfoot td {
|
|
27
|
+
border-bottom: none;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
td, th {
|
|
31
|
+
text-align: right;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
caption {
|
|
35
|
+
padding: 1rem;
|
|
36
|
+
font-weight: bolder;
|
|
37
|
+
font-family: sans-serif;
|
|
38
|
+
}
|
|
20
39
|
</style>
|
|
21
40
|
</head>
|
|
22
41
|
<body>
|
|
23
|
-
|
|
24
|
-
<
|
|
42
|
+
|
|
43
|
+
<custom-element>
|
|
44
|
+
<template>
|
|
45
|
+
<button slice="clickcount"
|
|
46
|
+
slice-event="click"
|
|
47
|
+
slice-value="//clickcount + 1" >
|
|
48
|
+
+
|
|
49
|
+
</button>
|
|
50
|
+
<button slice="clickcount"
|
|
51
|
+
slice-event="click"
|
|
52
|
+
slice-value="//clickcount - 1" >
|
|
53
|
+
-
|
|
54
|
+
</button>
|
|
55
|
+
<input slice="clickcount" type="number" value="{//clickcount ?? 0}" />
|
|
56
|
+
{//clickcount}
|
|
57
|
+
</template>
|
|
58
|
+
</custom-element>
|
|
25
59
|
|
|
26
60
|
</body>
|
|
27
61
|
</html>
|