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 { OverlayState } from './overlay-state' ;
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 _state : OverlayState ,
30- private _ngZone : NgZone ) {
31+ private _backdropHost : PortalHost | null ,
32+ private _state : OverlayState ) {
3133
3234 _state . scrollStrategy . attach ( this ) ;
3335 }
@@ -43,7 +45,7 @@ export class OverlayRef implements PortalHost {
4345 * @returns The portal attachment result.
4446 */
4547 attach ( portal : Portal < any > ) : any {
46- let attachResult = this . _portalHost . attach ( portal ) ;
48+ const attachResult = this . _portalHost . attach ( portal ) ;
4749
4850 if ( this . _state . positionStrategy ) {
4951 this . _state . positionStrategy . attach ( this ) ;
@@ -59,14 +61,15 @@ export class OverlayRef implements PortalHost {
5961 // Enable pointer events for the overlay pane element.
6062 this . _togglePointerEvents ( true ) ;
6163
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 ! ) ;
6467 }
6568
6669 if ( this . _state . panelClass ) {
6770 // We can't do a spread here, because IE doesn't support setting multiple classes.
6871 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 ) ) ;
7073 } else {
7174 this . _pane . classList . add ( this . _state . panelClass ) ;
7275 }
@@ -83,15 +86,17 @@ export class OverlayRef implements PortalHost {
8386 * @returns Resolves when the overlay has been detached.
8487 */
8588 detach ( ) : Promise < any > {
86- this . detachBackdrop ( ) ;
89+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
90+ this . _backdropHost . detach ( ) ;
91+ }
8792
8893 // When the overlay is detached, the pane element should disable pointer events.
8994 // This is necessary because otherwise the pane element will cover the page and disable
9095 // pointer events therefore. Depends on the position strategy and the applied pane boundaries.
9196 this . _togglePointerEvents ( false ) ;
9297 this . _state . scrollStrategy . disable ( ) ;
9398
94- let detachmentResult = this . _portalHost . detach ( ) ;
99+ const detachmentResult = this . _portalHost . detach ( ) ;
95100
96101 // Only emit after everything is detached.
97102 this . _detachments . next ( ) ;
@@ -108,10 +113,9 @@ export class OverlayRef implements PortalHost {
108113 }
109114
110115 this . _state . scrollStrategy . disable ( ) ;
111- this . detachBackdrop ( ) ;
116+ this . disposeBackdrop ( ) ;
112117 this . _portalHost . dispose ( ) ;
113118 this . _attachments . complete ( ) ;
114- this . _backdropClick . complete ( ) ;
115119 this . _detachments . next ( ) ;
116120 this . _detachments . complete ( ) ;
117121 }
@@ -127,7 +131,7 @@ export class OverlayRef implements PortalHost {
127131 * Returns an observable that emits when the backdrop has been clicked.
128132 */
129133 backdropClick ( ) : Observable < void > {
130- return this . _backdropClick . asObservable ( ) ;
134+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
131135 }
132136
133137 /** Returns an observable that emits when the overlay has been attached. */
@@ -191,31 +195,6 @@ export class OverlayRef implements PortalHost {
191195 this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
192196 }
193197
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-
219198 /**
220199 * Updates the stacking order of the element, moving it to the top if necessary.
221200 * This is required in cases where one overlay was detached, while another one,
@@ -229,43 +208,19 @@ export class OverlayRef implements PortalHost {
229208 }
230209 }
231210
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 ( ) ;
258216
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+ }
269224 }
270225 }
271226}
0 commit comments