Skip to content

Commit

Permalink
feat(overlay): add connected position strategy (#335)
Browse files Browse the repository at this point in the history
  • Loading branch information
jelbourn committed May 12, 2016
1 parent dfe683b commit 7f3b1bd
Show file tree
Hide file tree
Showing 18 changed files with 911 additions and 63 deletions.
7 changes: 7 additions & 0 deletions firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
"deploy",
"typings"
],
"headers": [{
"source": "*",
"headers": [{
"key": "Cache-Control",
"value": "no-cache"
}]
}],
"rewrites": [{
"source": "/**/!(*.@(js|ts|html|css|json|svg|png|jpg|jpeg))",
"destination": "/index.html"
Expand Down
17 changes: 15 additions & 2 deletions src/core/overlay/overlay-ref.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {PortalHost, Portal} from '../portal/portal';
import {OverlayState} from './overlay-state';

/**
* Reference to an overlay that has been created with the Overlay service.
* Used to manipulate or dispose of said overlay.
*/
export class OverlayRef implements PortalHost {
constructor(private _portalHost: PortalHost) { }
constructor(
private _portalHost: PortalHost,
private _pane: HTMLElement,
private _state: OverlayState) { }

attach(portal: Portal<any>): Promise<any> {
return this._portalHost.attach(portal);
return this._portalHost.attach(portal).then(() => {
this._updatePosition();
});
}

detach(): Promise<any> {
Expand All @@ -23,5 +29,12 @@ export class OverlayRef implements PortalHost {
return this._portalHost.hasAttached();
}

/** Updates the position of the overlay based on the position strategy. */
private _updatePosition() {
if (this._state.positionStrategy) {
this._state.positionStrategy.apply(this._pane);
}
}

// TODO(jelbourn): add additional methods for manipulating the overlay.
}
1 change: 1 addition & 0 deletions src/core/overlay/overlay.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@
.md-overlay-pane {
position: absolute;
pointer-events: auto;
box-sizing: border-box;
}
4 changes: 4 additions & 0 deletions src/core/overlay/overlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import {Overlay, OVERLAY_CONTAINER_TOKEN} from './overlay';
import {OverlayRef} from './overlay-ref';
import {OverlayState} from './overlay-state';
import {PositionStrategy} from './position/position-strategy';
import {OverlayPositionBuilder} from './position/overlay-position-builder';
import {ViewportRuler} from './position/viewport-ruler';


export function main() {
Expand All @@ -32,6 +34,8 @@ export function main() {

beforeEachProviders(() => [
Overlay,
OverlayPositionBuilder,
ViewportRuler,
provide(OVERLAY_CONTAINER_TOKEN, {useFactory: () => {
overlayContainerElement = document.createElement('div');
return overlayContainerElement;
Expand Down
58 changes: 19 additions & 39 deletions src/core/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import {
OpaqueToken,
Inject,
Injectable,
ElementRef
} from '@angular/core';
import {OverlayState} from './overlay-state';
import {DomPortalHost} from '../portal/dom-portal-host';
import {OverlayRef} from './overlay-ref';
import {GlobalPositionStrategy} from './position/global-position-strategy';
import {RelativePositionStrategy} from './position/relative-position-strategy';

import {OverlayPositionBuilder} from './position/overlay-position-builder';
import {ViewportRuler} from './position/viewport-ruler';


// Re-export overlay-related modules so they can be imported directly from here.
Expand Down Expand Up @@ -39,7 +39,8 @@ let defaultState = new OverlayState();
export class Overlay {
constructor(
@Inject(OVERLAY_CONTAINER_TOKEN) private _overlayContainerElement: HTMLElement,
private _dynamicComponentLoader: DynamicComponentLoader) {
private _dynamicComponentLoader: DynamicComponentLoader,
private _positionBuilder: OverlayPositionBuilder) {
}

/**
Expand All @@ -48,44 +49,31 @@ export class Overlay {
* @returns A reference to the created overlay.
*/
create(state: OverlayState = defaultState): Promise<OverlayRef> {
return this._createPaneElement(state).then(pane => this._createOverlayRef(pane));
return this._createPaneElement().then(pane => this._createOverlayRef(pane, state));
}

/**
* Returns a position builder that can be used, via fluent API,
* to construct and configure a position strategy.
*/
position() {
return POSITION_BUILDER;
return this._positionBuilder;
}

/**
* Creates the DOM element for an overlay.
* @param state State to apply to the created element.
* Creates the DOM element for an overlay and appends it to the overlay container.
* @returns Promise resolving to the created element.
*/
private _createPaneElement(state: OverlayState): Promise<HTMLElement> {
private _createPaneElement(): Promise<HTMLElement> {
var pane = document.createElement('div');
pane.id = `md-overlay-${nextUniqueId++}`;
pane.id = `md-overlay-${nextUniqueId++}`;
pane.classList.add('md-overlay-pane');

this.applyState(pane, state);
this._overlayContainerElement.appendChild(pane);

return Promise.resolve(pane);
}

/**
* Applies a given state to the given pane element.
* @param pane The pane to modify.
* @param state The state to apply.
*/
applyState(pane: HTMLElement, state: OverlayState) {
if (state.positionStrategy != null) {
state.positionStrategy.apply(pane);
}
}

/**
* Create a DomPortalHost into which the overlay content can be loaded.
* @param pane The DOM element to turn into a portal host.
Expand All @@ -100,26 +88,18 @@ export class Overlay {
/**
* Creates an OverlayRef for an overlay in the given DOM element.
* @param pane DOM element for the overlay
* @param state
* @returns {OverlayRef}
*/
private _createOverlayRef(pane: HTMLElement): OverlayRef {
return new OverlayRef(this._createPortalHost(pane));
private _createOverlayRef(pane: HTMLElement, state: OverlayState): OverlayRef {
return new OverlayRef(this._createPortalHost(pane), pane, state);
}
}


/** Builder for overlay position strategy. */
export class OverlayPositionBuilder {
/** Creates a global position strategy. */
global() {
return new GlobalPositionStrategy();
}

/** Creates a relative position strategy. */
relativeTo(elementRef: ElementRef) {
return new RelativePositionStrategy(elementRef);
}
}

// We only ever need one position builder.
let POSITION_BUILDER: OverlayPositionBuilder = new OverlayPositionBuilder();
/** Providers for Overlay and its related injectables. */
export const OVERLAY_PROVIDERS = [
ViewportRuler,
OverlayPositionBuilder,
Overlay,
];
Loading

1 comment on commit 7f3b1bd

@nesheroj
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This closes some bullet points in #113, doesn't it?

Please sign in to comment.