# The Browser Detection Script - Java Script

The browser detection script described in this section uses the user-agent string detection to identify the following browsers:

• Opera 4.0 and higher
• Internet Explorer 4.0 and higher
• Mozilla 0.9.2 and higher
• Safari 1.0 and higher
• Netscape Navigator 4.0 – 4.8x

In addition,the methods developed in this chapter fail gracefully and do not cause JavaScript errors inolder browsers that perhaps don’t support ECMAScript Edition3 fully.

Methodology

To be practical,it is necessary to detect minimal versions of browsers instead of exact versions. For instance,this code detects exact versions:

It may not seem like a problem now, but what if IE gets up to version 10? You would be required to keepadding to this code:

This obviously is not optimal. However,if you test for minimal versions of browsers, the test remainsthe same regardless of how many future versions are released:

This algorithm never changes,and it represents the way that the browser detection code in this chapter is developed.

First Steps

The first two steps necessary for browser detection are storing the user-agent string in a local variable and getting the reported browser version:

A common occurrence in user-agent strings is a version number with multiple decimal points (for example, Mozilla 0.9.2). This causes a problem when you are trying to compare browser versions.You already know that the parseFloat() function is used to convert a string into a floating-point number.In addition, parseFloat() works by going character-by-character through a string,stopping when it finds a non-number character.In the case of a version number with multiple decimal points,the non-numbercharacter is the second decimal point.That means using parseFloat() on the string “0.9.2” yields a floating-point value of 0.9,completely losing .2.That’s not good.

The best method for comparing two versions of this type of string is to compare the value after the decimalpoint in each.For instance, suppose you want to determine whether 0.9.2 is greater than 0.9.1.Thecorrect way to do this is to compare 0 to 0, 9 to 9, and 2 to 1.Because 2 is greater than 1,version 0.9.2 isgreater than 0.9.1.Because you perform this operation so often when detecting browser and operating system versions, it’s logical to encapsulate this logic in a function.

The function compareVersions() accept two string versions as arguments and returns 0 if they areequal, 1 if the first version is greater than the second, and –1 if the first version is less than the second.(As you saw earlier in this book,this is a very common way of representing the relationship between two versions.)
The first step in the function is to convert each version into an array of values.This fastest way to do thisis to use the split() method and pass in the decimal point as the character separator:

At this point,aVersion1 contains the numbers for the first version passed in, and aVersion2 contains the number of the last version passed in.Next,it is necessary to assure that the arrays have the samenumber of digits; otherwise,it is very difficult to compare 0.8.4 to 0.9.To do this, first determine whicharray has more digits, and then add zeroes to the other array. This results in 0.9 becoming 0.9.0.

The highlighted block of code contains an if statement testing which array has more items (if they are equal,no changes are necessary).Both branches of the if statement do the same thing on different arrays:The first adds zeroes to aVersion2,whereas the second adds zeroes to aVersion1.After this point, both arrays have an equal number of digits.

The final step is to iterate through the arrays and compare the corresponding digits in each array:

In this section, a for loop is used to compare the arrays. If a digit in aVersion1 is less than the corresponding digit in aVersion2, the function automatically exits and returns –1.Likewise,if the digit in aVersion1 is greater than the one from aVersion2,the function exits and returns 1.If all digits are tested and no value has been returned,the function returns 0, meaning that the two versions are equal.

This function is used like this:

The first line returns 1 because 0.9.2 is greater than 0.9; the second line returns –1, because 1.13.2 is less than 1.14; the third line returns 0 because the two versions are equal. This function is used extensively in this chapter.

Detecting Opera

The simplest and best way to begin browser detection is to start with the problem browsers,such asOpera and Safari.If you determine that a browser is not one of these,it is much easier to determine when a browser is legitimately IE or Mozilla.

To begin,consider the possible Opera user-agent strings:

One thing that jumps out right away is that each of these strings has the word “Opera”.So the easiest way to determine if the browser is Opera is just to search for that string:

var isOpera = sUserAgent.indexOf(“Opera”) > -1;

When you know you have an Opera browser, you can go ahead and determine the actual version.The first step is to define several variables to test for the various versions of Opera.

To determine what version of Opera is being used, you can define some variables:

var isMinOpera4 = isMinOpera5 = isMinOpera6 = isMinOpera7 = isMinOpera7_5 = false;

This code uses compound assignment to set each variable to an initial value of false,ensuring that if the browser is Netscape,these variables return the correct value.

Naturally,you shouldn’t even bother setting these variables unless the browser has been identified as Opera,so any further evaluation of the browser version needs to take place inside of an if statement:

