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

Commit 1f32ccb

Browse files
clshortfusejelbourn
authored andcommitted
fix(menu): focus first non disabled item (#9228)
Previously, menu would attempt to focus first item. If the item was disabled, no attempts were made to seek another focusable item. * Iterate through menu items until it finds a non-disabled item * Add more menu items to autofocus spec tests Fixes #9165
1 parent 5cdceeb commit 1f32ccb

File tree

3 files changed

+66
-5
lines changed

3 files changed

+66
-5
lines changed

src/components/menu/js/menuController.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ function MenuController($mdMenu, $attrs, $element, $scope, $mdUtil, $timeout, $r
162162
var focusTarget = menuContainer[0]
163163
.querySelector(prefixer.buildSelector(['md-menu-focus-target', 'md-autofocus']));
164164

165-
if (!focusTarget) focusTarget = menuContainer[0].querySelector('.md-button');
165+
if (!focusTarget) focusTarget = menuContainer[0].querySelector('.md-button:not([disabled])');
166166
focusTarget.focus();
167167
};
168168

src/components/menu/js/menuServiceProvider.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,23 @@ function MenuProvider($$interimElementProvider) {
210210
opts.menuContentEl.on('keydown', onMenuKeyDown);
211211
opts.menuContentEl[0].addEventListener('click', captureClickListener, true);
212212

213-
// kick off initial focus in the menu on the first element
213+
// kick off initial focus in the menu on the first enabled element
214214
var focusTarget = opts.menuContentEl[0]
215215
.querySelector(prefixer.buildSelector(['md-menu-focus-target', 'md-autofocus']));
216216

217217
if ( !focusTarget ) {
218-
var firstChild = opts.menuContentEl[0].firstElementChild;
219-
220-
focusTarget = firstChild && (firstChild.querySelector('.md-button:not([disabled])') || firstChild.firstElementChild);
218+
var childrenLen = opts.menuContentEl[0].children.length;
219+
for(var childIndex = 0; childIndex < childrenLen; childIndex++) {
220+
var child = opts.menuContentEl[0].children[childIndex];
221+
focusTarget = child.querySelector('.md-button:not([disabled])');
222+
if (focusTarget) {
223+
break;
224+
}
225+
if (child.firstElementChild && !child.firstElementChild.disabled) {
226+
focusTarget = child.firstElementChild;
227+
break;
228+
}
229+
}
221230
}
222231

223232
focusTarget && focusTarget.focus();

src/components/menu/menu.spec.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,62 @@ describe('material.components.menu', function() {
152152
expect(getOpenMenuContainer(menu).length).toBe(0);
153153
}));
154154

155+
describe('default focus', function() {
156+
it('should focus on first item automatically', inject(function($compile, $rootScope, $document) {
157+
var menu = $compile(
158+
'<md-menu>' +
159+
'<button ng-click="$mdOpenMenu($event)">Hello World</button>' +
160+
'<md-menu-content>' +
161+
'<md-menu-item>' +
162+
'<button id="menuItem0" ng-click="doSomething($event)"></button>' +
163+
'</md-menu-item>' +
164+
'<md-menu-item>' +
165+
'<button ng-click="doSomething($event)"></button>' +
166+
'</md-menu-item>' +
167+
'</md-menu-content>' +
168+
'</md-menu>'
169+
)($rootScope);
170+
171+
openMenu(menu);
172+
173+
var menuTarget = $document[0].querySelector('#menuItem0');
174+
175+
expect(document.activeElement).toBe(menuTarget);
176+
}));
177+
178+
it('should focus on first non-disabled item', inject(function($compile, $rootScope, $document) {
179+
var menu = $compile(
180+
'<md-menu>' +
181+
'<button ng-click="$mdOpenMenu($event)">Hello World</button>' +
182+
'<md-menu-content>' +
183+
'<md-menu-item>' +
184+
'<button disabled ng-click="doSomething($event)"></button>' +
185+
'</md-menu-item>' +
186+
'<md-menu-item>' +
187+
'<button id="menuItem1" ng-click="doSomething($event)"></button>' +
188+
'</md-menu-item>' +
189+
'</md-menu-content>' +
190+
'</md-menu>'
191+
)($rootScope);
192+
193+
openMenu(menu);
194+
195+
var menuTarget = $document[0].querySelector('#menuItem1');
196+
197+
expect(document.activeElement).toBe(menuTarget);
198+
}));
199+
});
200+
155201
describe('autofocus', function() {
156202

157203
it('should focus a button with md-menu-focus-target', inject(function($compile, $rootScope, $document) {
158204
var menu = $compile(
159205
'<md-menu>' +
160206
'<button ng-click="$mdOpenMenu($event)">Hello World</button>' +
161207
'<md-menu-content>' +
208+
'<md-menu-item>' +
209+
'<button ng-click="doSomething($event)"></button>' +
210+
'</md-menu-item>' +
162211
'<md-menu-item>' +
163212
'<button id="menuFocus" md-menu-focus-target ng-click="doSomething($event)"></button>' +
164213
'</md-menu-item>' +
@@ -178,6 +227,9 @@ describe('material.components.menu', function() {
178227
'<md-menu>' +
179228
'<button ng-click="$mdOpenMenu($event)">Hello World</button>' +
180229
'<md-menu-content>' +
230+
'<md-menu-item>' +
231+
'<button ng-click="doSomething($event)"></button>' +
232+
'</md-menu-item>' +
181233
'<md-menu-item>' +
182234
'<button id="menuFocus" md-autofocus ng-click="doSomething($event)"></button>' +
183235
'</md-menu-item>' +

0 commit comments

Comments
 (0)