Handling MenuBuilder menu events

Adobe AIR 1.0 and later

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:

  • altKey

  • cmdKey

  • ctrlKey

  • defaultKeyEquivalentModifiers

  • enabled

  • keyEquivalent

  • label

  • mnemonicIndex

  • onSelect

  • shiftKey

  • toggled

  • type

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); 
    } 
}

// Ethnio survey code removed