<?xml version="1.0"?> <!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <?xml-stylesheet href="chrome://global/skin" type="text/css"?> <window id="NativeMenuWindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" width="300" height="300" onload="onLoad();" title="Native Menu Test"> <command id="cmd_FooItem0" oncommand="executedCommandID = 'cmd_FooItem0';"/> <command id="cmd_FooItem1" oncommand="executedCommandID = 'cmd_FooItem1';"/> <command id="cmd_BarItem0" oncommand="executedCommandID = 'cmd_BarItem0';"/> <command id="cmd_BarItem1" oncommand="executedCommandID = 'cmd_BarItem1';"/> <command id="cmd_NewItem0" oncommand="executedCommandID = 'cmd_NewItem0';"/> <command id="cmd_NewItem1" oncommand="executedCommandID = 'cmd_NewItem1';"/> <command id="cmd_NewItem2" oncommand="executedCommandID = 'cmd_NewItem2';"/> <command id="cmd_NewItem3" oncommand="executedCommandID = 'cmd_NewItem3';"/> <command id="cmd_NewItem4" oncommand="executedCommandID = 'cmd_NewItem4';"/> <command id="cmd_NewItem5" oncommand="executedCommandID = 'cmd_NewItem5';"/> <!-- We do not modify any menus or menu items defined here in testing. These serve as a baseline structure for us to test after other modifications. We add children to the menubar defined here and test by modifying those children. --> <menubar id="nativemenubar"> <menu id="foo" label="Foo"> <menupopup> <menuitem label="FooItem0" command="cmd_FooItem0"/> <menuitem label="FooItem1" command="cmd_FooItem1"/> <menuseparator/> <menu label="Bar"> <menupopup> <menuitem label="BarItem0" command="cmd_BarItem0"/> <menuitem label="BarItem1" command="cmd_BarItem1"/> </menupopup> </menu> </menupopup> </menu> </menubar> <script type="application/javascript"><![CDATA[ function ok(condition, message) { window.opener.wrappedJSObject.SimpleTest.ok(condition, message); } function onTestsFinished() { window.close(); window.opener.wrappedJSObject.SimpleTest.finish(); } // Force a menu to update itself. All of the menus parents will be updated // as well. An empty string will force a complete menu system reload. function forceUpdateNativeMenuAt(location) { var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor). getInterface(Components.interfaces.nsIDOMWindowUtils); try { utils.forceUpdateNativeMenuAt(location); } catch (e) { dump(e + "\n"); } } var executedCommandID = ""; function testItem(location, targetID) { var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor). getInterface(Components.interfaces.nsIDOMWindowUtils); var correctCommandHandler = false; try { utils.activateNativeMenuItemAt(location); correctCommandHandler = executedCommandID == targetID; } catch (e) { dump(e + "\n"); } finally { executedCommandID = ""; return correctCommandHandler; } } function createXULMenuPopup() { const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var item = document.createElementNS(XUL_NS, "menupopup"); return item; } function createXULMenu(aLabel) { const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var item = document.createElementNS(XUL_NS, "menu"); item.setAttribute("label", aLabel); return item; } function createXULMenuItem(aLabel, aCommandId) { const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; var item = document.createElementNS(XUL_NS, "menuitem"); item.setAttribute("label", aLabel); item.setAttribute("command", aCommandId); return item; } function runBaseMenuTests() { forceUpdateNativeMenuAt("0|3"); return testItem("0|0", "cmd_FooItem0") && testItem("0|1", "cmd_FooItem1") && testItem("0|3|0", "cmd_BarItem0") && testItem("0|3|1", "cmd_BarItem1"); } function onLoad() { var _delayedOnLoad = function() { // First let's run the base menu tests. ok(runBaseMenuTests()); // Set up some nodes that we'll use. var menubarNode = document.getElementById("nativemenubar"); var newMenu0 = createXULMenu("NewMenu0"); var newMenu1 = createXULMenu("NewMenu1"); var newMenuPopup0 = createXULMenuPopup(); var newMenuPopup1 = createXULMenuPopup(); var newMenuItem0 = createXULMenuItem("NewMenuItem0", "cmd_NewItem0"); var newMenuItem1 = createXULMenuItem("NewMenuItem1", "cmd_NewItem1"); var newMenuItem2 = createXULMenuItem("NewMenuItem2", "cmd_NewItem2"); var newMenuItem3 = createXULMenuItem("NewMenuItem3", "cmd_NewItem3"); var newMenuItem4 = createXULMenuItem("NewMenuItem4", "cmd_NewItem4"); var newMenuItem5 = createXULMenuItem("NewMenuItem5", "cmd_NewItem5"); // Create another submenu with hierarchy via DOM manipulation. // ****************** // * Foo * NewMenu0 * <- Menu bar // ****************** // **************** // * NewMenuItem0 * <- NewMenu0 submenu // **************** // * NewMenuItem1 * // **************** // * NewMenuItem2 * // ******************************* // * NewMenu1 > * NewMenuItem3 * <- NewMenu1 submenu // ******************************* // * NewMenuItem4 * // **************** // * NewMenuItem5 * // **************** newMenu0.appendChild(newMenuPopup0); newMenuPopup0.appendChild(newMenuItem0); newMenuPopup0.appendChild(newMenuItem1); newMenuPopup0.appendChild(newMenuItem2); newMenuPopup0.appendChild(newMenu1); newMenu1.appendChild(newMenuPopup1); newMenuPopup1.appendChild(newMenuItem3); newMenuPopup1.appendChild(newMenuItem4); newMenuPopup1.appendChild(newMenuItem5); //XXX - we have to append the menu to the top-level of the menu bar // only after constructing it. If we append before construction, it is // invalid because it has no children and we don't validate it if we add // children later. menubarNode.appendChild(newMenu0); forceUpdateNativeMenuAt("1|3"); // Run basic tests again. ok(runBaseMenuTests()); // Error strings. var sa = "Command handler(s) should have activated"; var sna = "Command handler(s) should not have activated"; // Test middle items. ok(testItem("1|1", "cmd_NewItem1"), sa); ok(testItem("1|3|1", "cmd_NewItem4"), sa); // Hide newMenu0. newMenu0.setAttribute("hidden", "true"); ok(runBaseMenuTests(), sa); // the base menu should still be unhidden ok(!testItem("1|0", ""), sna); ok(!testItem("1|1", ""), sna); ok(!testItem("1|2", ""), sna); ok(!testItem("1|3|0", ""), sna); ok(!testItem("1|3|1", ""), sna); ok(!testItem("1|3|2", ""), sna); // Show newMenu0. newMenu0.setAttribute("hidden", "false"); forceUpdateNativeMenuAt("1|3"); ok(runBaseMenuTests(), sa); ok(testItem("1|0", "cmd_NewItem0"), sa); ok(testItem("1|1", "cmd_NewItem1"), sa); ok(testItem("1|2", "cmd_NewItem2"), sa); ok(testItem("1|3|0", "cmd_NewItem3"), sa); ok(testItem("1|3|1", "cmd_NewItem4"), sa); ok(testItem("1|3|2", "cmd_NewItem5"), sa); // Hide items. newMenuItem1.setAttribute("hidden", "true"); newMenuItem4.setAttribute("hidden", "true"); forceUpdateNativeMenuAt("1|2"); ok(runBaseMenuTests(), sa); ok(testItem("1|0", "cmd_NewItem0"), sa); ok(testItem("1|1", "cmd_NewItem2"), sa); ok(!testItem("1|2", ""), sna); ok(testItem("1|2|0", "cmd_NewItem3"), sa); ok(testItem("1|2|1", "cmd_NewItem5"), sa); ok(!testItem("1|2|2", ""), sna); // Show items. newMenuItem1.setAttribute("hidden", "false"); newMenuItem4.setAttribute("hidden", "false"); forceUpdateNativeMenuAt("1|3"); ok(runBaseMenuTests(), sa); ok(testItem("1|0", "cmd_NewItem0"), sa); ok(testItem("1|1", "cmd_NewItem1"), sa); ok(testItem("1|2", "cmd_NewItem2"), sa); ok(testItem("1|3|0", "cmd_NewItem3"), sa); ok(testItem("1|3|1", "cmd_NewItem4"), sa); ok(testItem("1|3|2", "cmd_NewItem5"), sa); // At this point in the tests the state of the menus has been returned // to the originally diagramed state. // Test command disabling var cmd_NewItem0 = document.getElementById("cmd_NewItem0"); ok(testItem("1|0", "cmd_NewItem0"), sa); cmd_NewItem0.setAttribute("disabled", "true"); ok(!testItem("1|0", "cmd_NewItem0"), sna); cmd_NewItem0.removeAttribute("disabled"); ok(testItem("1|0", "cmd_NewItem0"), sa); // Remove menu. menubarNode.removeChild(newMenu0); ok(runBaseMenuTests(), sa); ok(!testItem("1|0", ""), sna); ok(!testItem("1|1", ""), sna); ok(!testItem("1|2", ""), sna); ok(!testItem("1|3|0", ""), sna); ok(!testItem("1|3|1", ""), sna); ok(!testItem("1|3|2", ""), sna); // return state to original diagramed state menubarNode.appendChild(newMenu0); // Test for bug 447042, make sure that adding a menu node with no children // to the menu bar and then adding another menu node with children works. // Menus with no children don't get their native menu items shown and that // caused internal arrays to get out of sync and an append crashed. var tmpMenu0 = createXULMenu("tmpMenu0"); menubarNode.removeChild(newMenu0); menubarNode.appendChild(tmpMenu0); menubarNode.appendChild(newMenu0); forceUpdateNativeMenuAt("1|3"); ok(runBaseMenuTests()); ok(testItem("1|0", "cmd_NewItem0"), sa); ok(testItem("1|1", "cmd_NewItem1"), sa); ok(testItem("1|2", "cmd_NewItem2"), sa); ok(testItem("1|3|0", "cmd_NewItem3"), sa); ok(testItem("1|3|1", "cmd_NewItem4"), sa); ok(testItem("1|3|2", "cmd_NewItem5"), sa); // return state to original diagramed state menubarNode.removeChild(tmpMenu0); delete tmpMenu0; // This test is basically a crash test for bug 433858. newMenuItem1.setAttribute("hidden", "true"); newMenuItem2.setAttribute("hidden", "true"); newMenu1.setAttribute("hidden", "true"); forceUpdateNativeMenuAt("1"); newMenuItem1.setAttribute("hidden", "false"); newMenuItem2.setAttribute("hidden", "false"); newMenu1.setAttribute("hidden", "false"); forceUpdateNativeMenuAt("1"); onTestsFinished(); } setTimeout(_delayedOnLoad, 1000); } ]]></script> </window>