Skip to content

Commit 210e57c

Browse files
jelbourntinayuangao
authored andcommitted
fix(menu): close menu panel on escape (#4666)
Fixes to #3601
1 parent fa5b427 commit 210e57c

File tree

3 files changed

+40
-13
lines changed

3 files changed

+40
-13
lines changed

src/lib/menu/menu-directive.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import {FocusKeyManager} from '../core/a11y/focus-key-manager';
2020
import {MdMenuPanel} from './menu-panel';
2121
import {Subscription} from 'rxjs/Subscription';
2222
import {transformMenu, fadeInItems} from './menu-animations';
23+
import {ESCAPE} from '../core/keyboard/keycodes';
24+
2325

2426
@Component({
2527
moduleId: module.id,
@@ -75,17 +77,6 @@ export class MdMenu implements AfterContentInit, MdMenuPanel, OnDestroy {
7577
/** Whether the menu should overlap its trigger. */
7678
@Input() overlapTrigger = true;
7779

78-
ngAfterContentInit() {
79-
this._keyManager = new FocusKeyManager(this.items).withWrap();
80-
this._tabSubscription = this._keyManager.tabOut.subscribe(() => this._emitCloseEvent());
81-
}
82-
83-
ngOnDestroy() {
84-
if (this._tabSubscription) {
85-
this._tabSubscription.unsubscribe();
86-
}
87-
}
88-
8980
/**
9081
* This method takes classes set on the host md-menu element and applies them on the
9182
* menu template that displays in the overlay container. Otherwise, it's difficult
@@ -104,6 +95,28 @@ export class MdMenu implements AfterContentInit, MdMenuPanel, OnDestroy {
10495
/** Event emitted when the menu is closed. */
10596
@Output() close = new EventEmitter<void>();
10697

98+
ngAfterContentInit() {
99+
this._keyManager = new FocusKeyManager(this.items).withWrap();
100+
this._tabSubscription = this._keyManager.tabOut.subscribe(() => this._emitCloseEvent());
101+
}
102+
103+
ngOnDestroy() {
104+
if (this._tabSubscription) {
105+
this._tabSubscription.unsubscribe();
106+
}
107+
}
108+
109+
/** Handle a keyboard event from the menu, delegating to the appropriate action. */
110+
_handleKeydown(event: KeyboardEvent) {
111+
switch (event.keyCode) {
112+
case ESCAPE:
113+
this._emitCloseEvent();
114+
return;
115+
default:
116+
this._keyManager.onKeydown(event);
117+
}
118+
}
119+
107120
/**
108121
* Focus the first item in the menu. This method is used by the menu trigger
109122
* to focus the first item when the menu is opened by the ENTER key.

src/lib/menu/menu.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<ng-template>
2-
<div class="mat-menu-panel" [ngClass]="_classList" (keydown)="_keyManager.onKeydown($event)"
2+
<div class="mat-menu-panel" [ngClass]="_classList" (keydown)="_handleKeydown($event)"
33
(click)="_emitCloseEvent()" [@transformMenu]="'showing'">
44
<div class="mat-menu-content" [@fadeInItems]="'showing'">
55
<ng-content></ng-content>

src/lib/menu/menu.spec.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ import {
1818
MenuPositionY
1919
} from './index';
2020
import {OverlayContainer} from '../core/overlay/overlay-container';
21-
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
2221
import {Dir, LayoutDirection} from '../core/rtl/dir';
2322
import {extendObject} from '../core/util/object-extend';
23+
import {ESCAPE} from '../core/keyboard/keycodes';
24+
import {dispatchKeyboardEvent} from '../core/testing/dispatch-events';
25+
2426

2527
describe('MdMenu', () => {
2628
let overlayContainerElement: HTMLElement;
@@ -80,6 +82,18 @@ describe('MdMenu', () => {
8082
expect(overlayContainerElement.textContent).toBe('');
8183
});
8284

85+
it('should close the menu when pressing escape', () => {
86+
const fixture = TestBed.createComponent(SimpleMenu);
87+
fixture.detectChanges();
88+
fixture.componentInstance.trigger.openMenu();
89+
90+
const panel = overlayContainerElement.querySelector('.mat-menu-panel');
91+
dispatchKeyboardEvent(panel, 'keydown', ESCAPE);
92+
fixture.detectChanges();
93+
94+
expect(overlayContainerElement.textContent).toBe('');
95+
});
96+
8397
it('should open a custom menu', () => {
8498
const fixture = TestBed.createComponent(CustomMenu);
8599
fixture.detectChanges();

0 commit comments

Comments
 (0)