Skip to content

Commit

Permalink
Store all dom tree data in __dom private storage; implement compose…
Browse files Browse the repository at this point in the history
…d patching via a linked list.
  • Loading branch information
Steven Orvell committed Dec 15, 2015
1 parent d135fef commit 9a3bead
Show file tree
Hide file tree
Showing 5 changed files with 359 additions and 277 deletions.
224 changes: 100 additions & 124 deletions src/lib/dom-tree-api.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,101 +55,103 @@

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
Expand All @@ -160,20 +162,22 @@
// 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:
Expand All @@ -188,52 +192,60 @@
},

_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;
}

}

Expand All @@ -242,10 +254,6 @@
// to the tree for optional patching pluggability.
Polymer.TreeApi.Composed = {


ensureParentNodes: function(parent, children) {
},

getChildNodes: function(node) {
return Polymer.TreeApi.arrayCopyChildNodes(node);
},
Expand All @@ -254,38 +262,6 @@
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
Expand Down
Loading

0 comments on commit 9a3bead

Please sign in to comment.