Tải bản đầy đủ (.pdf) (10 trang)

JavaScript Bible, Gold Edition part 88 potx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (92.31 KB, 10 trang )

718
Part III ✦ Document Objects Reference
Listing 29-2 (continued)
NAME=”layerButton2”
onClick=”alert(‘Event finally reached Button:’ + this.name)”></P>
</FORM>
</BODY>
</LAYER>
</BODY>
</HTML>
Passing events toward their targets
If you capture a particular event type, your script may need to perform some lim-
ited processing on that event before letting it reach its intended target. For exam-
ple, perhaps you want to do something special if a user clicks an element with the
Shift metakey pressed. In that case, the function that handles the event at the docu-
ment level inspects the event’s modifiers property to determine if the Shift key was
pressed at the time of the event. If the Shift key was not pressed, you want the
event to continue on its way to the element that the user clicked.
To let an event pass through the object hierarchy to its target, you use the
routeEvent() method, passing as a parameter the event object being handled in
the current function. A
routeEvent() method does not guarantee that the event
will reach its intended destination, because another object in between may have
event capturing for that event type turned on and will intercept the event. That
object, too, can let the event pass through with its own
routeEvent() method.
Listing 29-3 demonstrates event routing by adding onto the document being built
in previous examples. While the clickable button objects are the same, additional
powers are added to the document and layer function handlers that process events
that come their way. For each of these event-capturing objects, you have additional
checkbox settings to allow or disallow events from passing through after each level


has processed them.
The default settings for the checkboxes are like the ones in Listing 29-2, where
event capture (for the
click event) is set for both the document and layer
objects. Clicking any button causes the document object’s event handler to process
and none other. But if you then enable the checkbox that lets the event continue,
you find that click events on the layer buttons cause alerts to display from both the
document and layer object event handler functions. If you then also let events con-
tinue from the layer object, a click on the button displays a third alert, showing that
the event has reached the buttons. Because the
main1 button is not in the layer,
none of the layer object event handling settings affect its behavior.
Listing 29-3: NN4 Capture, Release, and Route Events
<HTML>
<HEAD>
<SCRIPT LANGUAGE=”JavaScript”>
function setDocCapture(enable) {
if (!enable) {
document.captureEvents(Event.CLICK)
719
Chapter 29 ✦ Event Objects
} else {
document.releaseEvents(Event.CLICK)
document.forms[0].setDocRte.checked = false
docRoute = false
}
}
function setLayerCapture(enable) {
if (!enable) {
document.layer1.captureEvents(Event.CLICK)

} else {
document.layer1.releaseEvents(Event.CLICK)
document.forms[0].setLyrRte.checked = false
layerRoute = false
}
}
var docRoute = false
var layerRoute = false
function setDocRoute(enable) {
docRoute = !enable
}
function setLayerRoute(enable) {
layerRoute = !enable
}
function doMainClick(e) {
if (e.target.type == “button”) {
alert(“Captured in top document”)
if (docRoute) {
routeEvent(e)
}
}
}
document.captureEvents(Event.CLICK)
document.onclick=doMainClick
</SCRIPT>
</HEAD>
<BODY>
<B>Capture, Release, and Routing of Event.CLICK</B>
<HR>
<FORM>

<INPUT TYPE=”checkbox” NAME=”setDocCap”
onMouseDown=”setDocCapture(this.checked)” CHECKED>Enable Document Capture&nbsp;
<INPUT TYPE=”checkbox” NAME=”setDocRte”
onMouseDown =”setDocRoute(this.checked)”>And let event continue<P>
<INPUT TYPE=”checkbox” NAME=”setLyrCap”
onMouseDown =”setLayerCapture(this.checked)” CHECKED>Enable Layer Capture&nbsp;
<INPUT TYPE=”checkbox” NAME=”setLyrRte”
onMouseDown =”setLayerRoute(this.checked)”>And let event continue
<HR>
<INPUT TYPE=”button” VALUE=”Button ‘main1’” NAME=”main1”
onClick=”alert(‘Event finally reached Button:’ + this.name)”>
</FORM>
<LAYER ID=”layer1” LEFT=200 TOP=150 BGCOLOR=”coral”>
Continued
720
Part III ✦ Document Objects Reference
Listing 29-3 (continued)
<HEAD>
<SCRIPT LANGUAGE=”JavaScript”>
function doLayerClick(e) {
if (e.target.type == “button”) {
alert(“Captured in layer1”)
if (layerRoute) {
routeEvent(e)
}
}
}
layer1.captureEvents(Event.CLICK)
layer1.onclick=doLayerClick
</SCRIPT>

