Skip to content

Commit

Permalink
fix(html-template-element): fix template.content.cloneNode
Browse files Browse the repository at this point in the history
where native support is missing fix aurelia/templating#569
  • Loading branch information
StrahilKazlachev committed Jan 1, 2018
1 parent c60c394 commit fd5331f
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 5 deletions.
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = function(config) {

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


Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"aurelia-pal": "^1.4.0"
},
"devDependencies": {
"aurelia-polyfills": "^1.1.1",
"babel": "babel-core@^5.8.22",
"babel-runtime": "^5.8.20",
"core-js": "^2.0.3"
Expand All @@ -42,6 +43,7 @@
"aurelia-pal": "^1.4.0"
},
"devDependencies": {
"aurelia-polyfills": "^1.1.1",
"aurelia-tools": "^0.2.4",
"babel-dts-generator": "^0.6.1",
"babel-eslint": "^6.1.2",
Expand Down Expand Up @@ -74,6 +76,7 @@
"karma-babel-preprocessor": "^6.0.1",
"karma-chrome-launcher": "^1.0.1",
"karma-coverage": "^1.1.1",
"karma-ie-launcher": "^1.0.0",
"karma-jasmine": "^1.0.2",
"karma-jspm": "^2.2.0",
"merge2": "^1.0.2",
Expand Down
44 changes: 40 additions & 4 deletions src/html-template-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {_FEATURE} from './feature';
if (typeof FEATURE_NO_IE === 'undefined') {
function isSVGTemplate(el) {
return el.tagName === 'template' &&
el.namespaceURI === 'http://www.w3.org/2000/svg';
el.namespaceURI === 'http://www.w3.org/2000/svg';
}

function fixSVGTemplateElement(el) {
Expand Down Expand Up @@ -36,9 +36,42 @@ if (typeof FEATURE_NO_IE === 'undefined') {
return template;
}

// replaces a #document-fragment .cloneNode
function __safeCloneNode(deep) {
const clone = this.standardCloneNode(deep);
if (deep) {
if (!this.__templates) {
// cache child templates on first call
// fix child templates on first call
this.__templates = this.querySelectorAll('template');
let i = this.__templates.length;
while (i--) {
installSafeCloneNode(this.__templates.item(i));
}
}
if (this.__templates.length) {
const clonedTemplates = clone.querySelectorAll('template');
let i = clonedTemplates.length;
while (i--) {
clonedTemplates.item(i).content = this.__templates.item(i).content;
}
}
}
return clone;
}

function installSafeCloneNode(template) {
if (!template.content.__safeToCloneNode) {
template.content.standardCloneNode = template.content.cloneNode;
template.content.cloneNode = __safeCloneNode;
template.content.__safeToCloneNode = true;
}
return template;
}

function fixHTMLTemplateElementRoot(template) {
let content = fixHTMLTemplateElement(template).content;
let childTemplates = content.querySelectorAll('template');
const content = fixHTMLTemplateElement(template).content;
const childTemplates = content.querySelectorAll('template');

for (let i = 0, ii = childTemplates.length; i < ii; ++i) {
let child = childTemplates[i];
Expand All @@ -48,12 +81,15 @@ if (typeof FEATURE_NO_IE === 'undefined') {
} else {
fixHTMLTemplateElement(child);
}
// installSafeCloneNode(child);
}

installSafeCloneNode(template);

return template;
}

if (!_FEATURE.htmlTemplateElement) {
if (!_FEATURE.htmlTemplateElement) {
_FEATURE.ensureHTMLTemplateElement = fixHTMLTemplateElementRoot;
}
}
40 changes: 40 additions & 0 deletions test/dom.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {_DOM} from '../src/dom';
import {_FEATURE} from '../src/feature';

describe('dom', () => {
describe('createTemplateFromMarkup', () => {
Expand All @@ -13,11 +14,50 @@ describe('dom', () => {
it('should throw an error when creating a template from markup where <template> is not the root element', () => {
expect(() => _DOM.createTemplateFromMarkup('<div>throw an error!</div>')).toThrow();
});

it('should call ensureTemplateElement', () => {
spyOn(_FEATURE, 'ensureHTMLTemplateElement').and.callThrough();
const template = _DOM.createTemplateFromMarkup('<template>this is valid!</template>');
expect(_FEATURE.ensureHTMLTemplateElement).toHaveBeenCalledWith(template);
});
});

describe('createAttribute', () => {
it('should create an attribute', () => {
expect(() => _DOM.createAttribute('aurelia-app')).not.toBeFalsy();
});
});

describe('createTemplateElement', () => {
it('should call ensureTemplateElement', () => {
spyOn(_FEATURE, 'ensureHTMLTemplateElement').and.callThrough();
const template =_DOM.createTemplateElement();
expect(_FEATURE.ensureHTMLTemplateElement).toHaveBeenCalledWith(template);
});
});

describe('ensureHTMLTemplateElement', () => {
it('should ensure child templates are properly cloned', () => {
const template = _DOM.createTemplateFromMarkup(`
<template>
<template>child template</template>
<p>other content</p>
</template>
`);
const clone = template.content.cloneNode(true);
const clonedChild = clone.querySelectorAll('template')[0];
expect(clonedChild).toBeDefined();
expect(clonedChild.content).toBeDefined();
});

it('should ensure child templates added post creation are properly cloned', () => {
const template = _DOM.createTemplateElement();
const childTemplate = _DOM.createTemplateFromMarkup('<template>child template</template>');
template.content.appendChild(childTemplate);
const clone = template.content.cloneNode(true);
const clonedChild = clone.querySelectorAll('template')[0];
expect(clonedChild).toBeDefined();
expect(clonedChild.content).toBeDefined();
});
});
});
1 change: 1 addition & 0 deletions test/setup.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
import 'aurelia-polyfills';
import {initialize} from '../src/index';
initialize();

0 comments on commit fd5331f

Please sign in to comment.