Unselect the MenuItem in the top level MenuBar when auto-hiding a child MenuBar.
http://gwt-code-reviews.appspot.com/141804
Issue: 2458
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7556 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/MenuBar.java b/user/src/com/google/gwt/user/client/ui/MenuBar.java
index 72b373f..22c0e57 100644
--- a/user/src/com/google/gwt/user/client/ui/MenuBar.java
+++ b/user/src/com/google/gwt/user/client/ui/MenuBar.java
@@ -17,6 +17,8 @@
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.EventTarget;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
@@ -534,7 +536,7 @@
} else if ((parentMenu != null) && parentMenu.vertical) {
parentMenu.selectPrevItem();
} else {
- close();
+ close(true);
}
}
@@ -598,14 +600,12 @@
eatEvent(event);
break;
case KeyCodes.KEY_ESCAPE:
- closeAllParents();
- // Ensure the popup is closed even if it has not been enetered
- // with the mouse or key navigation
- if (parentMenu == null && popup != null) {
- popup.hide();
- }
+ closeAllParentsAndChildren();
eatEvent(event);
break;
+ case KeyCodes.KEY_TAB:
+ closeAllParentsAndChildren();
+ break;
case KeyCodes.KEY_ENTER:
if (!selectFirstItemIfNoneSelected()) {
doItemAction(selectedItem, true, true);
@@ -793,10 +793,24 @@
* Closes all parent menu popups.
*/
void closeAllParents() {
- MenuBar curMenu = this;
- while (curMenu.parentMenu != null) {
- curMenu.close();
- curMenu = curMenu.parentMenu;
+ if (parentMenu != null) {
+ // The parent menu will recursively call closeAllParents.
+ close(false);
+ } else {
+ // If this is the top most menu, deselect the current item.
+ selectItem(null);
+ }
+ }
+
+ /**
+ * Closes all parent and child menu popups.
+ */
+ void closeAllParentsAndChildren() {
+ closeAllParents();
+ // Ensure the popup is closed even if it has not been enetered
+ // with the mouse or key navigation
+ if (parentMenu == null && popup != null) {
+ popup.hide();
}
}
@@ -856,6 +870,13 @@
}
}
+ /**
+ * Visible for testing.
+ */
+ PopupPanel getPopup() {
+ return popup;
+ }
+
void itemOver(MenuItem item, boolean focus) {
if (item == null) {
// Don't clear selection if the currently selected item's menu is showing.
@@ -952,11 +973,15 @@
/**
* Closes this menu (if it is a popup).
+ *
+ * @param focus true to move focus to the parent
*/
- private void close() {
+ private void close(boolean focus) {
if (parentMenu != null) {
- parentMenu.popup.hide();
- parentMenu.focus();
+ parentMenu.popup.hide(!focus);
+ if (focus) {
+ parentMenu.focus();
+ }
}
}
@@ -1017,6 +1042,15 @@
// Hide focus outline in IE 6/7
DOM.setElementAttribute(getElement(), "hideFocus", "true");
+
+ // Deselect items when blurring without a child menu.
+ addDomHandler(new BlurHandler() {
+ public void onBlur(BlurEvent event) {
+ if (shownChildMenu == null) {
+ selectItem(null);
+ }
+ }
+ }, BlurEvent.getType());
}
private void moveToNextItem() {
@@ -1055,7 +1089,7 @@
if ((parentMenu != null) && (!parentMenu.vertical)) {
parentMenu.selectPrevItem();
} else {
- close();
+ close(true);
}
}
}
diff --git a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
index aab7b47..3567400 100644
--- a/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
+++ b/user/test/com/google/gwt/user/client/ui/MenuBarTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2008 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,9 +15,11 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.junit.DoNotRunWith;
import com.google.gwt.junit.Platform;
-import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
@@ -26,7 +28,16 @@
/**
* Tests the DockPanel widget.
*/
-public class MenuBarTest extends GWTTestCase {
+public class MenuBarTest extends WidgetTestBase {
+
+ /**
+ * A blank command.
+ */
+ private static final Command BLANK_COMMAND = new Command() {
+ public void execute() {
+ }
+ };
+
@Override
public String getModuleName() {
return "com.google.gwt.user.DebugTest";
@@ -40,16 +51,10 @@
// Create a menu bar
MenuBar bar = new MenuBar(true);
- // Create a blank command
- Command blankCommand = new Command() {
- public void execute() {
- }
- };
-
// Add an item, default to text
- MenuItem item0 = bar.addItem("<b>test</b>", blankCommand);
+ MenuItem item0 = bar.addItem("<b>test</b>", BLANK_COMMAND);
assertEquals("<b>test</b>", item0.getText());
- assertEquals(blankCommand, item0.getCommand());
+ assertEquals(BLANK_COMMAND, item0.getCommand());
assertEquals(bar, item0.getParentMenu());
// Add a separator
@@ -57,9 +62,9 @@
assertEquals(bar, separator0.getParentMenu());
// Add another item, force to html
- MenuItem item1 = bar.addItem("<b>test1</b>", true, blankCommand);
+ MenuItem item1 = bar.addItem("<b>test1</b>", true, BLANK_COMMAND);
assertEquals("test1", item1.getText());
- assertEquals(blankCommand, item1.getCommand());
+ assertEquals(BLANK_COMMAND, item1.getCommand());
assertEquals(bar, item1.getParentMenu());
// Get all items
@@ -78,11 +83,11 @@
assertNull(separator0.getParentMenu());
// Add a bunch of items and clear them all
- MenuItem item2 = bar.addItem("test2", true, blankCommand);
+ MenuItem item2 = bar.addItem("test2", true, BLANK_COMMAND);
MenuItemSeparator separator1 = bar.addSeparator();
- MenuItem item3 = bar.addItem("test3", true, blankCommand);
+ MenuItem item3 = bar.addItem("test3", true, BLANK_COMMAND);
MenuItemSeparator separator2 = bar.addSeparator();
- MenuItem item4 = bar.addItem("test4", true, blankCommand);
+ MenuItem item4 = bar.addItem("test4", true, BLANK_COMMAND);
MenuItemSeparator separator3 = bar.addSeparator();
bar.clearItems();
assertEquals(0, bar.getItems().size());
@@ -94,6 +99,83 @@
assertNull(separator3.getParentMenu());
}
+ public void testAutoHideChildMenuPopup() {
+ // Create a menu bar with children.
+ MenuBar l0 = new MenuBar();
+ l0.setAutoOpen(true);
+ MenuBar l1 = new MenuBar();
+ l1.setAutoOpen(true);
+ MenuBar l2 = new MenuBar();
+ l2.setAutoOpen(true);
+ MenuItem item2 = l2.addItem("l2", BLANK_COMMAND);
+ MenuItem item1 = l1.addItem("l1", l2);
+ MenuItem item0 = l0.addItem("l0", l1);
+ RootPanel.get().add(l0);
+
+ // Open l2.
+ l0.itemOver(item0, true);
+ l1.itemOver(item1, true);
+ l2.itemOver(item2, true);
+ assertTrue(l0.getPopup().isShowing());
+ assertEquals(item0, l0.getSelectedItem());
+ assertTrue(l1.getPopup().isShowing());
+ assertEquals(item1, l1.getSelectedItem());
+
+ // Auto-hide the child popup.
+ l1.getPopup().hide(true);
+ assertNull(l0.getPopup());
+ assertNull(l0.getSelectedItem());
+ assertNull(l1.getPopup());
+ }
+
+ public void testBlur() {
+ // Create a menu bar with children.
+ final MenuBar menu = new MenuBar();
+ MenuItem item0 = menu.addItem("item0", BLANK_COMMAND);
+ RootPanel.get().add(menu);
+
+ // Select the item.
+ menu.focus();
+ menu.selectItem(item0);
+ assertEquals(item0, menu.getSelectedItem());
+
+ // Blur the menu bar.
+ NativeEvent event = Document.get().createBlurEvent();
+ menu.getElement().dispatchEvent(event);
+ assertNull(menu.getSelectedItem());
+ }
+
+ public void testEscapeKey() {
+ // Create a menu bar with children.
+ MenuBar l0 = new MenuBar();
+ l0.setAutoOpen(true);
+ MenuBar l1 = new MenuBar();
+ l1.setAutoOpen(true);
+ MenuBar l2 = new MenuBar();
+ l2.setAutoOpen(true);
+ MenuItem item2 = l2.addItem("l2", BLANK_COMMAND);
+ MenuItem item1 = l1.addItem("l1", l2);
+ MenuItem item0 = l0.addItem("l0", l1);
+ RootPanel.get().add(l0);
+
+ // Open l2.
+ l0.itemOver(item0, true);
+ l1.itemOver(item1, true);
+ l2.itemOver(item2, true);
+ assertTrue(l0.getPopup().isShowing());
+ assertEquals(item0, l0.getSelectedItem());
+ assertTrue(l1.getPopup().isShowing());
+ assertEquals(item1, l1.getSelectedItem());
+
+ // Escape from the menu.
+ NativeEvent event = Document.get().createKeyDownEvent(false, false, false,
+ false, KeyCodes.KEY_ESCAPE, KeyCodes.KEY_ESCAPE);
+ l1.getElement().dispatchEvent(event);
+ assertNull(l0.getPopup());
+ assertNull(l0.getSelectedItem());
+ assertNull(l1.getPopup());
+ }
+
/**
* Test inserting {@link MenuItem}s and {@link MenuItemSeparator}s into the
* menu.
@@ -102,23 +184,17 @@
// Create a menu bar
MenuBar bar = new MenuBar(true);
- // Create a blank command
- Command blankCommand = new Command() {
- public void execute() {
- }
- };
-
// Insert first item
- MenuItem item0 = bar.insertItem(new MenuItem("test", blankCommand), 0);
+ MenuItem item0 = bar.insertItem(new MenuItem("test", BLANK_COMMAND), 0);
assertEquals(bar.getItemIndex(item0), 0);
// Insert item at 0
- MenuItem item1 = bar.insertItem(new MenuItem("test", blankCommand), 0);
+ MenuItem item1 = bar.insertItem(new MenuItem("test", BLANK_COMMAND), 0);
assertEquals(bar.getItemIndex(item1), 0);
assertEquals(bar.getItemIndex(item0), 1);
// Insert item at end
- MenuItem item2 = bar.insertItem(new MenuItem("test", blankCommand), 2);
+ MenuItem item2 = bar.insertItem(new MenuItem("test", BLANK_COMMAND), 2);
assertEquals(bar.getItemIndex(item1), 0);
assertEquals(bar.getItemIndex(item0), 1);
assertEquals(bar.getItemIndex(item2), 2);
@@ -156,20 +232,14 @@
// Create a menu bar
MenuBar bar = new MenuBar(true);
- // Create a blank command
- Command blankCommand = new Command() {
- public void execute() {
- }
- };
-
// Add some items to the menu
for (int i = 0; i < 3; i++) {
- bar.addItem("item", blankCommand);
+ bar.addItem("item", BLANK_COMMAND);
}
// Add an item at a negative index
try {
- bar.insertItem(new MenuItem("test", blankCommand), -1);
+ bar.insertItem(new MenuItem("test", BLANK_COMMAND), -1);
fail("Expected IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException e) {
// Expected exception
@@ -177,7 +247,7 @@
// Add an item at a high index
try {
- bar.insertItem(new MenuItem("test", blankCommand), 4);
+ bar.insertItem(new MenuItem("test", BLANK_COMMAND), 4);
fail("Expected IndexOutOfBoundsException");
} catch (IndexOutOfBoundsException e) {
// Expected exception
@@ -185,15 +255,10 @@
}
public void testSelectItem() {
- Command emptyCommand = new Command() {
- public void execute() {
- }
- };
-
MenuBar bar = new MenuBar(false);
- MenuItem item1 = new MenuItem("item1", emptyCommand);
- MenuItem item2 = new MenuItem("item2", emptyCommand);
- MenuItem item3 = new MenuItem("item3", emptyCommand);
+ MenuItem item1 = new MenuItem("item1", BLANK_COMMAND);
+ MenuItem item2 = new MenuItem("item2", BLANK_COMMAND);
+ MenuItem item3 = new MenuItem("item3", BLANK_COMMAND);
bar.addItem(item1);
bar.addItem(item2);
bar.addItem(item3);
@@ -209,23 +274,18 @@
@DoNotRunWith({Platform.HtmlUnit})
public void testDebugId() {
- Command emptyCommand = new Command() {
- public void execute() {
- }
- };
-
// Create a sub menu
MenuBar subMenu = new MenuBar(true);
- subMenu.addItem("sub0", emptyCommand);
- subMenu.addItem("sub1", emptyCommand);
- subMenu.addItem("sub2", emptyCommand);
+ subMenu.addItem("sub0", BLANK_COMMAND);
+ subMenu.addItem("sub1", BLANK_COMMAND);
+ subMenu.addItem("sub2", BLANK_COMMAND);
// Create a menu bar
MenuBar bar = new MenuBar(false);
bar.setAnimationEnabled(false);
bar.setAutoOpen(true);
- bar.addItem("top0", emptyCommand);
- bar.addItem("top1", emptyCommand);
+ bar.addItem("top0", BLANK_COMMAND);
+ bar.addItem("top1", BLANK_COMMAND);
MenuItem top2 = bar.addItem("top2", subMenu);
RootPanel.get().add(bar);
@@ -258,16 +318,10 @@
// Create a menu bar
MenuBar bar = new MenuBar(true);
- // Create a blank command
- Command blankCommand = new Command() {
- public void execute() {
- }
- };
-
// Add some items
- MenuItem item1 = bar.addItem("item1", blankCommand);
- MenuItem item2 = bar.addItem("item2", blankCommand);
- MenuItem item3 = bar.addItem("item3", blankCommand);
+ MenuItem item1 = bar.addItem("item1", BLANK_COMMAND);
+ MenuItem item2 = bar.addItem("item2", BLANK_COMMAND);
+ MenuItem item3 = bar.addItem("item3", BLANK_COMMAND);
// Test setting the selected item
assertNull(bar.getSelectedItem());
@@ -288,4 +342,35 @@
bar.clearItems();
assertNull(bar.getSelectedItem());
}
+
+ public void testTabKey() {
+ // Create a menu bar with children.
+ MenuBar l0 = new MenuBar();
+ l0.setAutoOpen(true);
+ MenuBar l1 = new MenuBar();
+ l1.setAutoOpen(true);
+ MenuBar l2 = new MenuBar();
+ l2.setAutoOpen(true);
+ MenuItem item2 = l2.addItem("l2", BLANK_COMMAND);
+ MenuItem item1 = l1.addItem("l1", l2);
+ MenuItem item0 = l0.addItem("l0", l1);
+ RootPanel.get().add(l0);
+
+ // Open l2.
+ l0.itemOver(item0, true);
+ l1.itemOver(item1, true);
+ l2.itemOver(item2, true);
+ assertTrue(l0.getPopup().isShowing());
+ assertEquals(item0, l0.getSelectedItem());
+ assertTrue(l1.getPopup().isShowing());
+ assertEquals(item1, l1.getSelectedItem());
+
+ // Tab away from the menu.
+ NativeEvent event = Document.get().createKeyDownEvent(false, false, false,
+ false, KeyCodes.KEY_TAB, KeyCodes.KEY_TAB);
+ l1.getElement().dispatchEvent(event);
+ assertNull(l0.getPopup());
+ assertNull(l0.getSelectedItem());
+ assertNull(l1.getPopup());
+ }
}