Template polypill: (a) support template.cloneNode and (b) document.importNode(template). Supports nested templates.

This commit is contained in:
Steven Orvell
2016-02-09 18:37:36 -08:00
parent 6d0f05a7f0
commit 3af33f74a2
2 changed files with 127 additions and 1 deletions

View File

@@ -61,15 +61,52 @@ if (typeof HTMLTemplateElement === 'undefined') {
},
configurable: true
});
template.cloneNode = function(deep) {
return HTMLTemplateElement.cloneNode(this, deep);
};
} catch (err) {
canDecorate = false;
}
}
var nativeCloneNode = Node.prototype.cloneNode;
HTMLTemplateElement.cloneNode = function(template, deep) {
var clone = nativeCloneNode.call(template);
this.decorate(clone);
if (deep) {
// NOTE: use native clone node to make sure CE's wrapped
// cloneNode does not cause elements to upgrade.
clone.content.appendChild(
nativeCloneNode.call(template.content, true));
// these two lists should be coincident
var s$ = template.content.querySelectorAll(TEMPLATE_TAG);
var t$ = clone.content.querySelectorAll(TEMPLATE_TAG);
for (var i=0, l=t$.length, t, s; i<l; i++) {
s = s$[i];
t = t$[i];
this.decorate(s);
t.parentNode.replaceChild(s.cloneNode(true), t);
}
}
return clone;
};
// bootstrap recursively
HTMLTemplateElement.bootstrap(template.content);
};
var originalImportNode = document.importNode;
// clone instead of importing <template>
document.importNode = function(element, deep) {
return (element.localName === TEMPLATE_TAG) ?
HTMLTemplateElement.cloneNode(element, deep) :
originalImportNode.call(document, element, deep);
};
/**
The `bootstrap` method is called automatically and "fixes" all
<template> elements in the document referenced by the `doc` argument.

View File

@@ -61,8 +61,97 @@
div.innerHTML = s;
// innerHTML is properly escaped
assert.equal(imp.innerHTML, escaped);
assert.equal(imp.content.childNodes.length, div.childNodes.length);
assert.equal(imp.content.textContent, div.textContent);
});
test('clone', function() {
var imp = document.createElement('template');
var s = '<div>Hi</div>';
imp.innerHTML = s;
var clone = imp.cloneNode();
assert.notEqual(clone, imp, 'element is not cloned');
assert.isDefined(clone.content, 'cloned template content dne');
assert.equal(clone.content.childNodes.length, 0,
'non-deep cloned template.content is not empty');
var deepClone = imp.cloneNode(true);
assert.equal(deepClone.content.childNodes.length, 1,
'deep cloned template.content is empty');
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
'cloned content is not different from source');
});
test('nested clone', function() {
var imp = document.createElement('template');
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
imp.innerHTML = s;
var clone = imp.cloneNode();
assert.notEqual(clone, imp, 'element is not cloned');
assert.isDefined(clone.content, 'cloned template content dne');
assert.equal(clone.content.childNodes.length, 0,
'non-deep cloned template.content is not empty');
var deepClone = imp.cloneNode(true);
assert.equal(deepClone.content.childNodes.length, 2,
'deep cloned template.content is empty');
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
'cloned content is not different from source');
var nested = deepClone.content.lastChild;
assert.isDefined(nested.content, 'nested cloned template content dne');
assert.equal(nested.content.childNodes.length, 2,
'deep cloned template.content is empty');
nested = nested.content.lastChild;
assert.isDefined(nested, 'nested cloned template content dne');
assert.equal(nested.content.childNodes.length, 2,
'deep cloned template.content is empty');
nested = nested.content.lastChild;
assert.isDefined(nested, 'nested cloned template content dne');
assert.equal(nested.content.childNodes.length, 1,
'deep cloned template.content is empty');
});
test('importNode', function() {
var imp = document.createElement('template');
var s = '<div>Hi</div>';
imp.innerHTML = s;
var clone = document.importNode(imp);
assert.notEqual(clone, imp, 'element is not cloned');
assert.isDefined(clone.content, 'cloned template content dne');
assert.equal(clone.content.childNodes.length, 0,
'non-deep cloned template.content is not empty');
var deepClone = document.importNode(imp, true);
assert.equal(deepClone.content.childNodes.length, 1,
'deep cloned template.content is empty');
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
'cloned content is not different from source');
});
test('nested importNode', function() {
var imp = document.createElement('template');
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
imp.innerHTML = s;
var clone = document.importNode(imp);
assert.notEqual(clone, imp, 'element is not cloned');
assert.isDefined(clone.content, 'cloned template content dne');
assert.equal(clone.content.childNodes.length, 0,
'non-deep cloned template.content is not empty');
var deepClone = document.importNode(imp, true);
assert.equal(deepClone.content.childNodes.length, 2,
'deep cloned template.content is empty');
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
'cloned content is not different from source');
var nested = deepClone.content.lastChild;
assert.isDefined(nested.content, 'nested cloned template content dne');
assert.equal(nested.content.childNodes.length, 2,
'deep cloned template.content is empty');
nested = nested.content.lastChild;
assert.isDefined(nested, 'nested cloned template content dne');
assert.equal(nested.content.childNodes.length, 2,
'deep cloned template.content is empty');
nested = nested.content.lastChild;
assert.isDefined(nested, 'nested cloned template content dne');
assert.equal(nested.content.childNodes.length, 1,
'deep cloned template.content is empty');
});
});
</script>
</body>