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

Commit 2f60691

Browse files
committed
fix(dialog): remove focus trap focus listeners onRemove
- improve JSDoc and Closure types - fix typos - simplify `isNodeOneOf()` and ensure it returns a `boolean` Relates to #11207
1 parent 0d431e0 commit 2f60691

File tree

1 file changed

+53
-31
lines changed

1 file changed

+53
-31
lines changed

src/components/dialog/dialog.js

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ function MdDialogDirective($$rAF, $mdTheming, $mdDialog) {
552552
function MdDialogProvider($$interimElementProvider) {
553553
// Elements to capture and redirect focus when the user presses tab at the dialog boundary.
554554
var topFocusTrap, bottomFocusTrap;
555+
var removeFocusTrap;
555556

556557
return $$interimElementProvider('$mdDialog')
557558
.setDefaults({
@@ -641,9 +642,9 @@ function MdDialogProvider($$interimElementProvider) {
641642
}
642643

643644
/* @ngInject */
644-
function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document, $window, $rootElement,
645-
$log, $injector, $mdTheming, $interpolate, $mdInteraction) {
646-
645+
function dialogDefaultOptions($mdDialog, $mdAria, $mdUtil, $mdConstant, $animate, $document,
646+
$window, $rootElement, $log, $injector, $mdTheming, $interpolate,
647+
$mdInteraction) {
647648
return {
648649
hasBackdrop: true,
649650
isolateScope: true,
@@ -768,12 +769,9 @@ function MdDialogProvider($$interimElementProvider) {
768769
options.hideBackdrop(options.$destroy);
769770

770771
// Remove the focus traps that we added earlier for keeping focus within the dialog.
771-
if (topFocusTrap && topFocusTrap.parentNode) {
772-
topFocusTrap.parentNode.removeChild(topFocusTrap);
773-
}
774-
775-
if (bottomFocusTrap && bottomFocusTrap.parentNode) {
776-
bottomFocusTrap.parentNode.removeChild(bottomFocusTrap);
772+
if (removeFocusTrap) {
773+
removeFocusTrap();
774+
removeFocusTrap = null;
777775
}
778776

779777
// For navigation $destroy events, do a quick, non-animated removal,
@@ -936,10 +934,8 @@ function MdDialogProvider($$interimElementProvider) {
936934

937935
// Queue remove listeners function
938936
removeListeners.push(function() {
939-
940937
element.off('keydown', keyHandlerFn);
941938
parentTarget.off('keydown', keyHandlerFn);
942-
943939
});
944940
}
945941

@@ -1015,11 +1011,13 @@ function MdDialogProvider($$interimElementProvider) {
10151011
*/
10161012
options.hideBackdrop = function hideBackdrop($destroy) {
10171013
if (options.backdrop) {
1018-
if ($destroy) options.backdrop.remove();
1019-
else $animate.leave(options.backdrop);
1014+
if ($destroy) {
1015+
options.backdrop.remove();
1016+
} else {
1017+
$animate.leave(options.backdrop);
1018+
}
10201019
}
10211020

1022-
10231021
if (options.disableParentScroll) {
10241022
options.restoreScroll && options.restoreScroll();
10251023
delete options.restoreScroll;
@@ -1088,15 +1086,27 @@ function MdDialogProvider($$interimElementProvider) {
10881086
topFocusTrap.addEventListener('focus', focusHandler);
10891087
bottomFocusTrap.addEventListener('focus', focusHandler);
10901088

1091-
// The top focus trap inserted immeidately before the md-dialog element (as a sibling).
1089+
removeFocusTrap = function () {
1090+
topFocusTrap.removeEventListener('focus', focusHandler);
1091+
bottomFocusTrap.removeEventListener('focus', focusHandler);
1092+
1093+
if (topFocusTrap && topFocusTrap.parentNode) {
1094+
topFocusTrap.parentNode.removeChild(topFocusTrap);
1095+
}
1096+
1097+
if (bottomFocusTrap && bottomFocusTrap.parentNode) {
1098+
bottomFocusTrap.parentNode.removeChild(bottomFocusTrap);
1099+
}
1100+
};
1101+
1102+
// The top focus trap inserted immediately before the md-dialog element (as a sibling).
10921103
// The bottom focus trap is inserted at the very end of the md-dialog element (as a child).
10931104
element[0].parentNode.insertBefore(topFocusTrap, element[0]);
10941105
element.after(bottomFocusTrap);
10951106
}
10961107

10971108
/**
1098-
* Prevents screen reader interaction behind modal window
1099-
* on swipe interfaces
1109+
* Prevents screen reader interaction behind modal window on swipe interfaces.
11001110
*/
11011111
function lockScreenReader(element, options) {
11021112
var isHidden = true;
@@ -1112,8 +1122,9 @@ function MdDialogProvider($$interimElementProvider) {
11121122
};
11131123

11141124
/**
1115-
* Get all of an element's parent elements up the DOM tree
1116-
* @return {Array} The parent elements
1125+
* Get all of an element's parent elements up the DOM tree.
1126+
* @param {Node & ParentNode} element the element to start from
1127+
* @return {Element[]} The parent elements
11171128
*/
11181129
function getParents(element) {
11191130
var parents = [];
@@ -1137,8 +1148,9 @@ function MdDialogProvider($$interimElementProvider) {
11371148
}
11381149

11391150
/**
1140-
* Walk DOM to apply or remove aria-hidden on sibling nodes
1141-
* and parent sibling nodes
1151+
* Walk DOM to apply or remove aria-hidden on sibling nodes and parent sibling nodes.
1152+
* @param {Element} element the element to start from when walking up the DOM
1153+
* @returns {void}
11421154
*/
11431155
function walkDOM(element) {
11441156
var elements = getParents(element);
@@ -1149,12 +1161,17 @@ function MdDialogProvider($$interimElementProvider) {
11491161
}
11501162

11511163
/**
1152-
* Ensure the dialog container fill-stretches to the viewport
1164+
* Ensure the dialog container fill-stretches to the viewport.
1165+
* @param {JQLite} container dialog container
1166+
* @param {Object} options
1167+
* @returns {function(): void} function that reverts the modified styles
11531168
*/
11541169
function stretchDialogContainerToViewport(container, options) {
11551170
var isFixed = $window.getComputedStyle($document[0].body).position === 'fixed';
11561171
var backdrop = options.backdrop ? $window.getComputedStyle(options.backdrop[0]) : null;
1157-
var height = backdrop ? Math.min($document[0].body.clientHeight, Math.ceil(Math.abs(parseInt(backdrop.height, 10)))) : 0;
1172+
var height = backdrop ?
1173+
Math.min($document[0].body.clientHeight, Math.ceil(Math.abs(parseInt(backdrop.height, 10))))
1174+
: 0;
11581175

11591176
var previousStyles = {
11601177
top: container.css('top'),
@@ -1178,7 +1195,10 @@ function MdDialogProvider($$interimElementProvider) {
11781195
}
11791196

11801197
/**
1181-
* Dialog open and pop-in animation
1198+
* Dialog open and pop-in animation.
1199+
* @param {JQLite} container dialog container
1200+
* @param {Object} options
1201+
* @returns {*}
11821202
*/
11831203
function dialogPopIn(container, options) {
11841204
// Add the `md-dialog-container` to the DOM
@@ -1219,7 +1239,6 @@ function MdDialogProvider($$interimElementProvider) {
12191239
buildTranslateToOrigin(dialogEl, options.origin)
12201240
)
12211241
);
1222-
12231242
};
12241243

12251244
// Function to revert the generated animation styles on the dialog element.
@@ -1243,7 +1262,10 @@ function MdDialogProvider($$interimElementProvider) {
12431262
}
12441263

12451264
/**
1246-
* Dialog close and pop-out animation
1265+
* Dialog close and pop-out animation.
1266+
* @param {JQLite} container dialog container
1267+
* @param {Object} options
1268+
* @returns {*}
12471269
*/
12481270
function dialogPopOut(container, options) {
12491271
return options.reverseAnimate().then(function() {
@@ -1256,13 +1278,13 @@ function MdDialogProvider($$interimElementProvider) {
12561278
}
12571279

12581280
/**
1259-
* Utility function to filter out raw DOM nodes
1281+
* Utility function to filter out raw DOM nodes.
1282+
* @param {Node} elem
1283+
* @param {string[]} nodeTypeArray
1284+
* @returns {boolean}
12601285
*/
12611286
function isNodeOneOf(elem, nodeTypeArray) {
1262-
if (nodeTypeArray.indexOf(elem.nodeName) !== -1) {
1263-
return true;
1264-
}
1287+
return nodeTypeArray.indexOf(elem.nodeName) !== -1;
12651288
}
1266-
12671289
}
12681290
}

0 commit comments

Comments
 (0)