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

Commit df99f6e

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 a1f2e17 commit df99f6e

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) {
641+
$log, $injector, $mdTheming, $mdInteraction) {
642642

643643
return {
644644
hasBackdrop: true,
@@ -793,7 +793,10 @@ function MdDialogProvider($$interimElementProvider) {
793793
// Exposed cleanup function from the $mdCompiler.
794794
options.cleanupElement();
795795

796-
if (!options.$destroy) options.origin.focus();
796+
// Restores the focus to the origin element if the last interaction upon opening was a keyboard.
797+
if (!options.$destroy && options.originInteraction === 'keyboard') {
798+
options.origin.focus();
799+
}
797800
}
798801
}
799802

@@ -830,7 +833,8 @@ function MdDialogProvider($$interimElementProvider) {
830833
options.openFrom = getBoundingClientRect(getDomElement(options.openFrom));
831834

832835
if ( options.targetEvent ) {
833-
options.origin = getBoundingClientRect(options.targetEvent.target, options.origin);
836+
options.origin = getBoundingClientRect(options.targetEvent.target, options.origin);
837+
options.originInteraction = $mdInteraction.getLastInteractionType();
834838
}
835839

836840

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+
fit('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)