Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit b8889b6

Browse files
committed
fix(dialog): only restore focus with keyboard interaction
* Currently the dialog always restores focus to the origin element upon close. * The focus should be only restored if the dialog was opened with keyboard interaction - Same behavior as with the sidenav closing. Fixes #7963.
1 parent 70cecda commit b8889b6

File tree

2 files changed

+83
-3
lines changed

2 files changed

+83
-3
lines changed

src/components/dialog/dialog.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ function MdDialogProvider($$interimElementProvider) {
638638

639639
/* @ngInject */
640640
function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document, $window, $rootElement,
641-
$log, $injector, $mdTheming, $interpolate) {
641+
$log, $injector, $mdTheming, $interpolate, $mdInteraction) {
642642

643643
return {
644644
hasBackdrop: true,
@@ -798,7 +798,10 @@ function MdDialogProvider($$interimElementProvider) {
798798
// Exposed cleanup function from the $mdCompiler.
799799
options.cleanupElement();
800800

801-
if (!options.$destroy) options.origin.focus();
801+
// Restores the focus to the origin element if the last interaction upon opening was a keyboard.
802+
if (!options.$destroy && options.originInteraction === 'keyboard') {
803+
options.origin.focus();
804+
}
802805
}
803806
}
804807

@@ -850,7 +853,8 @@ function MdDialogProvider($$interimElementProvider) {
850853
options.openFrom = getBoundingClientRect(getDomElement(options.openFrom));
851854

852855
if ( options.targetEvent ) {
853-
options.origin = getBoundingClientRect(options.targetEvent.target, options.origin);
856+
options.origin = getBoundingClientRect(options.targetEvent.target, options.origin);
857+
options.originInteraction = $mdInteraction.getLastInteractionType();
854858
}
855859

856860

src/components/dialog/dialog.spec.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,82 @@ describe('$mdDialog', function() {
11341134
expect($document.activeElement).toBe(parent[0].querySelector('#focus-target'));
11351135
}));
11361136

1137+
it('should restore the focus to the origin upon close', inject(function($mdDialog, $compile, $rootScope) {
1138+
var scope = $rootScope.$new();
1139+
var body = angular.element(document.body);
1140+
var parent = angular.element('<div>');
1141+
var button = $compile('<button ng-click="openDialog($event)">Open</button>')(scope);
1142+
1143+
// Append the button to the body, because otherwise the dialog is not able to determine
1144+
// the origin rectangle.
1145+
document.body.appendChild(button[0]);
1146+
1147+
scope.openDialog = function($event) {
1148+
$mdDialog.show({
1149+
parent: parent,
1150+
template: '<md-dialog>Test</md-dialog>',
1151+
targetEvent: $event,
1152+
scope: scope.$new()
1153+
});
1154+
};
1155+
1156+
// Emit a keyboard event to fake a keyboard interaction.
1157+
body.triggerHandler('keydown');
1158+
button.triggerHandler('click');
1159+
1160+
runAnimation();
1161+
1162+
expect(parent.find('md-dialog').length).toBe(1);
1163+
expect(document.activeElement).not.toBe(button[0]);
1164+
1165+
1166+
$mdDialog.hide();
1167+
runAnimation();
1168+
1169+
expect(parent.find('md-dialog').length).toBe(0);
1170+
expect(document.activeElement).toBe(button[0]);
1171+
1172+
button.remove();
1173+
}));
1174+
1175+
it('should not restore the focus without keyboard interaction', inject(function($mdDialog, $compile, $rootScope) {
1176+
var scope = $rootScope.$new();
1177+
var body = angular.element(document.body);
1178+
var parent = angular.element('<div>');
1179+
var button = $compile('<button ng-click="openDialog($event)">Open</button>')(scope);
1180+
1181+
// Append the button to the body, because otherwise the dialog is not able to determine
1182+
// the origin rectangle.
1183+
document.body.appendChild(button[0]);
1184+
1185+
scope.openDialog = function($event) {
1186+
$mdDialog.show({
1187+
parent: parent,
1188+
template: '<md-dialog>Test</md-dialog>',
1189+
targetEvent: $event,
1190+
scope: scope.$new()
1191+
});
1192+
};
1193+
1194+
// Emit a keyboard event to fake a mouse interaction.
1195+
body.triggerHandler('mousedown');
1196+
button.triggerHandler('click');
1197+
1198+
runAnimation();
1199+
1200+
expect(parent.find('md-dialog').length).toBe(1);
1201+
expect(document.activeElement).not.toBe(button[0]);
1202+
1203+
1204+
$mdDialog.hide();
1205+
runAnimation();
1206+
1207+
expect(parent.find('md-dialog').length).toBe(0);
1208+
expect(document.activeElement).not.toBe(button[0]);
1209+
1210+
button.remove();
1211+
}));
1212+
11371213
it('should focus the dialog element if no actions are set', inject(function($mdDialog, $rootScope, $document) {
11381214
jasmine.mockElementFocus(this);
11391215

0 commit comments

Comments
 (0)