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

Commit 6dcecd5

Browse files
crisbetohansl
authored andcommitted
fix(menu-bar): unable to close menu when clicking on toolbar (#9428)
* Fixes not being able to close a toolbar menu by clicking on the wrapping toolbar. Works by adding an extra click handler on the toolbar that closes the menu. Note that the same effect could be achieved by removing the `z-index` altogether, but that could break the functionality that allows users to jump from one menu to the next without clicking. * Moves the menu bar's z-index to CSS so it's easier to manage. * Adds call to `disableOpenOnHover` when the scope is destroyed, in order to clean up leftover event handlers. Fixes #8965.
1 parent ef0c714 commit 6dcecd5

File tree

3 files changed

+68
-19
lines changed

3 files changed

+68
-19
lines changed

src/components/menuBar/js/menuBarController.js

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ MenuBarController.prototype.init = function() {
6666
}));
6767

6868
$scope.$on('$destroy', function() {
69+
self.disableOpenOnHover();
6970
while (deregisterFns.length) {
7071
deregisterFns.shift()();
7172
}
@@ -82,17 +83,23 @@ MenuBarController.prototype.setKeyboardMode = function(enabled) {
8283

8384
MenuBarController.prototype.enableOpenOnHover = function() {
8485
if (this.openOnHoverEnabled) return;
85-
this.openOnHoverEnabled = true;
8686

87-
var parentToolbar;
88-
if (parentToolbar = this.parentToolbar) {
89-
parentToolbar.dataset.mdRestoreStyle = parentToolbar.getAttribute('style');
90-
parentToolbar.style.position = 'relative';
91-
parentToolbar.style.zIndex = 100;
87+
var self = this;
88+
89+
self.openOnHoverEnabled = true;
90+
91+
if (self.parentToolbar) {
92+
self.parentToolbar.classList.add('md-has-open-menu');
93+
94+
// Needs to be on the next tick so it doesn't close immediately.
95+
self.$mdUtil.nextTick(function() {
96+
angular.element(self.parentToolbar).on('click', self.handleParentClick);
97+
}, false);
9298
}
99+
93100
angular
94-
.element(this.getMenus())
95-
.on('mouseenter', this.handleMenuHover);
101+
.element(self.getMenus())
102+
.on('mouseenter', self.handleMenuHover);
96103
};
97104

98105
MenuBarController.prototype.handleMenuHover = function(e) {
@@ -102,14 +109,16 @@ MenuBarController.prototype.handleMenuHover = function(e) {
102109
}
103110
};
104111

105-
106112
MenuBarController.prototype.disableOpenOnHover = function() {
107113
if (!this.openOnHoverEnabled) return;
114+
108115
this.openOnHoverEnabled = false;
109-
var parentToolbar;
110-
if (parentToolbar = this.parentToolbar) {
111-
parentToolbar.style.cssText = parentToolbar.dataset.mdRestoreStyle || '';
116+
117+
if (this.parentToolbar) {
118+
this.parentToolbar.classList.remove('md-has-open-menu');
119+
angular.element(this.parentToolbar).off('click', this.handleParentClick);
112120
}
121+
113122
angular
114123
.element(this.getMenus())
115124
.off('mouseenter', this.handleMenuHover);
@@ -226,7 +235,6 @@ MenuBarController.prototype.getFocusedMenuIndex = function() {
226235

227236
var focusedIndex = this.getMenus().indexOf(focusedEl);
228237
return focusedIndex;
229-
230238
};
231239

232240
MenuBarController.prototype.getOpenMenuIndex = function() {
@@ -237,7 +245,13 @@ MenuBarController.prototype.getOpenMenuIndex = function() {
237245
return -1;
238246
};
239247

248+
MenuBarController.prototype.handleParentClick = function(event) {
249+
var openMenu = this.querySelector('md-menu.md-open');
240250

251+
if (openMenu && !openMenu.contains(event.target)) {
252+
angular.element(openMenu).controller('mdMenu').close();
253+
}
254+
};
241255

242256

243257

src/components/menuBar/menu-bar.scss

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
1-
md-toolbar.md-menu-toolbar {
2-
h2.md-toolbar-tools {
3-
line-height: 1rem;
4-
height: auto;
5-
padding: 3.5 * $baseline-grid;
6-
padding-bottom: 1.5 * $baseline-grid;
1+
md-toolbar {
2+
&.md-menu-toolbar {
3+
h2.md-toolbar-tools {
4+
line-height: 1rem;
5+
height: auto;
6+
padding: 3.5 * $baseline-grid;
7+
padding-bottom: 1.5 * $baseline-grid;
8+
}
9+
}
10+
11+
// Used to allow hovering from one menu to the
12+
// next when inside of a toolbar.
13+
&.md-has-open-menu {
14+
position: relative;
15+
z-index: $z-index-menu;
716
}
817
}
918

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,32 @@ describe('material.components.menuBar', function() {
2525
expect(nestedMenu.getAttribute('md-position-mode')).toBe('left bottom');
2626
});
2727

28+
it('should close when clicking on the wrapping toolbar', inject(function($compile, $rootScope, $timeout) {
29+
var ctrl = null;
30+
var toolbar = $compile(
31+
'<md-toolbar>' +
32+
'<md-menu-bar>' +
33+
'<md-menu ng-repeat="i in [1, 2, 3]">' +
34+
'<button ng-click></button>' +
35+
'<md-menu-content></md-menu-content>' +
36+
'</md-menu>' +
37+
'</md-menu-bar>' +
38+
'</md-toolbar>'
39+
)($rootScope);
40+
41+
$rootScope.$digest();
42+
ctrl = toolbar.find('md-menu-bar').controller('mdMenuBar');
43+
44+
toolbar.find('md-menu').eq(0).controller('mdMenu').open();
45+
$timeout.flush();
46+
47+
expect(toolbar).toHaveClass('md-has-open-menu');
48+
toolbar.triggerHandler('click');
49+
50+
expect(toolbar).not.toHaveClass('md-has-open-menu');
51+
expect(ctrl.getOpenMenuIndex()).toBe(-1);
52+
}));
53+
2854
describe('ARIA', function() {
2955

3056
it('sets role="menubar" on the menubar', function() {

0 commit comments

Comments
 (0)