Because of Opera’s disguises,you have two different ways to determine the browser version.If Opera isusing its own user-agent string,the version is contained in fAppVersion, which was defined earlier.You can check to see if Opera is using a disguise by checking navigator.appName; if it equals “Opera”,then the browser isn’t using a disguise.

The first step is to define a variable to hold the Opera version called fOperaVersion.Then,you can testto see if Opera is using a disguise.If it isn’t,then just assign fAppVersion to fOperaVersion:

The more difficult case is when Opera is using a disguise.For this, you need to use the user-agent stringand extract the version by using a regular expression:

var reOperaVersion = new RegExp(“Opera (\d+\.\d+)”);

This regular expression captures the Opera version, which is one or more numbers,followed by a decimal point,followed by one or more numbers.Note that this regular expression uses the constructor method and so d and . must be double escaped. The constructor method is used for backwards compatibility.

Even if the browser proves not to be Opera and this code isn’t executed, it may not support the regular expression literal style (which breaks ECMAScript Edition 1 syntax). This may cause an error.

Using this regular expression with the test() method stores the version in RegExp.$1,which is represented as RegExp[“$1”] to ensure it won’t break old-style JavaScript syntax.

At this point,the version of Opera is contained in fOperaVersion.The only thing left is to fill in the variables:

This completes the first section of the browser detection code.With just this section,it is possible to determine if a browser is Opera;and if it is, which version. Next up is the other problem browser: Safari.

Detecting Konqueror/Safari

Both Konqueror and Safari are based on the KHTML project and so can be considered the same. The problem is that you have no way to tell what version of KHTML the browser is using.Therefore,you can detect whether KHTML is in use,but you still need to rely on the browser version numbers to indicate browser capabilities.

To start,take a look at a few KHTML-based user agent strings:

The first four strings are from Konqueror; the last two are from Safari.Notice a few things in this mixture. First,not all the user-agent strings contain the string “KHTML”, so it is necessary to search for“Konqueror” and “AppleWebKit” or “Safari” as well as “KHTML”.Apple suggests that you look for“AppleWebKit” instead of “Safari” because other developers may embed the Apple Web Kit to create other browsers. Second, the Konqueror version number has no relation to either the Apple Web Kit or Safari version numbers.

So to start,you should determine if the browser is KHTML based:

After isKHTML is set, you can then determine which KHTML browser is being used.

Next,set up the variables for the different versions of the browsers:

To determine the version of Safari,you can either interpret the build number or the Apple Web Kit version.As mentioned previously,Apple suggests you only use the Apple Web Kit information. Safari 1.0 uses Apple Web Kit version 85 whereas Safari 1.2 uses version 124.To extract this information,it is again necessary to use a regular expression.

Looking at the user-agent strings at the beginning of this section,you see that the Apple Web Kit version can have decimals,but doesn’t always. This makes the regular expression a little bit more complicated than others in this chapter:

var reAppleWebKit = new RegExp(“AppleWebKit\/(\d+(?:\.\d*)?)”);

This expression uses a non-capturing group to include the decimal point and numbers after it.Other than that bit of trickery,the capturing group returns the version:

To determine the version of Konqueror,the regular expression is also a little bit complicated becauseKonqueror uses version numbers with zero, one, or two decimal points.Because of this,multiple noncapturing groups are necessary to capture all the variations.

var reKonq = new RegExp(“Konqueror\/(\d+(?:\.\d+(?:\.\d)?)?)”);

This regular expression says to match the string “Konqueror”, followed by a forward slash, followed by at least one digit, which may or may not be followed by a decimal point and one or more digits,which may or may not be followed by another decimal point and one or more digits.

After this value is extracted, it must be tested using the compareVersions() function in order to determine the minimal browser versions:

In this section of the code,check whether the compareVersions() returns a value greater-than or equal to zero, which indicates that the versions are either equal (if it returns 0) or that the first version is greater than the second (if it returns 1). The detection for KHTML-based browsers is complete.You can either just use isKHTML if you don’t care which browser is being used, or use the more specific variables to determine the browser and version.

Detecting Internet Explorer

As discussed earlier, the IE user-agent string is quite unique.Recall the user-agent string for IE 6.0:

Mozilla/4.0(compatible; MSIE 6.0; Windows NT)

When you compare this to other browsers, two parts stand out as unique:“compatible” and “MSIE”.This is the basis for detecting IE:

This seems to be straightforward, but there is a problem.Take a second look at the Opera user-agentstring when it is disguised as IE 6.0:

Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.54

