Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit 35ced04

Browse files
atrinhwesleycho
atrinh
authored andcommitted
fix(modal): filter out non-tabbable elements
- Ensure non-tabbable elements with taxindex of -1 are not tabbed to Closes #5963 Fixes #5955
1 parent 90fa2f6 commit 35ced04

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

src/modal/modal.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,9 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
261261
var previousTopOpenedModal = null;
262262

263263
//Modal focus behavior
264-
var tabableSelector = 'a[href], area[href], input:not([disabled]), ' +
265-
'button:not([disabled]),select:not([disabled]), textarea:not([disabled]), ' +
266-
'iframe, object, embed, *[tabindex], *[contenteditable=true]';
264+
var tabbableSelector = 'a[href], area[href], input:not([disabled]):not([tabindex=\'-1\']), ' +
265+
'button:not([disabled]):not([tabindex=\'-1\']),select:not([disabled]):not([tabindex=\'-1\']), textarea:not([disabled]):not([tabindex=\'-1\']), ' +
266+
'iframe, object, embed, *[tabindex]:not([tabindex=\'-1\']), *[contenteditable=true]';
267267
var scrollbarPadding;
268268

269269
function isVisible(element) {
@@ -599,7 +599,7 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap', 'ui.bootstrap.p
599599
if (modalWindow) {
600600
var modalDomE1 = modalWindow.value.modalDomEl;
601601
if (modalDomE1 && modalDomE1.length) {
602-
var elements = modalDomE1[0].querySelectorAll(tabableSelector);
602+
var elements = modalDomE1[0].querySelectorAll(tabbableSelector);
603603
return elements ?
604604
Array.prototype.filter.call(elements, function(element) {
605605
return isVisible(element);

src/modal/test/modal.spec.js

+46
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,52 @@ describe('$uibModal', function() {
807807

808808
initialPage.remove();
809809
});
810+
811+
it('should change focus to next tabbable element when tab is pressed', function() {
812+
var initialPage = angular.element('<a href="#" id="cannot-get-focus-from-modal">Outland link</a>');
813+
angular.element(document.body).append(initialPage);
814+
initialPage.focus();
815+
816+
open({
817+
template:'<button id="tab-focus-button1" tabindex="-1">Skip me!</button><a href="#" id="tab-focus-link1">a</a>' +
818+
'<a href="#" id="tab-focus-link2">b</a><a href="#" id="tab-focus-link3">c</a>' +
819+
'<button id="tab-focus-button2" tabindex="-1">Skip me!</button>',
820+
keyboard: false
821+
});
822+
$rootScope.$digest();
823+
expect($document).toHaveModalsOpen(1);
824+
825+
$('#tab-focus-link3').focus();
826+
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link3');
827+
828+
triggerKeyDown(angular.element(document.activeElement), 9, false);
829+
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link1');
830+
831+
initialPage.remove();
832+
});
833+
834+
it('should change focus to previous tabbable element when shift+tab is pressed', function() {
835+
var initialPage = angular.element('<a href="#" id="cannot-get-focus-from-modal">Outland link</a>');
836+
angular.element(document.body).append(initialPage);
837+
initialPage.focus();
838+
839+
open({
840+
template:'<button id="tab-focus-button1" tabindex="-1">Skip me!</button><a href="#" id="tab-focus-link1">a</a>' +
841+
'<a href="#" id="tab-focus-link2">b</a><a href="#" id="tab-focus-link3">c</a>' +
842+
'<button id="tab-focus-button2" tabindex="-1">Skip me!</button>',
843+
keyboard: false
844+
});
845+
$rootScope.$digest();
846+
expect($document).toHaveModalsOpen(1);
847+
848+
$('#tab-focus-link1').focus();
849+
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link1');
850+
851+
triggerKeyDown(angular.element(document.activeElement), 9, true);
852+
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link3');
853+
854+
initialPage.remove();
855+
});
810856
});
811857

812858
describe('default options can be changed in a provider', function() {

0 commit comments

Comments
 (0)