123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- // removeSubsets
- // Given an array of nodes, remove any member that is contained by another.
- exports.removeSubsets = function(nodes) {
- var idx = nodes.length, node, ancestor, replace;
- // Check if each node (or one of its ancestors) is already contained in the
- // array.
- while (--idx > -1) {
- node = ancestor = nodes[idx];
- // Temporarily remove the node under consideration
- nodes[idx] = null;
- replace = true;
- while (ancestor) {
- if (nodes.indexOf(ancestor) > -1) {
- replace = false;
- nodes.splice(idx, 1);
- break;
- }
- ancestor = ancestor.parent;
- }
- // If the node has been found to be unique, re-insert it.
- if (replace) {
- nodes[idx] = node;
- }
- }
- return nodes;
- };
- // Source: http://dom.spec.whatwg.org/#dom-node-comparedocumentposition
- var POSITION = {
- DISCONNECTED: 1,
- PRECEDING: 2,
- FOLLOWING: 4,
- CONTAINS: 8,
- CONTAINED_BY: 16
- };
- // Compare the position of one node against another node in any other document.
- // The return value is a bitmask with the following values:
- //
- // document order:
- // > There is an ordering, document order, defined on all the nodes in the
- // > document corresponding to the order in which the first character of the
- // > XML representation of each node occurs in the XML representation of the
- // > document after expansion of general entities. Thus, the document element
- // > node will be the first node. Element nodes occur before their children.
- // > Thus, document order orders element nodes in order of the occurrence of
- // > their start-tag in the XML (after expansion of entities). The attribute
- // > nodes of an element occur after the element and before its children. The
- // > relative order of attribute nodes is implementation-dependent./
- // Source:
- // http://www.w3.org/TR/DOM-Level-3-Core/glossary.html#dt-document-order
- //
- // @argument {Node} nodaA The first node to use in the comparison
- // @argument {Node} nodeB The second node to use in the comparison
- //
- // @return {Number} A bitmask describing the input nodes' relative position.
- // See http://dom.spec.whatwg.org/#dom-node-comparedocumentposition for
- // a description of these values.
- var comparePos = exports.compareDocumentPosition = function(nodeA, nodeB) {
- var aParents = [];
- var bParents = [];
- var current, sharedParent, siblings, aSibling, bSibling, idx;
- if (nodeA === nodeB) {
- return 0;
- }
- current = nodeA;
- while (current) {
- aParents.unshift(current);
- current = current.parent;
- }
- current = nodeB;
- while (current) {
- bParents.unshift(current);
- current = current.parent;
- }
- idx = 0;
- while (aParents[idx] === bParents[idx]) {
- idx++;
- }
- if (idx === 0) {
- return POSITION.DISCONNECTED;
- }
- sharedParent = aParents[idx - 1];
- siblings = sharedParent.children;
- aSibling = aParents[idx];
- bSibling = bParents[idx];
- if (siblings.indexOf(aSibling) > siblings.indexOf(bSibling)) {
- if (sharedParent === nodeB) {
- return POSITION.FOLLOWING | POSITION.CONTAINED_BY;
- }
- return POSITION.FOLLOWING;
- } else {
- if (sharedParent === nodeA) {
- return POSITION.PRECEDING | POSITION.CONTAINS;
- }
- return POSITION.PRECEDING;
- }
- };
- // Sort an array of nodes based on their relative position in the document and
- // remove any duplicate nodes. If the array contains nodes that do not belong
- // to the same document, sort order is unspecified.
- //
- // @argument {Array} nodes Array of DOM nodes
- //
- // @returns {Array} collection of unique nodes, sorted in document order
- exports.uniqueSort = function(nodes) {
- var idx = nodes.length, node, position;
- nodes = nodes.slice();
- while (--idx > -1) {
- node = nodes[idx];
- position = nodes.indexOf(node);
- if (position > -1 && position < idx) {
- nodes.splice(idx, 1);
- }
- }
- nodes.sort(function(a, b) {
- var relative = comparePos(a, b);
- if (relative & POSITION.PRECEDING) {
- return -1;
- } else if (relative & POSITION.FOLLOWING) {
- return 1;
- }
- return 0;
- });
- return nodes;
- };
|