mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
alert wip
This commit is contained in:
@ -18,7 +18,6 @@
|
||||
"components/list/list.ios",
|
||||
"components/menu/menu.ios",
|
||||
"components/modal/modal.ios",
|
||||
"components/popup/popup.ios",
|
||||
"components/radio/radio.ios",
|
||||
"components/searchbar/searchbar.ios",
|
||||
"components/segment/segment.ios",
|
||||
|
@ -7,6 +7,7 @@
|
||||
@import
|
||||
"components/app/app.md",
|
||||
"components/action-sheet/action-sheet.md",
|
||||
"components/alert/alert.md",
|
||||
"components/badge/badge.md",
|
||||
"components/button/button.md",
|
||||
"components/card/card.md",
|
||||
@ -17,7 +18,6 @@
|
||||
"components/list/list.md",
|
||||
"components/menu/menu.md",
|
||||
"components/modal/modal.md",
|
||||
"components/popup/popup.md",
|
||||
"components/radio/radio.md",
|
||||
"components/tap-click/ripple",
|
||||
"components/searchbar/searchbar.md",
|
||||
|
@ -25,8 +25,6 @@ export * from './components/nav/nav-push'
|
||||
export * from './components/nav/nav-router'
|
||||
export * from './components/navbar/navbar'
|
||||
export * from './components/overlay/overlay'
|
||||
export * from './components/overlay/overlay-controller'
|
||||
export * from './components/popup/popup'
|
||||
export * from './components/slides/slides'
|
||||
export * from './components/radio/radio'
|
||||
export * from './components/scroll/scroll'
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {Component, Injectable, Renderer} from 'angular2/core';
|
||||
import {NgFor, NgIf} from 'angular2/common';
|
||||
|
||||
import {OverlayController} from '../overlay/overlay-controller';
|
||||
import {Config} from '../../config/config';
|
||||
import {Icon} from '../icon/icon';
|
||||
import {Animation} from '../../animations/animation';
|
||||
@ -109,8 +108,8 @@ class ActionSheetCmp {
|
||||
@Injectable()
|
||||
export class ActionSheet {
|
||||
|
||||
constructor(ctrl: OverlayController, config: Config) {
|
||||
this.ctrl = ctrl;
|
||||
constructor(config: Config) {
|
||||
//this.ctrl = ctrl;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
@ -2,5 +2,3 @@
|
||||
<ion-content padding>
|
||||
<button class="e2eOpenActionSheet" (click)="openActionSheet()">Open Action Sheet</button>
|
||||
</ion-content>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
||||
|
75
ionic/components/alert/alert.md.scss
Normal file
75
ionic/components/alert/alert.md.scss
Normal file
@ -0,0 +1,75 @@
|
||||
@import "../../globals.md";
|
||||
@import "./alert";
|
||||
|
||||
// Material Design Alerts
|
||||
// --------------------------------------------------
|
||||
|
||||
$alert-md-max-width: 280px !default;
|
||||
$alert-md-border-radius: 2px !default;
|
||||
$alert-md-background-color: #fafafa !default;
|
||||
$alert-md-box-shadow: 0px 16px 20px rgba(0, 0, 0, 0.4) !default;
|
||||
|
||||
$alert-md-head-text-align: left !default;
|
||||
$alert-md-head-padding: 24px 24px 10px 24px !default;
|
||||
|
||||
$alert-md-title-font-size: 20px !default;
|
||||
$alert-md-sub-title-font-size: 15px !default;
|
||||
|
||||
$alert-md-body-padding: 10px 24px 24px 24px !default;
|
||||
$alert-md-body-text-color: rgba(0,0,0,.5) !default;
|
||||
|
||||
$alert-md-input-border-color: #dedede !default;
|
||||
$alert-md-input-text-color: #000000 !default;
|
||||
$alert-md-input-highlight-color: map-get($colors-md, primary) !default;
|
||||
$alert-md-input-margin-top: 5px !default;
|
||||
$alert-md-input-margin-bottom: 5px !default;
|
||||
|
||||
$alert-md-buttons-padding: 8px 8px 8px 24px !default;
|
||||
$alert-md-buttons-justify-content: flex-end !default;
|
||||
|
||||
|
||||
.alert-wrapper {
|
||||
max-width: $alert-md-max-width;
|
||||
border-radius: $alert-md-border-radius;
|
||||
background-color: $alert-md-background-color;
|
||||
|
||||
box-shadow: $alert-md-box-shadow;
|
||||
}
|
||||
|
||||
.alert-head {
|
||||
text-align: $alert-md-head-text-align;
|
||||
padding: $alert-md-head-padding;
|
||||
}
|
||||
|
||||
.alert-title {
|
||||
font-size: $alert-md-title-font-size;
|
||||
}
|
||||
|
||||
.alert-sub-title {
|
||||
font-size: $alert-md-sub-title-font-size;
|
||||
}
|
||||
|
||||
.alert-body {
|
||||
padding: $alert-md-body-padding;
|
||||
color: $alert-md-body-text-color;
|
||||
}
|
||||
|
||||
.alert-input {
|
||||
border-bottom: 1px solid $alert-md-input-border-color;
|
||||
color: $alert-md-input-text-color;
|
||||
margin: $alert-md-input-margin-top 0 $alert-md-input-margin-bottom 0;
|
||||
|
||||
&:focus {
|
||||
border-bottom: 2px solid $alert-md-input-highlight-color;
|
||||
margin-bottom: $alert-md-input-margin-bottom - 1;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-buttons {
|
||||
padding: $alert-md-buttons-padding;
|
||||
justify-content: $alert-md-buttons-justify-content;
|
||||
}
|
||||
|
||||
.alert-button.activated {
|
||||
opacity: 1;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import {Component, ElementRef, Renderer} from 'angular2/core';
|
||||
import {NgClass, NgIf, NgFor, FORM_DIRECTIVES} from 'angular2/common';
|
||||
|
||||
import {NavParams} from '../nav/nav-controller';
|
||||
import {NavController, NavParams} from '../nav/nav-controller';
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
import {Animation} from '../../animations/animation';
|
||||
import {Button} from '../button/button';
|
||||
@ -11,17 +11,15 @@ import {extend, isDefined} from '../../util/util';
|
||||
export class Alert extends ViewController {
|
||||
|
||||
constructor(opts={}) {
|
||||
super(null, AlertCmp, opts);
|
||||
super(AlertCmp, opts);
|
||||
|
||||
this.data.inputs = this.data.inputs || [];
|
||||
let buttons = this.data.buttons || [];
|
||||
this.data.buttons = [];
|
||||
for (let button of buttons) {
|
||||
this.addButton(button);
|
||||
}
|
||||
this.data.buttons = this.data.buttons || [];
|
||||
}
|
||||
|
||||
this.enterAnimationKey = 'alertEnter';
|
||||
this.leaveAnimationKey = 'alertLeave';
|
||||
getTransitionName(direction) {
|
||||
let key = (direction === 'back' ? 'alertLeave' : 'alertEnter');
|
||||
return this._nav.config.get(key);
|
||||
}
|
||||
|
||||
setTitle(title) {
|
||||
@ -37,26 +35,19 @@ export class Alert extends ViewController {
|
||||
}
|
||||
|
||||
addInput(input) {
|
||||
input.value = isDefined(input.value) ? input.value : '';
|
||||
this.data.inputs.push(input);
|
||||
}
|
||||
|
||||
addButton(button) {
|
||||
if (typeof button === 'string') {
|
||||
button = {
|
||||
text: button
|
||||
};
|
||||
}
|
||||
this.data.buttons.push(button);
|
||||
}
|
||||
|
||||
close() {
|
||||
let index = this._nav.indexOf(this);
|
||||
this._nav.remove(index, { animateFirst: true });
|
||||
onDismiss(handler) {
|
||||
this.data.onDismiss = handler;
|
||||
}
|
||||
|
||||
onClose(handler) {
|
||||
this.data.onClose = handler;
|
||||
dismiss() {
|
||||
this._nav.dismiss(this);
|
||||
}
|
||||
|
||||
static create(opts={}) {
|
||||
@ -69,7 +60,7 @@ export class Alert extends ViewController {
|
||||
@Component({
|
||||
selector: 'ion-alert',
|
||||
template:
|
||||
'<div (click)="close()" tappable disable-activated class="backdrop" role="presentation"></div>' +
|
||||
'<div (click)="dismiss()" tappable disable-activated class="backdrop" role="presentation"></div>' +
|
||||
'<div class="alert-wrapper">' +
|
||||
'<div class="alert-head">' +
|
||||
'<h2 class="alert-title" *ngIf="d.title">{{d.title}}</h2>' +
|
||||
@ -78,8 +69,8 @@ export class Alert extends ViewController {
|
||||
'<div class="alert-body" *ngIf="d.body">{{d.body}}</div>' +
|
||||
'<div class="alert-body alert-inputs" *ngIf="d.inputs.length">' +
|
||||
'<div class="alert-input-wrapper" *ngFor="#i of d.inputs">' +
|
||||
'<div class="alert-input-title" *ngIf="i.title">{{i.title}}</div>' +
|
||||
'<input [placeholder]="i.placeholder" [(ngModel)]="i.input" [value]="i.value" class="alert-input">' +
|
||||
'<div class="alert-input-label" *ngIf="i.label">{{i.label}}</div>' +
|
||||
'<input [placeholder]="i.placeholder" [(ngModel)]="i.value" [type]="i.type" class="alert-input">' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="alert-buttons">' +
|
||||
@ -97,54 +88,93 @@ class AlertCmp {
|
||||
|
||||
constructor(
|
||||
private _viewCtrl: ViewController,
|
||||
elementRef: ElementRef,
|
||||
private _elementRef: ElementRef,
|
||||
params: NavParams,
|
||||
renderer: Renderer
|
||||
) {
|
||||
this.d = params.data;
|
||||
if (this.d.cssClass) {
|
||||
renderer.setElementClass(elementRef, this.d.cssClass, true);
|
||||
renderer.setElementClass(_elementRef, this.d.cssClass, true);
|
||||
}
|
||||
}
|
||||
|
||||
click(button, ev) {
|
||||
let shouldClose = true;
|
||||
click(button) {
|
||||
let shouldDismiss = true;
|
||||
|
||||
if (button.handler) {
|
||||
// a handler has been provided, run it
|
||||
if (button.handler(this.getValue()) === false) {
|
||||
if (button.handler(this.getValues()) === false) {
|
||||
// if the return value is a false then do not close
|
||||
shouldClose = false;
|
||||
shouldDismiss = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldClose) {
|
||||
this.close();
|
||||
if (shouldDismiss) {
|
||||
this.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this._viewCtrl.close();
|
||||
dismiss() {
|
||||
this._viewCtrl.dismiss(this);
|
||||
}
|
||||
|
||||
getValue() {
|
||||
let inputs = this.d.inputs;
|
||||
if (inputs) {
|
||||
if (inputs.length > 1) {
|
||||
// array of values for each input
|
||||
return inputs.map(i => i.input);
|
||||
getValues() {
|
||||
let values = {};
|
||||
this.d.inputs.forEach(input => {
|
||||
values[input.name] = input.value;
|
||||
});
|
||||
return values;
|
||||
}
|
||||
|
||||
} else if (inputs.length === 1) {
|
||||
// single value of the one input
|
||||
return inputs[0].input;
|
||||
onPageWillEnter() {
|
||||
// normalize the data
|
||||
this.d.buttons = this.d.buttons.map(button => {
|
||||
if (typeof button === 'string') {
|
||||
return { text: button };
|
||||
}
|
||||
return button;
|
||||
});
|
||||
|
||||
this.d.inputs = this.d.inputs.map((input, index) => {
|
||||
return {
|
||||
name: input.name || index,
|
||||
label: input.label,
|
||||
placeholder: input.placeholder || '',
|
||||
type: input.type || 'text',
|
||||
value: isDefined(input.value) ? input.value : ''
|
||||
}
|
||||
});
|
||||
|
||||
let self = this;
|
||||
self.keyUp = function(ev) {
|
||||
if (ev.keyCode === 13) {
|
||||
// enter
|
||||
console.debug('alert enter');
|
||||
let button = self.d.buttons[self.d.buttons.length - 1];
|
||||
self.click(button);
|
||||
|
||||
} else if (ev.keyCode === 27) {
|
||||
console.debug('alert escape');
|
||||
self.dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keyup', this.keyUp);
|
||||
}
|
||||
|
||||
onPageDidEnter() {
|
||||
document.activeElement && document.activeElement.blur();
|
||||
if (this.d.inputs.length) {
|
||||
let firstInput = this._elementRef.nativeElement.querySelector('input');
|
||||
if (firstInput) {
|
||||
firstInput.focus();
|
||||
}
|
||||
}
|
||||
// there are no inputs
|
||||
return null;
|
||||
}
|
||||
|
||||
onPageDidLeave() {
|
||||
this.d.onClose && this.d.onClose(this.getValue());
|
||||
this.d.onDismiss && this.d.onDismiss(this.getValues());
|
||||
document.removeEventListener('keyup', this.keyUp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,18 @@
|
||||
import {App, Alert, OverlayController} from 'ionic/ionic';
|
||||
import {App, Page, Alert, NavController} from 'ionic/ionic';
|
||||
|
||||
|
||||
@App({
|
||||
@Page({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class E2EApp {
|
||||
class E2EPage {
|
||||
|
||||
constructor(private overlay: OverlayController) {
|
||||
this.alertOpen = false;
|
||||
this.confirmOpen = false;
|
||||
this.promptOpen = false;
|
||||
this.promptResult = '';
|
||||
constructor(nav: NavController) {
|
||||
this.nav = nav;
|
||||
this.testAlertOpen = false;
|
||||
this.testConfirmOpen = false;
|
||||
this.testPromptOpen = false;
|
||||
this.testConfirmResult = '';
|
||||
this.testPromptResult = '';
|
||||
}
|
||||
|
||||
doAlert() {
|
||||
@ -18,34 +20,41 @@ class E2EApp {
|
||||
title: 'Alert!',
|
||||
subTitle: 'Subtitle!!!',
|
||||
buttons: ['Ok'],
|
||||
onClose: () => {
|
||||
this.alertOpen = false;
|
||||
onDismiss: () => {
|
||||
this.testAlertOpen = false;
|
||||
}
|
||||
});
|
||||
|
||||
this.overlay.push(alert);
|
||||
this.nav.present(alert);
|
||||
|
||||
this.alertOpen = true;
|
||||
this.testAlertOpen = true;
|
||||
}
|
||||
|
||||
doConfirm() {
|
||||
let alert = Alert.create();
|
||||
alert.setTitle('Confirm!');
|
||||
alert.setBody('Body text!!!');
|
||||
alert.addButton('Cancel');
|
||||
alert.addButton({
|
||||
text: 'Cancel',
|
||||
handler: () => {
|
||||
console.log('Confirm Cancel');
|
||||
this.testConfirmResult = 'Cancel';
|
||||
}
|
||||
});
|
||||
alert.addButton({
|
||||
text: 'Ok',
|
||||
handler: () => {
|
||||
console.log('Confirm Ok');
|
||||
this.testConfirmResult = 'Ok';
|
||||
}
|
||||
});
|
||||
|
||||
alert.onClose(data => {
|
||||
this.confirmOpen = false;
|
||||
alert.onDismiss(data => {
|
||||
this.testConfirmOpen = false;
|
||||
});
|
||||
|
||||
this.overlay.push(alert).then(() => {
|
||||
this.confirmOpen = true;
|
||||
this.nav.present(alert).then(() => {
|
||||
this.testConfirmOpen = true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -53,8 +62,13 @@ class E2EApp {
|
||||
let alert = Alert.create();
|
||||
alert.setTitle('Prompt!');
|
||||
alert.addInput({
|
||||
label: 'Input Label',
|
||||
placeholder: 'Placeholder'
|
||||
placeholder: 'Placeholder 1'
|
||||
});
|
||||
alert.addInput({
|
||||
name: 'name2',
|
||||
value: 'hello',
|
||||
label: 'Input Label 2',
|
||||
placeholder: 'Placeholder 2'
|
||||
});
|
||||
alert.addButton({
|
||||
text: 'Cancel',
|
||||
@ -76,13 +90,24 @@ class E2EApp {
|
||||
}
|
||||
});
|
||||
|
||||
alert.onClose(data => {
|
||||
this.promptOpen = false;
|
||||
this.promptResult = data;
|
||||
alert.onDismiss(data => {
|
||||
this.testPromptOpen = false;
|
||||
this.testPromptResult = data;
|
||||
});
|
||||
|
||||
this.overlay.push(alert).then(() => {
|
||||
this.promptOpen = true;
|
||||
this.nav.present(alert).then(() => {
|
||||
this.testPromptOpen = true;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@App({
|
||||
template: '<ion-nav [root]="root"></ion-nav>'
|
||||
})
|
||||
class E2EApp {
|
||||
constructor() {
|
||||
this.root = E2EPage;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
|
||||
<ion-navbar *navbar>
|
||||
<ion-title>Alerts</ion-title>
|
||||
</ion-navbar>
|
||||
|
||||
<ion-content padding>
|
||||
|
||||
<button class="e2eOpenAlert" (click)="doAlert()">Alert</button>
|
||||
@ -6,12 +10,11 @@
|
||||
<button class="e2eOpenPrompt" (click)="doPrompt()">Prompt</button>
|
||||
|
||||
<pre>
|
||||
Alert Opened: {{alertOpen}}
|
||||
Confirm Opened: {{confirmOpen}}
|
||||
Prompt Opened: {{promptOpen}}
|
||||
Prompt Result: {{promptResult}}
|
||||
Alert Opened: {{testAlertOpen}}
|
||||
Confirm Opened: {{testConfirmOpen}}
|
||||
Confirm Result: {{testConfirmResult}}
|
||||
Prompt Opened: {{testPromptOpen}}
|
||||
Prompt Result: {{testPromptResult | json}}
|
||||
</pre>
|
||||
|
||||
</ion-content>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
||||
|
@ -105,5 +105,3 @@
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
||||
|
@ -46,5 +46,3 @@
|
||||
</ion-menu>
|
||||
|
||||
<ion-nav id="nav" [root]="rootView" #content swipe-back-enabled="false"></ion-nav>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {Injectable, Type} from 'angular2/core';
|
||||
|
||||
import {OverlayController} from '../overlay/overlay-controller';
|
||||
import {Config} from '../../config/config';
|
||||
import {Animation} from '../../animations/animation';
|
||||
import {extend} from '../../util';
|
||||
@ -42,8 +41,8 @@ import {extend} from '../../util';
|
||||
@Injectable()
|
||||
export class Modal {
|
||||
|
||||
constructor(ctrl: OverlayController, config: Config) {
|
||||
this.ctrl = ctrl;
|
||||
constructor(config: Config) {
|
||||
//this.ctrl = ctrl;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
|
@ -13,5 +13,3 @@
|
||||
<button (click)="openModalCustomAnimation()">Modal: Custom Animation</button>
|
||||
</p>
|
||||
</ion-content>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
||||
|
@ -245,39 +245,18 @@ export class NavController extends Ion {
|
||||
return Promise.reject('nav controller actively transitioning');
|
||||
}
|
||||
|
||||
this.setTransitioning(true, 500);
|
||||
|
||||
let promise = null;
|
||||
if (!callback) {
|
||||
promise = new Promise(res => { callback = res; });
|
||||
}
|
||||
|
||||
// create a new ViewController
|
||||
let enteringView = new ViewController(this, componentType, params);
|
||||
enteringView.pageType = opts.pageType;
|
||||
enteringView.handle = opts.handle || null;
|
||||
|
||||
this.pushView(enteringView, opts, callback);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
pushView(enteringView, opts, callback) {
|
||||
this.setTransitioning(true, 500);
|
||||
|
||||
// do not animate if this is the first in the stack
|
||||
if (!this._views.length && !opts.animateFirst) {
|
||||
opts.animate = false;
|
||||
}
|
||||
|
||||
// default the direction to "forward"
|
||||
opts.direction = opts.direction || 'forward';
|
||||
|
||||
if (!opts.animation) {
|
||||
opts.animation = this.config.get(enteringView.enterAnimationKey);
|
||||
}
|
||||
|
||||
// the active view is going to be the leaving one (if one exists)
|
||||
let leavingView = this.getActive() || new ViewController();
|
||||
leavingView.shouldCache = (isBoolean(opts.cacheLeavingView) ? opts.cacheLeavingView : true);
|
||||
@ -286,16 +265,78 @@ export class NavController extends Ion {
|
||||
leavingView.willUnload();
|
||||
}
|
||||
|
||||
// create a new ViewController
|
||||
let enteringView = new ViewController(componentType, params);
|
||||
enteringView.setNav(this);
|
||||
enteringView.pageType = opts.pageType;
|
||||
enteringView.handle = opts.handle || null;
|
||||
|
||||
// default the direction to "forward"
|
||||
opts.direction = opts.direction || 'forward';
|
||||
|
||||
if (!opts.animation) {
|
||||
opts.animation = enteringView.getTransitionName(opts.direction);
|
||||
}
|
||||
|
||||
// add the view to the stack
|
||||
this._add(enteringView);
|
||||
|
||||
if (this.router) {
|
||||
// notify router of the state change
|
||||
this.router.stateChange('push', enteringView, enteringView.params);
|
||||
this.router.stateChange('push', enteringView, params);
|
||||
}
|
||||
|
||||
// start the transition
|
||||
this._transition(enteringView, leavingView, opts, callback);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
present(enteringView, opts={}) {
|
||||
enteringView.setNav(this);
|
||||
|
||||
let resolve;
|
||||
let promise = new Promise(res => { resolve = res; });
|
||||
|
||||
opts.keyboardClose = false;
|
||||
opts.skipCache = true;
|
||||
opts.direction = 'forward';
|
||||
|
||||
if (!opts.animation) {
|
||||
opts.animation = enteringView.getTransitionName(opts.direction);
|
||||
}
|
||||
|
||||
// the active view is going to be the leaving one (if one exists)
|
||||
let leavingView = this.getActive() || new ViewController();
|
||||
leavingView.shouldCache = (isBoolean(opts.cacheLeavingView) ? opts.cacheLeavingView : true);
|
||||
leavingView.shouldDestroy = !leavingView.shouldCache;
|
||||
if (leavingView.shouldDestroy) {
|
||||
leavingView.willUnload();
|
||||
}
|
||||
|
||||
let rootNav = this.rootNav;
|
||||
|
||||
// add the view to the stack
|
||||
rootNav._add(enteringView);
|
||||
|
||||
// start the transition
|
||||
rootNav._transition(enteringView, leavingView, opts, resolve);
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
dismiss(leavingView, opts={}) {
|
||||
opts.skipCache = true;
|
||||
opts.direction ='back';
|
||||
|
||||
if (!opts.animation) {
|
||||
opts.animation = leavingView.getTransitionName(opts.direction);
|
||||
}
|
||||
|
||||
let rootNav = this.rootNav;
|
||||
|
||||
let index = rootNav.indexOf(leavingView);
|
||||
return rootNav.remove(index, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,9 +371,6 @@ export class NavController extends Ion {
|
||||
let resolve = null;
|
||||
let promise = new Promise(res => { resolve = res; });
|
||||
|
||||
// default the direction to "back"
|
||||
opts.direction = opts.direction || 'back';
|
||||
|
||||
// get the active view and set that it is staged to be leaving
|
||||
// was probably the one popped from the stack
|
||||
let leavingView = this.getActive() || new ViewController();
|
||||
@ -342,10 +380,6 @@ export class NavController extends Ion {
|
||||
leavingView.willUnload();
|
||||
}
|
||||
|
||||
if (!opts.animation) {
|
||||
opts.animation = this.config.get(leavingView.leaveAnimationKey);
|
||||
}
|
||||
|
||||
// the entering view is now the new last view
|
||||
// Note: we might not have an entering view if this is the
|
||||
// only view on the history stack.
|
||||
@ -355,6 +389,13 @@ export class NavController extends Ion {
|
||||
this.router.stateChange('pop', enteringView);
|
||||
}
|
||||
|
||||
// default the direction to "back"
|
||||
opts.direction = opts.direction || 'back';
|
||||
|
||||
if (!opts.animation) {
|
||||
opts.animation = leavingView.getTransitionName(opts.direction);
|
||||
}
|
||||
|
||||
// start the transition
|
||||
this._transition(enteringView, leavingView, opts, resolve);
|
||||
|
||||
@ -382,7 +423,11 @@ export class NavController extends Ion {
|
||||
|
||||
let resolve = null;
|
||||
let promise = new Promise(res => { resolve = res; });
|
||||
|
||||
opts.direction = opts.direction || 'back';
|
||||
if (!opts.animation) {
|
||||
opts.animation = viewCtrl.getTransitionName(opts.direction);
|
||||
}
|
||||
|
||||
let leavingView = this.getActive() || new ViewController();
|
||||
|
||||
@ -451,7 +496,8 @@ export class NavController extends Ion {
|
||||
}
|
||||
|
||||
// create new ViewController, but don't render yet
|
||||
let viewCtrl = new ViewController(this, componentType, params);
|
||||
let viewCtrl = new ViewController(componentType, params);
|
||||
viewCtrl.setNav(this);
|
||||
viewCtrl.state = CACHED_STATE;
|
||||
viewCtrl.shouldDestroy = false;
|
||||
viewCtrl.shouldCache = false;
|
||||
@ -625,7 +671,8 @@ export class NavController extends Ion {
|
||||
// could be an object with a componentType property, or it is a componentType
|
||||
componentType = componentObj.componentType || componentObj;
|
||||
|
||||
viewCtrl = new ViewController(this, componentType, componentObj.params);
|
||||
viewCtrl = new ViewController(componentType, componentObj.params);
|
||||
viewCtrl.setNav(this);
|
||||
viewCtrl.state = CACHED_STATE;
|
||||
viewCtrl.shouldDestroy = false;
|
||||
viewCtrl.shouldCache = false;
|
||||
@ -760,7 +807,7 @@ export class NavController extends Ion {
|
||||
// make sure the entering and leaving views are showing
|
||||
// and all others are hidden, but don't remove the leaving view yet
|
||||
// DOM WRITE
|
||||
this._cleanup(enteringView, leavingView, true);
|
||||
this._cleanup(enteringView, leavingView, true, opts.skipCache);
|
||||
|
||||
// lifecycle events may have updated some data
|
||||
// wait one frame and allow the raf to do a change detection
|
||||
@ -858,7 +905,7 @@ export class NavController extends Ion {
|
||||
leavingView.didLeave();
|
||||
}
|
||||
|
||||
if (this.keyboard.isOpen()) {
|
||||
if (opts.keyboardClose !== false && this.keyboard.isOpen()) {
|
||||
// the keyboard is still open!
|
||||
// no problem, let's just close for them
|
||||
this.keyboard.close();
|
||||
@ -1038,7 +1085,7 @@ export class NavController extends Ion {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_cleanup(activeView, previousView, skipDestroy) {
|
||||
_cleanup(activeView, previousView, skipDestroy, skipCache) {
|
||||
// the active page, and the previous page, should be rendered in dom and ready to go
|
||||
// all others, like a cached page 2 back, should be display: none and not rendered
|
||||
let destroys = [];
|
||||
@ -1050,7 +1097,7 @@ export class NavController extends Ion {
|
||||
if (view.shouldDestroy && !skipDestroy) {
|
||||
destroys.push(view);
|
||||
|
||||
} else if (view.isLoaded()) {
|
||||
} else if (view.isLoaded() && !skipCache) {
|
||||
let shouldShow = (view === activeView) || (view === previousView);
|
||||
this._cachePage(view, shouldShow);
|
||||
}
|
||||
|
57
ionic/components/nav/overlay-controller.ts
Normal file
57
ionic/components/nav/overlay-controller.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import {ViewController} from '../view-controller';
|
||||
import {Config} from '../../config/config';
|
||||
import {IonicApp} from '../app/app';
|
||||
|
||||
|
||||
export class OverlayController extends ViewController {
|
||||
|
||||
constructor(navCtrl, componentType, opts={}) {
|
||||
super(null, AlertCmp, opts);
|
||||
|
||||
this.data.inputs = this.data.inputs || [];
|
||||
let buttons = this.data.buttons || [];
|
||||
this.data.buttons = [];
|
||||
for (let button of buttons) {
|
||||
this.addButton(button);
|
||||
}
|
||||
|
||||
this.enterAnimationKey = 'alertEnter';
|
||||
this.leaveAnimationKey = 'alertLeave';
|
||||
}
|
||||
|
||||
setTitle(title) {
|
||||
this.data.title = title;
|
||||
}
|
||||
|
||||
setSubTitle(subTitle) {
|
||||
this.data.subTitle = subTitle;
|
||||
}
|
||||
|
||||
setBody(body) {
|
||||
this.data.body = body;
|
||||
}
|
||||
|
||||
addInput(input) {
|
||||
input.value = isDefined(input.value) ? input.value : '';
|
||||
this.data.inputs.push(input);
|
||||
}
|
||||
|
||||
addButton(button) {
|
||||
if (typeof button === 'string') {
|
||||
button = {
|
||||
text: button
|
||||
};
|
||||
}
|
||||
this.data.buttons.push(button);
|
||||
}
|
||||
|
||||
close() {
|
||||
let index = this._nav.indexOf(this);
|
||||
this._nav.remove(index, { animateFirst: true });
|
||||
}
|
||||
|
||||
onClose(handler) {
|
||||
this.data.onClose = handler;
|
||||
}
|
||||
|
||||
}
|
@ -222,8 +222,8 @@ export function run() {
|
||||
describe("first", () => {
|
||||
it('should get the first item', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(null, FirstPage),
|
||||
vc3 = new ViewController(null, SecondPage);
|
||||
vc2 = new ViewController(FirstPage),
|
||||
vc3 = new ViewController(SecondPage);
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
|
||||
expect(nav.first()).toBe(vc1);
|
||||
@ -241,9 +241,9 @@ export function run() {
|
||||
|
||||
describe("popTo", () => {
|
||||
it('should popTo 1st view', () => {
|
||||
let vc1 = new ViewController(null, FirstPage),
|
||||
vc2 = new ViewController(null, SecondPage),
|
||||
vc3 = new ViewController(null, ThirdPage);
|
||||
let vc1 = new ViewController(FirstPage),
|
||||
vc2 = new ViewController(SecondPage),
|
||||
vc3 = new ViewController(ThirdPage);
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
|
||||
nav._transition = mockTransitionFn;
|
||||
@ -257,8 +257,8 @@ export function run() {
|
||||
describe("remove", () => {
|
||||
it('should remove the view at the specified index', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(null, FirstPage),
|
||||
vc3 = new ViewController(null, SecondPage);
|
||||
vc2 = new ViewController(FirstPage),
|
||||
vc3 = new ViewController(SecondPage);
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
expect(nav._views.length).toBe(3);
|
||||
expect(nav._views[1].componentType).toBe(FirstPage);
|
||||
@ -271,8 +271,8 @@ export function run() {
|
||||
|
||||
it('should pop if index is of active view', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(null, FirstPage),
|
||||
vc3 = new ViewController(null, SecondPage);
|
||||
vc2 = new ViewController(FirstPage),
|
||||
vc3 = new ViewController(SecondPage);
|
||||
|
||||
vc3.state = 1; //ACTIVE_STATE
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
|
@ -17,8 +17,7 @@ import {NavParams} from './nav-controller';
|
||||
*/
|
||||
export class ViewController {
|
||||
|
||||
constructor(navCtrl, componentType, data={}) {
|
||||
this.setNav(navCtrl);
|
||||
constructor(componentType, data={}) {
|
||||
this.componentType = componentType;
|
||||
this.data = data;
|
||||
this.instance = {};
|
||||
@ -27,14 +26,16 @@ export class ViewController {
|
||||
this._loaded = false;
|
||||
this.shouldDestroy = false;
|
||||
this.shouldCache = false;
|
||||
this.enterAnimationKey = 'pageTransition';
|
||||
this.leaveAnimationKey = 'pageTransition';
|
||||
}
|
||||
|
||||
setNav(navCtrl) {
|
||||
this._nav = navCtrl;
|
||||
}
|
||||
|
||||
getTransitionName(direction) {
|
||||
return this._nav && this._nav.config.get('pageTransition');
|
||||
}
|
||||
|
||||
getNavParams() {
|
||||
return new NavParams(this.data);
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
import {Injectable} from 'angular2/core';
|
||||
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
import {Config} from '../../config/config';
|
||||
import {IonicApp} from '../app/app';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class OverlayController {
|
||||
|
||||
constructor(private _config: Config) {}
|
||||
|
||||
push(overlayView, opts={}) {
|
||||
overlayView.setNav(this._nav);
|
||||
opts.animateFirst = true;
|
||||
|
||||
return new Promise(resolve => {
|
||||
this._nav.pushView(overlayView, opts, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
pop(opts={}) {
|
||||
opts.animateFirst = true;
|
||||
return this._nav.pop(opts);
|
||||
}
|
||||
|
||||
setNav(nav) {
|
||||
this._nav = nav;
|
||||
}
|
||||
|
||||
}
|
@ -1,41 +1,17 @@
|
||||
import {ChangeDetectorRef, Component, ElementRef, Compiler, AppViewManager, NgZone, Renderer} from 'angular2/core';
|
||||
|
||||
import {IonicApp} from '../app/app';
|
||||
import {Config} from '../../config/config';
|
||||
import {Keyboard} from '../../util/keyboard';
|
||||
import {OverlayController} from './overlay-controller';
|
||||
import {NavController} from '../nav/nav-controller';
|
||||
|
||||
import {Directive} from 'angular2/core';
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@Component({
|
||||
selector: 'ion-overlay',
|
||||
template: ''
|
||||
@Directive({
|
||||
selector: 'ion-overlay'
|
||||
})
|
||||
export class OverlayNav extends NavController {
|
||||
export class OverlayNav {
|
||||
|
||||
constructor(
|
||||
overlayCtrl: OverlayController,
|
||||
app: IonicApp,
|
||||
config: Config,
|
||||
keyboard: Keyboard,
|
||||
elementRef: ElementRef,
|
||||
compiler: Compiler,
|
||||
viewManager: AppViewManager,
|
||||
zone: NgZone,
|
||||
renderer: Renderer,
|
||||
cd: ChangeDetectorRef
|
||||
) {
|
||||
super(null, app, config, keyboard, elementRef, null, compiler, viewManager, zone, renderer, cd);
|
||||
|
||||
if (overlayCtrl.anchor) {
|
||||
throw ('An app should only have one <ion-overlay></ion-overlay>');
|
||||
}
|
||||
|
||||
this.initZIndex = 1000;
|
||||
overlayCtrl.setNav(this);
|
||||
constructor() {
|
||||
// deprecated warning
|
||||
console.warn('<ion-overlay> is no longer needed and can be safely removed.');
|
||||
console.warn('See the v2 docs for an update on how overlays work.');
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,129 +0,0 @@
|
||||
@import "../../globals.ios";
|
||||
@import "./popup";
|
||||
|
||||
// iOS Popups
|
||||
// --------------------------------------------------
|
||||
|
||||
$popup-ios-max-width: 270px !default;
|
||||
$popup-ios-background: rgba(0,0,0,0) !default;
|
||||
$popup-ios-border-radius: 13px !default;
|
||||
$popup-ios-background-color: #f8f8f8 !default;
|
||||
|
||||
$popup-ios-head-padding: 12px 16px 20px !default;
|
||||
$popup-ios-head-text-align: center !default;
|
||||
|
||||
$popup-ios-title-margin-top: 12px !default;
|
||||
$popup-ios-title-font-weight: bold !default;
|
||||
$popup-ios-title-font-size: 17px !default;
|
||||
$popup-ios-sub-title-font-size: 14px !default;
|
||||
$popup-ios-sub-title-text-color: #666 !default;
|
||||
|
||||
$popup-ios-body-padding: 0px 16px 24px !default;
|
||||
$popup-ios-body-text-color: inherit !default;
|
||||
$popup-ios-body-text-align: center !default;
|
||||
$popup-ios-body-font-size: 13px !default;
|
||||
|
||||
$popup-ios-prompt-input-padding: 6px !default;
|
||||
$popup-ios-prompt-input-margin-top: 24px !default;
|
||||
$popup-ios-prompt-input-background-color: #fff !default;
|
||||
$popup-ios-prompt-input-border: 1px solid #ccc !default;
|
||||
$popup-ios-prompt-input-border-radius: 4px !default;
|
||||
|
||||
$popup-ios-button-min-height: 44px !default;
|
||||
$popup-ios-button-font-size: 17px !default;
|
||||
$popup-ios-button-border-color: #c8c7cc !default;
|
||||
$popup-ios-button-activated-background-color: #e9e9e9 !default;
|
||||
|
||||
|
||||
ion-popup {
|
||||
background: $popup-ios-background;
|
||||
}
|
||||
|
||||
.popup-wrapper {
|
||||
border-radius: $popup-ios-border-radius;
|
||||
background-color: $popup-ios-background-color;
|
||||
max-width: $popup-ios-max-width;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.popup-head {
|
||||
padding: $popup-ios-head-padding;
|
||||
text-align: $popup-ios-head-text-align;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
margin-top: $popup-ios-title-margin-top;
|
||||
font-weight: $popup-ios-title-font-weight;
|
||||
font-size: $popup-ios-title-font-size;
|
||||
}
|
||||
|
||||
.popup-sub-title {
|
||||
font-size: $popup-ios-sub-title-font-size;
|
||||
color: $popup-ios-sub-title-text-color;
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
padding: $popup-ios-body-padding;
|
||||
color: $popup-ios-body-text-color;
|
||||
text-align: $popup-ios-body-text-align;
|
||||
font-size: $popup-ios-body-font-size;
|
||||
}
|
||||
|
||||
.prompt-input {
|
||||
padding: $popup-ios-prompt-input-padding;
|
||||
margin-top: $popup-ios-prompt-input-margin-top;
|
||||
|
||||
background-color: $popup-ios-prompt-input-background-color;
|
||||
border: $popup-ios-prompt-input-border;
|
||||
border-radius: $popup-ios-prompt-input-border-radius;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
:last-child {
|
||||
font-weight: bold;
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-button {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
border-radius: 0;
|
||||
font-size: $popup-ios-button-font-size;
|
||||
min-height: $popup-ios-button-min-height;
|
||||
border-right: 1px solid $popup-ios-button-border-color;
|
||||
|
||||
&.activated {
|
||||
opacity: 1;
|
||||
background-color: $popup-ios-button-activated-background-color;
|
||||
}
|
||||
|
||||
&:hover:not(.disable-hover) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
border-top: 1px solid $popup-ios-button-border-color;
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
&.hairlines {
|
||||
.prompt-input {
|
||||
border-width: 0.55px;
|
||||
}
|
||||
|
||||
.popup-button {
|
||||
border-right-width: 0.55px;
|
||||
|
||||
&:before {
|
||||
border-top-width: 0.55px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
@import "../../globals.md";
|
||||
@import "./popup";
|
||||
|
||||
// Material Design Popups
|
||||
// --------------------------------------------------
|
||||
|
||||
$popup-md-max-width: 280px !default;
|
||||
$popup-md-border-radius: 2px !default;
|
||||
$popup-md-background-color: #fafafa !default;
|
||||
$popup-md-box-shadow: 0px 16px 20px rgba(0, 0, 0, 0.4) !default;
|
||||
|
||||
$popup-md-head-text-align: left !default;
|
||||
$popup-md-head-padding: 24px 24px 10px 24px !default;
|
||||
|
||||
$popup-md-title-font-size: 20px !default;
|
||||
$popup-md-sub-title-font-size: 15px !default;
|
||||
|
||||
$popup-md-body-padding: 10px 24px 24px 24px !default;
|
||||
$popup-md-body-text-color: rgba(0,0,0,.5) !default;
|
||||
|
||||
$popup-md-prompt-input-border-color: #dedede !default;
|
||||
$popup-md-prompt-input-text-color: #000000 !default;
|
||||
$popup-md-prompt-input-highlight-color: map-get($colors-md, primary) !default;
|
||||
$popup-md-prompt-input-margin-top: 5px !default;
|
||||
$popup-md-prompt-input-margin-bottom: 5px !default;
|
||||
|
||||
$popup-md-buttons-padding: 8px 8px 8px 24px !default;
|
||||
$popup-md-buttons-justify-content: flex-end !default;
|
||||
|
||||
|
||||
.popup-wrapper {
|
||||
max-width: $popup-md-max-width;
|
||||
border-radius: $popup-md-border-radius;
|
||||
background-color: $popup-md-background-color;
|
||||
|
||||
box-shadow: $popup-md-box-shadow;
|
||||
}
|
||||
|
||||
.popup-head {
|
||||
text-align: $popup-md-head-text-align;
|
||||
padding: $popup-md-head-padding;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: $popup-md-title-font-size;
|
||||
}
|
||||
|
||||
.popup-sub-title {
|
||||
font-size: $popup-md-sub-title-font-size;
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
padding: $popup-md-body-padding;
|
||||
color: $popup-md-body-text-color;
|
||||
}
|
||||
|
||||
.prompt-input {
|
||||
border-bottom: 1px solid $popup-md-prompt-input-border-color;
|
||||
color: $popup-md-prompt-input-text-color;
|
||||
margin: $popup-md-prompt-input-margin-top 0 $popup-md-prompt-input-margin-bottom 0;
|
||||
|
||||
&:focus {
|
||||
border-bottom: 2px solid $popup-md-prompt-input-highlight-color;
|
||||
margin-bottom: $popup-md-prompt-input-margin-bottom - 1;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
padding: $popup-md-buttons-padding;
|
||||
justify-content: $popup-md-buttons-justify-content;
|
||||
}
|
||||
|
||||
.popup-button.activated {
|
||||
opacity: 1;
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
@import "../../globals.core";
|
||||
|
||||
// Popups
|
||||
// --------------------------------------------------
|
||||
|
||||
$popup-min-width: 250px !default;
|
||||
$popup-max-height: 90% !default;
|
||||
|
||||
$popup-button-line-height: 20px !default;
|
||||
$popup-button-font-size: 14px !default;
|
||||
$popup-button-margin-right: 8px !default;
|
||||
|
||||
|
||||
ion-popup {
|
||||
position: absolute;
|
||||
z-index: $z-index-overlay;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
input,
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-wrapper {
|
||||
z-index: $z-index-overlay-wrapper;
|
||||
min-width: $popup-min-width;
|
||||
max-height: $popup-max-height;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.popup-sub-title {
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
overflow: auto;
|
||||
|
||||
&:empty {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.prompt-input {
|
||||
@include placeholder();
|
||||
|
||||
border: 0;
|
||||
background: inherit;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.popup-button {
|
||||
display: block;
|
||||
margin: 0;
|
||||
line-height: $popup-button-line-height;
|
||||
font-size: $popup-button-font-size;
|
||||
margin-right: $popup-button-margin-right;
|
||||
}
|
@ -1,406 +0,0 @@
|
||||
import {Component, ElementRef, Injectable, Renderer} from 'angular2/core';
|
||||
import {NgClass, NgIf, NgFor, FORM_DIRECTIVES} from 'angular2/common';
|
||||
|
||||
import {OverlayController} from '../overlay/overlay-controller';
|
||||
import {Config} from '../../config/config';
|
||||
import {Animation} from '../../animations/animation';
|
||||
import {NavParams} from '../nav/nav-controller';
|
||||
import {Button} from '../button/button';
|
||||
import {extend} from '../../util/util';
|
||||
|
||||
|
||||
/**
|
||||
* @name Popup
|
||||
* @description
|
||||
* The Ionic Popup service allows the creation of popup windows that require the user to respond in order to continue.
|
||||
*
|
||||
* The popup service has support for more flexible versions of the built in `alert()`, `prompt()`, and `confirm()` functions that users are used to, in addition to allowing popups with completely custom content and look.
|
||||
*
|
||||
* @usage
|
||||
* ```ts
|
||||
* class myApp {
|
||||
*
|
||||
* constructor(popup: Popup) {
|
||||
* this.popup = popup;
|
||||
* }
|
||||
*
|
||||
* doAlert() {
|
||||
* this.popup.alert({
|
||||
* title: "New Friend!",
|
||||
* template: "Your friend, Obi wan Kenobi, just accepted your friend request!",
|
||||
* cssClass: 'my-alert'
|
||||
* }).then(() => {
|
||||
* console.log('Alert closed');
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* doPrompt() {
|
||||
* this.popup.prompt({
|
||||
* title: "New Album",
|
||||
* template: "Enter a name for this new album you're so keen on adding",
|
||||
* inputPlaceholder: "Title",
|
||||
* okText: "Save",
|
||||
* okType: "secondary"
|
||||
* }).then((name) => {
|
||||
* console.log('Name entered:', name);
|
||||
* }, () => {
|
||||
* console.error('Prompt closed');
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* doConfirm() {
|
||||
* this.popup.confirm({
|
||||
* title: "Use this lightsaber?",
|
||||
* subTitle: "You can't exchange lightsabers",
|
||||
* template: "Do you agree to use this lightsaber to do good across the intergalactic galaxy?",
|
||||
* cancelText: "Disagree",
|
||||
* okText: "Agree"
|
||||
* }).then((result, ev) => {
|
||||
* console.log('Confirmed!', result);
|
||||
* }, () => {
|
||||
* console.error('Not confirmed!');
|
||||
* });
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @demo /docs/v2/demos/popup/
|
||||
* @see {@link /docs/v2/components#popups Popup Component Docs}
|
||||
*/
|
||||
@Injectable()
|
||||
export class Popup {
|
||||
|
||||
constructor(ctrl: OverlayController, config: Config) {
|
||||
this.ctrl = ctrl;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {TODO} opts TODO
|
||||
* @returns {object} A promise
|
||||
*/
|
||||
open(opts) {
|
||||
return new Promise((resolve, reject)=> {
|
||||
opts.promiseResolve = resolve;
|
||||
opts.promiseReject = reject;
|
||||
|
||||
opts = extend({
|
||||
pageType: OVERLAY_TYPE,
|
||||
enterAnimation: this.config.get('popupEnter'),
|
||||
leaveAnimation: this.config.get('popupLeave')
|
||||
}, opts);
|
||||
|
||||
return this.ctrl.open(PopupCmp, opts, opts);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a simple alert popup with a message and one button
|
||||
* that the user can tap to close the popup.
|
||||
* @param {object} opts The options for showing the alert, of the form:
|
||||
* - `{String}` `title` The title of the popup.
|
||||
* - `{String}` `cssClass` (optional). The custom CSS class name.
|
||||
* - `{String}` `subTitle` (optional). The sub-title of the popup.
|
||||
* - `{String}` `template` (optional). The html template to place in the popup body.
|
||||
* - `{String}` `okText` (default: 'OK'). The text of the OK button.
|
||||
* @returns {object} A promise which is resolved when the popup is closed.
|
||||
*/
|
||||
alert(opts={}) {
|
||||
if (typeof opts === 'string') {
|
||||
opts = {
|
||||
title: opts
|
||||
};
|
||||
}
|
||||
let button = {
|
||||
text: opts.okText || 'OK',
|
||||
type: opts.okType || '',
|
||||
onTap: (event, popupRef) => {
|
||||
// Allow it to close
|
||||
//resolve();
|
||||
}
|
||||
};
|
||||
opts = extend({
|
||||
showPrompt: false,
|
||||
cancel: () => {
|
||||
//reject();
|
||||
},
|
||||
buttons: [
|
||||
button
|
||||
]
|
||||
}, opts);
|
||||
return this.open(opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a simple confirm popup with a message, Cancel and OK button.
|
||||
*
|
||||
* Resolves the promise with true if the user presses the OK button, and false if the user presses the Cancel button.
|
||||
*
|
||||
* @param {object} opts The options for showing the confirm, of the form:
|
||||
* - `{String}` `title` The title of the popup.
|
||||
* - `{String}` `cssClass` (optional). The custom CSS class name.
|
||||
* - `{String}` `subTitle` (optional). The sub-title of the popup.
|
||||
* - `{String}` `template` (optional). The html template to place in the popup body.
|
||||
* - `{String}` `okText` (default: 'OK'). The text of the OK button.
|
||||
* - `{String}` `cancelText` (default: 'Cancel'). The text of the OK button.
|
||||
* @returns {object} A promise which is resolved when the popup is closed.
|
||||
*/
|
||||
confirm(opts={}) {
|
||||
if (typeof opts === 'string') {
|
||||
opts = {
|
||||
title: opts
|
||||
}
|
||||
}
|
||||
let okButton = {
|
||||
text: opts.okText || 'OK',
|
||||
type: opts.okType || '',
|
||||
onTap: (event, popupRef) => {
|
||||
// Allow it to close
|
||||
}
|
||||
}
|
||||
let cancelButton = {
|
||||
text: opts.cancelText || 'Cancel',
|
||||
type: opts.cancelType || '',
|
||||
isCancel: true,
|
||||
onTap: (event, popupRef) => {
|
||||
// Allow it to close
|
||||
}
|
||||
}
|
||||
opts = extend({
|
||||
showPrompt: false,
|
||||
cancel: () => {
|
||||
},
|
||||
buttons: [
|
||||
cancelButton, okButton
|
||||
]
|
||||
}, opts);
|
||||
return this.open(opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a simple prompt popup with a message, input, Cancel and OK button.
|
||||
*
|
||||
* Resolves the promise with the value of the input if the user presses OK, and with undefined if the user presses Cancel.
|
||||
*
|
||||
* @param {object} opts The options for showing the prompt, of the form:
|
||||
* - `{String}` `title` The title of the popup.
|
||||
* - `{String}` `cssClass` (optional). The custom CSS class name.
|
||||
* - `{String}` `subTitle` (optional). The sub-title of the popup.
|
||||
* - `{String}` `template` (optional). The html template to place in the popup body.
|
||||
* - `{String}` `inputType` (default: 'text'). The type of input to use.
|
||||
* - `{String} `inputPlaceholder` (default: ''). A placeholder to use for the input.
|
||||
* - `{String}` `okText` (default: 'OK'). The text of the OK button.
|
||||
* - `{String}` `cancelText` (default: 'Cancel'). The text of the OK button.
|
||||
* @returns {object} A promise which is resolved when the popup is closed.
|
||||
*/
|
||||
prompt(opts={}) {
|
||||
if (typeof opts === 'string') {
|
||||
opts = {
|
||||
title: opts
|
||||
};
|
||||
}
|
||||
let okButton = {
|
||||
text: opts.okText || 'OK',
|
||||
type: opts.okType || '',
|
||||
onTap: (event, popupRef) => {
|
||||
// Allow it to close
|
||||
}
|
||||
}
|
||||
|
||||
let cancelButton = {
|
||||
text: opts.cancelText || 'Cancel',
|
||||
type: opts.cancelType || '',
|
||||
isCancel: true,
|
||||
onTap: (event, popupRef) => {
|
||||
// Allow it to close
|
||||
}
|
||||
}
|
||||
|
||||
opts = extend({
|
||||
showPrompt: true,
|
||||
promptPlaceholder: '',
|
||||
cancel: () => {
|
||||
},
|
||||
buttons: [
|
||||
cancelButton, okButton
|
||||
]
|
||||
}, opts);
|
||||
return this.open(opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {TODO} handle TODO
|
||||
* @returns {TODO} TODO
|
||||
*/
|
||||
get(handle) {
|
||||
if (handle) {
|
||||
return this.ctrl.getByHandle(handle);
|
||||
}
|
||||
return this.ctrl.getByType(OVERLAY_TYPE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const OVERLAY_TYPE = 'popup';
|
||||
|
||||
|
||||
// TODO add button type to button: [type]="button.type"
|
||||
@Component({
|
||||
selector: 'ion-popup',
|
||||
template:
|
||||
'<div (click)="cancel($event)" tappable disable-activated class="backdrop"></div>' +
|
||||
'<div class="popup-wrapper">' +
|
||||
'<div class="popup-head">' +
|
||||
'<h2 class="popup-title" [innerHTML]="d.title" *ngIf="d.title"></h2>' +
|
||||
'<h3 class="popup-sub-title" [innerHTML]="d.subTitle" *ngIf="d.subTitle"></h3>' +
|
||||
'</div>' +
|
||||
'<div class="popup-body">' +
|
||||
'<div [innerHTML]="d.template" *ngIf="d.template"></div>' +
|
||||
'<input type="{{d.inputType || \'text\'}}" placeholder="{{d.inputPlaceholder}}" *ngIf="d.showPrompt" class="prompt-input">' +
|
||||
'</div>' +
|
||||
'<div class="popup-buttons" *ngIf="d.buttons.length">' +
|
||||
'<button clear *ngFor="#btn of d.buttons" (click)="buttonTapped(btn, $event)" [innerHTML]="btn.text" class="popup-button"></button>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
host: {
|
||||
'role': 'dialog'
|
||||
},
|
||||
directives: [FORM_DIRECTIVES, NgClass, NgIf, NgFor, Button]
|
||||
})
|
||||
class PopupCmp {
|
||||
|
||||
constructor(elementRef: ElementRef, params: NavParams, renderer: Renderer) {
|
||||
this.elementRef = elementRef;
|
||||
this.d = params.data;
|
||||
|
||||
if (this.d.cssClass) {
|
||||
renderer.setElementClass(elementRef, this.d.cssClass, true);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
setTimeout(() => {
|
||||
// TODO: make more better, no DOM BS
|
||||
this.promptInput = this.elementRef.nativeElement.querySelector('input');
|
||||
if (this.promptInput) {
|
||||
this.promptInput.value = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
buttonTapped(button, ev) {
|
||||
let promptValue = this.promptInput && this.promptInput.value;
|
||||
|
||||
let retVal = button.onTap && button.onTap(ev, this, {
|
||||
promptValue: promptValue
|
||||
});
|
||||
|
||||
// If the event.preventDefault() wasn't called, close
|
||||
if (!ev.defaultPrevented) {
|
||||
// If this is a cancel button, reject the promise
|
||||
if (button.isCancel) {
|
||||
this.d.promiseReject();
|
||||
|
||||
} else {
|
||||
// Resolve with the prompt value
|
||||
this.d.promiseResolve(promptValue);
|
||||
}
|
||||
|
||||
return this.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cancel(ev) {
|
||||
this.d.cancel && this.d.cancel(event);
|
||||
|
||||
if (!ev.defaultPrevented) {
|
||||
this.d.promiseReject();
|
||||
return this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Animations for popups
|
||||
*/
|
||||
class PopupPopIn extends Animation {
|
||||
constructor(enteringView, leavingView, opts) {
|
||||
super(null, opts);
|
||||
|
||||
let ele = enteringView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.popup-wrapper'));
|
||||
|
||||
wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1');
|
||||
backdrop.fromTo('opacity', '0.01', '0.3');
|
||||
|
||||
this
|
||||
.easing('ease-in-out')
|
||||
.duration(200)
|
||||
.add(backdrop, wrapper);
|
||||
}
|
||||
}
|
||||
Animation.register('popup-pop-in', PopupPopIn);
|
||||
|
||||
|
||||
class PopupPopOut extends Animation {
|
||||
constructor(enteringView, leavingView, opts) {
|
||||
super(null, opts);
|
||||
|
||||
let ele = leavingView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.popup-wrapper'));
|
||||
|
||||
wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9');
|
||||
backdrop.fromTo('opacity', '0.3', '0');
|
||||
|
||||
this
|
||||
.easing('ease-in-out')
|
||||
.duration(200)
|
||||
.add(backdrop, wrapper);
|
||||
}
|
||||
}
|
||||
Animation.register('popup-pop-out', PopupPopOut);
|
||||
|
||||
|
||||
class PopupMdPopIn extends Animation {
|
||||
constructor(enteringView, leavingView, opts) {
|
||||
super(null, opts);
|
||||
|
||||
let ele = enteringView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.popup-wrapper'));
|
||||
|
||||
wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1');
|
||||
backdrop.fromTo('opacity', '0.01', '0.5');
|
||||
|
||||
this
|
||||
.easing('ease-in-out')
|
||||
.duration(200)
|
||||
.add(backdrop, wrapper);
|
||||
}
|
||||
}
|
||||
Animation.register('popup-md-pop-in', PopupMdPopIn);
|
||||
|
||||
|
||||
class PopupMdPopOut extends Animation {
|
||||
constructor(enteringView, leavingView, opts) {
|
||||
super(null, opts);
|
||||
|
||||
let ele = leavingView.pageRef().nativeElement;
|
||||
let backdrop = new Animation(ele.querySelector('.backdrop'));
|
||||
let wrapper = new Animation(ele.querySelector('.popup-wrapper'));
|
||||
|
||||
wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9');
|
||||
backdrop.fromTo('opacity', '0.5', '0');
|
||||
|
||||
this
|
||||
.easing('ease-in-out')
|
||||
.duration(200)
|
||||
.add(backdrop, wrapper);
|
||||
}
|
||||
}
|
||||
Animation.register('popup-md-pop-out', PopupMdPopOut);
|
@ -1,27 +0,0 @@
|
||||
|
||||
it('should open alert', function() {
|
||||
element(by.css('.e2eOpenAlert')).click();
|
||||
});
|
||||
|
||||
|
||||
it('should close alert', function() {
|
||||
element(by.css('.popup-buttons button:last-of-type')).click();
|
||||
});
|
||||
|
||||
it('should open confirm', function() {
|
||||
element(by.css('.e2eOpenConfirm')).click();
|
||||
});
|
||||
|
||||
it('should close confirm', function() {
|
||||
element(by.css('.popup-buttons button:last-of-type')).click();
|
||||
});
|
||||
|
||||
it('should open prompt', function() {
|
||||
element(by.css('.e2eOpenPrompt')).click();
|
||||
});
|
||||
|
||||
it('should close prompt', function() {
|
||||
var inputEle = element(by.css('.popup-body input'));
|
||||
inputEle.sendKeys('prompt text');
|
||||
element(by.css('.popup-buttons button:last-of-type')).click();
|
||||
});
|
@ -1,62 +0,0 @@
|
||||
import {App, Popup} from 'ionic/ionic';
|
||||
|
||||
|
||||
@App({
|
||||
templateUrl: 'main.html'
|
||||
})
|
||||
class E2EApp {
|
||||
|
||||
constructor(popup: Popup) {
|
||||
this.popup = popup;
|
||||
this.alertOpen = false;
|
||||
this.promptOpen = false;
|
||||
this.promptResult = '';
|
||||
this.confirmOpen = false;
|
||||
this.confirmResult = '';
|
||||
}
|
||||
|
||||
doAlert() {
|
||||
this.alertOpen = true;
|
||||
this.popup.alert({
|
||||
title: "New Friend!",
|
||||
template: "Your friend, Obi wan Kenobi, just accepted your friend request!",
|
||||
cssClass: 'my-alert'
|
||||
}).then(() => {
|
||||
this.alertOpen = false;
|
||||
});
|
||||
}
|
||||
|
||||
doPrompt() {
|
||||
this.promptOpen = true;
|
||||
this.popup.prompt({
|
||||
title: "New Album",
|
||||
template: "Enter a name for this new album you're so keen on adding",
|
||||
inputPlaceholder: "Title",
|
||||
okText: "Save"
|
||||
}).then((name) => {
|
||||
this.promptResult = name;
|
||||
this.promptOpen = false;
|
||||
}, () => {
|
||||
console.log('Prompt closed');
|
||||
this.promptOpen = false;
|
||||
});
|
||||
}
|
||||
|
||||
doConfirm() {
|
||||
this.confirmOpen = true;
|
||||
this.popup.confirm({
|
||||
title: "Use this lightsaber?",
|
||||
subTitle: "You can't exchange lightsabers",
|
||||
template: "Do you agree to use this lightsaber to do good across the intergalactic galaxy?",
|
||||
cancelText: "Disagree",
|
||||
okText: "Agree"
|
||||
}).then((result, ev) => {
|
||||
console.log('CONFIRMED', result);
|
||||
this.confirmResult = result;
|
||||
this.confirmOpen = false;
|
||||
}, () => {
|
||||
this.confirmOpen = false;
|
||||
console.log('NOT CONFIRMED');
|
||||
});
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
|
||||
<ion-content padding>
|
||||
|
||||
<button class="e2eOpenAlert" (click)="doAlert()">Alert</button>
|
||||
<button class="e2eOpenPrompt" (click)="doPrompt()">Prompt</button>
|
||||
<button class="e2eOpenConfirm" (click)="doConfirm()">Confirm</button>
|
||||
|
||||
<pre>
|
||||
Alert Opened: {{alertOpen}}
|
||||
Prompt Opened: {{promptOpen}}
|
||||
Prompt Result: {{promptResult}}
|
||||
Confirm Opened: {{confirmOpen}}
|
||||
Confirm Result: {{confirmResult}}
|
||||
</pre>
|
||||
|
||||
</ion-content>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
@ -5,5 +5,3 @@
|
||||
<ion-tab tabTitle="Settings" tabIcon="settings" [root]="tab3Root"></ion-tab>
|
||||
<ion-tab tabTitle="Chat" tabIcon="chatbubbles" (select)="chat()"></ion-tab>
|
||||
</ion-tabs>
|
||||
|
||||
<ion-overlay></ion-overlay>
|
||||
|
@ -5,12 +5,9 @@ import {HTTP_PROVIDERS} from 'angular2/http';
|
||||
import {IonicApp} from '../components/app/app';
|
||||
import {Config} from './config';
|
||||
import {Platform} from '../platform/platform';
|
||||
import {OverlayController} from '../components/overlay/overlay-controller';
|
||||
import {Form} from '../util/form';
|
||||
import {Keyboard} from '../util/keyboard';
|
||||
import {ActionSheet} from '../components/action-sheet/action-sheet';
|
||||
import {Modal} from '../components/modal/modal';
|
||||
import {Popup} from '../components/popup/popup';
|
||||
import {Events} from '../util/events';
|
||||
import {NavRegistry} from '../components/nav/nav-registry';
|
||||
import {Translate} from '../translation/translate';
|
||||
@ -61,10 +58,7 @@ export function ionicProviders(args={}) {
|
||||
TapClick,
|
||||
Form,
|
||||
Keyboard,
|
||||
OverlayController,
|
||||
ActionSheet,
|
||||
Modal,
|
||||
Popup,
|
||||
Translate,
|
||||
ROUTER_PROVIDERS,
|
||||
provide(LocationStrategy, {useClass: HashLocationStrategy}),
|
||||
|
@ -44,7 +44,6 @@ import {ShowWhen, HideWhen} from '../components/show-hide-when/show-hide-when';
|
||||
* - FORM_DIRECTIVES
|
||||
*
|
||||
* **Content**
|
||||
* - OverlayNav
|
||||
* - Menu
|
||||
* - MenuToggle
|
||||
* - MenuClose
|
||||
|
Reference in New Issue
Block a user