You might think that with the advent of Netscape 6 and increasing standards support in Internet Explorer 5, crossbrowser scripting is a thing of the past. Guess again. There are still plenty of differences to code around between these two browsers. The good news is, instead of compensating for Netscape's weaknesses, we'll be playing to its strengths and coding around IE's proprietary implementations. This is not meant as a knock to Microsoft, who've put some very useful features into their browser. But the goal here is not to rely on proprietary code, but do the best we can to use the W3C's recommendations for the Document Object Model and its ECMAScript interface, and only branch the code when necessary.
The differences in event registration in NS6 and IE5 are a perfect example. As we saw in Working With Events in Netscape 6, NS6 implements the EventListener interface as described by the W3C spec. To attach an event to an element, you use that element's addEventListener
method to define the type of event to listen for, the handler function to execute when the event is fired, and whether you want to use event capture:
object.addEventListener(String evType, Function fn, Boolean useCapture);
To illustrate, this is how you could attach an onmousedown
event handler named processEvent
to an image object in NS6:
imgObj.addEventListener("mousedown", processEvent, false);
To remove the handler, you simply call the element's removeEventListener
method using the exact same arguments:
imgObj.removeEventListener("mousedown", processEvent, false);
IE5 does not employ the EventLister interface. However, it has a similar set of methods, attachEvent
and detachEvent
, which take similar arguments. Here is how we would attach the same event to the same object in IE:
imgObj.attachEvent("onmousedown", processEvent);
Immediately we notice two things:
- the event type must include "on" at the beginning of the string, and
- the
useCapture
boolean is omitted, as events bubble by default in IE
It should be noted that Microsoft was an early implementer of many W3C working drafts and recommendations, so it may be that attachEvent
was an attempt to implement the EventLister interface prior to its formalization.
With this information, its not hard to see how we can get around these differences with a bit of creative scripting. Let's make our own event interface!
We'll start by creating a function to replace the IE5 and NS6 implementation. We'll call it addEvent
and design it to accept four parameters:
- the object to attach the event handler to
- the same three parameters required for the EventListener interface, described above
function addEvent(obj, evType, fn, useCapture){
}
Now, rather than do any browser sniffing, we'll first just check to see if the object implements the EventListener interface. If so, we'll just use that and call it a day. This will keep our code compatible if IE implements the same interface in the future.
function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType,fn,useCapture);
return true;
}
}
The return true;
statement is simply to provide a return value in the case of NS6. addEventListener
does not return a value by itself, but IE's attachEvent
returns either true or false depending on whether or not the operation was successful.
If addEventListener
is not present, we'll assume IE5 and check for the attachEvent
instead.
function addEvent(obj, evType, fn, useCapture){
if (obj.addEventListener){
obj.addEventListener(evType, fn, useCapture);
return true;
} else if (obj.attachEvent){
var r = obj.attachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be attached");
}
}
Note how I'm appending "on" to the front of evType
, and discarding the useCapture
boolean, which is only relevant to the EventListener interface. If the browser implements neither addEventListener
nor attachEvent
, the alert statement warns the developer of the problem.
To remove an event, we can easily build a removeEvent
method that uses almost exactly the same code, but utilizing removeEventListener
and detachEvent
.
function removeEvent(obj, evType, fn, useCapture){
if (obj.removeEventListener){
obj.removeEventListener(evType, fn, useCapture);
return true;
} else if (obj.detachEvent){
var r = obj.detachEvent("on"+evType, fn);
return r;
} else {
alert("Handler could not be removed");
}
}
In just a few short lines of code, we've bridged the gap between the IE5 and NS6 event models. This code can be extended to include more error checking, or if you're really ambitious, backward compatibility with NS4/IE4. (You're on your own on that one.)
As support for standard scripting models increases, workarounds like this one will hopefully become unnecessary, which is why we should strive to use standards-based approaches in our web applications, and encourage browser manufacturers to implement standards before proprietary features.
- Find out more about Netscape 6.0 at developer.netscape.com
- Learn about DOM, CSS and standards support at www.w3c.org
- Join the cause at the Web Standards Project www.webstandards.org
Copyright © 2001 by Scott Andrew LePera