Mark Needham

Thoughts on Software Development

Javascript: Isolating browser specific code

with 5 comments

One thing we've found on my current project is that despite our best efforts we've still ended up with some javascript code which we only want to run if the user is using Internet Explorer 6 and the question then becomes how to write that code so that it doesn't end up being spread all over the application.

jQuery has some functions which allow you to work out which browser's being used but I've noticed that when we use those you tend to end up with if statements dotted all around the code which isn't so good.

An approach which I was shown recently involves using CSS conditionals to identify when we're using Internet Explorer instead.

We can then include an IE6 specific javascript file like so:

<!--[if lt IE 7]>
	<script type="text/javascript" src="/path/to/ie6.js") %>"></script>
<![endif]-->

Since we're building an ASP.NET MVC application we include this bit of code in our master page so that it gets picked up by all the web pages.

We've either needed to override existing functions or call the existing function but then do some extra work afterwards as well.

In order to do this we have to make sure that the IE6 specific file is included after our other javascript files since the interpreter will use the last definition of a function that it finds.

Given an existing function defined like so:

Foo = {
    Bar : function() {
            console.log("original bar call");
    }
};

If we want to override this function to do something else we could include the following code in our IE6 specific file:

Foo.bar = function() {
    console.log("overriding bar call");
}

When we call 'Foo.bar()' we'd only see the second 'console.log' statement.

It becomes a bit more interesting if we want to call the original function and then do some other functionality.

We can make use of the proxy pattern to allow us to do this cleanly.

Foo = {
    bar : function() {
            console.log("original bar call");
    }
};
 
(function() {
    var originalBar = Foo.bar;
    Foo.bar = function() {
        originalBar.apply(this, arguments);
        console.log("overriding bar call");
    };
})();

If we call 'Foo.bar()' in IE6 we'd now see both of those 'console.log' statements.

The reason that we wrap the reassignment in a function is so that we can hide the 'originalBar' function from the rest of our code. We save 'Foo.bar' in a closure and then override it and delegate calls to the original before logging the extra message.

I quite like this approach although I'm not sure if it's the most intention revealing code because it's not necessarily obvious that the function is being rewritten unless you happen to know about the IE6 only file.

Is there a better way to do this than the approach I've described?

Written by Mark Needham

February 28th, 2010 at 12:11 am

Posted in Javascript

Tagged with

5 Responses to 'Javascript: Isolating browser specific code'

Subscribe to comments with RSS or TrackBack to 'Javascript: Isolating browser specific code'.

  1. Usual approach is to prefer object detection over version detection. What people traditionally called object detection in JavaScript is more-or-less done using duck typing.

    If you really do need to target IE specifically, you might find that having detection in your HTML for things in your JavaScript is a bit unwieldly so it's worth noting that IE also supports conditional compilation inside JavaScript.

    Patrick

    28 Feb 10 at 1:39 am

  2. In this case we were writing some code to get around the IE6 bug with placing a div over a select box as described here – http://weblogs.asp.net/bleroy/archive/2005/08/09/how-to-put-a-div-over-a-select-in-ie.aspx – so we needed to insert an empty iframe in front of the div in order for the div to be displayed above the select box for IE6.

    Would that be an example of something that is IE specific or is there a way to detect that otherwise?

    Mark Needham

    28 Feb 10 at 1:45 am

  3. IE6 is a pain in the ass. Although you can loads scripts using JQuery's getScript(). I.e $.getScript("test.js");

    Chris Airey

    28 Feb 10 at 10:11 pm

  4. Mark… targeting IE specifically is exactly how I've worked around that one in the past.

    Patrick

    2 Mar 10 at 11:32 am

  5. Hi Mark,
    Look at this
    http://www.prototypejs.org/api/class/addMethods

    Look at the inheritance of snake that makes a supercall.

    Jquery does allow class/object creation now(very much like prototype). This should work there too.

    -Sudhindra

    Sudhindra Rao

    3 Mar 10 at 11:33 pm

Leave a Reply