From fe37cb2551929844d5467e1b9bf45032df35981f Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 1 Sep 2017 17:07:35 +0200 Subject: [PATCH] refactor(overlay): allow for object to be passed to the OverlayState constructor (#6615) Allows for a config object to be passed to the `OverlayState` constructor. This makes the longer configurations a bit more convenient to use. --- src/cdk/overlay/overlay-directives.ts | 13 +++++------ src/cdk/overlay/overlay-ref.ts | 19 ++++++++++++---- src/cdk/overlay/overlay-state.ts | 10 +++++++-- src/cdk/overlay/overlay.spec.ts | 18 +++++---------- .../scroll/block-scroll-strategy.spec.ts | 3 +-- .../scroll/close-scroll-strategy.spec.ts | 3 +-- .../scroll/reposition-scroll-strategy.spec.ts | 3 +-- src/cdk/overlay/scroll/scroll-strategy.md | 5 +++-- src/demo-app/overlay/overlay-demo.ts | 21 +++++++----------- src/lib/autocomplete/autocomplete-trigger.ts | 12 +++++----- src/lib/datepicker/datepicker.ts | 13 ++++++----- src/lib/dialog/dialog.ts | 22 ++++++++++--------- src/lib/menu/menu-trigger.ts | 14 ++++++------ src/lib/snack-bar/snack-bar.ts | 8 ++++--- src/lib/tooltip/tooltip.ts | 18 +++++++-------- 15 files changed, 95 insertions(+), 87 deletions(-) diff --git a/src/cdk/overlay/overlay-directives.ts b/src/cdk/overlay/overlay-directives.ts index fdceb1dca12..76bfe87d841 100644 --- a/src/cdk/overlay/overlay-directives.ts +++ b/src/cdk/overlay/overlay-directives.ts @@ -272,7 +272,12 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges { /** Builds the overlay config based on the directive's inputs */ private _buildConfig(): OverlayState { - let overlayConfig = new OverlayState(); + const positionStrategy = this._position = this._createPositionStrategy(); + const overlayConfig = new OverlayState({ + positionStrategy, + scrollStrategy: this.scrollStrategy, + hasBackdrop: this.hasBackdrop + }); if (this.width || this.width === 0) { overlayConfig.width = this.width; @@ -290,16 +295,10 @@ export class ConnectedOverlayDirective implements OnDestroy, OnChanges { overlayConfig.minHeight = this.minHeight; } - overlayConfig.hasBackdrop = this.hasBackdrop; - if (this.backdropClass) { overlayConfig.backdropClass = this.backdropClass; } - this._position = this._createPositionStrategy() as ConnectedPositionStrategy; - overlayConfig.positionStrategy = this._position; - overlayConfig.scrollStrategy = this.scrollStrategy; - return overlayConfig; } diff --git a/src/cdk/overlay/overlay-ref.ts b/src/cdk/overlay/overlay-ref.ts index 765187848ec..352485df420 100644 --- a/src/cdk/overlay/overlay-ref.ts +++ b/src/cdk/overlay/overlay-ref.ts @@ -29,7 +29,9 @@ export class OverlayRef implements PortalHost { private _state: OverlayState, private _ngZone: NgZone) { - _state.scrollStrategy.attach(this); + if (_state.scrollStrategy) { + _state.scrollStrategy.attach(this); + } } /** The overlay's HTML element */ @@ -54,7 +56,10 @@ export class OverlayRef implements PortalHost { this.updateSize(); this.updateDirection(); this.updatePosition(); - this._state.scrollStrategy.enable(); + + if (this._state.scrollStrategy) { + this._state.scrollStrategy.enable(); + } // Enable pointer events for the overlay pane element. this._togglePointerEvents(true); @@ -89,7 +94,10 @@ export class OverlayRef implements PortalHost { // This is necessary because otherwise the pane element will cover the page and disable // pointer events therefore. Depends on the position strategy and the applied pane boundaries. this._togglePointerEvents(false); - this._state.scrollStrategy.disable(); + + if (this._state.scrollStrategy) { + this._state.scrollStrategy.disable(); + } let detachmentResult = this._portalHost.detach(); @@ -107,7 +115,10 @@ export class OverlayRef implements PortalHost { this._state.positionStrategy.dispose(); } - this._state.scrollStrategy.disable(); + if (this._state.scrollStrategy) { + this._state.scrollStrategy.disable(); + } + this.detachBackdrop(); this._portalHost.dispose(); this._attachments.complete(); diff --git a/src/cdk/overlay/overlay-state.ts b/src/cdk/overlay/overlay-state.ts index faba40d0588..702468b9031 100644 --- a/src/cdk/overlay/overlay-state.ts +++ b/src/cdk/overlay/overlay-state.ts @@ -18,10 +18,10 @@ import {NoopScrollStrategy} from './scroll/noop-scroll-strategy'; */ export class OverlayState { /** Strategy with which to position the overlay. */ - positionStrategy: PositionStrategy; + positionStrategy?: PositionStrategy; /** Strategy to be used when handling scroll events while the overlay is open. */ - scrollStrategy: ScrollStrategy = new NoopScrollStrategy(); + scrollStrategy?: ScrollStrategy = new NoopScrollStrategy(); /** Custom class to add to the overlay pane. */ panelClass?: string | string[] = ''; @@ -53,6 +53,12 @@ export class OverlayState { /** The direction of the text in the overlay panel. */ direction?: Direction = 'ltr'; + constructor(state?: OverlayState) { + if (state) { + Object.keys(state).forEach(key => this[key] = state[key]); + } + } + // TODO(jelbourn): configuration still to add // - focus trap // - disable pointer events diff --git a/src/cdk/overlay/overlay.spec.ts b/src/cdk/overlay/overlay.spec.ts index f5551047e96..8b1e3c4e212 100644 --- a/src/cdk/overlay/overlay.spec.ts +++ b/src/cdk/overlay/overlay.spec.ts @@ -133,8 +133,7 @@ describe('Overlay', () => { }); it('should set the direction', () => { - const state = new OverlayState(); - state.direction = 'rtl'; + const state = new OverlayState({direction: 'rtl'}); overlay.create(state).attach(componentPortal); @@ -153,10 +152,7 @@ describe('Overlay', () => { }); it('should emit the attachment event after everything is added to the DOM', () => { - let state = new OverlayState(); - - state.hasBackdrop = true; - + let state = new OverlayState({hasBackdrop: true}); let overlayRef = overlay.create(state); overlayRef.attachments().subscribe(() => { @@ -415,9 +411,8 @@ describe('Overlay', () => { describe('panelClass', () => { it('should apply a custom overlay pane class', () => { - const config = new OverlayState(); + const config = new OverlayState({panelClass: 'custom-panel-class'}); - config.panelClass = 'custom-panel-class'; overlay.create(config).attach(componentPortal); viewContainerFixture.detectChanges(); @@ -426,9 +421,8 @@ describe('Overlay', () => { }); it('should be able to apply multiple classes', () => { - const config = new OverlayState(); + const config = new OverlayState({panelClass: ['custom-class-one', 'custom-class-two']}); - config.panelClass = ['custom-class-one', 'custom-class-two']; overlay.create(config).attach(componentPortal); viewContainerFixture.detectChanges(); @@ -445,8 +439,8 @@ describe('Overlay', () => { let overlayRef: OverlayRef; beforeEach(() => { - config = new OverlayState(); - fakeScrollStrategy = config.scrollStrategy = new FakeScrollStrategy(); + fakeScrollStrategy = new FakeScrollStrategy(); + config = new OverlayState({scrollStrategy: fakeScrollStrategy}); overlayRef = overlay.create(config); }); diff --git a/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts index 2be0acd12f7..b7eefac45c2 100644 --- a/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/block-scroll-strategy.spec.ts @@ -23,9 +23,8 @@ describe('BlockScrollStrategy', () => { })); beforeEach(inject([Overlay, ViewportRuler], (overlay: Overlay, viewportRuler: ViewportRuler) => { - let overlayState = new OverlayState(); + let overlayState = new OverlayState({scrollStrategy: overlay.scrollStrategies.block()}); - overlayState.scrollStrategy = overlay.scrollStrategies.block(); overlayRef = overlay.create(overlayState); componentPortal = new ComponentPortal(FocacciaMsg); diff --git a/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts index 2fc805efe39..d2b686eb4e9 100644 --- a/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/close-scroll-strategy.spec.ts @@ -33,8 +33,7 @@ describe('CloseScrollStrategy', () => { })); beforeEach(inject([Overlay], (overlay: Overlay) => { - let overlayState = new OverlayState(); - overlayState.scrollStrategy = overlay.scrollStrategies.close(); + let overlayState = new OverlayState({scrollStrategy: overlay.scrollStrategies.close()}); overlayRef = overlay.create(overlayState); componentPortal = new ComponentPortal(MozarellaMsg); })); diff --git a/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts b/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts index 01e60314262..9405f375285 100644 --- a/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts +++ b/src/cdk/overlay/scroll/reposition-scroll-strategy.spec.ts @@ -33,8 +33,7 @@ describe('RepositionScrollStrategy', () => { })); beforeEach(inject([Overlay], (overlay: Overlay) => { - let overlayState = new OverlayState(); - overlayState.scrollStrategy = overlay.scrollStrategies.reposition(); + let overlayState = new OverlayState({scrollStrategy: overlay.scrollStrategies.reposition()}); overlayRef = overlay.create(overlayState); componentPortal = new ComponentPortal(PastaMsg); })); diff --git a/src/cdk/overlay/scroll/scroll-strategy.md b/src/cdk/overlay/scroll/scroll-strategy.md index b39772b0b43..72d912d1cec 100644 --- a/src/cdk/overlay/scroll/scroll-strategy.md +++ b/src/cdk/overlay/scroll/scroll-strategy.md @@ -11,9 +11,10 @@ scroll strategy, to the `OverlayState`. By default, all overlays will use the `n doesn't do anything. The other available strategies are `reposition`, `block` and `close`: ```ts -let overlayState = new OverlayState(); +let overlayState = new OverlayState({ + scrollStrategy: overlay.scrollStrategies.block() +}); -overlayState.scrollStrategy = overlay.scrollStrategies.block(); this._overlay.create(overlayState).attach(yourPortal); ``` diff --git a/src/demo-app/overlay/overlay-demo.ts b/src/demo-app/overlay/overlay-demo.ts index d084959cd9c..bc925ee8275 100644 --- a/src/demo-app/overlay/overlay-demo.ts +++ b/src/demo-app/overlay/overlay-demo.ts @@ -74,10 +74,9 @@ export class OverlayDemo { {originX: 'start', originY: 'bottom'}, {overlayX: 'start', overlayY: 'top'} ); - let config = new OverlayState(); - config.positionStrategy = strategy; - + let config = new OverlayState({positionStrategy: strategy}); let overlayRef = this.overlay.create(config); + overlayRef.attach(new ComponentPortal(SpagettiPanel, this.viewContainerRef)); } @@ -88,22 +87,18 @@ export class OverlayDemo { {originX: 'start', originY: 'bottom'}, {overlayX: 'end', overlayY: 'top'} ); - let config = new OverlayState(); - config.positionStrategy = strategy; - + let config = new OverlayState({positionStrategy: strategy}); let overlayRef = this.overlay.create(config); overlayRef.attach(this.tortelliniTemplate); } openPanelWithBackdrop() { - let config = new OverlayState(); - - config.positionStrategy = this.overlay.position() - .global() - .centerHorizontally(); - config.hasBackdrop = true; - config.backdropClass = 'cdk-overlay-transparent-backdrop'; + let config = new OverlayState({ + hasBackdrop: true, + backdropClass: 'cdk-overlay-transparent-backdrop', + positionStrategy: this.overlay.position().global().centerHorizontally() + }); let overlayRef = this.overlay.create(config); overlayRef.attach(this.templatePortals.first); diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts index ade59b533b3..bbc97e95833 100644 --- a/src/lib/autocomplete/autocomplete-trigger.ts +++ b/src/lib/autocomplete/autocomplete-trigger.ts @@ -468,12 +468,12 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy { } private _getOverlayConfig(): OverlayState { - const overlayState = new OverlayState(); - overlayState.positionStrategy = this._getOverlayPosition(); - overlayState.width = this._getHostWidth(); - overlayState.direction = this._dir ? this._dir.value : 'ltr'; - overlayState.scrollStrategy = this._scrollStrategy(); - return overlayState; + return new OverlayState({ + positionStrategy: this._getOverlayPosition(), + scrollStrategy: this._scrollStrategy(), + width: this._getHostWidth(), + direction: this._dir ? this._dir.value : 'ltr' + }); } private _getOverlayPosition(): PositionStrategy { diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 9312ba22e3e..7f8ed7d49bf 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -321,12 +321,13 @@ export class MdDatepicker implements OnDestroy { /** Create the popup. */ private _createPopup(): void { - const overlayState = new OverlayState(); - overlayState.positionStrategy = this._createPopupPositionStrategy(); - overlayState.hasBackdrop = true; - overlayState.backdropClass = 'md-overlay-transparent-backdrop'; - overlayState.direction = this._dir ? this._dir.value : 'ltr'; - overlayState.scrollStrategy = this._scrollStrategy(); + const overlayState = new OverlayState({ + positionStrategy: this._createPopupPositionStrategy(), + hasBackdrop: true, + backdropClass: 'md-overlay-transparent-backdrop', + direction: this._dir ? this._dir.value : 'ltr', + scrollStrategy: this._scrollStrategy() + }); this._popupRef = this._overlay.create(overlayState); } diff --git a/src/lib/dialog/dialog.ts b/src/lib/dialog/dialog.ts index 784459779bb..a398f3dde73 100644 --- a/src/lib/dialog/dialog.ts +++ b/src/lib/dialog/dialog.ts @@ -186,17 +186,19 @@ export class MdDialog { * @returns The overlay configuration. */ private _getOverlayState(dialogConfig: MdDialogConfig): OverlayState { - const overlayState = new OverlayState(); - overlayState.panelClass = dialogConfig.panelClass; - overlayState.hasBackdrop = dialogConfig.hasBackdrop; - overlayState.scrollStrategy = this._scrollStrategy(); - overlayState.direction = dialogConfig.direction; - if (dialogConfig.backdropClass) { - overlayState.backdropClass = dialogConfig.backdropClass; - } - overlayState.positionStrategy = this._overlay.position().global(); + const state = new OverlayState({ + positionStrategy: this._overlay.position().global(), + scrollStrategy: this._scrollStrategy(), + panelClass: dialogConfig.panelClass, + hasBackdrop: dialogConfig.hasBackdrop, + direction: dialogConfig.direction + }); - return overlayState; + if (dialogConfig.backdropClass) { + state.backdropClass = dialogConfig.backdropClass; + } + + return state; } /** diff --git a/src/lib/menu/menu-trigger.ts b/src/lib/menu/menu-trigger.ts index db95674e750..045b872296e 100644 --- a/src/lib/menu/menu-trigger.ts +++ b/src/lib/menu/menu-trigger.ts @@ -322,13 +322,13 @@ export class MdMenuTrigger implements AfterViewInit, OnDestroy { * @returns OverlayState */ private _getOverlayConfig(): OverlayState { - const overlayState = new OverlayState(); - overlayState.positionStrategy = this._getPosition(); - overlayState.hasBackdrop = !this.triggersSubmenu(); - overlayState.backdropClass = 'cdk-overlay-transparent-backdrop'; - overlayState.direction = this.dir; - overlayState.scrollStrategy = this._scrollStrategy(); - return overlayState; + return new OverlayState({ + positionStrategy: this._getPosition(), + hasBackdrop: !this.triggersSubmenu(), + backdropClass: 'cdk-overlay-transparent-backdrop', + direction: this.dir, + scrollStrategy: this._scrollStrategy() + }); } /** diff --git a/src/lib/snack-bar/snack-bar.ts b/src/lib/snack-bar/snack-bar.ts index 6f182f8f5d8..8c2b8979902 100644 --- a/src/lib/snack-bar/snack-bar.ts +++ b/src/lib/snack-bar/snack-bar.ts @@ -153,9 +153,11 @@ export class MdSnackBar { * @param config The user-specified snack bar config. */ private _createOverlay(config: MdSnackBarConfig): OverlayRef { - const state = new OverlayState(); - state.direction = config.direction; - state.positionStrategy = this._overlay.position().global().centerHorizontally().bottom('0'); + const state = new OverlayState({ + direction: config.direction, + positionStrategy: this._overlay.position().global().centerHorizontally().bottom('0') + }); + return this._overlay.create(state); } diff --git a/src/lib/tooltip/tooltip.ts b/src/lib/tooltip/tooltip.ts index 0defc0add49..29a89a81c88 100644 --- a/src/lib/tooltip/tooltip.ts +++ b/src/lib/tooltip/tooltip.ts @@ -279,13 +279,13 @@ export class MdTooltip implements OnDestroy { /** Create the overlay config and position strategy */ private _createOverlay(): OverlayRef { - let origin = this._getOrigin(); - let position = this._getOverlayPosition(); + const origin = this._getOrigin(); + const position = this._getOverlayPosition(); // Create connected position strategy that listens for scroll events to reposition. // After position changes occur and the overlay is clipped by a parent scrollable then // close the tooltip. - let strategy = this._overlay.position().connectedTo(this._elementRef, origin, position); + const strategy = this._overlay.position().connectedTo(this._elementRef, origin, position); strategy.withScrollableContainers(this._scrollDispatcher.getScrollContainers(this._elementRef)); strategy.onPositionChange.subscribe(change => { if (change.scrollableViewProperties.isOverlayClipped && @@ -294,12 +294,12 @@ export class MdTooltip implements OnDestroy { } }); - let config = new OverlayState(); - - config.direction = this._dir ? this._dir.value : 'ltr'; - config.positionStrategy = strategy; - config.panelClass = TOOLTIP_PANEL_CLASS; - config.scrollStrategy = this._scrollStrategy(); + const config = new OverlayState({ + direction: this._dir ? this._dir.value : 'ltr', + positionStrategy: strategy, + panelClass: TOOLTIP_PANEL_CLASS, + scrollStrategy: this._scrollStrategy() + }); this._overlayRef = this._overlay.create(config);