</HEAD>
<BODY>
<FORM>
&nbsp;layer1<BR><P><INPUT TYPE=”button” VALUE=”Button ‘layerButton1’”
NAME=”layerButton1”
onClick=”alert(‘Event finally reached Button:’ + this.name)”></P>
<P><INPUT TYPE=”button” VALUE=”Button ‘layerButton2’”
NAME=”layerButton2”
onClick=”alert(‘Event finally reached Button:’ + this.name)”></P>
</FORM>
</BODY>
</LAYER>
</BODY>
</HTML>
In some cases, your scripts need to know if an event that is passed onward by
routeEvent() method activated a function that returns a value. This knowledge is
especially valuable if your event must return a
true or false value to let an object
know if it should proceed with its default behavior (for example, whether a link
should activate its
HREF attribute URL or cancel after the event handler evaluates
to
return true or return false). When a function is invoked by the action of a
routeEvent() method, the return value of the destination function is passed back
to the
routeEvent() method. That value, in turn, can be returned to the object
that originally captured the event.
Event traffic cop
The last scenario is one in which a higher-level object captures an event and
directs the event to a particular object elsewhere in the hierarchy. For example, you

could have a document-level event handler function direct every click event whose
modifiers property indicates that the Alt key was pressed to a Help button object
whose own
onClick event handler displays a help panel (perhaps shows an other-
wise hidden layer).
You can redirect an event to any object via the
handleEvent() method. This
method works differently from the others described in this chapter, because the
object reference of this method is the reference of the object to handle the event
721
Chapter 29 ✦ Event Objects
(with the event object being passed as a parameter, such as the other methods). As
long as the target object has an event handler defined for that event, it will process
the event as if it had received the event directly from the system (even though the
event object’s
target property may be some other object entirely).
To demonstrate how this event redirection works, Listing 29-4 includes the final
additions to the document being built so far in this chapter. The listing includes
mechanisms that allow all
click events to be sent directly to the second button in
the layer (
layerButton2). The previous interaction with document and layer event
capture and routing is still intact, although you cannot have event routing and redi-
rection on at the same time.
The best way to see event redirection at work is to enable both document and
layer event capture (the default settings). When you click the
main1 button, the
event reaches only as far as the document-level capture handler. But if you then
turn on the “Send event to ‘layerButton2’” checkbox associated with the document
level, a click of the

