Fix cloneNode/importNode for dom that contains templates.

This commit is contained in:
Steven Orvell
2016-02-10 15:28:45 -08:00
parent 3ff9cdc3f5
commit 178272092a
2 changed files with 85 additions and 13 deletions

View File

@@ -85,25 +85,43 @@ if (typeof HTMLTemplateElement === 'undefined') {
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);
}
this.fixClonedDom(clone.content, template.content);
}
return clone;
};
HTMLTemplateElement.fixClonedDom = function(clone, source) {
var s$ = source.querySelectorAll(TEMPLATE_TAG);
var t$ = clone.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);
}
};
var originalImportNode = document.importNode;
Node.prototype.cloneNode = function(deep) {
var dom = nativeCloneNode.call(this, deep);
if (deep) {
HTMLTemplateElement.fixClonedDom(dom, this);
}
return dom;
};
// clone instead of importing <template>
document.importNode = function(element, deep) {
return (element.localName === TEMPLATE_TAG) ?
HTMLTemplateElement.cloneNode(element, deep) :
originalImportNode.call(document, element, deep);
if (element.localName === TEMPLATE_TAG) {
return HTMLTemplateElement.cloneNode(element, deep);
} else {
var dom = originalImportNode.call(document, element, deep);
if (deep) {
HTMLTemplateElement.fixClonedDom(dom, element);
}
return dom;
}
};
/**

View File

@@ -80,7 +80,7 @@
'cloned content is not different from source');
});
test('nested clone', function() {
test('clone nested', 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;
@@ -108,6 +108,33 @@
'deep cloned template.content is empty');
});
test('clone node containing templates', function() {
var imp = document.createElement('div');
var t = document.createElement('template');
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
t.innerHTML = s;
imp.appendChild(t);
var impClone = imp.cloneNode(true);
var imp = imp.firstChild;
var deepClone = impClone.firstChild;
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>';
@@ -124,7 +151,7 @@
'cloned content is not different from source');
});
test('nested importNode', function() {
test('importNode: nested', 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;
@@ -152,6 +179,33 @@
'deep cloned template.content is empty');
});
test('importNode: element containing nested templates', function() {
var imp = document.createElement('div');
var t = document.createElement('template');
var s = 'a<template id="a">b<template id="b">c<template id="c">d</template></template></template>';
t.innerHTML = s;
imp.appendChild(t);
var impClone = document.importNode(imp, true);
imp = imp.firstChild;
var deepClone = impClone.firstChild;
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>