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

Commit 04527ce

Browse files
author
Steven Orvell
committed
Add comments and test for ownerDoc.
1 parent 2a334a8 commit 04527ce

2 files changed

Lines changed: 34 additions & 2 deletions

File tree

src/Template/Template.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,16 @@
139139

140140
// make cloning/importing work!
141141
if (needsTemplate || needsCloning) {
142+
// NOTE: we rely on this cloneNode not causing element upgrade.
143+
// This means this polyfill must load before the CE polyfill and
144+
// this would need to be re-worked if a browser supports native CE
145+
// but not <template>.
142146
var nativeCloneNode = Node.prototype.cloneNode;
143147

144148
TemplateImpl.cloneNode = function(template, deep) {
145149
var clone = nativeCloneNode.call(template);
150+
// NOTE: decorate doesn't auto-fix children because they are already
151+
// decorated so they need special clone fixup.
146152
if (this.decorate) {
147153
this.decorate(clone);
148154
}
@@ -151,13 +157,17 @@
151157
// cloneNode does not cause elements to upgrade.
152158
clone.content.appendChild(
153159
nativeCloneNode.call(template.content, true));
154-
// these two lists should be coincident
160+
// now ensure nested templates are cloned correctly.
155161
this.fixClonedDom(clone.content, template.content);
156162
}
157163
return clone;
158164
};
159165

166+
// Given a source and cloned subtree, find <template>'s in the cloned
167+
// subtree and replace them with cloned <template>'s from source.
168+
// We must do this because only the source templates have proper .content.
160169
TemplateImpl.fixClonedDom = function(clone, source) {
170+
// these two lists should be coincident
161171
var s$ = source.querySelectorAll(TEMPLATE_TAG);
162172
var t$ = clone.querySelectorAll(TEMPLATE_TAG);
163173
for (var i=0, l=t$.length, t, s; i<l; i++) {
@@ -172,15 +182,22 @@
172182

173183
var originalImportNode = document.importNode;
174184

185+
// override all cloning to fix the cloned subtree to contain properly
186+
// cloned templates.
175187
Node.prototype.cloneNode = function(deep) {
176188
var dom = nativeCloneNode.call(this, deep);
189+
// template.content is cloned iff `deep`.
177190
if (deep) {
178191
TemplateImpl.fixClonedDom(dom, this);
179192
}
180193
return dom;
181194
};
182195

183-
// clone instead of importing <template>
196+
// NOTE: we are cloning instead of importing <template>'s.
197+
// However, the ownerDocument of the cloned template will be correct!
198+
// This is because the native import node creates the right document owned
199+
// subtree and `fixClonedDom` inserts cloned templates into this subtree,
200+
// thus updating the owner doc.
184201
document.importNode = function(element, deep) {
185202
if (element.localName === TEMPLATE_TAG) {
186203
return TemplateImpl.cloneNode(element, deep);

tests/Template/tests.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,21 @@
206206
'deep cloned template.content is empty');
207207
});
208208

209+
test('importNode: templates have proper owner document', function() {
210+
var doc = document.implementation.createHTMLDocument('');
211+
var imp = doc.createElement('div');
212+
var t = doc.createElement('template');
213+
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
214+
t.innerHTML = s;
215+
imp.appendChild(t);
216+
var impClone = document.importNode(imp, true);
217+
imp = imp.firstChild;
218+
var deepClone = impClone.firstChild;
219+
assert.notEqual(imp.ownerDocument, document);
220+
assert.equal(impClone.ownerDocument, document);
221+
assert.equal(deepClone.ownerDocument, document);
222+
});
223+
209224
});
210225
</script>
211226
</body>

0 commit comments

Comments
 (0)