Skip to content

Commit

Permalink
Fixes #2311, #2323: when elements are removed from their previous pos…
Browse files Browse the repository at this point in the history
…ition when they are added elsewhere, make sure to remove them from composed, not logical parent.
  • Loading branch information
Steven Orvell committed Aug 20, 2015
1 parent 0f8483d commit 3d93116
Show file tree
Hide file tree
Showing 3 changed files with 327 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/lib/dom-api.html
Expand Up @@ -289,7 +289,7 @@
this._updateInsertionPoints(root.host);
this._lazyDistribute(root.host);
} else if (ensureComposedRemoval) {
removeFromComposedParent(parent || node.parentNode, node);
removeFromComposedParent(node._composedParent, node);
}
},

Expand Down
325 changes: 325 additions & 0 deletions test/unit/polymer-dom-content.html
Expand Up @@ -29,6 +29,26 @@
</script>
</dom-module>

<dom-module id="x-dist-inside-deep-tree">
<template>
x-dist-inside-deep-tree
<div></div>
<div>
<div>
<div>
<div id="distWrapper"><content id="content"></content></div>
</div>
</div>
</div>
<div></div>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'x-dist-inside-deep-tree'});
});
</script>
</dom-module>

<dom-module id="x-no-dist">
<template><span id="static">x-no-dist</span></template>
<script>
Expand Down Expand Up @@ -191,6 +211,27 @@
</script>
</dom-module>

<dom-module id="x-repeat">
<template>
<x-dist-inside-deep-tree id="dist">
<template is="dom-repeat" items="{{items}}"><div>{{item}}</div></template>
</x-dist-inside-deep-tree>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-repeat',
properties: {
items: {
type: Array,
value: ["ITEM1", "ITEM2", "ITEM3"]
}
}
});
});
</script>
</dom-module>

<x-compose-lazy-no-dist><span>Child</span></x-compose-lazy-no-dist>


Expand Down Expand Up @@ -877,6 +918,290 @@
document.body.removeChild(h2);
});

test('moving children between distributing hosts (parsed child)', function() {
var div = document.createElement('div');
div.innerHTML = '<x-dist><div></div></x-dist>';
var h1 = div.firstChild;
var h2 = document.createElement('x-dist');
document.body.appendChild(div);
document.body.appendChild(h2);
Polymer.dom.flush();
var d = Polymer.dom(h1).firstElementChild;
assert.equal(d.localName, 'div');
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes().length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes().length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(div);
document.body.removeChild(h2);
});

test('moving children between distributing host and fragment', function() {
var h1 = document.createElement('x-dist');
var h2 = document.createDocumentFragment();;
document.body.appendChild(h1);
Polymer.dom.flush();
var d = document.createElement('div');
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(h1);
});

test('moving children between distributing host and fragment (parsed child)', function() {
var div = document.createElement('div');
div.innerHTML = '<x-dist><div></div></x-dist>';
var h1 = div.firstChild;
var h2 = document.createDocumentFragment();;
document.body.appendChild(h1);
Polymer.dom.flush();
var d = Polymer.dom(h1).firstElementChild;
assert.equal(d.localName, 'div');
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(h1);
});

test('moving children between distributing hosts with deep insertion points', function() {
var h1 = document.createElement('x-dist-inside-deep-tree');
var h2 = document.createElement('x-dist-inside-deep-tree');
document.body.appendChild(h1);
document.body.appendChild(h2);
Polymer.dom.flush();
var d = document.createElement('div');
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes().length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes().length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(h1);
document.body.removeChild(h2);
});

test('moving children between distributing hosts with deep insertion points (parsed child)', function() {
var div = document.createElement('div');
div.innerHTML = '<x-dist-inside-deep-tree><div></div></x-dist-inside-deep-tree>';
var h1 = div.firstChild;
var h2 = document.createElement('x-dist-inside-deep-tree');
document.body.appendChild(div);
document.body.appendChild(h2);
Polymer.dom.flush();
var d = Polymer.dom(h1).firstElementChild;
assert.equal(d.localName, 'div');
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes().length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes().length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.deepEqual(Polymer.dom(h2.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(div);
document.body.removeChild(h2);
});

test('moving children between distributing host with deep insertion and fragment', function() {
var h1 = document.createElement('x-dist-inside-deep-tree');
var h2 = document.createDocumentFragment();;
document.body.appendChild(h1);
Polymer.dom.flush();
var d = document.createElement('div');
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(h1);
});

test('moving children between distributing host with deep insertion and fragment (parsed child)', function() {
var div = document.createElement('div');
div.innerHTML = '<x-dist-inside-deep-tree><div></div></x-dist-inside-deep-tree>';
var h1 = div.firstChild;
var h2 = document.createDocumentFragment();;
document.body.appendChild(h1);
Polymer.dom.flush();
var d = Polymer.dom(h1).firstElementChild;
assert.equal(d.localName, 'div');
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
Polymer.dom(h1).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h1).childNodes.length, 1);
assert.equal(Polymer.dom(h1).firstElementChild, d);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes(), [d]);
assert.equal(Polymer.dom(h2).childNodes.length, 0);
Polymer.dom(h2).appendChild(d);
Polymer.dom.flush();
assert.equal(Polymer.dom(h2).childNodes.length, 1);
assert.equal(Polymer.dom(h2).firstElementChild, d);
assert.equal(Polymer.dom(h1).childNodes.length, 0);
assert.deepEqual(Polymer.dom(h1.$.content).getDistributedNodes().length, 0);
document.body.removeChild(h1);
});

test('moving an element containing a dom-repeat that distributes items', function() {
var x1 = document.createElement('x-repeat');
var div = document.createElement('div');
Polymer.dom(document.body).appendChild(x1);
Polymer.dom(document.body).appendChild(div);
Polymer.dom.flush();
assert.equal(Polymer.dom(x1.$.dist).children.length, 4);
if (x1.$.dist.shadyRoot) {
assert.equal(x1.$.dist.$.distWrapper.children.length, 4);
}
Polymer.dom(div).appendChild(x1);
Polymer.dom.flush();
assert.equal(Polymer.dom(x1.$.dist).children.length, 4);
if (x1.$.dist.shadyRoot) {
assert.equal(x1.$.dist.$.distWrapper.children.length, 4);
}
Polymer.dom(document.body).appendChild(x1);
Polymer.dom.flush();
assert.equal(Polymer.dom(x1.$.dist).children.length, 4);
if (x1.$.dist.shadyRoot) {
assert.equal(x1.$.dist.$.distWrapper.children.length, 4);
}
Polymer.dom(div).appendChild(x1);
Polymer.dom.flush();
assert.equal(Polymer.dom(x1.$.dist).children.length, 4);
if (x1.$.dist.shadyRoot) {
assert.equal(x1.$.dist.$.distWrapper.children.length, 4);
}
Polymer.dom(document.body).removeChild(div);
});

});

suite('multi-content mutations', function() {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/polymer-dom.js
Expand Up @@ -59,7 +59,7 @@ suite('Polymer.dom', function() {
Polymer.dom.flush();
assert.equal(Polymer.dom(el.$.container).querySelectorAll('*').length, 6, 'querySelectorAll finds repeated elements');
document.body.removeChild(el);
})
});

test('querySelector document', function() {
assert.ok(Polymer.dom().querySelector('body'));
Expand Down

0 comments on commit 3d93116

Please sign in to comment.