mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Store all dom tree data in __dom private storage; implement composed patching via a linked list.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user