Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(html): nested custom elements in template break indexing parts
  • Loading branch information
smalluban committed Jun 5, 2019
1 parent dd00d09 commit 4c2ee3f
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 25 deletions.
8 changes: 4 additions & 4 deletions src/template/core.js
Expand Up @@ -243,7 +243,7 @@ export function compileTemplate(rawParts, isSVG, styles) {
const data = dataMap.get(target, { type: 'function' });

if (template !== data.template) {
if (data.template) removeTemplate(target);
if (data.template || target.nodeType === Node.ELEMENT_NODE) removeTemplate(target);
data.lastArgs = null;

const fragment = document.importNode(applyShadyCSS(template, host.tagName).content, true);
Expand Down Expand Up @@ -283,10 +283,10 @@ export function compileTemplate(rawParts, isSVG, styles) {
renderIndex += 1;
}

data.startNode = fragment.childNodes[0];
data.endNode = fragment.childNodes[fragment.childNodes.length - 1];

if (target.nodeType === Node.TEXT_NODE) {
data.startNode = fragment.childNodes[0];
data.endNode = fragment.childNodes[fragment.childNodes.length - 1];

let previousChild = target;

let child = fragment.childNodes[0];
Expand Down
34 changes: 20 additions & 14 deletions src/template/utils.js
@@ -1,11 +1,10 @@
const map = new WeakMap();
export const dataMap = {
get(key, defaultValue) {
if (map.has(key)) {
return map.get(key);
}
const value = map.get(key);
if (value) return value;

if (defaultValue !== undefined) {
if (defaultValue) {
map.set(key, defaultValue);
}

Expand All @@ -28,19 +27,26 @@ export function getTemplateEnd(node) {
}

export function removeTemplate(target) {
const data = dataMap.get(target);
const startNode = data.startNode;
if (target.nodeType !== Node.TEXT_NODE) {
let child = target.childNodes[0];
while (child) {
target.removeChild(child);
child = target.childNodes[0];
}
} else {
const data = dataMap.get(target);

if (startNode) {
const endNode = getTemplateEnd(data.endNode);
if (data.startNode) {
const endNode = getTemplateEnd(data.endNode);

let node = startNode;
const lastNextSibling = endNode.nextSibling;
let node = data.startNode;
const lastNextSibling = endNode.nextSibling;

while (node) {
const nextSibling = node.nextSibling;
node.parentNode.removeChild(node);
node = nextSibling !== lastNextSibling && nextSibling;
while (node) {
const nextSibling = node.nextSibling;
node.parentNode.removeChild(node);
node = nextSibling !== lastNextSibling && nextSibling;
}
}
}
}
16 changes: 16 additions & 0 deletions test/spec/html.js
@@ -1,6 +1,7 @@
import { html } from '../../src/template';
import { createInternalWalker } from '../../src/template/core';
import define from '../../src/define';
import renderFactory from '../../src/render';
import { dispatch } from '../../src/utils';
import { test, resolveTimeout } from '../helpers';

Expand Down Expand Up @@ -61,6 +62,21 @@ describe('html:', () => {
expect(fragment.children[0].innerHTML).toBe('10');
});

it('replaces resolved nested custom element template', (done) => {
define('test-replace-trigger', {
render: renderFactory(() => html`content`, { shadowRoot: false }),
});

const render = flag => html`${flag && html`<test-replace-trigger></test-replace-trigger>`}<button></button>`;
render(true)(fragment);

resolveTimeout(() => {
render(false)(fragment);
expect(fragment.children.length).toBe(1);
done();
});
});

describe('attribute expression with combined text value', () => {
const render = (two, three) => html`<div name="test" class="class-one ${two} ${three}"></div>`;

Expand Down
12 changes: 5 additions & 7 deletions test/spec/render.js
Expand Up @@ -69,7 +69,7 @@ describe('render:', () => {
});

describe('options object with shadowRoot option', () => {
it('for false appends template to light DOM', (done) => {
it('for false renders template in light DOM', (done) => {
define('test-render-light-dom', {
testValue: true,
render: render(({ testValue }) => (testValue
Expand All @@ -86,16 +86,14 @@ describe('render:', () => {
<div>other content</div>
</test-render-light-dom>
`)(el => resolveRaf(() => {
expect(el.children.length).toBe(2);
expect(el.children[0].innerHTML).toBe('other content');
expect(el.children[1].innerHTML).toBe('true');
expect(el.children.length).toBe(1);
expect(el.children[0].innerHTML).toBe('true');

el.testValue = false;

return resolveRaf(() => {
expect(el.children.length).toBe(2);
expect(el.children[0].innerHTML).toBe('other content');
expect(el.children[1].innerHTML).toBe('false');
expect(el.children.length).toBe(1);
expect(el.children[0].innerHTML).toBe('false');
});
}))(done);
});
Expand Down

0 comments on commit 4c2ee3f

Please sign in to comment.