diff --git a/src/components/select/select.js b/src/components/select/select.js index 68ea849cfd8..6d91ca87bd0 100755 --- a/src/components/select/select.js +++ b/src/components/select/select.js @@ -184,7 +184,9 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $compile, $par element.empty().append(valueEl); element.append(selectTemplate); - attr.tabindex = attr.tabindex || '0'; + if(!attr.tabindex){ + attr.$set('tabindex', 0); + } return function postLink(scope, element, attr, ctrls) { var untouched = true; @@ -372,23 +374,25 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $compile, $par } isDisabled = disabled; if (disabled) { - element.attr({'tabindex': -1, 'aria-disabled': 'true'}); - element.off('click', openSelect); - element.off('keydown', handleKeypress); + element + .attr({'aria-disabled': 'true'}) + .removeAttr('tabindex') + .off('click', openSelect) + .off('keydown', handleKeypress); } else { - element.attr({'tabindex': attr.tabindex, 'aria-disabled': 'false'}); - element.on('click', openSelect); - element.on('keydown', handleKeypress); + element + .attr({'tabindex': attr.tabindex, 'aria-disabled': 'false'}) + .on('click', openSelect) + .on('keydown', handleKeypress); } }); - if (!attr.disabled && !attr.ngDisabled) { - element.attr({'tabindex': attr.tabindex, 'aria-disabled': 'false'}); + if (!attr.hasOwnProperty('disabled') && !attr.hasOwnProperty('ngDisabled')) { + element.attr({'aria-disabled': 'false'}); element.on('click', openSelect); element.on('keydown', handleKeypress); } - var ariaAttrs = { role: 'listbox', 'aria-expanded': 'false', @@ -1220,7 +1224,7 @@ function SelectProvider($$interimElementProvider) { } newOption = optionsArray[index]; if (newOption.hasAttribute('disabled')) newOption = undefined; - } while (!newOption && index < optionsArray.length - 1 && index > 0) + } while (!newOption && index < optionsArray.length - 1 && index > 0); newOption && newOption.focus(); opts.focusedNode = newOption; } diff --git a/src/components/select/select.spec.js b/src/components/select/select.spec.js index 890368437a3..6fa5158d237 100755 --- a/src/components/select/select.spec.js +++ b/src/components/select/select.spec.js @@ -31,17 +31,22 @@ describe('', function() { })); it('should preserve tabindex', function() { - var select = setupSelect('tabindex="2", ng-model="val"').find('md-select'); + var select = setupSelect('tabindex="2" ng-model="val"').find('md-select'); expect(select.attr('tabindex')).toBe('2'); }); + it('should set a tabindex if the element does not have one', function() { + var select = setupSelect('ng-model="val"').find('md-select'); + expect(select.attr('tabindex')).toBeDefined(); + }); + it('supports non-disabled state', function() { var select = setupSelect('ng-model="val"').find('md-select'); expect(select.attr('aria-disabled')).toBe('false'); }); it('supports disabled state', inject(function($document) { - var select = setupSelect('disabled="disabled", ng-model="val"').find('md-select'); + var select = setupSelect('disabled ng-model="val"').find('md-select'); openSelect(select); expectSelectClosed(select); expect($document.find('md-select-menu').length).toBe(0); @@ -49,7 +54,7 @@ describe('', function() { })); it('supports passing classes to the container', inject(function($document) { - var select = setupSelect('ng-model="val", md-container-class="test"').find('md-select'); + var select = setupSelect('ng-model="val" md-container-class="test"').find('md-select'); openSelect(select); var container = $document[0].querySelector('.md-select-menu-container'); @@ -58,7 +63,7 @@ describe('', function() { })); it('supports passing classes to the container using `data-` attribute prefix', inject(function($document) { - var select = setupSelect('ng-model="val", data-md-container-class="test"').find('md-select'); + var select = setupSelect('ng-model="val" data-md-container-class="test"').find('md-select'); openSelect(select); var container = $document[0].querySelector('.md-select-menu-container'); @@ -67,7 +72,7 @@ describe('', function() { })); it('supports passing classes to the container using `x-` attribute prefix', inject(function($document) { - var select = setupSelect('ng-model="val", x-md-container-class="test"').find('md-select'); + var select = setupSelect('ng-model="val" x-md-container-class="test"').find('md-select'); openSelect(select); var container = $document[0].querySelector('.md-select-menu-container'); @@ -88,7 +93,7 @@ describe('', function() { $rootScope.onClose = function() { called = true; }; - var select = setupSelect('ng-model="val", md-on-close="onClose()"', [1, 2, 3]).find('md-select'); + var select = setupSelect('ng-model="val" md-on-close="onClose()"', [1, 2, 3]).find('md-select'); openSelect(select); expectSelectOpen(select); @@ -153,7 +158,6 @@ describe('', function() { expect($rootScope.myForm.select.$touched).toBe(true); })); - it('restores focus to select when the menu is closed', inject(function($document) { var select = setupSelect('ng-model="val"').find('md-select'); openSelect(select); @@ -186,6 +190,11 @@ describe('', function() { })); + it('should remove the tabindex from a disabled element', inject(function($document) { + var select = setupSelect('ng-model="val" disabled tabindex="1"').find('md-select'); + expect(select.attr('tabindex')).toBeUndefined(); + })); + describe('input container', function() { it('should set has-value class on container for non-ng-model input', inject(function($rootScope) { var el = setupSelect('ng-model="$root.model"', [1, 2, 3]); @@ -210,7 +219,7 @@ describe('', function() { })); it('should match label to given input id', function() { - var el = setupSelect('ng-model="$root.value", id="foo"'); + var el = setupSelect('ng-model="$root.value" id="foo"'); expect(el.find('label').attr('for')).toBe('foo'); expect(el.find('md-select').attr('id')).toBe('foo'); }); @@ -224,7 +233,7 @@ describe('', function() { describe('label behavior', function() { it('defaults to the placeholder text', function() { - var select = setupSelect('ng-model="someVal", placeholder="Hello world"', null, true).find('md-select'); + var select = setupSelect('ng-model="someVal" placeholder="Hello world"', null, true).find('md-select'); var label = select.find('md-select-value'); expect(label.text()).toBe('Hello world'); expect(label.hasClass('md-select-placeholder')).toBe(true); @@ -444,7 +453,7 @@ describe('', function() { changesCalled = true; }; - var selectEl = setupSelect('ng-model="myModel", ng-change="changed()"', [1, 2, 3]).find('md-select'); + var selectEl = setupSelect('ng-model="myModel" ng-change="changed()"', [1, 2, 3]).find('md-select'); openSelect(selectEl); var menuEl = $document.find('md-select-menu'); @@ -763,7 +772,7 @@ describe('', function() { })); it('adds an aria-label from placeholder', function() { - var select = setupSelect('ng-model="someVal", placeholder="Hello world"', null, true).find('md-select'); + var select = setupSelect('ng-model="someVal" placeholder="Hello world"', null, true).find('md-select'); expect(select.attr('aria-label')).toBe('Hello world'); }); @@ -783,7 +792,7 @@ describe('', function() { })); it('preserves existing aria-label', function() { - var select = setupSelect('ng-model="someVal", aria-label="Hello world", placeholder="Pick"').find('md-select'); + var select = setupSelect('ng-model="someVal" aria-label="Hello world" placeholder="Pick"').find('md-select'); expect(select.attr('aria-label')).toBe('Hello world'); });