66 * found in the LICENSE file at https://angular.io/license
77 */
88
9- import { NgZone } from '@angular/core' ;
109import { PortalHost , Portal } from '@angular/cdk/portal' ;
1110import { OverlayConfig } from './overlay-config' ;
1211import { Observable } from 'rxjs/Observable' ;
1312import { 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' ;
1417
1518
1619/**
1720 * Reference to an overlay that has been created with the Overlay service.
1821 * Used to manipulate or dispose of said overlay.
1922 */
2023export class OverlayRef implements PortalHost {
21- private _backdropElement : HTMLElement | null = null ;
22- private _backdropClick : Subject < any > = new Subject ( ) ;
2324 private _attachments = new Subject < void > ( ) ;
2425 private _detachments = new Subject < void > ( ) ;
26+ private _backdropInstance : MdBackdrop | null ;
2527
2628 constructor (
2729 private _portalHost : PortalHost ,
2830 private _pane : HTMLElement ,
29- private _config : OverlayConfig ,
30- private _ngZone : NgZone ) {
31+ private _backdropHost : PortalHost | null ,
32+ private _config : OverlayConfig ) {
3133
3234 if ( _config . scrollStrategy ) {
3335 _config . scrollStrategy . attach ( this ) ;
@@ -45,7 +47,7 @@ export class OverlayRef implements PortalHost {
4547 * @returns The portal attachment result.
4648 */
4749 attach ( portal : Portal < any > ) : any {
48- let attachResult = this . _portalHost . attach ( portal ) ;
50+ const attachResult = this . _portalHost . attach ( portal ) ;
4951
5052 if ( this . _config . positionStrategy ) {
5153 this . _config . positionStrategy . attach ( this ) ;
@@ -64,14 +66,15 @@ export class OverlayRef implements PortalHost {
6466 // Enable pointer events for the overlay pane element.
6567 this . _togglePointerEvents ( true ) ;
6668
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 ! ) ;
6972 }
7073
7174 if ( this . _config . panelClass ) {
7275 // We can't do a spread here, because IE doesn't support setting multiple classes.
7376 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 ) ) ;
7578 } else {
7679 this . _pane . classList . add ( this . _config . panelClass ) ;
7780 }
@@ -88,7 +91,9 @@ export class OverlayRef implements PortalHost {
8891 * @returns The portal detachment result.
8992 */
9093 detach ( ) : any {
91- this . detachBackdrop ( ) ;
94+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
95+ this . _backdropHost . detach ( ) ;
96+ }
9297
9398 // When the overlay is detached, the pane element should disable pointer events.
9499 // This is necessary because otherwise the pane element will cover the page and disable
@@ -123,10 +128,9 @@ export class OverlayRef implements PortalHost {
123128 this . _config . scrollStrategy . disable ( ) ;
124129 }
125130
126- this . detachBackdrop ( ) ;
131+ this . disposeBackdrop ( ) ;
127132 this . _portalHost . dispose ( ) ;
128133 this . _attachments . complete ( ) ;
129- this . _backdropClick . complete ( ) ;
130134 this . _detachments . next ( ) ;
131135 this . _detachments . complete ( ) ;
132136 }
@@ -142,7 +146,7 @@ export class OverlayRef implements PortalHost {
142146 * Returns an observable that emits when the backdrop has been clicked.
143147 */
144148 backdropClick ( ) : Observable < void > {
145- return this . _backdropClick . asObservable ( ) ;
149+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
146150 }
147151
148152 /** Returns an observable that emits when the overlay has been attached. */
@@ -206,31 +210,6 @@ export class OverlayRef implements PortalHost {
206210 this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
207211 }
208212
209- /** Attaches a backdrop for this overlay. */
210- private _attachBackdrop ( ) {
211- this . _backdropElement = document . createElement ( 'div' ) ;
212- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
213-
214- if ( this . _config . backdropClass ) {
215- this . _backdropElement . classList . add ( this . _config . backdropClass ) ;
216- }
217-
218- // Insert the backdrop before the pane in the DOM order,
219- // in order to handle stacked overlays properly.
220- this . _pane . parentElement ! . insertBefore ( this . _backdropElement , this . _pane ) ;
221-
222- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
223- // action desired when such a click occurs (usually closing the overlay).
224- this . _backdropElement . addEventListener ( 'click' , ( ) => this . _backdropClick . next ( null ) ) ;
225-
226- // Add class to fade-in the backdrop after one frame.
227- requestAnimationFrame ( ( ) => {
228- if ( this . _backdropElement ) {
229- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop-showing' ) ;
230- }
231- } ) ;
232- }
233-
234213 /**
235214 * Updates the stacking order of the element, moving it to the top if necessary.
236215 * This is required in cases where one overlay was detached, while another one,
@@ -244,43 +223,19 @@ export class OverlayRef implements PortalHost {
244223 }
245224 }
246225
247- /** Detaches the backdrop (if any) associated with the overlay. */
248- detachBackdrop ( ) : void {
249- let backdropToDetach = this . _backdropElement ;
250-
251- if ( backdropToDetach ) {
252- let finishDetach = ( ) => {
253- // It may not be attached to anything in certain cases (e.g. unit tests).
254- if ( backdropToDetach && backdropToDetach . parentNode ) {
255- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
256- }
257-
258- // It is possible that a new portal has been attached to this overlay since we started
259- // removing the backdrop. If that is the case, only clear the backdrop reference if it
260- // is still the same instance that we started to remove.
261- if ( this . _backdropElement == backdropToDetach ) {
262- this . _backdropElement = null ;
263- }
264- } ;
265-
266- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
267-
268- if ( this . _config . backdropClass ) {
269- backdropToDetach . classList . remove ( this . _config . backdropClass ) ;
270- }
271-
272- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
226+ /** Animates out and disposes of the backdrop. */
227+ disposeBackdrop ( ) : void {
228+ if ( this . _backdropHost ) {
229+ if ( this . _backdropHost . hasAttached ( ) ) {
230+ this . _backdropHost . detach ( ) ;
273231
274- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
275- // In this case we make it unclickable and we try to remove it after a delay.
276- backdropToDetach . style . pointerEvents = 'none' ;
277-
278- // Run this outside the Angular zone because there's nothing that Angular cares about.
279- // If it were to run inside the Angular zone, every test that used Overlay would have to be
280- // either async or fakeAsync.
281- this . _ngZone . runOutsideAngular ( ( ) => {
282- setTimeout ( finishDetach , 500 ) ;
283- } ) ;
232+ first . call ( this . _backdropInstance ! . _animationStream ) . subscribe ( ( ) => {
233+ this . _backdropHost ! . dispose ( ) ;
234+ this . _backdropHost = this . _backdropInstance = null ;
235+ } ) ;
236+ } else {
237+ this . _backdropHost . dispose ( ) ;
238+ }
284239 }
285240 }
286241}
0 commit comments