main1 button reaches both the document-level event handler
and
layerButton2, even though the main1 button is not anywhere near the layer
button in the document object hierarchy. Click other checkboxes to work with the
interaction of event capturing, routing, and redirection.
Listing 29-4: NN4 Redirecting Events
<HTML>
<HEAD>
<SCRIPT LANGUAGE=”JavaScript”>
function setDocCapture(enable) {
if (!enable) {
document.captureEvents(Event.CLICK)
} else {
document.releaseEvents(Event.CLICK)
document.forms[0].setDocRte.checked = false
docRoute = false
}
}
function setLayerCapture(enable) {
if (!enable) {
document.layer1.captureEvents(Event.CLICK)
} else {
document.layer1.releaseEvents(Event.CLICK)
document.forms[0].setLyrRte.checked = false
layerRoute = false
}
}
var docRoute = false
var layerRoute = false
function setDocRoute(enable) {

docRoute = !enable
document.forms[0].setDocShortCircuit.checked = false
docShortCircuit = false
}
Continued
722
Part III ✦ Document Objects Reference
Listing 29-4 (continued)
function setLayerRoute(enable) {
layerRoute = !enable
document.forms[0].setLyrShortCircuit.checked = false
layerShortCircuit = false
}
var docShortCircuit = false
var layerShortCircuit = false
function setDocShortcut(enable) {
docShortCircuit = !enable
if (docShortCircuit) {
document.forms[0].setDocRte.checked = false
docRoute = false
}
}
function setLayerShortcut(enable) {
layerShortCircuit = !enable
if (layerShortCircuit) {
document.forms[0].setLyrRte.checked = false
layerRoute = false
}
}
function doMainClick(e) {

if (e.target.type == “button”) {
alert(“Captured in top document”)
if (docRoute) {
routeEvent(e)
} else if (docShortCircuit) {
document.layer1.document.forms[0].layerButton2.handleEvent(e)
}
}
}
document.captureEvents(Event.CLICK)
document.onclick=doMainClick
</SCRIPT>
</HEAD>
<BODY>
<B>Redirecting Event.CLICK</B>
<HR>
<FORM>
<INPUT TYPE=”checkbox” NAME=”setDocCap”
onMouseDown=”setDocCapture(this.checked)” CHECKED>Enable Document Capture&nbsp;
<INPUT TYPE=”checkbox” NAME=”setDocRte”
onMouseDown =”setDocRoute(this.checked)”>And let event continue
<INPUT TYPE=”checkbox” NAME=”setDocShortCircuit”
onMouseDown =”setDocShortcut(this.checked)”>Send event to ‘layerButton2’<P>
<INPUT TYPE=”checkbox” NAME=”setLyrCap”
onMouseDown =”setLayerCapture(this.checked)” CHECKED>Enable Layer Capture&nbsp;
<INPUT TYPE=”checkbox” NAME=”setLyrRte”
onMouseDown =”setLayerRoute(this.checked)”>And let event continue
723
Chapter 29 ✦ Event Objects
<INPUT TYPE=”checkbox” NAME=”setLyrShortCircuit”

onMouseDown =”setLayerShortcut(this.checked)”>Send event to ‘layerButton2’<P>
<HR>
<INPUT TYPE=”button” VALUE=”Button ‘main1’” NAME=”main1”
onClick=”alert(‘Event finally reached Button:’ + this.name)”>
</FORM>
<LAYER ID=”layer1” LEFT=200 TOP=200 BGCOLOR=”coral”>
<HEAD>
<SCRIPT LANGUAGE=”JavaScript”>
function doLayerClick(e) {
if (e.target.type == “button”) {
alert(“Captured in layer1”)
if (layerRoute) {
routeEvent(e)
} else if (layerShortCircuit) {
document.forms[0].layerButton2.handleEvent(e)
}
}
}
layer1.captureEvents(Event.CLICK)
layer1.onclick=doLayerClick
</SCRIPT>
</HEAD>
<BODY>
<FORM>
&nbsp;layer1<BR><P><INPUT TYPE=”button” VALUE=”Button ‘layerButton1’”
NAME=”layerButton1”
onClick=”alert(‘Event finally reached Button:’ + this.name)”></P>
<P><INPUT TYPE=”button” VALUE=”Button ‘layerButton2’”
NAME=”layerButton2”
onClick=”alert(‘Event finally reached Button:’ + this.name)”></P>

</FORM>
</BODY>
</LAYER>
</BODY>
</HTML>
IE4+ event propagation
Event propagation in IE4+ flows in the opposite direction of the NN4 event cap-
ture model. IE’s model is called event bubbling, in which events “bubble” upward
from the target object through the element containment hierarchy. It’s important to
distinguish between the old-fashioned document object hierarchy (followed in the
NN4 event capture model) and the more modern notion of HTML element contain-
ment — a concept that carries to the W3C DOM as well.
A good way to demonstrate the effect of event bubbling — a behavior that is
turned on by default — is to populate a simple document with lots of event handlers
to see which ones fire and in what order. Listing 29-5 has
onClick event handlers
defined for a button inside a form, the form itself, and other elements and object all
the way up the hierarchy out to the window.
724
Part III ✦ Document Objects Reference
Listing 29-5: Event Bubbling Demonstration
<HTML onClick=”alert(‘Event is now at the HTML element.’)”>
<HEAD>
<TITLE>Event Bubbles</TITLE>
<SCRIPT LANGUAGE=”JavaScript”>
function init() {
window.onclick = winEvent
document.onclick = docEvent
document.body.onclick = docBodEvent
}

