Skip to content

Commit afcb3ea

Browse files
josephperrottjelbourn
authored andcommitted
fix(focus-monitor): set up global listeners in root zone (#9542)
1 parent fe0f7ed commit afcb3ea

File tree

1 file changed

+17
-7
lines changed

1 file changed

+17
-7
lines changed

src/cdk/a11y/focus-monitor/focus-monitor.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
98
import {Platform, supportsPassiveEventListeners} from '@angular/cdk/platform';
109
import {
1110
Directive,
@@ -56,7 +55,13 @@ export class FocusMonitor implements OnDestroy {
5655
private _lastTouchTarget: EventTarget | null;
5756

5857
/** The timeout id of the touch timeout, used to cancel timeout later. */
59-
private _touchTimeout: number;
58+
private _touchTimeoutId: number;
59+
60+
/** The timeout id of the window focus timeout. */
61+
private _windowFocusTimeoutId: number;
62+
63+
/** The timeout id of the origin clearing timeout. */
64+
private _originTimeoutId: number;
6065

6166
/** Map of elements being monitored to their info. */
6267
private _elementInfo = new Map<HTMLElement, MonitoredElementInfo>();
@@ -187,18 +192,18 @@ export class FocusMonitor implements OnDestroy {
187192
// we can't rely on the trick used above (setting timeout of 0ms). Instead we wait 650ms to
188193
// see if a focus happens.
189194
let documentTouchstartListener = (event: TouchEvent) => {
190-
if (this._touchTimeout != null) {
191-
clearTimeout(this._touchTimeout);
195+
if (this._touchTimeoutId != null) {
196+
clearTimeout(this._touchTimeoutId);
192197
}
193198
this._lastTouchTarget = event.target;
194-
this._touchTimeout = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
199+
this._touchTimeoutId = setTimeout(() => this._lastTouchTarget = null, TOUCH_BUFFER_MS);
195200
};
196201

197202
// Make a note of when the window regains focus, so we can restore the origin info for the
198203
// focused element.
199204
let windowFocusListener = () => {
200205
this._windowFocused = true;
201-
setTimeout(() => this._windowFocused = false, 0);
206+
this._windowFocusTimeoutId = setTimeout(() => this._windowFocused = false, 0);
202207
};
203208

204209
// Note: we listen to events in the capture phase so we can detect them even if the user stops
@@ -217,6 +222,11 @@ export class FocusMonitor implements OnDestroy {
217222
document.removeEventListener('touchstart', documentTouchstartListener,
218223
supportsPassiveEventListeners() ? ({passive: true, capture: true} as any) : true);
219224
window.removeEventListener('focus', windowFocusListener);
225+
226+
// Clear timeouts for all potentially pending timeouts to prevent the leaks.
227+
clearTimeout(this._windowFocusTimeoutId);
228+
clearTimeout(this._touchTimeoutId);
229+
clearTimeout(this._originTimeoutId);
220230
};
221231
}
222232

@@ -251,7 +261,7 @@ export class FocusMonitor implements OnDestroy {
251261
*/
252262
private _setOriginForCurrentEventQueue(origin: FocusOrigin): void {
253263
this._origin = origin;
254-
setTimeout(() => this._origin = null, 0);
264+
this._originTimeoutId = setTimeout(() => this._origin = null, 0);
255265
}
256266

257267
/**

0 commit comments

Comments
 (0)