Team LiB
Previous Section Next Section

Creating a Multi-Browser Compatible Web Page

It is important to understand the differences between different browsers in order to handle each in the way it expects. First of all, though, you need to know which browser your Web page is running in. To get information about the browser your Web page is currently running in, use the built-in navigator object.

Navigator Properties

There are several Navigator-only properties that you can use in your Web page. The following is a list of the names and descriptions of each:

  • appCodeName. This property is a string that contains the code name of the browser, "Netscape" for Netscape and "Microsoft Internet Explorer" for Internet Explorer.

  • appVersion. This property is a string that contains the version of the browser as well as other useful information such as its language and compatibility.

  • language. This property contains the two-letter abbreviation for the language that is used by the browser. Netscape only.

  • mimTypes[]. This property is an array that contains all MIME types supported by the client. Netscape only.

  • platform[]. This property is a string that contains the platform for which the browser was compiled—"Win32" for 32-bit Windows operating systems.

  • plugins[]. This property is an array containing all the plug-ins that have been installed on the client. Netscape only.

  • userAgent[]. This property is a string that contains the code name and version of the browser. This value is sent to the originating server to identify the client.

Navigator Methods

In addition to Navigator-specific properties, there are several Navigator-specific methods. Here is a list of their names and descriptions:

  • javaEnabled(). This method determines if JavaScript is enabled in the client. If JavaScript is enabled, this method returns true; otherwise, it returns false.

  • plugings.refresh. This method makes newly installed plug-ins available and populates the plugins array with all new plug-in names. Netscape only.

  • preference(name,value). This method allows a signed script to get and set some Netscape preferences. If the second parameter is omitted, this method will return the value of the specified preference; otherwise, it sets the value. Netscape only.

  • taintEnabled(). This method returns true if data tainting is enabled and false otherwise.

Handling Differences in Event Models among Browsers

When an event is fired in a Netscape browser, the event travels through each of the objects in the object hierarchy—window, document, layer—before it reaches the element that was the target of the event. Without any instructions to the contrary, these objects simply pass the event down the hierarchy. If you wish to capture the events at the window, document,or layer objects, you must use the captureEvent() method.

You can specify several event types to be captured with one call to the captureEvent() method by using the bitwise operator or (|). For example, if you wanted to capture several of the mouse events, you could use the following call to the captureEvent() method:

captureEvent( Event.MOUSEDOWN | Event.MOUSEUP | Event.CLICK |
                       Event.MOUSEOVER | Event.MOUSEOUT );

After specifying which event to capture, you still need to write handler functions for each event. You tell the object which handler function goes with which event by setting the object's event handler properties:

document.mouseover = imageRollOver;
document.mouseout = imageRollBack;

When an event handler function is called, it is automatically passed the event object as a parameter. The function can then query information about the event, such as where the mouse was at the time, what modifier keys were used, and what the intended target for the event was.

function imageRollOver( event )
{
  <statements>
}

function imageRollBack( event )
{
  <statements>
}

Some events may not have information in each property. To make sure the event handlers for window, document, and layer work immediately when the page loads, it would be a good idea to put the code to capture them in the onLoad event handler for the object:

document.onload = loading;

function loading( event )
{
  document.onclick = clicked; 
  document.ondblclick = dblClicked;
}

function clicked( event )
{
  <statements>
}

function dblClicked( event )
{
  <statements>
}

This will ensure that the event handlers are set up before any events of that type can occur.

It is often necessary, after capturing an event, to send the event to a different object for handling. There are two separate ways to do this. The routeEvent() method of the window and document objects allow an event to be transferred to its intended target. The routeEvent() method requires that the event object be passed to the event-handler function as a parameter. The second way to pass an event to a different object is by the object's handleEvent() method. Every object that has event-handler capabilities has the handleEvent() method. The handleEvent() method takes one parameter, the event object passed to the event-handler function.

Some time during the execution of the code on your page, it may be necessary to release events that were previously being captured. All top-level objects in the Navigator hierarchy have the releaseEvents()method, which will turn off event-capturing for that object. Just like the captureEvents() method, the releaseEvents() method requires one parameter that will specify which event or events are to be released.

Internet Explorer handles events in the opposite way that Netscape does. Events in Internet Explorer bubble up from the root element (the target of the event) through the element hierarchy. The element hierarchy is different from Netscape's object hierarchy in that it is comprised of HTML elements rather than JavaScript objects. For example, in the following simple HTML document:

<HTML>
  <BODY>
    <FORM>
      <INPUT TYPE="text"> 
    </FORM>
  </BODY>
</HTML>

any events that are generated for the text field, such as the user typing into it or clicking on it, are passed up the element hierarchy if not captured at the text field itself. The event could go through the INPUT element, and if there is no suitable event handler, the event will propagate up through the FORM and BODY elements, each of which will get a change to capture it.

Event bubbling is automatic in Internet Explorer and, for the most part, you will not need to worry about it. Sometimes it is necessary to turn this feature off. For example, if you are using an onClick event handler on the document object of your Web page and at the same time capturing onClick events of specific buttons in a form, you would not want the onClick events caused by the buttons that don't have an event handler to propagate to the document object. If you find that you need to turn off this feature, you can do so with the following command:

window.event.cancelBubble = true;

This statement can be used to cancel any given event anywhere in the element hierarchy. Only one event can bubble through the hierarchy at a time, so this command can be used on a perevent basis.

Here is a partial example of using bubbling and non-bubbling events together:

var isNav = navigator.appName == "Netscape";
function onLoad()
{
   if( isNav )
   {
     captureEvent( Event.MOUSEDOWN | Event.MOUSEUP);
   }
   document.onmousedown = mouseDown();
   document.onmouseup   = mouseUp(); 
}

function mouseDown()
{
   if( isNav )
   {
     captureEvent( Event.MOUSEMOVE );
   }
   document.mousemove = mouseMove();
}

function mouseMove()
{
   ...
}

function mouseUp()
{
  if( isNav )
  {
    releaseEvent( Event.MOUSEMOVE );
  }
  document.mousemove = null;
}

As you can see, it is not that difficult to handle both types of event propagation.


Team LiB
Previous Section Next Section