function winEvent() {
alert(“Event is now at the window object level.”)
}
function docEvent() {
alert(“Event is now at the document object level.”)
}
function docBodEvent() {
alert(“Event is now at the BODY element.”)
}
</SCRIPT>
</HEAD>
<BODY onLoad=”init()”>
<H1>Event Bubbles</H1>
<HR>
<FORM onClick=”alert(‘Event is now at the FORM element.’)”>
<INPUT TYPE=”button” VALUE=”Button ‘main1’” NAME=”main1”
onClick=”alert(‘Event started at Button: ‘ + this.name)”>
</FORM>
</BODY>
</HTML>
You can try this listing in IE4+ and even NN6, because the latter observes event
bubbling. But you will notice differences in the precise propagation among
IE4+/Windows, IE4+/Macintosh, and NN6. But first, notice that after you click the
button in Listing 29-5, the event first fires at the target: the button. Then the event
bubbles upward through the HTML containment to fire at the enclosing FORM ele-
ment; next to the enclosing BODY element; and so on. Where the differences occur
are after the BODY element. Table 29-1 shows the objects for which event handlers
are defined in Listing 29-5 and which objects have the
click event bubble to them
in the three classes of browsers.

Table 29-1 Event Bubbling Variations for Listing 29-5
Event Handler Location IE4+/Windows IE4+/Macintosh NN6
BUTTON yes yes yes
FORM yes yes yes
725
Chapter 29 ✦ Event Objects
Event Handler Location IE4+/Windows IE4+/Macintosh NN6
BODY yes yes yes
HTML yes no yes
document yes yes yes
window no no yes
Despite the discrepancies in Table 29-1, events do bubble through the most
likely HTML containers that come to mind. The object level with the most global
scope and that works in all browser categories shown in the table is the
document
object.
Preventing IE event bubbling
Because bubbling occurs by default, there are times when you may prefer to pre-
vent an event from bubbling up the hierarchy. For example, if you have one handler
at the
document level whose job is to deal with the click event from a related
series of buttons, any other object that receives
click events will allow those
events to bubble upward to the
document level unless the bubbling is cancelled.
Having the event bubble up could conflict with the document-level event handler.
Each
event object in IE has a property called cancelBubble. The default value
of this property is
false, which means that the event bubbles to the next outer-

most container that has an event handler for that event. But if, in the execution of
an event handler, that property is set to
true, the processing of that handler fin-
ishes its job, but the event does not bubble up any higher. Therefore, to stop an
event from bubbling beyond the current event handler, include the following state-
ment somewhere in the handler function:
event.cancelBubble = true
You can prove this to yourself by modifying the page in Listing 29-5 to cancel
bubbling at any level. For example, if you change the event handler of the FORM ele-
ment to include a statement that cancels bubbling, the event goes not further than
the FORM in IE (the syntax is different for NN6, as discussed later):
<FORM
onClick=”alert(‘Event is now at the FORM element.’); event.cancelBubble=true”>
Redirecting events
Starting with IE5.5, you can redirect an event to another element, but with some
limitations. The mechanism that makes this possible is the
fireEvent() method of
all HTML element objects (see Chapter 15). This method isn’t so much redirecting
an event as causing a brand-new event to be fired. But you can pass most of the
properties of the original
event object with the new event by specifying a reference
to the old
event object as the optional second parameter to the fireEvent()
method.
The big limitation in this technique, however, is that the reference to the target
element gets lost in this hand-off to the new event. The
srcElement property of the
old event gets overwritten with a reference to the object that is the target of the call
to
fireEvent(). For example, consider the following onClick event handler func-

