Adding Event Handlers
Next, we'll find out how to add event handlers to XBL-defined elements.
As you might expect, mouse clicks, key presses and other events are passed to each of the elements inside the content. However, you may wish to trap the events and handle them in a special way. You can add event handlers to the elements inside the content if needed. The last example in the previous section demonstrated this. In that example, oncommand handlers were added to some buttons.
However, you may want to add an event handler to the entire contents, that is, all the elements defined in the content tag. This could be useful when trapping the focus and blur events. To define an event handler, use the handler element. Each will describe the action taken for a single event handler. You can use more than one handler if necessary. If an event does not match any of the handler events, it is simply passed to the inner content as usual.
The general handler syntax is as follows:
<binding id="binding-name"> <handlers> <handler event="event-name" action="script"/> </handlers> </binding>
A common reason to set handlers is to modify the custom properties when an event occurs. For example, a custom checkbox might have a checked property which needs to be changed when the user clicks the checkbox:
<handlers> <handler event="mouseup" action="this.checked=!this.checked"/> </handlers>
When the user clicks and releases the mouse button over the check box, the mouseup event is sent to it, and the handler defined here is called, causing the state of the checked property to be reversed. Similarly, you may wish to change a property when the element is focused. You will need to add handlers to adjust the properties whenever input from the mouse or keyboard would require it.
For mouse events, you can use the button attribute to have the handler only trap events that occur from a certain button. Without this attribute, the handler traps all events regardless of the button that was pressed. The button attribute should be set to either 0 for the left mouse button, 1 for the middle mouse button or 2 for the right mouse button.
<handlers> <handler event="click" button="0" action="alert('Left button pressed');"/> <handler event="mouseup" button="1" action="alert('Middle button pressed')"/> <handler event="click" button="2" action="alert('Right button pressed');"/> </handlers>
For key events, you can use a number of attributes similar to those for the key element to match a specific key and match only when certain modifer keys are pressed. The previous example could be extended so that the checked property of the check box is changed when the space bar is pressed.
<handlers> <handler event="keypress" key=" " action="this.checked=!checked"/> </handlers>
You can also use the keycode attribute to check for non-printable keys. The section on keyboard shortcuts provides more information. The modifier keys can be checked by adding a modifiers attribute. This should be set to one of the values set below:
- altThe user must press the Alt key.
- controlThe user must press the Control key.
- metaThe user must press the Meta key.
- shiftThe user must press the Shift key.
- accelThe user must press the special modifier key that is usually used for keyboard shortcuts on their platform.
If set, the handler is only called when the modifier is pressed. You can require multiple modifier keys by separating them with spaces.
The following alternate syntax can be used when the code in a handler is more complex:
<binding id="binding-name"> <handlers> <handler event="event-name"> -- handler code goes here -- </handler> </handlers> </binding>
The following example adds some key handlers to create a very primitive local clipboard:Example 11.6.1: Source
<binding id="clipbox"> <content> <xul:textbox/> </content> <implementation> <field name="clipboard"/> </implementation> <handlers> <handler event="keypress" key="x" modifiers="control" action="this.clipboard=document.getAnonymousNodes(this).value; document.getAnonymousNodes(this).value='';"/> <handler event="keypress" key="c" modifiers="control" action="this.clipboard=document.getAnonymousNodes(this).value;"/> <handler event="keypress" key="v" modifiers="control" action="document.getAnonymousNodes(this).value=this.clipboard ? this.clipboard : '';"/> </handlers> </binding>
The content is a single textbox. A field clipboard has been added to it to store the clipboard contents. This does mean that the clipboard operations are limited to this single textbox. However, each one will have its own buffer.
Three handlers have been added, one for cut, one for copy and the other for paste. Each has its own keystroke that invokes it. The first handler is the cut operation and is invoked when the Control key is pressed along with the x key. The script within the action attribute is used to cut the text from the textbox and put it into the clipboard field. For simplicity, the entire text is cut and not just the selected text. The code works as follows:
this.clipboard=document.getAnonymousNodes(this).value;The first element of the anonymous content array is retrieved which gives a reference to the textbox element, which happens to be the first (and only) element within the content element. The value property is retrieved which will provide the text within the textbox. This is then assigned to the clipboard field. The result is copying the text in the textbox into this special clipboard.
document.getAnonymousNodes(this).value=''The text of the textbox is then assigned a value of a null string. This effectively clears the text in the textbox.
A copy operation is similar but does not the clear the text afterwards. Pasting is the opposite where the value of the textbox is assigned from the value in the clipboard field. If we were creating a real implementation of these clipboard keyboard shortcuts, we would probably use the real clipboard interface and handle the current selection as well.
(Next) In the next section, we'll see how to extend existing XBL definitions.
<handler event="blur" phase="capturing">
var value = document.getAnonymousNodes(this).value;
dump( value + "\n" );
In this case I have a binding that looks like:
So, document.getAnonymousNodes(this).value; just get's me the textbox's value.