9
9
import { Direction } from '@angular/cdk/bidi' ;
10
10
import { ComponentPortal , Portal , PortalOutlet , TemplatePortal } from '@angular/cdk/portal' ;
11
11
import { ComponentRef , EmbeddedViewRef , NgZone } from '@angular/core' ;
12
- import { Observable , Subject } from 'rxjs' ;
12
+ import { Observable , Subject , empty } from 'rxjs' ;
13
13
import { take } from 'rxjs/operators' ;
14
14
import { OverlayKeyboardDispatcher } from './keyboard/overlay-keyboard-dispatcher' ;
15
15
import { OverlayConfig } from './overlay-config' ;
16
+ import { CdkOverlayBackdrop } from './backdrop' ;
16
17
17
18
18
19
/** An object where all of its properties cannot be written. */
@@ -25,10 +26,10 @@ export type ImmutableObject<T> = {
25
26
* Used to manipulate or dispose of said overlay.
26
27
*/
27
28
export class OverlayRef implements PortalOutlet {
28
- private _backdropElement : HTMLElement | null = null ;
29
- private _backdropClick : Subject < MouseEvent > = new Subject ( ) ;
29
+ private _backdropClick = new Subject < MouseEvent > ( ) ;
30
30
private _attachments = new Subject < void > ( ) ;
31
31
private _detachments = new Subject < void > ( ) ;
32
+ private _backdropInstance : CdkOverlayBackdrop | null ;
32
33
33
34
/** Stream of keydown events dispatched to this overlay. */
34
35
_keydownEvents = new Subject < KeyboardEvent > ( ) ;
@@ -37,10 +38,10 @@ export class OverlayRef implements PortalOutlet {
37
38
private _portalOutlet : PortalOutlet ,
38
39
private _host : HTMLElement ,
39
40
private _pane : HTMLElement ,
41
+ private _backdropHost : PortalOutlet | null ,
40
42
private _config : ImmutableObject < OverlayConfig > ,
41
43
private _ngZone : NgZone ,
42
- private _keyboardDispatcher : OverlayKeyboardDispatcher ,
43
- private _document : Document ) {
44
+ private _keyboardDispatcher : OverlayKeyboardDispatcher ) {
44
45
45
46
if ( _config . scrollStrategy ) {
46
47
_config . scrollStrategy . attach ( this ) ;
@@ -54,7 +55,7 @@ export class OverlayRef implements PortalOutlet {
54
55
55
56
/** The overlay's backdrop HTML element. */
56
57
get backdropElement ( ) : HTMLElement | null {
57
- return this . _backdropElement ;
58
+ return this . _backdropInstance ? this . _backdropInstance . _element . nativeElement : null ;
58
59
}
59
60
60
61
/**
@@ -78,7 +79,7 @@ export class OverlayRef implements PortalOutlet {
78
79
* @returns The portal attachment result.
79
80
*/
80
81
attach ( portal : Portal < any > ) : any {
81
- let attachResult = this . _portalOutlet . attach ( portal ) ;
82
+ const attachResult = this . _portalOutlet . attach ( portal ) ;
82
83
83
84
if ( this . _config . positionStrategy ) {
84
85
this . _config . positionStrategy . attach ( this ) ;
@@ -109,8 +110,10 @@ export class OverlayRef implements PortalOutlet {
109
110
// Enable pointer events for the overlay pane element.
110
111
this . _togglePointerEvents ( true ) ;
111
112
112
- if ( this . _config . hasBackdrop ) {
113
- this . _attachBackdrop ( ) ;
113
+ if ( this . _backdropHost ) {
114
+ this . _backdropInstance =
115
+ this . _backdropHost . attach ( new ComponentPortal ( CdkOverlayBackdrop ) ) . instance ;
116
+ this . _backdropInstance ! . _setClass ( this . _config . backdropClass ! ) ;
114
117
}
115
118
116
119
if ( this . _config . panelClass ) {
@@ -140,7 +143,9 @@ export class OverlayRef implements PortalOutlet {
140
143
return ;
141
144
}
142
145
143
- this . detachBackdrop ( ) ;
146
+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
147
+ this . _backdropHost . detach ( ) ;
148
+ }
144
149
145
150
// When the overlay is detached, the pane element should disable pointer events.
146
151
// This is necessary because otherwise the pane element will cover the page and disable
@@ -178,7 +183,7 @@ export class OverlayRef implements PortalOutlet {
178
183
this . _config . scrollStrategy . disable ( ) ;
179
184
}
180
185
181
- this . detachBackdrop ( ) ;
186
+ this . disposeBackdrop ( ) ;
182
187
this . _keyboardDispatcher . remove ( this ) ;
183
188
this . _portalOutlet . dispose ( ) ;
184
189
this . _attachments . complete ( ) ;
@@ -204,7 +209,7 @@ export class OverlayRef implements PortalOutlet {
204
209
205
210
/** Gets an observable that emits when the backdrop has been clicked. */
206
211
backdropClick ( ) : Observable < MouseEvent > {
207
- return this . _backdropClick . asObservable ( ) ;
212
+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty ( ) ;
208
213
}
209
214
210
215
/** Gets an observable that emits when the overlay has been attached. */
@@ -283,40 +288,6 @@ export class OverlayRef implements PortalOutlet {
283
288
this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
284
289
}
285
290
286
- /** Attaches a backdrop for this overlay. */
287
- private _attachBackdrop ( ) {
288
- const showingClass = 'cdk-overlay-backdrop-showing' ;
289
-
290
- this . _backdropElement = this . _document . createElement ( 'div' ) ;
291
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
292
-
293
- if ( this . _config . backdropClass ) {
294
- this . _backdropElement . classList . add ( this . _config . backdropClass ) ;
295
- }
296
-
297
- // Insert the backdrop before the pane in the DOM order,
298
- // in order to handle stacked overlays properly.
299
- this . _host . parentElement ! . insertBefore ( this . _backdropElement , this . _host ) ;
300
-
301
- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
302
- // action desired when such a click occurs (usually closing the overlay).
303
- this . _backdropElement . addEventListener ( 'click' ,
304
- ( event : MouseEvent ) => this . _backdropClick . next ( event ) ) ;
305
-
306
- // Add class to fade-in the backdrop after one frame.
307
- if ( typeof requestAnimationFrame !== 'undefined' ) {
308
- this . _ngZone . runOutsideAngular ( ( ) => {
309
- requestAnimationFrame ( ( ) => {
310
- if ( this . _backdropElement ) {
311
- this . _backdropElement . classList . add ( showingClass ) ;
312
- }
313
- } ) ;
314
- } ) ;
315
- } else {
316
- this . _backdropElement . classList . add ( showingClass ) ;
317
- }
318
- }
319
-
320
291
/**
321
292
* Updates the stacking order of the element, moving it to the top if necessary.
322
293
* This is required in cases where one overlay was detached, while another one,
@@ -330,43 +301,30 @@ export class OverlayRef implements PortalOutlet {
330
301
}
331
302
}
332
303
333
- /** Detaches the backdrop (if any) associated with the overlay. */
334
- detachBackdrop ( ) : void {
335
- let backdropToDetach = this . _backdropElement ;
336
-
337
- if ( backdropToDetach ) {
338
- let finishDetach = ( ) => {
339
- // It may not be attached to anything in certain cases (e.g. unit tests).
340
- if ( backdropToDetach && backdropToDetach . parentNode ) {
341
- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
342
- }
343
-
344
- // It is possible that a new portal has been attached to this overlay since we started
345
- // removing the backdrop. If that is the case, only clear the backdrop reference if it
346
- // is still the same instance that we started to remove.
347
- if ( this . _backdropElement == backdropToDetach ) {
348
- this . _backdropElement = null ;
349
- }
350
- } ;
351
-
352
- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
304
+ /** Animates out and disposes of the backdrop. */
305
+ disposeBackdrop ( ) : void {
306
+ if ( this . _backdropHost ) {
307
+ if ( this . _backdropHost . hasAttached ( ) ) {
308
+ this . _backdropHost . detach ( ) ;
353
309
354
- if ( this . _config . backdropClass ) {
355
- backdropToDetach . classList . remove ( this . _config . backdropClass ) ;
310
+ this . _backdropInstance ! . _animationStream . pipe ( take ( 1 ) ) . subscribe ( ( ) => {
311
+ this . _backdropHost ! . dispose ( ) ;
312
+ this . _backdropHost = this . _backdropInstance = null ;
313
+ } ) ;
314
+ } else {
315
+ this . _backdropHost . dispose ( ) ;
356
316
}
357
-
358
- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
359
-
360
- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
361
- // In this case we make it unclickable and we try to remove it after a delay.
362
- backdropToDetach . style . pointerEvents = 'none' ;
363
-
364
- // Run this outside the Angular zone because there's nothing that Angular cares about.
365
- // If it were to run inside the Angular zone, every test that used Overlay would have to be
366
- // either async or fakeAsync.
367
- this . _ngZone . runOutsideAngular ( ( ) => setTimeout ( finishDetach , 500 ) ) ;
368
317
}
369
318
}
319
+
320
+ /**
321
+ * Detaches the backdrop (if any) associated with the overlay.
322
+ * @deprecated Use `disposeBackdrop` instead.
323
+ * @deletion -target 7.0.0
324
+ */
325
+ detachBackdrop ( ) : void {
326
+ this . disposeBackdrop ( ) ;
327
+ }
370
328
}
371
329
372
330
function formatCssUnit ( value : number | string ) {
0 commit comments