Focus and Selection

The section will describe how to handle the focus and selection of elements.

Focused Elements

The focused element refers to the element which currently receives input events. If there are three textboxes on a window, the one that has the focus is the one that the user can currently enter text into. Only one element per window has the focus at a time.

The user can change the focus by clicking an element with the mouse or by pressing the TAB key. When the TAB key is pressed, the next element is given the focus. To step backwards, the Shift key and Tab key can be pressed.

You can change the order in which elements are focused when the user presses the TAB key by adding a tabindex attribute to an element. This attribute should be set to a number. When the user presses TAB, the focus will shift to the element with the next highest tab index. That means that you can order the elements by setting indices on elements in sequence. Usually, however, you would not set the tabindex attribute. If you do not, pressing TAB will set the focus to the next displayed element. You only need to set tab indices if you wish to use a different order. Here is an example:

Example 6.4.1: Source View
<button label="Button 1" tabindex="2"/>
<button label="Button 2" tabindex="1"/>
<button label="Button 3" tabindex="3"/>

The focus event is used to respond when the focus is given to an element. The blur event is used to respond when the focus is removed from an element. You can respond to focus changes by adding an onfocus or onblur attribute on an element. They work just like their HTML counterparts. You might use these event handlers to highlight the element or display text on a status bar. The following example can be used to apply a function to handle a focus event.

Example 6.4.2: Source View
<script>
function displayFocus()
{
  var elem=document.getElementById('sbar');
  elem.setAttribute('value','Enter your phone number.');
}
</script>
<textbox id="tbox1"/>
<textbox id="tbox2" onfocus="displayFocus();"/>
<description id="sbar" value=""/>

The focus event, when it occurs, will call the displayFocus function. This function will change the value of the text label. We could extend this example to remove the text when the blur event occurs. Typically, you will use focus and blur events to update parts of the interface as the user selects elements. For instance, you might update a total as the user enters values in other fields, or use focus events to validate certain values. Don't display an alert during a focus or blur event as this will be distracting for the user and is poor user interface design.

You can also add event handlers dynamically using the DOM function addEventListener. You can use it for any element and event type. It takes three parameters, the event type, a function to execute when the event occurs and a boolean indicating whether to capture or not.

The currently focused element is held by an object called a command dispatcher, of which there is only one for the window. The command dispatcher is responsible for keeping track of the focused element as the user uses the interface. The command dispatcher has other roles, which will be discussed in a later section on commands. For now, we'll look at some of the focus related features of the command dispatcher.

You can retrieve the command dispatcher from a window using the document's commandDispatcher property. From there, you can get the focused element with the dispatcher's focusedElement property. The example below shows this.

Example 6.4.3: Source View
<window id="focus-example" title="Focus Example"
        onload="init();"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script>
function init()
{
  addEventListener("focus",setFocusedElement,true);
}
function setFocusedElement()
{
  var focused = document.commandDispatcher.focusedElement;
  document.getElementById("focused").value = focused.tagName;
}
</script>
<hbox>
  <label control="username" value="User Name:"/>
  <textbox id="username"/>
</hbox>
<button label="Hello"/>
<checkbox label="Remember This Decision"/>
<label id="focused" value="-No focus-"/>
</window>

In this example, a focus event handler is attached the window. We want to use a capturing event handler, so the addEventListener method needs to be used. It registers a capturing event handler with the window which will call the setFocusedElement method. This method gets the focused element from the command dispatcher and sets a label to its tag name. As the focused element is changed, the label will show the tagname of the element. A few things to note. First, when the textbox is focused, the tag name is 'html:input', not 'textbox' as we might expect. This is because XUL text boxes are implemented using the HTML input widget, so the focus event is received for that element instead. Second, clicking the textbox's label changes the focus to the textbox. This is because the label has a control attribute pointing to the id of the textbox. Finally, the other label which displays the tag name has no control attribute, so clicking it has no effect on the focused element. Only focusable elements can be focused.

If you were creating custom elements, you might have a need to change whether an element can have the focus or not. For this, you can use a special style property -moz-user-focus. This property controls whether an element can be focused. For instance, you could make a label focusable, as in the example below.

Example 6.4.4: Source View
<label id="focused" style="-moz-user-focus: normal;"
          onkeypress="alert('Label Focused');" value="Focus Me"/>

The style property is set to normal. You can also set it to ignore to turn off the focus for an element. This shouldn't be used for disabling an element, however; the disabled attribute or property should be used instead, since that is what it is designed for. Once the label in the example is focused, it can respond to key presses. Naturally, the label gives no indication that it is focused, since it isn't normally expected to ever be focused.

There are several ways to change the currently focused element. The simplest is to call the focus method of a the XUL element that you wish to set the focus to. The blur method can be used to remove the focus from an element. The following example demonstrates this:

