Javascript: The Definitive Guide

Previous Chapter 18 Next
 

18.3 Compatibility with JavaScript 1.0 Browsers

The previous section discussed compatibility techniques that are useful when JavaScript 1.0 (or JavaScript 1.1) code is loaded into a browser that does not support JavaScript. This section discusses techniques you can use when JavaScript 1.1 code is loaded into browsers that only support JavaScript 1.0. The basic goals are the same: we need to prevent the code from being interpreted by browsers that don't understand it, and we need to display a special message on those browsers that informs the user that their browsers can't run the scripts on the page.

The LANGUAGE Attribute

The first goal is easy. As we saw in Chapter 10, Client-Side Program Structure, we can prevent a JavaScript 1.0 browser from attempting to run code that requires JavaScript 1.1 by setting the LANGUAGE attribute of the <SCRIPT> tag appropriately. It looks like this:

<SCRIPT LANGUAGE="JavaScript1.1">
<!-- Hide from non-JavaScript browsers
        .
        .  JavaScript 1.1 code goes here
        .
// Done hiding -->
</SCRIPT>  
Note that we still have to use our trick with HTML comments to prevent old non-JavaScript browsers from formatting our JavaScript code as HTML.

Note that the use of the LANGUAGE attribute is a perfectly general technique. When the next version of JavaScript (presumably known as "JavaScript1.2") arrives, we'll be able to prevent JavaScript 1.0 and JavaScript 1.1 browsers from interpreting 1.2-level code by specifying LANGUAGE="JavaScript1.2".

<NOSCRIPT>

Hiding our JavaScript 1.1 code from browsers that can't understand it was easy. It turns out that gracefully displaying a message on all browsers that don't understand our JavaScript 1.1 code is not nearly so straightforward. When we wanted to display a message for non-JavaScript browsers that couldn't run our JavaScript 1.0 code used the comment trick shown in Example 18-2. This technique will still work when our JavaScript 1.1 code is read by non-JavaScript browsers, but it won't work when that code is read by JavaScript 1.0 browsers.

The <NOSCRIPT> and </NOSCRIPT> tags provide a partial solution. These tags were introduced by Netscape in Navigator 3.0. The intent of these tags is that anything between them will be ignored on a script-capable browser and will be displayed on a script-incapable browser. This is a simple, obvious idea, but the implementation isn't quite right. Since these tags were introduced in Navigator 3.0, Navigator 2.0 does not know about them, and so it ignores them and displays any HTML that appears between them. Navigator 3.0, on the other hand knows about these tags, and since it is a JavaScript-enabled browser it ignores all the HTML between the tags. What this means is that <NOSCRIPT> and </NOSCRIPT> provide us a way to display a message on Navigator 2.0 (a JavaScript 1.0 browser) that does not appear on Navigator 3.0 (a JavaScript 1.1 browser). Example 18-4 shows how you might use these tags to display a message when our JavaScript 1.1 code could not be run.

Example 18-4: Displaying a Message with <NOSCRIPT>

<HTML>
<HEAD><TITLE>My Cool JavaScript 1.1 Page</TITLE></HEAD>
<BODY>
<H1>My Cool JavaScript 1.1 Page</H1>
<NOSCRIPT>
    <!-- This message will be displayed by Navigator 2.0 and -->
    <!-- by non-JavaScript browsers -->
    <HR><I>
    This page depends heavily on JavaScript 1.1.<BR>
    Since your browser doesn't seem support that version of
    JavaScript, you're missing out on a lot of cool stuff!
    </I><HR>
</NOSCRIPT>
<SCRIPT LANGUAGE="JavaScript1.1"> <!--
    // My Cool JavaScript 1.1 code goes here
// --></SCRIPT>
</BODY></HTML>

