WARNING: Most of this content (with the exception of the Mozilla 1.9 XPCOM reference) is very old, and can be expected to be out of date and possibly obsolete. For better XUL documentation, please visit the
XUL hub at the
Mozilla Developer Center.
Adding Event Handlers
The find files dialog so far looks quite good. We haven't cleaned it up much but
we have created a simple user interface easily. Next, we will show how to add
scripts to it.
s
Using Scripts
To make the find files dialog functional, we need to add some scripts which will
execute when the user interacts with the dialog. We would want to add a script to
handle the Find button, the Cancel button and to handle each menu command. We write
this using JavaScript functions much in the same way as HTML.
You can use the script element to include scripts
in XUL files. You can embed the script code directly in the XUL file in between
the opening and closing script tags but it is much better
to include code in a separate file as the XUL window will load slightly faster. The
src attribute is used to link in an external script
file.
Let's add a script to the find file dialog. Although it does not matter what
the script file is called, usually it would be the same as the XUL file
with a js extension. In this case, findfile.js will be used. Add the line below
just after the opening window tag and before any elements.
<script src="findfile.js"/>
We'll create the script file later when we know what we want to put it in it. We'll
define some functions in the file and we can call them in event handlers.
You can include multiple scripts in a XUL file by using multiple
script tags, each pointing to a different script. You
may use relative or absolute URLs. For example, you may use URLs of the following form:
<script src="findfile.js"/>
<script src="chrome://findfiles/content/help.js"/>
<script src="http://www.example.com/js/items.js"/>
This tutorial does not attempt to describe how to use JavaScript as this is a
fairly large topic and there are plenty of other resources that available for this.
Responding to Events
The script will contain code which responds to various events triggered by the user
or other situations. There are about thirty or so different events that may be
handled in several different ways. A typical event is the user pressing a mouse
button or pressing a key. Each XUL element has the ability to trigger certain events
in different situations. Some events are triggered only by certain elements.
Each event has a name, for example, 'mousemove' is the name of the event that is
triggered when the user moves the mouse over a UI element. XUL uses the same event
mechanism as defined by
DOM Events.
When an action occurs that would trigger an event, such as the user moving the mouse,
an event object is created corresponding to that event type. Various properties are set
on the event object such as the mouse position, the key that was pressed, and so forth.
The event is then sent to the XUL in phases. The first phase is the capturing
phase, in which the event is first sent to the window, then to the document,
followed by each ancestor of the XUL element where the event occured downwards
until it reaches that element. Then, the event is sent to that XUL element.
Finally, during the bubbling phase, the event is sent to each element back upwards
until it reaches the window again. You can respond to an event during either the
capturing or bubbling phase. Once the event has finished propagating, any default
action will occur, which is the built in behaviour of the element.
For example, when the mouse is moved over a button that is inside a box, a
'mousemove' event is generated, and sent first to the window, followed by the
document, and then the box. That completes the capturing phase. Next, the
'mousemove' event is sent to the button. Finally, the bubbling phase causes the
event to be sent to the box, document and window. The bubbling phase is
essentially the reverse of the capturing phase. Note that some events don't do the
bubbling phase.
You can attach listeners to each element to listen to the events during each step
of event propagation. Due to the way a single event is passed to all the ancestors,
you may attach a listener to a specific element or to an element higher in the
hierarchy. Naturally, an event attached to an element higher up will receive
notification of all elements inside it, whereas an event attached to a button will
only receive events pertaining to that button. This is useful if there are several
elements you would like to handle using the same or similar code.
Once you handle an event, regardless of where in the propagation the event is, you
will likely want to stop the event from being sent to further elements, essentially
stopping the capturing or bubbling phases from continuing. Depending on how you
attach the event listener to an element, there are different ways of doing this.
The most common event used is the 'command' event. The command event is fired when a
user activates an element, for example by pressing a button, changing a checkbox or
selecting an item from a menu. The command event is a useful event since it
automatically handles different ways of activating the element. For example, the
command event will occur regardless of whether the user uses the mouse to click a
button, or presses the Enter key.
There are two ways to attach an event listener to an element. First, by using
an attribute with script as its value. Second, by calling an element's addEventListener
method. The former may only handle bubbling events but tends to be simpler to
write. The latter can handle events at any phase and may also be used attach multiple
listeners for an event to an element. Using the attribute form is more common for most
events.
To use the attribute form, place an attribute on the element where you want the event
listener to be, the name of which should be the event name preceded by the word 'on'.
For example, the corresponding attribute for the 'command' event is 'oncommand'. The
value of the attribute should be some script that should be executed when the event
occurs. Typically, this code will be short and just call a function defined in a
separate script. An example of responding to a button being pressed:
Example 6.1.1:
Source
View
<button label="OK" oncommand="alert('Button was pressed!');"/>
Since the command event will bubble, it is also possible to place the event listener
on an enclosing element. In the example below, the listener has been placed on a box
and will receive events for both elements.
Example 6.1.2:
Source
View
<vbox oncommand="alert(event.target.tagName);">
<button label="OK"/>
<checkbox label="Show images"/>
</vbox>
In this example, the command event will bubble up from the button or checkbox to
the vbox, where it is handled. If a second listener (the
oncommand attribute) were placed on the button, its
code will be called first, followed by the handler on the vbox. Event handlers are
passed the event object as an implied argument called 'event'. This is used to get
specific information about the event. One commonly used property is the 'target'
property of the event, which holds the element where the event actually occured.
In the example we display an alert containing the target's tag name. The target is
useful when using a bubbling event so that you could have a set of buttons which
are all handled by a single script.
You might notice that the attribute syntax is similar to that used for events in HTML
documents. In fact, both HTML and XUL share the same event mechanism. One important
difference is that while the 'click' event (or the onclick
attribute) is used in HTML to respond to buttons, in XUL the command event should be
used instead. XUL does have a click event, but it only responds to mouse clicks, not
to keyboard usage. Thus, the click event should be avoided in XUL, unless you have a
reason to have an element that can only be handled with a mouse. In addition, whereas
the command event will not be sent if an element is disabled, the click event will be
sent regardless of whether the element is disabled or not.
A command handler can be placed on the Find and Cancel buttons in the find files
dialog. Pressing the Find button should start the search. Because we aren't going to
implement this part yet, we'll leave it out for now. However, pressing the Cancel
button should close the window. The code below shows how to do this. While we're at
it, let's add the same code to the Close menu item.
<menuitem label="Close" accesskey="c" oncommand="window.close();"/>
...
<button id="cancel-button" label="Cancel"
oncommand="window.close();"/>
Two handlers have been added here. The oncommand
attribute was added to the Close menu item. By using this handler, the user will
be able to close the window by clicking the menu item with the mouse or by selecting
it with the keyboard. The oncommand handler was also added
to the Cancel button.
DOM Event Listeners
The second way to add an event handler is to call an element's addEventListener
method. This allows you to attach an event listener dynamically and listen for
events during the capturing phase. The syntax is as follows:
Example 6.1.3:
Source
View
<button id="okbutton" label="OK"/>
<script>
function buttonPressed(event)
{
alert('Button was pressed!');
}
var button = document.getElementById("okbutton");
button.addEventListener('command', buttonPressed, true);
</script>
The getElementById function returns the element with a given id, in this case the
button. The addEventListener function is called to add a new capturing event
listener. The first argument is the name of the event to listen to. The second
argument is the event listener function which will be called when the event occurs.
Finally, the last argument should be true for capturing listeners. You can also
listen during the bubbling phase by setting the last argument to false. The event
listener function passed as the second argument should take one argument, the event
object, as shown in the declaration for the buttonPressed function above.
(Next)
Next, we'll look at some more details about the event object.
Examples:
6.1.1
6.1.2
6.1.3
Find files example so far:
Source
View