Example 6.4.5: Source View
<textbox id="addr"/>
<button label="Focus" oncommand="document.getElementById('addr').focus()"/>

Or, you can use the methods advanceFocus and rewindFocus on the command dispatcher. These methods move the focus to the next element is sequence or the previous element respectively. This is what happens when the user presses TAB or Shift+Tab.

For textboxes, a special attribute, focused is added whenever the element has the focus. You can check for the presence of this attribute to determine if the element has the focus, either from a script or within a style sheet. It will have the value true. if the textbox has the focus and, if the textbox does not have the focus, the attribute will not be present.

Handling Text Changes

There are two events that can used when the user changes the value of a textbox. Naturally, these events will only be sent to the textbox that has the focus. The input event is fired whenever the text is modified in the field. The new value will be different than the old value. You may want to use this event instead of using key events, as some keys such as the shift key don't change the value. Also, the input event would not fire if a letter key was pressed and there were already more characters than will fit in the textbox.

The change event is similar in that it fires only when the field is changed. However it only fires once the textbox loses the focus, thus, only once per set of changes.

Text Selection

When working with a textbox, you may wish to retrieve not the entire contents of a field but only what the user has selected. Or, you may wish to change the current selection.

XUL textboxes support a way to retrieve and modify the selection. The simplest one is to select all of the text in a textbox. This involves using the select method of the textbox.

tbox.select();

However, you may wish to select only part of the text. To do this you can use the setSelectionRange function. It takes two parameters, the first is the starting character and the second is the character after the last one that you want to have selected. Values are zero-based, so the first character is 0, the second is 1 and so on.

tbox.setSelectionRange(4,8);

This example will select the fifth character displayed, as well as the sixth, seventh and eighth. If there were only six characters entered into the field, only the fifth and sixth characters would be selected. No error would occur.

If you use the same value for both parameters, the start and end of the selection changes to the same position. This results in changing the cursor position within the textbox. For example, the line below can be used to move the cursor to the beginning of the text.

tbox.setSelectionRange(0,0);

You can retrieve the current selection by using the selectionStart and selectionEnd properties. These properties are set to the starting and ending positions of the current selection respectively. If both are set to the same value, no text is selected, but the values will be set to the current cursor position. Once you have the start and end positions, you can pull out the substring from the whole text.

You can retrieve and modify the contents of the textbox by using the value property.

One additional useful property of textboxes is the textLength property, which holds the total number of characters in the field.


(Next) Next, we'll find out how to use commands.

Examples: 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5

Add a note User Contributed Notes
May 21, 2005, 12:19 am goodwill at webhippo dot org
For textbox setting -moz-user-focus: ignore does not work well. It disables the xul element but does not pass on the setting to the html:input or html:textarea of which textbox is constructed. The effect is while the you do not see the focus on the texbox the tabindex for it still counts and wreaks havoc. Here is a quick fix that involves javascript.


function fix_tabindex()
{
alert('please set focus to the top textbox and try tabbing again');

var elemid = 'no_focus_textbox';
textbox_RemoveTabedIndex(elemid);
}

function textbox_RemoveTabedIndex(elemid)
{
var elem = document.getElementById(elemid);
if (elem && elem.tagName=='textbox')
{
var html_elem = document.getAnonymousNodes(
document.getElementById(elemid)).item(0).firstChild;
var style=document.defaultView.getComputedStyle(html_elem,null);
html_elem.style.setProperty('-moz-user-focus','ignore','');
}
}



<vbox>
<spacer height="20px" />
<label id='desc' value="tab thru each element, the second textbox has -moz-user-focus: ignore set but still when you tab, you will have to press tab key twice till you get to the 3rd textbox" />
<textbox value="should have tabindex"/>
<textbox id="no_focus_textbox"
style="-moz-user-focus: ignore; -moz-user-input: none; -moz-user-select: none;"
value="should NOT have tabindex but does even though style='-moz-user-focus: ignore; -moz-user-input: none; -moz-user-select: none;' is set" />
<textbox value="should have tabindex"/>
</vbox>
<button label="click fix tabindex" oncommand="fix_tabindex();" />

</window>
January 14, 2005, 8:52 am l3ert at hotmail dot com
You have to go up 2 parentNode to get the id of a textbox because a textbox is actually a html:input inside of a hbox so, when a textbox has focus, document.commandDispatcher.focusedElement is the html:input and not the textbox.
September 27, 2004, 7:25 am tony at gigaday dot com
In example 7.4.3 it doesn't actually explain how to get the id of the element that has focus. I did this using
focused_com =      document.commandDispatcher.focusedElement.parentNode.parentNode.getAttribute("id")

which did the trick for a textbox in a grid.

Copyright © 1999 - 2005 XULPlanet.com