@@ -11,22 +11,25 @@ import {PortalHost, Portal} from '@angular/cdk/portal';
11
11
import { OverlayConfig } from './overlay-config' ;
12
12
import { Observable } from 'rxjs/Observable' ;
13
13
import { Subject } from 'rxjs/Subject' ;
14
- import { first } from 'rxjs/operator/first' ;
14
+ import { MatBackdrop } from './backdrop' ;
15
+ import { ComponentPortal } from '@angular/cdk/portal' ;
16
+ import { first } from '@angular/cdk/rxjs' ;
17
+ import { empty } from 'rxjs/observable/empty' ;
15
18
16
19
17
20
/**
18
21
* Reference to an overlay that has been created with the Overlay service.
19
22
* Used to manipulate or dispose of said overlay.
20
23
*/
21
24
export class OverlayRef implements PortalHost {
22
- private _backdropElement : HTMLElement | null = null ;
23
- private _backdropClick : Subject < any > = new Subject ( ) ;
24
25
private _attachments = new Subject < void > ( ) ;
25
26
private _detachments = new Subject < void > ( ) ;
27
+ private _backdropInstance : MatBackdrop | null ;
26
28
27
29
constructor (
28
30
private _portalHost : PortalHost ,
29
31
private _pane : HTMLElement ,
32
+ private _backdropHost : PortalHost | null ,
30
33
private _config : OverlayConfig ,
31
34
private _ngZone : NgZone ) {
32
35
@@ -46,7 +49,7 @@ export class OverlayRef implements PortalHost {
46
49
* @returns The portal attachment result.
47
50
*/
48
51
attach ( portal : Portal < any > ) : any {
49
- let attachResult = this . _portalHost . attach ( portal ) ;
52
+ const attachResult = this . _portalHost . attach ( portal ) ;
50
53
51
54
if ( this . _config . positionStrategy ) {
52
55
this . _config . positionStrategy . attach ( this ) ;
@@ -71,14 +74,15 @@ export class OverlayRef implements PortalHost {
71
74
// Enable pointer events for the overlay pane element.
72
75
this . _togglePointerEvents ( true ) ;
73
76
74
- if ( this . _config . hasBackdrop ) {
75
- this . _attachBackdrop ( ) ;
77
+ if ( this . _backdropHost ) {
78
+ this . _backdropInstance = this . _backdropHost . attach ( new ComponentPortal ( MatBackdrop ) ) . instance ;
79
+ this . _backdropInstance ! . _setClass ( this . _config . backdropClass ! ) ;
76
80
}
77
81
78
82
if ( this . _config . panelClass ) {
79
83
// We can't do a spread here, because IE doesn't support setting multiple classes.
80
84
if ( Array . isArray ( this . _config . panelClass ) ) {
81
- this . _config . panelClass . forEach ( cls => this . _pane . classList . add ( cls ) ) ;
85
+ this . _config . panelClass . forEach ( cssClass => this . _pane . classList . add ( cssClass ) ) ;
82
86
} else {
83
87
this . _pane . classList . add ( this . _config . panelClass ) ;
84
88
}
@@ -95,7 +99,9 @@ export class OverlayRef implements PortalHost {
95
99
* @returns The portal detachment result.
96
100
*/
97
101
detach ( ) : any {
98
- this . detachBackdrop ( ) ;
102
+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
103
+ this . _backdropHost . detach ( ) ;
104
+ }
99
105
100
106
// When the overlay is detached, the pane element should disable pointer events.
101
107
// This is necessary because otherwise the pane element will cover the page and disable
@@ -130,10 +136,9 @@ export class OverlayRef implements PortalHost {
130
136
this . _config . scrollStrategy . disable ( ) ;
131
137
}
132
138
133
- this . detachBackdrop ( ) ;
139
+ this . disposeBackdrop ( ) ;
134
140
this . _portalHost . dispose ( ) ;
135
141
this . _attachments . complete ( ) ;
136
- this . _backdropClick . complete ( ) ;
137
142
this . _detachments . next ( ) ;
138
143
this . _detachments . complete ( ) ;
139
144
}
@@ -149,7 +154,7 @@ export class OverlayRef implements PortalHost {
149
154
* Returns an observable that emits when the backdrop has been clicked.
150
155
*/
151
156
backdropClick ( ) : Observable < void > {
152
- return this . _backdropClick . asObservable ( ) ;
157
+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
153
158
}
154
159
155
160
/** Returns an observable that emits when the overlay has been attached. */
@@ -213,31 +218,6 @@ export class OverlayRef implements PortalHost {
213
218
this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
214
219
}
215
220
216
- /** Attaches a backdrop for this overlay. */
217
- private _attachBackdrop ( ) {
218
- this . _backdropElement = document . createElement ( 'div' ) ;
219
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
220
-
221
- if ( this . _config . backdropClass ) {
222
- this . _backdropElement . classList . add ( this . _config . backdropClass ) ;
223
- }
224
-
225
- // Insert the backdrop before the pane in the DOM order,
226
- // in order to handle stacked overlays properly.
227
- this . _pane . parentElement ! . insertBefore ( this . _backdropElement , this . _pane ) ;
228
-
229
- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
230
- // action desired when such a click occurs (usually closing the overlay).
231
- this . _backdropElement . addEventListener ( 'click' , ( ) => this . _backdropClick . next ( null ) ) ;
232
-
233
- // Add class to fade-in the backdrop after one frame.
234
- requestAnimationFrame ( ( ) => {
235
- if ( this . _backdropElement ) {
236
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop-showing' ) ;
237
- }
238
- } ) ;
239
- }
240
-
241
221
/**
242
222
* Updates the stacking order of the element, moving it to the top if necessary.
243
223
* This is required in cases where one overlay was detached, while another one,
@@ -251,43 +231,19 @@ export class OverlayRef implements PortalHost {
251
231
}
252
232
}
253
233
254
- /** Detaches the backdrop (if any) associated with the overlay. */
255
- detachBackdrop ( ) : void {
256
- let backdropToDetach = this . _backdropElement ;
257
-
258
- if ( backdropToDetach ) {
259
- let finishDetach = ( ) => {
260
- // It may not be attached to anything in certain cases (e.g. unit tests).
261
- if ( backdropToDetach && backdropToDetach . parentNode ) {
262
- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
263
- }
264
-
265
- // It is possible that a new portal has been attached to this overlay since we started
266
- // removing the backdrop. If that is the case, only clear the backdrop reference if it
267
- // is still the same instance that we started to remove.
268
- if ( this . _backdropElement == backdropToDetach ) {
269
- this . _backdropElement = null ;
270
- }
271
- } ;
272
-
273
- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
274
-
275
- if ( this . _config . backdropClass ) {
276
- backdropToDetach . classList . remove ( this . _config . backdropClass ) ;
277
- }
278
-
279
- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
234
+ /** Animates out and disposes of the backdrop. */
235
+ disposeBackdrop ( ) : void {
236
+ if ( this . _backdropHost ) {
237
+ if ( this . _backdropHost . hasAttached ( ) ) {
238
+ this . _backdropHost . detach ( ) ;
280
239
281
- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
282
- // In this case we make it unclickable and we try to remove it after a delay.
283
- backdropToDetach . style . pointerEvents = 'none' ;
284
-
285
- // Run this outside the Angular zone because there's nothing that Angular cares about.
286
- // If it were to run inside the Angular zone, every test that used Overlay would have to be
287
- // either async or fakeAsync.
288
- this . _ngZone . runOutsideAngular ( ( ) => {
289
- setTimeout ( finishDetach , 500 ) ;
290
- } ) ;
240
+ first . call ( this . _backdropInstance ! . _animationStream ) . subscribe ( ( ) => {
241
+ this . _backdropHost ! . dispose ( ) ;
242
+ this . _backdropHost = this . _backdropInstance = null ;
243
+ } ) ;
244
+ } else {
245
+ this . _backdropHost . dispose ( ) ;
246
+ }
291
247
}
292
248
}
293
249
}
0 commit comments