Skip to content

Commit

Permalink
feat(overlay): emit position change event (#1832)
Browse files Browse the repository at this point in the history
  • Loading branch information
kara authored Nov 14, 2016
1 parent 009046f commit b79c953
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 2 deletions.
28 changes: 28 additions & 0 deletions src/lib/core/overlay/position/connected-position-strategy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {ElementRef} from '@angular/core';
import {ConnectedPositionStrategy} from './connected-position-strategy';
import {ViewportRuler} from './viewport-ruler';
import {OverlayPositionBuilder} from './overlay-position-builder';
import {ConnectedOverlayPositionChange} from './connected-position';


// Default width and height of the overlay and origin panels throughout these tests.
Expand Down Expand Up @@ -259,6 +260,33 @@ describe('ConnectedPositionStrategy', () => {

});

it('should emit onPositionChange event when position changes', () => {
// force the overlay to open in a fallback position
fakeViewportRuler.fakeRect = {
top: 0, left: 0, width: 500, height: 500, right: 500, bottom: 500
};
positionBuilder = new OverlayPositionBuilder(fakeViewportRuler);
originElement.style.top = '200px';
originElement.style.left = '475px';

strategy = positionBuilder.connectedTo(
fakeElementRef,
{originX: 'end', originY: 'center'},
{overlayX: 'start', overlayY: 'center'})
.withFallbackPosition(
{originX: 'start', originY: 'bottom'},
{overlayX: 'end', overlayY: 'top'});

const positionChangeHandler = jasmine.createSpy('positionChangeHandler');
strategy.onPositionChange.first().subscribe(positionChangeHandler);

strategy.apply(overlayElement);
expect(positionChangeHandler).toHaveBeenCalled();
expect(positionChangeHandler.calls.mostRecent().args[0])
.toEqual(jasmine.any(ConnectedOverlayPositionChange),
`Expected strategy to emit an instance of ConnectedOverlayPositionChange.`);
});


/**
* Run all tests for connecting the overlay to the origin such that first preferred
Expand Down
18 changes: 16 additions & 2 deletions src/lib/core/overlay/position/connected-position-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {applyCssTransform} from '../../style/apply-transform';
import {
ConnectionPositionPair,
OriginConnectionPosition,
OverlayConnectionPosition
OverlayConnectionPosition,
ConnectedOverlayPositionChange
} from './connected-position';

import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';

/**
* A strategy for positioning overlays. Using this strategy, an overlay is given an
Expand Down Expand Up @@ -36,6 +38,13 @@ export class ConnectedPositionStrategy implements PositionStrategy {
/** The origin element against which the overlay will be positioned. */
private _origin: HTMLElement;

private _onPositionChange:
Subject<ConnectedOverlayPositionChange> = new Subject<ConnectedOverlayPositionChange>();

/** Emits an event when the connection point changes. */
get onPositionChange(): Observable<ConnectedOverlayPositionChange> {
return this._onPositionChange.asObservable();
}

constructor(
private _connectedTo: ElementRef,
Expand Down Expand Up @@ -64,6 +73,7 @@ export class ConnectedPositionStrategy implements PositionStrategy {
// We use the viewport rect to determine whether a position would go off-screen.
const viewportRect = this._viewportRuler.getViewportRect();
let firstOverlayPoint: Point = null;
let isFirstPosition = true;

// We want to place the overlay in the first of the preferred positions such that the
// overlay fits on-screen.
Expand All @@ -77,8 +87,12 @@ export class ConnectedPositionStrategy implements PositionStrategy {
// If the overlay in the calculated position fits on-screen, put it there and we're done.
if (this._willOverlayFitWithinViewport(overlayPoint, overlayRect, viewportRect)) {
this._setElementPosition(element, overlayPoint);
if (!isFirstPosition) {
this._onPositionChange.next(new ConnectedOverlayPositionChange(pos));
}
return Promise.resolve(null);
}
isFirstPosition = false;
}

// TODO(jelbourn): fallback behavior for when none of the preferred positions fit on-screen.
Expand Down
5 changes: 5 additions & 0 deletions src/lib/core/overlay/position/connected-position.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,8 @@ export class ConnectionPositionPair {
this.overlayY = overlay.overlayY;
}
}

/** The change event emitted by the strategy when a fallback position is used. */
export class ConnectedOverlayPositionChange {
constructor(public connectionPair: ConnectionPositionPair) {}
}

0 comments on commit b79c953

Please sign in to comment.