@epa-wg/custom-element 0.0.16 → 0.0.18
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 +32 -17
- package/bin/xslDtd2Ide.mjs +160 -0
- package/custom-element.d.ts +31 -0
- package/custom-element.js +38 -5
- package/demo/a.html +6 -11
- package/demo/hex-grid-dce.html +13 -13
- package/demo/http-request.html +13 -13
- package/demo/local-storage.html +2 -2
- package/demo/location-element.html +12 -12
- package/demo/parameters.html +4 -4
- package/demo/s.xslt +4 -6
- package/demo/z.html +3 -5
- package/ide/IDE.md +31 -0
- package/ide/customData-dce.json +89 -0
- package/ide/customData-xsl.json +1018 -0
- package/ide/web-types-dce.json +98 -0
- package/ide/web-types-xsl.json +867 -0
- package/index.html +5 -4
- package/package.json +6 -3
- package/request.html +2 -2
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"html.customData": [
|
|
3
|
+
"./ide/customData-dce.json",
|
|
4
|
+
"./ide/customData-xsl.json"
|
|
5
|
+
],
|
|
6
|
+
"terminal.integrated.profiles.windows": {
|
|
7
|
+
|
|
8
|
+
"PowerShell": {
|
|
9
|
+
"source": "PowerShell",
|
|
10
|
+
"icon": "terminal-powershell"
|
|
11
|
+
},
|
|
12
|
+
"Command Prompt": {
|
|
13
|
+
"path": [
|
|
14
|
+
"${env:windir}\\Sysnative\\cmd.exe",
|
|
15
|
+
"${env:windir}\\System32\\cmd.exe"
|
|
16
|
+
],
|
|
17
|
+
"args": [],
|
|
18
|
+
"icon": "terminal-cmd"
|
|
19
|
+
},
|
|
20
|
+
"Git Bash": {
|
|
21
|
+
"source": "Git Bash"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"terminal.integrated.defaultProfile.windows": "Git Bash"
|
|
25
|
+
}
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# custom-element
|
|
2
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
|
-
discussion. The functionality of DCE and its data access does not require programming using JavaScript.
|
|
4
|
+
discussion. **NO-JS** 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].
|
|
@@ -45,6 +45,8 @@ This project is a POC( Proof of Concept ) targeting to become a base for native
|
|
|
45
45
|
</details>
|
|
46
46
|
|
|
47
47
|
# use
|
|
48
|
+
|
|
49
|
+
Use the [bootstrap project](https://github.com/EPA-WG/custom-element-bootstrap) with all pre-configured or
|
|
48
50
|
## install
|
|
49
51
|
use via CDN
|
|
50
52
|
```html
|
|
@@ -56,17 +58,21 @@ npm i -P @epa-wg/custom-element
|
|
|
56
58
|
yarn add @epa-wg/custom-element
|
|
57
59
|
```
|
|
58
60
|
|
|
61
|
+
## [enable IDE support](ide/IDE.md)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
59
65
|
## [Live demo 🔗][demo-url]
|
|
60
66
|
```html
|
|
61
67
|
<custom-element tag="pokemon-tile" hidden>
|
|
62
68
|
<h3>{title}</h3> <!-- title is an attribute in instance
|
|
63
69
|
mapped into /*/attributes/title -->
|
|
64
|
-
<
|
|
70
|
+
<if test="//smile"> <!-- data-smile DCE instance attribute,
|
|
65
71
|
mapped into /*/dataset/smile
|
|
66
72
|
used in condition -->
|
|
67
73
|
<!-- data-smile DCE instance attribute, used as HTML -->
|
|
68
74
|
<div>Smile as: {//smile} </div>
|
|
69
|
-
</
|
|
75
|
+
</if>
|
|
70
76
|
<!-- image would not be visible in sandbox, see live demo -->
|
|
71
77
|
<img src="https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world/{pokemon-id}.svg"
|
|
72
78
|
alt="{title} image"/>
|
|
@@ -133,10 +139,19 @@ constructor creates XML with
|
|
|
133
139
|
|
|
134
140
|
DOM content is replaced with results of instance XML transformation by declaration XSLT.
|
|
135
141
|
|
|
142
|
+
# `tag` attribute
|
|
143
|
+
allows to define the Custom Element tag registered by `window.customElements.define()`.
|
|
144
|
+
|
|
145
|
+
If omitted, the tag is auto-generated and the content is rendered inline.
|
|
146
|
+
```html
|
|
147
|
+
<custom-element> my tag is {tag} </custom-element>
|
|
148
|
+
```
|
|
149
|
+
See [demo](https://unpkg.com/@epa-wg/custom-element@0.0/demo/external-template.html) for `tag` attribute use.
|
|
150
|
+
|
|
136
151
|
# `src` attribute
|
|
137
152
|
allows to refer either external template or template within external library by `#id` hash in URL.
|
|
138
153
|
|
|
139
|
-
See [demo](demo/external-template.html) with various samples.
|
|
154
|
+
See [demo](https://unpkg.com/@epa-wg/custom-element@0.0/demo/external-template.html) with various samples.
|
|
140
155
|
|
|
141
156
|
## types of template
|
|
142
157
|
* HTML with DCE syntax ( slots, data slices, xslt operators, etc. )
|
|
@@ -196,12 +211,12 @@ In same way as in DCE itself:
|
|
|
196
211
|
</dce-2>
|
|
197
212
|
```
|
|
198
213
|
## Attributes
|
|
199
|
-
To be served by IDE and to track the attributes changes, they have to be declared via `
|
|
214
|
+
To be served by IDE and to track the attributes changes, they have to be declared via `attribute`:
|
|
200
215
|
```html
|
|
201
216
|
<custom-element tag="dce-with-attrs" hidden>
|
|
202
|
-
<
|
|
203
|
-
<
|
|
204
|
-
<
|
|
217
|
+
<attribute name="p1" >default_P1 </attribute>
|
|
218
|
+
<attribute name="p2" select="'always_p2'" ></attribute>
|
|
219
|
+
<attribute name="p3" select="//p3 ?? 'def_P3' " ></attribute>
|
|
205
220
|
p1: {$p1} <br/> p2: {$p2} <br/> p3: {$p3}
|
|
206
221
|
</custom-element>
|
|
207
222
|
<dce-with-attrs p1="123" p3="qwe"></dce-with-attrs>
|
|
@@ -220,7 +235,7 @@ i.e. slot `xxx` is matching `<i slot="xxx">...</i>` in payload.
|
|
|
220
235
|
<custom-element tag="with-description" >
|
|
221
236
|
<slot name="description">description is not available</slot>
|
|
222
237
|
<!-- same as
|
|
223
|
-
<
|
|
238
|
+
<value-of select='/*/payload/*[@slot="description"]'/>
|
|
224
239
|
-->
|
|
225
240
|
</custom-element>
|
|
226
241
|
<with-description>
|
|
@@ -229,12 +244,12 @@ i.e. slot `xxx` is matching `<i slot="xxx">...</i>` in payload.
|
|
|
229
244
|
```
|
|
230
245
|
|
|
231
246
|
## loops, variables
|
|
232
|
-
Loop implemented via [
|
|
247
|
+
Loop implemented via [for-each](https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each)
|
|
233
248
|
|
|
234
249
|
[Variables in XSLT](https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/variable)
|
|
235
250
|
|
|
236
251
|
## [XPath](https://developer.mozilla.org/en-US/docs/Web/XSLT/Transforming_XML_with_XSLT/The_Netscape_XSLT_XPath_Reference)
|
|
237
|
-
is available in `{}` in attributes, in `
|
|
252
|
+
is available in `{}` in attributes, in `for-each`, `if`, `value-of`, and other XSL tags.
|
|
238
253
|
|
|
239
254
|
XPath is a selector language to navigate over custom element instance data, attributes, and payload.
|
|
240
255
|
|
|
@@ -253,12 +268,12 @@ in template. In such cases the `xhtml:` prefix in front of troubled tag would so
|
|
|
253
268
|
<local-storage key="basket" slice="basket" live type="json"></local-storage>
|
|
254
269
|
<xhtml:table xmlns:xhtml="http://www.w3.org/1999/xhtml" >
|
|
255
270
|
<xhtml:tbody>
|
|
256
|
-
<
|
|
271
|
+
<for-each select="//basket/@*">
|
|
257
272
|
<xhtml:tr>
|
|
258
273
|
<xhtml:th> {name()} </xhtml:th>
|
|
259
274
|
<xhtml:td> {.} </xhtml:td>
|
|
260
275
|
</xhtml:tr>
|
|
261
|
-
</
|
|
276
|
+
</for-each>
|
|
262
277
|
</xhtml:tbody>
|
|
263
278
|
<xhtml:tfoot>
|
|
264
279
|
<xhtml:tr>
|
|
@@ -293,7 +308,7 @@ run transformation under debugger.
|
|
|
293
308
|
* try to add as attribute you could observe and put the value of node name or text to identify the current location in data
|
|
294
309
|
within template
|
|
295
310
|
```xml
|
|
296
|
-
<b title="{name(*)} : {text()}">xml tag name: <
|
|
311
|
+
<b title="{name(*)} : {text()}">xml tag name: <value-of select='name()'/></b>
|
|
297
312
|
```
|
|
298
313
|
|
|
299
314
|
[git-url]: https://github.com/EPA-WG/custom-element
|
|
@@ -308,9 +323,9 @@ within template
|
|
|
308
323
|
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
|
|
309
324
|
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
|
|
310
325
|
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element
|
|
311
|
-
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
312
|
-
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
313
|
-
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.
|
|
326
|
+
[coverage-image]: https://unpkg.com/@epa-wg/custom-element-test@0.0.18/coverage/coverage.svg
|
|
327
|
+
[coverage-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.18/coverage/lcov-report/index.html
|
|
328
|
+
[storybook-url]: https://unpkg.com/@epa-wg/custom-element-test@0.0.18/storybook-static/index.html?path=/story/welcome--introduction
|
|
314
329
|
[sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
|
|
315
330
|
[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
|
|
316
331
|
[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* node xslDtd2Ide.cjs
|
|
3
|
+
* would get xsl 1.0 schema and populate IntelliJ and VS Code IDE custom elements definitions
|
|
4
|
+
*
|
|
5
|
+
* This is one time use script as XSLT 1.0 schema is not changing.
|
|
6
|
+
* DTD parsing here is not generic and cobers only particula XSLT 1.0 schema.
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const dtdText = await fetch( 'https://www.w3.org/1999/11/xslt10.dtd' )
|
|
12
|
+
.then( ( response ) => response.text() )
|
|
13
|
+
.then( ( body ) =>
|
|
14
|
+
{
|
|
15
|
+
return body;
|
|
16
|
+
} );
|
|
17
|
+
const matches = dtdText.match( /<([^>]*)>/g );
|
|
18
|
+
|
|
19
|
+
const chopOff = ( s, begin = 1, end = 1 ) => s.substring( begin, s.length - end );
|
|
20
|
+
const trim = s => s?.trim ? s.trim() : s;
|
|
21
|
+
|
|
22
|
+
let lastComment = ''
|
|
23
|
+
const dtdObj = { ENTITY: {}, ELEMENT: {} }
|
|
24
|
+
for( const match of matches ){
|
|
25
|
+
if( match.startsWith( '<!--' ) ) {
|
|
26
|
+
lastComment = match;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const body = chopOff( match, 2 );
|
|
30
|
+
const arr = body.split( /\s/ );
|
|
31
|
+
const name = arr[ 1 ].trim();
|
|
32
|
+
const resolveRef = s => s ? ( s.startsWith ? ( s.startsWith( '%' ) ? dtdObj.ENTITY[ chopOff( s, 1, 0 ).replace( ';',
|
|
33
|
+
'' ) ] : s ) : s ) : s;
|
|
34
|
+
const attrObj = a =>
|
|
35
|
+
{
|
|
36
|
+
if( !a || Array.isArray( a ) || !a.trim )
|
|
37
|
+
return a;
|
|
38
|
+
const as = a.trim();
|
|
39
|
+
if( 'CDATA,#PCDATA,NMTOKEN,NMTOKENS,'.includes( as + ',' ) )
|
|
40
|
+
return as;
|
|
41
|
+
const ar = as.split( ';' )
|
|
42
|
+
const aa = ar[ 0 ].split( ' ' );
|
|
43
|
+
// if( aa[0].includes('select')){debugger;}
|
|
44
|
+
return { name: aa[ 0 ], type: resolveRef( aa[ 1 ] ), defValue: aa[ 1 ], required: (ar[1] || aa[ 2 ])?.trim() }
|
|
45
|
+
};
|
|
46
|
+
switch( arr[ 0 ] ){
|
|
47
|
+
case 'ENTITY':{
|
|
48
|
+
let key = arr[ 2 ];
|
|
49
|
+
let val = body.substring( body.indexOf( key ) + key.length ).trim();
|
|
50
|
+
let ss;
|
|
51
|
+
if( val.startsWith( '"' ) || val.startsWith( "'" ) ) {
|
|
52
|
+
val = chopOff( val );
|
|
53
|
+
if( val.includes( '(#PCDATA' ) ) {
|
|
54
|
+
val = val.replace( '(#PCDATA', '' ).replace( ')*', '' ).trim();
|
|
55
|
+
ss = [ '#PCDATA', ...val.split( '\n' ).map( s => s.trim() ).map( resolveRef ).flat() ];
|
|
56
|
+
} else
|
|
57
|
+
ss = val.split( /[\n]/ ).map( s => s.replace( '|', '' ).trim() ).filter( s => s );
|
|
58
|
+
} else
|
|
59
|
+
ss = val.split( /[|\n]/ );
|
|
60
|
+
|
|
61
|
+
const v = ss.map( trim ).filter( s => s ).map( resolveRef ).map( attrObj ).flat().filter( s => s );
|
|
62
|
+
dtdObj.ENTITY[ key ] = !v.length ? '' : v.length === 1 ? v[ 0 ] : v;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case 'ELEMENT':
|
|
66
|
+
dtdObj.ELEMENT[ name ] = { values: arr[ 2 ], attributes: [] };
|
|
67
|
+
break;
|
|
68
|
+
case 'ATTLIST':{
|
|
69
|
+
const attrStr = body.split( name )[ 1 ].trim();
|
|
70
|
+
const attrs = attrStr.split( '\n' ).map( s => s.trim() );
|
|
71
|
+
const elementAttrs = dtdObj.ELEMENT[ name ].attributes;
|
|
72
|
+
for( let a of attrs ){
|
|
73
|
+
if( a.startsWith( '%' ) ) {
|
|
74
|
+
const v = dtdObj.ENTITY[ chopOff( a.split( ';' )[ 0 ], 1, 0 ) ];
|
|
75
|
+
if( !v ) {
|
|
76
|
+
debugger;
|
|
77
|
+
}
|
|
78
|
+
Array.isArray( v )
|
|
79
|
+
? elementAttrs.push( ...v )
|
|
80
|
+
: elementAttrs.push( v );
|
|
81
|
+
} else
|
|
82
|
+
elementAttrs.push( attrObj( a ) );
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// replace the tags list in custom-element.js
|
|
91
|
+
|
|
92
|
+
const tagsCsv = Object.keys( dtdObj.ELEMENT ).map( s => s.replace( 'xsl:', '' ) ).join( ',' );
|
|
93
|
+
const jsText = readFileSync( '../custom-element.js', 'utf8' )
|
|
94
|
+
const updatedJs = jsText.replace( /^.*export const xslTags = .*$/mg,
|
|
95
|
+
`export const xslTags = '${ tagsCsv }'.split(',');` );
|
|
96
|
+
writeFileSync( '../custom-element.js', updatedJs );
|
|
97
|
+
|
|
98
|
+
const vsCode = {
|
|
99
|
+
"version": 1.1, tags: Object.keys( dtdObj.ELEMENT ).map( s => (
|
|
100
|
+
{ name : s.replace( 'xsl:', '' )
|
|
101
|
+
, description : `${ s }`
|
|
102
|
+
, attributes : dtdObj.ELEMENT[ s ].attributes.map( a => (
|
|
103
|
+
{ name : a.name
|
|
104
|
+
, description: `${ JSON.stringify( a ) }`
|
|
105
|
+
, type : "string"
|
|
106
|
+
, required : a.required === '#REQUIRED'
|
|
107
|
+
} ) )
|
|
108
|
+
, references : [ { name: "MDN docs"
|
|
109
|
+
, url : `https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/${s.replace( 'xsl:', '' )}`
|
|
110
|
+
}]
|
|
111
|
+
} ) )
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
writeFileSync( '.././ide/customData-xsl.json', JSON.stringify( vsCode, undefined, 4 ) );
|
|
115
|
+
|
|
116
|
+
const intelliJ = {
|
|
117
|
+
"$schema": "http://json.schemastore.org/web-types",
|
|
118
|
+
"name": "@epa-wg/custom-element",
|
|
119
|
+
"version": "0.0.18",
|
|
120
|
+
"js-types-syntax": "typescript",
|
|
121
|
+
"description-markup": "markdown",
|
|
122
|
+
"contributions": {
|
|
123
|
+
"html": {
|
|
124
|
+
"elements": [
|
|
125
|
+
...Object.keys( dtdObj.ELEMENT ).map( s => (
|
|
126
|
+
{ name : s.replace( 'xsl:', '' )
|
|
127
|
+
, description : `${ s }`
|
|
128
|
+
, attributes : dtdObj.ELEMENT[ s ].attributes.map( a => (
|
|
129
|
+
{ name : a.name
|
|
130
|
+
, description : `${ JSON.stringify( a ) }`
|
|
131
|
+
, type : "string"
|
|
132
|
+
, required : a.required === '#REQUIRED'
|
|
133
|
+
} ) )
|
|
134
|
+
, 'doc-url' : `https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/${s.replace( 'xsl:', '' )}`
|
|
135
|
+
} ) ),
|
|
136
|
+
{
|
|
137
|
+
"name": "for-each",
|
|
138
|
+
"description": "The <xsl:for-each> element selects a set of nodes and processes each of them in the same way. It is often used to iterate through a set of nodes or to change the current node. If one or more <xsl:sort> elements appear as the children of this element, sorting occurs before processing. Otherwise, nodes are processed in document order.",
|
|
139
|
+
"doc-url": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each",
|
|
140
|
+
"attributes": [
|
|
141
|
+
{
|
|
142
|
+
"name": "select",
|
|
143
|
+
"description": "Uses an XPath expression to select nodes to be processed.",
|
|
144
|
+
"required": true,
|
|
145
|
+
"doc-url": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each#select",
|
|
146
|
+
"value": {
|
|
147
|
+
"type": "string"
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
writeFileSync( '.././ide/web-types-xsl.json', JSON.stringify( intelliJ, undefined, 4 ) );
|
|
159
|
+
|
|
160
|
+
|
package/custom-element.d.ts
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
export function log(x: any): void;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @summary Declarative Custom Element as W3C proposal PoC with native(XSLT) based templating
|
|
5
|
+
* ```html
|
|
6
|
+
* <custom-element tag="my-element">
|
|
7
|
+
* <template>
|
|
8
|
+
* <attribute name="p1" >default_P1</attribute>
|
|
9
|
+
* <style>
|
|
10
|
+
* color:green;
|
|
11
|
+
* b{ color: blue;}
|
|
12
|
+
* input:checked+b{ color: darkblue; text-shadow: 0 0 4px springgreen;}
|
|
13
|
+
* </style>
|
|
14
|
+
* <label>
|
|
15
|
+
* green
|
|
16
|
+
* <input type="checkbox" value="Glowing Blue" checked/><b>blue</b>
|
|
17
|
+
* </label>
|
|
18
|
+
* p1:{$p1}
|
|
19
|
+
* </template>
|
|
20
|
+
* </custom-element>
|
|
21
|
+
* <my-element p1="abc"></my-element>
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @extends HTMLElement
|
|
25
|
+
* @tag custom-element
|
|
26
|
+
* @tag-name custom-element
|
|
27
|
+
* @attr {boolean} hidden - hides DCE definition to prevent visual appearance of content. Wrap the payload into template tag to prevent applying the inline CSS in global scope.
|
|
28
|
+
* @attr {string} tag - HTML tag for Custom Element. Used for window.customElements.define(). If not set, would be generated and DCE instance rendered inline.
|
|
29
|
+
* @attr {string} src - full, relative, or hash URL to DCE template.
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
2
32
|
export class CustomElement extends HTMLElement {
|
|
33
|
+
static observedAttributes : string[];
|
|
3
34
|
}
|
|
4
35
|
export default CustomElement;
|
package/custom-element.js
CHANGED
|
@@ -12,7 +12,15 @@ const attr = (el, attr)=> el.getAttribute?.(attr)
|
|
|
12
12
|
, emptyNode = n=> { while(n.firstChild) n.firstChild.remove(); return n; }
|
|
13
13
|
, createNS = ( ns, tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElementNS( ns, tag ))
|
|
14
14
|
, xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
|
|
15
|
-
, xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) )
|
|
15
|
+
, xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) )
|
|
16
|
+
, cloneAs = (p,tag) =>
|
|
17
|
+
{ const px = p.ownerDocument.createElementNS(p.namespaceURI,tag);
|
|
18
|
+
for( let a of p.attributes)
|
|
19
|
+
px.setAttribute(a.name, a.value);
|
|
20
|
+
while( p.firstChild )
|
|
21
|
+
px.append(p.firstChild);
|
|
22
|
+
return px;
|
|
23
|
+
}
|
|
16
24
|
|
|
17
25
|
function
|
|
18
26
|
ASSERT(x)
|
|
@@ -141,6 +149,8 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
|
|
|
141
149
|
, tc = (n =>
|
|
142
150
|
{
|
|
143
151
|
forEach$(n,'script', s=> s.remove() );
|
|
152
|
+
const xslRoot = n.content ?? n.firstElementChild?.content ?? n.body ?? n;
|
|
153
|
+
xslTags.forEach( tag => forEach$( xslRoot, tag, el=>toXsl(el,xslRoot) ) );
|
|
144
154
|
const e = n.firstElementChild?.content || n.content
|
|
145
155
|
, asXmlNode = r => {
|
|
146
156
|
const d = xml2dom( '<xhtml/>' )
|
|
@@ -202,14 +212,15 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
|
|
|
202
212
|
if( !fr )
|
|
203
213
|
return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
|
|
204
214
|
const params = [];
|
|
205
|
-
[...fr.querySelectorAll('dce-root>
|
|
206
|
-
{
|
|
215
|
+
[...fr.querySelectorAll('dce-root>attribute')].forEach(p=>
|
|
216
|
+
{ p = cloneAs(p,'xsl:param');
|
|
217
|
+
payload.append(p);
|
|
207
218
|
let select = attr(p,'select')?.split('??')
|
|
208
219
|
if( !select)
|
|
209
220
|
{ select = ['//'+attr(p, 'name'), `'${p.textContent}'`];
|
|
210
221
|
emptyNode(p);
|
|
211
222
|
}
|
|
212
|
-
if( select?.length>1){
|
|
223
|
+
if( select?.length>1 ){
|
|
213
224
|
p.removeAttribute('select');
|
|
214
225
|
const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
|
|
215
226
|
c.firstElementChild.setAttribute('test',select[0]);
|
|
@@ -383,9 +394,30 @@ export function assureUID(n,attr)
|
|
|
383
394
|
n.setAttribute(attr, crypto.randomUUID());
|
|
384
395
|
return n.getAttribute(attr)
|
|
385
396
|
}
|
|
397
|
+
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(',');
|
|
398
|
+
export const toXsl = (el, defParent) => {
|
|
399
|
+
const x = create('xsl:'+el.localName);
|
|
400
|
+
for( let a of el.attributes )
|
|
401
|
+
x.setAttribute( a.name, a.value );
|
|
402
|
+
while(el.firstChild)
|
|
403
|
+
x.append(el.firstChild);
|
|
404
|
+
if( el.parentElement )
|
|
405
|
+
el.parentElement.replaceChild( x, el );
|
|
406
|
+
else
|
|
407
|
+
{ const p = (el.parentElement || defParent)
|
|
408
|
+
, arr = [...p.childNodes];
|
|
409
|
+
arr.forEach((n, i) => {
|
|
410
|
+
if (n === el)
|
|
411
|
+
arr[i] = x;
|
|
412
|
+
});
|
|
413
|
+
p.replaceChildren(...arr);
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
|
|
386
417
|
export class
|
|
387
418
|
CustomElement extends HTMLElement
|
|
388
419
|
{
|
|
420
|
+
static observedAttributes = ['src','tag','hidden'];
|
|
389
421
|
async connectedCallback()
|
|
390
422
|
{
|
|
391
423
|
const templateRoots = await loadTemplateRoots( attr( this, 'src' ), this )
|
|
@@ -521,10 +553,11 @@ CustomElement extends HTMLElement
|
|
|
521
553
|
window.customElements.define( tag, DceElement);
|
|
522
554
|
else
|
|
523
555
|
{ const t = tagName;
|
|
556
|
+
this.setAttribute('tag', t );
|
|
524
557
|
window.customElements.define( t, DceElement);
|
|
525
558
|
const el = document.createElement(t);
|
|
526
559
|
this.getAttributeNames().forEach(a=>el.setAttribute(a,this.getAttribute(a)));
|
|
527
|
-
el.append(...[...this.childNodes].filter(e=>e.localName!=='style'))
|
|
560
|
+
el.append(...[...this.childNodes].filter( e => e.localName!=='style') );
|
|
528
561
|
this.append(el);
|
|
529
562
|
}
|
|
530
563
|
}
|
package/demo/a.html
CHANGED
|
@@ -21,18 +21,13 @@
|
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
|
|
24
|
-
<custom-element >
|
|
25
|
-
<
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<html:th> {name()} </html:th>
|
|
30
|
-
<html:td> {.} </html:td>
|
|
31
|
-
</html:tr>
|
|
32
|
-
</xsl:for-each>
|
|
33
|
-
</html:table>
|
|
34
|
-
count:<xsl:value-of select="count(//slice/basket/@*)"/>
|
|
24
|
+
<custom-element tag="dce-link" hidden>
|
|
25
|
+
<param name="p1" >default_P1 </param>
|
|
26
|
+
<param name="p2" select="'always_p2'" ></param>
|
|
27
|
+
<param name="p3" select="//p3 ?? 'def_P3' " ></param>
|
|
28
|
+
p1:{$p1} <br/> p2: {$p2} <br/> p3: {$p3}
|
|
35
29
|
</custom-element>
|
|
30
|
+
<dce-link id="dce1" ></dce-link>
|
|
36
31
|
|
|
37
32
|
</body>
|
|
38
33
|
</html>
|
package/demo/hex-grid-dce.html
CHANGED
|
@@ -69,20 +69,20 @@
|
|
|
69
69
|
}
|
|
70
70
|
</style>
|
|
71
71
|
<nav>
|
|
72
|
-
<
|
|
73
|
-
<
|
|
74
|
-
<
|
|
75
|
-
</
|
|
72
|
+
<for-each select="/datadom/payload/xhtml:*">
|
|
73
|
+
<if test="local-name(.) = 'style'">
|
|
74
|
+
<copy-of select="." />
|
|
75
|
+
</if>
|
|
76
76
|
<!-- sanitize blank spans -->
|
|
77
|
-
<
|
|
77
|
+
<if test="local-name(.) != 'style' and (local-name(.) != 'span' or normalize-space(.) != '')">
|
|
78
78
|
<section>
|
|
79
79
|
<button class="action">
|
|
80
80
|
{@alt}
|
|
81
|
-
<
|
|
81
|
+
<copy-of select="."/>
|
|
82
82
|
</button>
|
|
83
83
|
</section>
|
|
84
|
-
</
|
|
85
|
-
</
|
|
84
|
+
</if>
|
|
85
|
+
</for-each>
|
|
86
86
|
</nav>
|
|
87
87
|
</template>
|
|
88
88
|
</custom-element>
|
|
@@ -152,14 +152,14 @@
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
</style>
|
|
155
|
-
<
|
|
155
|
+
<for-each select="/datadom/payload/xhtml:*">
|
|
156
156
|
<!-- sanitize blank spans -->
|
|
157
|
-
<
|
|
157
|
+
<if test="local-name(.) != 'span' or normalize-space(.) != ''">
|
|
158
158
|
<hex-grid>
|
|
159
|
-
<
|
|
159
|
+
<copy-of select="."/>
|
|
160
160
|
</hex-grid>
|
|
161
|
-
</
|
|
162
|
-
</
|
|
161
|
+
</if>
|
|
162
|
+
</for-each>
|
|
163
163
|
</template>
|
|
164
164
|
</custom-element>
|
|
165
165
|
<hex-row class="grid2x">
|
package/demo/http-request.html
CHANGED
|
@@ -43,18 +43,18 @@
|
|
|
43
43
|
method="GET"
|
|
44
44
|
header-accept="application/json"
|
|
45
45
|
></http-request>
|
|
46
|
-
<
|
|
47
|
-
>https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world</
|
|
48
|
-
<
|
|
49
|
-
<
|
|
46
|
+
<variable name="slides-url"
|
|
47
|
+
>https://unpkg.com/pokeapi-sprites@2.0.2/sprites/pokemon/other/dream-world</variable>
|
|
48
|
+
<for-each select="//slice/page/data/results/*">
|
|
49
|
+
<variable name="pokeid"
|
|
50
50
|
select="substring-before( substring-after( @url, 'https://pokeapi.co/api/v2/pokemon/'),'/')"
|
|
51
|
-
></
|
|
51
|
+
></variable>
|
|
52
52
|
<button>
|
|
53
53
|
<img src="{$slides-url}/{$pokeid}.svg"
|
|
54
54
|
alt="{@name}"/>
|
|
55
55
|
{@name}
|
|
56
56
|
</button>
|
|
57
|
-
</
|
|
57
|
+
</for-each>
|
|
58
58
|
</template>
|
|
59
59
|
</custom-element>
|
|
60
60
|
</template>
|
|
@@ -86,22 +86,22 @@
|
|
|
86
86
|
<tr><th> //slice/request_slice/response/@status </th>
|
|
87
87
|
<td>{ //slice/request_slice/response/@status }</td></tr>
|
|
88
88
|
</table>
|
|
89
|
-
<
|
|
90
|
-
<
|
|
89
|
+
<apply-templates mode="display" select="//slice/request_slice/*"></apply-templates>
|
|
90
|
+
<template mode="display" match="*">
|
|
91
91
|
<fieldset>
|
|
92
92
|
<legend> {local-name(.)} </legend>
|
|
93
93
|
<ul>
|
|
94
|
-
<
|
|
94
|
+
<for-each select="@*">
|
|
95
95
|
<li>
|
|
96
96
|
<var data-testid="section-attribute">@{local-name(.)}</var>
|
|
97
97
|
=
|
|
98
|
-
<code><
|
|
98
|
+
<code><value-of select='.'/></code>
|
|
99
99
|
</li>
|
|
100
|
-
</
|
|
100
|
+
</for-each>
|
|
101
101
|
</ul>
|
|
102
|
-
<
|
|
102
|
+
<apply-templates mode="display" select="*"></apply-templates>
|
|
103
103
|
</fieldset>
|
|
104
|
-
</
|
|
104
|
+
</template>
|
|
105
105
|
</template>
|
|
106
106
|
</custom-element>
|
|
107
107
|
</template>
|
package/demo/local-storage.html
CHANGED
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
<local-storage key="basket" slice="basket" live type="json"></local-storage>
|
|
46
46
|
<xhtml:table xmlns:xhtml="http://www.w3.org/1999/xhtml" >
|
|
47
47
|
<xhtml:tbody>
|
|
48
|
-
<
|
|
48
|
+
<for-each select="//basket/@*">
|
|
49
49
|
<xhtml:tr>
|
|
50
50
|
<xhtml:th> {name()} </xhtml:th>
|
|
51
51
|
<xhtml:td> {.} </xhtml:td>
|
|
52
52
|
</xhtml:tr>
|
|
53
|
-
</
|
|
53
|
+
</for-each>
|
|
54
54
|
</xhtml:tbody>
|
|
55
55
|
<xhtml:tfoot>
|
|
56
56
|
<xhtml:tr>
|