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

Commit

Permalink
feat(modal): exclude hidden elements from query
Browse files Browse the repository at this point in the history
- Modify element query to exclude hidden elements

Closes #5512
Closes #5644
  • Loading branch information
wesleycho committed Mar 18, 2016
1 parent bc7c55a commit 5ef56e2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,16 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
};

//Modal focus behavior
var tababbleSelector = 'a[href], area[href], input:not([disabled]), ' +
var tabableSelector = 'a[href], area[href], input:not([disabled]), ' +
'button:not([disabled]),select:not([disabled]), textarea:not([disabled]), ' +
'iframe, object, embed, *[tabindex], *[contenteditable=true]';

function isVisible(element) {
return !!(element.offsetWidth ||
element.offsetHeight ||
element.getClientRects().length);
}

function backdropIndex() {
var topBackdropIndex = -1;
var opened = openedWindows.keys();
Expand Down Expand Up @@ -565,7 +571,11 @@ angular.module('ui.bootstrap.modal', ['ui.bootstrap.stackedMap'])
if (modalWindow) {
var modalDomE1 = modalWindow.value.modalDomEl;
if (modalDomE1 && modalDomE1.length) {
return modalDomE1[0].querySelectorAll(tababbleSelector);
var elements = modalDomE1[0].querySelectorAll(tabableSelector);
return elements ?
Array.prototype.filter.call(elements, function(element) {
return isVisible(element);
}) : elements;
}
}
};
Expand Down
46 changes: 46 additions & 0 deletions src/modal/test/modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,52 @@ describe('$uibModal', function() {

initialPage.remove();
});

it('should change focus to next non-hidden element when tab is pressed', function() {
var initialPage = angular.element('<a href="#" id="cannot-get-focus-from-modal">Outland link</a>');
angular.element(document.body).append(initialPage);
initialPage.focus();

open({
template:'<a href="#" id="tab-focus-link1">a</a><a href="#" id="tab-focus-link2">b</a><a href="#" id="tab-focus-link3">c</a>' +
'<button id="tab-focus-button">Open me!</button>',
keyboard: false
});
$rootScope.$digest();
expect($document).toHaveModalsOpen(1);

$('#tab-focus-link3').focus();
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link3');

$('#tab-focus-button').css('display', 'none');
triggerKeyDown(angular.element(document.activeElement), 9, false);
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link1');

initialPage.remove();
});

it('should change focus to previous non-hidden element when shift+tab is pressed', function() {
var initialPage = angular.element('<a href="#" id="cannot-get-focus-from-modal">Outland link</a>');
angular.element(document.body).append(initialPage);
initialPage.focus();

open({
template:'<a href="#" id="tab-focus-link1">a</a><a href="#" id="tab-focus-link2">b</a><a href="#" id="tab-focus-link3">c</a>' +
'<button id="tab-focus-button">Open me!</button>',
keyboard: false
});
$rootScope.$digest();
expect($document).toHaveModalsOpen(1);

$('#tab-focus-link1').focus();
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link1');

$('#tab-focus-button').css('display', 'none');
triggerKeyDown(angular.element(document.activeElement), 9, true);
expect(document.activeElement.getAttribute('id')).toBe('tab-focus-link3');

initialPage.remove();
});
});

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

0 comments on commit 5ef56e2

Please sign in to comment.