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