Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit b58343c

Browse files
topherfangioThomasBurleson
authored andcommitted
fix(menuBar): Fix hovering consecutive nested menus.
Fix issue where hovering two consecutive nested menus would not properly open the second nested menu. Also adds a test and fixes an issue where the focusMenu() method of the menu bar controller would not focus the first menu if none was already selected. Fixes #6685. Closes #7361
1 parent cb864d5 commit b58343c

File tree

3 files changed

+114
-3
lines changed

3 files changed

+114
-3
lines changed

src/components/menu/js/menuController.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ function MenuController($mdMenu, $attrs, $element, $scope, $mdUtil, $timeout, $r
8787
if (self.currentlyOpenMenu && self.currentlyOpenMenu != nestedMenu) {
8888
var closeTo = self.nestLevel + 1;
8989
self.currentlyOpenMenu.close(true, { closeTo: closeTo });
90+
self.isAlreadyOpening = true;
91+
nestedMenu.open();
9092
} else if (nestedMenu && !nestedMenu.isOpen && nestedMenu.open) {
9193
self.isAlreadyOpening = true;
9294
nestedMenu.open();

src/components/menuBar/js/menuBarController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ MenuBarController.prototype.focusMenu = function(direction) {
187187

188188
var changed = false;
189189

190-
if (focusedIndex == -1) { focusedIndex = 0; }
190+
if (focusedIndex == -1) { focusedIndex = 0; changed = true; }
191191
else if (
192192
direction < 0 && focusedIndex > 0 ||
193193
direction > 0 && focusedIndex < menus.length - direction

src/components/menuBar/menu-bar.spec.js

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe('material.components.menuBar', function() {
1515
it('sets md-position-mode to "bottom left" on nested menus', function() {
1616
var menuBar = setup();
1717
var nestedMenu = menuBar[0].querySelector('md-menu');
18+
1819
expect(nestedMenu.getAttribute('md-position-mode')).toBe('left bottom');
1920
});
2021

@@ -25,6 +26,92 @@ describe('material.components.menuBar', function() {
2526
expect(ariaRole).toBe('menubar');
2627
});
2728
});
29+
30+
describe('nested menus', function() {
31+
var menuBar, menus, subMenuOpen, ctrl;
32+
33+
it('opens consecutive nested menus', function() {
34+
menuBar = setup();
35+
ctrl = menuBar.controller('mdMenuBar');
36+
menus = menuBar[0].querySelectorAll('md-menu md-menu');
37+
38+
angular.element(document.body).append(menuBar);
39+
40+
// Open the menu-bar menu
41+
ctrl.focusMenu(1);
42+
ctrl.openFocusedMenu();
43+
waitForMenuOpen();
44+
45+
// Open the first nested menu
46+
openSubMenu(0);
47+
waitForMenuOpen();
48+
expect(getOpenSubMenu().text().trim()).toBe('Sub 1 - Content');
49+
50+
// Open the second nested menu, the first menu should close
51+
openSubMenu(1);
52+
waitForMenuClose();
53+
54+
// Then the second menu should become visible
55+
waitForMenuOpen();
56+
expect(getOpenSubMenu().text().trim()).toBe('Sub 2 - Content');
57+
58+
menuBar.remove();
59+
});
60+
61+
function openSubMenu(index) {
62+
// If a menu is already open, trigger the mouse leave to close it
63+
if (subMenuOpen) {
64+
subMenuOpen.triggerHandler({
65+
type: 'mouseleave',
66+
target: subMenuOpen[0],
67+
currentTarget: subMenuOpen[0]
68+
});
69+
}
70+
71+
// Set the currently open sub-menu and trigger the mouse enter
72+
subMenuOpen = angular.element(menus[index]);
73+
subMenuOpen.triggerHandler({
74+
type: 'mouseenter',
75+
target: subMenuOpen[0],
76+
currentTarget: subMenuOpen[0]
77+
});
78+
}
79+
80+
function getOpenSubMenu() {
81+
debugger;
82+
var containers = document.body.querySelectorAll('._md-open-menu-container._md-active');
83+
var lastContainer = containers.item(containers.length - 1);
84+
85+
return angular.element(lastContainer.querySelector('md-menu-content'));
86+
}
87+
88+
function setup(){
89+
var el;
90+
inject(function($compile, $rootScope) {
91+
el = $compile([
92+
'<md-menu-bar>',
93+
' <md-menu>',
94+
' <md-menu-item>',
95+
' <button ng-click="clicked=true">Button {{i}}</button>',
96+
' </md-menu-item>',
97+
' <md-menu-content class="test-submenu">',
98+
' <md-menu ng-repeat="i in [1, 2]">',
99+
' <md-menu-item>',
100+
' <button ng-click="subclicked=true">Sub Button{{i}}</button>',
101+
' </md-menu-item>',
102+
' <md-menu-content>Sub {{i}} - Content</md-menu-content>',
103+
' </md-menu>',
104+
' </md-menu-content>',
105+
' </md-menu>',
106+
'</md-menu-bar>'
107+
].join(''))($rootScope);
108+
$rootScope.$digest();
109+
});
110+
attachedMenuElements.push(el);
111+
112+
return el;
113+
}
114+
});
28115
});
29116

30117
describe('MenuBarCtrl', function() {
@@ -64,6 +151,13 @@ describe('material.components.menuBar', function() {
64151
describe('#focusMenu', function() {
65152
var focused;
66153
beforeEach(function() { focused = false; });
154+
it('focuses the first menu if none is focused', function() {
155+
var menus = mockButtonAtIndex(0);
156+
spyOn(ctrl, 'getFocusedMenuIndex').and.returnValue(-1);
157+
spyOn(ctrl, 'getMenus').and.returnValue(menus);
158+
ctrl.focusMenu(1);
159+
expect(focused).toBe(true);
160+
});
67161
it('focuses the next menu', function() {
68162
var menus = mockButtonAtIndex(1);
69163
spyOn(ctrl, 'getFocusedMenuIndex').and.returnValue(0);
@@ -100,13 +194,16 @@ describe('material.components.menuBar', function() {
100194
var mockButton = {
101195
querySelector: function() { return {
102196
focus: function() { focused = true; }
103-
}; }
197+
}; },
198+
199+
// TODO: This may need to become more complex if more of the tests use it
200+
classList: { contains: function() { return false; } }
104201
};
105202
for (var i = 0; i < 3; ++i) {
106203
if (i == index) {
107204
result.push(mockButton);
108205
} else {
109-
result.push({});
206+
result.push({ classList: mockButton.classList });
110207
}
111208
}
112209
return result;
@@ -307,5 +404,17 @@ describe('material.components.menuBar', function() {
307404
}
308405
});
309406
});
407+
408+
function waitForMenuOpen() {
409+
inject(function($material) {
410+
$material.flushInterimElement();
411+
});
412+
}
413+
414+
function waitForMenuClose() {
415+
inject(function($material) {
416+
$material.flushInterimElement();
417+
});
418+
}
310419
});
311420

0 commit comments

Comments
 (0)