This repository was archived by the owner on Feb 2, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(dialog): support basic alert and confirm dialogs
1 parent
72e8381
commit 7236279
Showing
13 changed files
with
595 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<div class="md-padding" id="popupContainer"> | ||
<p class="inset"> | ||
Open a dialog over the app's content. Press escape or click outside to close the dialog and | ||
send focus back to the triggering button. | ||
</p> | ||
|
||
<div class="dialog-demo-content" layout="row" layout-wrap layout-margin> | ||
<button md-raised-button class="md-primary" (click)="showAlert($event)" flex="100" flex-gt-md="auto"> | ||
Alert Dialog | ||
</button> | ||
<button md-raised-button class="md-primary" (click)="showConfirm($event)" flex="100" flex-gt-md="auto"> | ||
Confirm Dialog | ||
</button> | ||
<button md-raised-button class="md-primary" (click)="showAdvanced($event)" flex="100" flex-gt-md="auto"> | ||
Custom Dialog | ||
</button> | ||
<div hide-gt-sm layout="row" layout-align="center center" flex="100"> | ||
<md-checkbox [(checked)]="customFullscreen" aria-label="Fullscreen Custom Dialog">Custom Dialog Fullscreen</md-checkbox> | ||
</div> | ||
<button md-raised-button class="md-primary" (click)="showTabDialog($event)" flex="100" flex-gt-md="auto"> | ||
Tab Dialog | ||
</button> | ||
</div> | ||
<p class="footer">Note: The <b>Confirm</b> dialog does not use <code>config.clickOutsideToClose(true)</code>.</p> | ||
|
||
<div *ngIf="status"> | ||
<br/> | ||
<b layout="row" layout-align="center center" class="md-padding"> | ||
{{status}} | ||
</b> | ||
</div> | ||
|
||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#popupContainer { | ||
position:relative; | ||
} | ||
|
||
.footer { | ||
width:100%; | ||
text-align: center; | ||
margin-left:20px; | ||
} | ||
.footer, .footer > code { | ||
font-size: 0.8em; | ||
margin-top:50px; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import {View, Component} from 'angular2/core'; | ||
import {MATERIAL_DIRECTIVES,MdDialog} from 'ng2-material/all'; | ||
import {ElementRef} from "angular2/core"; | ||
import {Input} from "angular2/core"; | ||
import {DOM} from "angular2/src/platform/dom/dom_adapter"; | ||
import {MdDialogConfig} from "ng2-material/components/dialog/dialog_config"; | ||
import {MdDialogBasic} from "ng2-material/components/dialog/dialog_basic"; | ||
import {MdDialogRef} from "ng2-material/components/dialog/dialog_ref"; | ||
|
||
|
||
function hasMedia(size: string) { | ||
// TODO: Implement as $mdMedia | ||
return true; | ||
} | ||
|
||
@Component({selector: 'dialog-basic-usage'}) | ||
@View({ | ||
templateUrl: 'examples/components/dialog/basic_usage.html', | ||
styleUrls: ['examples/components/dialog/basic_usage.css'], | ||
directives: [MATERIAL_DIRECTIVES] | ||
}) | ||
export default class DialogBasicUsage { | ||
|
||
status = ' '; | ||
customFullscreen = hasMedia('xs') || hasMedia('sm'); | ||
|
||
constructor(public dialog: MdDialog, public element: ElementRef) { | ||
|
||
} | ||
|
||
showAlert(ev) { | ||
let config = new MdDialogConfig() | ||
.parent(DOM.query('#popupContainer')) | ||
.textContent('You can specify some description text in here') | ||
.title('This is an alert title') | ||
.ok('Got it!') | ||
.targetEvent(ev); | ||
this.dialog.open(MdDialogBasic, this.element, config); | ||
//// Appending dialog to document.body to cover sidenav in docs app | ||
//// Modal dialogs should fully cover application | ||
//// to prevent interaction outside of dialog | ||
//this.dialog.show( | ||
// this.dialog.alert() | ||
// .parent(angular.element(document.querySelector('#popupContainer'))) | ||
// .clickOutsideToClose(true) | ||
// .title('This is an alert title') | ||
// .textContent('You can specify some description text in here.') | ||
// .ariaLabel('Alert Dialog Demo') | ||
// .ok('Got it!') | ||
// .targetEvent(ev) | ||
//); | ||
}; | ||
|
||
showConfirm(ev) { | ||
let config = new MdDialogConfig() | ||
.textContent('All of the banks have agreed to forgive you your debts.') | ||
.clickOutsideToClose(false) | ||
.title('Would you like to delete your debt?') | ||
.ariaLabel('Lucky day') | ||
.ok('Please do it!') | ||
.cancel('Sounds like a scam') | ||
.targetEvent(ev); | ||
this.dialog | ||
.open(MdDialogBasic, this.element, config) | ||
.then((ref: MdDialogRef) => { | ||
ref.whenClosed.then((result) => { | ||
if (result) { | ||
this.status = 'You decided to get rid of your debt.'; | ||
} | ||
else { | ||
this.status = 'You decided to keep your debt.'; | ||
} | ||
}) | ||
}); | ||
}; | ||
|
||
showAdvanced(ev) { | ||
//var useFullScreen = ($mdMedia('sm') || $mdMedia('xs')) && this.customFullscreen; | ||
// | ||
//this.dialog.show({ | ||
// controller: DialogController, | ||
// templateUrl: 'dialog1.tmpl.html', | ||
// parent: angular.element(document.body), | ||
// targetEvent: ev, | ||
// clickOutsideToClose: true, | ||
// fullscreen: useFullScreen | ||
// }) | ||
// .then((answer) => { | ||
// $scope.status = 'You said the information was "' + answer + '".'; | ||
// }, () =>{ | ||
// $scope.status = 'You cancelled the dialog.'; | ||
// }); | ||
// | ||
// | ||
//$scope.$watch(() =>{ | ||
// return $mdMedia('xs') || $mdMedia('sm'); | ||
//}, (wantsFullScreen) => { | ||
// this.customFullscreen = (wantsFullScreen === true); | ||
//}); | ||
|
||
}; | ||
|
||
showTabDialog(ev) { | ||
//this.dialog.show({ | ||
// controller: DialogController, | ||
// templateUrl: 'tabDialog.tmpl.html', | ||
// parent: angular.element(document.body), | ||
// targetEvent: ev, | ||
// clickOutsideToClose: true | ||
// }) | ||
// .then((answer) => { | ||
// this.status = 'You said the information was "' + answer + '".'; | ||
// }, () =>{ | ||
// this.status = 'You cancelled the dialog.'; | ||
// }); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,91 @@ | ||
@import "../../core/style/variables"; | ||
@import "../../core/style/shadows"; | ||
@import "../../core/style/default-theme"; | ||
|
||
.md-dialog { | ||
position: absolute; | ||
position: fixed; | ||
z-index: 80; | ||
|
||
/** Center the dialog. */ | ||
top: 50%; | ||
left: 50%; | ||
transform: translate(-50%, -50%); | ||
min-width: 300px; | ||
min-height: 100px; | ||
|
||
padding: $baseline-grid * 3; | ||
|
||
box-shadow: $whiteframe-shadow-13dp; | ||
display: flex; | ||
flex-direction: column; | ||
|
||
opacity: 0; | ||
transition: $swift-ease-out; | ||
transform: translate3d(-50%, -50%, 0) scale(0.2); | ||
|
||
order: 1; | ||
overflow: auto; | ||
-webkit-overflow-scrolling: touch; | ||
|
||
&:not([layout=row]) > * > *:first-child:not(.md-subheader) { | ||
margin-top: 0; | ||
} | ||
|
||
&:focus { | ||
outline: none; | ||
} | ||
|
||
&.md-active { | ||
opacity: 1; | ||
transition: $swift-ease-out; | ||
transform: translate3d(-50%, -50%, 0) scale(1.0); | ||
} | ||
|
||
&.md-dialog-absolute { | ||
position: absolute; | ||
} | ||
|
||
width: 300px; | ||
height: 300px; | ||
.md-actions, md-dialog-actions { | ||
display: flex; | ||
order: 2; | ||
box-sizing: border-box; | ||
align-items: center; | ||
justify-content: flex-end; | ||
padding-top: $baseline-grid * 3; | ||
padding-right: $baseline-grid; | ||
padding-left: $baseline-grid * 2; | ||
|
||
background-color: white; | ||
border: 1px solid black; | ||
box-shadow: 0 4px 4px;; | ||
// Align md-actions outside of the padding of .md-dialog | ||
margin-bottom: -$baseline-grid * 3; | ||
margin-left: -$baseline-grid * 3; | ||
margin-right: -$baseline-grid * 3; | ||
|
||
right: -$baseline-grid * 3; | ||
min-height: $baseline-grid * 6.5; | ||
overflow: hidden; | ||
|
||
[md-button], [md-raised-button] { | ||
margin-bottom: $baseline-grid; | ||
margin-left: $baseline-grid; | ||
margin-right: 0; | ||
margin-top: $baseline-grid; | ||
} | ||
} | ||
|
||
padding: 20px; | ||
} | ||
|
||
.md-backdrop { | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
background-color: rgba(0, 0, 0, 0.12); | ||
// Theme | ||
|
||
$dialog-border-radius: 4px !default; | ||
|
||
.md-dialog { | ||
border-radius: $dialog-border-radius; | ||
background-color: md-color($md-background, lighter); //'{{background-color}}'; | ||
|
||
&.md-content-overflow { | ||
.md-actions, md-dialog-actions { | ||
border-top-color: md-color($md-foreground, divider); //'{{foreground-4}}'; | ||
} | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
import {NgIf} from "angular2/common"; | ||
import {MdButton} from "ng2-material/components/button/button"; | ||
import {View} from "angular2/core"; | ||
import {Component} from "angular2/core"; | ||
import {IDialogComponent} from "./dialog"; | ||
import {MdDialogRef} from "ng2-material/components/dialog/dialog_ref"; | ||
import {Input} from "angular2/core"; | ||
@Component({selector: 'md-dialog-basic'}) | ||
@View({ | ||
template: ` | ||
<h2>{{ title }}</h2> | ||
<p>{{ textContent }}</p> | ||
<md-dialog-actions> | ||
<button md-button *ngIf="cancel != ''" type="button" (click)="dialog.close(false)"> | ||
<span>{{ cancel }}</span> | ||
</button> | ||
<button md-button *ngIf="ok != ''" class="md-primary" type="button" (click)="dialog.close(true)"> | ||
<span>{{ ok }}</span> | ||
</button> | ||
</md-dialog-actions>`, | ||
directives: [MdButton, NgIf] | ||
}) | ||
export class MdDialogBasic implements IDialogComponent { | ||
dialog: MdDialogRef; | ||
@Input() title: string = ''; | ||
@Input() textContent: string = ''; | ||
@Input() cancel: string = ''; | ||
@Input() ok: string = ''; | ||
@Input() type: string = 'alert'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
|
||
|
||
import {MdDialogRef} from "./dialog_ref"; | ||
|
||
/** Configuration for a dialog to be opened. */ | ||
export class MdDialogConfig { | ||
width: string = null; | ||
height: string = null; | ||
container: HTMLElement = null; | ||
sourceEvent: Event = null; | ||
clickClose: boolean = true; | ||
context: any = {}; | ||
|
||
parent(element: HTMLElement): MdDialogConfig { | ||
this.container = element; | ||
return this; | ||
} | ||
|
||
clickOutsideToClose(enabled: boolean): MdDialogConfig { | ||
this.clickClose = enabled; | ||
return this; | ||
} | ||
|
||
title(text: string): MdDialogConfig { | ||
this.context.title = text; | ||
return this; | ||
} | ||
|
||
textContent(text: string): MdDialogConfig { | ||
this.context.textContent = text; | ||
return this; | ||
} | ||
|
||
ariaLabel(text: string): MdDialogConfig { | ||
this.context.ariaLabel = text; | ||
return this; | ||
} | ||
|
||
ok(text: string): MdDialogConfig { | ||
this.context.ok = text; | ||
return this; | ||
} | ||
|
||
cancel(text: string): MdDialogConfig { | ||
this.context.cancel = text; | ||
return this; | ||
} | ||
|
||
targetEvent(ev: Event): MdDialogConfig { | ||
this.sourceEvent = ev; | ||
return this; | ||
} | ||
|
||
dialogRef(ref: MdDialogRef): MdDialogConfig { | ||
this.context.dialog = ref; | ||
return this; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import {ViewEncapsulation} from "angular2/core"; | ||
import {View} from "angular2/core"; | ||
import {Component} from "angular2/core"; | ||
import {ElementRef} from "angular2/core"; | ||
import {MdDialogRef} from "./dialog_ref"; | ||
import {KeyCodes} from "../../core/key_codes"; | ||
import {forwardRef} from "angular2/core"; | ||
import {Directive} from "angular2/core"; | ||
import {Host} from "angular2/core"; | ||
import {SkipSelf} from "angular2/core"; | ||
|
||
/** | ||
* Container for user-provided dialog content. | ||
*/ | ||
@Component({ | ||
selector: 'md-dialog-container', | ||
host: { | ||
'class': 'md-dialog', | ||
'tabindex': '0', | ||
'(body:keydown)': 'documentKeypress($event)', | ||
}, | ||
}) | ||
@View({ | ||
encapsulation: ViewEncapsulation.None, | ||
template: ` | ||
<md-dialog-content></md-dialog-content> | ||
<div tabindex="0" (focus)="wrapFocus()"></div>`, | ||
directives: [forwardRef(() => MdDialogContent)] | ||
}) | ||
export class MdDialogContainer { | ||
// Ref to the dialog content. Used by the DynamicComponentLoader to load the dialog content. | ||
contentRef: ElementRef; | ||
|
||
// Ref to the open dialog. Used to close the dialog based on certain events. | ||
dialogRef: MdDialogRef; | ||
|
||
constructor() { | ||
this.contentRef = null; | ||
this.dialogRef = null; | ||
} | ||
|
||
wrapFocus() { | ||
// Return the focus to the host element. Blocked on #1251. | ||
} | ||
|
||
documentKeypress(event: KeyboardEvent) { | ||
if (event.keyCode == KeyCodes.ESCAPE) { | ||
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' | ||
}) | ||
export class MdDialogContent { | ||
constructor(@Host() @SkipSelf() dialogContainer: MdDialogContainer, elementRef: ElementRef) { | ||
dialogContainer.contentRef = elementRef; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import {ComponentRef} from "angular2/core"; | ||
import {PromiseWrapper} from "angular2/src/facade/promise"; | ||
import {Animate} from "../../core/util/animate"; | ||
import {isPresent} from "angular2/src/facade/lang"; | ||
|
||
/** | ||
* Reference to an opened dialog. | ||
*/ | ||
export class MdDialogRef { | ||
// Reference to the MdDialogContainer component. | ||
containerRef: ComponentRef; | ||
|
||
// Reference to the MdBackdrop component. | ||
_backdropRef: ComponentRef; | ||
|
||
// Reference to the Component loaded as the dialog content. | ||
_contentRef: ComponentRef; | ||
|
||
// Whether the dialog is closed. | ||
isClosed: boolean; | ||
|
||
// Deferred resolved when the dialog is closed. The promise for this deferred is publicly exposed. | ||
whenClosedDeferred: any; | ||
|
||
// Deferred resolved when the content ComponentRef is set. Only used internally. | ||
contentRefDeferred: any; | ||
|
||
constructor() { | ||
this._contentRef = null; | ||
this.containerRef = null; | ||
this.isClosed = false; | ||
|
||
this.contentRefDeferred = PromiseWrapper.completer(); | ||
this.whenClosedDeferred = PromiseWrapper.completer(); | ||
} | ||
|
||
set backdropRef(value: ComponentRef) { | ||
this._backdropRef = value; | ||
let subscription = this._backdropRef.instance.onHiding.subscribe(() => { | ||
this.close(); | ||
subscription.unsubscribe(); | ||
}); | ||
} | ||
|
||
set contentRef(value: ComponentRef) { | ||
this._contentRef = value; | ||
this.contentRefDeferred.resolve(value); | ||
} | ||
|
||
/** Gets the component instance for the content of the dialog. */ | ||
get instance() { | ||
if (isPresent(this._contentRef)) { | ||
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`). | ||
throw "Cannot access dialog component instance *from* that component's constructor."; | ||
} | ||
|
||
|
||
/** Gets a promise that is resolved when the dialog is closed. */ | ||
get whenClosed(): Promise<any> { | ||
return this.whenClosedDeferred.promise; | ||
} | ||
|
||
/** Closes the dialog. This operation is asynchronous. */ | ||
close(result: any = null): Promise<void> { | ||
return Animate.leave(this.containerRef.location.nativeElement, 'md-active').then(() => { | ||
this._backdropRef.instance.hide(); | ||
return this.contentRefDeferred.promise.then((_) => { | ||
if (!this.isClosed) { | ||
this.isClosed = true; | ||
this.containerRef.dispose(); | ||
this.whenClosedDeferred.resolve(result); | ||
} | ||
}); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters