Saturday, November 25th, 2006

DOMContentLoaded.Next

Category: JavaScript, Tip

Andrea Giammarchi has taken the work of Dean Edwards, Mark Wubben, and Paul Sowden to create his DOMContentLoaded Final Solution.

The work comes with a test page for http and https, and is documented in this function:

javascript

  1. function onContent(callback){ // (C) webreflection.blogspot.com
  2.     // [please note that this code doesn't work]
  3.  
  4.  // private scope variable
  5.  
  6.  var IEStringToWrite =  // this is IE dedicated string
  7.  
  8.   "<script defer src='//:' onreadystatechange='
  9.   (function(element){
  10.    
  11.    // if readystate is complete
  12.    if(element.readyState === "complete")
  13.  
  14.     // call the global variable
  15.     window.__onContent__();
  16.   })(this);
  17.   '></script>";
  18.  
  19.  // the above string is necessary to use onreadystatechange property
  20.  // with an undefined page. In this way IE tell us the readyState
  21.  // of the current document
  22.  
  23.  
  24.  
  25.  // to call callback function IE need a global scope variable
  26.  // this variable could call one or more callback
  27.  // then if it's already created we need to call the old callback
  28.  // then this new callback
  29.  window.__onContent__ = (function(oldCallback){
  30.  
  31.   // returns a function that will delete __onContent__
  32.   // to remove multiple callbacks with different
  33.   // events and different ways for each browser
  34.  
  35.   return function(){
  36.  
  37.    // clear __onContent__ as generic function
  38.    window.__onContent__ = function(){};
  39.    
  40.    
  41.    // checks if oldCallback isn't null or undefined
  42.    if(oldCallback)
  43.     oldCallback(); // call them to preserve the right order
  44.  
  45.    callback();  // call this scope callback function
  46.       // (sent calling onContent)
  47.   }
  48.  
  49.  })(window.__onContent__); // undefined if is the first time we use __onContent__
  50.  
  51.  
  52.  
  53.  // __onContent__ is my function to use as callback
  54.  
  55.  // I need to add this function as event
  56.  
  57.  // Opera 9 and FireFox both support DOMContentLoaded as well as
  58.  // addEventListener document method
  59.  if(document.addEventListener)
  60.   document.addEventListener("DOMContentLoaded", __onContent__, false);
  61.  
  62.  // if some browser supports addEventListener but doesn't support DOMContentLoaded
  63.  // event I don't need to care about that because this event will never be fired
  64.  
  65.  // at the same time if Safari or KDE one day will support DOMContentLoaded
  66.  // I prefere use this dedicated in-core
  67.  // event instead of next trick that's quite horrible but works with Safari,
  68.  // KDE as Opera 8.5 and lower too
  69.  
  70.  // that's why I don't use an else if but an if ... because the first time
  71.  // event will be fired __onContent__
  72.  // became an empty function ... then calling them twice is not a problem
  73.  
  74.  if(
  75.   // Safari and KDE
  76.   /WebKit|Khtml/i.test(navigator.userAgent) ||
  77.  
  78.   // Opera less than 9
  79.   (window.opera && parseInt(window.opera.version())&lt;9)
  80.  )
  81.   // runtime anonymous function
  82.   (function(){
  83.  
  84.    // checks if document.readyState is loaded or complete
  85.    /loaded|complete/.test(document.readyState) ?
  86.  
  87.     // then call __onContent__ , stopping internal loop
  88.     window.__onContent__() :
  89.  
  90.     // or loops itself with the faster timeout
  91.     setTimeout(arguments.callee, 1);
  92.   })();
  93.  
  94.  // at this point I've setted the DOMContentLoaded event for every browser
  95.  // but not for Inernet Explorer.
  96.  else if (/MSIE/i.test(navigator.userAgent))
  97.  
  98.   // I can write dedicated string
  99.   document.write(IEStringToWrite);
  100. };

Posted by Dion Almaer at 8:29 am
16 Comments

+++--
3.4 rating from 30 votes

16 Comments »

Comments feed TrackBack URI

I’ll post a more readable version on my blog in the next few days. But essentially you use src=//: instead of src=javascript:void(0) for the deferred IE script tag.

Comment by Dean Edwards — November 25, 2006

I’m being slightly unfair. The posted code is perfectly readable. :-) It was this code that I saw first:

http://webreflection.blogspot.com/2006/11/my-domcontentloaded-final-solution.html

Comment by Dean Edwards — November 25, 2006

Hasn’t jQuery had a very good solution based on all the same stuff for a while now?

Comment by Peter Goodman — November 25, 2006

No.

Comment by Dean Edwards — November 25, 2006

What’s wrong with the jquery function?

I found using another domloaded function (http://www.thefutureoftheweb.com/blog/2006/6/adddomloadevent) that many IE users got a weird page not accessible error (noted on msdn) and couldn’t view the website (!!). It was from writing something to the document before loaded. Something weird like that. I had to remove it.

Comment by ziggy — November 25, 2006

For the record this fix is also now a part of Dojo (thanks to Mark Wubben for kicking it off, and Paul showing his solution to the problem).

Comment by Tom Trenka — November 26, 2006

I shouldn’t have been so brief. :-) I meant that jQuery did not have an HTTPS solution for DOMContentLoaded. It does indeed have a DOMContentLoaded solution as do most of the major libraries now.

Comment by Dean Edwards — November 26, 2006

Dean and John Resig and others worked together on the DOMContentLoaded function and it has now found its way into most major libraries. This appears to be an improvement and I find generally that if Dean says its an improvement, it is :)

Comment by wioota — November 26, 2006

YUI still seems to be the outliar in taking a very different approach toward grabbing nodes when you need them. By simply polling the document for a node, you get onAvailable… and then when you want to know when its content is available, you simply check when it’s nextSibling is available too. See the documentation. Overall, it’s a pretty clever idea.

Comment by Dustin Diaz — November 26, 2006

Hello guys, with a little “perfect” trick, suggested by an anonymous developer, the function now removes itself (I mean the script tag) automatically with one or multiple onContent and only with IE5 or greater (because only IE or compatibles uses script defer).

Thank You for this post, bye :-)

Comment by Andrea Giammarchi — November 28, 2006

What if to do without window. __ onContent __? For example:

var onContent = (function (aCallback) {
var IEStringToWrite = "";
if (document.addEventListener) {
document.addEventListener('DOMContentLoaded',
aCallback,
false);
}
if (/WebKit|Khtml/i.test(navigator.userAgent) ||
window.opera && parseInt(window.opera.version())

Comment by AKS — January 6, 2007

Here’s full code – http://aksus-69.narod.ru/test.html.

Comment by AKS — January 6, 2007

Hi people,

I’ve posted an alternative solution for IE that doen’t need the conditional comments. The code there is a bit verbose, but that’s to make it clear. For those who don’t like to put code into comments (UGLY practice if you ask me :D)

See it at: Robert Nyman’s site

Comment by Stefan Van Reeth — January 21, 2007

Now I now not why nobody thought of this before: the https solution that works with the solution above AND with adding the script through the DOM is dead easy: src=””.

Problem solved :). Tested on my own server and never got that alert again.

Comment by Stefan Van Reeth — January 21, 2007

I am confused with this part of script
What if we skip the
#
// __onContent__ is my function to use as callback
#
#
// addEventListener document method
#
if(document.addEventListener)
#
document.addEventListener(“DOMContentLoaded”, __onCo
Thanks,
Bob

Comment by Bob — June 10, 2007

Agree with Dean. Something wrong with that so need to be fixed

Comment by Buygenericultram — August 20, 2007

Leave a comment

You must be logged in to post a comment.