Original sourse

Emulating Prototyping of DOM Objects in Internet Explorer

In Mozilla all DOM objects are native Javascript objects, which means we can easily use prototypes to add methods and properties to all instances of a DOM class at once. This is very useful as it allows us to easily extend the functionality of DOM objects. Unfortuantly there isn't such an easy way to do this in IE, but we can emulate it by using behaviors and extending the document.createElement method.

To illustrate my method I've written my own getAttribute and setAttribute functions to replace the pair provided in Internet Explorer which fix the problem of having to use className instead of class and htmlFor instead of for. These need to be applied to every single DOM object.

My methods

The two methods I'm implementing are part of the Element interface, so I've created my own Element class to contain them. The functions themselves are very simple and are shown below.

Element = function () {};

Element.prototype.getAttribute = function (attribute) {
    if (attribute == "class") attribute = "className";
    if (attribute == "for") attribute = "htmlFor";
    return this[attribute];
}

Element.prototype.setAttribute = function (attribute, value) {
    if (attribute == "class") attribute = "className";
    if (attribute == "for") attribute = "htmlFor";
    this[attribute] = value;
}

How does it work

There are two places that DOM objects come from:

  1. they're either present in the original document
  2. or they are created using document.createElement

Adding methods and properties to elements created using the document.createElement method is easy; all we have to do is extend this function, do our modifcations and return our new object. Adding methods and properties to the elements in the original document is a little harder, we have to process each one individually, which would involve walking through the whole document. Fortunatly Internet Explorer provides an easy way to extend the functionality of all elements on a page by using DHTML behaviours.

Using Behaviours

DHTML behaviours, like the Mozilla project's XBL, allow you to bind Javascript (hence behaviours) to the DOM elements in a document.

Dynamic HTML (DHTML) behaviors are components that encapsulate specific functionality or behavior on a page. When applied to a standard HTML element on a page, a behavior enhances that element's default behavior.

Behaviours can be bound to elements using either a CSS property or progmatically using Javascript. This allows us to add Javascript methods and variables to all the HTML objects in a document using a CSS wildcard, the universal selector.

The HTC file we need simply adds the two methods, which are just references to the methods we defined above. It would look something like this:

<PUBLIC:COMPONENT>
    <PUBLIC:METHOD NAME="getAttribute"
           INTERNALNAME="_getAttribute" />
    <PUBLIC:METHOD NAME="setAttribute"
           INTERNALNAME="_setAttribute" />

    <script type="text/javascript">
        var el = new Element;
        _getAttribute = el.getAttribute;
        _setAttribute = el.setAttribute;
    </script>

</PUBLIC:COMPONENT>

Extending createElement

To extend the createElement method we first have to store a reference to Internet Explorer's built in method. We then define our own method in place of the default one, calling the built in method to first create the element. After creating the element it's simply a case of adding our Element interface, which includes the two methods I created above, and returning the new new element with our methods attached.

The code to do this is pretty short and is shown below:

var __IEcreateElement = document.createElement;

document.createElement = function (tagName) {
    var element = __IEcreateElement(tagName);

    var interface = new Element;
    for (method in interface)
        element[method] = interface[method];

    return element;
}

Including the Files

Adding the required CSS and Javascript to your documents is quick and painless, thanks to Internet Explorer's conditional comments, which allow authors to add HTML hidden in specially formatted comment blocks. The snippet you'll need will look something like this:

<!--[if IE]>
    <script type="text/javascript" src="attributes.js"></script>

    <style type="text/css">
        * { behavior: url(attributes.htc); }
    </style>
<![endif]-->

Here I've put the Javascript in a file named attributes.js and the HTC is in a file called attributes.htc. The conditional comment ensures that only Internet Explorer downloads these files. This is should now allow us to access the class and for attributes using the getAttribute and setAttribute in all the modern browsers, including IE.

Closure

Well, that's it, it's a pretty simple method which seems to work fairly well.