User interaction with a NativeMenu is event-driven. When the
user selects a menu item or opens a menu or submenu, the NativeMenuItem
object dispatches an event. With a NativeMenu object created using
the MenuBuilder framework, you can register event listeners with
individual NativeMenuItem objects or with the NativeMenu. You subscribe
and respond to these events the same way as if you had created the
NativeMenu and NativeMenuItem objects manually rather than using
the MenuBuilder framework. For more information see
Menu events
.
The MenuBuilder framework supplements the standard event handling, providing
a way to specify a
select
event handler function
for a menu item within the menu data source. If you specify an
onSelect
field
in the menu item data source, the specified function is called when
the user selects the menu item. For example, suppose the following
XML node is included in a data source that’s loaded using the MenuBuilder
framework. When the menu item is selected the function named
doSave()
is
called:
<menuitem label="Save" onSelect="doSave"/>
The
onSelect
field is a String when it’s used
with an XML data source. With a JSON array, the field can be a String
with the name of the function. In addition, for a JSON array only,
the field can also be a variable reference to the function as an
object. However, if the JSON array uses a Function variable reference
the menu must be created before or during the
onload
event
handler or a JavaScript security violation occurs. In all cases,
the specified function must be defined in the global scope.
When the specified function is called, the runtime passes two
arguments to it. The first argument is the event object dispatched
by the
select
event. It is an instance of the Event
class. The second argument that’s passed to the function is an anonymous
object containing the data that was used to create the menu item. This
object has the following properties. Each property’s value matches
the value in the original data structure or
null
if
the property is not set in the original data structure:
The following example lets you experiment with NativeMenu events.
The example includes two menus. The window and application menu
is created using an XML data source. The context menu for the list
of items represented by the
<ul>
and
<li>
elements
is created using a JSON array data source. A text area on the screen
displays information about each event as the user selects menu items.
The following listing is the source code of the application:
<html>
<head>
<title>Menu event handling example</title>
<script type="text/javascript" src="AIRAliases.js"></script>
<script type="text/javascript" src="AIRMenuBuilder.js"></script>
<script type="text/javascript" src="printObject.js"></script>
<script type="text/javascript">
function fileMenuCommand(event, data) {
print("fileMenuCommand", event, data);
}
function editMenuCommand(event, data) {
print("editMenuCommand", event, data);
}
function moveItemUp(event, data) {
print("moveItemUp", event, data);
}
function moveItemDown(event, data) {
print("moveItemDown", event, data);
}
function print(command, event, data) {
var result = "";
result += "<h1>Command: " + command + '</h1>';
result += "<p>" + printObject(event) + "</p>";
result += "<p>Data:</p>";
result += "<ul>";
for (var s in data) {
result += "<li>" + s + ": " + printObject(data[s]) + "</li>";
}
result += "</ul>";
var o = document.getElementById("output");
o.innerHTML = result;
}
</script>
<style type="text/css">
#contextList {
position: absolute; left: 0; top: 25px; bottom: 0; width: 100px;
background: #eeeeee;
}
#output {
position: absolute; left: 125px; top: 25px; right: 0; bottom: 0;
}
</style>
</head>
<body>
<div id="contextList">
<ul>
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
</ul>
</div>
<div id="output">
Choose menu commands. Information about the events displays here.
</div>
<script type="text/javascript">
var mainMenu = air.ui.Menu.createFromXML("mainMenu.xml");
air.ui.Menu.setAsMenu(mainMenu);
var listContextMenu = air.ui.Menu.createFromJSON("listContextMenu.js");
air.ui.Menu.setAsContextMenu(listContextMenu, "contextList")
// clear the default context menu
air.ui.Menu.setAsContextMenu(null);
</script>
</body>|
</html>
The following listing is the data source for the main menu (“mainMenu.xml”):
<?xml version="1.0" encoding="utf-8" ?>
<root>
<menuitem label="File">
<menuitem label="New" keyEquivalent="n" onSelect="fileMenuCommand"/>
<menuitem label="Open" keyEquivalent="o" onSelect="fileMenuCommand"/>
<menuitem label="Save" keyEquivalent="s" onSelect="fileMenuCommand"/>
<menuitem label="Save As..." keyEquivalent="S" onSelect="fileMenuCommand"/>
<menuitem label="Close" keyEquivalent="w" onSelect="fileMenuCommand"/>
</menuitem>
<menuitem label="Edit">
<menuitem label="Cut" keyEquivalent="x" onSelect="editMenuCommand"/>
<menuitem label="Copy" keyEquivalent="c" onSelect="editMenuCommand"/>
<menuitem label="Paste" keyEquivalent="v" onSelect="editMenuCommand"/>
</menuitem>
</root>
The following listing is the data source for the context menu
(“listContextMenu.js”);
[
{label: "Move Item Up", onSelect: "moveItemUp"},
{label: "Move Item Down", onSelect: "moveItemDown"}
]
The following listing contains the code from the printObject.js
file. The file includes the
printObject()
function,
which the application uses but which doesn’t affect the operation
of the menus in the example.
function printObject(obj) {
if (!obj) {
if (typeof obj == "undefined") { return "[undefined]"; };
if (typeof obj == "object") { return "[null]"; };
return "[false]";
} else {
if (typeof obj == "boolean") { return "[true]"; };
if (typeof obj == "object") {
if (typeof obj.length == "number") {
var ret = [];
for (var i=0; i<obj.length; i++) {
ret.push(printObject(obj[i]));
}
return ["[", ret.join(", "), "]"].join(" ");
} else {
var ret = [];
var hadChildren = false;
for (var k in obj) {
hadChildren = true;
ret.push ([k, " => ", printObject(obj[k])]);
}
if (hadChildren) {
return ["{\n", ret.join(",\n"), "\n}"].join("");
}
}
}
if (typeof obj == "function") { return "[Function]"; }
return String(obj);
}
}