@@ -11,22 +11,25 @@ import {PortalHost, Portal} from '@angular/cdk/portal';
1111import { OverlayConfig } from './overlay-config' ;
1212import { Observable } from 'rxjs/Observable' ;
1313import { 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' ;
1518
1619
1720/**
1821 * Reference to an overlay that has been created with the Overlay service.
1922 * Used to manipulate or dispose of said overlay.
2023 */
2124export class OverlayRef implements PortalHost {
22- private _backdropElement : HTMLElement | null = null ;
23- private _backdropClick : Subject < any > = new Subject ( ) ;
2425 private _attachments = new Subject < void > ( ) ;
2526 private _detachments = new Subject < void > ( ) ;
27+ private _backdropInstance : MatBackdrop | null ;
2628
2729 constructor (
2830 private _portalHost : PortalHost ,
2931 private _pane : HTMLElement ,
32+ private _backdropHost : PortalHost | null ,
3033 private _config : OverlayConfig ,
3134 private _ngZone : NgZone ) {
3235
@@ -46,7 +49,7 @@ export class OverlayRef implements PortalHost {
4649 * @returns The portal attachment result.
4750 */
4851 attach ( portal : Portal < any > ) : any {
49- let attachResult = this . _portalHost . attach ( portal ) ;
52+ const attachResult = this . _portalHost . attach ( portal ) ;
5053
5154 if ( this . _config . positionStrategy ) {
5255 this . _config . positionStrategy . attach ( this ) ;
@@ -71,14 +74,15 @@ export class OverlayRef implements PortalHost {
7174 // Enable pointer events for the overlay pane element.
7275 this . _togglePointerEvents ( true ) ;
7376
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 ! ) ;
7680 }
7781
7882 if ( this . _config . panelClass ) {
7983 // We can't do a spread here, because IE doesn't support setting multiple classes.
8084 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 ) ) ;
8286 } else {
8387 this . _pane . classList . add ( this . _config . panelClass ) ;
8488 }
@@ -95,7 +99,9 @@ export class OverlayRef implements PortalHost {
9599 * @returns The portal detachment result.
96100 */
97101 detach ( ) : any {
98- this . detachBackdrop ( ) ;
102+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
103+ this . _backdropHost . detach ( ) ;
104+ }
99105
100106 // When the overlay is detached, the pane element should disable pointer events.
101107 // This is necessary because otherwise the pane element will cover the page and disable
@@ -130,10 +136,9 @@ export class OverlayRef implements PortalHost {
130136 this . _config . scrollStrategy . disable ( ) ;
131137 }
132138
133- this . detachBackdrop ( ) ;
139+ this . disposeBackdrop ( ) ;
134140 this . _portalHost . dispose ( ) ;
135141 this . _attachments . complete ( ) ;
136- this . _backdropClick . complete ( ) ;
137142 this . _detachments . next ( ) ;
138143 this . _detachments . complete ( ) ;
139144 }
@@ -149,7 +154,7 @@ export class OverlayRef implements PortalHost {
149154 * Returns an observable that emits when the backdrop has been clicked.
150155 */
151156 backdropClick ( ) : Observable < void > {
152- return this . _backdropClick . asObservable ( ) ;
157+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
153158 }
154159
155160 /** Returns an observable that emits when the overlay has been attached. */
@@ -213,31 +218,6 @@ export class OverlayRef implements PortalHost {
213218 this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
214219 }
215220
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-
241221 /**
242222 * Updates the stacking order of the element, moving it to the top if necessary.
243223 * This is required in cases where one overlay was detached, while another one,
@@ -251,43 +231,19 @@ export class OverlayRef implements PortalHost {
251231 }
252232 }
253233
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 ( ) ;
280239
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+ }
291247 }
292248 }
293249}
0 commit comments