Team LiB   Previous Section   Next Section

19.4 The Netscape 4 Event Model

The Netscape 4 event model is like the original Level 0 event model, except that it provides event details in an Event object that is passed as an argument to handler functions. It also supports special methods to enable event capturing. These features are explained in the sections that follow.

19.4.1 The Netscape 4 Event Object

The Netscape 4 event model defines an Event object that contains details about the event that occurred. Like the DOM Level 2 model, it passes an Event object as an argument to all event handlers. Unfortunately, however, the properties of the Netscape 4 Event object are almost entirely different than those of the IE Event object and the various DOM Level 2 event objects. The key Event properties in the Netscape 4 event model are:

type

A string that specifies the type of event that occurred. This string is the name of the event handler, minus the "on" prefix (e.g., "click" or "mousedown"). This property is compatible with the IE and DOM Level 2 Event objects.

target

The document element on which the event occurred. This property is compatible with the target property of the DOM Level 2 Event object and comparable to srcElement in the IE Event object.

pageX , pageY

These properties specify the pixel coordinates at which the event occurred, relative to the upper-left corner of the window. For documents that are larger than the window, you need to add in the offsets window.pageXOffset and window.pageYOffset to convert these to document coordinates. Comparable to the clientX and clientY properties of the DOM Level 2 MouseEvent object and the IE Event object.

which

An integer that specifies which mouse button or key was pressed. For mouse events, the left, middle, and right buttons are specified by the values 1, 2, and 3, respectively. Compare this to the (mutually incompatible) button properties of the DOM Level 2 MouseEvent object and the IE Event object. For keyboard events, this property contains the Unicode encoding of the key that was pressed. Compare this to the keyCode property of the IE Event object.

modifiers

An integer that specifies which keyboard modifier keys were pressed when the event occurred. The value is a bitmask comprised of any of the following values: Event.ALT_MASK, Event.CONTROL_MASK, Event.META_MASK, and Event.SHIFT_MASK. Comparable to the altKey, ctrlKey, metaKey, and shiftKey properties of the DOM Level 2 MouseEvent object and the IE Event object.

In the Netscape 4 event model, an Event object is passed to all event handlers. When an event handler is defined as a string of JavaScript code in an HTML attribute, that code is implicitly converted to a function with an argument named event. This means that HTML event handlers can refer to the Event object with the identifier event. (Compare this to the IE model, in which the event identifier refers to the global Event object. The implementations are quite different, but the practical result is the same.)

For backward compatibility, the Event objects used by Mozilla and Netscape 6 implement most of the properties of the Netscape 4 Event object, with the notable exception, at the time of this writing, of the modifiers property.

19.4.2 Event Capturing in Netscape 4

The Netscape 4 event model does not support event bubbling, as the IE event model does, but it does support a limited form of event capturing, like the DOM Level 2 model does. (In fact, the event-propagation model for the DOM standard is a combination of the Netscape capturing and IE bubbling models.) Although Netscape 4 supports a form of event capturing, the way it works is quite different from that defined by the DOM Level 2 event model.

In Netscape 4, the Window, Document, and Layer objects may request the opportunity to preview certain types of events before they are processed by the elements that generated them. Such a request is made with the captureEvents( ) method of these objects. The argument to this method specifies the type of events to be captured; it is a bitmask composed of constants defined as static properties of the Event constructor. So, for example, if a program wants all mousedown and mouseup events to be routed to the Window object before being handled by the object for which they were intended, it can call captureEvents( ) like this:

window.captureEvents(Event.MOUSEDOWN | Event.MOUSEUP);

Having made this request to receive the events, the program then has to register event handlers for those events:

window.onmousedown = function(event) { ... };

window.onmouseup = function(event) { ... }; 

When one of these capturing event handlers receives an event, it gets to decide what should happen to it next. In some programs, a captured event is handled and propagates no further. In other circumstances, however, the program wants to pass the event along. If you pass the event to the routeEvent( ) method of the Window, Document, and Layer objects, the method passes the event to the next Window, Document, or Layer object that has used captureEvents( ) to specify interest in that type of event. Or, if there is no other capturing object to which to route the event, it is routed to its original source object and the appropriate event handler of that object is invoked. For example:

function clickHandler(event) {

  if (event.which == 3) {  // It is the right mouse button

    // Handle the event here, and do nothing else

    // The event will not propagate any further

  }

  else {  // It is not the right mouse button

    // We're not interested in this event, so let it propagate on

    // to some element that is interested in it

    window.routeEvent(event);

  }

} 

An alternative to calling routeEvent( ) is to simply pass the Event object to the handleEvent( ) method of the object to which you want the event delivered. The handleEvent( ) method passes the event to the appropriate event handler of that object.

When a Window, Document, or Layer object no longer wishes to capture events, it should call the releaseEvents( ) method, specifying the same argument it passed to captureEvents( ).

The Netscape 4 event-capturing model is fundamentally incompatible with the DOM Level 2 event-capturing model. For example, the DOM model propagates captured events by default, but the Netscape model does not. Mozilla and Netscape 6 implement the Netscape 4 event-capturing API, but the API appears to be nonfunctional.

19.4.3 Example: Dragging with the Netscape 4 Event Model

Example 19-4 is an implementation of our familiar beginDrag( ) method, using the Netscape 4 event model (and the Netscape 4 Layer-based DOM). It demonstrates how events are captured and how event handlers are written for this event model. This example includes both JavaScript code and a simple HTML document that uses the beginDrag( ) method to define an image that the user can drag. Compare this implementation of beginDrag( ) to the two we've seen previously. Note that this example defines its nested event handler functions at the beginning of the beginDrag( ) function instead of at the end. This is a bug workaround: if the nested functions are placed at the end of beginDrag( ), they do not work in Netscape 4. Also note the onmousedown handler at the end of the example: it allows dragging only if the Shift key is held down and tests for this modifier key using the Netscape 4 Event object API, which is significantly different from the DOM Level 2 and IE APIs.[2]

[2] At the time of this writing, Mozilla and Netscape 6 have not retained compatibility with the modifiers property of the Netscape 4 Event object, so the onmousedown handler shown here works only in Netscape 4, not in Netscape 6.

Example 19-4. Dragging in Netscape 4
<script>

/**

 * This function is intended for use in a mousedown event handler of an object

 * within a layer. The first argument must be a Layer object. The second

 * argument must be the Event object for the mousedown event.

 **/

function beginDrag(layerToDrag, event) {

    // This nested function responds to mousemove events and moves the layer

    function moveHandler(event) {

        // Move the element to the current mouse position, adjusted as

        // necessary by the offset of the initial mouse-click

        layerToDrag.moveTo(event.pageX - deltaX, event.pageY-deltaY);



        // Don't take any default action, and don't propagate further

        return false;

    }



    // This nested function handles mouseup events

    // It stops capturing events and deregisters the handlers

    function upHandler(event) {

        // Stop capturing and handling drag events

        document.releaseEvents(Event.MOUSEMOVE | Event.MOUSEUP);

        document.onmousemove = null;

        document.onmouseup = null;



        // Don't take any default action, and don't propagate further

        return false;

    }



    // Compute the distance between the upper-left corner of the layer and

    // the mouse-click. The moveHandler function below needs these values.

    var deltaX = event.pageX - layerToDrag.left;

    var deltaY = event.pageY - layerToDrag.top;



    // Arrange to capture mousemove and mouseup events

    // Then arrange to handle them using the functions defined below

    document.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP);

    document.onmousemove = moveHandler;

    document.onmouseup = upHandler;

}

</script>

<!-- Here's how we might use beginDrag(  ) in Netscape 4 -->

<!-- Define a layer using CSS attributes -->

<div id="div1" style="position:absolute; left:100px; top:100px;">

<!-- Give the layer some content and a mousedown event handler -->

<img src="plus.gif" width="20" height="20"

     onmousedown="if (event.modifiers & Event.SHIFT_MASK)

                      beginDrag(window.document.div1, event);">

</div>

    Team LiB   Previous Section   Next Section