Dynamic Documents with Less Script
A number of markup technologies involve attaching behaviors to specific parts of a document. XML Events is a W3C Recommendation that allows declarative attachment of a behavior — which can be a predefined bundle of actions defined in XML or a more general call to a scripting language — to a specific element. This article gives an overview of how XML Events came about, what it’s useful for, and how it works.
Modern Web sites are highly interactive: Dynamic navigation menus, image rollovers, forms, and even drag and drop are available. A common factor among all such sites is some kind of technique for associating a behavior with a specific part of the document. Unfortunately, current practice is something of a jumble of script-heavy approaches, especially in cases where code needs to work on multiple browsers.
Two Kinds of Events
Listing 1 shows some of the variation that’s possible. It defines two event handlers, one for the load event, and one for the unload event. One is written in VBScript, and attached through a less-common technique involving extra attributes on the script element. The other is written in ECMAscript (see Resources).
Listing 1. Two kinds of events
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
<script event="onload" for="window" language="vbscript">
When viewed in Microsoft Internet Explorer or another browser that supports VBScript, an alert box displaying “hello” appears upon loading the document. In nearly all browsers, “goodbye” appears upon closing the window or navigating to another page. To fully describe what’s going on here, you need to understand DOM Events, currently specified by a W3C document entitled Document Object Model (DOM) Level 2 Events Specification (see Resources).
How Events Work
What exactly is an event? For purposes of this discussion, it’s best not to think about it in the traditional sense of the word “event”, but rather as a simple data structure that contains details about something that’s changing. For example, on a mouseover event, the interesting information in the event object is the mouse pointer coordinates, which mouse buttons are depressed, whether modifier keys like “shift” are currently depressed, and so on. An individual event object is short-lived, and exists only long enough for immediate processing before it ceases to be.
Every event has a target, the XML or HTML element most closely associated with the event. An event handler is a piece of executable code or markup that responds to a particular event. Distinct from any handler, some events, such as clicking on a hyperlink, can cause activity called a default action. In Listing 1, the target of the unload event is the body element, and the event handler is the bit of script inside the onunload attribute.
The easiest and most common technique is to attach event handlers right at the target, and once upon a time this technique was all that browsers supported. However, this often isn’t practical. Listing 2 offers one example:
Listing 2. Demonstrating the need for event observers
<p>You want to capture all clicks on this paragraph,
even if the text has <em>special markup</em>.</p>
In Listing 2, suppose you have an event handler in place to handle click events targeted at the p element. If the user happens to click on the words “special markup”, this will create an event targeted at the em element. Because the paragraph isn’t the target, its click handler will not fire. Getting this to work involves placing an event observer on the p element that can respond to events targeted at itself or any of its children.
DOM Level 2 Events describes how an event handler can be connected in a way that solves the problem shown in Listing 2 — though it may be more complex than necessary due to ancient browser history (earlier versions of Internet Explorer and Netscape had their own idiosyncrasies, and some of them were grandfathered in to the official DOM spec). An event takes an imaginary journey, known as propagation, through the tree structure of the document. Actually, it takes two journeys: The first, called capture, begins at the document root and proceeds to the target element. After a chance for ordinary target processing, a second journey, called bubbling, starts at the target element and ends up back at the document root. During each phase, any element along the path can be registered as an observer of the event, and can thus trigger an event handler. Events can even be stopped from further propagation, which prevents later observers from detecting that the event happened. Figure 1 illustrates propagation.
Figure 1. Event propagation
If you need to set up an event observer, should you use the capture or bubbling phase? Here are a few guidelines:
• If you’re dealing with only a single observation point, which is usually the case, you can use either the capture or bubbling phase — there’s no real difference. The distinction only matters if a single event will be observed from multiple places in the document tree.
• Some events like focus do not participate in the bubbling phase, and thus can only be observed during the capture phase or directly at the target.
• When multiple observers are present, use the bubbling phase if you want closer observers to fire first. For example, suppose that in Figure 1 there were observers on both body and p. With capture, the observer on body would fire first, followed by the one on p. With bubbling, the observer on p would fire first, followed by the one on body.
• Keep in mind that the HTML 4.0-style attribute syntax, used for onunload in Listing 1, registers observers for the bubbling phase.
• Whether the bubbling or capture phase is used, the default action always happens after all event propagation is finished. Stopping the event propagation doesn’t by itself prevent the default action. A separate API feature allows the default action to be cancelled, regardless of whatever else happens during propagation.
The DOM Events specification defines a way to attach event observers from script, as shown here in Listing 3.
Listing 3. Attaching event observers
var el = document.getElementById('observer_element_id');
el.addEventListener("mouseover", highlight_func, true);
el.addEventListener("mouseout", normal_func, true);
In the call to addEventListener, the first parameter is the event name, the second parameter is a function reference that will get executed, and the third parameter is either true (indicating the capture phase) or false (for bubbling). The DOM Events specification defines a number of core events, as well as an API method to stop the propagation of an event, and cancel the default action associated with it.
It’s worth noting that there are significant differences in various browser implementations of these APIs. In particular, Internet Explorer up to version 6 doesn’t support addEventListener, but instead uses a similar function named attachEvent.
Events and accessibility
Any time you’re thinking about events, it’s worth figuring out which events you really need. For example, do you really care whether a button was clicked with a mouse? What if it was activated in some other way? A number of Web users don’t have mice, or even graphical user interfaces for that matter. When possible, it’s almost always better to use device-independent events — for example, DOMActivate instead of click for buttons.
The W3C publishes a number of documents (see Resources) describing techniques for making Web content more accessible.
From Events to XML Events
Up to this point, everything about events has been tied to procedural script. The XML Events specification builds upon the foundation of DOM Level 2 Events, adding a declarative way to hook up event observers. The W3C XForms specification (see Resources) is one of the first to define a library of XML Events-compatible elements that can accomplish common tasks declaratively. Listing 4 shows an example of this in XForms. (For the complete namespace declarations in use here, see the full example in Listing 5.)
Listing 4. Declarative event handlers
<xf:label>Reset the form</xf:label>
<xf:reset ev:event="DOMActivate" model="mymodel" />
XML Events is defined as a number of attributes. In Listing 4, the ev:event attribute specifies the specific event being listened for; the handler is the xf:reset element, and the observer defaults to the parent element, xf:trigger. Notice that no script is needed in this listing.
The XML Events specification consists mainly of the definitions of attributes that can be placed on existing elements, along with a listener element that can also host the attributes. Each attribute maps to a feature of DOM Level 2 events. Table 1 lists all the XML Events attributes.
Table 1. XML Events attributes
|event||As shown in Listing 4, this required attribute names the event that triggers the listener.|
|observer||This attribute points to the unique ID of an element that is the observer.|
|handler||This attribute points to the URI of an element, possibly in a different document, that performs some action or processing.|
|phase||Either capture or default , this attribute specifies the capture phase to be used.|
|propagate||Either stop or continue (the default), this attribute specifies whether event propagation continues.|
|defaultAction||Either cancel or perform (the default), this attribute specifies whether the default action fires after propagation.|
|target||This attribute causes the listener to respond only to events directed at the specific target, and you should only use it in special situations.|
|id||This attribute allows a document-unique identifier to be given to the listener element.|
Listing 4 shows a convenient way to use XML Events with the minimum possible number of attributes: XML Events attributes are attached directly to the handler element. Whenever the ev:handler attribute is omitted, the element bearing the XML Events attributes is considered the handler. The observer is either specified through the ev:observer attribute, or the parent element. In Listing 4, the observer is xf:trigger.
Another kind of defaulting allows the XML Events attributes to be attached to the observer element when the ev:observer attribute is absent but the ev:handler attribute is present.
Listing 5 recreates the behavior in Listing 1, showing both defaulting techniques and using both script and a declarative action.
Listing 5. Two ways to use XML Events
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
<xf:message level="modal" id="hndl_id">goodbye</xf:message>
<body id="bod_id" ev:event="unload" ev:handler="#hndl_id">
The script element here is a handler, attached to an observer on bod_id (the body element). The xf:message element by itself doesn’t do anything, but the observer element (body again) points back to it, registering the event handler.
Script is clearly useful for many things. Even so, it still can be difficult to accomplish certain tasks through scripting. XML Events offers a uniform syntax for declaratively attaching scripts to documents, and even makes it possible to define behaviors that work without a dependency on a script interpreter. XML Events is now used by an increasing number of markup technologies, including XForms, XHTML, SVG, and others. In a future article, I will go into more detail on how to use and implement XML Events.
• Gain a deeper insight into event flow — consult The DOM Level 2 Events Specification , a W3C Recommendation.
• Next, have a look at the well-written XML Events specification, also a W3C Recommendation.
• Get a slightly different angle on understanding XML Events. Read Steven Pemberton’s ” XML Events for HTML Authors” on the W3C site.
• Consult the Working Draft of Web Content Accessibility Guidelines 2.0 and the documents linked to it, for advice on deciding which events you need to work with, and a host of other accessibility issues.
• To see a real-world example of declarative actions based on XML Events, examine the XForms Actions chapter of the W3C XForms specification. While you’re at it, take a look at Micah Dubinko’s recent developerWorks article ” Inside the XForms Validator” (September 2004).
• Want a more complete understanding of how all the major XML standards interrelate? Check out Uche Ogbuji’s excellent four-part survey of XML standards here on developerWorks:
• Part 1 — The core standards (January 2004)
• Part 2 — XML processing standards (February 2004)
• Part 3 — The most important vocabularies (February 2004)
• Part 4 — Detailed cross-reference of the most important XML standards (March 2004)
• Find more XML resources on the developerWorks XML zone.
• Learn how you can become an IBM Certified Developer in XML and related technologies.