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 { OverlayState } from './overlay-state' ;
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 _state : OverlayState ,
30
- private _ngZone : NgZone ) {
31
+ private _backdropHost : PortalHost | null ,
32
+ private _state : OverlayState ) {
31
33
32
34
_state . scrollStrategy . attach ( this ) ;
33
35
}
@@ -43,7 +45,7 @@ export class OverlayRef implements PortalHost {
43
45
* @returns The portal attachment result.
44
46
*/
45
47
attach ( portal : Portal < any > ) : any {
46
- let attachResult = this . _portalHost . attach ( portal ) ;
48
+ const attachResult = this . _portalHost . attach ( portal ) ;
47
49
48
50
if ( this . _state . positionStrategy ) {
49
51
this . _state . positionStrategy . attach ( this ) ;
@@ -59,14 +61,15 @@ export class OverlayRef implements PortalHost {
59
61
// Enable pointer events for the overlay pane element.
60
62
this . _togglePointerEvents ( true ) ;
61
63
62
- if ( this . _state . hasBackdrop ) {
63
- this . _attachBackdrop ( ) ;
64
+ if ( this . _backdropHost ) {
65
+ this . _backdropInstance = this . _backdropHost . attach ( new ComponentPortal ( MdBackdrop ) ) . instance ;
66
+ this . _backdropInstance ! . _setClass ( this . _state . backdropClass ! ) ;
64
67
}
65
68
66
69
if ( this . _state . panelClass ) {
67
70
// We can't do a spread here, because IE doesn't support setting multiple classes.
68
71
if ( Array . isArray ( this . _state . panelClass ) ) {
69
- this . _state . panelClass . forEach ( cls => this . _pane . classList . add ( cls ) ) ;
72
+ this . _state . panelClass . forEach ( cssClass => this . _pane . classList . add ( cssClass ) ) ;
70
73
} else {
71
74
this . _pane . classList . add ( this . _state . panelClass ) ;
72
75
}
@@ -83,15 +86,17 @@ export class OverlayRef implements PortalHost {
83
86
* @returns Resolves when the overlay has been detached.
84
87
*/
85
88
detach ( ) : Promise < any > {
86
- this . detachBackdrop ( ) ;
89
+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
90
+ this . _backdropHost . detach ( ) ;
91
+ }
87
92
88
93
// When the overlay is detached, the pane element should disable pointer events.
89
94
// This is necessary because otherwise the pane element will cover the page and disable
90
95
// pointer events therefore. Depends on the position strategy and the applied pane boundaries.
91
96
this . _togglePointerEvents ( false ) ;
92
97
this . _state . scrollStrategy . disable ( ) ;
93
98
94
- let detachmentResult = this . _portalHost . detach ( ) ;
99
+ const detachmentResult = this . _portalHost . detach ( ) ;
95
100
96
101
// Only emit after everything is detached.
97
102
this . _detachments . next ( ) ;
@@ -108,10 +113,9 @@ export class OverlayRef implements PortalHost {
108
113
}
109
114
110
115
this . _state . scrollStrategy . disable ( ) ;
111
- this . detachBackdrop ( ) ;
116
+ this . disposeBackdrop ( ) ;
112
117
this . _portalHost . dispose ( ) ;
113
118
this . _attachments . complete ( ) ;
114
- this . _backdropClick . complete ( ) ;
115
119
this . _detachments . next ( ) ;
116
120
this . _detachments . complete ( ) ;
117
121
}
@@ -127,7 +131,7 @@ export class OverlayRef implements PortalHost {
127
131
* Returns an observable that emits when the backdrop has been clicked.
128
132
*/
129
133
backdropClick ( ) : Observable < void > {
130
- return this . _backdropClick . asObservable ( ) ;
134
+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
131
135
}
132
136
133
137
/** Returns an observable that emits when the overlay has been attached. */
@@ -191,31 +195,6 @@ export class OverlayRef implements PortalHost {
191
195
this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
192
196
}
193
197
194
- /** Attaches a backdrop for this overlay. */
195
- private _attachBackdrop ( ) {
196
- this . _backdropElement = document . createElement ( 'div' ) ;
197
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
198
-
199
- if ( this . _state . backdropClass ) {
200
- this . _backdropElement . classList . add ( this . _state . backdropClass ) ;
201
- }
202
-
203
- // Insert the backdrop before the pane in the DOM order,
204
- // in order to handle stacked overlays properly.
205
- this . _pane . parentElement ! . insertBefore ( this . _backdropElement , this . _pane ) ;
206
-
207
- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
208
- // action desired when such a click occurs (usually closing the overlay).
209
- this . _backdropElement . addEventListener ( 'click' , ( ) => this . _backdropClick . next ( null ) ) ;
210
-
211
- // Add class to fade-in the backdrop after one frame.
212
- requestAnimationFrame ( ( ) => {
213
- if ( this . _backdropElement ) {
214
- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop-showing' ) ;
215
- }
216
- } ) ;
217
- }
218
-
219
198
/**
220
199
* Updates the stacking order of the element, moving it to the top if necessary.
221
200
* This is required in cases where one overlay was detached, while another one,
@@ -229,43 +208,19 @@ export class OverlayRef implements PortalHost {
229
208
}
230
209
}
231
210
232
- /** Detaches the backdrop (if any) associated with the overlay. */
233
- detachBackdrop ( ) : void {
234
- let backdropToDetach = this . _backdropElement ;
235
-
236
- if ( backdropToDetach ) {
237
- let finishDetach = ( ) => {
238
- // It may not be attached to anything in certain cases (e.g. unit tests).
239
- if ( backdropToDetach && backdropToDetach . parentNode ) {
240
- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
241
- }
242
-
243
- // It is possible that a new portal has been attached to this overlay since we started
244
- // removing the backdrop. If that is the case, only clear the backdrop reference if it
245
- // is still the same instance that we started to remove.
246
- if ( this . _backdropElement == backdropToDetach ) {
247
- this . _backdropElement = null ;
248
- }
249
- } ;
250
-
251
- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
252
-
253
- if ( this . _state . backdropClass ) {
254
- backdropToDetach . classList . remove ( this . _state . backdropClass ) ;
255
- }
256
-
257
- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
211
+ /** Animates out and disposes of the backdrop. */
212
+ disposeBackdrop ( ) : void {
213
+ if ( this . _backdropHost ) {
214
+ if ( this . _backdropHost . hasAttached ( ) ) {
215
+ this . _backdropHost . detach ( ) ;
258
216
259
- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
260
- // In this case we make it unclickable and we try to remove it after a delay.
261
- backdropToDetach . style . pointerEvents = 'none' ;
262
-
263
- // Run this outside the Angular zone because there's nothing that Angular cares about.
264
- // If it were to run inside the Angular zone, every test that used Overlay would have to be
265
- // either async or fakeAsync.
266
- this . _ngZone . runOutsideAngular ( ( ) => {
267
- setTimeout ( finishDetach , 500 ) ;
268
- } ) ;
217
+ first . call ( this . _backdropInstance ! . _animationStream ) . subscribe ( ( ) => {
218
+ this . _backdropHost ! . dispose ( ) ;
219
+ this . _backdropHost = this . _backdropInstance = null ;
220
+ } ) ;
221
+ } else {
222
+ this . _backdropHost . dispose ( ) ;
223
+ }
269
224
}
270
225
}
271
226
}
0 commit comments