@@ -12,25 +12,28 @@ import {OverlayConfig} from './overlay-config';
1212import { OverlayKeyboardDispatcher } from './keyboard/overlay-keyboard-dispatcher' ;
1313import { Observable } from 'rxjs/Observable' ;
1414import { Subject } from 'rxjs/Subject' ;
15+ import { MatBackdrop } from './backdrop' ;
16+ import { ComponentPortal } from '@angular/cdk/portal' ;
1517import { take } from 'rxjs/operators/take' ;
16-
18+ import { empty } from 'rxjs/observable/empty' ;
1719
1820/**
1921 * Reference to an overlay that has been created with the Overlay service.
2022 * Used to manipulate or dispose of said overlay.
2123 */
2224export class OverlayRef implements PortalOutlet {
23- private _backdropElement : HTMLElement | null = null ;
2425 private _backdropClick : Subject < any > = new Subject ( ) ;
2526 private _attachments = new Subject < void > ( ) ;
2627 private _detachments = new Subject < void > ( ) ;
28+ private _backdropInstance : MatBackdrop | null ;
2729
2830 /** Stream of keydown events dispatched to this overlay. */
2931 _keydownEvents = new Subject < KeyboardEvent > ( ) ;
3032
3133 constructor (
3234 private _portalOutlet : PortalOutlet ,
3335 private _pane : HTMLElement ,
36+ private _backdropHost : PortalOutlet | null ,
3437 private _config : OverlayConfig ,
3538 private _ngZone : NgZone ,
3639 private _keyboardDispatcher : OverlayKeyboardDispatcher ) {
@@ -51,7 +54,7 @@ export class OverlayRef implements PortalOutlet {
5154 * @returns The portal attachment result.
5255 */
5356 attach ( portal : Portal < any > ) : any {
54- let attachResult = this . _portalOutlet . attach ( portal ) ;
57+ const attachResult = this . _portalOutlet . attach ( portal ) ;
5558
5659 if ( this . _config . positionStrategy ) {
5760 this . _config . positionStrategy . attach ( this ) ;
@@ -76,14 +79,15 @@ export class OverlayRef implements PortalOutlet {
7679 // Enable pointer events for the overlay pane element.
7780 this . _togglePointerEvents ( true ) ;
7881
79- if ( this . _config . hasBackdrop ) {
80- this . _attachBackdrop ( ) ;
82+ if ( this . _backdropHost ) {
83+ this . _backdropInstance = this . _backdropHost . attach ( new ComponentPortal ( MatBackdrop ) ) . instance ;
84+ this . _backdropInstance ! . _setClass ( this . _config . backdropClass ! ) ;
8185 }
8286
8387 if ( this . _config . panelClass ) {
8488 // We can't do a spread here, because IE doesn't support setting multiple classes.
8589 if ( Array . isArray ( this . _config . panelClass ) ) {
86- this . _config . panelClass . forEach ( cls => this . _pane . classList . add ( cls ) ) ;
90+ this . _config . panelClass . forEach ( cssClass => this . _pane . classList . add ( cssClass ) ) ;
8791 } else {
8892 this . _pane . classList . add ( this . _config . panelClass ) ;
8993 }
@@ -107,7 +111,9 @@ export class OverlayRef implements PortalOutlet {
107111 return ;
108112 }
109113
110- this . detachBackdrop ( ) ;
114+ if ( this . _backdropHost && this . _backdropHost . hasAttached ( ) ) {
115+ this . _backdropHost . detach ( ) ;
116+ }
111117
112118 // When the overlay is detached, the pane element should disable pointer events.
113119 // This is necessary because otherwise the pane element will cover the page and disable
@@ -147,7 +153,7 @@ export class OverlayRef implements PortalOutlet {
147153 this . _config . scrollStrategy . disable ( ) ;
148154 }
149155
150- this . detachBackdrop ( ) ;
156+ this . disposeBackdrop ( ) ;
151157 this . _keyboardDispatcher . remove ( this ) ;
152158 this . _portalOutlet . dispose ( ) ;
153159 this . _attachments . complete ( ) ;
@@ -172,7 +178,7 @@ export class OverlayRef implements PortalOutlet {
172178 * Gets an observable that emits when the backdrop has been clicked.
173179 */
174180 backdropClick ( ) : Observable < void > {
175- return this . _backdropClick . asObservable ( ) ;
181+ return this . _backdropInstance ? this . _backdropInstance . _clickStream : empty < void > ( ) ;
176182 }
177183
178184 /** Gets an observable that emits when the overlay has been attached. */
@@ -241,31 +247,6 @@ export class OverlayRef implements PortalOutlet {
241247 this . _pane . style . pointerEvents = enablePointer ? 'auto' : 'none' ;
242248 }
243249
244- /** Attaches a backdrop for this overlay. */
245- private _attachBackdrop ( ) {
246- this . _backdropElement = document . createElement ( 'div' ) ;
247- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop' ) ;
248-
249- if ( this . _config . backdropClass ) {
250- this . _backdropElement . classList . add ( this . _config . backdropClass ) ;
251- }
252-
253- // Insert the backdrop before the pane in the DOM order,
254- // in order to handle stacked overlays properly.
255- this . _pane . parentElement ! . insertBefore ( this . _backdropElement , this . _pane ) ;
256-
257- // Forward backdrop clicks such that the consumer of the overlay can perform whatever
258- // action desired when such a click occurs (usually closing the overlay).
259- this . _backdropElement . addEventListener ( 'click' , ( ) => this . _backdropClick . next ( null ) ) ;
260-
261- // Add class to fade-in the backdrop after one frame.
262- requestAnimationFrame ( ( ) => {
263- if ( this . _backdropElement ) {
264- this . _backdropElement . classList . add ( 'cdk-overlay-backdrop-showing' ) ;
265- }
266- } ) ;
267- }
268-
269250 /**
270251 * Updates the stacking order of the element, moving it to the top if necessary.
271252 * This is required in cases where one overlay was detached, while another one,
@@ -279,45 +260,29 @@ export class OverlayRef implements PortalOutlet {
279260 }
280261 }
281262
282- /** Detaches the backdrop (if any) associated with the overlay. */
283- detachBackdrop ( ) : void {
284- let backdropToDetach = this . _backdropElement ;
285-
286- if ( backdropToDetach ) {
287- let finishDetach = ( ) => {
288- // It may not be attached to anything in certain cases (e.g. unit tests).
289- if ( backdropToDetach && backdropToDetach . parentNode ) {
290- backdropToDetach . parentNode . removeChild ( backdropToDetach ) ;
291- }
292-
293- // It is possible that a new portal has been attached to this overlay since we started
294- // removing the backdrop. If that is the case, only clear the backdrop reference if it
295- // is still the same instance that we started to remove.
296- if ( this . _backdropElement == backdropToDetach ) {
297- this . _backdropElement = null ;
298- }
299- } ;
300-
301- backdropToDetach . classList . remove ( 'cdk-overlay-backdrop-showing' ) ;
302-
303- if ( this . _config . backdropClass ) {
304- backdropToDetach . classList . remove ( this . _config . backdropClass ) ;
305- }
306-
307- backdropToDetach . addEventListener ( 'transitionend' , finishDetach ) ;
263+ /** Animates out and disposes of the backdrop. */
264+ disposeBackdrop ( ) : void {
265+ if ( this . _backdropHost ) {
266+ if ( this . _backdropHost . hasAttached ( ) ) {
267+ this . _backdropHost . detach ( ) ;
308268
309- // If the backdrop doesn't have a transition, the `transitionend` event won't fire.
310- // In this case we make it unclickable and we try to remove it after a delay.
311- backdropToDetach . style . pointerEvents = 'none' ;
312-
313- // Run this outside the Angular zone because there's nothing that Angular cares about.
314- // If it were to run inside the Angular zone, every test that used Overlay would have to be
315- // either async or fakeAsync.
316- this . _ngZone . runOutsideAngular ( ( ) => {
317- setTimeout ( finishDetach , 500 ) ;
318- } ) ;
269+ this . _backdropInstance ! . _animationStream . pipe ( take ( 1 ) ) . subscribe ( ( ) => {
270+ this . _backdropHost ! . dispose ( ) ;
271+ this . _backdropHost = this . _backdropInstance = null ;
272+ } ) ;
273+ } else {
274+ this . _backdropHost . dispose ( ) ;
275+ }
319276 }
320277 }
278+
279+ /**
280+ * Detaches the backdrop (if any) associated with the overlay.
281+ * @deprecated Use `disposeBackdrop` instead.
282+ */
283+ detachBackdrop ( ) : void {
284+ this . disposeBackdrop ( ) ;
285+ }
321286}
322287
323288function formatCssUnit ( value : number | string ) {
0 commit comments