Skip to content

Commit fd5331f

Browse files
fix(html-template-element): fix template.content.cloneNode
where native support is missing fix aurelia/templating#569
1 parent c60c394 commit fd5331f

File tree

5 files changed

+85
-5
lines changed

5 files changed

+85
-5
lines changed

karma.conf.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module.exports = function(config) {
1414

1515
jspm: {
1616
// Edit this to your needs
17-
loadFiles: ['src/**/*.js', 'test/**/*.js']
17+
loadFiles: ['src/**/*.js', 'test/**/*.js', 'jspm_packages/system-polyfills.js']
1818
},
1919

2020

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"aurelia-pal": "^1.4.0"
3434
},
3535
"devDependencies": {
36+
"aurelia-polyfills": "^1.1.1",
3637
"babel": "babel-core@^5.8.22",
3738
"babel-runtime": "^5.8.20",
3839
"core-js": "^2.0.3"
@@ -42,6 +43,7 @@
4243
"aurelia-pal": "^1.4.0"
4344
},
4445
"devDependencies": {
46+
"aurelia-polyfills": "^1.1.1",
4547
"aurelia-tools": "^0.2.4",
4648
"babel-dts-generator": "^0.6.1",
4749
"babel-eslint": "^6.1.2",
@@ -74,6 +76,7 @@
7476
"karma-babel-preprocessor": "^6.0.1",
7577
"karma-chrome-launcher": "^1.0.1",
7678
"karma-coverage": "^1.1.1",
79+
"karma-ie-launcher": "^1.0.0",
7780
"karma-jasmine": "^1.0.2",
7881
"karma-jspm": "^2.2.0",
7982
"merge2": "^1.0.2",

src/html-template-element.js

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {_FEATURE} from './feature';
33
if (typeof FEATURE_NO_IE === 'undefined') {
44
function isSVGTemplate(el) {
55
return el.tagName === 'template' &&
6-
el.namespaceURI === 'http://www.w3.org/2000/svg';
6+
el.namespaceURI === 'http://www.w3.org/2000/svg';
77
}
88

99
function fixSVGTemplateElement(el) {
@@ -36,9 +36,42 @@ if (typeof FEATURE_NO_IE === 'undefined') {
3636
return template;
3737
}
3838

39+
// replaces a #document-fragment .cloneNode
40+
function __safeCloneNode(deep) {
41+
const clone = this.standardCloneNode(deep);
42+
if (deep) {
43+
if (!this.__templates) {
44+
// cache child templates on first call
45+
// fix child templates on first call
46+
this.__templates = this.querySelectorAll('template');
47+
let i = this.__templates.length;
48+
while (i--) {
49+
installSafeCloneNode(this.__templates.item(i));
50+
}
51+
}
52+
if (this.__templates.length) {
53+
const clonedTemplates = clone.querySelectorAll('template');
54+
let i = clonedTemplates.length;
55+
while (i--) {
56+
clonedTemplates.item(i).content = this.__templates.item(i).content;
57+
}
58+
}
59+
}
60+
return clone;
61+
}
62+
63+
function installSafeCloneNode(template) {
64+
if (!template.content.__safeToCloneNode) {
65+
template.content.standardCloneNode = template.content.cloneNode;
66+
template.content.cloneNode = __safeCloneNode;
67+
template.content.__safeToCloneNode = true;
68+
}
69+
return template;
70+
}
71+
3972
function fixHTMLTemplateElementRoot(template) {
40-
let content = fixHTMLTemplateElement(template).content;
41-
let childTemplates = content.querySelectorAll('template');
73+
const content = fixHTMLTemplateElement(template).content;
74+
const childTemplates = content.querySelectorAll('template');
4275

4376
for (let i = 0, ii = childTemplates.length; i < ii; ++i) {
4477
let child = childTemplates[i];
@@ -48,12 +81,15 @@ if (typeof FEATURE_NO_IE === 'undefined') {
4881
} else {
4982
fixHTMLTemplateElement(child);
5083
}
84+
// installSafeCloneNode(child);
5185
}
5286

87+
installSafeCloneNode(template);
88+
5389
return template;
5490
}
5591

56-
if (!_FEATURE.htmlTemplateElement) {
92+
if (!_FEATURE.htmlTemplateElement) {
5793
_FEATURE.ensureHTMLTemplateElement = fixHTMLTemplateElementRoot;
5894
}
5995
}

test/dom.spec.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {_DOM} from '../src/dom';
2+
import {_FEATURE} from '../src/feature';
23

34
describe('dom', () => {
45
describe('createTemplateFromMarkup', () => {
@@ -13,11 +14,50 @@ describe('dom', () => {
1314
it('should throw an error when creating a template from markup where <template> is not the root element', () => {
1415
expect(() => _DOM.createTemplateFromMarkup('<div>throw an error!</div>')).toThrow();
1516
});
17+
18+
it('should call ensureTemplateElement', () => {
19+
spyOn(_FEATURE, 'ensureHTMLTemplateElement').and.callThrough();
20+
const template = _DOM.createTemplateFromMarkup('<template>this is valid!</template>');
21+
expect(_FEATURE.ensureHTMLTemplateElement).toHaveBeenCalledWith(template);
22+
});
1623
});
1724

1825
describe('createAttribute', () => {
1926
it('should create an attribute', () => {
2027
expect(() => _DOM.createAttribute('aurelia-app')).not.toBeFalsy();
2128
});
2229
});
30+
31+
describe('createTemplateElement', () => {
32+
it('should call ensureTemplateElement', () => {
33+
spyOn(_FEATURE, 'ensureHTMLTemplateElement').and.callThrough();
34+
const template =_DOM.createTemplateElement();
35+
expect(_FEATURE.ensureHTMLTemplateElement).toHaveBeenCalledWith(template);
36+
});
37+
});
38+
39+
describe('ensureHTMLTemplateElement', () => {
40+
it('should ensure child templates are properly cloned', () => {
41+
const template = _DOM.createTemplateFromMarkup(`
42+
<template>
43+
<template>child template</template>
44+
<p>other content</p>
45+
</template>
46+
`);
47+
const clone = template.content.cloneNode(true);
48+
const clonedChild = clone.querySelectorAll('template')[0];
49+
expect(clonedChild).toBeDefined();
50+
expect(clonedChild.content).toBeDefined();
51+
});
52+
53+
it('should ensure child templates added post creation are properly cloned', () => {
54+
const template = _DOM.createTemplateElement();
55+
const childTemplate = _DOM.createTemplateFromMarkup('<template>child template</template>');
56+
template.content.appendChild(childTemplate);
57+
const clone = template.content.cloneNode(true);
58+
const clonedChild = clone.querySelectorAll('template')[0];
59+
expect(clonedChild).toBeDefined();
60+
expect(clonedChild.content).toBeDefined();
61+
});
62+
});
2363
});

test/setup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
import 'aurelia-polyfills';
12
import {initialize} from '../src/index';
23
initialize();

0 commit comments

Comments
 (0)