You are reading O'Reilly XForms Essentials by Micah Dubinko. (What is this?) - Buy XForms Essentials Online

Chapter 7. Actions and Events

"While we are free to choose our actions, we are not free to choose the consequences of our actions."

Stephen Covey

"We are not ready for any unforeseen event that may or may not occur."

Dan Quayle

Scripting. It sounds good, at first. With a quick hack, it can cure every problem you throw at it. It's seductive. The problem is, a couple of months later, when you need to fix a bug or add another feature, you can't remember what the script was supposed to do, and you spend a week reverse engineering the whole system. And you'll do it again a few months later. And again, and again. The major problem with script is that even though it's easy to get started with, it's expensive to maintain. If you don't believe it, try debugging someone else's script some time.

There are other problems with scripting as well. Scripts are usually biased towards a visual platform, which means that accessibility aids, or even just regular users with an eyes-free browser, will tend to have trouble with scripting. For the foreseeable future, security-conscious users will have scripting disabled in their browsers.

The answer is to identify areas where scripting is most commonly needed, and create declarative replacements, which is exactly what XForms accomplishes. The core technology that makes this possible is called XML Events.

An event, as far as XForms is concerned, is a data structure that gets passed around to certain interfaces, called event listeners. The Document Object Model (DOM) Level 2 Events specification spells out how events work. The latter part of this chapter describes specific events that are useful in XForms authoring.

Each event has a target element, which represents the point where the main action is happening, from the viewpoint of a particular event. Each event also can have a default action that is effectively triggered by the event. For example, an xforms-focus event will have a form control element as a target and a default action of changing the active focus. DOM Level 2 includes a method to configure an observer, which can take a specific action in response to an event, possibly in lieu of the default action. The most common case is for the observer to attach directly to the target element.

In some cases, however, an observer would like to have broader access to events, for instance to all xforms-focus events for all form controls. In this scenario, the observer is farther downstream from the event target. DOM Level 2 Events define how events "propagate" (or flow) through the DOM, as shown in Figure 7.1, “Event propagation”.

Event propagation is divided into two phases: capture and bubbling. Capture occurs first, as the DOM root node is given the option to observe the event, then additional nodes following the path from the root to the target element. Any listener has the ability to end the propagation, or to prevent the default action of the event. After reaching the target (and giving observers there a change to handle the event), the event reverses course and makes its way back to the root, in a process called bubbling. If the event finishes this journey without being cancelled, the default action happens as long as no listeners have signaled to block the default action.

In the design of HTML forms, script is used whenever some specific action is needed. For example, a form might have a button that copies values from a "ship to" section onto a "bill to" section. In HTML forms plus script, the following code would accomplish this:

<script type="text/javascript"> <!--

function copyAddresses(  ) {
  var frm = document.forms[0];
  frm.shipAddr.value = frm.billAddr.value;
  frm.shipCity.value = frm.billCity.value;
  frm.shipProv.value = frm.billProv.value;
  frm.shipPostCode.value = frm.billPostCode.value;
}
--> </script>

This code simply copies form values from one control to another. It would then be activated by a button, with an event-specific attribute, specified like this:

<input type="button" id="cp" value="Copy values" onclick="copyAddresses(  )"/>

In terms of DOM Level 2 Events, this represents a registration of an observer on the input element, watching for the DOM click event at the target, and handling the event by calling a short script. As a result, the script in the onclick attribute will get called when the user clicks on the button.

Note that a minor leap of faith is required by the browser to interpret the contents of the onclick attribute as JavaScript—in principle, any scripting language could be used, and a special meta tag would be needed to specify which scripting language is truly in use in the event attributes. (In practice, nobody actually does this, and browsers just muddle through, making essentially an educated guess, almost always JavaScript.) To recap the disadvantages of this approach:

XML Events solves all of these problems by specifying a better way to observe and, ultimately, handle events.

XML Events provides an element-based syntax for DOM Level 2 events. It defines a listener element that, even though not directly used in XForms, is still worth examining. This element has eight attributes defined:

The specification also calls for an id attribute to be declared by the host language. If the listener element was used in XHTML, it might look like the following.

<head>
  <listener event="click" observer="btn" handler="#id_of_handler"/>
  ...
</head>

While these attributes map directly to equivalent concepts in DOM Level 2 Events, it can be cumbersome to provide an extra element with extra attributes. To accommodate for this, the XML Events specification contains a few shortcuts, based on namespaced or global attributes. These attributes can be placed directly on the observer element:

<body>
  ...
  <input type="button" ev:event="click" ev:handler="#id_of_handler"/>
  ...
</body>

Alternatively, the attributes can be placed on the handler element:

<head>
  <script type="text/javascript" ev:event="click" ev:observer="btn">...</script>
  ...
</head>

This final technique is used extensively in XForms.