@epa-wg/custom-element 0.0.8 → 0.0.10
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 +12 -6
- package/custom-element.js +14 -12
- package/demo/dce-social-preview.png +0 -0
- package/demo/http-request.html +66 -0
- package/demo/local-storage.html +4 -0
- package/demo/location-element.html +149 -0
- package/demo/logo.png +0 -0
- package/demo/wc-square.svg +1 -0
- package/http-request.js +19 -4
- package/index.html +3 -1
- package/location-element.js +63 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
# custom-element
|
|
2
|
-
`Declarative Custom Element` proof of concept as a part of
|
|
3
|
-
|
|
2
|
+
`Declarative Custom Element` is a part of pure `Declarative Web Application` stack. A proof of concept as a part of
|
|
3
|
+
[WCCG in Declarative custom elements](https://github.com/w3c/webcomponents-cg/issues/32#issuecomment-1321037301)
|
|
4
|
+
discussion. The functionality of DCE and its data access does not require programming using JavaScript.
|
|
4
5
|
|
|
5
|
-
It allows to define custom HTML tag with template filled from slots and
|
|
6
|
+
It allows to define custom HTML tag with template filled from slots, attributes and data `slice` as of now from
|
|
7
|
+
[local-storage][local-storage-demo], [http-request][http-request-demo], [location][location-demo].
|
|
8
|
+
UI is re-rendered on each data slice change.
|
|
6
9
|
|
|
7
10
|
[![git][github-image] GitHub][git-url]
|
|
8
11
|
| Live demo: [custom-element][demo-url]
|
|
@@ -182,12 +185,15 @@ within template
|
|
|
182
185
|
[git-url]: https://github.com/EPA-WG/custom-element
|
|
183
186
|
[git-test-url]: https://github.com/EPA-WG/custom-element-test
|
|
184
187
|
[demo-url]: https://unpkg.com/@epa-wg/custom-element@0.0/index.html
|
|
188
|
+
[local-storage-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/local-storage.html
|
|
189
|
+
[http-request-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/http-request.html
|
|
190
|
+
[location-demo]: https://unpkg.com/@epa-wg/custom-element@0.0/demo/location.html
|
|
185
191
|
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
|
|
186
192
|
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
|
|
187
193
|
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element
|
|
188
|
-
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
189
|
-
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
190
|
-
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
194
|
+
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.10/coverage/coverage.svg
|
|
195
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.10/coverage/lcov-report/index.html
|
|
196
|
+
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.10/storybook-static/index.html?path=/story/welcome--introduction
|
|
191
197
|
[sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
|
|
192
198
|
[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
|
|
193
199
|
[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
|
package/custom-element.js
CHANGED
|
@@ -17,7 +17,9 @@ bodyXml( dce )
|
|
|
17
17
|
{
|
|
18
18
|
const t = dce.firstElementChild
|
|
19
19
|
, sanitize = s => s.replaceAll("<html:","<")
|
|
20
|
-
.replaceAll("</html:","</")
|
|
20
|
+
.replaceAll("</html:","</")
|
|
21
|
+
.replaceAll( />\s*<\/xsl:value-of>/g ,"/>")
|
|
22
|
+
.replaceAll( />\s*<\/(br|hr|img|area|base|col|embed|input|link|meta|param|source|track|wbr)>/g ,"/>");
|
|
21
23
|
if( t?.tagName === 'TEMPLATE')
|
|
22
24
|
return sanitize( new XMLSerializer().serializeToString( t.content ) );
|
|
23
25
|
|
|
@@ -71,17 +73,17 @@ Json2Xml( o, tag )
|
|
|
71
73
|
return "<"+tag+">"+o.map(function(el){ return Json2Xml(el,tag); }).join()+"</"+tag+">";
|
|
72
74
|
}
|
|
73
75
|
noTag && (tag = 'r');
|
|
74
|
-
tag=tag.replace( /[^a-z0-9]/gi,'_' );
|
|
76
|
+
tag=tag.replace( /[^a-z0-9\-]/gi,'_' );
|
|
75
77
|
var oo = {}
|
|
76
78
|
, ret = [ "<"+tag+" "];
|
|
77
|
-
for(
|
|
79
|
+
for( let k in o )
|
|
78
80
|
if( typeof o[k] == "object" )
|
|
79
81
|
oo[k] = o[k];
|
|
80
82
|
else
|
|
81
|
-
ret.push( k.replace( /[^a-z0-9]/gi,'_' ) + '="'+o[k].toString().replace(/&/gi,'&')+'"');
|
|
83
|
+
ret.push( k.replace( /[^a-z0-9\-]/gi,'_' ) + '="'+o[k].toString().replace(/&/gi,'&')+'"');
|
|
82
84
|
if( oo )
|
|
83
85
|
{ ret.push(">");
|
|
84
|
-
for(
|
|
86
|
+
for( let k in oo )
|
|
85
87
|
ret.push( Json2Xml( oo[k], k ) );
|
|
86
88
|
ret.push("</"+tag+">");
|
|
87
89
|
}else
|
|
@@ -92,12 +94,13 @@ Json2Xml( o, tag )
|
|
|
92
94
|
function
|
|
93
95
|
injectSlice( x, s, data )
|
|
94
96
|
{
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
el
|
|
98
|
-
|
|
97
|
+
const isString = typeof data === 'string' ;
|
|
98
|
+
|
|
99
|
+
const el = isString
|
|
100
|
+
? create(s, data)
|
|
101
|
+
: document.adoptNode( xml2dom( Json2Xml( data, s ) ).documentElement);
|
|
99
102
|
[...x.children].filter( e=>e.localName === s ).map( el=>el.remove() );
|
|
100
|
-
x.append(
|
|
103
|
+
x.append(el);
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
export class
|
|
@@ -142,7 +145,7 @@ CustomElement extends HTMLElement
|
|
|
142
145
|
}
|
|
143
146
|
let timeoutID;
|
|
144
147
|
|
|
145
|
-
|
|
148
|
+
this.onSlice = ev=>
|
|
146
149
|
{ ev.stopPropagation?.();
|
|
147
150
|
sliceEvents.push(ev);
|
|
148
151
|
if( !timeoutID )
|
|
@@ -151,7 +154,6 @@ CustomElement extends HTMLElement
|
|
|
151
154
|
timeoutID =0;
|
|
152
155
|
},10);
|
|
153
156
|
};
|
|
154
|
-
this.onSlice = onSlice;
|
|
155
157
|
const transform = ()=>
|
|
156
158
|
{
|
|
157
159
|
const f = p.transformToFragment( x, document );
|
|
Binary file
|
package/demo/http-request.html
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
5
|
<title>http-request Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg" />
|
|
7
|
+
|
|
6
8
|
<script type="module" src="../http-request.js"></script>
|
|
7
9
|
<script type="module" src="../custom-element.js"></script>
|
|
8
10
|
<style>
|
|
@@ -25,6 +27,9 @@
|
|
|
25
27
|
</head>
|
|
26
28
|
<body>
|
|
27
29
|
|
|
30
|
+
<nav>
|
|
31
|
+
<a href=".."><h3><code>custom-element</code> demo</h3></a>
|
|
32
|
+
</nav>
|
|
28
33
|
|
|
29
34
|
<html-demo-element legend="1. http-request simplest"
|
|
30
35
|
description="load the list of pokemons">
|
|
@@ -35,6 +40,8 @@
|
|
|
35
40
|
<http-request
|
|
36
41
|
url="https://pokeapi.co/api/v2/pokemon?limit=6&offset=0"
|
|
37
42
|
slice="page"
|
|
43
|
+
method="GET"
|
|
44
|
+
header-accept="application/json"
|
|
38
45
|
></http-request>
|
|
39
46
|
<xsl:for-each select="//slice/page/data/results/*">
|
|
40
47
|
<xsl:variable name="slides-url"
|
|
@@ -54,6 +61,65 @@
|
|
|
54
61
|
</template>
|
|
55
62
|
</html-demo-element>
|
|
56
63
|
|
|
64
|
+
<html-demo-element legend="1. http-request headers"
|
|
65
|
+
description="request and response headers access demo">
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<custom-element
|
|
69
|
+
tag="headers-demo"
|
|
70
|
+
hidden
|
|
71
|
+
>
|
|
72
|
+
<http-request
|
|
73
|
+
url="https://pokeapi.co/api/v2/pokemon?offset=6&limit=6"
|
|
74
|
+
slice="request_slice"
|
|
75
|
+
type="text"
|
|
76
|
+
mode="cors"
|
|
77
|
+
header-x-test="testing"
|
|
78
|
+
></http-request>
|
|
79
|
+
Content of <code>//slice/request_slice</code> is filled by <b>request</b> and <b>response</b>
|
|
80
|
+
from <code>${url}</code>
|
|
81
|
+
|
|
82
|
+
<h3>Samples</h3>
|
|
83
|
+
<table>
|
|
84
|
+
<tr><th>//slice/request_slice/request/headers/@mode</th>
|
|
85
|
+
<td><xsl:value-of select="//slice/request_slice/request/@mode"/></td></tr>
|
|
86
|
+
<tr><th>//slice/request_slice/response/headers/@content-type</th>
|
|
87
|
+
<td><xsl:value-of select="//slice/request_slice/response/headers/@content-type"/></td></tr>
|
|
88
|
+
<tr><th>//slice/request_slice/response/@status</th>
|
|
89
|
+
<td><xsl:value-of select="//slice/request_slice/response/@status"/></td></tr>
|
|
90
|
+
</table>
|
|
91
|
+
<xsl:for-each select="//slice/request_slice/*">
|
|
92
|
+
<ul data-request-section="{name(.)}">
|
|
93
|
+
<b data-testid="request-section"><xsl:value-of select='name(.)'/></b>
|
|
94
|
+
<xsl:for-each select="@*">
|
|
95
|
+
<div>
|
|
96
|
+
<var data-testid="section-attribute">@<xsl:value-of select='local-name(.)'/></var>
|
|
97
|
+
=
|
|
98
|
+
<code><xsl:value-of select='.'/></code>
|
|
99
|
+
</div>
|
|
100
|
+
</xsl:for-each>
|
|
101
|
+
<xsl:for-each select="*">
|
|
102
|
+
<div>
|
|
103
|
+
<b data-testid="section-deep"><xsl:value-of select='local-name(.)'/></b>
|
|
104
|
+
<ul>
|
|
105
|
+
<xsl:for-each select="@*">
|
|
106
|
+
<li>
|
|
107
|
+
<var data-testid="section-attribute">@<xsl:value-of select='local-name(.)'/></var>
|
|
108
|
+
=
|
|
109
|
+
<code><xsl:value-of select='.'/></code>
|
|
110
|
+
</li>
|
|
111
|
+
</xsl:for-each>
|
|
112
|
+
<code><xsl:value-of select='.'/></code>
|
|
113
|
+
</ul>
|
|
114
|
+
</div>
|
|
115
|
+
</xsl:for-each>
|
|
116
|
+
</ul>
|
|
117
|
+
</xsl:for-each>
|
|
118
|
+
</custom-element>
|
|
119
|
+
<headers-demo></headers-demo>
|
|
120
|
+
</template>
|
|
121
|
+
</html-demo-element>
|
|
122
|
+
|
|
57
123
|
|
|
58
124
|
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
59
125
|
|
package/demo/local-storage.html
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
5
|
<title>custom-element Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg" />
|
|
6
7
|
<script type="module" src="../local-storage.js"></script>
|
|
7
8
|
<script type="module" src="../custom-element.js"></script>
|
|
8
9
|
<style>
|
|
@@ -18,6 +19,9 @@
|
|
|
18
19
|
</head>
|
|
19
20
|
<body>
|
|
20
21
|
|
|
22
|
+
<nav>
|
|
23
|
+
<a href=".."><h3><code>custom-element</code> demo</h3></a>
|
|
24
|
+
</nav>
|
|
21
25
|
|
|
22
26
|
<html-demo-element legend="1. localStorage simplest"
|
|
23
27
|
description="local-storage read only during initial and only render, does not track the changes.">
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:html="http://www.w3.org/1999/xhtml">
|
|
3
|
+
<head>
|
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
|
+
<title>custom-element Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="./wc-square.svg" />
|
|
7
|
+
<script type="module" src="../location-element.js"></script>
|
|
8
|
+
<script type="module" src="../custom-element.js"></script>
|
|
9
|
+
<style>
|
|
10
|
+
@import "./demo.css";
|
|
11
|
+
|
|
12
|
+
button{ background: forestgreen; }
|
|
13
|
+
table{ min-width: 16rem; }
|
|
14
|
+
td{ border-bottom: 1px solid silver; }
|
|
15
|
+
tfoot td{ border-bottom: none; }
|
|
16
|
+
td,th{text-align: right; }
|
|
17
|
+
caption{ padding: 1rem; font-weight: bolder; font-family: sans-serif; }
|
|
18
|
+
</style>
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
<nav>
|
|
22
|
+
<a href=".."><h3><code>custom-element</code> demo</h3></a>
|
|
23
|
+
</nav>
|
|
24
|
+
<html-demo-element legend="Change window URL">
|
|
25
|
+
<template>
|
|
26
|
+
<a href="#dce2">#dce2</a>
|
|
27
|
+
<form >
|
|
28
|
+
<input name="p1" value="abc"/>
|
|
29
|
+
<input name="p2" value="def"/>
|
|
30
|
+
<input type="submit" value="params"/>
|
|
31
|
+
</form>
|
|
32
|
+
<button onclick="history.pushState( {},'', 'location.html?pushstate')"
|
|
33
|
+
>history.pushState</button>
|
|
34
|
+
<button onclick="history.replaceState( {},'', 'location.html?replaceState#dce1')"
|
|
35
|
+
>history.replaceState</button>
|
|
36
|
+
|
|
37
|
+
</template>
|
|
38
|
+
</html-demo-element>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
<html-demo-element legend="2. window.location live update"
|
|
42
|
+
description="In the page beginning change the window URL via link or by history change"
|
|
43
|
+
id="dce2"
|
|
44
|
+
>
|
|
45
|
+
<p>Has to produce URL properties</p>
|
|
46
|
+
<template>
|
|
47
|
+
<custom-element tag="dce-2" hidden>
|
|
48
|
+
<template>
|
|
49
|
+
|
|
50
|
+
<location-element slice="window-url" live></location-element>
|
|
51
|
+
|
|
52
|
+
<html:table>
|
|
53
|
+
<xsl:for-each select="//slice/window-url/@*">
|
|
54
|
+
<html:tr>
|
|
55
|
+
<html:th><xsl:value-of select="name()"/></html:th>
|
|
56
|
+
<html:td><xsl:value-of select="."/></html:td>
|
|
57
|
+
</html:tr>
|
|
58
|
+
</xsl:for-each>
|
|
59
|
+
<html:tr>
|
|
60
|
+
<html:th><u>params</u></html:th>
|
|
61
|
+
<html:th></html:th>
|
|
62
|
+
</html:tr>
|
|
63
|
+
<xsl:for-each select="//slice/window-url/params/*">
|
|
64
|
+
<html:tr>
|
|
65
|
+
<html:th><xsl:value-of select="name()"/></html:th>
|
|
66
|
+
<html:td><xsl:value-of select="."/></html:td>
|
|
67
|
+
</html:tr>
|
|
68
|
+
</xsl:for-each>
|
|
69
|
+
</html:table>
|
|
70
|
+
</template>
|
|
71
|
+
</custom-element>
|
|
72
|
+
<dce-2>?</dce-2>
|
|
73
|
+
</template>
|
|
74
|
+
</html-demo-element>
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
<html-demo-element legend="1. window.location simplest"
|
|
78
|
+
description="location read only during initial and only render, does not track the changes."
|
|
79
|
+
id="dce1">
|
|
80
|
+
<p>Has to produce URL properties</p>
|
|
81
|
+
<template>
|
|
82
|
+
<custom-element tag="dce-1" hidden>
|
|
83
|
+
<template>
|
|
84
|
+
|
|
85
|
+
<location-element slice="window-url"></location-element>
|
|
86
|
+
|
|
87
|
+
<html:table>
|
|
88
|
+
<xsl:for-each select="//slice/window-url/@*">
|
|
89
|
+
<html:tr>
|
|
90
|
+
<html:th><xsl:value-of select="name()"/></html:th>
|
|
91
|
+
<html:td><xsl:value-of select="."/></html:td>
|
|
92
|
+
</html:tr>
|
|
93
|
+
</xsl:for-each>
|
|
94
|
+
<html:tr>
|
|
95
|
+
<html:th><u>params</u></html:th>
|
|
96
|
+
<html:th></html:th>
|
|
97
|
+
</html:tr>
|
|
98
|
+
<xsl:for-each select="//slice/window-url/params/*">
|
|
99
|
+
<html:tr>
|
|
100
|
+
<html:th><xsl:value-of select="name()"/></html:th>
|
|
101
|
+
<html:td><xsl:value-of select="."/></html:td>
|
|
102
|
+
</html:tr>
|
|
103
|
+
</xsl:for-each>
|
|
104
|
+
</html:table>
|
|
105
|
+
</template>
|
|
106
|
+
</custom-element>
|
|
107
|
+
<dce-1>?</dce-1>
|
|
108
|
+
</template>
|
|
109
|
+
</html-demo-element>
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
<html-demo-element legend="3. External URL as SRC attribute"
|
|
113
|
+
description="url parsed and populated into slice."
|
|
114
|
+
id="dce3">
|
|
115
|
+
<p>Has to produce URL properties</p>
|
|
116
|
+
<template>
|
|
117
|
+
<custom-element tag="dce-3" hidden>
|
|
118
|
+
<template>
|
|
119
|
+
|
|
120
|
+
<location-element slice="src-url" src="https://my.example?a=1&b=2#3"></location-element>
|
|
121
|
+
|
|
122
|
+
<html:table>
|
|
123
|
+
<xsl:for-each select="//slice/src-url/@*">
|
|
124
|
+
<html:tr>
|
|
125
|
+
<html:th><xsl:value-of select="name()"/></html:th>
|
|
126
|
+
<html:td><xsl:value-of select="."/></html:td>
|
|
127
|
+
</html:tr>
|
|
128
|
+
</xsl:for-each>
|
|
129
|
+
<html:tr>
|
|
130
|
+
<html:th><u>params</u></html:th>
|
|
131
|
+
<html:th></html:th>
|
|
132
|
+
</html:tr>
|
|
133
|
+
<xsl:for-each select="//slice/src-url/params/*">
|
|
134
|
+
<html:tr>
|
|
135
|
+
<html:th><xsl:value-of select="name()"/></html:th>
|
|
136
|
+
<html:td><xsl:value-of select="."/></html:td>
|
|
137
|
+
</html:tr>
|
|
138
|
+
</xsl:for-each>
|
|
139
|
+
</html:table>
|
|
140
|
+
</template>
|
|
141
|
+
</custom-element>
|
|
142
|
+
<dce-3>?</dce-3>
|
|
143
|
+
</template>
|
|
144
|
+
</html-demo-element>
|
|
145
|
+
|
|
146
|
+
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
|
|
147
|
+
|
|
148
|
+
</body>
|
|
149
|
+
</html>
|
package/demo/logo.png
ADDED
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?><svg id="Artwork" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 216 209.18"><defs><style>.cls-1{fill:#c2e6f1;}.cls-2{fill:#dcf1f7;}.cls-3{fill:#2d4554;}.cls-4{fill:#60cae5;}</style></defs><polygon class="cls-3" 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"/><path class="cls-2" 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"/><path class="cls-2" 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"/><path class="cls-1" 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"/><path class="cls-2" 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"/><path class="cls-2" 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"/><path class="cls-2" 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"/><path class="cls-2" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-4" 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"/><path class="cls-2" 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"/><path class="cls-1" 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"/><path class="cls-1" 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"/><path class="cls-2" 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"/><path class="cls-1" 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"/><path class="cls-1" 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"/></svg>
|
package/http-request.js
CHANGED
|
@@ -6,6 +6,16 @@ export class HttpRequestElement extends HTMLElement
|
|
|
6
6
|
constructor() {
|
|
7
7
|
super();
|
|
8
8
|
}
|
|
9
|
+
get requestHeaders()
|
|
10
|
+
{ const ret = {};
|
|
11
|
+
[...this.attributes].filter(a=>a.name.startsWith('header-')).map( a => ret[a.name.substring(7)] = a.value );
|
|
12
|
+
return ret;
|
|
13
|
+
}
|
|
14
|
+
get requestProps()
|
|
15
|
+
{ const ret = {};
|
|
16
|
+
[...this.attributes].filter(a=>!a.name.startsWith('header-')).map( a => ret[a.name] = a.value );
|
|
17
|
+
return ret;
|
|
18
|
+
}
|
|
9
19
|
sliceInit( s )
|
|
10
20
|
{ if( !s )
|
|
11
21
|
s = {};
|
|
@@ -18,7 +28,7 @@ export class HttpRequestElement extends HTMLElement
|
|
|
18
28
|
controller.abort();
|
|
19
29
|
};
|
|
20
30
|
const url = attr(this, 'url') || ''
|
|
21
|
-
, request = {
|
|
31
|
+
, request = { ...this.requestProps, headers: this.requestHeaders }
|
|
22
32
|
, slice = { detail: { request }, target: this }
|
|
23
33
|
, updateSlice = slice =>
|
|
24
34
|
{ for( let parent = s.element.parentElement; parent; parent = parent.parentElement )
|
|
@@ -30,9 +40,14 @@ export class HttpRequestElement extends HTMLElement
|
|
|
30
40
|
|
|
31
41
|
setTimeout( async ()=>
|
|
32
42
|
{ updateSlice( slice );
|
|
33
|
-
|
|
43
|
+
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])
|
|
47
|
+
|
|
48
|
+
slice.detail.response = r;
|
|
34
49
|
updateSlice( slice );
|
|
35
|
-
slice.detail.data = await
|
|
50
|
+
slice.detail.data = await response.json();
|
|
36
51
|
updateSlice( slice );
|
|
37
52
|
},0 );
|
|
38
53
|
|
|
@@ -41,4 +56,4 @@ export class HttpRequestElement extends HTMLElement
|
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
window.customElements.define( 'http-request', HttpRequestElement );
|
|
44
|
-
export default HttpRequestElement;
|
|
59
|
+
export default HttpRequestElement;
|
package/index.html
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
|
5
5
|
<title>custom-element Declarative Custom Element implementation demo</title>
|
|
6
|
+
<link rel="icon" href="demo/wc-square.svg" />
|
|
6
7
|
<script type="module" src="custom-element.js"></script>
|
|
7
8
|
<style>
|
|
8
9
|
@import "demo/demo.css";
|
|
@@ -26,7 +27,8 @@
|
|
|
26
27
|
<section>
|
|
27
28
|
<b>Data layer demo</b>
|
|
28
29
|
<a href="./demo/local-storage.html">local-storage</a> |
|
|
29
|
-
<a href="./demo/http-request.html">http-request</a>
|
|
30
|
+
<a href="./demo/http-request.html">http-request</a> |
|
|
31
|
+
<a href="./demo/location-element.html">location-element</a>
|
|
30
32
|
</section>
|
|
31
33
|
</nav>
|
|
32
34
|
<html-demo-element legend="1. simple payload"
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const attr = (el, attr)=> el.getAttribute(attr);
|
|
2
|
+
|
|
3
|
+
export class LocationElement extends HTMLElement
|
|
4
|
+
{
|
|
5
|
+
// @attribute live - monitors localStorage change
|
|
6
|
+
// @attribute src - URL to be parsed, defaults to `window.location`
|
|
7
|
+
|
|
8
|
+
constructor()
|
|
9
|
+
{
|
|
10
|
+
super();
|
|
11
|
+
const state = {}
|
|
12
|
+
, listener = e=> propagateSlice(e)
|
|
13
|
+
, propagateSlice = (e)=>
|
|
14
|
+
{ const urlStr = attr(this,'src')
|
|
15
|
+
const url = urlStr? new URL(urlStr) : window.location
|
|
16
|
+
|
|
17
|
+
const params= {}
|
|
18
|
+
const search = new URLSearchParams(url.search);
|
|
19
|
+
for (const key of search.keys())
|
|
20
|
+
params[key] = search.getAll(key)
|
|
21
|
+
|
|
22
|
+
const detail = {params}
|
|
23
|
+
for( const k in url )
|
|
24
|
+
{ if ('string' === typeof url[k])
|
|
25
|
+
detail[k] = url[k]
|
|
26
|
+
}
|
|
27
|
+
for( let parent = this.parentElement; parent; parent = parent.parentElement)
|
|
28
|
+
{ if (parent.onSlice)
|
|
29
|
+
return parent.onSlice(
|
|
30
|
+
{ detail
|
|
31
|
+
, target: this
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
console.error(`${this.localName} used outside of custom-element`)
|
|
35
|
+
debugger;
|
|
36
|
+
};
|
|
37
|
+
this.sliceInit = s =>
|
|
38
|
+
{
|
|
39
|
+
if( !state.listener && this.hasAttribute('live') )
|
|
40
|
+
{ state.listener = 1;
|
|
41
|
+
window.addEventListener( 'popstate', listener );
|
|
42
|
+
window.addEventListener( 'hashchange', listener );
|
|
43
|
+
}
|
|
44
|
+
propagateSlice();
|
|
45
|
+
return s || {}
|
|
46
|
+
}
|
|
47
|
+
this._destroy = ()=>
|
|
48
|
+
{
|
|
49
|
+
if( !state.listener )
|
|
50
|
+
return;
|
|
51
|
+
if(state.listener)
|
|
52
|
+
{ window.removeEventListener('popstate', listener);
|
|
53
|
+
window.removeEventListener('hashchange', listener);
|
|
54
|
+
}
|
|
55
|
+
delete state.listener;
|
|
56
|
+
};
|
|
57
|
+
this.sliceInit()
|
|
58
|
+
}
|
|
59
|
+
disconnectedCallback(){ this._destroy(); }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
window.customElements.define( 'location-element', LocationElement );
|
|
63
|
+
export default LocationElement;
|
package/package.json
CHANGED