Commander Chain
The HP webOS SDK provides a model for propagating commands through the app, which are stage and scene controllers called the Commander Chain. The DOM event model did not provide the fine-grained control needed for event propagation to serve this need. Although the commanders are often in the DOM, they are not consistently ordered with the event handling required.
The chain is an array of handlers, ordered like a stack. The handlers, or commanders, are put onto the chain in the order that they register themselves and events propagate according this order.
Registering Commanders
Commanders are registered implicitly by declaring a handleCommand method as a stage-assistant or scene-assistant method, or for dialogs, when instantiated. The framework always adds the App-Assistants to the bottom of the Stage-Controller chain at instantiation.
Commanders can register explicitly by calling the pushCommander method from either StageController or SceneController. The commander is removed after popping the scene-assistant is popped or closing the application.
Command Propagation
The chain is really a tree of chains, illustrated in the figure. There is a chain for each StageController, and then within each stage there is a chain for each SceneController. Commands propagate starting with the first commander in the Scene-Controller chain in the active Scene. After calling all of the commanders in the Scene, propagation continues with the first commander in the StageController chain through the rest of the chain. There are chains for each of the inactive StageControllers and SceneControllers, but commands do not propagate to any inactive chains.

Figure - Commander Chain Propagation
Any commander can at any time stop propagation by calling event.stopPropagation. For example, a scene puts up a modal dialog, so it is implicitly added to the chain. It has the opportunity to handle a back event and stop propagation before it gets back to the scene that pushed the dialog. If not, the stage controller sees the back gesture and pops the scene, which is not the desired user experience.
Commanders can always remove themselves from the chain by calling the removeCommander method, either StageController or SceneController. For example:
{{this.controller.removeCommander(this);}}
Events and Commands
There are three types of events that propagate through the chain:
- Mojo.Event.back: indicates a back gesture.
- Mojo.Event.command: used for all menu commands.
- Mojo.Event.commandEnable: enables a menu item dynamically.
Command and Command Enable events are both discussed under Menus - Code Examples. The former is used when selecting a menu command and the latter when creating a menu for any menu item that includes the property commandEnable set to true. If any commander wants to inhibit the menu command, it calls stopPropagation to do so. The framework uses this to inhibit the Edit functions in the App Menu when anything other than a Text Field is in focus.
Using the Commander Chain for an App Menu
A common application of the commander chain is the consolidation of the setup and handling of the AppMenu into the stage controller. You can create a global app menu attributes and model in the stage-assistant:
myMenuAttr = {omitDefaultItems: true}; myMenuModel = { visible: true, items: [ {label: "About My App...", command: 'do-about'}, Mojo.Menu.editItem, { label: "Preferences...", command: 'do-prefs' }, { label: "Help...", command: 'do-help' } ] };
And add the handleCommand method:
// ---------------------------------------------------- // Set up handlers for command menu // // handleCommand - Setup handlers for App menus // StageAssistant.prototype.handleCommand = function(event) { // Find the current scene var currentScene = Mojo.Controller.stageController.activeScene(); if(event.type == Mojo.Event.command) { switch(event.command) { case 'do-about': currentScene.showAlertDialog({ onChoose: function(value) {}, title: $L("My App - v1.0"), message: $L("Copyright 2008-2009, Palm Inc."), choices:[ {label:$L("OK"), value:""} ] }); break; case 'do-prefs': Mojo.Controller.stageController.pushScene("myPrefs", this); break; case 'do-help': Mojo.Log.info("...........", "Help selected from menu, not currently available."); break; } } };
Then simply instantiate the menu in each scene with:
// Set up App Menu this.controller.setupWidget(Mojo.Menu.appMenu, myMenuAttr, myMenuModel);
When the App Menu commands propagate, the stage-assistant handles them, but they need to be aware of the current scene, which can be done by setting the local variable currentScene to the active scene controller at the beginning of handleCommand. From there, the code is just as you would do it within a given scene.
You can override the application-wide behavior in a specific scene by defining scene-specific app menu attributes or model before setting up the app menu and including a handleCommand method in that scene to handle the app menu commands there. Do not forget to call event.stopPropagation if you use any of the same commands used in your global app menu.