19.4 The Netscape 4 Event ModelThe 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 ObjectThe 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:
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 4The 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 ModelExample 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]
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>
|