W3C

XML Events for HTML Authors

Steven Pemberton, W3C/CWI

Version date: 21 July 2004

Introduction

This document is a quick introduction to XML Events for HTML authors. XML Events is a method of catching events in markup languages that offers several advantages over the HTML onclick style of event handling.

Table of Contents

  1. The Basic Idea
  2. Other Ways to Specify the Relationship
    1. On the handler
    2. With <listener>
    3. On the Observer
  3. Fine details
    1. phase ("capture" | "default"*)
    2. target
    3. propagate ("stop" | "continue"*)
    4. defaultAction ("cancel" | "perform"*)
  4. Conclusions

The Basic Idea

The important thing to know about XML Events is that it uses exactly the same event mechanism as HTML, only written differently.

Consider this simple HTML example:

<input type="submit" onclick="verify(); return true;">

This says that if the <input> element (or any of its children) gets the click event, then the piece of code in the onclick attribute is performed.

We say "or any of its children" because in a case like

<a href="..." onclick="...">A <em>very</em> nice place to go</a>

or

<a href="..." onclick="..."><strong>More</strong></a>

you want the onclick to be performed even if the click actually happens on the <em> or <strong> elements. In these cases we call the element that was clicked on the target, and the element that responds to the event an observer (though often target and observer are the same element).

So what you see is that there are three important things involved: an event, an observer, and a piece of script (called a handler). As you can see from the above, the fourth thing, the target, isn't usually important.

There are some problems with the way HTML specifies the relationship between the three:

XML Events specifies the relationship between the event, observer and handler in a different way. The equivalent to:

<input type="submit" onclick="validate(); return true;">

would be:

<input type="submit">
   <script ev:event="DOMActivate" type="text/javascript">
      validate();
   </script>
</input>

(Note that there is no markup language yet that allows you to write exactly this: these examples just show what the equivalent markup would be, in order to explain the concepts. There are some pointers at the end to languages that already use XML Events.)

This says that the <script> element is a handler for the DOMActivate event (which we use in preference to click, because buttons can be activated in different ways, not just by clicks), and in the absence of any other information, the parent element is the observer (<input> in this case).

(Note that handlers must only be evaluated when the event happens, and not when the document is loading as with <script> in HTML4.)

This approach now allows you to specify handlers for different scripting languages:

<input type="submit">
   <script ev:event="DOMActivate" type="text/javascript">
      ...
   </script>
   <script ev:event="DOMActivate" type="text/vbs">
      ...
   </script>
</input>

and/or different events:

<input type="submit">
   <script ev:event="DOMActivate" type="text/javascript">
      ...
   </script>
   <script ev:event="DOMFocusIn" type="text/javascript">
      ...
   </script>
</input>

You now know enough to be able to do event handling using XML Events. However, there are some other useful features.

Other Ways to Specify the Relationship

Just as with HTML, there are other ways you can specify the event-observer-handler relationship. You can put the information on the handler, on the observer, or on a <listener> element. Note that whichever method you use, you always have to specify the three parts: so if you use the handler you have to say what the event and observer are, if you use the observer you have to say what the event and handler are, and with <listener> you have to specify all three.

The reason why you would want to this is mostly to make your documents more manageable. You can separate all scripting out of the main body of your document. It also allows you to avoid duplicating your handlers, and just having one copy which you can apply to several places.

Specifying the Relationship on the Handler

Here you move the handler to some other part of the document, and specify the relationship there (like some versions of HTML use the for attribute on the <script> element):

 <script ev:observer="button" ev:event="DOMActivate" type="text/javascript">
      validate();
 </script>
...
<input type="submit" id="button"/>

Specifying the Relationship with <listener>

Here you again put the handler somewhere, and specify the relationship in another place with the <listener> element (this allows you to use the same handler for more than one observer):

<ev:listener observer="button" handler="#validator" event="DOMActivate"/>
...
<script id="validator" type="text/javascript">
      validate();
</script>
...
<input type="submit" id="button"/>

(Note that in this case it is the <listener> element that carries the ev: prefix, and not the attributes.)

Specifying the Relationship on the Observer

And finally, you can specify the relationship on the observer:

<script id="validator" type="text/javascript">
      validate();
</script>
...
<input type="submit" ev:handler="#validator" ev:event="DOMActivate"/>

Fine Details

Really for everyday use of events, that's all you need to know. There are however a few details that may occasionally come in useful.

phase ("capture" | "default"*)

Since, as was said, event handlers get invoked for an element or any of its children, it is possible for instance to listen for all clicks on anything within a paragraph:

<p>
    <script ev:event="DOMActivate" type="...">
        ...
    </script>
    ...
    <a href="...">...</a>
    ...
    <a href="...">...</a>
    ...
</p>

which would respond to clicks on either contained <a> (as well as on anything else in the paragraph).

However, since the <a> elements might also have handlers on them, the phase attribute is used to specify whether a given handler should be activated before handlers lower in the tree, or after them. Normally handlers lower in the tree for an event are activated first, but the attribute ev:phase="capture" causes a handler higher in the tree to be executed before lower handlers for the same event:

<p>
    <script ev:event="DOMActivate" ev:phase="capture" type="...">
        <!-- This handler will be done before any lower in the tree -->
        ...
    </script>
    ...
    <a href="...">...</a>
    ...
    <a href="...">...</a>
    ...
</p>

target

If you really do care about which element is the target, then you can say that you are only listening for events for that element:

<p>
    <script ev:event="DOMActivate" ev:target="img1" type="...">
        ...
    </script>
    ...
    <a href="..."><img id="img1" ... /><img id="img2" ... /></a>
</p>

(Remember, the target is the thing actually clicked on, which we usually aren't particularly interested in.)

propagate ("stop" | "continue"*)

Event handlers for an event are handled in the following order: first all handlers with ev:phase="capture", starting first at the top of the tree, and then working down to the target's parent element, and then all other handlers, working from the target element, back up to the top of the tree.

If any handler has ev:propagate="stop" then no handler after those on the current element will be invoked for the current event.

<body>
    <script ev:event="DOMActivate" ev:propagate="stop" ev:phase="capture" type="...">
        <!-- This script is the only one that will respond to DOMActivate -->
        ...
    </script>
    ...
</body>

By the way, if there is more than one handler on an element for the same event, it is undefined what order they are performed in.

defaultAction ("cancel" | "perform"*)

Many events have a default action which gets carried out after all event handlers for the event in the tree have been performed. For instance, a click on a button will cause the button to be activated, a click on an <a> or one of its children will cause the link to be activated. It is possible to stop this default action with the attribute ev:defaultAction="cancel".

<input type="submit" ...>
    <script ev:event="DOMActivate" ev:defaultAction="cancel" type="...">
        <!-- This script will be activated, but the default action will not be done -->
        ...
    </script>
</input>

(This is what onclick="...; return=false;" does in HTML4. If you want to do this conditionally in XML Events, you should call the DOM preventDefault method appropriately.)

Conclusions

This introduction has shown you how to do event handling in XML. As mentioned above, presently there is no version of XHTML that supports XML Events with scripting; XHTML2 is in preparation. XForms uses XML Events (though with its own <action> element rather than <script>); other languages that use XML Events are XHTML+Voice (also known as X+V), and SVG 1.2 (also in preparation).