Home > Web > Cross browser event handling

Cross browser event handling


We all know very well what a mess is Internet Explorer. Especially when it comes to following standards. But if I have to choose one thing and one thing only to change in IE, I will choose event handling without second thoughts.
Why is that? Because you will face this in your every day life as JavaScript developer and writing code that handles both world can lead to hardly readable code. I said both, because all the other browsers follows W3C event model. Except IE, but this no surprise by now. Of course you have the option of using different frameworks that will hide the messy part in their internals. But why to do so, when you have already such a good framework define by W3C?
And the good news is that you can make a little trick to make IE compliant. Yes, you heard well and then your code can be clean, W3C compliant and work on all the browsers.
I explained this technique before, which is based on IE behaviors. With behaviors you can add in an uniform and transparent way methods, properties and register events. What we are looking here is to define addEventListener, removeEventListener and dispatchEvent. Fortunately all these have IE counterparts attachEvent, detachEvent and fireEvent, so only a bridge will be required.
Before actually writting the code, there is one more thing to add: IE has even different names for some events (I know, I know …), so a mapping will be required here.

<PUBLIC:COMPONENT lightWeight="true">
<PUBLIC:DEFAULTS viewLinkContent="true"/>  
<PUBLIC:METHOD name="addEventListener" />
<PUBLIC:METHOD name="removeEventListener" />
<PUBLIC:METHOD name="dispatchEvent" />

<SCRIPT>
var TRANSLATED_IE_EVENT_TYPES = {
    DOMContentLoaded: "readystatechange", 
    DOMAttrModified: "propertychange",
    DOMMouseScroll: "mousewheel",
    invalid: "error" // for HTML 5
};

/**
 * Translates W3C DOM event types into IE ones
 * @param type the event type
 * @return the translation or the initial type if there is no translation
 */ 
function translateIEEventType(type) {
    var xtype = TRANSLATED_IE_EVENT_TYPES[type];
    return (xtype != null ? xtype : type);
}

function addEventListener(type, listener, useCapture) {
    return this.attachEvent("on" + translateIEEventType(type), wrapListener(listener)); 
}

function removeEventListener(type, listener, useCapture) {
    return this.detachEvent("on" + translateIEEventType(type), wrapListener(listener));
};

function dispatchEvent(event) {
    try {
        return this.fireEvent("on" + translateIEEventType(type));
    } catch(exc) {
		// if we can log ...
    	if (window != null && window.console != null && window.console.log != null)
    		window.console.log(exc + ";" + exc.message);
    }
}
</SCRIPT>
</PUBLIC:COMPONENT>

Pretty straightforward. You probably notice the wrapListener method. The idea is to wrap the W3C listener into an IE one, so that it can be handled by IE, and consequently, to wrap the IE event into a W3C one, so that it can be used by the original handler. For the last part we also have to define the Event type and all its methods as per W3C specifications.

function wrapListener(handler) {
    var h = handler;
    if (h._wrapper == null) {
        h._wrapper = function() {
            var event = wrapIEEvent();
            retval = h(event);
            return retval == null ? (!event.defaultPrevented) : retval;
        };
        h._wrapper.toString = function() {
            return h.toString();
        };
    }
    return h._wrapper;
}


/**
 * Wrap the IE Event into a W3C one. 
 */ 
function wrapIEEvent() {
    // keep the W3C event as a standardEvent property of the window
    if (window.standardEvent == null || window.standardEvent.ieEvent != window.event) {
        window.standardEvent = new Event(window.event);
    }
    return window.standardEvent;
}

/** 
 * Creates a new event.
 * @param ieEvent the IE event. 
 */
function Event(ieEvent) {
	// wrap the IE event into a W3C one
}

Event.prototype.preventDefault = function() {

};

Event.prototype.stopPropagation = function() {

};

The only thing left for you is to fill in the gaps: wrap the IE event into a W3C one and define the W3C methods for the event – preventDefault, stopPropagation and all the rest. This is your homework. Or you can download it from here.
The final stage of the trick – using it. Like any other behavior and in this case you have to register it for all the elements.

* { 
	behavior: url(cb.event.htc);
}

Or another resolution of this problem (I would like it better) will be to stop using IE, tell your friends to do the same and them to their friends and so on until we will get rid of this “web poison”.

P.S. This was tested with IE 7 & 8. It seems that IE 9 is implementing W3C events, but still I would like to see it gone.

Categories: Web
  1. Adrian
    April 30, 2012 at 10:56 am

    I think is is a good method to solve this:
    http://www.minus99.com/blog/javascript-cross-browser-custom-events/

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: