The propagation of events through the object hierarchy is very important to understand. If an event is fired for a specific object that does not have an event handler for it, where does the event go? Unfortunately, like many things, event propagation differs between Netscape and Internet Explorer. Netscape uses a top-down technique of event propagation where an event starts at the document level and passes through each layer of HTML code on its way to the source. An event can be captured at any one of these layers. Internet Explorer uses an event propagation approach that is the complete opposite of Netscape. In Internet Explorer, an event starts at the source and bubbles up through the different HTML layers. Just like Netscape, the even can be captured and handled at any one of these layers.
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 any one of these object levels, you need to use the captureEvent() method for any of the window, document, or layer objects.
The captureEvent() method requires one parameter that will tell the corresponding object which type of event to capture. This parameter can be one of several static properties of the Event object:
Event.ABORT |
Event.BLUR |
Event.CHANGE |
Event.CLICK |
Event.DBLCLICK |
Event.DRAGDROP |
Event.ERROR |
Event.FOCUS |
Event.KEYDOWN |
Event.KEYPRESS |
Event.KEYUP |
Event.LOAD |
Event.MOUSEDOWN |
Event.MOUSEMOVE |
Event.MOUSEOUT |
Event.MOUSEOVER |
Event.MOUSEUP |
Event.MOVE |
Event.RESET |
Event.RESIZE |
Event.SCROLL |
Event.SELECT |
Event.SUBMIT |
Event.UNLOAD |
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, like this:
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> }
A Navigator event supports the following Navigator-specific properties:
Data. Returns a string array that contains the URL of any dropped objects. Netscape only.
layerX/layerY. Synonyms for the x/y properties of the event object.
Modifiers. Captures the document's mouse clicks. Syntax is:
document.onClick="<statements>"
pageX/pageY. These properties return the point at which the cursor was when the event occurred in relation to the page.
screenX/screenY. These properties return the point at which the cursor was when the event occurred in relation to the screen.
target. This property contains a reference to the object to which the event was originally sent.
Type. This property returns a string containing the vent type, click, key down, etc.
Which. This property returns which mouse button or key was pressed. For the mouse, 1 = left button, 2 = middle button, and 3 = right button. For keys, this property is the ASCII value of the key.
Some events may not have information in each property; whether they do or not depends on what type of events they are. To make sure the event handlers for the top-level objects— 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, like this:
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 allows 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.
Sometime in the execution of the code on your page, it may be necessary to release events that were previously captured. All top-level objects in the Navigator hierarchy have the method releaseEvents(), 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 Navigator 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 instead of JavaScript objects. For example, in this 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 not a suitable event handler, propagate up through the FORM and BODY elements, each of which will get a chance to capture the event.
Event bubbling is automatic in Internet Explorer, and for the most part, you will not need to worry about it. If, however, 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.
One very common ability that you can enjoy with most native applications is drag and drop. The ability to perform drag-and-drop operations in a Web page is quite a bit more complicated. This example will help you to understand Internet Explorer's event propogation.
<html> <head> <title> JavaScript Professional Projects - Drag and Drop </title> <style type="text/css"> <!-- #imageA{ position: absolute; left: 450; top = 250; z-index: 1; } #imageB{ position: absolute; left: 10; top = 150; z-index: 0; } --> </style> <script language="JavaScript"> <!-- var clicked; function onLoad() { document.onmousedown = mouseDown; } function mouseDown() { if( clicked == null ) { if( clicked = getClickedImage( event ) ) { document.onmousemove = mouseMove; clicked.style.zIndex += 2; } } else { document.onmousemove = null; clicked = null; } } function mouseMove() { with( clicked.style ) { positionImage( clicked, window.event.x, window.event.y ); } } function getClickedImage( event ) { var obj = window.event.srcElement.parentElement; if( obj.tagName == "DIV" ) return( window.event.srcElement.parentElement ); else return( null ); } function positionImage( image, xPos, yPos ) { image.style.left = xPos; image.style.top = yPos; } // --> </script> </head> <body onLoad="JavaScript: onLoad();"> <center> <font size=6>JavaScript Professional Projects</font><br> <font size=4>Chapter 6: Drag and Drop</font> </center> <br><br> Click on an image to move it. Click again to release it.<br><br> <div ID="imageB"> <img border="0" src="myImage1.jpg"> </div> <div ID="imageA"> <img border="0" src="myImage2.jpg"> </div> </body> </html>
In this example, all events are forwarded to the document object of the Web page. From there, the mouse events are used to move one of two images around on the screen. Unfortunately, this example will only work in Internet Explorer browsers, due to Netscape's inability to access HTML elements directly.