|
@@ -39,12 +39,13 @@ class AttributeNode { |
|
|
|
|
|
|
|
addListeners() { |
|
|
|
this.boundEvents.forEach((eventHandler, eventName) => { |
|
|
|
const events = eventHandler.split(/\;/); |
|
|
|
const events = eventHandler.split(/;/); |
|
|
|
const eventsSafe = events.filter(event => event.match(sanitizePattern)); |
|
|
|
const sanitizedEvents = eventsSafe.join('; '); |
|
|
|
if (eventHandler.match(sanitizePattern)) { |
|
|
|
const handler = new Function(sanitizedEvents); |
|
|
|
this.node.addEventListener(eventName, handler.bind(this.context)); |
|
|
|
const handler = new Function(sanitizedEvents).bind(this.context); |
|
|
|
this.node.addEventListener(eventName, handler); |
|
|
|
this.node._boundEvents = handler; |
|
|
|
} |
|
|
|
|
|
|
|
if (eventsSafe.length < events.length) { |
|
@@ -63,7 +64,6 @@ class AttributeNode { |
|
|
|
const newAttr = newNode.boundAttrs.get(attr.name); |
|
|
|
newAttr && attr.value !== newAttr.value ? attr.value = newAttr.value : null; |
|
|
|
|
|
|
|
/* TODO */ |
|
|
|
if (attr.name.match(propPattern)) { |
|
|
|
this.updateAttributes(attr.name, newAttr); |
|
|
|
} |
|
@@ -76,7 +76,6 @@ class AttributeNode { |
|
|
|
this.node[attributeName] = newAttr.value; |
|
|
|
this.node.setAttribute(attributeName, newAttr.value); |
|
|
|
} else { |
|
|
|
this.node; |
|
|
|
this.node.removeAttribute(attributeName); |
|
|
|
} |
|
|
|
} |
|
@@ -87,16 +86,23 @@ class Template { |
|
|
|
const template = document.createElement('template'); |
|
|
|
const content = base.replace(startSeparator, '').replace(endSeparator, ''); |
|
|
|
template.innerHTML = content; |
|
|
|
this.node = document.importNode(template.content, true); |
|
|
|
this.parts = new Map(); |
|
|
|
this.templiteralParts = new Set(); |
|
|
|
this.eventHandlers = []; |
|
|
|
this.location = location; |
|
|
|
this.context = context; |
|
|
|
this._init(base); |
|
|
|
} |
|
|
|
|
|
|
|
paint() { |
|
|
|
this.location.appendChild(this.node); |
|
|
|
disconnect() { |
|
|
|
this.eventHandlers.forEach((eventName, index) => { |
|
|
|
const node = this.eventHandlers[index].currentNode; |
|
|
|
node.removeEventListener(eventName, node._boundEvents); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
paint(node) { |
|
|
|
this.location.appendChild(node); |
|
|
|
} |
|
|
|
|
|
|
|
update(content) { |
|
@@ -108,7 +114,7 @@ class Template { |
|
|
|
} |
|
|
|
|
|
|
|
_parseUpdates(walker) { |
|
|
|
const updatedParts = this._walk(walker, new Map()); |
|
|
|
const updatedParts = this._walk(walker, new Map(), false); |
|
|
|
this.parts.forEach((part, index) => part.update(updatedParts.get(index))); |
|
|
|
} |
|
|
|
|
|
@@ -117,51 +123,55 @@ class Template { |
|
|
|
baseTemplate.innerHTML = base; |
|
|
|
const baseNode = document.importNode(baseTemplate.content, true); |
|
|
|
const walker = document.createTreeWalker(baseNode, 133, null, false); |
|
|
|
this._walk(walker, this.parts); |
|
|
|
this.node = baseNode; |
|
|
|
this.paint(); |
|
|
|
this._walk(walker, this.parts, true); |
|
|
|
this.paint(baseNode); |
|
|
|
} |
|
|
|
|
|
|
|
_walk(walker, parts) { |
|
|
|
_walk(walker, parts, setup) { |
|
|
|
let index = -1; |
|
|
|
|
|
|
|
while (walker.nextNode()) { |
|
|
|
index += 1; |
|
|
|
const { currentNode } = walker; |
|
|
|
switch (currentNode.nodeType) { |
|
|
|
case 1: { |
|
|
|
const { attributes } = currentNode; |
|
|
|
if (attributes.length) { |
|
|
|
const boundAttrs = new Map(); |
|
|
|
const boundEvents = new Map(); |
|
|
|
for (let i = 0; i < attributes.length; i += 1) { |
|
|
|
const attribute = attributes[i]; |
|
|
|
if (attribute.value.match(valuePattern) || attribute.name.match(propPattern)) { |
|
|
|
boundAttrs.set(attribute.name, attribute); |
|
|
|
if (!currentNode.__templiteralCompiler) { |
|
|
|
switch (currentNode.nodeType) { |
|
|
|
case 1: { |
|
|
|
const { attributes } = currentNode; |
|
|
|
if (attributes.length) { |
|
|
|
const boundAttrs = new Map(); |
|
|
|
const boundEvents = new Map(); |
|
|
|
for (let i = 0; i < attributes.length; i += 1) { |
|
|
|
const attribute = attributes[i]; |
|
|
|
if (attribute.value.match(valuePattern) || attribute.name.match(propPattern)) { |
|
|
|
boundAttrs.set(attribute.name, attribute); |
|
|
|
} |
|
|
|
if (setup && attribute.name.match(eventPattern)) { |
|
|
|
const eventName = attribute.name.substring(1, attribute.name.length - 1); |
|
|
|
boundEvents.set(eventName, attribute.value); |
|
|
|
this.eventHandlers.push({ eventName, currentNode }); |
|
|
|
} |
|
|
|
} |
|
|
|
if (attribute.name.match(eventPattern)) { |
|
|
|
const eventName = attribute.name.substring(1, attribute.name.length - 1); |
|
|
|
boundEvents.set(eventName, attribute.value); |
|
|
|
this.eventHandlers.push({ eventName, currentNode }); |
|
|
|
if (boundAttrs.size >= 1 || boundEvents.size >= 1 || this.parts.has(index)) { |
|
|
|
const attrNode = new AttributeNode(currentNode, index, boundAttrs, boundEvents, this.context); |
|
|
|
parts.set(index, attrNode); |
|
|
|
attrNode.cleanUp(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (boundAttrs.size >= 1 || boundEvents.size >= 1 || this.parts.has(index)) { |
|
|
|
const attrNode = new AttributeNode(currentNode, index, boundAttrs, boundEvents, this.context); |
|
|
|
parts.set(index, attrNode); |
|
|
|
attrNode.cleanUp(); |
|
|
|
break; |
|
|
|
} |
|
|
|
case 3: { |
|
|
|
if (currentNode.textContent && currentNode.textContent.match(valuePattern) || this.parts.has(index)) { |
|
|
|
const contentNode = new ContentNode(currentNode, index); |
|
|
|
parts.set(index, contentNode); |
|
|
|
contentNode.cleanUp(); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case 3: { |
|
|
|
if (currentNode.textContent && currentNode.textContent.match(valuePattern) || this.parts.has(index)) { |
|
|
|
const contentNode = new ContentNode(currentNode, index); |
|
|
|
parts.set(index, contentNode); |
|
|
|
contentNode.cleanUp(); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} else { |
|
|
|
this.templiteralParts.add(currentNode); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return parts; |
|
@@ -184,15 +194,23 @@ function html(location) { |
|
|
|
compiler = new Template(output, location, this); |
|
|
|
templateCache.set(templateKey, compiler); |
|
|
|
} |
|
|
|
} |
|
|
|
location.__templiteralCompiler = compiler; |
|
|
|
return compiler; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
function templiteral(location, context) { |
|
|
|
function templiteral(location, context = this) { |
|
|
|
function render(...args) { |
|
|
|
const renderer = Reflect.apply(html, context, [location]); |
|
|
|
return Reflect.apply(renderer, context, args); |
|
|
|
} |
|
|
|
return render.bind(context); |
|
|
|
} |
|
|
|
|
|
|
|
function registerElements(elements) { |
|
|
|
elements.forEach(elementClass => |
|
|
|
customElements.define(elementClass.tagName, elementClass)); |
|
|
|
} |
|
|
|
|
|
|
|
exports.templiteral = templiteral; |
|
|
|
exports.registerElements = registerElements; |
0 comments on commit
6391fd8