352 Part VI — Creating Extensions and Themes Buttons A button element creates a button that can be pushed to trigger some action (see Figure 17-12): <button label=”Test” oncommand=”alert(‘Testing 1 2 3’);”/> F IGURE 17-12: A simple button A toolbarbutton is a special button that is usually a part of a toolbar and typically has an image (see Figure 17-13): <toolbarbutton id=”home-button” class=”toolbarbutton-1” label=”Home” onclick=”BrowserHomeClick(event);”/> F IGURE 17-13: A toolbarbutton XUL element The toolbar button image is usually specified in a CSS style sheet, rather than directly in the XUL document. Text Labels A label element can be used to display a short string, often used as a label for another ele- ment (see Figure 17-14): <label value=”Your first name:”/> <textbox id=”first-name”/> F IGURE 17-14: A label element next to a text box 25_596500 ch17.qxd 6/30/05 3:14 PM Page 352 353 Chapter 17 — Creating Extensions Larger pieces of text that can optionally wrap to multiple lines should be placed inside a description element (see Figure 17-15): <description> She Sells Sea Shells by the Sea Shore. </description> F IGURE 17-15: A description element The text of the description element wraps to multiple lines only when necessary—for exam- ple, when the parent element isn’t wide enough. You can resize the window and make it narrow to see the wrapping, as in Figure 17-15. Text Entry Boxes A textbox element can be used to create a text entry box like the one shown in Figure 17-14. If you want to allow entering multiple lines of text, set the multiline attribute to true (see Figure 17-16): <textbox multiline=”true” rows=”4” cols=”10”/> F IGURE 17-16: A multiline text entry box Checkboxes and Radio Buttons A checkbox is a UI element that can have either an on or an off state (see Figure 17-17): <checkbox label=”Add sugar” checked=”false”/> <checkbox label=”Add cream” checked=”true”/> 25_596500 ch17.qxd 6/30/05 3:14 PM Page 353 354 Part VI — Creating Extensions and Themes F IGURE 17-17: A couple of checkboxes Radio buttons can also have two states, but unlike checkboxes, they usually make more sense when grouped. When the user turns on a radio button that is a part of a group, all the other radio buttons in that group are automatically turned off. You can use a radio element to create a radio button and a radiogroup element to group several radio buttons (see Figure 17-18): <radiogroup> <radio label=”Jazz”/> <radio label=”Rock” selected=”true”/> <radio label=”Blues”/> </radiogroup> F IGURE 17-18: A group of radio buttons List Boxes A listbox element is used to create a list of items (listitem elements) that can be selected by the user (see Figure 17-19): <listbox rows=”3”> <listitem label=”Red”/> <listitem label=”Green”/> <listitem label=”Blue”/> <listitem label=”White”/> </listbox> F IGURE 17-19: A simple list box 25_596500 ch17.qxd 6/30/05 3:14 PM Page 354 355 Chapter 17 — Creating Extensions You can use a menulist element to create a drop-down list (see Figure 17-20): <menulist label=”Tuesday”> <menupopup> <menuitem label=”Sunday”/> <menuitem label=”Monday”/> <menuitem label=”Tuesday” selected=”true”/> <menuitem label=”Wednesday”/> <menuitem label=”Thursday”/> <menuitem label=”Friday”/> <menuitem label=”Saturday”/> </menupopup> </menulist> F IGURE 17-20: A drop-down list Menus A menu is usually created by defining a menu element that displays the menu title and a menupopup element that defines the contents of the menu popup window. This window can have any number of menuitem elements, menuseparator separators, and other menus. <menu label=”Tools” accesskey=”T”> <menupopup> <menuitem label=”JavaScript Console”/> <menuitem label=”DOM Inspector”/> <menuseparator/> <menu label=”ColorZilla”> <menupopup> <menuitem label=”Eyedropper”/> <menuitem label=”Color Picker”/> </menupopup> </menu> </menupopup> </menu> Figure 17-21 shows a multilevel menu. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 355 356 Part VI — Creating Extensions and Themes F IGURE 17-21: A multilevel menu This section merely scratched the surface of what can be done with XUL. The XULPlanet site has a complete reference of all the available elements, their attributes, and many more examples of their usage. Introduction to Events The event mechanism allows your JavaScript functions to be called in response to events that occur in the browser. For example, you can attach a script to handle a mouse click or a key- board button press, or to have it called every time Firefox loads a web page. Events are essential for creating dynamic user interfaces because they are the primary mechanism for adding behav- ior to otherwise static elements. For example, it is hard to imagine a user interface having a button that does nothing when clicked. XUL and HTML events in Mozilla are very similar because they both use the same World Wide Web Consortium (W3C) DOM events specification ( http://www.w3.org/ TR/DOM-Level-2-Events/ ). If you have worked with dynamic HTML in the past, you will find the concepts introduced in this section very familiar. The simplest way to attach your script to an element is by adding an appropriate attribute to its XUL definition: <label value=”I’m a clickable label” onclick=”alert(‘Label clicked’);”/> Each time the user clicks on the preceding label, the script defined by the onclick attribute is executed. The name of the attribute is the event name ( click in our example) prefixed by on. The JavaScript functions referenced in the event attribute should be defined when the script is executed. For example, you can define your functions in an external JavaScript file and include this file in the XUL document using the script tag. An explanation of how this is done is pro- vided in previous sections. The most common events and their attributes are listed here: Ⅲ Mouse events ■ click: Occurs when a mouse button is clicked on an element. This is even trig- gered when the mouse button is pressed and then released over the same screen location. In that case, three events occur: mousedown, mouseup, and click. When handling a button press or selection of a menu item, you should use the command event instead, because the user may also use the keyboard to trigger these actions. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 356 357 Chapter 17 — Creating Extensions ■ mousedown: Occurs when the mouse button is pressed on an element. ■ mouseup: Occurs when the mouse button is released over an element. ■ mouseover: Occurs when the mouse pointer is moved onto an element (enters it). ■ mousemove: Occurs when the mouse is moved while it is over an element. ■ mouseout: Occurs when the mouse pointer is moved away from the element (leaves it). Ⅲ Keyboard events ■ keypress: Occurs when a keyboard key is pressed and then released. ■ keydown: Occurs when a keyboard key is pressed (before being released). ■ keyup: Occurs when a keyboard key is released. Ⅲ Focus events ■ focus: Occurs when an element receives focus either because the user clicked on it with a mouse or navigated to it using the keyboard. ■ blur: Occurs when an element loses focus. Ⅲ Document events ■ load: Occurs when all content in a document (HTML page, XUL window, and so on) is finished loading and initializing. ■ unload: Occurs when the document is unloaded or a XUL window is being closed. ■ resize: Occurs when a document view is being resized. ■ scroll: Occurs when a document view is being scrolled. Ⅲ General event ■ command: Occurs when an element is being activated in some way. For example, this event is triggered whenever a button is pressed or a menu item is selected. As previously mentioned, you should handle this event in these cases rather than the mouse click events, because there are several alternative ways a user can activate a button or use a menu. When an event handling function is called, its first parameter is the event object that contains additional information about the event that occurred. For example, the target property of this object contains the element that triggered the event: <label value=”I’m a clickable label” onclick=”handleLabelClick(event);”/> Our handleLabelClick function is defined as follows: function handleLabelClick(event) { alert(event.target.value); } 25_596500 ch17.qxd 6/30/05 3:14 PM Page 357 358 Part VI — Creating Extensions and Themes When we click on the label, our handleLabelClick function is called. We can obtain the label element that triggered the event from the target property of the event parameter. When the user clicks on the label, the alert box (similar to the one shown in Figure 17-22) is opened. F IGURE 17-22: An alert box displaying the value of the label element To allow additional flexibility, several elements can receive notifications when a certain event occurs. This notification process is called event propagation and is divided into two phases. First, the event is sent to every ancestor element on the document hierarchy path, starting with the top-level document and moving all the way down to the element that triggered the event (the target). If any element above the target node has a registered capturing handler for the event (see the Note that follows), the handler will be executed during this capturing phase.Any event handler can prevent further event propagation by calling the stopPropagation method of its event parameter. Event handlers defined using the element event attributes (such as onclick) are noncaptur- ing. Further, as you will see in this section, you can use the addEventListener method to dynamically define a capturing event handler. The second part of the event propagation process is called the bubbling phase, and it is the reverse of the capturing phase. During event bubbling, the event is sent to every ancestor of the target element, starting with the parent of the target node and moving all the way up the ele- ment hierarchy, ending with the top-level document node. Any event handler can prevent fur- ther bubbling by calling the stopPropagation method of its event parameter. An example of the bubbling phase follows: <box id=”top-box” onclick=”handleClick(event);”> <box id=”inner-box” onclick=”handleClick(event);”> <button id=”button-element” label=”Test” onclick=”handleClick(event);”/> </box> </box> 25_596500 ch17.qxd 6/30/05 3:14 PM Page 358 359 Chapter 17 — Creating Extensions We defined the following element hierarchy: top-box ➪ inner-box ➪ button-element We attached the same event handler to all three elements. Let’s define our handleClick function: function handleClick(event) { dump(event.currentTarget.id + ‘\n’); } When the user clicks on the button, three lines will be printed on the console: button-element inner-box top-box We are witnessing the bubbling phase. First, the button’s event handler is called; then the one attached to the inner box; and finally, the event handler defined on the top-level box. To see the previous example in action, you can create the following XUL document and open it in Firefox: <?xml version=”1.0” encoding=”UTF-8”?> <window align=”start” xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul”> <script type=”application/x-javascript”> <![CDATA[ function handleClick(event) { dump(event.currentTarget.id + ‘\n’); } ]]> </script> <box id=”top-box” onclick=”handleClick(event);”> <box id=”inner-box” onclick=”handleClick(event);”> <button id=”button-element” label=”Test” onclick=”handleClick(event);”/> </box> </box> </window> The currentTarget property contains the element that defined the executing event handler, and the target property contains the element that triggered the event (the button, in our example). If we used the target property in our last example, we would see the “button- element” line printed three times. 25_596500 ch17.qxd 6/30/05 3:14 PM Page 359 360 Part VI — Creating Extensions and Themes There is an additional way of registering event handlers. You can use the DOM addEventListener method to attach an event handler to an element. This method is more flexible because it allows you to attach event handlers dynamically, define more than one handler for a given element, and define capturing events. Let’s continue our previous example by attaching a capturing event handler to our top-box element: var topBoxElement = document.getElementById(‘top-box’); topBoxElement.addEventListener(“click”, handleClick, true); The third parameter of the addEventListener method specifies whether the attached event handler will capture events during the capturing phase. We can attach an event handler by using the addEventListener function at any time — during the UI initialization, as a result of some user action, and so on. After we attached the capturing event handler, pressing the button produces the following output: top-box button-element inner-box top-box As you can see, the first line is printed during the capturing phase, before the button itself receives the event; all the other lines that are printed during the bubbling phase remained the same, as in the previous example. Figure 17-23 demonstrates the two phases of the event propagation process. F IGURE 17-23: The event propagation process Some events have default actions associated with them. These actions, which are imple- mented internally by the browser, can be cancelled from any event handler by calling the preventDefault method of the event object passed to it as a parameter. top-box 1 Capturing phase capturing? inner-box button-element 2 Bubbling phase Event target capturing? capturing? 25_596500 ch17.qxd 6/30/05 3:14 PM Page 360 361 Chapter 17 — Creating Extensions Dialogs In the previous sections, we saw a XUL document that defines an overlay, a portion of the user interface that will be merged with another document. An overlay document has an overlay element at its root. Documents having a window element as their root define stand-alone, top- level application windows, such as the Bookmarks Manager or the JavaScript Console. Dialogs and windows have several things in common, but there are several conceptual differ- ences between them: Ⅲ Dialogs usually perform a temporary function, such as asking for a password, letting the user change some aspect of the program, or displaying a message. Ⅲ A dialog often has buttons that allow the user to close it. Many dialogs have an OK but- ton that closes the dialog while accepting the user input and a Cancel button that closes the dialog without performing any action. Ⅲ Dialogs are typically smaller than the top-level application windows. Ⅲ A dialog can be modal, meaning that the user cannot resume using the application until the dialog is closed. In XUL, a dialog is defined by creating a document having the dialog element at its root. An example of a simple dialog follows: <?xml version=”1.0” encoding=”UTF-8”?> <?xml-stylesheet href=”chrome://global/skin” type=”text/css”?> <dialog xmlns=”http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul” id=”test-dialog” title=”Test Dialog” buttons=”accept,cancel” ondialogaccept=”return dialogOK();” ondialogcancel=”return dialogCancel();”> <script type=”application/x-javascript”><![CDATA[ function dialogOK() { alert(“OK pressed”); return true; } function dialogCancel() { alert(“Cancel pressed”); return true; } ]]></script> <label value=”Testing 1 2 3”/> </dialog> 25_596500 ch17.qxd 6/30/05 3:14 PM Page 361 . 3’);”/> F IGURE 1 7-1 2: A simple button A toolbarbutton is a special button that is usually a part of a toolbar and typically has an image (see Figure 1 7-1 3): <toolbarbutton id=”home-button” class=”toolbarbutton-1”. string, often used as a label for another ele- ment (see Figure 1 7-1 4): <label value=”Your first name:”/> <textbox id=”first-name”/> F IGURE 1 7-1 4: A label element next to a text box 25_596500. capturing event handler, pressing the button produces the following output: top-box button-element inner-box top-box As you can see, the first line is printed during the capturing phase, before