@@ -15,7 +15,7 @@ import {
1515import { MenuPositionX , MenuPositionY } from './menu-positions' ;
1616import { MdMenuInvalidPositionX , MdMenuInvalidPositionY } from './menu-errors' ;
1717import { MdMenuItem } from './menu-item' ;
18- import { UP_ARROW , DOWN_ARROW , TAB } from '../core' ;
18+ import { ListKeyManager } from '../core/keyboard/ListKeyManager ' ;
1919
2020@Component ( {
2121 moduleId : module . id ,
@@ -27,7 +27,7 @@ import {UP_ARROW, DOWN_ARROW, TAB} from '../core';
2727 exportAs : 'mdMenu'
2828} )
2929export class MdMenu {
30- private _focusedItemIndex : number = 0 ;
30+ private _keyManager : ListKeyManager ;
3131
3232 // config object to be passed into the menu's ngClass
3333 _classList : Object ;
@@ -44,6 +44,11 @@ export class MdMenu {
4444 if ( posY ) { this . _setPositionY ( posY ) ; }
4545 }
4646
47+ ngAfterContentInit ( ) {
48+ this . _keyManager = new ListKeyManager ( this . items ) ;
49+ this . _keyManager . tabOut . subscribe ( ( ) => this . _emitCloseEvent ( ) ) ;
50+ }
51+
4752 /**
4853 * This method takes classes set on the host md-menu element and applies them on the
4954 * menu template that displays in the overlay container. Otherwise, it's difficult
@@ -67,61 +72,16 @@ export class MdMenu {
6772 */
6873 _focusFirstItem ( ) {
6974 this . items . first . focus ( ) ;
75+ this . _keyManager . focusedItemIndex = 0 ;
7076 }
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-
8477 /**
8578 * This emits a close event to which the trigger is subscribed. When emitted, the
8679 * trigger will close the menu.
8780 */
8881 private _emitCloseEvent ( ) : void {
89- this . _focusedItemIndex = 0 ;
9082 this . close . emit ( null ) ;
9183 }
9284
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-
12585 private _setPositionX ( pos : MenuPositionX ) : void {
12686 if ( pos !== 'before' && pos !== 'after' ) {
12787 throw new MdMenuInvalidPositionX ( ) ;
0 commit comments