Store all dom tree data in __dom private storage; implement composed patching via a linked list.

This commit is contained in:
Steven Orvell
2015-12-14 18:40:01 -08:00
parent d135fef14a
commit 9a3bead568
5 changed files with 360 additions and 278 deletions

View File

@@ -55,101 +55,103 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
Polymer.TreeApi.Logical = {
hasChildNodes: function(node) {
return Boolean(node.__childNodes !== undefined);
},
hasParentNode: function(node) {
return Boolean(node.__parentNode);
return Boolean(node.__dom && node.__dom.parentNode);
},
hasChildNodes: function(node) {
return Boolean(node.__dom && node.__dom.childNodes !== undefined);
},
getChildNodes: function(node) {
// note: we're distinguishing here between undefined and false-y:
// hasChildNodes uses undefined check to see if this element has logical
// children; the false-y check indicates whether or not we should rebuild
// the cached childNodes array.
if (this.hasChildNodes(node)) {
if (!node.__childNodes) {
node.__childNodes = [];
for (var n=node.__firstChild; n; n=n.__nextSibling) {
node.__childNodes.push(n);
}
}
return node.__childNodes;
} else {
// TODO(sorvell): it's more correct to `Composed.getChildNodes`
// instead of `childNodes` here but any trivial failure
//to use Polymer.dom will result in an error.
return node.childNodes;
return this.hasChildNodes(node) ? this._getChildNodes(node) :
node.childNodes;
},
_getChildNodes: function(node) {
if (!node.__dom.childNodes) {
node.__dom.childNodes = [];
for (var n=node.__dom.firstChild; n; n=n.__dom.nextSibling) {
node.__dom.childNodes.push(n);
}
}
return node.__dom.childNodes;
},
getParentNode: function(node) {
return node.__parentNode || TreeApi.Composed.getParentNode(node);
return node.__dom && node.__dom.parentNode || node.parentNode;
},
getFirstChild: function(node) {
return node.__firstChild || TreeApi.Composed.getFirstChild(node);
return node.__dom && node.__dom.firstChild || node.firstChild;
},
getLastChild: function(node) {
return node.__lastChild || TreeApi.Composed.getLastChild(node);
return node.__dom && node.__dom.lastChild || node.lastChild;
},
getNextSibling: function(node) {
return node.__nextSibling || TreeApi.Composed.getNextSibling(node);
return node.__dom && node.__dom.nextSibling || node.nextSibling;
},
getPreviousSibling: function(node) {
return node.__previousSibling || TreeApi.Composed.getPreviousSibling(node);
return node.__dom && node.__dom.previousSibling || node.previousSibling;
},
getFirstElementChild: function(node) {
if (node.__firstChild) {
var n = node.__firstChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__nextSibling;
}
return n;
} else {
return TreeApi.Composed.getFirstElementChild(node);
return node.__dom && node.__dom.firstChild ?
this._getFirstElementChild(node) : node.firstElementChild;
},
_getFirstElementChild: function(node) {
var n = node.__dom.firstChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.nextSibling;
}
return n;
},
getLastElementChild: function(node) {
if (node.__lastChild) {
var n = node.__lastChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__previousSibling;
}
return n;
} else {
return TreeApi.Composed.getLastElementChild(node);
return node.__dom && node.__dom.lastChild ?
this._getLastElementChild(node) : node.firstElementChild;
},
_getLastElementChild: function(node) {
var n = node.__dom.lastChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.previousSibling;
}
return n;
},
getNextElementSibling: function(node) {
if (node.__nextSibling) {
var n = node.__nextSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__nextSibling;
}
return n;
} else {
return TreeApi.Composed.getNextElementSibling(node);
return node.__dom && node.__dom.nextSibling ?
this._getNextElementSibling(node) : node.nextElementSibling;
},
_getNextElementSibling: function(node) {
var n = node.__dom.nextSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.nextSibling;
}
return n;
},
getPreviousElementSibling: function(node) {
if (node.__previousSibling) {
var n = node.__previousSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__previousSibling;
}
return n;
} else {
return TreeApi.Composed.getPreviousElementSibling(node);
return node.__dom && node.__dom.previousSibling ?
this._getPreviousElementSibling(node) : node.previousElementSibling;
},
_getPreviousElementSibling: function(node) {
var n = node.__dom.previousSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.previousSibling;
}
return n;
},
// Capture the list of light children. It's important to do this before we
@@ -160,20 +162,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// has been called.
saveChildNodes: function(node) {
if (!this.hasChildNodes(node)) {
node.__firstChild = node.firstChild;
node.__lastChild = node.lastChild;
node.__childNodes = [];
node.__dom = node.__dom || {};
node.__dom.firstChild = node.firstChild;
node.__dom.lastChild = node.lastChild;
node.__dom.childNodes = [];
for (var n=node.firstChild; n; n=n.nextSibling) {
n.__parentNode = node;
node.__childNodes.push(n);
n.__nextSibling = n.nextSibling;
n.__previousSibling = n.previousSibling;
n.__dom = n.__dom || {};
n.__dom.parentNode = node;
node.__dom.childNodes.push(n);
n.__dom.nextSibling = n.nextSibling;
n.__dom.previousSibling = n.previousSibling;
}
}
},
recordInsertBefore: function(node, container, ref_node) {
container.__childNodes = null;
container.__dom.childNodes = null;
// handle document fragments
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
// TODO(sorvell): remember this for patching:
@@ -188,52 +192,60 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
_linkNode: function(node, container, ref_node) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (ref_node) {
ref_node.__dom = ref_node.__dom || {};
}
// update ref_node.previousSibling <-> node
node.__previousSibling = ref_node ? ref_node.__previousSibling :
container.__lastChild;
if (node.__previousSibling) {
node.__previousSibling.__nextSibling = node;
node.__dom.previousSibling = ref_node ? ref_node.__dom.previousSibling :
container.__dom.lastChild;
if (node.__dom.previousSibling) {
node.__dom.previousSibling.__dom.nextSibling = node;
}
// update node <-> ref_node
node.__nextSibling = ref_node;
if (node.__nextSibling) {
node.__nextSibling.__previousSibling = node;
node.__dom.nextSibling = ref_node;
if (node.__dom.nextSibling) {
node.__dom.nextSibling.__dom.previousSibling = node;
}
// update node <-> container
node.__parentNode = container;
node.__dom.parentNode = container;
if (ref_node) {
if (ref_node === container.__firstChild) {
container.__firstChild = node;
if (ref_node === container.__dom.firstChild) {
container.__dom.firstChild = node;
}
} else {
container.__lastChild = node;
if (!container.__firstChild) {
container.__firstChild = node;
container.__dom.lastChild = node;
if (!container.__dom.firstChild) {
container.__dom.firstChild = node;
}
}
// remove caching of childNodes
container.__childNodes = null;
container.__dom.childNodes = null;
},
recordRemoveChild: function(node, container) {
if (node === container.__firstChild) {
container.__firstChild = node.__nextSibling;
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (node === container.__dom.firstChild) {
container.__dom.firstChild = node.__dom.nextSibling;
}
if (node === container.__lastChild) {
container.__lastChild = node.__previousSibling;
if (node === container.__dom.lastChild) {
container.__dom.lastChild = node.__dom.previousSibling;
}
var p = node.__previousSibling;
var n = node.__nextSibling;
var p = node.__dom.previousSibling;
var n = node.__dom.nextSibling;
if (p) {
p.__nextSibling = n;
p.__dom.nextSibling = n;
}
if (n) {
n.__previousSibling = p;
n.__dom.previousSibling = p;
}
node.__parentNode = node.__previousSibling = node.__nextSibling = null;
node.__dom.parentNode = node.__dom.previousSibling =
node.__dom.nextSibling = null;
// remove caching of childNodes
container.__childNodes = null;
},
container.__dom.childNodes = null;
}
}
@@ -242,10 +254,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// to the tree for optional patching pluggability.
Polymer.TreeApi.Composed = {
ensureParentNodes: function(parent, children) {
},
getChildNodes: function(node) {
return Polymer.TreeApi.arrayCopyChildNodes(node);
},
@@ -254,38 +262,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return node.parentNode;
},
getFirstChild: function(node) {
return node.firstChild;
},
getLastChild: function(node) {
return node.lastChild;
},
getNextSibling: function(node) {
return node.nextSibling;
},
getPreviousSibling: function(node) {
return node.previousSibling;
},
getFirstElementChild: function(node) {
return node.firstElementChild;
},
getLastElementChild: function(node) {
return node.lastElementChild;
},
getNextElementSibling: function(node) {
return node.nextElementSibling;
},
getPreviousElementSibling: function(node) {
return node.previousElementSibling;
},
// composed tracking needs to reset composed children here in case
// they may have already been set (this shouldn't happen but can
// if dependency ordering is incorrect and as a result upgrade order

View File

@@ -245,24 +245,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// NOTE: patch logical implementations here so we can use
// composed getters
Polymer.TreeApi.Logical.saveChildNodes = function(node) {
TreeApi.Logical.saveChildNodes = function(node) {
if (!this.hasChildNodes(node)) {
node.__firstChild = node.firstChild;
node.__lastChild = node.lastChild;
node.__childNodes = [];
if (!node.__dom) {
node.__dom = {};
}
node.__dom.firstChild = node.firstChild;
node.__dom.lastChild = node.lastChild;
node.__dom.childNodes = [];
for (var n=TreeApi.Composed.getFirstChild(node); n;
n=TreeApi.Composed.getNextSibling(n)) {
n.__parentNode = node;
node.__childNodes.push(n);
n.__nextSibling = TreeApi.Composed.getNextSibling(n);
n.__previousSibling = TreeApi.Composed.getPreviousSibling(n);
n.__dom = n.__dom || {};
n.__dom.parentNode = node;
node.__dom.childNodes.push(n);
n.__dom.nextSibling = TreeApi.Composed.getNextSibling(n);
n.__dom.previousSibling = TreeApi.Composed.getPreviousSibling(n);
}
}
}
Polymer.TreeApi.Logical.recordInsertBefore =
function(node, container, ref_node) {
container.__childNodes = null;
TreeApi.Logical.recordInsertBefore = function(node, container, ref_node) {
container.__dom.childNodes = null;
// handle document fragments
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
// TODO(sorvell): remember this for patching:
@@ -277,160 +280,265 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
}
Polymer.TreeApi.Composed = {
TreeApi.Logical.getChildNodes = function(node) {
if (this.hasChildNodes(node)) {
return this._getChildNodes(node);
} else {
// TODO(sorvell): it's more correct to `Composed.getChildNodes`
// instead of `childNodes` here but any trivial failure
//to use Polymer.dom will result in an error.
return node.childNodes;
}
};
TreeApi.Logical.getParentNode = function(node) {
return node.__dom && node.__dom.parentNode ||
TreeApi.Composed.getParentNode(node);
};
TreeApi.Logical.getFirstChild = function(node) {
return node.__dom && node.__dom.firstChild ||
TreeApi.Composed.getFirstChild(node);
};
TreeApi.Logical.getLastChild = function(node) {
return node.__dom && node.__dom.lastChild ||
TreeApi.Composed.getLastChild(node);
};
TreeApi.Logical.getNextSibling = function(node) {
return node.__dom && node.__dom.nextSibling ||
TreeApi.Composed.getNextSibling(node);
};
TreeApi.Logical.getPreviousSibling = function(node) {
return node.__dom && node.__dom.previousSibling ||
TreeApi.Composed.getPreviousSibling(node);
};
TreeApi.Logical.getFirstElementChild = function(node) {
return node.__dom && node.__dom.firstChild ?
this._getFirstElementChild(node) :
TreeApi.Composed.getFirstElementChild(node);
};
TreeApi.Logical.getLastElementChild = function(node) {
return node.__dom && node.__dom.lastChild ?
this._getLastElementChild(node) :
TreeApi.Composed.getLastElementChild(node);
};
TreeApi.Logical.getNextElementSibling = function(node) {
return node.__dom && node.__dom.nextSibling ?
this._getNextElementSibling(node) :
TreeApi.Composed.getNextElementSibling(node);
};
TreeApi.Logical.getPreviousElementSibling = function(node) {
return node.__dom && node.__dom.previousSibling ?
this._getPreviousElementSibling(node) :
TreeApi.Composed.getPreviousElementSibling(node);
};
TreeApi.Composed = {
hasParentNode: function(node) {
return Boolean(node.__composedParent !== undefined);
return Boolean(node.__dom && node.__dom.$parentNode !== undefined);
},
hasChildNodes: function(node) {
return Boolean(node.__composedChildNodes !== undefined);
return Boolean(node.__dom && node.__dom.$childNodes !== undefined);
},
getChildNodes: function(node) {
return node.__composedChildNodes ||
return node.__dom.$childNodes ||
(!node.__patched && TreeApi.arrayCopy(node.childNodes));
},
getComposedChildNodes: function(node) {
return node.__composedChildNodes;
return node.__dom.$childNodes;
},
getParentNode: function(node) {
return this.hasParentNode(node) ? node.__composedParent :
return this.hasParentNode(node) ? node.__dom.$parentNode :
(!node.__patched && node.parentNode);
},
getFirstChild: function(node) {
if (node.__patched) {
return this.getChildNodes(node)[0];
} else {
return node.firstChild;
}
return node.__patched ? node.__dom.$firstChild : node.firstChild;
},
getLastChild: function(node) {
if (node.__patched) {
var c$ = this.getChildNodes(node);
return c$[c$.length-1];
} else {
return node.lastChild;
}
return node.__patched ? node.__dom.$lastChild : node.lastChild;
},
getNextSibling: function(node) {
// TODO(sorvell): linked list
var parent = this.getParentNode(node);
if (parent.__patched) {
var c$ = this.getChildNodes(parent);
var i = c$.indexOf(node);
return c$[i+1];
} else if (!node.__patched) {
return node.nextSibling;
}
return node.__patched ? node.__dom.$nextSibling : node.nextSibling;
},
getPreviousSibling: function(node) {
// TODO(sorvell): linked list
var parent = this.getParentNode(node);
if (parent.__patched) {
var c$ = this.getChildNodes(parent);
var i = c$.indexOf(node);
return c$[i-1];
} else if (!node.__patched) {
return node.previousSibling;
}
return node.__patched ? node.__dom.$previousSibling : node.previousSibling;
},
getFirstElementChild: function(node) {
if (node.__patched) {
var c$ = this.getChildNodes(node);
for (var i=0, n; i < c$.length; i++) {
n = c$[i];
if (n.nodeType === Node.ELEMENT_NODE) {
return n;
}
}
} else {
return node.firstElementChild;
return node.__patched ? this._getFirstElementChild(node) :
node.firstElementChild;
},
_getFirstElementChild: function(node) {
var n = node.__dom.$firstChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.$nextSibling;
}
return n;
},
getLastElementChild: function(node) {
if (node.__patched) {
var c$ = this.getChildNodes(node);
for (var i=c$.length, n; i >=0 ; i--) {
n = c$[i];
if (n.nodeType === Node.ELEMENT_NODE) {
return n;
}
}
} else {
return node.lastElementChild;
return node.__patched ? this._getLastElementChild(node) :
node.firstElementChild;
},
_getLastElementChild: function(node) {
var n = node.__dom.$lastChild;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.$previousSibling;
}
return n;
},
getNextElementSibling: function(node) {
if (node.__patched) {
var c$ = this.getChildNodes(node);
var i = c$.indexOf(node);
if (i >= 0) {
for (var n; i < c$.length; i++) {
n = c$[i];
if (n.nodeType === Node.ELEMENT_NODE) {
return n;
}
}
}
} else {
return node.nextElementSibling;
return node.__patched ? this._getNextElementSibling(node) :
node.nextElementSibling;
},
_getNextElementSibling: function(node) {
var n = node.__dom.$nextSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.$nextSibling;
}
return n;
},
getPreviousElementSibling: function(node) {
if (node.__patched) {
var c$ = this.getChildNodes(node);
var i = c$.indexOf(node);
if (i >= 0) {
for (var n; i >=0 ; i--) {
n = c$[i];
if (n.nodeType === Node.ELEMENT_NODE) {
return n;
}
}
return node.__patched ? this._getPreviousElementSibling(node) :
node.previousElementSibling;
},
_getPreviousElementSibling: function(node) {
var n = node.__dom.$previousSibling;
while (n && n.nodeType !== Node.ELEMENT_NODE) {
n = n.__dom.$previousSibling;
}
return n;
},
saveChildNodes: function(node) {
if (!this.hasChildNodes(node)) {
node.__dom = node.__dom || {};
node.__dom.$firstChild = node.firstChild;
node.__dom.$lastChild = node.lastChild;
node.__dom.$childNodes = [];
for (var n=node.firstChild; n; n=n.nextSibling) {
n.__dom = n.__dom || {};
n.__dom.$parentNode = node;
node.__dom.$childNodes.push(n);
n.__dom.$nextSibling = n.nextSibling;
n.__dom.$previousSibling = n.previousSibling;
}
}
},
recordInsertBefore: function(node, container, ref_node) {
container.__dom.$childNodes = null;
// handle document fragments
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
// TODO(sorvell): remember this for patching:
// the act of setting this info can affect patched nodes
// getters; therefore capture childNodes before patching.
for (var n=this.getFirstChild(node); n; n=this.getNextSibling(n)) {
this._linkNode(n, container, ref_node);
}
} else {
return node.previousElementSibling;
this._linkNode(node, container, ref_node);
}
},
_linkNode: function(node, container, ref_node) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (ref_node) {
ref_node.__dom = ref_node.__dom || {};
}
// update ref_node.previousSibling <-> node
node.__dom.$previousSibling = ref_node ? ref_node.__dom.$previousSibling :
container.__dom.$lastChild;
if (node.__dom.$previousSibling) {
node.__dom.$previousSibling.__dom.$nextSibling = node;
}
// update node <-> ref_node
node.__dom.$nextSibling = ref_node;
if (node.__dom.$nextSibling) {
node.__dom.$nextSibling.__dom.$previousSibling = node;
}
// update node <-> container
node.__dom.$parentNode = container;
if (ref_node) {
if (ref_node === container.__dom.$firstChild) {
container.__dom.$firstChild = node;
}
} else {
container.__dom.$lastChild = node;
if (!container.__dom.$firstChild) {
container.__dom.$firstChild = node;
}
}
// remove caching of childNodes
container.__dom.$childNodes = null;
},
recordRemoveChild: function(node, container) {
node.__dom = node.__dom || {};
container.__dom = container.__dom || {};
if (node === container.__dom.$firstChild) {
container.__dom.$firstChild = node.__dom.$nextSibling;
}
if (node === container.__dom.$lastChild) {
container.__dom.$lastChild = node.__dom.$previousSibling;
}
var p = node.__dom.$previousSibling;
var n = node.__dom.$nextSibling;
if (p) {
p.__dom.$nextSibling = n;
}
if (n) {
n.__dom.$previousSibling = p;
}
node.__dom.$parentNode = node.__dom.$previousSibling =
node.__dom.$nextSibling = null;
// remove caching of childNodes
container.__dom.$childNodes = null;
},
// composed tracking needs to reset composed children here in case
// they may have already been set (this shouldn't happen but can
// if dependency ordering is incorrect and as a result upgrade order
// is unexpected)
clearChildNodes: function(node) {
if (node.__composedParent) {
node.__composedParent.__composedChildNodes = [];
if (node.__dom && node.__dom.$parentNode) {
node.__dom.$parentNode.__dom.$childNodes = [];
}
node.textContent = '';
},
saveChildNodes: function(node) {
var c$ = node.__composedChildNodes = [];
for (var n=node.firstChild; n; n=n.nextSibling) {
n.__composedParent = node;
c$.push(n);
}
},
saveParentNode: function(node) {
node.__composedParent = node.parentNode;
node.__dom = node.__dom || {};
node.__dom.$parentNode = node.parentNode;
},
insertBefore: function(parentNode, newChild, refChild) {
if (!this.hasChildNodes(parentNode)) {
this.saveChildNodes(parentNode);
}
this.saveChildNodes(parentNode);
// remove from current location.
if (this.hasParentNode(newChild)) {
var oldParent = this.getParentNode(newChild);
@@ -443,9 +551,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
appendChild: function(parentNode, newChild) {
if (!this.hasChildNodes(parentNode)) {
this.saveChildNodes(parentNode);
}
this.saveChildNodes(parentNode);
// remove from current location.
if (this.hasParentNode(newChild)) {
var oldParent = this.getParentNode(newChild);
@@ -459,13 +565,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
removeChild: function(parentNode, node) {
var currentParent = this.getParentNode(node);
if (!this.hasChildNodes(parentNode)) {
this.saveChildNodes(parentNode);
}
this.saveChildNodes(parentNode);
this._removeChild(parentNode, node);
if (currentParent === parentNode) {
// TODO(sorvell); abort if the composedParent is not expected...
if (!node.__patched && node.parentNode !== node.__composedParent) {
if (!node.__patched && node.parentNode !== node.__dom.$parentNode) {
return;
}
return nativeRemoveChild.call(parentNode, node);
@@ -479,7 +583,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
this._addChild(parentNode, c$[j], refChild);
}
} else {
newChild.__composedParent = parentNode;
newChild.__dom = newChild.__dom || {};
newChild.__dom.$parentNode = parentNode;
var c$ = this.getComposedChildNodes(parentNode);
if (c$) {
var i = c$.indexOf(refChild);
@@ -490,7 +595,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
_removeChild: function(parentNode, node) {
node.__composedParent = null;
node.__dom = node.__dom || {};
node.__dom.$parentNode = null;
var c$ = this.getComposedChildNodes(parentNode);
if (c$) {
var i = c$.indexOf(node);

View File

@@ -40,6 +40,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (!this.__domApi) {
this.__domApi = null;
}
if (!this.__dom) {
this.__dom = null;
}
if (!this._ownerShadyRoot) {
this._ownerShadyRoot = undefined;
}
@@ -417,7 +420,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
// dirty a shadyRoot if a change may trigger reprojection!
function maybeRedistributeParent(content, host) {
var parent = content.__parentNode;
// only get logical parent.
var parent = TreeApi.Logical.hasParentNode(content) &&
TreeApi.Logical.getParentNode(content);
if (parent && parent.shadyRoot &&
DomApi.hasInsertionPoint(parent.shadyRoot) &&
parent.shadyRoot._distributionClean) {

View File

@@ -251,19 +251,19 @@ suite('Polymer.dom (patch)', function() {
assert.equal(s.parentNode, rere);
Polymer.dom.flush();
if (rere.shadyRoot) {
assert.notEqual(s.__composedParent, rere);
assert.notEqual(s.__dom.$parentNode, rere);
}
Polymer.dom.flush();
if (rere.shadyRoot) {
assert.equal(s.__composedParent, p);
assert.equal(s.__dom.$parentNode, p);
}
rere.removeChild(s);
if (rere.shadyRoot) {
assert.equal(s.__composedParent, p);
assert.equal(s.__dom.$parentNode, p);
}
Polymer.dom.flush();
if (rere.shadyRoot) {
assert.equal(s.__composedParent, null);
assert.equal(s.__dom.$parentNode, null);
}
});
@@ -343,13 +343,13 @@ suite('Polymer.dom non-distributed elements', function() {
function testNoAttr() {
assert.equal(Polymer.dom(child).getDestinationInsertionPoints()[0], d.$.notTestContent, 'child not distributed logically');
if (shady) {
assert.equal(child.__composedParent, d.$.notTestContainer, 'child not rendered in composed dom');
assert.equal(child.__dom.$parentNode, d.$.notTestContainer, 'child not rendered in composed dom');
}
}
function testWithAttr() {
assert.equal(Polymer.dom(child).getDestinationInsertionPoints()[0], d.$.testContent, 'child not distributed logically');
if (shady) {
assert.equal(child.__composedParent, d.$.testContainer, 'child not rendered in composed dom');
assert.equal(child.__dom.$parentNode, d.$.testContainer, 'child not rendered in composed dom');
}
}
// test with x-distribute

View File

@@ -135,14 +135,14 @@ test('Reproject', function() {
assert.strictEqual(getComposedHTML(host),
'<x-content-test id="p">a: <a></a>b: <b></b></x-content-test>');
assertArrayEqual(host.__childNodes, [a]);
assert.strictEqual(a.__parentNode, host);
assertArrayEqual(host.shadyRoot.__childNodes, [p]);
assert.strictEqual(p.__parentNode, host.shadyRoot);
assertArrayEqual(p.__childNodes, [b, content]);
assert.strictEqual(b.__parentNode, p);
assert.strictEqual(content.__parentNode, p);
assertArrayEqual(p.shadyRoot.__childNodes,
assertArrayEqual(host.__dom.childNodes, [a]);
assert.strictEqual(a.__dom.parentNode, host);
assertArrayEqual(host.shadyRoot.__dom.childNodes, [p]);
assert.strictEqual(p.__dom.parentNode, host.shadyRoot);
assertArrayEqual(p.__dom.childNodes, [b, content]);
assert.strictEqual(b.__dom.parentNode, p);
assert.strictEqual(content.__dom.parentNode, p);
assertArrayEqual(p.shadyRoot.__dom.childNodes,
[textNodeA, contentA, textNodeB, contentB]);
}
@@ -165,7 +165,7 @@ suite('Mutate light DOM', function() {
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a></a>');
host.__childNodes = [];
host.__dom.childNodes = [];
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), 'fallback');
});
@@ -180,11 +180,11 @@ suite('Mutate light DOM', function() {
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');
host.shadyRoot.__childNodes[1].textContent = '';
host.shadyRoot.__dom.childNodes[1].textContent = '';
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
host.shadyRoot.__childNodes = [];
host.shadyRoot.__dom.childNodes = [];
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
});
@@ -203,11 +203,11 @@ suite('Mutate light DOM', function() {
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<b></b>');
host.shadyRoot.firstChild.__childNodes = [];
host.shadyRoot.firstChild.__dom.childNodes = [];
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
host.shadyRoot.__childNodes = [];
host.shadyRoot.__dom.childNodes = [];
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
});
@@ -225,7 +225,7 @@ suite('Mutate light DOM', function() {
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a></a>');
host.__childNodes = [];
host.__dom.childNodes = [];
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), 'fallback');
});
@@ -265,11 +265,11 @@ suite('Mutate light DOM', function() {
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
host.shadyRoot.__childNodes.splice(1, 1); // remove b
host.shadyRoot.__dom.childNodes.splice(1, 1); // remove b
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.shadyRoot.__childNodes = []; // remove a
host.shadyRoot.__dom.childNodes = []; // remove a
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '');
});
@@ -368,7 +368,7 @@ suite('Mutate light DOM', function() {
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
host.__childNodes[0] = b;
host.__dom.childNodes[0] = b;
distributeContentNow(host);
assert.strictEqual(getComposedHTML(host), '<b></b>');
});
@@ -437,16 +437,17 @@ suite('Mutate light DOM', function() {
});
function syncLightDOM(n) {
if (n.__childNodes) {
var c$ = n.__patched ? n._composedChildren || [] : Array.prototype.slice.call(n.childNodes);
n.__firstChild = c$[0];
n.__lastChild = c$[c$.length-1];
if (n.__dom.childNodes !== undefined) {
var c$ = Array.prototype.slice.call(n.childNodes);
n.__dom.firstChild = c$[0];
n.__dom.lastChild = c$[c$.length-1];
c$.forEach(function(c, i) {
if (n.__childNodes.indexOf(c) < 0) {
c.__parentNode = n;
c.__previousSibling = c$[i-1];
c.__nextSibling = c$[i+1];
n.__childNodes.push(c);
if (n.__dom.childNodes.indexOf(c) < 0) {
c.__dom = c.__dom || {};
c.__dom.parentNode = n;
c.__dom.previousSibling = c$[i-1];
c.__dom.nextSibling = c$[i+1];
n.__dom.childNodes.push(c);
}
});
}
@@ -456,17 +457,11 @@ var nativeAppendChild = Element.prototype.appendChild;
function setInnerHTML(node, value) {
node.textContent = '';
if (node._composedChildren) {
node._composedChildren = [];
}
var temp = node.ownerDocument.createElement('div');
temp.innerHTML = value;
var firstChild;
while (firstChild = temp.firstChild) {
nativeAppendChild.call(node, firstChild);
if (node._composedChildren) {
node._composedChildren.push(firstChild);
}
}
}
@@ -481,11 +476,11 @@ function updateRootInsertionPoints(root) {
}
function getComposedHTML(node) {
return node.__patched ? Polymer.domInnerHTML.getInnerHTML(node, true) : node.innerHTML;
return node.innerHTML;
}
function getComposedChildAtIndex(node, index) {
var c$ = node._composedChildren || node.childNodes;
var c$ = node.childNodes;
if (c$) {
index = index || 0;
index = Math.max(0, Math.min(index, c$.length-1));