tion for a button inside a FORM element:
726
Part III ✦ Document Objects Reference
function buttonEvent() {
event.cancelBubble = true
document.body.fireEvent(“onclick”, event)
}
By cancelling event bubbling, the event does not propagate upward to the
enclosing FORM element. Instead, the event is explicitly redirected to the BODY ele-
ment, passing the current
event object as the second parameter. When the event
handler function for the BODY element runs, its
event object has information
about the original event, such as the mouse button used for the click and the coor-
dinates. But the
event.srcElement property points to the document.body object.
As the event bubbles upward from the BODY element, the
srcElement property
continues to point to the
document.body object. You can see this at work in Listing
29-6 for IE5.5+.
Listing 29-6: Cancelling and Redirecting Events in IE5.5+
<HTML onClick=”revealEvent(‘HTML’, event)”>
<HEAD>
<TITLE>Event Cancelling & Redirecting</TITLE>
<SCRIPT LANGUAGE=”JavaScript”>
// display alert with event object info
function revealEvent(elem, evt) {
var msg = “Event (from “ + evt.srcElement.tagName + “ at “
msg += event.clientX + “,” + event.clientY + “) is now at the “

msg += elem + “ element.”
alert(msg)
}
function init() {
document.onclick = docEvent
document.body.onclick = docBodEvent
}
function docEvent() {
revealEvent(“document”, event)
}
function docBodEvent() {
revealEvent(“BODY”, event)
}
function buttonEvent(form) {
revealEvent(“BUTTON”, event)
// cancel if checked (IE4+)
event.cancelBubble = form.bubbleCancelState.checked
// redirect if checked (IE5.5+)
if (form.redirect.checked) {
document.body.fireEvent(“onclick”, event)
}
}
</SCRIPT>
</HEAD>
<BODY onLoad=”init()”>
<H1>Event Cancelling & Redirecting</H1>
<HR>
<FORM onClick=”revealEvent(‘FORM’, event)”>
727
Chapter 29 ✦ Event Objects

<P><BUTTON NAME=”main1” onClick=”buttonEvent(this.form)”>
Button ‘main1’
</BUTTON></P>
<P><INPUT TYPE=”checkbox” NAME=”bubbleCancelState”
onClick=”event.cancelBubble=true”>Cancel Bubbling at BUTTON<BR>
<INPUT TYPE=”checkbox” NAME=”redirect” onClick=”event.cancelBubble=true”>
Redirect Event to BODY</P>
</FORM>
</BODY>
</HTML>
Listing 29-6 is a modified version of Listing 29-5. Major additions are enhanced
event handlers at each level so that you can see the tag name of the event that is
regarded as the
srcElement of the event as well as the coordinates of the click
event. With both checkboxes unchecked, events bubble upward from the button,
and the BUTTON element is then shown to be the original target all the way up the
bubble hierarchy. If you check the Cancel Bubbling checkbox, the event goes no fur-
ther than the BUTTON element, because that’s where event bubbling is turned off.
If you then check the Redirect Event to BODY checkbox, the original event is can-
celled at the BUTTON level, but a new event is fired at the BODY element. But
notice that by passing the old
event object as the second parameter, the click loca-
tion properties of the old event are applied to the new event directed at the BODY.
This event then continues to bubble upward from the BODY.
As a side note, if you uncheck the Cancel Bubbling checkbox but leave the
Redirect Event box checked, you can see how the redirection is observed at the end
of the BUTTON’s event handler, and something special goes on. The original event
is held aside by the browser while the redirected event bubbles upward. As soon as
that event processing branch finishes, the original bubbling propagation carries on
with the FORM. Notice, though that the

event object still knows that it was tar-
geted at the BUTTON element, and the other properties are intact. This means that
for a time, two
event objects were in the browser’s memory, but only one is
“active” at a time. While the redirected event is propagating, the
window.event
object refers to that event object only.
NN6+ event propagation
Yielding to arguments in favor of both event capture and event bubbling, the
W3C DOM group managed to assemble an event model that employs both propaga-
tion systems. Although forced to use new syntax so as not to conflict with older
browsers, the W3C DOM propagation model works like the NN4 one for capture and
like IE4+ for bubbling. In other words, an event bubbles by default, but you can also
turn on event capture if you want. Thus, an event first trickles down the element
containment hierarchy to the target; then it bubbles up through the reverse path.
Event bubbling is on by default, just as in IE4+. To enable capture, you must
apply a W3C DOM event listener to an object at some higher container. Use the
addEventListener() method (see Chapter 15) for any visible HTML element or
node. One of the parameters of the
addEventListener() method determines
whether the event listener function should be triggered while the event is bubbling
or is captured.

×