See the problem? If you check for only “compatible” and “MSIE”,then Opera disguised as IE also returns true.The solution is to use the isOpera variable (explained previously) to ensure proper detection:

Next,define variables for the different IE versions:
var isMinIE4 = isMinIE5 = isMinIE5_5 = isMinIE6 = false;

Just as when you are determining the version of a disguised Opera, using a regular expression is the easiest way to extract IE’s version from the user-agent string:

var reIE = new RegExp(“MSIE (\d+\.\d+)”);

Once again, the pattern looks for one or more numbers,followed by a decimal point,followed by one or more numbers.Putting that expression into practice, you end up with this code:

And that’s all it takes to detect Internet Explorer.This code works equally well on Windows and Macintosh.Next up is IE’s main competitor, Mozilla.

Detecting Mozilla

By now,you should be familiar with how this works. Refresh your memory with the Mozilla user-agent string:

Mozilla/5.0(Windows; U; Windows NT 5.1; en-US; rv:0.9.4)
Gecko/20011128Netscape6/6.2.1

To be thorough,take a look at the Opera user-agent string when it is disguised as Mozilla 5.0:

Mozilla/5.0 (Windows NT 5.1; U) Opera 7.54

Fortunately,you have plenty of ways to determine that this is Mozilla.The glaring item that is clearly visible is that the Mozilla user-agent string says “Gecko”.If you a look at the Opera Mozilla 5.0 disguise, the string does not appear there. Eureka! That makes this easy:

var isMoz = sUserAgent.indexOf(“Gecko”) > -1;

Up until recently, this was enough to determine if the browser was indeed Mozilla.However,as you sawearlier,KHTML-based browsers have a user-agent string containing the phrase “like Gecko”, whichwould also return true for this test.So it is necessary to make sure that the browser contains “Gecko”but is not KHTML-based:

The isMoz variable is now accurate,so it’s time to move on to the specific versions.

Depending on which browsers you plan on supporting,you may have different Mozilla versions.Forinstance,Netscape 7 is based on Mozilla 1.0 whereas Netscape 7.1 is based on Mozilla 1.4.So,it makessense to test for these versions in case some users still have the Netscape-branded browsers. Mozilla 1.5 also is fairly popular,so that would be a good one to include as well:

var isMinMoz1 = sMinMoz1_4 = isMinMoz1_5 = false;

Once again,it is necessary to pull out the actual version number from the user-agent string. In Mozilla’scase,the Mozilla version is located after the text “rv:” and can contain either one or two decimal points,so a non-capturing group is also necessary here:

var reMoz = new RegExp(“rv:(\d+\.\d+(?:\.\d+)?)”);

It is easy to detect the Mozilla version if you use this value and the compareVersions() function:

The last task is to properly detect Mozilla’s predecessor: the original Netscape browser.

Detecting Netscape Communicator 4.x

Although Netscape Communicator is a dinosaur in the light of today’s standards-compliant browsers,it still has a pretty significant user base around the world.

To start, remember the user-agent string from Netscape Communicator 4.79:

Mozilla/4.79 (Win98; I)

As you can see,the user-agent string doesn’t specifically say that this is Netscape Communicator.All other browsers include the string “Mozilla” in their user-agent strings,so you can’t just check for that. The method for detecting Netscape Communicator 4.x is the same one used by Sherlock Holmes: If you eliminate the impossible, whatever remains, however implausible, must be true. For the purposes ofbrowser detection,this means you must first determine all the browsers that the user isn’t using:

var isNS4 = !isIE && !isOpera && !isMoz && !isKHTML;

So far so good. Next, there are three additional things to check:

1. That the string “Mozilla” is at the beginning of the user-agent string(at position 0).
2. That the value of navigator.appName is “Netscape”.
3. That the value of navigator.appVersion is greater-than or equal to 4.0, but less than 5.0 (this value has already been stored in the variable fAppVersion, created way back at the beginningof the code).

Adding these checks to the code, you get the following:

This variable accurately determines if the browser is Netscape Communicator.Next you want to determinethe minimal versions.For this,you should check for version 4.0, 4.5 (which was a major release with lots of code improvements),4.7 (another major release),and 4.8 (the last release).

var isMinNS4 = isMinNS4_5 = isMinNS4_7 = isMinNS4_8 = false;

And because Netscape Communicator stores its version number in a logical way, it is very easy to determine the values for these variables:

The first variable, isMinNS4,is automatically set to true because this was one of the tests performedwhen calculating isNS4.All the other minimal versions must be checked for in the normal way.

This completes the browser detection portion of the script.Next up is platform and operating systemdetection.