@@ -15,7 +15,7 @@ import {
15
15
import { MenuPositionX , MenuPositionY } from './menu-positions' ;
16
16
import { MdMenuInvalidPositionX , MdMenuInvalidPositionY } from './menu-errors' ;
17
17
import { MdMenuItem } from './menu-item' ;
18
- import { UP_ARROW , DOWN_ARROW , TAB } from '../core' ;
18
+ import { ListKeyManager } from '../core/keyboard/ListKeyManager ' ;
19
19
20
20
@Component ( {
21
21
moduleId : module . id ,
@@ -27,7 +27,7 @@ import {UP_ARROW, DOWN_ARROW, TAB} from '../core';
27
27
exportAs : 'mdMenu'
28
28
} )
29
29
export class MdMenu {
30
- private _focusedItemIndex : number = 0 ;
30
+ private _keyManager : ListKeyManager ;
31
31
32
32
// config object to be passed into the menu's ngClass
33
33
_classList : Object ;
@@ -44,6 +44,11 @@ export class MdMenu {
44
44
if ( posY ) { this . _setPositionY ( posY ) ; }
45
45
}
46
46
47
+ ngAfterContentInit ( ) {
48
+ this . _keyManager = new ListKeyManager ( this . items ) ;
49
+ this . _keyManager . tabOut . subscribe ( ( ) => this . _emitCloseEvent ( ) ) ;
50
+ }
51
+
47
52
/**
48
53
* This method takes classes set on the host md-menu element and applies them on the
49
54
* menu template that displays in the overlay container. Otherwise, it's difficult
@@ -67,61 +72,16 @@ export class MdMenu {
67
72
*/
68
73
_focusFirstItem ( ) {
69
74
this . items . first . focus ( ) ;
75
+ this . _keyManager . focusedItemIndex = 0 ;
70
76
}
71
-
72
- // TODO(kara): update this when (keydown.downArrow) testability is fixed
73
- // TODO: internal
74
- _handleKeydown ( event : KeyboardEvent ) : void {
75
- if ( event . keyCode === DOWN_ARROW ) {
76
- this . _focusNextItem ( ) ;
77
- } else if ( event . keyCode === UP_ARROW ) {
78
- this . _focusPreviousItem ( ) ;
79
- } else if ( event . keyCode === TAB ) {
80
- this . _emitCloseEvent ( ) ;
81
- }
82
- }
83
-
84
77
/**
85
78
* This emits a close event to which the trigger is subscribed. When emitted, the
86
79
* trigger will close the menu.
87
80
*/
88
81
private _emitCloseEvent ( ) : void {
89
- this . _focusedItemIndex = 0 ;
90
82
this . close . emit ( null ) ;
91
83
}
92
84
93
- private _focusNextItem ( ) : void {
94
- this . _updateFocusedItemIndex ( 1 ) ;
95
- this . items . toArray ( ) [ this . _focusedItemIndex ] . focus ( ) ;
96
- }
97
-
98
- private _focusPreviousItem ( ) : void {
99
- this . _updateFocusedItemIndex ( - 1 ) ;
100
- this . items . toArray ( ) [ this . _focusedItemIndex ] . focus ( ) ;
101
- }
102
-
103
- /**
104
- * This method sets focus to the correct menu item, given a list of menu items and the delta
105
- * between the currently focused menu item and the new menu item to be focused. It will
106
- * continue to move down the list until it finds an item that is not disabled, and it will wrap
107
- * if it encounters either end of the menu.
108
- *
109
- * @param delta the desired change in focus index
110
- * @param menuItems the menu items that should be focused
111
- * @private
112
- */
113
- private _updateFocusedItemIndex ( delta : number , menuItems : MdMenuItem [ ] = this . items . toArray ( ) ) {
114
- // when focus would leave menu, wrap to beginning or end
115
- this . _focusedItemIndex = ( this . _focusedItemIndex + delta + this . items . length )
116
- % this . items . length ;
117
-
118
- // skip all disabled menu items recursively until an active one
119
- // is reached or the menu closes for overreaching bounds
120
- while ( menuItems [ this . _focusedItemIndex ] . disabled ) {
121
- this . _updateFocusedItemIndex ( delta , menuItems ) ;
122
- }
123
- }
124
-
125
85
private _setPositionX ( pos : MenuPositionX ) : void {
126
86
if ( pos !== 'before' && pos !== 'after' ) {
127
87
throw new MdMenuInvalidPositionX ( ) ;
0 commit comments