|
ArticleNodeContains
HOWTO determine if one node contains another (goog.dom.contains)
The DOM is hierarchical; some nodes can contain other nodes. So you would think that it would be straightforward to determine whether node A "contained" node B -- that is, whether node B is a descendant of node A. And you would be wrong. It is insanely complicated. It is made even more complicated by the fact that Safari used to offer a broken contains functions, but has since fixed it. The codeThis code relies on functions explained elsewhere: /**
* Safari contains is broken, but appears to be fixed in WebKit 522+
* @type {Boolean}
* @private
*/
goog.dom.BAD_CONTAINS_SAFARI_ = goog.userAgent.SAFARI &&
goog.userAgent.compare(goog.userAgent.VERSION, '521') <= 0;
/**
* Whether a node contains another node
* @param {Node} parent The node that should contain the other node
* @param {Node} descendant The node to test presence of
* @return {Boolean}
*/
goog.dom.contains = function(parent, descendant) {
// We use browser specific methods for this if available since it is faster
// that way.
// IE / Safari(some) DOM
if (typeof parent.contains != 'undefined' && !goog.dom.BAD_CONTAINS_SAFARI_ &&
descendant.nodeType == goog.dom.NodeType.ELEMENT) {
return parent == descendant || parent.contains(descendant);
}
// W3C DOM Level 3
if (typeof parent.compareDocumentPosition != 'undefined') {
return parent == descendant ||
Boolean(parent.compareDocumentPosition(descendant) & 16);
}
// W3C DOM Level 1
while (descendant && parent != descendant) {
descendant = descendant.parentNode;
}
return descendant == parent;
};The code walkthroughFirst we need to check whether we're dealing with a broken version of Safari: goog.dom.BAD_CONTAINS_SAFARI_ = goog.userAgent.SAFARI &&
goog.userAgent.compare(goog.userAgent.VERSION, '521') <= 0;Now we need to do some browser-specific voodoo to determine which function to call. We use object detection as much as possible, but we still need a user-agent hack to detect broken versions of Safari. The first method works on Microsoft Internet Explorer and non-broken versions of Safari. if (typeof parent.contains != 'undefined' && !goog.dom.BAD_CONTAINS_SAFARI_ &&
descendant.nodeType == goog.dom.NodeType.ELEMENT) {
return parent == descendant || parent.contains(descendant);
}The second method is defined in W3C DOM Level 3; it works in Mozilla Firefox, and in Opera 9.5 and later. if (typeof parent.compareDocumentPosition != 'undefined') {
return parent == descendant ||
Boolean(parent.compareDocumentPosition(descendant) & 16);
}The third method is slower but should work in all other browsers. while (descendant && parent != descendant) {
descendant = descendant.parentNode;
}
return descendant == parent;
};Further reading
|
Sign in to add a comment