Skip to content
This repository was archived by the owner on Sep 20, 2019. It is now read-only.

Commit 3af33f7

Browse files
author
Steven Orvell
committed
Template polypill: (a) support template.cloneNode and (b) document.importNode(template). Supports nested templates.
1 parent 6d0f05a commit 3af33f7

2 files changed

Lines changed: 127 additions & 1 deletion

File tree

src/Template/Template.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,52 @@ if (typeof HTMLTemplateElement === 'undefined') {
6161
},
6262
configurable: true
6363
});
64+
65+
template.cloneNode = function(deep) {
66+
return HTMLTemplateElement.cloneNode(this, deep);
67+
};
68+
6469
} catch (err) {
6570
canDecorate = false;
6671
}
6772
}
6873

74+
var nativeCloneNode = Node.prototype.cloneNode;
75+
76+
HTMLTemplateElement.cloneNode = function(template, deep) {
77+
var clone = nativeCloneNode.call(template);
78+
this.decorate(clone);
79+
if (deep) {
80+
// NOTE: use native clone node to make sure CE's wrapped
81+
// cloneNode does not cause elements to upgrade.
82+
clone.content.appendChild(
83+
nativeCloneNode.call(template.content, true));
84+
// these two lists should be coincident
85+
var s$ = template.content.querySelectorAll(TEMPLATE_TAG);
86+
var t$ = clone.content.querySelectorAll(TEMPLATE_TAG);
87+
for (var i=0, l=t$.length, t, s; i<l; i++) {
88+
s = s$[i];
89+
t = t$[i];
90+
this.decorate(s);
91+
t.parentNode.replaceChild(s.cloneNode(true), t);
92+
}
93+
}
94+
return clone;
95+
};
96+
6997
// bootstrap recursively
7098
HTMLTemplateElement.bootstrap(template.content);
7199
};
72100

101+
var originalImportNode = document.importNode;
102+
103+
// clone instead of importing <template>
104+
document.importNode = function(element, deep) {
105+
return (element.localName === TEMPLATE_TAG) ?
106+
HTMLTemplateElement.cloneNode(element, deep) :
107+
originalImportNode.call(document, element, deep);
108+
};
109+
73110
/**
74111
The `bootstrap` method is called automatically and "fixes" all
75112
<template> elements in the document referenced by the `doc` argument.

tests/Template/tests.html

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,97 @@
6161
div.innerHTML = s;
6262
// innerHTML is properly escaped
6363
assert.equal(imp.innerHTML, escaped);
64-
assert.equal(imp.content.childNodes.length, div.childNodes.length);
64+
assert.equal(imp.content.textContent, div.textContent);
6565
});
66+
67+
test('clone', function() {
68+
var imp = document.createElement('template');
69+
var s = '<div>Hi</div>';
70+
imp.innerHTML = s;
71+
var clone = imp.cloneNode();
72+
assert.notEqual(clone, imp, 'element is not cloned');
73+
assert.isDefined(clone.content, 'cloned template content dne');
74+
assert.equal(clone.content.childNodes.length, 0,
75+
'non-deep cloned template.content is not empty');
76+
var deepClone = imp.cloneNode(true);
77+
assert.equal(deepClone.content.childNodes.length, 1,
78+
'deep cloned template.content is empty');
79+
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
80+
'cloned content is not different from source');
81+
});
82+
83+
test('nested clone', function() {
84+
var imp = document.createElement('template');
85+
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
86+
imp.innerHTML = s;
87+
var clone = imp.cloneNode();
88+
assert.notEqual(clone, imp, 'element is not cloned');
89+
assert.isDefined(clone.content, 'cloned template content dne');
90+
assert.equal(clone.content.childNodes.length, 0,
91+
'non-deep cloned template.content is not empty');
92+
var deepClone = imp.cloneNode(true);
93+
assert.equal(deepClone.content.childNodes.length, 2,
94+
'deep cloned template.content is empty');
95+
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
96+
'cloned content is not different from source');
97+
var nested = deepClone.content.lastChild;
98+
assert.isDefined(nested.content, 'nested cloned template content dne');
99+
assert.equal(nested.content.childNodes.length, 2,
100+
'deep cloned template.content is empty');
101+
nested = nested.content.lastChild;
102+
assert.isDefined(nested, 'nested cloned template content dne');
103+
assert.equal(nested.content.childNodes.length, 2,
104+
'deep cloned template.content is empty');
105+
nested = nested.content.lastChild;
106+
assert.isDefined(nested, 'nested cloned template content dne');
107+
assert.equal(nested.content.childNodes.length, 1,
108+
'deep cloned template.content is empty');
109+
});
110+
111+
test('importNode', function() {
112+
var imp = document.createElement('template');
113+
var s = '<div>Hi</div>';
114+
imp.innerHTML = s;
115+
var clone = document.importNode(imp);
116+
assert.notEqual(clone, imp, 'element is not cloned');
117+
assert.isDefined(clone.content, 'cloned template content dne');
118+
assert.equal(clone.content.childNodes.length, 0,
119+
'non-deep cloned template.content is not empty');
120+
var deepClone = document.importNode(imp, true);
121+
assert.equal(deepClone.content.childNodes.length, 1,
122+
'deep cloned template.content is empty');
123+
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
124+
'cloned content is not different from source');
125+
});
126+
127+
test('nested importNode', function() {
128+
var imp = document.createElement('template');
129+
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
130+
imp.innerHTML = s;
131+
var clone = document.importNode(imp);
132+
assert.notEqual(clone, imp, 'element is not cloned');
133+
assert.isDefined(clone.content, 'cloned template content dne');
134+
assert.equal(clone.content.childNodes.length, 0,
135+
'non-deep cloned template.content is not empty');
136+
var deepClone = document.importNode(imp, true);
137+
assert.equal(deepClone.content.childNodes.length, 2,
138+
'deep cloned template.content is empty');
139+
assert.notEqual(imp.content.firstChild, deepClone.content.firstChild,
140+
'cloned content is not different from source');
141+
var nested = deepClone.content.lastChild;
142+
assert.isDefined(nested.content, 'nested cloned template content dne');
143+
assert.equal(nested.content.childNodes.length, 2,
144+
'deep cloned template.content is empty');
145+
nested = nested.content.lastChild;
146+
assert.isDefined(nested, 'nested cloned template content dne');
147+
assert.equal(nested.content.childNodes.length, 2,
148+
'deep cloned template.content is empty');
149+
nested = nested.content.lastChild;
150+
assert.isDefined(nested, 'nested cloned template content dne');
151+
assert.equal(nested.content.childNodes.length, 1,
152+
'deep cloned template.content is empty');
153+
});
154+
66155
});
67156
</script>
68157
</body>

0 commit comments

Comments
 (0)