Unfortunately, this <NOSCRIPT> technique is not entirely adequate. Since Navigator 2.0 does not recognize <NOSCRIPT>, this tag does not serve to distinguish JavaScript-enabled browsers from non-JavaScript browser. In the example above, we use it to distinguish JavaScript 1.1 browsers from JavaScript 1.0 browsers and from non-JavaScript browsers. But this use isn't correct either. It turns out that Internet Explorer 3.0 recognizes <NOSCRIPT>, and since it supports scripting, even JavaScript 1.0 scripting, it ignores everything between <NOSCRIPT> and </NOSCRIPT>. While this is the technically correct thing to do, the incompatibility between Navigator and Internet Explorer renders the <NOSCRIPT> tag practically useless. What this means is that the message shown in Example 18-4 will be displayed, as desired, in Navigator 2.0 and in non-JavaScript browsers, but it will not be displayed by Internet Explorer.

There is another problem with <NOSCRIPT> as well. It is not a general-purpose mechanism. When JavaScript 1.2 is out, there will no way to use <NOSCRIPT> to display a message on all browsers that do not support that version of the language.

Failing Gracefully the Hard Way

Since <NOSCRIPT> doesn't do quite what we want we have to be more explicit in displaying our messages. We'll revert to using HTML comments to display our failure message on non-JavaScript browsers, and we'll use JavaScript 1.0 to display a message on JavaScript-enabled browsers that do not support JavaScript 1.1. Example 18-5 shows how we do it.

Example 18-5: Displaying a Message for Browsers That Do Not Support JavaScript 1.1

<!-- Set a variable to determine what version of JavaScript we support -->
<!-- This technique can be extended to any number of language versions -->
<SCRIPT LANGUAGE="JavaScript"> <!--
  _version = 10; // --> </SCRIPT>
<SCRIPT LANGUAGE="JavaScript1.1"> <!--
  _version = 11; // --> </SCRIPT>
<SCRIPT LANGUAGE="JavaScript1.2"> <!-- 
  _version = 12; // --> </SCRIPT>
<!-- If the version is not high enough, display a message -->
<!-- This version of the message appears for JavaScript 1.0 browsers -->
<SCRIPT LANGUAGE="JavaScript"> <!--
  if (_version < 11) {
    document.write('<HR><H1>This Page Requires JavaScript 1.1</H1>');
    document.write('Your JavaScript 1.0 browser cannot run this page.<HR>');
  }
// --> </SCRIPT>
<SCRIPT LANGUAGE="JavaScript1.1">
<!-- This version of the message will appear on non-JavaScript browsers -->
<!-- --> <HR><H1>This Page Requires JavaScript 1.1</H1>
<!-- --> Your non-JavaScript browser cannot run this page.<HR>
<!--  Start hiding the actual program code
        .
        .  The actual JavaScript 1.1 code goes here.
        .
// Done hiding -->
</SCRIPT>

While the technique shown in Example 18-5 is not nearly so elegant as the <NOSCRIPT> solution, the important points to note are that it works correctly with Internet Explorer, and that it is extensible for future versions of the language. That is, this technique will allow you to display messages on JavaScript 1.0, JavaScript 1.1, and non-JavaScript browsers when you write code that only works for JavaScript 1.2.

Loading a New Page for Compatibility

In Example 18-3 we saw how you could use the Location object to read in a JavaScript-based page if JavaScript is supported, and otherwise simply use a non-JavaScript page. You can obviously use this same technique to load a JavaScript 1.1 page from a default JavaScript 1.0 page, or vice versa.

If we take this idea a couple of steps further, we can come up with some interesting variations. Example 18-6 shows one such variation. It is a short program that tests whether JavaScript 1.1 is supported. If so, it uses the Location.replace() method to load in a JavaScript 1.1 page (recall that using replace() prevents the Back button from breaking). If JavaScript 1.1 is not supported, it displays a message saying so on either a JavaScript 1.0 browser or a non-JavaScript browser.

Example 18-6: A Web Page to Test for JavaScript Compatibility

<!-- This script jumps to a new page if JavaScript 1.1 is supported -->
<!-- it also set a flag that we can test for below so we don't display -->
<!-- the message during the time the browser is loading the new file -->
<SCRIPT LANGUAGE="JavaScript1.1"> <!--
location.replace(location.search.substring(1)); self.loading = true;
// --> </SCRIPT>
<!-- Otherwise we display a message, either in HTML or with JavaScript 1.0 -->
<SCRIPT LANGUAGE="JavaScript">
<!-- --> <HR><H1>This Page Requires JavaScript 1.1</H1>
<!-- --> Your non-JavaScript browser cannot run this page.<HR>
<!-- 
  if (!self.loading) {
    document.write('<HR><H1>This Page Requires JavaScript 1.1</H1>');
    document.write('Your JavaScript 1.0 browser cannot run this page.<HR>');
  }
