Updating Commands

In this section, we will look at how to update commands.

Invoking Commands

If a command has an oncommand attribute, you can invoke it just by using the doCommand method of the command or an element which links to it. For other commands, you will need to use a couple of additional lines of code. You will need to use these extra steps when invoking commands implemented by a controller. In addition, you will need to do this when creating your own menu commands, for instance to implement the edit menu commands in your own application.

Fortunately, the extra code is fairly simple. All we need to do is get the needed controller and call the command. A simple way of doing this is the following:

var controller = document.commandDispatcher.getControllerForCommand("cmd_paste");
if (controller && controller.isCommandEnabled("cmd_paste")){
  controller.doCommand(command);
}

The code above first retrieves the controller for the 'cmd_paste' command from the command dispatcher. Then, it checks to see whether the command is enabled, and then executes the command using the doCommand method of the controller. Note that we don't need to figure out which element to use or which controller to use. The command dispatcher handles that part. Also, we could just call doCommand without checking if the command was enabled or not, although we probably shouldn't do that.

The code above is generic enough that it can be a function that takes a command as an argument and executes that command. This function could then be reused for all commands. In fact, this is common enough that Mozilla includes a library which does just that. If you include the script 'chrome://global/content/globalOverlay.js' in a XUL file, you can call the goDoCommand method which executes the command passed as the argument. The code for this function is only a few lines long so you could include it directly in your code if for some reason you didn't want to include the library.

<script src="chrome://global/content/globalOverlay.js"/>

<command id="cmd_paste" oncommand="goDoCommand('cmd_paste');"/>
<button label="Paste" command="cmd_paste"/>

The example above will implement a Paste button. It is attached to the command which will invoke the command on the necessary controller when called. The code above is all you need to implement the functionality of the paste command in your application. The only other thing you need to do is ensure that the enabled status of the paste command, and therefore the button, is updated at the right time, which is described below.

Command Updaters

A command updater is a feature of the commandset element which allows it to update commands when certain events happen. You will need to think about when a command is valid and when it is not. In addition, you will need to consider when the state could change and when the commands should be updated.

For example, the paste command is valid when a textbox has the focus and there is something on the clipboard to paste. The command will become enabled whenever a textbox is focused and when the clipboard contents change. A command updater will listen for these situations and code can be executed which enables and disables commands as necessary.

A simple command updater looks like this:

<commandset id="updatePasteItem"
            commandupdater="true"
            events="focus"
            oncommandupdate="goUpdateCommand('cmd_paste');"/>

A command updater is indicated by using the commandupdater attribute, which should be set to true. The events attribute is used to list the events that the command updater listens for. You can specify multiple events by separating them with commas. In the example above, the command updater listens for the focus event. This causes commands to be updated when an element receives the focus.

When a focus event occurs, the code in the oncommandupdate attribute is called. In the example, the goUpdateCommand method is called which is a function provided by the globalOverlay.js script described earlier. It will update the command and enable or disable necessary buttons and menu items. The code behind it is fairly simple. It just gets the necessary controller, calls its isCommandEnabled method, and then enables or disables the command. If you have several commands to update, call the goUpdateCommand method once for each command.

Note that the command updater will receive notifications about all focus events on all elements, even if other event handlers respond to the event. Essentially, a command updater is like a global event handler.

Command updaters have a number of events which they can respond to which are listed below. It is also possible to create your own.

  • focus: occurs when the focused element changes.
  • select: occurs when the selected text changes.
  • undo: occurs when the undo buffer changes.
  • clipboard: occurs when the contents of the clipboard changes.

The following example shows the command updaters used in the Mozilla browser to update the edit menu commands. The functions used can be found in the 'chrome://communicator/content/utilityOverlay.js' script.

<commandset id="globalEditMenuItems"
            commandupdater="true"
            events="focus"
            oncommandupdate="goUpdateGlobalEditMenuItems()"/>
<commandset id="selectEditMenuItems"
            commandupdater="true"
            events="select"
            oncommandupdate="goUpdateSelectEditMenuItems()"/>
<commandset id="undoEditMenuItems"
            commandupdater="true"
            events="undo"
            oncommandupdate="goUpdateUndoEditMenuItems()"/>
<commandset id="clipboardEditMenuItems"
            commandupdater="true"
            events="clipboard"
            oncommandupdate="goUpdatePasteMenuItems()"/>

Next, we'll find out how to use observers.