Source code
Revision control
Copy as Markdown
Other Tools
<?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
<window id="NativeMenuWindow"
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.arguments[0].SimpleTest.ok(condition, message);
}
function onTestsFinished() {
window.close();
window.arguments[0].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.windowUtils;
try {
utils.forceUpdateNativeMenuAt(location);
}
catch (e) {
dump(e + "\n");
}
}
var executedCommandID = "";
function testItem(location, targetID) {
var utils = window.windowUtils;
var correctCommandHandler = false;
try {
utils.activateNativeMenuItemAt(location);
correctCommandHandler = executedCommandID == targetID;
}
catch (e) {
dump(e + "\n");
}
finally {
executedCommandID = "";
}
return correctCommandHandler;
}
function createXULMenuPopup() {
var item = document.createElementNS(XUL_NS, "menupopup");
return item;
}
function createXULMenu(aLabel) {
var item = document.createElementNS(XUL_NS, "menu");
item.setAttribute("label", aLabel);
return item;
}
function createXULMenuItem(aLabel, aCommandId) {
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);
// 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);
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>