@epa-wg/custom-element 0.0.10 → 0.0.12
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/.gitignore +6 -2
- package/.idea/inspectionProfiles/Project_Default.xml +41 -0
- package/.idea/misc.xml +4 -5
- package/.vs/VSWorkspaceState.json +8 -0
- package/.vs/custom-element/FileContentIndex/1487e471-3751-47bc-a499-d78eda924eda.vsidx +0 -0
- package/.vs/custom-element/v17/.wsuo +0 -0
- package/.vs/slnx.sqlite +0 -0
- package/README.md +53 -19
- package/custom-element.js +335 -76
- package/demo/a.html +38 -0
- package/demo/confused.svg +37 -0
- package/demo/demo.css +3 -1
- package/demo/dom-merge.html +121 -0
- package/demo/embed-1.html +3 -0
- package/demo/external-template.html +178 -0
- package/demo/html-template.html +126 -0
- package/demo/html-template.xhtml +45 -0
- package/demo/html-template.xml +45 -0
- package/demo/http-request.html +45 -58
- package/demo/local-storage.html +24 -19
- package/demo/location-element.html +60 -59
- package/demo/s.xml +1 -0
- package/demo/s.xslt +159 -0
- package/demo/table.xml +25 -0
- package/demo/table.xsl +293 -0
- package/demo/template.xsl +46 -0
- package/demo/tree.xml +25 -0
- package/demo/tree.xsl +33 -0
- package/demo/wc-square.svg +1 -1
- package/demo/xhtml-template.xhtml +45 -0
- package/demo/z.html +42 -0
- package/demo/z.xml +60 -0
- package/http-request.js +28 -35
- package/index.html +41 -33
- package/input-text.js +17 -0
- package/local-storage.js +28 -35
- package/location-element.js +15 -16
- package/package.json +1 -1
package/http-request.js
CHANGED
|
@@ -2,56 +2,49 @@ const attr = (el, attr)=> el.getAttribute(attr);
|
|
|
2
2
|
|
|
3
3
|
export class HttpRequestElement extends HTMLElement
|
|
4
4
|
{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
static get observedAttributes() {
|
|
6
|
+
return [ 'value' // populated from localStorage, if defined initially, sets the value in storage
|
|
7
|
+
, 'slice'
|
|
8
|
+
, 'url'
|
|
9
|
+
, 'method'
|
|
10
|
+
, 'header-accept'
|
|
11
|
+
]
|
|
8
12
|
}
|
|
13
|
+
|
|
9
14
|
get requestHeaders()
|
|
10
15
|
{ const ret = {};
|
|
11
16
|
[...this.attributes].filter(a=>a.name.startsWith('header-')).map( a => ret[a.name.substring(7)] = a.value );
|
|
12
|
-
return ret
|
|
17
|
+
return ret
|
|
13
18
|
}
|
|
14
19
|
get requestProps()
|
|
15
20
|
{ const ret = {};
|
|
16
21
|
[...this.attributes].filter(a=>!a.name.startsWith('header-')).map( a => ret[a.name] = a.value );
|
|
17
|
-
return ret
|
|
22
|
+
return ret
|
|
18
23
|
}
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
s.destroy = ()=>
|
|
27
|
-
{ // todo destroy slices in custom-element
|
|
28
|
-
controller.abort();
|
|
29
|
-
};
|
|
24
|
+
|
|
25
|
+
disconnectedCallback(){ this._destroy?.(); }
|
|
26
|
+
|
|
27
|
+
connectedCallback()
|
|
28
|
+
{ const controller = new AbortController();
|
|
29
|
+
this._destroy = ()=> controller.abort(this.localName+' disconnected');
|
|
30
|
+
|
|
30
31
|
const url = attr(this, 'url') || ''
|
|
31
32
|
, request = { ...this.requestProps, headers: this.requestHeaders }
|
|
32
|
-
, slice = {
|
|
33
|
-
,
|
|
34
|
-
|
|
35
|
-
if ( parent.onSlice )
|
|
36
|
-
return parent.onSlice(slice);
|
|
37
|
-
console.error(`${this.localName} used outside of custom-element`)
|
|
38
|
-
debugger;
|
|
39
|
-
};
|
|
40
|
-
|
|
33
|
+
, slice = { request }
|
|
34
|
+
, update = () => this.dispatchEvent( new Event('change') );
|
|
35
|
+
this.value = slice;
|
|
41
36
|
setTimeout( async ()=>
|
|
42
|
-
{
|
|
37
|
+
{ update();
|
|
43
38
|
const response = await fetch(url,{ ...this.requestProps, signal: controller.signal, headers: this.requestHeaders })
|
|
44
|
-
, r= {headers: {}};
|
|
45
|
-
[...response.headers].map( ([k,v]) => r.headers[k]=v );
|
|
46
|
-
'ok,status,statusText,type,url,redirected'.split(',').map(k=>r[k]=response[k])
|
|
39
|
+
, r = {headers: {}};
|
|
40
|
+
[...response.headers].map( ([k,v]) => r.headers[k] = v );
|
|
41
|
+
'ok,status,statusText,type,url,redirected'.split(',').map( k=> r[k] = response[k] )
|
|
47
42
|
|
|
48
|
-
slice.
|
|
49
|
-
|
|
50
|
-
slice.
|
|
51
|
-
|
|
43
|
+
slice.response = r;
|
|
44
|
+
update();
|
|
45
|
+
slice.data = await response.json();
|
|
46
|
+
update();
|
|
52
47
|
},0 );
|
|
53
|
-
|
|
54
|
-
return s;
|
|
55
48
|
}
|
|
56
49
|
}
|
|
57
50
|
|
package/index.html
CHANGED
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
The data query is powered by XPath. </p>
|
|
26
26
|
<p>Try in <a href="https://stackblitz.com/github/EPA-WG/custom-element?file=index.html" >Sandbox</a> </p>
|
|
27
27
|
<section>
|
|
28
|
-
<
|
|
29
|
-
<a href="./demo/local-storage.html">local-storage</a> |
|
|
30
|
-
<a href="./demo/http-request.html">http-request</a> |
|
|
31
|
-
<a href="./demo/location-element.html">location-element</a>
|
|
28
|
+
<h4>Data layer demo</h4>
|
|
29
|
+
<a href="./demo/local-storage.html" >local-storage </a> |
|
|
30
|
+
<a href="./demo/http-request.html" >http-request </a> |
|
|
31
|
+
<a href="./demo/location-element.html" >location-element </a> |
|
|
32
|
+
<a href="./demo/external-template.html" >external template </a> |
|
|
33
|
+
<a href="./demo/dom-merge.html" >DOM merge on dynamic update </a>
|
|
32
34
|
</section>
|
|
33
35
|
</nav>
|
|
34
36
|
<html-demo-element legend="1. simple payload"
|
|
@@ -45,20 +47,22 @@
|
|
|
45
47
|
description="slots are filled as in template+shadow root">
|
|
46
48
|
<template>
|
|
47
49
|
<custom-element tag="dce-1-slot" hidden>
|
|
48
|
-
|
|
50
|
+
🐇❤️<slot name="slot1"> 🥦</slot>
|
|
49
51
|
</custom-element>
|
|
50
52
|
<dce-1-slot><i slot="slot1">🥕</i></dce-1-slot>
|
|
51
53
|
</template>
|
|
52
54
|
</html-demo-element>
|
|
53
55
|
|
|
54
56
|
<html-demo-element legend="2a. payload with slot definition and slot value"
|
|
55
|
-
description="same slot can be used multiple times
|
|
57
|
+
description="unlike in TEMPLATE, same slot can be used multiple times and within attribute ">
|
|
56
58
|
<template>
|
|
57
59
|
<custom-element tag="dce-2-slots" hidden>
|
|
58
60
|
<slot name="slot2"> 😃</slot> and again:
|
|
59
61
|
<slot name="slot2"> 😃</slot>
|
|
62
|
+
<xhtml:input placeholder="🐇❤️{//*[@slot='slot2']}"/>
|
|
60
63
|
</custom-element>
|
|
61
64
|
<dce-2-slots><i slot="slot2">🥕</i></dce-2-slots>
|
|
65
|
+
<dce-2-slots></dce-2-slots>
|
|
62
66
|
</template>
|
|
63
67
|
</html-demo-element>
|
|
64
68
|
|
|
@@ -94,6 +98,7 @@
|
|
|
94
98
|
<custom-element tag="greet-element" hidden>
|
|
95
99
|
<slot> Hello </slot> World!
|
|
96
100
|
</custom-element>
|
|
101
|
+
<greet-element></greet-element>
|
|
97
102
|
<greet-element>👋</greet-element>
|
|
98
103
|
</template>
|
|
99
104
|
</html-demo-element>
|
|
@@ -102,35 +107,38 @@
|
|
|
102
107
|
description="Complex case with slots, attributes, dataset, conditional render">
|
|
103
108
|
<template>
|
|
104
109
|
|
|
105
|
-
<custom-element tag="pokemon-tile" hidden>
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
110
|
+
<custom-element tag="pokemon-tile" hidden id="shared-template">
|
|
111
|
+
<template>
|
|
112
|
+
<h3> {title} </h3> <!-- title is an attribute in instance
|
|
113
|
+
mapped into /*/attributes/title -->
|
|
114
|
+
<xsl:if test="//smile"> <!-- data-smile DCE instance attribute,
|
|
115
|
+
mapped into /*/dataset/smile
|
|
116
|
+
used in condition -->
|
|
117
|
+
<!-- data-smile DCE instance attribute, used as HTML -->
|
|
118
|
+
<div>Smile as: {//smile}</div> <!-- /datadom/dataset/smile -->
|
|
119
|
+
</xsl:if>
|
|
120
|
+
<!-- image would not be visible in sandbox, see live demo -->
|
|
121
|
+
<img src="https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/{pokemon-id}.svg"
|
|
122
|
+
alt="{title} image"/>
|
|
123
|
+
<!-- image-src and title are DCE instance attributes,
|
|
124
|
+
mapped into /*/attributes/
|
|
125
|
+
used within output attribute via curly brackets -->
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
<!-- `slot name=xxx` replaced with elements with `slot=xxx` attribute -->
|
|
128
|
+
<p><slot name="description"><i>description is not available</i></slot></p>
|
|
129
|
+
<xsl:for-each select="//*[@pokemon-id]">
|
|
130
|
+
<!-- loop over payload elements with `pokemon-id` attribute,
|
|
131
|
+
i.e LI elements -->
|
|
132
|
+
<button>
|
|
133
|
+
<img height="32"
|
|
134
|
+
src="https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/{@pokemon-id}.svg"
|
|
135
|
+
alt="{text()}"/>
|
|
136
|
+
<br/>
|
|
137
|
+
{text()} <!-- text from LI element in loop -->
|
|
138
|
+
</button>
|
|
132
139
|
|
|
133
|
-
|
|
140
|
+
</xsl:for-each>
|
|
141
|
+
</template>
|
|
134
142
|
</custom-element>
|
|
135
143
|
|
|
136
144
|
<pokemon-tile title="bulbasaur" data-smile="👼" pokemon-id="1" >
|
package/input-text.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class InputTextElement extends HTMLElement
|
|
2
|
+
{
|
|
3
|
+
constructor()
|
|
4
|
+
{
|
|
5
|
+
super();
|
|
6
|
+
const i = this.ownerDocument.createElement('input');
|
|
7
|
+
for(let a of this.attributes)
|
|
8
|
+
a.namespaceURI ? i.setAttributeNS(a.namespaceURI,a.name,a.value) : i.setAttribute(a.name,a.value)
|
|
9
|
+
this.append(i)
|
|
10
|
+
}
|
|
11
|
+
get value(){ return this.firstChild.value }
|
|
12
|
+
set value(v){ return this.firstChild.value = v }
|
|
13
|
+
disconnectedCallback(){ }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
window.customElements.define( 'input-text', InputTextElement );
|
|
17
|
+
export default InputTextElement;
|
package/local-storage.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
const
|
|
2
|
-
, string2value = (type, v) =>
|
|
1
|
+
const string2value = (type, v) =>
|
|
3
2
|
{ if( type === 'text')
|
|
4
3
|
return v;
|
|
5
4
|
if( type === 'json')
|
|
@@ -24,42 +23,36 @@ function ensureTrackLocalStorage()
|
|
|
24
23
|
|
|
25
24
|
export class LocalStorageElement extends HTMLElement
|
|
26
25
|
{
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
static get observedAttributes() {
|
|
27
|
+
return [ 'value' // populated from localStorage, if defined initially, sets the valiue in storage
|
|
28
|
+
, 'slice'
|
|
29
|
+
, 'key'
|
|
30
|
+
, 'type' // `text|json`, defaults to text, other types are compatible with INPUT field
|
|
31
|
+
, 'live' // monitors localStorage change
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async connectedCallback()
|
|
30
36
|
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{ state.listener = 1;
|
|
48
|
-
window.addEventListener( 'local-storage', listener );
|
|
49
|
-
ensureTrackLocalStorage();
|
|
50
|
-
}
|
|
51
|
-
propagateSlice();
|
|
52
|
-
return s || {}
|
|
37
|
+
const attr = attr => this.getAttribute(attr)
|
|
38
|
+
, fromStorage = ()=>
|
|
39
|
+
{ this.value = string2value( attr('type'), localStorage.getItem( attr( 'key' ) ) );
|
|
40
|
+
this.dispatchEvent( new Event('change') )
|
|
41
|
+
}
|
|
42
|
+
// todo apply type
|
|
43
|
+
if( this.hasAttribute('value'))
|
|
44
|
+
localStorage.setItem( attr( this, 'key' ) )
|
|
45
|
+
else
|
|
46
|
+
fromStorage()
|
|
47
|
+
|
|
48
|
+
if( this.hasAttribute('live') )
|
|
49
|
+
{ const listener = (e => e.detail.key === attr( 'key' ) && fromStorage());
|
|
50
|
+
window.addEventListener( 'local-storage', listener );
|
|
51
|
+
ensureTrackLocalStorage();
|
|
52
|
+
this._destroy = ()=> window.removeEventListener('local-storage', listener );
|
|
53
53
|
}
|
|
54
|
-
this._destroy = ()=>
|
|
55
|
-
{
|
|
56
|
-
if( !state.listener )
|
|
57
|
-
return;
|
|
58
|
-
state.listener && window.removeEventListener('local-storage', listener );
|
|
59
|
-
delete state.listener;
|
|
60
|
-
};
|
|
61
54
|
}
|
|
62
|
-
disconnectedCallback(){ this._destroy(); }
|
|
55
|
+
disconnectedCallback(){ this._destroy?.(); }
|
|
63
56
|
}
|
|
64
57
|
|
|
65
58
|
window.customElements.define( 'local-storage', LocalStorageElement );
|
package/location-element.js
CHANGED
|
@@ -2,15 +2,20 @@ const attr = (el, attr)=> el.getAttribute(attr);
|
|
|
2
2
|
|
|
3
3
|
export class LocationElement extends HTMLElement
|
|
4
4
|
{
|
|
5
|
-
|
|
6
|
-
//
|
|
5
|
+
static get observedAttributes()
|
|
6
|
+
{ return [ 'value' // populated from localStorage, if defined initially, sets the valiue in storage
|
|
7
|
+
, 'slice'
|
|
8
|
+
, 'live' // monitors location change
|
|
9
|
+
, 'src' // URL to be parsed, defaults to `window.location`
|
|
10
|
+
];
|
|
11
|
+
}
|
|
7
12
|
|
|
8
13
|
constructor()
|
|
9
14
|
{
|
|
10
15
|
super();
|
|
11
16
|
const state = {}
|
|
12
17
|
, listener = e=> propagateSlice(e)
|
|
13
|
-
, propagateSlice = (
|
|
18
|
+
, propagateSlice = ()=>
|
|
14
19
|
{ const urlStr = attr(this,'src')
|
|
15
20
|
const url = urlStr? new URL(urlStr) : window.location
|
|
16
21
|
|
|
@@ -24,21 +29,14 @@ export class LocationElement extends HTMLElement
|
|
|
24
29
|
{ if ('string' === typeof url[k])
|
|
25
30
|
detail[k] = url[k]
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return parent.onSlice(
|
|
30
|
-
{ detail
|
|
31
|
-
, target: this
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
console.error(`${this.localName} used outside of custom-element`)
|
|
35
|
-
debugger;
|
|
32
|
+
this.value = detail;
|
|
33
|
+
this.dispatchEvent( new Event('change') );
|
|
36
34
|
};
|
|
37
35
|
this.sliceInit = s =>
|
|
38
36
|
{
|
|
39
37
|
if( !state.listener && this.hasAttribute('live') )
|
|
40
38
|
{ state.listener = 1;
|
|
41
|
-
window.addEventListener( 'popstate', listener );
|
|
39
|
+
window.addEventListener( 'popstate' , listener );
|
|
42
40
|
window.addEventListener( 'hashchange', listener );
|
|
43
41
|
}
|
|
44
42
|
propagateSlice();
|
|
@@ -49,14 +47,15 @@ export class LocationElement extends HTMLElement
|
|
|
49
47
|
if( !state.listener )
|
|
50
48
|
return;
|
|
51
49
|
if(state.listener)
|
|
52
|
-
{ window.removeEventListener('popstate', listener);
|
|
50
|
+
{ window.removeEventListener('popstate' , listener);
|
|
53
51
|
window.removeEventListener('hashchange', listener);
|
|
54
52
|
}
|
|
55
53
|
delete state.listener;
|
|
56
54
|
};
|
|
57
|
-
|
|
55
|
+
|
|
58
56
|
}
|
|
59
|
-
|
|
57
|
+
connectedCallback(){ this.sliceInit() }
|
|
58
|
+
disconnectedCallback(){ this._destroy() }
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
window.customElements.define( 'location-element', LocationElement );
|
package/package.json
CHANGED