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

Commit

Permalink
fix(modal): Fix focus when the dialog is close or cancelled
Browse files Browse the repository at this point in the history
- Return focus to element with focus before modal opened

Closes #2888
  • Loading branch information
Tobino authored and wesleycho committed Apr 5, 2015
1 parent 26b4090 commit e6b105a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/modal/modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ angular.module('ui.bootstrap.modal', [])

$modalStack.open = function (modalInstance, modal) {

var modalOpener = $document[0].activeElement;

openedWindows.add(modalInstance, {
deferred: modal.deferred,
renderDeferred: modal.renderDeferred,
Expand Down Expand Up @@ -303,6 +305,7 @@ angular.module('ui.bootstrap.modal', [])

var modalDomEl = $compile(angularDomEl)(modal.scope);
openedWindows.top().value.modalDomEl = modalDomEl;
openedWindows.top().value.modalOpener = modalOpener;
body.append(modalDomEl);
body.addClass(OPENED_MODAL_CLASS);
};
Expand All @@ -316,6 +319,7 @@ angular.module('ui.bootstrap.modal', [])
if (modalWindow && broadcastClosing(modalWindow, result, true)) {
modalWindow.value.deferred.resolve(result);
removeModalWindow(modalInstance);
modalWindow.value.modalOpener.focus();
return true;
}
return !modalWindow;
Expand All @@ -326,6 +330,7 @@ angular.module('ui.bootstrap.modal', [])
if (modalWindow && broadcastClosing(modalWindow, reason, false)) {
modalWindow.value.deferred.reject(reason);
removeModalWindow(modalInstance);
modalWindow.value.modalOpener.focus();
return true;
}
return !modalWindow;
Expand Down
51 changes: 51 additions & 0 deletions src/modal/test/modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,28 @@ describe('$modal', function () {
expect($document).toHaveModalsOpen(0);
});

it('should return to the element which had focus before the dialog is invoked', function () {
var link = '<a href>Link</a>';
var element = angular.element(link);
angular.element(document.body).append(element);
element.focus();
expect(document.activeElement.tagName).toBe('A');

var modal = open({template: '<div>Content<button>inside modal</button></div>'});
$timeout.flush();
expect(document.activeElement.tagName).toBe('DIV');
expect($document).toHaveModalsOpen(1);

triggerKeyDown($document, 27);
$timeout.flush();
$rootScope.$digest();

expect(document.activeElement.tagName).toBe('A');
expect($document).toHaveModalsOpen(0);

element.remove();
});

it('should resolve returned promise on close', function () {
var modal = open({template: '<div>Content</div>'});
close(modal, 'closed ok');
Expand Down Expand Up @@ -695,6 +717,35 @@ describe('$modal', function () {
dismiss(modal2);
expect(body).not.toHaveClass('modal-open');
});

it('should return to the element which had focus before the dialog is invoked', function () {
var link = '<a href>Link</a>';
var element = angular.element(link);
angular.element(document.body).append(element);
element.focus();
expect(document.activeElement.tagName).toBe('A');

var modal1 = open({template: '<div>Modal1<button id="focus">inside modal1</button></div>'});
$timeout.flush();
document.getElementById('focus').focus();
expect(document.activeElement.tagName).toBe('BUTTON');
expect($document).toHaveModalsOpen(1);

var modal2 = open({template: '<div>Modal2</div>'});
$timeout.flush();
expect(document.activeElement.tagName).toBe('DIV');
expect($document).toHaveModalsOpen(2);

dismiss(modal2);
expect(document.activeElement.tagName).toBe('BUTTON');
expect($document).toHaveModalsOpen(1);

dismiss(modal1);
expect(document.activeElement.tagName).toBe('A');
expect($document).toHaveModalsOpen(0);

element.remove();
});
});

describe('modal.closing event', function() {
Expand Down

0 comments on commit e6b105a

Please sign in to comment.