@epa-wg/custom-element 0.0.13 → 0.0.15

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 CHANGED
@@ -1,11 +1,11 @@
1
1
  # custom-element
2
- `Declarative Custom Element` is a part of pure `Declarative Web Application` stack. A proof of concept as a part of
2
+ `Declarative Custom Element` (DCE) is a part of pure `Declarative Web Application` stack. A proof of concept as a part of
3
3
  [WCCG in Declarative custom elements](https://github.com/w3c/webcomponents-cg/issues/32#issuecomment-1321037301) and [Declarative Web Application](https://github.com/EPA-WG/dwa#readme)
4
4
  discussion. The functionality of DCE and its data access does not require programming using JavaScript.
5
5
 
6
6
  It allows to define custom HTML tag with template filled from slots, attributes and data `slice` as of now from
7
7
  [local-storage][local-storage-demo], [http-request][http-request-demo], [location][location-demo].
8
- UI is re-rendered on each data slice change.
8
+ UI is re-rendered on each data slice change triggered by initialization or DOM event.
9
9
 
10
10
  [![git][github-image] GitHub][git-url]
11
11
  | Live demo: [custom-element][demo-url]
@@ -17,6 +17,33 @@ UI is re-rendered on each data slice change.
17
17
  [![coverage][coverage-image]][coverage-url]
18
18
  [![Published on webcomponents.org][webcomponents-img]][webcomponents-url]
19
19
 
20
+
21
+
22
+ <details>
23
+ <summary> What is DCE? </summary>
24
+ DCE provides the next level of abstraction in HTML - native composition. With native implementation which is
25
+ streaming parser, streaming transformation, multithreading. native assumes the C/Rust compiled code. There is no place for JavaScript except of polyfill and ability to extend DCE, which otherwise has to be native.
26
+
27
+ The composition assumes the fully functional template and ability to call the template with parameters( custom tag + attributes) .
28
+
29
+ As the next to HTML abstraction layer - composition, it needs and provide:
30
+ * ability to use dependencies as from withing the page as from external file/lib via src attribute and # in URL
31
+ * ability to treat external content via content-type like html, SVG, images, video with own template rendering
32
+ * provide styles and embedded DCE declarations in own and named(lib) scope, sharing the scoped registry.
33
+
34
+ As the next to composition layer of **functional component** it provides
35
+ * data layer with access to attributes/payload(+slots), dataset, data bound slice
36
+ * means in template to use the data selector for condition/enumeration/text injection into attributes and DOM
37
+ * Set of native primitives to support browser APIs declaratively: location,storage, http request which bonded to slice and as result to reactive UI.
38
+ * support the data change trigger over events
39
+
40
+ While DCE is no-JS concept, DCE provides the basic declarative constructs to build most of simple apps. Assuming the extending via custom elements and JS. The evolution goal is to adopt most demanded APIs/construct natively into DCE stack over time.
41
+
42
+ DCE is compatible with closed/open/named root. Enabling as site-scoped styling and registry as encapsulated anonymous scopes in shadow root.
43
+
44
+ This project is a POC( Proof of Concept ) targeting to become a base for native DCE implementation polyfill.
45
+ </details>
46
+
20
47
  # use
21
48
  ## install
22
49
  use via CDN
@@ -138,7 +165,7 @@ In order to prevent the style leaking, it has to be defined withing `template` t
138
165
  <custom-element>
139
166
  <template>
140
167
  <style>
141
- color:green;
168
+ color: green;
142
169
  button{ color: blue; }
143
170
  </style>
144
171
  <label> green <button>blue</button> </label>
@@ -169,7 +196,18 @@ In same way as in DCE itself:
169
196
  </dce-2>
170
197
  ```
171
198
  ## Attributes
172
- curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)
199
+ To be served by IDE and to track the attributes changes, they have to be declared via `xsl:param` syntax:
200
+ ```html
201
+ <custom-element tag="dce-with-attrs" hidden>
202
+ <xsl:param name="p1" >default_P1</xsl:param>
203
+ <xsl:param name="p2" select="'always_p2'" ></xsl:param>
204
+ <xsl:param name="p3" select="//p3 ?? 'def_P3' " ></xsl:param>
205
+ p1: {$p1} <br/> p2: {$p2} <br/> p3: {$p3}
206
+ </custom-element>
207
+ <dce-with-attrs p1="123" p3="qwe"></dce-with-attrs>
208
+ ```
209
+
210
+ The curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)
173
211
 
174
212
  The names in curly braces are matching the instance attributes. I.e. in XML node `/my-component/attributes/`.
175
213
 
@@ -270,9 +308,9 @@ within template
270
308
  [github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
271
309
  [npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
272
310
  [npm-url]: https://npmjs.org/package/@epa-wg/custom-element
273
- [coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.13/coverage/coverage.svg
274
- [coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.13/coverage/lcov-report/index.html
275
- [storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.13/storybook-static/index.html?path=/story/welcome--introduction
311
+ [coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.15/coverage/coverage.svg
312
+ [coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.15/coverage/lcov-report/index.html
313
+ [storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.15/storybook-static/index.html?path=/story/welcome--introduction
276
314
  [sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
277
315
  [webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
278
316
  [webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
package/custom-element.js CHANGED
@@ -7,8 +7,9 @@ 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
- , create = ( tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElement( tag ))
10
+ , create = ( tag, t = '', d=document ) => ( e => ((e.innerText = t||''),e) )((d.ownerDocument || d ).createElement( tag ))
11
11
  , createText = ( d, t) => (d.ownerDocument || d ).createTextNode( t )
12
+ , emptyNode = n=> { while(n.firstChild) n.firstChild.remove(); return n; }
12
13
  , createNS = ( ns, tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElementNS( ns, tag ))
13
14
  , xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
14
15
  , xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) );
@@ -19,12 +20,12 @@ ASSERT(x)
19
20
  // if(!x)
20
21
  // debugger
21
22
  }
22
- function
23
+ export function
23
24
  xml2dom( xmlString )
24
25
  {
25
26
  return new DOMParser().parseFromString( xmlString, "application/xml" )
26
27
  }
27
- function
28
+ export function
28
29
  xmlString(doc){ return new XMLSerializer().serializeToString( doc ) }
29
30
 
30
31
  function
@@ -95,7 +96,7 @@ tagUid( node )
95
96
  [...m].forEach(t=>
96
97
  { if( t.index > l )
97
98
  tt.push( txt( t.input.substring( l, t.index ) ))
98
- const v = e.ownerDocument.createElement('xsl:value-of');
99
+ const v = node.querySelector('value-of').cloneNode();
99
100
  v.setAttribute('select', t[1] );
100
101
  tt.push(v);
101
102
  l = t.index+t[0].length;
@@ -124,7 +125,7 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
124
125
  return tagUid(templateNode)
125
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" >
126
127
  <xsl:output method="xml" />
127
- <xsl:template match="/"><dce-root><xsl:apply-templates select="*"/></dce-root></xsl:template>
128
+ <xsl:template match="/"><dce-root xmlns="${ HTML_NS_URL }"><xsl:apply-templates select="*"/></dce-root></xsl:template>
128
129
  <xsl:template match="*[name()='template']"><xsl:apply-templates mode="sanitize" select="*|text()"/></xsl:template>
129
130
  <xsl:template match="*"><xsl:apply-templates mode="sanitize" select="*|text()"/></xsl:template>
130
131
  <xsl:template match="*[name()='svg']|*[name()='math']"><xsl:apply-templates mode="sanitize" select="."/></xsl:template>
@@ -141,7 +142,12 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
141
142
  {
142
143
  forEach$(n,'script', s=> s.remove() );
143
144
  const e = n.firstElementChild?.content || n.content
144
- , asXmlNode = r => xslHtmlNs(xml2dom( '<xhtml/>' ).importNode(r, true));
145
+ , asXmlNode = r => {
146
+ const d = xml2dom( '<xhtml/>' )
147
+ , n = d.importNode(r, true);
148
+ d.replaceChild(n,d.documentElement);
149
+ return xslHtmlNs(n);
150
+ };
145
151
  if( e )
146
152
  { const t = create('div');
147
153
  [ ...e.childNodes ].map( c => t.append(c.cloneNode(true)) )
@@ -152,10 +158,17 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
152
158
  , xslDom = xml2dom(
153
159
  `<xsl:stylesheet version="1.0"
154
160
  xmlns:xsl="${ XSL_NS_URL }"
161
+ xmlns:xhtml="${ HTML_NS_URL }"
155
162
  xmlns:dce="urn:schemas-epa-wg:dce"
156
163
  xmlns:exsl="http://exslt.org/common"
157
164
  exclude-result-prefixes="exsl"
158
165
  >
166
+ <xsl:template match="ignore">
167
+ <xsl:choose>
168
+ <xsl:when test="//attr">{//attr}</xsl:when>
169
+ <xsl:otherwise>{def}</xsl:otherwise>
170
+ </xsl:choose>
171
+ <xsl:value-of select="."/></xsl:template>
159
172
  <xsl:template mode="payload" match="attributes"></xsl:template>
160
173
  <xsl:template match="/">
161
174
  <xsl:apply-templates mode="payload" select="/datadom/attributes"/>
@@ -188,6 +201,24 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
188
201
  , payload = $( xslDom, 'template[mode="payload"]');
189
202
  if( !fr )
190
203
  return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
204
+ const params = [];
205
+ [...fr.querySelectorAll('dce-root>param')].forEach(p=>
206
+ { payload.append(p);
207
+ let select = attr(p,'select')?.split('??')
208
+ if( !select)
209
+ { select = ['//'+attr(p, 'name'), `'${p.textContent}'`];
210
+ emptyNode(p);
211
+ }
212
+ if( select?.length>1){
213
+ p.removeAttribute('select');
214
+ const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
215
+ c.firstElementChild.setAttribute('test',select[0]);
216
+ emptyNode(c.firstElementChild).append( createText(c,'{'+select[0]+'}'));
217
+ emptyNode(c.lastElementChild ).append( createText(c,'{'+select[1]+'}'));
218
+ p.append(c)
219
+ }
220
+ params.push(p)
221
+ });
191
222
 
192
223
  for( const c of fr.childNodes )
193
224
  payload.append(xslDom.importNode(c,true))
@@ -207,7 +238,9 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
207
238
 
208
239
  forEach$( payload,'slot', s => s.parentNode.replaceChild( slot2xsl(s), s ) )
209
240
 
210
- return tagUid(xslDom)
241
+ const ret = tagUid(xslDom)
242
+ ret.params = params;
243
+ return ret;
211
244
  }
212
245
  export async function
213
246
  xhrTemplate(src)
@@ -375,6 +408,10 @@ CustomElement extends HTMLElement
375
408
  const sliceNames = [...this.templateNode.querySelectorAll('[slice]')].map(e=>attr(e,'slice'));
376
409
  class DceElement extends HTMLElement
377
410
  {
411
+ static get observedAttributes()
412
+ {
413
+ return templateDocs.reduce( (ret,t) =>{ ret.push( ...t.params.map(e=>attr(e,'name')) ); return ret; }, [] );
414
+ }
378
415
  connectedCallback()
379
416
  { if( this.firstElementChild?.tagName === 'TEMPLATE' )
380
417
  { const t = this.firstElementChild;
@@ -409,7 +446,7 @@ CustomElement extends HTMLElement
409
446
  const applySlices = ()=>
410
447
  { const processed = {}
411
448
 
412
- for(let ev; ev = sliceEvents.pop(); )
449
+ for(let ev; ev = sliceEvents.pop(); )
413
450
  { const s = attr( ev.target, 'slice');
414
451
  if( processed[s] )
415
452
  continue;
@@ -433,10 +470,10 @@ CustomElement extends HTMLElement
433
470
  timeoutID =0;
434
471
  },10);
435
472
  };
436
- const transform = ()=>
473
+ const transform = this.transform = ()=>
437
474
  {
438
475
  const ff = xp.map( (p,i) =>
439
- { const f = p.transformToFragment(x, document)
476
+ { const f = p.transformToFragment(x.ownerDocument, document)
440
477
  if( !f )
441
478
  console.error( "XSLT transformation error. xsl:\n", xmlString(templateDocs[i]), '\nxml:\n', xmlString(x) );
442
479
  return f
@@ -462,6 +499,20 @@ CustomElement extends HTMLElement
462
499
  transform();
463
500
  applySlices();
464
501
  }
502
+ attributeChangedCallback(name, oldValue, newValue)
503
+ { if( !this.xml )
504
+ return;
505
+ let a = this.xml.querySelector(`attributes>${name}`);
506
+ if( a )
507
+ emptyNode(a).append( createText(a,newValue));
508
+ else
509
+ { a = create( name, newValue, this.xml );
510
+ a.append( createText(a,newValue) );
511
+ this.xml.querySelector('attributes').append( a );
512
+ }
513
+
514
+ this.transform(); // needs throttling
515
+ }
465
516
  get dce(){ return dce }
466
517
  }
467
518
  if(tag)
@@ -82,18 +82,19 @@
82
82
  </table>
83
83
  </fieldset>
84
84
  <script type="module">
85
+ import { localStorageSetItem } from '../local-storage.js';
85
86
  import $ from 'https://unpkg.com/css-chain@1/CssChain.js';
86
87
 
87
88
  const basket = {cherries: 12, lemons:1 };
88
- localStorage.setItem( 'basket', JSON.stringify(basket) );
89
+ localStorageSetItem( 'basket', JSON.stringify(basket) );
89
90
 
90
91
  $('button[name]')
91
92
  .forEach( b=> localStorage.setItem( b.name, b.value ) )
92
93
  .addEventListener( 'click', e =>
93
94
  { const k = e.target.name;
94
95
  basket[k] || (basket[k] = 1);
95
- localStorage.setItem( k, basket[k] = 1+1*localStorage[k] )
96
- localStorage.setItem( 'basket', JSON.stringify(basket) );
96
+ localStorageSetItem( k, basket[k] = 1+1*localStorage[k] )
97
+ localStorageSetItem( 'basket', JSON.stringify(basket) );
97
98
  renderStorage();
98
99
  } );
99
100
 
@@ -0,0 +1,52 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3
+ xmlns:xhtml="http://www.w3.org/1999/xhtml">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
6
+ <title>parameters - custom-element Declarative Custom Element implementation demo</title>
7
+ <link rel="icon" href="./wc-square.svg" />
8
+ <script type="module" src="../location-element.js"></script>
9
+ <script type="module" src="../custom-element.js"></script>
10
+ <style>
11
+ @import "./demo.css";
12
+
13
+ button{ background: forestgreen; }
14
+ table{ min-width: 16rem; }
15
+ td{ border-bottom: 1px solid silver; }
16
+ tfoot td{ border-bottom: none; }
17
+ td,th{text-align: right; }
18
+ caption{ padding: 1rem; font-weight: bolder; font-family: sans-serif; }
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <nav>
23
+ <a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
24
+ </nav>
25
+ <html-demo-element legend="param as attributes definition" description="
26
+ params needed to declare DCE attributes and track the attributes changes. It also be used by IDE and validation.
27
+ ">
28
+ <template>
29
+ <custom-element tag="dce-link" hidden>
30
+ <xsl:param name="p1" >default_P1</xsl:param>
31
+ <xsl:param name="p2" select="'always_p2'" ></xsl:param>
32
+ <xsl:param name="p3" select="//p3 ?? 'def_P3' " ></xsl:param>
33
+ p1:{$p1} <br/> p2: {$p2} <br/> p3: {$p3}
34
+ </custom-element>
35
+ <dce-link id="dce1"></dce-link>
36
+ <section>
37
+ <dce-link id="dce2" p1="123" p2="override ignored as select is defined"></dce-link> <br/>
38
+ <div><input id="i1" value="p1" /> <button onclick="dce2.setAttribute('p1',i1.value)"> set p1</button> </div>
39
+ <div><input id="i2" value="p2" /> <button onclick="dce2.setAttribute('p2',i2.value)"> set p2</button> </div>
40
+ <div><input id="i3" value="p3" /> <button onclick="dce2.setAttribute('p3',i3.value)"> set p3</button> </div>
41
+ </section>
42
+ <dce-link id="dce3" p1="123" p3="qwe"></dce-link> |
43
+
44
+ </template>
45
+ </html-demo-element>
46
+
47
+
48
+
49
+ <script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
50
+
51
+ </body>
52
+ </html>
package/demo/s.xml CHANGED
@@ -1 +1 @@
1
- <datadom><payload><i xmlns="http://www.w3.org/1999/xhtml" slot="">loading from HTML file ...</i></payload><attributes><src>/src/demo/html-template.html</src><tag/><data-smile>👼</data-smile><attr-1>a1</attr-1><attr-2>a2</attr-2></attributes><dataset><smile>👼</smile></dataset><slice/></datadom>
1
+ <datadom><payload><i xmlns="http://www.w3.org/1999/xhtml" slot="">🍋</i></payload><attributes/><dataset/><slice/></datadom>
package/demo/s.xslt CHANGED
@@ -1,140 +1,20 @@
1
- <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dce="urn:schemas-epa-wg:dce"
2
- xmlns:exsl="http://exslt.org/common" version="1.0" exclude-result-prefixes="exsl">
3
- <xsl:template mode="payload" match="attributes">
4
- <dce-root xmlns:xhtml="http://www.w3.org/1999/xhtml" data-dce-id="1">
5
- <head data-dce-id="2">
6
-
7
- <title data-dce-id="4">template based on HTML file</title>
8
- </head>
9
- <body data-dce-id="5">
10
- <b id="wave" data-dce-id="6">👋</b>
11
- <b id="ok" data-dce-id="7">👌</b>
12
- <svg xmlns="http://www.w3.org/2000/svg" id="dwc-logo" viewBox="0 0 216 209.18" data-dce-id="8">
13
- <defs data-dce-id="9">
14
- <style data-dce-id="10">
15
- .cls-1{fill:#c2e6f1;}.cls-2{fill:#dcf1f7;}.cls-3{fill:#2d4554;}.cls-4{fill:#60cae5;}
16
- </style>
17
- </defs>
18
- <polygon class="cls-3"
19
- points="0 82.47 0 126.71 34.84 146.83 34.84 187.06 73.16 209.18 108 189.07 142.84 209.18 181.16 187.06 181.16 146.83 216 126.71 216 82.47 181.16 62.35 181.16 22.12 142.84 0 108 20.12 73.16 0 34.84 22.12 34.84 62.35 0 82.47"
20
- data-dce-id="11"/>
21
- <path class="cls-2"
22
- d="m114.33,56.69l20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0Z"
23
- data-dce-id="12"/>
24
- <path class="cls-2"
25
- d="m98.19,62.71h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"
26
- data-dce-id="13"/>
27
- <path class="cls-1"
28
- d="m48.12,66.01l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97Z"
29
- data-dce-id="14"/>
30
- <path class="cls-2"
31
- d="m46.18,24.66l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0s20.64-11.92,20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06Z"
32
- data-dce-id="15"/>
33
- <path class="cls-2"
34
- d="m115.87,24.66l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0s20.64-11.92,20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06Z"
35
- data-dce-id="16"/>
36
- <path class="cls-2"
37
- d="m152.65,42.59c-4.44,2.56-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0v-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92h0Z"
38
- data-dce-id="17"/>
39
- <path class="cls-2"
40
- d="m77.55,158.4l20.65-11.92h0c4.44-2.57,6.33-5.84,6.33-10.97v-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92c-4.44,2.57-6.33,5.84-6.33,10.97h0s0,23.84,0,23.84c0,.54.45.8.92.54Z"
41
- data-dce-id="18"/>
42
- <path class="cls-4"
43
- d="m146.31,134.03v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0s0-23.84,0-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97Z"
44
- data-dce-id="19"/>
45
- <path class="cls-4"
46
- d="m63.35,123.06h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"
47
- data-dce-id="20"/>
48
- <path class="cls-4"
49
- d="m103.61,151.37l-20.64,11.92c-4.44,2.57-6.33,5.84-6.33,10.97h0s0,23.84,0,23.84c0,.54.45.8.92.54l20.65-11.92h0c4.44-2.57,6.33-5.84,6.33-10.97v-23.84c0-.54-.45-.8-.92-.53Z"
50
- data-dce-id="21"/>
51
- <path class="cls-4"
52
- d="m63.35,163.29h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"
53
- data-dce-id="22"/>
54
- <path class="cls-4"
55
- d="m28.51,102.94h0s-20.64-11.92-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84s0,0,0,0c0,5.13,1.89,8.4,6.33,10.97l20.65,11.92c.47.27.92,0,.92-.54v-23.84c0-5.13-1.89-8.4-6.33-10.97Z"
56
- data-dce-id="23"/>
57
- <path class="cls-4"
58
- d="m133.04,163.29l-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84c0,5.13,1.89,8.4,6.33,10.97h0s20.65,11.92,20.65,11.92c.47.27.92,0,.92-.54v-23.84s0,0,0,0c0-5.13-1.89-8.4-6.33-10.97Z"
59
- data-dce-id="24"/>
60
- <path class="cls-4"
61
- d="m173.29,151.37l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0s0-23.84,0-23.84c0-.54-.45-.8-.92-.53Z"
62
- data-dce-id="25"/>
63
- <path class="cls-4"
64
- d="m209.06,91.55c0-.54-.45-.8-.92-.53l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0v-23.84Z"
65
- data-dce-id="26"/>
66
- <path class="cls-2"
67
- d="m149.18,117.04l20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0Z"
68
- data-dce-id="27"/>
69
- <path class="cls-1"
70
- d="m112.39,98.05l20.65-11.92c4.44-2.57,6.33-5.84,6.33-10.97h0v-23.84c0-.54-.45-.8-.92-.53l-20.64,11.92h0c-4.44,2.57-6.33,5.84-6.33,10.97v23.84c0,.54.45.8.92.54Z"
71
- data-dce-id="28"/>
72
- <path class="cls-1"
73
- d="m100.13,105.12c.47-.27.47-.79,0-1.06l-20.65-11.92c-4.44-2.57-8.22-2.57-12.67,0h0s-20.65,11.92-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92h0c4.44,2.57,8.22,2.57,12.67,0l20.64-11.92Z"
74
- data-dce-id="29"/>
75
- <path class="cls-2"
76
- d="m65.29,85.01c.47-.27.47-.79,0-1.06l-20.65-11.92c-4.44-2.57-8.22-2.57-12.67,0h0s-20.65,11.92-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92h0c4.44,2.57,8.22,2.57,12.67,0l20.64-11.92Z"
77
- data-dce-id="30"/>
78
- <path class="cls-1"
79
- d="m133.04,123.06l-20.64-11.92c-.47-.27-.92-.01-.92.53v23.84c0,5.13,1.89,8.4,6.33,10.97h0s20.65,11.92,20.65,11.92c.47.27.92,0,.92-.54v-23.84s0,0,0,0c0-5.13-1.89-8.4-6.33-10.97Z"
80
- data-dce-id="31"/>
81
- <path class="cls-1"
82
- d="m184.02,96.93l20.64-11.92c.47-.27.47-.79,0-1.06l-20.65-11.92h0c-4.44-2.57-8.22-2.57-12.67,0l-20.65,11.92c-.47.27-.47.79,0,1.06l20.64,11.92c4.44,2.57,8.22,2.57,12.67,0h0Z"
83
- data-dce-id="32"/>
84
- </svg>
85
- <math xmlns="http://www.w3.org/1998/Math/MathML" id="sophomores-dream" display="block" data-dce-id="33">
86
- <mrow data-dce-id="34">
87
- <msubsup data-dce-id="35">
88
- <mo data-dce-id="36">∫</mo>
89
- <mn data-dce-id="37">0</mn>
90
- <mn data-dce-id="38">1</mn>
91
- </msubsup>
92
- <msup data-dce-id="39">
93
- <mi data-dce-id="40">x</mi>
94
- <mi data-dce-id="41">x</mi>
95
- </msup>
96
- <mo rspace="0.22em" data-dce-id="42">⁢</mo>
97
- <mo rspace="0" data-dce-id="43">ⅆ</mo>
98
- <mi data-dce-id="44">x</mi>
99
- <mo data-dce-id="45">=</mo>
100
- <munderover data-dce-id="46">
101
- <mo data-dce-id="47">∑</mo>
102
- <mrow data-dce-id="48">
103
- <mi data-dce-id="49">n</mi>
104
- <mo data-dce-id="50">=</mo>
105
- <mn data-dce-id="51">1</mn>
106
- </mrow>
107
- <mn data-dce-id="52">∞</mn>
108
- </munderover>
109
- <msup data-dce-id="53">
110
- <mrow data-dce-id="54">
111
- <mo data-dce-id="55">(</mo>
112
- <mrow data-dce-id="56">
113
- <mo form="prefix" data-dce-id="57">−</mo>
114
- <mn data-dce-id="58">1</mn>
115
- </mrow>
116
- <mo data-dce-id="59">)</mo>
117
- </mrow>
118
- <mrow data-dce-id="60">
119
- <mi data-dce-id="61">n</mi>
120
- <mo data-dce-id="62">+</mo>
121
- <mn data-dce-id="63">1</mn>
122
- </mrow>
123
- </msup>
124
- <mo data-dce-id="64">⁢</mo>
125
- <msup data-dce-id="65">
126
- <mi data-dce-id="66">n</mi>
127
- <mrow data-dce-id="67">
128
- <mo form="prefix" data-dce-id="68">−</mo>
129
- <mi data-dce-id="69">n</mi>
130
- </mrow>
131
- </msup>
132
- </mrow>
133
- </math>
134
- <script type="module" src="/__web-dev-server__web-socket.js?wds-import-map=0" data-dce-id="70"/>
135
- </body>
136
- </dce-root>
137
- </xsl:template>
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" xmlns:dce="urn:schemas-epa-wg:dce" xmlns:exsl="http://exslt.org/common" version="1.0" exclude-result-prefixes="exsl">
3
+ <xsl:template match="ignore">
4
+ <xsl:choose>
5
+ <xsl:when test="//attr"><xsl:value-of select="//attr"/></xsl:when>
6
+ <xsl:otherwise><xsl:value-of select="def"/></xsl:otherwise>
7
+ </xsl:choose>
8
+ <xsl:value-of select="."/></xsl:template>
9
+ <xsl:template mode="payload" match="attributes"><xsl:param xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="p1"><xsl:choose>
10
+ <xsl:when test="//p1 "><xsl:value-of select="//p1 "/></xsl:when>
11
+ <xsl:otherwise><xsl:value-of select=" 'def_p1' "/></xsl:otherwise>
12
+ </xsl:choose></xsl:param><xsl:param xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="p2" select="'always_p2'"/><xsl:param xmlns:xsl="http://www.w3.org/1999/XSL/Transform" name="p3"><xsl:choose>
13
+ <xsl:when test="p3"><xsl:value-of select="p3"/></xsl:when>
14
+ <xsl:otherwise><xsl:value-of select="default_P3"/></xsl:otherwise>
15
+ </xsl:choose></xsl:param><dce-root xmlns="http://www.w3.org/1999/xhtml" xmlns:xhtml="http://www.w3.org/1999/xhtml" data-dce-id="1"><dce-text xmlns="" data-dce-id="2">
16
+ p1:<xsl:value-of select="$p1"/> </dce-text><br xmlns="" data-dce-id="3"/><dce-text xmlns="" data-dce-id="4"> p2: <xsl:value-of select="$p2"/> </dce-text><br xmlns="" data-dce-id="5"/><dce-text xmlns="" data-dce-id="6"> p3: <xsl:value-of select="$p3"/>
17
+ </dce-text></dce-root></xsl:template>
138
18
  <xsl:template match="/">
139
19
  <xsl:apply-templates mode="payload" select="/datadom/attributes"/>
140
20
  </xsl:template>
package/demo/z.html CHANGED
@@ -1,42 +1,59 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <dce-root data-dce-id="1" xmlns:dce="urn:schemas-epa-wg:dce" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3
- <table data-dce-id="2">
4
- <tr data-dce-id="3">
5
- <xhtml:th data-dce-id="4">href</xhtml:th>
6
- <xhtml:td data-dce-id="5">http://localhost:63342/custom-element/demo/a.html?_ijt=qca6trk5kne6eo4s4tomq4egmm&amp;_ij_reload=RELOAD_ON_SAVE</xhtml:td>
7
- </tr>
8
- <tr data-dce-id="3">
9
- <xhtml:th data-dce-id="4">origin</xhtml:th>
10
- <xhtml:td data-dce-id="5">http://localhost:63342</xhtml:td>
11
- </tr>
12
- <tr data-dce-id="3">
13
- <xhtml:th data-dce-id="4">protocol</xhtml:th>
14
- <xhtml:td data-dce-id="5">http:</xhtml:td>
15
- </tr>
16
- <tr data-dce-id="3">
17
- <xhtml:th data-dce-id="4">host</xhtml:th>
18
- <xhtml:td data-dce-id="5">localhost:63342</xhtml:td>
19
- </tr>
20
- <tr data-dce-id="3">
21
- <xhtml:th data-dce-id="4">hostname</xhtml:th>
22
- <xhtml:td data-dce-id="5">localhost</xhtml:td>
23
- </tr>
24
- <tr data-dce-id="3">
25
- <xhtml:th data-dce-id="4">port</xhtml:th>
26
- <xhtml:td data-dce-id="5">63342</xhtml:td>
27
- </tr>
28
- <tr data-dce-id="3">
29
- <xhtml:th data-dce-id="4">pathname</xhtml:th>
30
- <xhtml:td data-dce-id="5">/custom-element/demo/a.html</xhtml:td>
31
- </tr>
32
- <tr data-dce-id="3">
33
- <xhtml:th data-dce-id="4">search</xhtml:th>
34
- <xhtml:td data-dce-id="5">?_ijt=qca6trk5kne6eo4s4tomq4egmm&amp;_ij_reload=RELOAD_ON_SAVE</xhtml:td>
35
- </tr>
36
- <tr data-dce-id="3">
37
- <xhtml:th data-dce-id="4">hash</xhtml:th>
38
- <xhtml:td data-dce-id="5"/>
39
- </tr>
40
- </table>
41
- <location-element slice="window-url" data-dce-id="6"/>
42
- </dce-root>
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>CSS scoping - Declarative Custom Element implementation demo</title>
6
+ <link rel="icon" href="./wc-square.svg"/>
7
+
8
+ <script type="module" src="../http-request.js"></script>
9
+ <script type="module" src="../input-text.js"></script>
10
+ <script type="module" src="../custom-element.js"></script>
11
+ <style>
12
+ @import "./demo.css";
13
+
14
+ button {
15
+ display: inline-flex;
16
+ flex-direction: column;
17
+ align-items: center;
18
+ flex: auto;
19
+ box-shadow: inset silver 0 0 1rem;
20
+ min-width: 12rem;
21
+ padding: 1rem;
22
+ color: coral;
23
+ text-shadow: 1px 1px silver;
24
+ font-weight: bolder;
25
+ }
26
+
27
+ caption {
28
+ padding: 1rem;
29
+ font-weight: bolder;
30
+ font-family: sans-serif;
31
+ }
32
+
33
+ code {
34
+ text-align: right;
35
+ min-width: 3rem;
36
+ }
37
+
38
+ </style>
39
+ </head>
40
+ <body>
41
+
42
+
43
+ <custom-element tag="dce-link" hidden>
44
+ <xsl:param name="p1" select="//p1 ?? 'def_p1' " ></xsl:param>
45
+ <xsl:param name="p2" select="'always_p2'" ></xsl:param>
46
+ <xsl:param name="p3" >default_P3</xsl:param>
47
+ p1:{$p1} <br/> p2: {$p2} <br/> p3: {$p3}
48
+ </custom-element>
49
+ <section>
50
+ <dce-link id="dce1"></dce-link>
51
+ <div><input id="i1" value="p1" /> <button onclick="debugger; dce2.setAttribute('p1',i1.value)"> set p1</button> </div>
52
+ <div><input id="i2" value="p2" /> <button onclick="dce2.setAttribute('p2',i2.value)"> set p2</button> </div>
53
+ <div><input id="i3" value="p3" /> <button onclick="dce2.setAttribute('p3',i3.value)"> set p3</button> </div>
54
+ </section>
55
+ <dce-link id="dce2" p1="123" p2="override ignored as select is defined"></dce-link> |
56
+ <dce-link id="dce3" p1="123" p3="qwe"></dce-link> |
57
+
58
+ </body>
59
+ </html>
package/index.html CHANGED
@@ -14,6 +14,7 @@
14
14
  <h3><code>custom-element</code> demo</h3>
15
15
  <div><a href="https://github.com/EPA-WG/custom-element"
16
16
  ><img src="https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg" alt="icon">GIT</a>
17
+ | <a href="https://github.com/EPA-WG/custom-element/blob/main/README.md">README</a>
17
18
  | <a href="https://stackblitz.com/github/EPA-WG/custom-element?file=index.html">Sandbox</a>
18
19
  | <a href="https://chrome.google.com/webstore/detail/epa-wgcustom-element/hiofgpmmkdembdogjpagmbbbmefefhbl"
19
20
  >Chrome devtools plugin</a>
@@ -25,13 +26,14 @@
25
26
  The data query is powered by XPath. </p>
26
27
  <p>Try in <a href="https://stackblitz.com/github/EPA-WG/custom-element?file=index.html" >Sandbox</a> </p>
27
28
  <section>
28
- <h4>Data layer demo</h4>
29
+ <h4>Features demo</h4>
29
30
  <a href="./demo/local-storage.html" >local-storage </a> |
30
31
  <a href="./demo/http-request.html" >http-request </a> |
31
32
  <a href="./demo/location-element.html" >location-element </a> |
32
33
  <a href="./demo/external-template.html" >external template </a> <br/>
33
34
  <a href="./demo/hex-grid.html" >hex grid lib </a> |
34
35
  <a href="./demo/scoped-css.html" >scoped CSS </a> |
36
+ <a href="./demo/parameters.html" >attributes </a> |
35
37
  <a href="./demo/dom-merge.html" >DOM merge on dynamic update </a>
36
38
  </section>
37
39
  </nav>
package/local-storage.js CHANGED
@@ -9,22 +9,14 @@ const string2value = (type, v) =>
9
9
  return type==='number'? el.valueAsNumber : 'date|time|dateTimeLocal'.includes(type)? el.valueAsDate: el.value;
10
10
  };
11
11
 
12
- let originalSetItem;
13
-
14
- function ensureTrackLocalStorage()
15
- { if( originalSetItem )
16
- return;
17
- originalSetItem = localStorage.setItem;
18
- localStorage.setItem = function( key, value, ...rest )
19
- { originalSetItem.apply(this, [ key, value, ...rest ]);
20
- window.dispatchEvent( new CustomEvent('local-storage',{detail:{key,value}}) );
21
- };
12
+ export function localStorageSetItem(key, value)
13
+ { localStorage.setItem(key, value);
14
+ window.dispatchEvent( new CustomEvent('local-storage',{detail:{key,value}}) );
22
15
  }
23
-
24
16
  export class LocalStorageElement extends HTMLElement
25
17
  {
26
18
  static get observedAttributes() {
27
- return [ 'value' // populated from localStorage, if defined initially, sets the valiue in storage
19
+ return [ 'value' // populated from localStorage, if defined initially, sets the value in storage
28
20
  , 'slice'
29
21
  , 'key'
30
22
  , 'type' // `text|json`, defaults to text, other types are compatible with INPUT field
@@ -41,14 +33,13 @@ export class LocalStorageElement extends HTMLElement
41
33
  }
42
34
  // todo apply type
43
35
  if( this.hasAttribute('value'))
44
- localStorage.setItem( attr( this, 'key' ) )
36
+ localStorageSetItem( attr( this, 'key' ) )
45
37
  else
46
38
  fromStorage()
47
39
 
48
40
  if( this.hasAttribute('live') )
49
41
  { const listener = (e => e.detail.key === attr( 'key' ) && fromStorage());
50
42
  window.addEventListener( 'local-storage', listener );
51
- ensureTrackLocalStorage();
52
43
  this._destroy = ()=> window.removeEventListener('local-storage', listener );
53
44
  }
54
45
  }
@@ -3,7 +3,7 @@ const attr = (el, attr)=> el.getAttribute(attr);
3
3
  export class LocationElement extends HTMLElement
4
4
  {
5
5
  static get observedAttributes()
6
- { return [ 'value' // populated from localStorage, if defined initially, sets the valiue in storage
6
+ { return [ 'value' // populated from localStorage, if defined initially, sets the value in storage
7
7
  , 'slice'
8
8
  , 'live' // monitors location change
9
9
  , 'src' // URL to be parsed, defaults to `window.location`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epa-wg/custom-element",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "Declarative Custom Element as W3C proposal PoC with native(XSLT) based templating",
5
5
  "browser": "custom-element.js",
6
6
  "module": "custom-element.js",