Compare commits

..
3 Commits
Author SHA1 Message Date
Piper 19794ec27f Add UNFORGIVING mode
* This will explicitly throw errors instead of handling them through
  Event Listeners
2026-08-16 16:56:10 +02:00
Piper 8a95e0f98a Add ref binding
* This will allow template-e6d users to also autobind references within
  their template for any more specific post-binding logic without
  risking ID conflicts.
2026-08-16 16:52:11 +02:00
Piper 3b93bbc44e Add ability to set SELECT values 2026-08-16 16:28:27 +02:00
2 changed files with 48 additions and 18 deletions
+13 -5
View File
@@ -5,11 +5,18 @@
<body> <body>
<template id="template-example" is="template-e6d"> <template id="template-example" is="template-e6d">
<div> <div>
<h2>Easy template</h2> <h2 data-e6d-ref="h2">Easy template</h2>
<p class="class-a class-b $class">Here's some text $textinterp interpolation, and some dynamic "$dynamicInterp".</p> <p class="class-a class-b $class">Here's some text $textinterp interpolation, and some dynamic "$dynamicInterp".</p>
<p>$textinterp</p> <p>$textinterp</p>
<button title="$title" data-e6d-event-click="click buttonclick">A button with tooltip and onclick $textinterpfunc</button> <button title="$title" data-e6d-event-click="click buttonclick">A button with tooltip and onclick $textinterpfunc</button>
<p>Oh, look: a normal dollar sign: $. And then a dollar sign with no vars (does not resolve, emits error): $dollar</p> <p>Oh, look: a normal dollar sign: $. And then a dollar sign with no vars (does not resolve, emits error): $dollar</p>
<label>This should autoselect to 3</label>
<select data-e6d-value="$selectval">
<option value="one">1</option>
<option data-e6d-ref="opt1" value="two">2</option>
<option value="three">3</option>
<option value="four">4</option>
</select>
</div> </div>
</template> </template>
<main> <main>
@@ -22,9 +29,7 @@
</div> </div>
</div> </div>
<section id="template-add"> <section id="template-add"></section>
</section>
<script> <script>
document.getElementById(`template-example`).addEventListener(`e6d-error`, console.log); document.getElementById(`template-example`).addEventListener(`e6d-error`, console.log);
@@ -40,8 +45,11 @@
}, },
title: `A title, injected`, title: `A title, injected`,
dynamicInterp: document.getElementById(`text-interp`).value, dynamicInterp: document.getElementById(`text-interp`).value,
selectval: `three`,
}); });
document.getElementById(`template-add`).appendChild(bind); document.getElementById(`template-add`).appendChild(bind[0]);
bind[1].h2.innerText = `Updated via Reference`;
bind[1].opt1.innerText = `Ref Update`;
}; };
</script> </script>
</main> </main>
+35 -13
View File
@@ -4,11 +4,18 @@ class TemplateE6d extends HTMLTemplateElement {
this.preprocessed = false; this.preprocessed = false;
} }
connectedCallback() {
this.unforgiving = this.hasAttribute(`data-e6d-unforgiving`);
}
dispatchError(type, detail) { dispatchError(type, detail) {
const evtBroad = new CustomEvent(`e6d-error`, {detail,}); const evtBroad = new CustomEvent(`e6d-error`, {detail,});
const evtSpecific = new CustomEvent(`e6d-error-${ type }`, {detail,}); const evtSpecific = new CustomEvent(`e6d-error-${ type }`, {detail,});
this.dispatchEvent(evtBroad); this.dispatchEvent(evtBroad);
this.dispatchEvent(evtSpecific); this.dispatchEvent(evtSpecific);
if (this.unforgiving) {
throw new Error(`${ type }: ${ JSON.stringify(detail) }`);
}
} }
preprocess() { preprocess() {
@@ -51,9 +58,12 @@ class TemplateE6d extends HTMLTemplateElement {
const bindAttr = []; const bindAttr = [];
const bindEvent = []; const bindEvent = [];
let bindContent = false; let bindContent = false;
let ref = null;
if (node.getAttributeNames) { if (node.getAttributeNames) {
for (const attr of node.getAttributeNames()) { for (const attr of node.getAttributeNames()) {
if (attr.indexOf(`data-e6d-event-`) >= 0) { if (attr === `data-e6d-ref`) {
ref = node.getAttribute(attr);
} else if (attr.indexOf(`data-e6d-event-`) >= 0) {
const matches = []; const matches = [];
node.getAttribute(attr).matchAll(eventRegex).forEach(f => matches.push(f)); node.getAttribute(attr).matchAll(eventRegex).forEach(f => matches.push(f));
if (matches.length === 1 && matches[0].length === 3) { if (matches.length === 1 && matches[0].length === 3) {
@@ -67,10 +77,16 @@ class TemplateE6d extends HTMLTemplateElement {
} else { } else {
const textTemplate = buildTextTemplate(node.getAttribute(attr)); const textTemplate = buildTextTemplate(node.getAttribute(attr));
if (textTemplate) { if (textTemplate) {
bindAttr.push({ const bindLogic = {
attr: attr, attr: attr,
template: textTemplate, template: textTemplate,
}); };
if (node.nodeName === `SELECT` && attr === `data-e6d-value`) {
bindLogic.func = (el, val) => {
el.value = val;
};
}
bindAttr.push(bindLogic);
} }
} }
} }
@@ -83,10 +99,11 @@ class TemplateE6d extends HTMLTemplateElement {
} }
} }
if (bindAttr.length !== 0 || bindEvent.length !== 0 || bindContent) { if (bindAttr.length !== 0 || bindEvent.length !== 0 || bindContent || ref !== null) {
// Add a leaf! // Add a leaf!
allRoutes.push({ allRoutes.push({
route: trail, route: trail,
ref,
bind: { bind: {
attr: bindAttr, attr: bindAttr,
event: bindEvent, event: bindEvent,
@@ -112,16 +129,10 @@ class TemplateE6d extends HTMLTemplateElement {
this.preprocessed = true; this.preprocessed = true;
} }
connectedCallback() { bind(obj = {}) {
}
bind(obj) {
this.preprocess(); this.preprocess();
const templated = document.importNode(this.content, true); const templated = document.importNode(this.content, true);
if (!obj) {
return templated;
}
const resolve = (root, route) => { const resolve = (root, route) => {
let ptr = root; let ptr = root;
@@ -156,11 +167,22 @@ class TemplateE6d extends HTMLTemplateElement {
return result; return result;
}; };
const references = {};
for (const route of this.bindRoute) { for (const route of this.bindRoute) {
const injectTarget = resolve(templated, route.route); const injectTarget = resolve(templated, route.route);
if (route.ref) {
references[route.ref] = injectTarget;
injectTarget.removeAttribute(`data-e6d-ref`);
}
for (const attr of route.bind.attr) { for (const attr of route.bind.attr) {
const attrValue = templateString(attr.template, obj); const attrValue = templateString(attr.template, obj);
injectTarget.setAttribute(attr.attr, attrValue); if (attr.func) {
attr.func(injectTarget, attrValue);
injectTarget.removeAttribute(attr.attr);
} else if (attr.template) {
injectTarget.setAttribute(attr.attr, attrValue);
}
} }
for (const evt of route.bind.event) { for (const evt of route.bind.event) {
const trigger = evt.event; const trigger = evt.event;
@@ -177,7 +199,7 @@ class TemplateE6d extends HTMLTemplateElement {
} }
} }
return templated; return [templated, references,];
} }
} }