Skip to content

Commit

Permalink
Merge pull request #33 from EPA-WG/develop
Browse files Browse the repository at this point in the history
0.0.15
  • Loading branch information
sashafirsov authored Feb 16, 2024
2 parents 76bd499 + 2203288 commit f5f1e75
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 13 deletions.
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,18 @@ In same way as in DCE itself:
</dce-2>
```
## Attributes
curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)
To be served by IDE and to track the attributes changes, they have to be declared via `xsl:param` syntax:
```html
<custom-element tag="dce-with-attrs" hidden>
<xsl:param name="p1" >default_P1</xsl:param>
<xsl:param name="p2" select="'always_p2'" ></xsl:param>
<xsl:param name="p3" select="//p3 ?? 'def_P3' " ></xsl:param>
p1: {$p1} <br/> p2: {$p2} <br/> p3: {$p3}
</custom-element>
<dce-with-attrs p1="123" p3="qwe"></dce-with-attrs>
```

The curly braces `{}` in attributes implemented as [attribute value template](https://www.w3.org/TR/xslt20/#attribute-value-templates)

The names in curly braces are matching the instance attributes. I.e. in XML node `/my-component/attributes/`.

Expand Down Expand Up @@ -297,9 +308,9 @@ within template
[github-image]: https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/mark-github.svg
[npm-image]: https://img.shields.io/npm/v/@epa-wg/custom-element.svg
[npm-url]: https://npmjs.org/package/@epa-wg/custom-element
[coverage-image]: https://unpkg.com/@epa-wg/[email protected].14/coverage/coverage.svg
[coverage-url]: https://unpkg.com/@epa-wg/[email protected].14/coverage/lcov-report/index.html
[storybook-url]: https://unpkg.com/@epa-wg/[email protected].14/storybook-static/index.html?path=/story/welcome--introduction
[coverage-image]: https://unpkg.com/@epa-wg/[email protected].15/coverage/coverage.svg
[coverage-url]: https://unpkg.com/@epa-wg/[email protected].15/coverage/lcov-report/index.html
[storybook-url]: https://unpkg.com/@epa-wg/[email protected].15/storybook-static/index.html?path=/story/welcome--introduction
[sandbox-url]: https://stackblitz.com/github/EPA-WG/custom-element?file=index.html
[webcomponents-url]: https://www.webcomponents.org/element/@epa-wg/custom-element
[webcomponents-img]: https://img.shields.io/badge/webcomponents.org-published-blue.svg
Expand Down
54 changes: 49 additions & 5 deletions custom-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ const XSL_NS_URL = 'http://www.w3.org/1999/XSL/Transform'

const attr = (el, attr)=> el.getAttribute?.(attr)
, isText = e => e.nodeType === 3
, create = ( tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElement( tag ))
, create = ( tag, t = '', d=document ) => ( e => ((e.innerText = t||''),e) )((d.ownerDocument || d ).createElement( tag ))
, createText = ( d, t) => (d.ownerDocument || d ).createTextNode( t )
, emptyNode = n=> { while(n.firstChild) n.firstChild.remove(); return n; }
, createNS = ( ns, tag, t = '' ) => ( e => ((e.innerText = t||''),e) )(document.createElementNS( ns, tag ))
, xslNs = x => ( x?.setAttribute('xmlns:xsl', XSL_NS_URL ), x )
, xslHtmlNs = x => ( x?.setAttribute('xmlns:xhtml', HTML_NS_URL ), xslNs(x) );
Expand Down Expand Up @@ -162,7 +163,12 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl"
>
<xsl:template match="ignore"><xsl:value-of select="."/></xsl:template>
<xsl:template match="ignore">
<xsl:choose>
<xsl:when test="//attr">{//attr}</xsl:when>
<xsl:otherwise>{def}</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="."/></xsl:template>
<xsl:template mode="payload" match="attributes"></xsl:template>
<xsl:template match="/">
<xsl:apply-templates mode="payload" select="/datadom/attributes"/>
Expand Down Expand Up @@ -195,6 +201,24 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )
, payload = $( xslDom, 'template[mode="payload"]');
if( !fr )
return console.error("transformation error",{ xml:tc.outerHTML, xsl: xmlString( sanitizeXsl ) });
const params = [];
[...fr.querySelectorAll('dce-root>param')].forEach(p=>
{ payload.append(p);
let select = attr(p,'select')?.split('??')
if( !select)
{ select = ['//'+attr(p, 'name'), `'${p.textContent}'`];
emptyNode(p);
}
if( select?.length>1){
p.removeAttribute('select');
const c = $( xslDom, 'template[match="ignore"]>choose').cloneNode(true);
c.firstElementChild.setAttribute('test',select[0]);
emptyNode(c.firstElementChild).append( createText(c,'{'+select[0]+'}'));
emptyNode(c.lastElementChild ).append( createText(c,'{'+select[1]+'}'));
p.append(c)
}
params.push(p)
});

for( const c of fr.childNodes )
payload.append(xslDom.importNode(c,true))
Expand All @@ -214,7 +238,9 @@ createXsltFromDom( templateNode, S = 'xsl:stylesheet' )

forEach$( payload,'slot', s => s.parentNode.replaceChild( slot2xsl(s), s ) )

return tagUid(xslDom)
const ret = tagUid(xslDom)
ret.params = params;
return ret;
}
export async function
xhrTemplate(src)
Expand Down Expand Up @@ -382,6 +408,10 @@ CustomElement extends HTMLElement
const sliceNames = [...this.templateNode.querySelectorAll('[slice]')].map(e=>attr(e,'slice'));
class DceElement extends HTMLElement
{
static get observedAttributes()
{
return templateDocs.reduce( (ret,t) =>{ ret.push( ...t.params.map(e=>attr(e,'name')) ); return ret; }, [] );
}
connectedCallback()
{ if( this.firstElementChild?.tagName === 'TEMPLATE' )
{ const t = this.firstElementChild;
Expand Down Expand Up @@ -416,7 +446,7 @@ CustomElement extends HTMLElement
const applySlices = ()=>
{ const processed = {}

for(let ev; ev = sliceEvents.pop(); )
for(let ev; ev = sliceEvents.pop(); )
{ const s = attr( ev.target, 'slice');
if( processed[s] )
continue;
Expand All @@ -440,7 +470,7 @@ CustomElement extends HTMLElement
timeoutID =0;
},10);
};
const transform = ()=>
const transform = this.transform = ()=>
{
const ff = xp.map( (p,i) =>
{ const f = p.transformToFragment(x.ownerDocument, document)
Expand Down Expand Up @@ -469,6 +499,20 @@ CustomElement extends HTMLElement
transform();
applySlices();
}
attributeChangedCallback(name, oldValue, newValue)
{ if( !this.xml )
return;
let a = this.xml.querySelector(`attributes>${name}`);
if( a )
emptyNode(a).append( createText(a,newValue));
else
{ a = create( name, newValue, this.xml );
a.append( createText(a,newValue) );
this.xml.querySelector('attributes').append( a );
}

this.transform(); // needs throttling
}
get dce(){ return dce }
}
if(tag)
Expand Down
52 changes: 52 additions & 0 deletions demo/parameters.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>parameters - custom-element Declarative Custom Element implementation demo</title>
<link rel="icon" href="./wc-square.svg" />
<script type="module" src="../location-element.js"></script>
<script type="module" src="../custom-element.js"></script>
<style>
@import "./demo.css";

button{ background: forestgreen; }
table{ min-width: 16rem; }
td{ border-bottom: 1px solid silver; }
tfoot td{ border-bottom: none; }
td,th{text-align: right; }
caption{ padding: 1rem; font-weight: bolder; font-family: sans-serif; }
</style>
</head>
<body>
<nav>
<a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
</nav>
<html-demo-element legend="param as attributes definition" description="
params needed to declare DCE attributes and track the attributes changes. It also be used by IDE and validation.
">
<template>
<custom-element tag="dce-link" hidden>
<xsl:param name="p1" >default_P1</xsl:param>
<xsl:param name="p2" select="'always_p2'" ></xsl:param>
<xsl:param name="p3" select="//p3 ?? 'def_P3' " ></xsl:param>
p1:{$p1} <br/> p2: {$p2} <br/> p3: {$p3}
</custom-element>
<dce-link id="dce1"></dce-link>
<section>
<dce-link id="dce2" p1="123" p2="override ignored as select is defined"></dce-link> <br/>
<div><input id="i1" value="p1" /> <button onclick="dce2.setAttribute('p1',i1.value)"> set p1</button> </div>
<div><input id="i2" value="p2" /> <button onclick="dce2.setAttribute('p2',i2.value)"> set p2</button> </div>
<div><input id="i3" value="p3" /> <button onclick="dce2.setAttribute('p3',i3.value)"> set p3</button> </div>
</section>
<dce-link id="dce3" p1="123" p3="qwe"></dce-link> |

</template>
</html-demo-element>



<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>

</body>
</html>
3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ <h3><code>custom-element</code> demo</h3>
The data query is powered by XPath. </p>
<p>Try in <a href="https://stackblitz.com/github/EPA-WG/custom-element?file=index.html" >Sandbox</a> </p>
<section>
<h4>Data layer demo</h4>
<h4>Features demo</h4>
<a href="./demo/local-storage.html" >local-storage </a> |
<a href="./demo/http-request.html" >http-request </a> |
<a href="./demo/location-element.html" >location-element </a> |
<a href="./demo/external-template.html" >external template </a> <br/>
<a href="./demo/hex-grid.html" >hex grid lib </a> |
<a href="./demo/scoped-css.html" >scoped CSS </a> |
<a href="./demo/parameters.html" >attributes </a> |
<a href="./demo/dom-merge.html" >DOM merge on dynamic update </a>
</section>
</nav>
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@epa-wg/custom-element",
"version": "0.0.14",
"version": "0.0.15",
"description": "Declarative Custom Element as W3C proposal PoC with native(XSLT) based templating",
"browser": "custom-element.js",
"module": "custom-element.js",
Expand Down

0 comments on commit f5f1e75

Please sign in to comment.