DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • Application Architecture Design Principles
  • 13 Impressive Ways To Improve the Developer’s Experience by Using AI
  • How Web3 Is Driving Social and Financial Empowerment
  • Using Render Log Streams to Log to Papertrail

Trending

  • Application Architecture Design Principles
  • 13 Impressive Ways To Improve the Developer’s Experience by Using AI
  • How Web3 Is Driving Social and Financial Empowerment
  • Using Render Log Streams to Log to Papertrail

Comparing Document Position

John Resig user avatar by
John Resig
·
Feb. 19, 08 · News
Like (0)
Save
Tweet
Share
6.36K Views

Join the DZone community and get the full member experience.

Join For Free

A great blog post, for me, was one written by PPK back about two years about in which he explained how the contains() and compareDocumentPosition() methods work in their respective browsers. I've, since, done a lot of research into these methods and have used them on a number of occasions. As it turns out they're incredibly useful for a number of tasks (especially relating to the construction of pure-DOM selector engines).

DOMElement.contains(DOMNode)

Originally introduced by Internet Explorer this method determines if one DOM Node is contained within another DOM Element. This method can be especially useful when attempting to optimize CSS Selector traversals that look like "#id1 #id2". With this method you could getElementById both elements then use .contains() to determine that #id1 does, in fact, contain #id2.

There's one gotchya: .contains() will return true if the DOM Node and DOM Element are identical (even though, technically, an element cannot contain itself).

Here's a simple implementation wrapper that works in Internet Explorer, Firefox, Opera, and Safari.

function contains(a, b){
  return a.contains ?
    a != b && a.contains(b) :
    !!(a.compareDocumentPosition(arg) & 16);
}

Note that we use compareDocumentPosition, which we'll be discussing next.

DOMNode.compareDocumentPosition(DOMNode)

This method is part of the DOM Level 3 specification and allows you determine where two DOM Nodes are, in relation to each other. This method is much more powerful to .contains(). One possible use of this method is to re-order DOM nodes to be in a specific order (as was also done by PPK).

With this method you can determine a whole slew of information pertaining to the position of an element. All of this information is returned using a bitmask.

For those who aren't familiar with it, a bitmask is a way of storing multiple points of data within a single number. You end up turning on/off the individual bits of the number, giving you a final result.

Here are the results from NodeA.compareDocumentPosition(NodeB) along with all the information that you can access:

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.
100000 32 For private use by the browser.

Now, this means that a possible result could be something like:

<div id="a"><div id="b"></div></div>
<script>
alert( document.getElementById("a")
  .compareDocumentPosition(document.getElementById("b")) == 20);
</script>

Since a node that contains another both "contains" it (+16) and precedes it (+4) the final result is the number 20. It might make more sense if you look at what's happening to the bits:

000100 (4) + 010000 (16) = 010100 (20)

This, undoubtedly, makes for the single most confusing method of the DOM API - however it's one whose worth will be well deserved.

Right now DOMNode.compareDocumentPosition is available in Firefox and Opera. However, there are some tricks that we can use to implement it completely in Internet Explorer, observe:

// Compare Position - MIT Licensed, John Resig
function comparePosition(a, b){
  return a.compareDocumentPosition ?
    a.compareDocumentPosition(b) :
    a.contains ?
      (a != b && a.contains(b) && 16) +
        (a != b && b.contains(a) && 8) +
        (a.sourceIndex >= 0 && b.sourceIndex >= 0 ?
          (a.sourceIndex < b.sourceIndex && 4) +
            (a.sourceIndex > b.sourceIndex && 2) :
          1) +
      0 :
      0;
}

Internet Explorer provides us with a couple methods and properties that we can use. To start, with the .contains() method (as we discussed before) so that gives us contains (+16) and 'is contained by' (+8). Internet Explorer also has a .sourceIndex property on all DOM Elements corresponding to the position of the element absolutely within the document. For example, document.documentElement.sourceIndex == 0. Because we have this information we can complete two more pieces of the compareDocumentPosition puzzle: preceded by (+2) and followed by (+4). Additionally, if an element isn't currently located within a document it's .sourceIndex will equal -1, which gives us an answer of 1. Finally, through process of deduction, we can determine if an element is equal to itself, returning an empty bitmask of 0.

This function will work in Internet Explorer, Firefox, and Opera. We'll only have crippled functionality in Safari (since it only has .contains(), and no .sourceIndex, we'll only get 'contains' +8 and 'is contained by' +16 - all other results will return '1' representing a disconnect).

PPK provides a great example of how this new functionality can be used by creating a getElementsByTagNames method. Let's adapt it to work with our new method:

// Original by PPK quirksmode.org
function getElementsByTagNames(list, elem) {
        elem = elem || document;
       
        var tagNames = list.split(','), results = [];
       
        for ( var i = 0; i < tagNames.length; i++ ) {
                var tags = elem.getElementsByTagName( tagNames[i] );
                for ( var j = 0; j < tags.length; j++ )
                        results.push( tags[j] );
        }
       
        return results.sort(function(a, b){
                return 3 - (comparePosition(a, b) & 6);
        });
}

We could now use this to construct an, in order, table of contents for a site:

getElementsByTagname("h1, h2, h3");

While both Firefox and Opera have taken some initiative to implement this method, I'm looking forward to seeing more browser get on board to help push this forward.



Note: In jQuery you can do $(":header") to select all header elements in order.

Document Element

Published at DZone with permission of John Resig. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Application Architecture Design Principles
  • 13 Impressive Ways To Improve the Developer’s Experience by Using AI
  • How Web3 Is Driving Social and Financial Empowerment
  • Using Render Log Streams to Log to Papertrail

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: