@@ -11,12 +11,13 @@ import {
11
11
Directive ,
12
12
ElementRef ,
13
13
EventEmitter ,
14
+ Inject ,
14
15
Injectable ,
16
+ InjectionToken ,
15
17
NgZone ,
16
18
OnDestroy ,
17
- Output ,
18
19
Optional ,
19
- Inject ,
20
+ Output ,
20
21
} from '@angular/core' ;
21
22
import { Observable , of as observableOf , Subject , Subscription } from 'rxjs' ;
22
23
import { coerceElement } from '@angular/cdk/coercion' ;
@@ -39,6 +40,30 @@ export interface FocusOptions {
39
40
preventScroll ?: boolean ;
40
41
}
41
42
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
+
42
67
type MonitoredElementInfo = {
43
68
unlisten : Function ,
44
69
checkChildren : boolean ,
@@ -85,6 +110,12 @@ export class FocusMonitor implements OnDestroy {
85
110
/** The number of elements currently being monitored. */
86
111
private _monitoredElementCount = 0 ;
87
112
113
+ /**
114
+ * The specified detection mode, used for attributing the origin of a focus
115
+ * event.
116
+ */
117
+ private readonly _detectionMode : FocusMonitorDetectionMode ;
118
+
88
119
/**
89
120
* Event listener for `keydown` events on the document.
90
121
* 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 {
137
168
this . _windowFocusTimeoutId = setTimeout ( ( ) => this . _windowFocused = false ) ;
138
169
}
139
170
140
- /** Used to reference correct document/window */
141
- protected _document ?: Document ;
171
+ /** Used to reference correct document/window */
172
+ protected _document ?: Document ;
142
173
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 ) {
147
181
this . _document = document ;
182
+ this . _detectionMode = options ?. detectionMode || FocusMonitorDetectionMode . IMMEDIATE ;
148
183
}
149
184
150
185
/**
@@ -306,15 +341,19 @@ export class FocusMonitor implements OnDestroy {
306
341
307
342
/**
308
343
* 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.
309
345
* @param origin The origin to set.
310
346
*/
311
347
private _setOriginForCurrentEventQueue ( origin : FocusOrigin ) : void {
312
348
this . _ngZone . runOutsideAngular ( ( ) => {
313
349
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
+ }
318
357
} ) ;
319
358
}
320
359
0 commit comments