chore(material): move dialog to TypeScript.
This commit is contained in:
parent
4f3acdb004
commit
c8947d77bf
|
@ -1,17 +1,21 @@
|
|||
import {DynamicComponentLoader, ElementRef, ComponentRef, onDestroy, DomRenderer} from 'angular2/angular2';
|
||||
import {bind, Injector} from 'angular2/di';
|
||||
import {
|
||||
Component,
|
||||
Directive,
|
||||
View,
|
||||
Parent,
|
||||
ElementRef,
|
||||
DynamicComponentLoader,
|
||||
ComponentRef,
|
||||
DomRenderer
|
||||
} from 'angular2/angular2';
|
||||
import {bind, Injector, Injectable, FORWARD_REF} from 'angular2/di';
|
||||
|
||||
import {ObservableWrapper, Promise, PromiseWrapper} from 'angular2/src/facade/async';
|
||||
import {isPresent, Type} from 'angular2/src/facade/lang';
|
||||
import {DOM} from 'angular2/src/dom/dom_adapter';
|
||||
import {MouseEvent, KeyboardEvent} from 'angular2/src/facade/browser';
|
||||
import {KEY_ESC} from 'angular2_material/src/core/constants';
|
||||
|
||||
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur,
|
||||
// add those imports back into 'angular2/angular2';
|
||||
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
|
||||
import {Parent} from 'angular2/src/core/annotations_impl/visibility';
|
||||
import {View} from 'angular2/src/core/annotations_impl/view';
|
||||
|
||||
// TODO(jelbourn): Opener of dialog can control where it is rendered.
|
||||
// TODO(jelbourn): body scrolling is disabled while dialog is open.
|
||||
// TODO(jelbourn): Don't manually construct and configure a DOM element. See #1402
|
||||
|
@ -21,11 +25,10 @@ import {View} from 'angular2/src/core/annotations_impl/view';
|
|||
// TODO(jelbourn): Pre-built `alert` and `confirm` dialogs.
|
||||
// TODO(jelbourn): Animate dialog out of / into opening element.
|
||||
|
||||
var _nextDialogId = 0;
|
||||
|
||||
/**
|
||||
* Service for opening modal dialogs.
|
||||
*/
|
||||
@Injectable()
|
||||
export class MdDialog {
|
||||
componentLoader: DynamicComponentLoader;
|
||||
domRenderer: DomRenderer;
|
||||
|
@ -39,13 +42,12 @@ export class MdDialog {
|
|||
* Opens a modal dialog.
|
||||
* @param type The component to open.
|
||||
* @param elementRef The logical location into which the component will be opened.
|
||||
* @param parentInjector
|
||||
* @param options
|
||||
* @returns Promise for a reference to the dialog.
|
||||
*/
|
||||
open(
|
||||
type: Type,
|
||||
elementRef: ElementRef,
|
||||
parentInjector: Injector,
|
||||
options: MdDialogConfig = null): Promise<MdDialogRef> {
|
||||
open(type: Type, elementRef: ElementRef, parentInjector: Injector,
|
||||
options: MdDialogConfig = null): Promise<MdDialogRef> {
|
||||
var config = isPresent(options) ? options : new MdDialogConfig();
|
||||
|
||||
// Create the dialogRef here so that it can be injected into the content component.
|
||||
|
@ -57,61 +59,63 @@ export class MdDialog {
|
|||
var backdropRefPromise = this._openBackdrop(elementRef, contentInjector);
|
||||
|
||||
// First, load the MdDialogContainer, into which the given component will be loaded.
|
||||
return this.componentLoader.loadIntoNewLocation(
|
||||
MdDialogContainer, elementRef).then(containerRef => {
|
||||
// TODO(tbosch): clean this up when we have custom renderers (https://github.com/angular/angular/issues/1807)
|
||||
// TODO(jelbourn): Don't use direct DOM access. Need abstraction to create an element
|
||||
// directly on the document body (also needed for web workers stuff).
|
||||
// Create a DOM node to serve as a physical host element for the dialog.
|
||||
var dialogElement = this.domRenderer.getHostElement(containerRef.hostView.render);
|
||||
DOM.appendChild(DOM.query('body'), dialogElement);
|
||||
return this.componentLoader.loadIntoNewLocation(MdDialogContainer, elementRef)
|
||||
.then(containerRef => {
|
||||
// TODO(tbosch): clean this up when we have custom renderers
|
||||
// (https://github.com/angular/angular/issues/1807)
|
||||
// TODO(jelbourn): Don't use direct DOM access. Need abstraction to create an element
|
||||
// directly on the document body (also needed for web workers stuff).
|
||||
// Create a DOM node to serve as a physical host element for the dialog.
|
||||
var dialogElement = this.domRenderer.getHostElement(containerRef.hostView.render);
|
||||
DOM.appendChild(DOM.query('body'), dialogElement);
|
||||
|
||||
// TODO(jelbourn): Use hostProperties binding to set these once #1539 is fixed.
|
||||
// Configure properties on the host element.
|
||||
DOM.addClass(dialogElement, 'md-dialog');
|
||||
DOM.setAttribute(dialogElement, 'tabindex', '0');
|
||||
// TODO(jelbourn): Use hostProperties binding to set these once #1539 is fixed.
|
||||
// Configure properties on the host element.
|
||||
DOM.addClass(dialogElement, 'md-dialog');
|
||||
DOM.setAttribute(dialogElement, 'tabindex', '0');
|
||||
|
||||
// TODO(jelbourn): Do this with hostProperties (or another rendering abstraction) once ready.
|
||||
if (isPresent(config.width)) {
|
||||
DOM.setStyle(dialogElement, 'width', config.width);
|
||||
}
|
||||
if (isPresent(config.height)) {
|
||||
DOM.setStyle(dialogElement, 'height', config.height);
|
||||
}
|
||||
// TODO(jelbourn): Do this with hostProperties (or another rendering abstraction) once
|
||||
// ready.
|
||||
if (isPresent(config.width)) {
|
||||
DOM.setStyle(dialogElement, 'width', config.width);
|
||||
}
|
||||
if (isPresent(config.height)) {
|
||||
DOM.setStyle(dialogElement, 'height', config.height);
|
||||
}
|
||||
|
||||
dialogRef.containerRef = containerRef;
|
||||
dialogRef.containerRef = containerRef;
|
||||
|
||||
// Now load the given component into the MdDialogContainer.
|
||||
return this.componentLoader.loadNextToExistingLocation(
|
||||
type, containerRef.instance.contentRef, contentInjector).then(contentRef => {
|
||||
// Now load the given component into the MdDialogContainer.
|
||||
return this.componentLoader.loadNextToExistingLocation(
|
||||
type, containerRef.instance.contentRef, contentInjector)
|
||||
.then(contentRef => {
|
||||
|
||||
// Wrap both component refs for the container and the content so that we can return
|
||||
// the `instance` of the content but the dispose method of the container back to the
|
||||
// opener.
|
||||
dialogRef.contentRef = contentRef;
|
||||
containerRef.instance.dialogRef = dialogRef;
|
||||
// Wrap both component refs for the container and the content so that we can return
|
||||
// the `instance` of the content but the dispose method of the container back to the
|
||||
// opener.
|
||||
dialogRef.contentRef = contentRef;
|
||||
containerRef.instance.dialogRef = dialogRef;
|
||||
|
||||
backdropRefPromise.then(backdropRef => {
|
||||
dialogRef.whenClosed.then((_) => {
|
||||
backdropRef.dispose();
|
||||
});
|
||||
backdropRefPromise.then(backdropRef => {
|
||||
dialogRef.whenClosed.then((_) => { backdropRef.dispose(); });
|
||||
});
|
||||
|
||||
return dialogRef;
|
||||
});
|
||||
});
|
||||
|
||||
return dialogRef;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** Loads the dialog backdrop (transparent overlay over the rest of the page). */
|
||||
_openBackdrop(elementRef:ElementRef, injector: Injector): Promise<ComponentRef> {
|
||||
return this.componentLoader.loadIntoNewLocation(
|
||||
MdBackdrop, elementRef, injector).then( (componentRef) => {
|
||||
// TODO(tbosch): clean this up when we have custom renderers (https://github.com/angular/angular/issues/1807)
|
||||
var backdropElement = this.domRenderer.getHostElement(componentRef.hostView.render);
|
||||
DOM.addClass(backdropElement, 'md-backdrop');
|
||||
DOM.appendChild(DOM.query('body'), backdropElement);
|
||||
return componentRef;
|
||||
});
|
||||
_openBackdrop(elementRef: ElementRef, injector: Injector): Promise<ComponentRef> {
|
||||
return this.componentLoader.loadIntoNewLocation(MdBackdrop, elementRef, injector)
|
||||
.then((componentRef) => {
|
||||
// TODO(tbosch): clean this up when we have custom renderers
|
||||
// (https://github.com/angular/angular/issues/1807)
|
||||
var backdropElement = this.domRenderer.getHostElement(componentRef.hostView.render);
|
||||
DOM.addClass(backdropElement, 'md-backdrop');
|
||||
DOM.appendChild(DOM.query('body'), backdropElement);
|
||||
return componentRef;
|
||||
});
|
||||
}
|
||||
|
||||
alert(message: string, okMessage: string): Promise {
|
||||
|
@ -163,8 +167,10 @@ export class MdDialogRef {
|
|||
return this._contentRef.instance;
|
||||
}
|
||||
|
||||
// The only time one could attempt to access this property before the value is set is if an access occurs during
|
||||
// the constructor of the very instance they are trying to get (which is much more easily accessed as `this`).
|
||||
// The only time one could attempt to access this property before the value is set is if an
|
||||
// access occurs during
|
||||
// the constructor of the very instance they are trying to get (which is much more easily
|
||||
// accessed as `this`).
|
||||
throw "Cannot access dialog component instance *from* that component's constructor.";
|
||||
}
|
||||
|
||||
|
@ -203,13 +209,11 @@ export class MdDialogConfig {
|
|||
*/
|
||||
@Component({
|
||||
selector: 'md-dialog-container',
|
||||
hostListeners: {
|
||||
'body:^keydown': 'documentKeypress($event)'
|
||||
}
|
||||
hostListeners: {'body:^keydown': 'documentKeypress($event)'},
|
||||
})
|
||||
@View({
|
||||
templateUrl: 'angular2_material/src/components/dialog/dialog.html',
|
||||
directives: [MdDialogContent]
|
||||
directives: [FORWARD_REF(() => MdDialogContent)]
|
||||
})
|
||||
class MdDialogContainer {
|
||||
// Ref to the dialog content. Used by the DynamicComponentLoader to load the dialog content.
|
||||
|
@ -234,13 +238,22 @@ class MdDialogContainer {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple decorator used only to communicate an ElementRef to the parent MdDialogContainer as the
|
||||
* location
|
||||
* for where the dialog content will be loaded.
|
||||
*/
|
||||
@Directive({selector: 'md-dialog-content'})
|
||||
class MdDialogContent {
|
||||
constructor(@Parent() dialogContainer: MdDialogContainer, elementRef: ElementRef) {
|
||||
dialogContainer.contentRef = elementRef;
|
||||
}
|
||||
}
|
||||
|
||||
/** Component for the dialog "backdrop", a transparent overlay over the rest of the page. */
|
||||
@Component({
|
||||
selector: 'md-backdrop',
|
||||
hostListeners: {
|
||||
'click': 'onClick()'
|
||||
}
|
||||
hostListeners: {'click': 'onClick()'},
|
||||
})
|
||||
@View({template: ''})
|
||||
class MdBackdrop {
|
||||
|
@ -256,15 +269,3 @@ class MdBackdrop {
|
|||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple decorator used only to communicate an ElementRef to the parent MdDialogContainer as the location
|
||||
* for where the dialog content will be loaded.
|
||||
*/
|
||||
@Directive({selector: 'md-dialog-content'})
|
||||
class MdDialogContent {
|
||||
constructor(@Parent() dialogContainer: MdDialogContainer, elementRef: ElementRef) {
|
||||
dialogContainer.contentRef = elementRef;
|
||||
}
|
||||
}
|
|
@ -1,23 +1,22 @@
|
|||
import {bootstrap, ElementRef, ComponentRef} from 'angular2/angular2';
|
||||
import {MdDialog, MdDialogRef, MdDialogConfig} from 'angular2_material/src/components/dialog/dialog'
|
||||
import {bootstrap, ElementRef, ComponentRef, Component, View} from 'angular2/angular2';
|
||||
import {
|
||||
MdDialog,
|
||||
MdDialogRef,
|
||||
MdDialogConfig
|
||||
} from 'angular2_material/src/components/dialog/dialog';
|
||||
import {UrlResolver} from 'angular2/src/services/url_resolver';
|
||||
import {commonDemoSetup, DemoUrlResolver} from '../demo_common';
|
||||
import {bind, Injector} from 'angular2/di';
|
||||
import {isPresent} from 'angular2/src/facade/lang';
|
||||
|
||||
// TODO(radokirov): Once the application is transpiled by TS instead of Traceur,
|
||||
// add those imports back into 'angular2/angular2';
|
||||
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
|
||||
import {View} from 'angular2/src/core/annotations_impl/view';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'demo-app',
|
||||
appInjector: [MdDialog]
|
||||
appInjector: [MdDialog],
|
||||
})
|
||||
@View({
|
||||
templateUrl: './demo_app.html',
|
||||
directives: []
|
||||
directives: [],
|
||||
})
|
||||
class DemoApp {
|
||||
dialog: MdDialog;
|
||||
|
@ -43,16 +42,16 @@ class DemoApp {
|
|||
return;
|
||||
}
|
||||
|
||||
this.dialog.open(SimpleDialogComponent,
|
||||
this.elementRef, this.injector, this.dialogConfig).then(ref => {
|
||||
this.dialogRef = ref;
|
||||
ref.instance.numCoconuts = 777;
|
||||
this.dialog.open(SimpleDialogComponent, this.elementRef, this.injector, this.dialogConfig)
|
||||
.then(ref => {
|
||||
this.dialogRef = ref;
|
||||
ref.instance.numCoconuts = 777;
|
||||
|
||||
ref.whenClosed.then(result => {
|
||||
this.dialogRef = null;
|
||||
this.lastResult = result;
|
||||
});
|
||||
});
|
||||
ref.whenClosed.then(result => {
|
||||
this.dialogRef = null;
|
||||
this.lastResult = result;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
|
@ -62,7 +61,7 @@ class DemoApp {
|
|||
|
||||
@Component({
|
||||
selector: 'simple-dialog',
|
||||
properties: ['numCoconuts']
|
||||
properties: ['numCoconuts'],
|
||||
})
|
||||
@View({
|
||||
template: `
|
||||
|
@ -70,7 +69,7 @@ class DemoApp {
|
|||
<p>There are {{numCoconuts}} coconuts.</p>
|
||||
<p>Return: <input (input)="updateValue($event)"></p>
|
||||
<button type="button" (click)="done()">Done</button>
|
||||
`
|
||||
`,
|
||||
})
|
||||
class SimpleDialogComponent {
|
||||
numCoconuts: number;
|
||||
|
@ -95,9 +94,5 @@ class SimpleDialogComponent {
|
|||
|
||||
export function main() {
|
||||
commonDemoSetup();
|
||||
bootstrap(DemoApp, [
|
||||
bind(UrlResolver).toValue(new DemoUrlResolver())
|
||||
]);
|
||||
bootstrap(DemoApp, [bind(UrlResolver).toValue(new DemoUrlResolver())]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue