compareDocumentPosition plugin for jQuery

Being able to quickly compare two elements' positions in the browser is extremely useful for a variety of tasks. The DOM Level 3 specification describes the compareDocumentPosition method. It returns a bitmask with a whole bunch of useful information. But not all browsers support it :(

posted in open-source, javascriptmvc, jquery, Development on June 03, 2010 by Brian Moschel

Being able to quickly compare two elements’ positions in the browser is extremely useful for a variety of tasks. The DOM Level 3 specification describes the compareDocumentPosition method. It returns a bitmask with a whole bunch of useful information. But not all browsers support it :(

For a really solid walkthrough of compareDocumentPosition, check out John Resig’s Comparing Document Position article. In this article, he gets close to providing a fast compareDocumentPosition for all browsers. JavaScriptMVC’s standalone jquery.compare plugin steals his ideas and DOES provide a fast compareDocumentPosition in all the browsers jQuery supports.

Download

jquery.compare.js (minified 0.8kb) [works with all versions of jQuery]

Demo

Compare Element Positions

Documentation

JavaScriptMVC’s jquery/dom/compare docs.

Use

To use the compare plugin, just call compare on your jQuery wrapped elements with another element or jQuery element:

$('#foo').compare( $("#bar") ) //-> Number

The number is actually a bitmask that represents multiple several pieces of relational information about the two elements. Here’s what each bit means:

Bits

Number

Meaning

000000

0

Elements are identical.

000001

1

The nodes are in different documents (or one is outside of a document).

000010

2

Node B precedes Node A.

000100

4

Node A precedes Node B.

001000

8

Node B contains Node A.

010000

16

Node A contains Node B.

This means if a compare results in a 10, node B is before and contains node A. Typically, you just want to know one bit’s information. To do this, use the bitwise AND operator (&) like:

if( $('#foo').compare( $("#bar") )  & 2  ){
  //do something  because #bar is before #foo
}

How it works

The plugin uses all the techniques in John’s article, but fixes the ‘Safari’ problem. Older versions of Safari lack compareDocumentPosition and sourceIndex. This makes comparing node order (the 2 and 4 values of the bitmask) challenging. A naive approach might be to walk up the parent nodes until an intersection happens. But, as I’ve learned from event delegation, calling parentNode is surprisingly slow. But using document Ranges and comparing them is fast. The following code adds the 2 and 4 values in Safari:

var range = document.createRange(), 
    sourceRange = document.createRange(),
    compare;
range.selectNode(this[0]);
sourceRange.selectNode(b);
compare = range.compareBoundaryPoints(Range.START_TO_START, 
                                      sourceRange);
number += (compare === -1 && 4)
number += (compare === 1 && 2)

This code uses Safari’s implemented compareBoundryPoints method in the DOM Level 2 Traversal-Range recommendation. CompareBoundaryPoints compares 2 ranges. You have to provide which parts of the ranges to compare and it returns -1,0, or 1 to indicate the the boundary positions.

comments powered by Disqus
Contact Us
(312) 620-0386 | contact@bitovi.com
 or cancel