diff --git a/src/modal/modal.js b/src/modal/modal.js index 9470f62d5c..c6215f4a11 100644 --- a/src/modal/modal.js +++ b/src/modal/modal.js @@ -195,7 +195,7 @@ angular.module('ui.bootstrap.modal', []) } }); - function removeModalWindow(modalInstance) { + function removeModalWindow(modalInstance, elementToReceiveFocus) { var body = $document.find('body').eq(0); var modalWindow = openedWindows.get(modalInstance).value; @@ -208,6 +208,13 @@ angular.module('ui.bootstrap.modal', []) body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0); checkRemoveBackdrop(); }); + + //move focus to specified element if available, or else to body + if (elementToReceiveFocus && elementToReceiveFocus.focus) { + elementToReceiveFocus.focus(); + } else { + body.focus(); + } } function checkRemoveBackdrop() { @@ -318,8 +325,7 @@ angular.module('ui.bootstrap.modal', []) var modalWindow = openedWindows.get(modalInstance); if (modalWindow && broadcastClosing(modalWindow, result, true)) { modalWindow.value.deferred.resolve(result); - removeModalWindow(modalInstance); - modalWindow.value.modalOpener.focus(); + removeModalWindow(modalInstance, modalWindow.value.modalOpener); return true; } return !modalWindow; @@ -329,8 +335,7 @@ angular.module('ui.bootstrap.modal', []) var modalWindow = openedWindows.get(modalInstance); if (modalWindow && broadcastClosing(modalWindow, reason, false)) { modalWindow.value.deferred.reject(reason); - removeModalWindow(modalInstance); - modalWindow.value.modalOpener.focus(); + removeModalWindow(modalInstance, modalWindow.value.modalOpener); return true; } return !modalWindow; diff --git a/src/modal/test/modal.spec.js b/src/modal/test/modal.spec.js index c1d5fe4c29..0afe94ab8d 100644 --- a/src/modal/test/modal.spec.js +++ b/src/modal/test/modal.spec.js @@ -250,7 +250,7 @@ describe('$modal', function () { expect($document).toHaveModalsOpen(0); }); - it('should return to the element which had focus before the dialog is invoked', function () { + it('should return to the element which had focus before the dialog was invoked', function () { var link = 'Link'; var element = angular.element(link); angular.element(document.body).append(element); @@ -272,6 +272,30 @@ describe('$modal', function () { element.remove(); }); + it('should return to document.body if element which had focus before the dialog was invoked is gone, or is missing focus function', function () { + var link = 'Link'; + var element = angular.element(link); + angular.element(document.body).append(element); + element.focus(); + expect(document.activeElement.tagName).toBe('A'); + + var modal = open({template: '
Content
'}); + $timeout.flush(); + expect(document.activeElement.tagName).toBe('DIV'); + expect($document).toHaveModalsOpen(1); + + // Fake undefined focus function, happening in IE in certain + // iframe conditions. See issue 3639 + element[0].focus = undefined; + triggerKeyDown($document, 27); + $timeout.flush(); + $rootScope.$digest(); + + expect(document.activeElement.tagName).toBe('BODY'); + expect($document).toHaveModalsOpen(0); + element.remove(); + }); + it('should resolve returned promise on close', function () { var modal = open({template: '
Content
'}); close(modal, 'closed ok');