DOMContentLoaded for IE, Safari, everything, without document.write

We have now had, for a while, a way of emulating the “DOMContentLoaded” event across all the main browsers. For those of you who don’t know what I’m talking about, a web browser fires an event, “load”, when a page finishes loading, and JavaScript can attach code to that event which will then run once the page has loaded. However, if there are big images or other slow-loading things in the page then the code gets delayed until after they’ve finished loading too; this is annoying, because most DOM scripting doesn’t actually need the images to be loaded, and so the delay is unnecessary. Opera and Mozilla fire a “DOMContentLoaded” event which runs after the page has loaded but before all the slow images and applets and Flash movies need to load, which is perfect. IE and Safari don’t fire such an event, but it’s been possible to do IE and Safari-specific things to make it happen. (In Safari you check document.readyState, in IE you document.write a <script> element with defer set. See Dean’s writeup.) If you’re using a JavaScript library of some sort (jQuery, Prototype, Mootools, whatever) then all this complexity gets wrapped up for you and you don’t have to worry about it, but if you’re writing stand-alone scripts (like my sorttable), which don’t depend on a library, then this is more of a problem; you have to include a big swathe of boilerplate code to emulate the DOMContentLoaded event. Recently, Hedger Wang provided an alternative approach for IE that doesn’t rely on document.write, which is rather neat. So, it should be possible to combine the existing Safari method, Opera and Mozilla’s DOMContentLoaded support, and Hedger’s IE approach into a short bit of boilerplate code that can be dropped into your standalone script. And indeed it is. See a simple demo, and more importantly, here is the short version of the code:

(function(i) {var u =navigator.userAgent;var e=/*@cc_on!@*/false; var st = 
setTimeout;if(/webkit/i.test(u)){st(function(){var dr=document.readyState;
if(dr=="loaded"||dr=="complete"){i()}else{st(arguments.callee,10);}},10);}
else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
document.addEventListener("DOMContentLoaded",i,false); } else if(e){     (
function(){var t=document.createElement('doc:rdy');try{t.doScroll('left');
i();t=null;}catch(e){st(arguments.callee,0);}})();}else{window.onload=i;}})(init);

The init on the last line is the name of your “init” function; the one that you want to call on page load. (It could be an inline function if required.) Simply copy those 7 lines into your standalone script and change the name of the init function to be your init, and you’re good to go on all browsers. Remember that if you’re already using a JavaScript library then you don’t need this, but if you’re not then it’s simpler than the current swathes of code, and less heavy than depending on a library just to get access to cross-browser onload event handling.