@@ -11,12 +11,13 @@ import {
1111 Directive ,
1212 ElementRef ,
1313 EventEmitter ,
14+ Inject ,
1415 Injectable ,
16+ InjectionToken ,
1517 NgZone ,
1618 OnDestroy ,
17- Output ,
1819 Optional ,
19- Inject ,
20+ Output ,
2021} from '@angular/core' ;
2122import { Observable , of as observableOf , Subject , Subscription } from 'rxjs' ;
2223import { coerceElement } from '@angular/cdk/coercion' ;
@@ -39,6 +40,30 @@ export interface FocusOptions {
3940 preventScroll ?: boolean ;
4041}
4142
43+ /** Detection mode used for attributing the origin of a focus event. */
44+ export const enum FocusMonitorDetectionMode {
45+ /**
46+ * Any mousedown, keydown, or touchstart event that happened in the previous
47+ * tick or the current tick will be used to assign a focus event's origin (to
48+ * either mouse, keyboard, or touch). This is the default option.
49+ */
50+ IMMEDIATE ,
51+ /**
52+ * A focus event's origin is always attributed to the last corresponding
53+ * mousedown, keydown, or touchstart event, no matter how long ago it occured.
54+ */
55+ EVENTUAL
56+ }
57+
58+ /** Injectable service-level options for FocusMonitor. */
59+ export interface FocusMonitorOptions {
60+ detectionMode ?: FocusMonitorDetectionMode ;
61+ }
62+
63+ /** InjectionToken for FocusMonitorOptions. */
64+ export const FOCUS_MONITOR_DEFAULT_OPTIONS =
65+ new InjectionToken < FocusMonitorOptions > ( 'cdk-focus-monitor-default-options' ) ;
66+
4267type MonitoredElementInfo = {
4368 unlisten : Function ,
4469 checkChildren : boolean ,
@@ -85,6 +110,12 @@ export class FocusMonitor implements OnDestroy {
85110 /** The number of elements currently being monitored. */
86111 private _monitoredElementCount = 0 ;
87112
113+ /**
114+ * The specified detection mode, used for attributing the origin of a focus
115+ * event.
116+ */
117+ private readonly _detectionMode : FocusMonitorDetectionMode ;
118+
88119 /**
89120 * Event listener for `keydown` events on the document.
90121 * Needs to be an arrow function in order to preserve the context when it gets bound.
@@ -137,14 +168,18 @@ export class FocusMonitor implements OnDestroy {
137168 this . _windowFocusTimeoutId = setTimeout ( ( ) => this . _windowFocused = false ) ;
138169 }
139170
140- /** Used to reference correct document/window */
141- protected _document ?: Document ;
171+ /** Used to reference correct document/window */
172+ protected _document ?: Document ;
142173
143- constructor ( private _ngZone : NgZone ,
144- private _platform : Platform ,
145- /** @breaking -change 11.0.0 make document required */
146- @Optional ( ) @Inject ( DOCUMENT ) document ?: any ) {
174+ constructor (
175+ private _ngZone : NgZone ,
176+ private _platform : Platform ,
177+ /** @breaking -change 11.0.0 make document required */
178+ @Optional ( ) @Inject ( DOCUMENT ) document : any | null ,
179+ @Optional ( ) @Inject ( FOCUS_MONITOR_DEFAULT_OPTIONS ) options :
180+ FocusMonitorOptions | null ) {
147181 this . _document = document ;
182+ this . _detectionMode = options ?. detectionMode || FocusMonitorDetectionMode . IMMEDIATE ;
148183 }
149184
150185 /**
@@ -306,15 +341,19 @@ export class FocusMonitor implements OnDestroy {
306341
307342 /**
308343 * Sets the origin and schedules an async function to clear it at the end of the event queue.
344+ * If the detection mode is 'eventual', the origin is never cleared.
309345 * @param origin The origin to set.
310346 */
311347 private _setOriginForCurrentEventQueue ( origin : FocusOrigin ) : void {
312348 this . _ngZone . runOutsideAngular ( ( ) => {
313349 this . _origin = origin ;
314- // Sometimes the focus origin won't be valid in Firefox because Firefox seems to focus *one*
315- // tick after the interaction event fired. To ensure the focus origin is always correct,
316- // the focus origin will be determined at the beginning of the next tick.
317- this . _originTimeoutId = setTimeout ( ( ) => this . _origin = null , 1 ) ;
350+
351+ if ( this . _detectionMode === FocusMonitorDetectionMode . IMMEDIATE ) {
352+ // Sometimes the focus origin won't be valid in Firefox because Firefox seems to focus *one*
353+ // tick after the interaction event fired. To ensure the focus origin is always correct,
354+ // the focus origin will be determined at the beginning of the next tick.
355+ this . _originTimeoutId = setTimeout ( ( ) => this . _origin = null , 1 ) ;
356+ }
318357 } ) ;
319358 }
320359
0 commit comments