|
|
|
@ -1,9 +1,10 @@
|
|
|
|
|
define([], function () {
|
|
|
|
|
var tree = {};
|
|
|
|
|
|
|
|
|
|
tree.some = function (branch, predicate) {
|
|
|
|
|
// take the index of the last element in the current branch
|
|
|
|
|
var last = branch.childElementCount - 1;
|
|
|
|
|
// FIXME this isn't being used
|
|
|
|
|
var someElement = tree.some = function (root, predicate) {
|
|
|
|
|
// take the index of the last element in the current root
|
|
|
|
|
var last = root.childElementCount - 1;
|
|
|
|
|
|
|
|
|
|
// it might be a leaf node
|
|
|
|
|
if (last < 0) { return false; }
|
|
|
|
@ -14,12 +15,12 @@ define([], function () {
|
|
|
|
|
|
|
|
|
|
// check the node's children (depth first)
|
|
|
|
|
// if the predicate tests true, return true
|
|
|
|
|
if (tree.some(branch.children[last], predicate)) {
|
|
|
|
|
if (tree.some(root.children[last], predicate)) {
|
|
|
|
|
return true;
|
|
|
|
|
} // otherwise none of the nodes inside it matched.
|
|
|
|
|
|
|
|
|
|
// check the node itself
|
|
|
|
|
if (predicate(branch.children[last], last)) {
|
|
|
|
|
if (predicate(root.children[last], last)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
last--;
|
|
|
|
@ -27,9 +28,10 @@ define([], function () {
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.someIncludingText = function (branch, predicate) {
|
|
|
|
|
// take the index of the last element in the current branch
|
|
|
|
|
var last = branch.childNodes.length - 1;
|
|
|
|
|
// FIXME this isn't being used
|
|
|
|
|
var someText = tree.someIncludingText = function (root, predicate) {
|
|
|
|
|
// take the index of the last element in the current root
|
|
|
|
|
var last = root.childNodes.length - 1;
|
|
|
|
|
|
|
|
|
|
// it might be a leaf node
|
|
|
|
|
if (last < 0) { return false; }
|
|
|
|
@ -40,12 +42,12 @@ define([], function () {
|
|
|
|
|
|
|
|
|
|
// check the node's children (depth first)
|
|
|
|
|
// if the predicate tests true, return true
|
|
|
|
|
if (tree.someIncludingText(branch.childNodes[last], predicate)) {
|
|
|
|
|
if (tree.someIncludingText(root.childNodes[last], predicate)) {
|
|
|
|
|
return true;
|
|
|
|
|
} // otherwise none of the nodes inside it matched.
|
|
|
|
|
|
|
|
|
|
// check the node itself
|
|
|
|
|
if (predicate(branch.childNodes[last], last)) {
|
|
|
|
|
if (predicate(root.childNodes[last], last)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
last--;
|
|
|
|
@ -53,6 +55,7 @@ define([], function () {
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// FIXME not being used
|
|
|
|
|
tree.findSameHierarchy = function (list, ancestor) {
|
|
|
|
|
var i = 0;
|
|
|
|
|
var success = true;
|
|
|
|
@ -90,117 +93,74 @@ define([], function () {
|
|
|
|
|
return Array.prototype.indexOf.call(el.parentNode.childNodes, el);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// not being used internally, but is useful externally
|
|
|
|
|
tree.contains = function (el, root) {
|
|
|
|
|
return el && root.contains && root.contains(el);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var siblingCount = tree.siblingCount = function (el) {
|
|
|
|
|
return el.parentNodes.childNodes.length;
|
|
|
|
|
return el.parentNode.childNodes.length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var childCount = tree.childCount = function (el) {
|
|
|
|
|
return el.childNodes.length;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var parentsOf = tree.parentsOf = function (el, root) {
|
|
|
|
|
var P = [];
|
|
|
|
|
var p = el;
|
|
|
|
|
while (p !== root) { P.push((p = p.parentNode)); }
|
|
|
|
|
return P;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var deepestNode = tree.deepestNode = function (el) {
|
|
|
|
|
var deepest = el.childNodes.length;
|
|
|
|
|
if (!deepest) { // no children
|
|
|
|
|
/* rightmost and leftmost return the deepest right and left
|
|
|
|
|
leaf nodes of a tree
|
|
|
|
|
*/
|
|
|
|
|
var rightmostNode = tree.rightmostNode = function (el) {
|
|
|
|
|
var childNodeCount = childCount(el);
|
|
|
|
|
if (!childNodeCount) { // no children
|
|
|
|
|
return el; // return the element
|
|
|
|
|
} else {
|
|
|
|
|
return deepestNode(el.childNodes[deepest - 1]);
|
|
|
|
|
return rightmostNode(el.childNodes[childNodeCount - 1]);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var leftMostNode = tree.leftMostNode = function (el) {
|
|
|
|
|
var left = el.childNodes[0];
|
|
|
|
|
if (el.childNodes.length) {
|
|
|
|
|
return leftMostNode(el.childNodes[0]);
|
|
|
|
|
var leftmostNode = tree.leftmostNode = function (el) {
|
|
|
|
|
if (childCount(el)) {
|
|
|
|
|
return leftmostNode(el.childNodes[0]);
|
|
|
|
|
} else {
|
|
|
|
|
return el;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* previousNode and nextNode traverse child elements of the dom
|
|
|
|
|
in the order in which they appear when selected by a cursor.
|
|
|
|
|
in particular, these algorithms traverse text nodes, not just tags
|
|
|
|
|
*/
|
|
|
|
|
var previousNode = tree.previousNode = function (el, root) {
|
|
|
|
|
if (!el || el === root) { return null; }
|
|
|
|
|
|
|
|
|
|
var i = indexOfNode(el);
|
|
|
|
|
if (!el.parentNode) { return null; }
|
|
|
|
|
if (i === 0) {
|
|
|
|
|
|
|
|
|
|
if (root && el.parentNode === root.childNodes[0]) { return null; }
|
|
|
|
|
return deepestNode(previousNode(el.parentNode));
|
|
|
|
|
return rightmostNode(previousNode(el.parentNode));
|
|
|
|
|
} else {
|
|
|
|
|
return el.parentNode.childNodes[i-1];
|
|
|
|
|
return rightmostNode(el.parentNode.childNodes[i-1])
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* includes text elements */
|
|
|
|
|
var nextNode = tree.nextNode = function (el, root) {
|
|
|
|
|
if (!el || el === root) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (!el || el === root) { return null; }
|
|
|
|
|
var i = indexOfNode(el) + 1, // the index of the next node
|
|
|
|
|
l = el.parentNode.childNodes.length;
|
|
|
|
|
l = siblingCount(el);
|
|
|
|
|
if (i === l) { // out of bounds
|
|
|
|
|
return leftMostNode(nextNode(el.parentNode, root));
|
|
|
|
|
if (el.parentNode === root) { return null; }
|
|
|
|
|
return nextNode(el.parentNode, root);
|
|
|
|
|
} else {
|
|
|
|
|
return el.parentNode.childNodes[i];
|
|
|
|
|
return leftmostNode(el.parentNode.childNodes[i], root);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.recoverElement = function (el, root) {
|
|
|
|
|
var tags = tree.tagsUntilElement(el, root);
|
|
|
|
|
var found = tree.findSameHierarchy(tags, root);
|
|
|
|
|
var isSame = found === el;
|
|
|
|
|
console.log("found an equivalent node: %s", isSame);
|
|
|
|
|
return found;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.tagsUntilElement = function (el, ancestor) {
|
|
|
|
|
var list = [];
|
|
|
|
|
tree.someIncludingText(ancestor, function (e, index) {
|
|
|
|
|
list.push(e.tagName||e.nodeName);
|
|
|
|
|
return e === el;
|
|
|
|
|
});
|
|
|
|
|
return list;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.distanceFromEnd = function (el, ancestor) {
|
|
|
|
|
var i = 0, success = false;
|
|
|
|
|
// FIXME can't be trusted if element is not found.
|
|
|
|
|
tree.some(ancestor, function (e, index) {
|
|
|
|
|
++i;
|
|
|
|
|
return e === el;
|
|
|
|
|
});
|
|
|
|
|
return i;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.nthFromEnd = function (n, ancestor) {
|
|
|
|
|
var el = false, i = 0;
|
|
|
|
|
tree.some(ancestor, function (e) {
|
|
|
|
|
if (i > n) {
|
|
|
|
|
// terminate
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
if (++i === n) {
|
|
|
|
|
el = e;
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return el;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.contains = function (el, ancestor) {
|
|
|
|
|
return el && ancestor.contains && ancestor.contains(el);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
tree.check = function (el, ancestor) {
|
|
|
|
|
return tree.nthFromEnd(tree.distanceFromEnd(el, ancestor), ancestor) === el;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// TODO see if we can use this
|
|
|
|
|
tree.getNext = function (node, parent) {
|
|
|
|
|
if (node.firstChild) { return node.nextSibling; }
|
|
|
|
|
do {
|
|
|
|
|
if(node.nextSibling) { return node.nextSibling; }
|
|
|
|
|
node = node.parentNode;
|
|
|
|
|
} while (node && node !== parent);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return tree;
|
|
|
|
|
});
|
|
|
|
|