|
1 <?xml version="1.0"?> |
|
2 |
|
3 <!-- This Source Code Form is subject to the terms of the Mozilla Public |
|
4 - License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> |
|
6 |
|
7 <?xml-stylesheet href="chrome://global/skin" type="text/css"?> |
|
8 |
|
9 <window id="NativeMenuWindow" |
|
10 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" |
|
11 width="300" |
|
12 height="300" |
|
13 onload="onLoad();" |
|
14 title="Native Menu Test"> |
|
15 |
|
16 <command id="cmd_FooItem0" oncommand="executedCommandID = 'cmd_FooItem0';"/> |
|
17 <command id="cmd_FooItem1" oncommand="executedCommandID = 'cmd_FooItem1';"/> |
|
18 <command id="cmd_BarItem0" oncommand="executedCommandID = 'cmd_BarItem0';"/> |
|
19 <command id="cmd_BarItem1" oncommand="executedCommandID = 'cmd_BarItem1';"/> |
|
20 <command id="cmd_NewItem0" oncommand="executedCommandID = 'cmd_NewItem0';"/> |
|
21 <command id="cmd_NewItem1" oncommand="executedCommandID = 'cmd_NewItem1';"/> |
|
22 <command id="cmd_NewItem2" oncommand="executedCommandID = 'cmd_NewItem2';"/> |
|
23 <command id="cmd_NewItem3" oncommand="executedCommandID = 'cmd_NewItem3';"/> |
|
24 <command id="cmd_NewItem4" oncommand="executedCommandID = 'cmd_NewItem4';"/> |
|
25 <command id="cmd_NewItem5" oncommand="executedCommandID = 'cmd_NewItem5';"/> |
|
26 |
|
27 <!-- We do not modify any menus or menu items defined here in testing. These |
|
28 serve as a baseline structure for us to test after other modifications. |
|
29 We add children to the menubar defined here and test by modifying those |
|
30 children. --> |
|
31 <menubar id="nativemenubar"> |
|
32 <menu id="foo" label="Foo"> |
|
33 <menupopup> |
|
34 <menuitem label="FooItem0" command="cmd_FooItem0"/> |
|
35 <menuitem label="FooItem1" command="cmd_FooItem1"/> |
|
36 <menuseparator/> |
|
37 <menu label="Bar"> |
|
38 <menupopup> |
|
39 <menuitem label="BarItem0" command="cmd_BarItem0"/> |
|
40 <menuitem label="BarItem1" command="cmd_BarItem1"/> |
|
41 </menupopup> |
|
42 </menu> |
|
43 </menupopup> |
|
44 </menu> |
|
45 </menubar> |
|
46 |
|
47 <script type="application/javascript"><![CDATA[ |
|
48 |
|
49 function ok(condition, message) { |
|
50 window.opener.wrappedJSObject.SimpleTest.ok(condition, message); |
|
51 } |
|
52 |
|
53 function onTestsFinished() { |
|
54 window.close(); |
|
55 window.opener.wrappedJSObject.SimpleTest.finish(); |
|
56 } |
|
57 |
|
58 // Force a menu to update itself. All of the menus parents will be updated |
|
59 // as well. An empty string will force a complete menu system reload. |
|
60 function forceUpdateNativeMenuAt(location) { |
|
61 var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
|
62 getInterface(Components.interfaces.nsIDOMWindowUtils); |
|
63 try { |
|
64 utils.forceUpdateNativeMenuAt(location); |
|
65 } |
|
66 catch (e) { |
|
67 dump(e + "\n"); |
|
68 } |
|
69 } |
|
70 |
|
71 var executedCommandID = ""; |
|
72 |
|
73 function testItem(location, targetID) { |
|
74 var utils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor). |
|
75 getInterface(Components.interfaces.nsIDOMWindowUtils); |
|
76 var correctCommandHandler = false; |
|
77 try { |
|
78 utils.activateNativeMenuItemAt(location); |
|
79 correctCommandHandler = executedCommandID == targetID; |
|
80 } |
|
81 catch (e) { |
|
82 dump(e + "\n"); |
|
83 } |
|
84 finally { |
|
85 executedCommandID = ""; |
|
86 return correctCommandHandler; |
|
87 } |
|
88 } |
|
89 |
|
90 function createXULMenuPopup() { |
|
91 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; |
|
92 var item = document.createElementNS(XUL_NS, "menupopup"); |
|
93 return item; |
|
94 } |
|
95 |
|
96 function createXULMenu(aLabel) { |
|
97 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; |
|
98 var item = document.createElementNS(XUL_NS, "menu"); |
|
99 item.setAttribute("label", aLabel); |
|
100 return item; |
|
101 } |
|
102 |
|
103 function createXULMenuItem(aLabel, aCommandId) { |
|
104 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; |
|
105 var item = document.createElementNS(XUL_NS, "menuitem"); |
|
106 item.setAttribute("label", aLabel); |
|
107 item.setAttribute("command", aCommandId); |
|
108 return item; |
|
109 } |
|
110 |
|
111 function runBaseMenuTests() { |
|
112 forceUpdateNativeMenuAt("0|3"); |
|
113 return testItem("0|0", "cmd_FooItem0") && |
|
114 testItem("0|1", "cmd_FooItem1") && |
|
115 testItem("0|3|0", "cmd_BarItem0") && |
|
116 testItem("0|3|1", "cmd_BarItem1"); |
|
117 } |
|
118 |
|
119 function onLoad() { |
|
120 var _delayedOnLoad = function() { |
|
121 // First let's run the base menu tests. |
|
122 ok(runBaseMenuTests()); |
|
123 |
|
124 // Set up some nodes that we'll use. |
|
125 var menubarNode = document.getElementById("nativemenubar"); |
|
126 var newMenu0 = createXULMenu("NewMenu0"); |
|
127 var newMenu1 = createXULMenu("NewMenu1"); |
|
128 var newMenuPopup0 = createXULMenuPopup(); |
|
129 var newMenuPopup1 = createXULMenuPopup(); |
|
130 var newMenuItem0 = createXULMenuItem("NewMenuItem0", "cmd_NewItem0"); |
|
131 var newMenuItem1 = createXULMenuItem("NewMenuItem1", "cmd_NewItem1"); |
|
132 var newMenuItem2 = createXULMenuItem("NewMenuItem2", "cmd_NewItem2"); |
|
133 var newMenuItem3 = createXULMenuItem("NewMenuItem3", "cmd_NewItem3"); |
|
134 var newMenuItem4 = createXULMenuItem("NewMenuItem4", "cmd_NewItem4"); |
|
135 var newMenuItem5 = createXULMenuItem("NewMenuItem5", "cmd_NewItem5"); |
|
136 |
|
137 // Create another submenu with hierarchy via DOM manipulation. |
|
138 // ****************** |
|
139 // * Foo * NewMenu0 * <- Menu bar |
|
140 // ****************** |
|
141 // **************** |
|
142 // * NewMenuItem0 * <- NewMenu0 submenu |
|
143 // **************** |
|
144 // * NewMenuItem1 * |
|
145 // **************** |
|
146 // * NewMenuItem2 * |
|
147 // ******************************* |
|
148 // * NewMenu1 > * NewMenuItem3 * <- NewMenu1 submenu |
|
149 // ******************************* |
|
150 // * NewMenuItem4 * |
|
151 // **************** |
|
152 // * NewMenuItem5 * |
|
153 // **************** |
|
154 newMenu0.appendChild(newMenuPopup0); |
|
155 newMenuPopup0.appendChild(newMenuItem0); |
|
156 newMenuPopup0.appendChild(newMenuItem1); |
|
157 newMenuPopup0.appendChild(newMenuItem2); |
|
158 newMenuPopup0.appendChild(newMenu1); |
|
159 newMenu1.appendChild(newMenuPopup1); |
|
160 newMenuPopup1.appendChild(newMenuItem3); |
|
161 newMenuPopup1.appendChild(newMenuItem4); |
|
162 newMenuPopup1.appendChild(newMenuItem5); |
|
163 //XXX - we have to append the menu to the top-level of the menu bar |
|
164 // only after constructing it. If we append before construction, it is |
|
165 // invalid because it has no children and we don't validate it if we add |
|
166 // children later. |
|
167 menubarNode.appendChild(newMenu0); |
|
168 forceUpdateNativeMenuAt("1|3"); |
|
169 // Run basic tests again. |
|
170 ok(runBaseMenuTests()); |
|
171 |
|
172 // Error strings. |
|
173 var sa = "Command handler(s) should have activated"; |
|
174 var sna = "Command handler(s) should not have activated"; |
|
175 |
|
176 // Test middle items. |
|
177 ok(testItem("1|1", "cmd_NewItem1"), sa); |
|
178 ok(testItem("1|3|1", "cmd_NewItem4"), sa); |
|
179 |
|
180 // Hide newMenu0. |
|
181 newMenu0.setAttribute("hidden", "true"); |
|
182 ok(runBaseMenuTests(), sa); // the base menu should still be unhidden |
|
183 ok(!testItem("1|0", ""), sna); |
|
184 ok(!testItem("1|1", ""), sna); |
|
185 ok(!testItem("1|2", ""), sna); |
|
186 ok(!testItem("1|3|0", ""), sna); |
|
187 ok(!testItem("1|3|1", ""), sna); |
|
188 ok(!testItem("1|3|2", ""), sna); |
|
189 |
|
190 // Show newMenu0. |
|
191 newMenu0.setAttribute("hidden", "false"); |
|
192 forceUpdateNativeMenuAt("1|3"); |
|
193 ok(runBaseMenuTests(), sa); |
|
194 ok(testItem("1|0", "cmd_NewItem0"), sa); |
|
195 ok(testItem("1|1", "cmd_NewItem1"), sa); |
|
196 ok(testItem("1|2", "cmd_NewItem2"), sa); |
|
197 ok(testItem("1|3|0", "cmd_NewItem3"), sa); |
|
198 ok(testItem("1|3|1", "cmd_NewItem4"), sa); |
|
199 ok(testItem("1|3|2", "cmd_NewItem5"), sa); |
|
200 |
|
201 // Hide items. |
|
202 newMenuItem1.setAttribute("hidden", "true"); |
|
203 newMenuItem4.setAttribute("hidden", "true"); |
|
204 forceUpdateNativeMenuAt("1|2"); |
|
205 ok(runBaseMenuTests(), sa); |
|
206 ok(testItem("1|0", "cmd_NewItem0"), sa); |
|
207 ok(testItem("1|1", "cmd_NewItem2"), sa); |
|
208 ok(!testItem("1|2", ""), sna); |
|
209 ok(testItem("1|2|0", "cmd_NewItem3"), sa); |
|
210 ok(testItem("1|2|1", "cmd_NewItem5"), sa); |
|
211 ok(!testItem("1|2|2", ""), sna); |
|
212 |
|
213 // Show items. |
|
214 newMenuItem1.setAttribute("hidden", "false"); |
|
215 newMenuItem4.setAttribute("hidden", "false"); |
|
216 forceUpdateNativeMenuAt("1|3"); |
|
217 ok(runBaseMenuTests(), sa); |
|
218 ok(testItem("1|0", "cmd_NewItem0"), sa); |
|
219 ok(testItem("1|1", "cmd_NewItem1"), sa); |
|
220 ok(testItem("1|2", "cmd_NewItem2"), sa); |
|
221 ok(testItem("1|3|0", "cmd_NewItem3"), sa); |
|
222 ok(testItem("1|3|1", "cmd_NewItem4"), sa); |
|
223 ok(testItem("1|3|2", "cmd_NewItem5"), sa); |
|
224 |
|
225 // At this point in the tests the state of the menus has been returned |
|
226 // to the originally diagramed state. |
|
227 |
|
228 // Remove menu. |
|
229 menubarNode.removeChild(newMenu0); |
|
230 ok(runBaseMenuTests(), sa); |
|
231 ok(!testItem("1|0", ""), sna); |
|
232 ok(!testItem("1|1", ""), sna); |
|
233 ok(!testItem("1|2", ""), sna); |
|
234 ok(!testItem("1|3|0", ""), sna); |
|
235 ok(!testItem("1|3|1", ""), sna); |
|
236 ok(!testItem("1|3|2", ""), sna); |
|
237 // return state to original diagramed state |
|
238 menubarNode.appendChild(newMenu0); |
|
239 |
|
240 // Test for bug 447042, make sure that adding a menu node with no children |
|
241 // to the menu bar and then adding another menu node with children works. |
|
242 // Menus with no children don't get their native menu items shown and that |
|
243 // caused internal arrays to get out of sync and an append crashed. |
|
244 var tmpMenu0 = createXULMenu("tmpMenu0"); |
|
245 menubarNode.removeChild(newMenu0); |
|
246 menubarNode.appendChild(tmpMenu0); |
|
247 menubarNode.appendChild(newMenu0); |
|
248 forceUpdateNativeMenuAt("1|3"); |
|
249 ok(runBaseMenuTests()); |
|
250 ok(testItem("1|0", "cmd_NewItem0"), sa); |
|
251 ok(testItem("1|1", "cmd_NewItem1"), sa); |
|
252 ok(testItem("1|2", "cmd_NewItem2"), sa); |
|
253 ok(testItem("1|3|0", "cmd_NewItem3"), sa); |
|
254 ok(testItem("1|3|1", "cmd_NewItem4"), sa); |
|
255 ok(testItem("1|3|2", "cmd_NewItem5"), sa); |
|
256 // return state to original diagramed state |
|
257 menubarNode.removeChild(tmpMenu0); |
|
258 delete tmpMenu0; |
|
259 |
|
260 // This test is basically a crash test for bug 433858. |
|
261 newMenuItem1.setAttribute("hidden", "true"); |
|
262 newMenuItem2.setAttribute("hidden", "true"); |
|
263 newMenu1.setAttribute("hidden", "true"); |
|
264 forceUpdateNativeMenuAt("1"); |
|
265 newMenuItem1.setAttribute("hidden", "false"); |
|
266 newMenuItem2.setAttribute("hidden", "false"); |
|
267 newMenu1.setAttribute("hidden", "false"); |
|
268 forceUpdateNativeMenuAt("1"); |
|
269 |
|
270 onTestsFinished(); |
|
271 } |
|
272 |
|
273 setTimeout(_delayedOnLoad, 1000); |
|
274 } |
|
275 |
|
276 ]]></script> |
|
277 </window> |