// -->
</SCRIPT>

The most interesting thing about this example is that it is a generic one--the name of the JavaScript 1.1 file to be loaded is encoded in the search portion of the original URL, and that file will be loaded only if JavaScript 1.1 is supported. Thus if the file in this example had the name testjs11.html, then you could use it in URLs like the one shown in this hyperlink:

<A HREF="http://my.isp.net/~david/utils/testjs11.html?../js/cooljs11.html">
Visit my cool JavaScript 1.1 page!
</A>  

The other thing to note about Example 18-6 is that (at least with Navigator 3.0) calling Location.replace() starts a new page loading but does not immediately stop the current page from executing. Therefore, this example has to set a flag when it starts loading the specified JavaScript 1.1 page. If this flag is set, then the JavaScript 1.0 code in the example will not display the message. If it didn't do this, the message would briefly flash on the screen before the JavaScript 1.1 page was loaded. For this same reason the example can't simply display the compatibility message in a normal HTML <BODY>.

Included Files and Compatibility with Navigator 2.0

As we saw in Chapter 10, Client-Side Program Structure, Navigator 3.0 can use the SRC attribute of the <SCRIPT> tag to refer indirectly to a file of JavaScript code rather than having that code appear directly in the HTML file. This is a very useful thing to do for a number of reasons, including modularity, ease of code maintenance and reuse, and caching efficiency on the client-side.

The use of the SRC attribute also makes it somewhat easier to fail gracefully and display a message. Example 18-7 shows how. This example relies on the fact that a JavaScript 1.0 browser doesn't understand the SRC attribute and tries to execute the code between the <SCRIPT> and </SCRIPT> tags.

Example 18-7: Displaying a Failure Message When Using <SCRIPT SRC=>

<SCRIPT LANGUAGE="JavaScript" SRC="../javascript/util.js">
<!-- This is the message for non-JavaScript browsers -->
<!-- --> <H1>Sorry, this page requires Netscape Navigator 3.0</H1>
<!--  code for Navigator 2.0 browsers here
document.write("<H1>Sorry, this page requires Navigator 3.0.</H1>");
// --></SCRIPT>

There are so many good reasons to use the SRC attribute that you may find yourself wanting to use it even when you are trying to maintain compatibility with JavaScript 1.0. In order to do this, you'll have to maintain two separate versions of your web page, one that works with JavaScript 1.1 and one that works with JavaScript 1.0. The default page will assume JavaScript 1.1 support and will load the JavaScript code with the SRC attribute. If that attribute is not recognized, then this default page must arrange to load in the other version of the page which has JavaScript 1.0 code explicitly included in it. You can do this with a variation on code we saw earlier in this chapter. Example 18-8 shows what it will look like.

Example 18-8: Load an Alternate Page When <SCRIPT SRC=> Fails

<!-- Try to load the JavaScript code with SRC. -->
<SCRIPT SRC="../javascript/utils.js"> <!--
// if the SRC attribute is not recognized, then this code will load
// a compatible version of the page that does not use SRC. The new
// page will have the same name but will be in a directory named "compat/"
var path = location.path;
var filename = path.substring(path.lastIndexOf("/")+1, path.length);
location = "compat/" + filename;
// --></SCRIPT>

Note that, as we've seen, techniques like this one that rely on assigning a new URL to the location property break the Back button of the browser. Also note that server-side includes (SSI) provide an easy way to maintain the two separate versions of a web page required by this technique. One file uses the SRC attribute to read in its JavaScript code on the client side, and the other uses a server-side include to read in the JavaScript code on the server side.


Previous Home Next
Compatibility with Non-JavaScript Browsers Book Index Compatibility Through CGI Scripts