refactor(overlay): use NavController

This commit is contained in:
Adam Bradley
2015-11-21 19:18:47 -06:00
parent a7505f6ac9
commit e1c160eb54
22 changed files with 488 additions and 563 deletions

View File

@ -254,10 +254,10 @@ export class Animation {
});
}
if (self._duration > 16 && this._opts.renderDelay > 0) {
if (self._duration > 16 && self._opts.renderDelay > 0) {
// begin each animation when everything is rendered in their starting point
// give the browser some time to render everything in place before starting
rafFrames(this._opts.renderDelay / 16, kickoff);
rafFrames(self._opts.renderDelay / 16, kickoff);
} else {
// no need to render everything in there place before animating in
@ -538,6 +538,17 @@ export class Animation {
return new AnimationClass(element);
}
static createTransition(enteringView, leavingView, opts = {}) {
const name = opts.animation || 'ios-transition';
let TransitionClass = AnimationRegistry[name];
if (!TransitionClass) {
TransitionClass = Animation;
}
return new TransitionClass(enteringView, leavingView, opts);
}
static register(name, AnimationClass) {
AnimationRegistry[name] = AnimationClass;
}
@ -912,8 +923,9 @@ let AnimationRegistry = {};
function parallel(tasks, done) {
var l = tasks.length;
if (!l) {
return done();
if (!l ) {
done && done();
return;
}
var completed = 0;
@ -921,7 +933,7 @@ function parallel(tasks, done) {
function taskCompleted() {
completed++;
if (completed === l) {
done();
done && done();
}
}

View File

@ -1,5 +1,4 @@
import {Transition} from './transition';
import {Animation} from '../animations/animation';
import {Animation} from './animation';
const DURATION = 550;
const EASING = 'cubic-bezier(0.36,0.66,0.04,1)';
@ -14,7 +13,7 @@ const SHOW_BACK_BTN_CSS = 'show-back-button';
class IOSTransition extends Animation {
constructor(navCtrl, opts) {
constructor(enteringView, leavingView, opts) {
super(null, opts);
this.duration(DURATION);
@ -23,10 +22,6 @@ class IOSTransition extends Animation {
// what direction is the transition going
let backDirection = (opts.direction === 'back');
// get entering/leaving views
let enteringView = navCtrl.getStagedEnteringView();
let leavingView = navCtrl.getStagedLeavingView();
// do they have navbars?
let enteringHasNavbar = enteringView.hasNavbar();
let leavingHasNavbar = leavingView && leavingView.hasNavbar();
@ -189,4 +184,4 @@ class IOSTransition extends Animation {
}
Transition.register('ios', IOSTransition);
Animation.register('ios-transition', IOSTransition);

View File

@ -1,5 +1,4 @@
import {Transition} from './transition';
import {Animation} from '../animations/animation';
import {Animation} from './animation';
const TRANSLATEY = 'translateY';
const OFF_BOTTOM = '40px';
@ -9,16 +8,12 @@ const SHOW_BACK_BTN_CSS = 'show-back-button';
class MDTransition extends Animation {
constructor(navCtrl, opts) {
constructor(enteringView, leavingView, opts) {
super(null, opts);
// what direction is the transition going
let backDirection = (opts.direction === 'back');
// get entering/leaving views
let enteringView = navCtrl.getStagedEnteringView();
let leavingView = navCtrl.getStagedLeavingView();
// do they have navbars?
let enteringHasNavbar = enteringView.hasNavbar();
let leavingHasNavbar = leavingView && leavingView.hasNavbar();
@ -61,4 +56,4 @@ class MDTransition extends Animation {
}
Transition.register('md', MDTransition);
Animation.register('md-transition', MDTransition);

View File

@ -5,14 +5,14 @@
* @description
* The ActionSheet is a modal menu with options to select based on an action.
*/
import {Component, Injectable, NgFor, NgIf} from 'angular2/angular2';
import {Component, Injectable, Renderer, NgFor, NgIf} from 'angular2/angular2';
import {OverlayController} from '../overlay/overlay-controller';
import {Config} from '../../config/config';
import {Icon} from '../icon/icon';
import {Animation} from '../../animations/animation';
import * as util from 'ionic/util';
import {NavParams} from '../nav/nav-controller';
import {extend} from '../../util/util';
/**
@ -56,48 +56,55 @@ import * as util from 'ionic/util';
@Component({
selector: 'ion-action-sheet',
template:
'<backdrop (click)="_cancel()" tappable disable-activated></backdrop>' +
'<backdrop (click)="cancel()" tappable disable-activated></backdrop>' +
'<action-sheet-wrapper>' +
'<div class="action-sheet-container">' +
'<div class="action-sheet-group action-sheet-options">' +
'<div class="action-sheet-title" *ng-if="titleText">{{titleText}}</div>' +
'<button (click)="_buttonClicked(i)" *ng-for="#b of buttons; #i=index" class="action-sheet-option disable-hover">' +
'<div class="action-sheet-title" *ng-if="d.titleText">{{d.titleText}}</div>' +
'<button (click)="buttonClicked(i)" *ng-for="#b of d.buttons; #i=index" class="action-sheet-option disable-hover">' +
'<icon [name]="b.icon" *ng-if="b.icon"></icon> ' +
'{{b.text}}' +
'</button>' +
'<button *ng-if="destructiveText" (click)="_destructive()" class="action-sheet-destructive disable-hover">' +
'<icon [name]="destructiveIcon" *ng-if="destructiveIcon"></icon> ' +
'{{destructiveText}}</button>' +
'<button *ng-if="d.destructiveText" (click)="destructive()" class="action-sheet-destructive disable-hover">' +
'<icon [name]="d.destructiveIcon" *ng-if="d.destructiveIcon"></icon> ' +
'{{d.destructiveText}}</button>' +
'</div>' +
'<div class="action-sheet-group action-sheet-cancel" *ng-if="cancelText">' +
'<button (click)="_cancel()" class=" disable-hover">' +
'<icon [name]="cancelIcon"></icon> ' +
'{{cancelText}}</button>' +
'<div class="action-sheet-group action-sheet-cancel" *ng-if="d.cancelText">' +
'<button (click)="cancel()" class="disable-hover">' +
'<icon [name]="d.cancelIcon" *ng-if="d.cancelIcon"></icon> ' +
'{{d.cancelText}}</button>' +
'</div>' +
'</div>' +
'</action-sheet-wrapper>',
host: {
'[style.zIndex]': '_zIndex'
'[style.zIndex]': '_zIndex',
'role': 'dialog'
},
directives: [NgFor, NgIf, Icon]
})
class ActionSheetCmp {
_cancel() {
this.cancel && this.cancel();
constructor(params: NavParams, renderer: Renderer) {
this.d = params.data;
if (this.d.cssClass) {
renderer.setElementClass(elementRef, this.d.cssClass, true);
}
}
cancel() {
this.d.cancel && this.d.cancel();
return this.close();
}
_destructive() {
let shouldClose = this.destructiveButtonClicked();
if (shouldClose === true) {
destructive() {
if (this.d.destructiveButtonClicked()) {
return this.close();
}
}
_buttonClicked(index) {
let shouldClose = this.buttonClicked(index);
if (shouldClose === true) {
buttonClicked(index) {
if (this.d.buttonClicked(index)) {
return this.close();
}
}
@ -109,12 +116,7 @@ export class ActionSheet {
constructor(ctrl: OverlayController, config: Config) {
this.ctrl = ctrl;
this._defaults = {
enterAnimation: config.get('actionSheetEnter'),
leaveAnimation: config.get('actionSheetLeave'),
cancelIcon: config.get('actionSheetCancelIcon'),
destructiveIcon: config.get('actionSheetDestructiveIcon')
};
this.config = config;
}
/**
@ -125,7 +127,15 @@ export class ActionSheet {
* @return {Promise} Promise that resolves when the action sheet is open.
*/
open(opts={}) {
return this.ctrl.open(OVERLAY_TYPE, ActionSheetCmp, util.extend(this._defaults, opts));
opts = extend({
pageType: OVERLAY_TYPE,
enterAnimation: this.config.get('actionSheetEnter'),
leaveAnimation: this.config.get('actionSheetLeave'),
cancelIcon: this.config.get('actionSheetCancelIcon'),
destructiveIcon: this.config.get('actionSheetDestructiveIcon')
}, opts);
return this.ctrl.open(ActionSheetCmp, opts, opts);
}
/**
@ -134,7 +144,7 @@ export class ActionSheet {
*/
get(handle) {
if (handle) {
return this.ctrl.getByHandle(handle, OVERLAY_TYPE);
return this.ctrl.getByHandle(handle);
}
return this.ctrl.getByType(OVERLAY_TYPE);
}
@ -144,56 +154,70 @@ export class ActionSheet {
const OVERLAY_TYPE = 'action-sheet';
/**
* Animations for action sheet
*/
class ActionSheetAnimation extends Animation {
constructor(element) {
super(element);
this.easing('cubic-bezier(.36, .66, .04, 1)');
this.backdrop = new Animation(element.querySelector('backdrop'));
this.wrapper = new Animation(element.querySelector('action-sheet-wrapper'));
class ActionSheetSlideIn extends Animation {
constructor(enteringView, leavingView, opts) {
super(null, opts);
this.add(this.backdrop, this.wrapper);
}
}
let ele = enteringView.pageRef().nativeElement;
let backdrop = new Animation(ele.querySelector('backdrop'));
let wrapper = new Animation(ele.querySelector('action-sheet-wrapper'));
class ActionSheetSlideIn extends ActionSheetAnimation {
constructor(element) {
super(element);
this.duration(400);
this.backdrop.fromTo('opacity', 0.01, 0.4);
this.wrapper.fromTo('translateY', '100%', '0%');
backdrop.fromTo('opacity', 0.01, 0.4);
wrapper.fromTo('translateY', '100%', '0%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add([backdrop, wrapper]);
}
}
Animation.register('action-sheet-slide-in', ActionSheetSlideIn);
class ActionSheetSlideOut extends ActionSheetAnimation {
constructor(element) {
super(element);
this.duration(300);
this.backdrop.fromTo('opacity', 0.4, 0.01);
this.wrapper.fromTo('translateY', '0%', '100%');
class ActionSheetSlideOut 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('action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.4, 0);
wrapper.fromTo('translateY', '0%', '100%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(300).add([backdrop, wrapper]);
}
}
Animation.register('action-sheet-slide-out', ActionSheetSlideOut);
class ActionSheetMdSlideIn extends ActionSheetSlideIn {
constructor(element) {
super(element);
this.duration(450);
this.backdrop.fromTo('opacity', 0.01, 0.26);
class ActionSheetMdSlideIn 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('action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.01, 0.26);
wrapper.fromTo('translateY', '100%', '0%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add([backdrop, wrapper]);
}
}
Animation.register('action-sheet-md-slide-in', ActionSheetMdSlideIn);
class ActionSheetMdSlideOut extends ActionSheetSlideOut {
constructor(element) {
super(element);
this.duration(450);
this.backdrop.fromTo('opacity', 0.26, 0.01);
class ActionSheetMdSlideOut 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('action-sheet-wrapper'));
backdrop.fromTo('opacity', 0.26, 0);
wrapper.fromTo('translateY', '0%', '100%');
this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add([backdrop, wrapper]);
}
}
Animation.register('action-sheet-md-slide-out', ActionSheetMdSlideOut);

View File

@ -23,17 +23,17 @@ class E2EApp {
return items;
}
didClick(ev, item) {
console.log('CLICK', ev.defaultPrevented, ev)
didClick(item) {
console.log('CLICK')
}
archive(ev, item) {
console.log('Archive', ev, item);
archive(item) {
console.log('Archive', item);
item.close();
}
del(ev, item) {
console.log('Delete', ev, item);
del(item) {
console.log('Delete', item);
item.close();
}

View File

@ -10,15 +10,15 @@
<ion-list id="myList">
<ion-item-sliding #item>
<button ion-item text-wrap (click)="didClick($event, item)">
<button ion-item text-wrap (click)="didClick(item)">
<h3>Max Lynch</h3>
<p>
Hey do you want to go to the game tonight?
</p>
</button>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button danger (click)="del($event, item)">Delete</button>
<button primary (click)="archive(item)">Archive</button>
<button danger (click)="del(item)">Delete</button>
</ion-item-options>
</ion-item-sliding>
@ -30,8 +30,8 @@
</p>
</ion-item>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button danger (click)="del($event, item)"><icon trash></icon></button>
<button primary (click)="archive(item)">Archive</button>
<button danger (click)="del(item)"><icon trash></icon></button>
</ion-item-options>
</ion-item-sliding>
@ -43,8 +43,8 @@
</p>
</ion-item>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button danger (click)="del($event, item)">Delete</button>
<button primary (click)="archive(item)">Archive</button>
<button danger (click)="del(item)">Delete</button>
</ion-item-options>
</ion-item-sliding>
@ -54,7 +54,7 @@
One Line w/ Icon, div only text
</ion-item>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button primary (click)="archive(item)">Archive</button>
</ion-item-options>
</ion-item-sliding>
@ -66,7 +66,7 @@
One Line w/ Avatar, div only text
</ion-item>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button primary (click)="archive(item)">Archive</button>
</ion-item-options>
</ion-item-sliding>
@ -79,7 +79,7 @@
<p>Paragraph text.</p>
</ion-item>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button primary (click)="archive(item)">Archive</button>
</ion-item-options>
</ion-item-sliding>
@ -88,7 +88,7 @@
<h3>ng-for {{data}}</h3>
</ion-item>
<ion-item-options>
<button primary (click)="archive($event, item)">Archive</button>
<button primary (click)="archive(item)">Archive</button>
</ion-item-options>
</ion-item-sliding>

View File

@ -3,22 +3,24 @@ import {Injectable} from 'angular2/angular2';
import {OverlayController} from '../overlay/overlay-controller';
import {Config} from '../../config/config';
import {Animation} from '../../animations/animation';
import * as util from 'ionic/util';
import {extend} from 'ionic/util';
/**
* The Modal is a content pane that can go over the user's main view temporarily.
* Usually used for making a choice or editing an item.
* The Modal is a content pane that can go over the user's current page.
* Usually used for making a choice or editing an item. A modal can be opened
* similar to how NavController#push works, where you pass it a Page component,
* along with optional Page params, and options for presenting the modal.
*
* @usage
* ```ts
* class MyApp {
*
* constructor(modal: Modal, app: IonicApp, Config: Config) {
* constructor(modal: Modal) {
* this.modal = modal;
* }
*
* openModal() {
* this.modal.open(ContactModal, {
* this.modal.open(ContactPage, null, {
* enterAnimation: 'my-fade-in',
* leaveAnimation: 'my-fade-out',
* handle: 'my-modal'
@ -32,20 +34,24 @@ export class Modal {
constructor(ctrl: OverlayController, config: Config) {
this.ctrl = ctrl;
this._defaults = {
enterAnimation: config.get('modalEnter') || 'modal-slide-in',
leaveAnimation: config.get('modalLeave') || 'modal-slide-out',
};
this.config = config;
}
/**
* TODO
* @param {Type} componentType TODO
* @param {Object} [opts={}] TODO
* @returns {TODO} TODO
* @param {TODO} componentType TODO
* @param {TODO} [params={}] TODO
* @param {TODO} [opts={}] TODO
* @returns {Promise} TODO
*/
open(componentType: Type, opts={}) {
return this.ctrl.open(OVERLAY_TYPE, componentType, util.extend(this._defaults, opts));
open(componentType: Type, params={}, opts={}) {
opts = extend({
pageType: OVERLAY_TYPE,
enterAnimation: this.config.get('modalEnter'),
leaveAnimation: this.config.get('modalLeave'),
}, opts);
return this.ctrl.open(componentType, params, opts);
}
/**
@ -55,7 +61,7 @@ export class Modal {
*/
get(handle) {
if (handle) {
return this.ctrl.getByHandle(handle, OVERLAY_TYPE);
return this.ctrl.getByHandle(handle);
}
return this.ctrl.getByType(OVERLAY_TYPE);
}
@ -69,20 +75,21 @@ const OVERLAY_TYPE = 'modal';
* Animations for modals
*/
class ModalSlideIn extends Animation {
constructor(element) {
super(element);
constructor(enteringView, leavingView, opts) {
super(enteringView.pageRef(), opts);
this
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(400)
.fromTo('translateY', '100%', '0%');
.fromTo('translateY', '100%', '0%')
.before.addClass('show-page');
}
}
Animation.register('modal-slide-in', ModalSlideIn);
class ModalSlideOut extends Animation {
constructor(element) {
super(element);
constructor(enteringView, leavingView, opts) {
super(leavingView.pageRef(), opts);
this
.easing('ease-out')
.duration(250)
@ -93,21 +100,22 @@ Animation.register('modal-slide-out', ModalSlideOut);
class ModalMDSlideIn extends Animation {
constructor(element) {
super(element);
constructor(enteringView, leavingView, opts) {
super(enteringView.pageRef(), opts);
this
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(280)
.fromTo('translateY', '40px', '0px')
.fadeIn();
.fadeIn()
.before.addClass('show-page');
}
}
Animation.register('modal-md-slide-in', ModalMDSlideIn);
class ModalMDSlideOut extends Animation {
constructor(element) {
super(element);
constructor(enteringView, leavingView, opts) {
super(leavingView.pageRef(), opts);
this
.duration(200)
.easing('cubic-bezier(0.47,0,0.745,0.715)')

View File

@ -1,13 +1,13 @@
import {App, Page, IonicApp, Config, Platform} from 'ionic/ionic';
import {App, Page, Config, Platform} from 'ionic/ionic';
import {Modal, ActionSheet, NavController, NavParams, Animation} from 'ionic/ionic';
@App({
templateUrl: 'main.html'
})
class MyAppCmp {
class E2EApp {
constructor(modal: Modal, app: IonicApp, config: Config, platform: Platform) {
constructor(modal: Modal, config: Config, platform: Platform) {
this.modal = modal;
console.log('platforms', platform.platforms());
@ -25,7 +25,7 @@ class MyAppCmp {
console.log('windows phone', platform.is('windowsphone'))
platform.ready().then(() => {
console.log('platform.ready')
console.log('platform.ready');
});
}
@ -38,13 +38,14 @@ class MyAppCmp {
}
openModalChildNav() {
this.modal.open(ContactModal, {
this.modal.open(ContactUs, null, {
handle: 'my-awesome-modal'
});
}
openModalCustomAnimation() {
this.modal.open(ContactModal, {
this.modal.open(ContactUs, null, {
handle: 'my-awesome-modal',
enterAnimation: 'my-fade-in',
leaveAnimation: 'my-fade-out'
});
@ -67,21 +68,22 @@ class PlainPage {
}
}
@Page({
template: `
<ion-toolbar>
<ion-title>Modals</ion-title>
</ion-toolbar>
<ion-toolbar primary>
<ion-title>Another toolbar</ion-title>
</ion-toolbar>
<ion-content padding>
<button block danger (click)="closeModal()" class="e2eCloseToolbarModal">
<icon close></icon>
Close Modal
</button>
<button block danger (click)="closeModal()" class="e2eCloseToolbarModal">
<icon close></icon>
Close Modal
</button>
</ion-content>
`
})
@ -97,38 +99,43 @@ class ToolbarModal {
@Page({
template: '<ion-nav [root]="rootView"></ion-nav>'
})
class ContactModal {
class ContactUs {
constructor() {
console.log('ContactModal constructor')
console.log('ContactUs constructor');
this.rootView = ModalFirstPage;
}
onPageLoaded() {
console.log('ContactModal onPageLoaded');
console.log('ContactUs onPageLoaded');
}
onPageWillEnter() {
console.log('ContactModal onPageWillEnter');
console.log('ContactUs onPageWillEnter');
}
onPageDidEnter() {
console.log('ContactModal onPageDidEnter');
console.log('ContactUs onPageDidEnter');
}
onPageWillLeave() {
console.log('ContactModal onPageWillLeave');
console.log('ContactUs onPageWillLeave');
}
onPageDidLeave() {
console.log('ContactModal onPageDidLeave');
console.log('ContactUs onPageDidLeave');
}
onPageWillUnload() {
console.log('ContactModal onPageWillUnload');
console.log('ContactUs onPageWillUnload');
}
onPageDidUnload() {
console.log('ContactModal onPageDidUnload');
console.log('ContactUs onPageDidUnload');
}
}
@Page({
template: `
<ion-navbar *navbar><ion-title>First Page Header</ion-title><ion-nav-items primary><button class="e2eCloseMenu" (click)="closeModal()">Close</button></ion-nav-items></ion-navbar>
<ion-navbar *navbar>
<ion-title>First Page Header</ion-title>
<ion-nav-items primary>
<button class="e2eCloseMenu" (click)="closeModal()">Close</button>
</ion-nav-items>
</ion-navbar>
<ion-content padding>
<p>
<button (click)="push()">Push (Go to 2nd)</button>
@ -156,17 +163,19 @@ class ModalFirstPage {
}
push() {
this.nav.push(ModalSecondPage, { id: 8675309, myData: [1,2,3,4] }, { animation: 'ios' });
let page = ModalSecondPage;
let params = { id: 8675309, myData: [1,2,3,4] };
let opts = { animation: 'ios' };
this.nav.push(page, params, opts);
}
closeModal() {
let modal = this.modal.get();
modal.close();
this.modal.get().close();
}
closeByHandeModal() {
let modal = this.modal.get('my-awesome-modal');
modal.close();
this.modal.get('my-awesome-modal').close();
}
openActionSheet() {
@ -198,7 +207,9 @@ class ModalFirstPage {
@Page({
template: `
<ion-navbar *navbar><ion-title>Second Page Header</ion-title></ion-navbar>
<ion-navbar *navbar>
<ion-title>Second Page Header</ion-title>
</ion-navbar>
<ion-content padding>
<p>
<button (click)="nav.pop()">Pop (Go back to 1st)</button>
@ -214,32 +225,32 @@ class ModalSecondPage {
params: NavParams
) {
this.nav = nav;
this.params = params;
console.log('Second page params:', params);
}
}
class FadeIn extends Animation {
constructor(element) {
super(element);
constructor(enteringView, leavingView) {
super(enteringView.pageRef());
this
.easing('ease')
.duration(450)
.fadeIn();
.duration(1000)
.fromTo('translateY', '0%', '0%')
.fadeIn()
.before.addClass('show-page');
}
}
Animation.register('my-fade-in', FadeIn);
class FadeOut extends Animation {
constructor(element) {
super(element);
constructor(enteringView, leavingView) {
super(leavingView.pageRef());
this
.easing('ease')
.duration(250)
.fadeOut();
.duration(500)
.fadeOut()
.before.addClass('show-page');
}
}
Animation.register('my-fade-out', FadeOut);

View File

@ -4,7 +4,7 @@ import {Ion} from '../ion';
import {IonicApp} from '../app/app';
import {Config} from '../../config/config';
import {ViewController} from './view-controller';
import {Transition} from '../../transitions/transition';
import {Animation} from '../../animations/animation';
import {SwipeBackGesture} from './swipe-back';
import * as util from 'ionic/util';
import {raf} from '../../util/dom';
@ -158,7 +158,7 @@ export class NavController extends Ion {
let promise = new Promise(res => { resolve = res; });
// do not animate if this is the first in the stack
if (!this._views.length) {
if (!this._views.length && !opts.animateFirst) {
opts.animate = false;
}
@ -177,6 +177,8 @@ export class NavController extends Ion {
let enteringView = new ViewController(this, componentType, params);
enteringView.shouldDestroy = false;
enteringView.shouldCache = false;
enteringView.pageType = opts.pageType;
enteringView.handle = opts.handle || null;
// add the view to the stack
this._add(enteringView);
@ -202,7 +204,7 @@ export class NavController extends Ion {
* @returns {Promise} TODO
*/
pop(opts = {}) {
if (!this.canGoBack()) {
if (!opts.animateFirst && !this.canGoBack()) {
return Promise.reject();
}
@ -225,20 +227,14 @@ export class NavController extends Ion {
// Note: we might not have an entering view if this is the
// only view on the history stack.
let enteringView = this.getPrevious(leavingView);
if (enteringView) {
if (this.router) {
// notify router of the state change
this.router.stateChange('pop', enteringView);
}
// start the transition
this._transition(enteringView, leavingView, opts, resolve);
} else {
this._transComplete();
resolve();
if (this.router) {
// notify router of the state change
this.router.stateChange('pop', enteringView);
}
// start the transition
this._transition(enteringView, leavingView, opts, resolve);
return promise;
}
@ -429,8 +425,8 @@ export class NavController extends Ion {
* @returns {any} TODO
*/
_transition(enteringView, leavingView, opts, done) {
if (!enteringView || enteringView === leavingView) {
return done();
if (enteringView === leavingView) {
return done(enteringView);
}
if (!opts.animation) {
@ -440,15 +436,21 @@ export class NavController extends Ion {
opts.animate = false;
}
if (!enteringView) {
// if not entering view then create a bogus one
enteringView = new ViewController()
enteringView.loaded();
}
// wait for the new view to complete setup
this._stage(enteringView, () => {
if (enteringView.shouldDestroy) {
// already marked as a view that will be destroyed, don't continue
return done();
return done(enteringView);
}
this._setZIndex(enteringView.instance, leavingView && leavingView.instance, opts.direction);
this._setZIndex(enteringView.instance, leavingView.instance, opts.direction);
this._zone.runOutsideAngular(() => {
@ -466,8 +468,11 @@ export class NavController extends Ion {
leavingView.state = STAGED_LEAVING_STATE;
// init the transition animation
opts.renderDelay = this.config.get('pageTransitionDelay');
let transAnimation = Transition.create(this, opts);
opts.renderDelay = opts.transitionDelay || this.config.get('pageTransitionDelay');
let transAnimation = Animation.createTransition(this._getStagedEntering(),
this._getStagedLeaving(),
opts);
if (opts.animate === false) {
// force it to not animate the elements, just apply the "to" styles
transAnimation.clearDuration();
@ -482,9 +487,12 @@ export class NavController extends Ion {
this.app.setTransitioning(true, duration);
}
if (opts.pageType) {
transAnimation.before.addClass(opts.pageType);
}
// start the transition
transAnimation.play(() => {
// transition has completed, update each view's state
enteringView.state = ACTIVE_STATE;
leavingView.state = CACHED_STATE;
@ -500,7 +508,7 @@ export class NavController extends Ion {
// all done!
this._zone.run(() => {
this._transComplete();
done();
done(enteringView);
});
});
@ -514,7 +522,7 @@ export class NavController extends Ion {
* @private
*/
_stage(viewCtrl, done) {
if (viewCtrl.instance || viewCtrl.shouldDestroy) {
if (viewCtrl.isLoaded() || viewCtrl.shouldDestroy) {
// already compiled this view
return done();
}
@ -685,8 +693,8 @@ export class NavController extends Ion {
this._zone.run(() => {
// find the views that were entering and leaving
let enteringView = this.getStagedEnteringView();
let leavingView = this.getStagedLeavingView();
let enteringView = this._getStagedEntering();
let leavingView = this._getStagedLeaving();
if (enteringView && leavingView) {
// finish up the animation
@ -883,29 +891,50 @@ export class NavController extends Ion {
/**
* @private
* TODO
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
_add(view) {
this._incrementId(view);
this._views.push(view);
}
_incrementId(view) {
view.id = this.id + '-' + (++this._ids);
_add(viewCtrl) {
this._incrementId(viewCtrl);
this._views.push(viewCtrl);
}
/**
* @private
*/
_incrementId(viewCtrl) {
viewCtrl.id = this.id + '-' + (++this._ids);
}
/**
* @private
* TODO
* @param {TODO} viewOrIndex TODO
* @returns {TODO} TODO
*/
_remove(viewOrIndex) {
util.array.remove(this._views, viewOrIndex);
}
/**
* @private
*/
_getStagedEntering() {
for (let i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].state === STAGED_ENTERING_STATE) {
return this._views[i];
}
}
return null;
}
/**
* @private
*/
_getStagedLeaving() {
for (let i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].state === STAGED_LEAVING_STATE) {
return this._views[i];
}
}
return null;
}
/**
* TODO
* @returns {TODO} TODO
@ -931,14 +960,42 @@ export class NavController extends Ion {
return null;
}
/**
* TODO
* @param {TODO} handle TODO
* @returns {TODO} TODO
*/
getByHandle(handle) {
for (let i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].handle === handle) {
return this._views[i];
}
}
return null;
}
/**
* TODO
* @param {TODO} pageType TODO
* @returns {TODO} TODO
*/
getByType(pageType) {
for (let i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].pageType === pageType) {
return this._views[i];
}
}
return null;
}
/**
* TODO
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
getPrevious(view) {
if (view) {
let viewIndex = this._views.indexOf(view);
getPrevious(viewCtrl) {
if (viewCtrl) {
let viewIndex = this._views.indexOf(viewCtrl);
for (let i = viewIndex - 1; i >= 0; i--) {
if (!this._views[i].shouldDestroy) {
@ -949,32 +1006,6 @@ export class NavController extends Ion {
return null;
}
/**
* TODO
* @returns {TODO} TODO
*/
getStagedEnteringView() {
for (let i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].state === STAGED_ENTERING_STATE) {
return this._views[i];
}
}
return null;
}
/**
* TODO
* @returns {TODO} TODO
*/
getStagedLeavingView() {
for (let i = 0, ii = this._views.length; i < ii; i++) {
if (this._views[i].state === STAGED_LEAVING_STATE) {
return this._views[i];
}
}
return null;
}
/**
* First view in this nav controller's stack. This would
* not return an view which is about to be destroyed.
@ -1008,8 +1039,8 @@ export class NavController extends Ion {
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
indexOf(view) {
return this._views.indexOf(view);
indexOf(viewCtrl) {
return this._views.indexOf(viewCtrl);
}
/**
@ -1027,36 +1058,13 @@ export class NavController extends Ion {
return len;
}
/**
* TODO
* @returns {TODO} TODO
*/
instances() {
let instances = [];
for (let view of this._views) {
if (view.instance) {
instances.push(view.instance);
}
}
return instances;
}
/**
* TODO
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
isActive(view) {
return (view && view.state === ACTIVE_STATE);
}
/**
* TODO
* @param {TODO} view TODO
* @returns {TODO} TODO
*/
isStagedEntering(view) {
return (view && view.state === STAGED_ENTERING_STATE);
isActive(viewCtrl) {
return (viewCtrl && viewCtrl.state === ACTIVE_STATE);
}
/**

View File

@ -10,9 +10,10 @@ export class ViewController {
this.navCtrl = navCtrl;
this.componentType = componentType;
this.params = new NavParams(params);
this.instance = null;
this.instance = {};
this.state = 0;
this._destroys = [];
this._loaded = false;
}
/**
@ -142,6 +143,10 @@ export class ViewController {
}
}
isLoaded() {
return this._loaded;
}
/**
* The view has loaded. This event only happens once per view being
* created. If a view leaves but is cached, then this will not
@ -150,8 +155,9 @@ export class ViewController {
* recommended method to use when a view becomes active.
*/
loaded() {
this._loaded = true;
if (!this.shouldDestroy) {
this.instance && this.instance.onPageLoaded && this.instance.onPageLoaded();
this.instance.onPageLoaded && this.instance.onPageLoaded();
}
}
@ -160,7 +166,7 @@ export class ViewController {
*/
willEnter() {
if (!this.shouldDestroy) {
this.instance && this.instance.onPageWillEnter && this.instance.onPageWillEnter();
this.instance.onPageWillEnter && this.instance.onPageWillEnter();
}
}
@ -171,14 +177,14 @@ export class ViewController {
didEnter() {
let navbar = this.getNavbar();
navbar && navbar.didEnter();
this.instance && this.instance.onPageDidEnter && this.instance.onPageDidEnter();
this.instance.onPageDidEnter && this.instance.onPageDidEnter();
}
/**
* The view has is about to leave and no longer be the active view.
*/
willLeave() {
this.instance && this.instance.onPageWillLeave && this.instance.onPageWillLeave();
this.instance.onPageWillLeave && this.instance.onPageWillLeave();
}
/**
@ -186,27 +192,25 @@ export class ViewController {
* will fire, whether it is cached or unloaded.
*/
didLeave() {
this.instance && this.instance.onPageDidLeave && this.instance.onPageDidLeave();
this.instance.onPageDidLeave && this.instance.onPageDidLeave();
}
/**
* The view is about to be destroyed and have its elements removed.
*/
willUnload() {
this.instance && this.instance.onPageWillUnload && this.instance.onPageWillUnload();
this.instance.onPageWillUnload && this.instance.onPageWillUnload();
}
/**
* The view has been destroyed and its elements have been removed.
*/
didUnload() {
this.instance && this.instance.onPageDidUnload && this.instance.onPageDidUnload();
this.instance.onPageDidUnload && this.instance.onPageDidUnload();
}
domCache(isActiveView, isPreviousView) {
if (this.instance) {
this.instance._hidden = (!isActiveView && !isPreviousView);
}
this.instance._hidden = (!isActiveView && !isPreviousView);
}
}

View File

@ -1,164 +1,43 @@
import {Component, NgZone, Injectable, Renderer} from 'angular2/angular2';
import {IonicApp} from '../app/app';
import {Config} from '../../config/config';
import {Animation} from '../../animations/animation';
import * as util from 'ionic/util';
import {extend} from 'ionic/util';
@Injectable()
export class OverlayController {
constructor(app: IonicApp, config: Config, zone: NgZone, renderer: Renderer) {
this.app = app;
this.config = config;
this.zone = zone;
this.renderer = renderer;
this.refs = [];
}
open(overlayType, componentType: Type, opts={}) {
if (!this.anchor) {
console.error('<ion-overlay></ion-overlay> required in root component template to use: ' + overlayType);
open(componentType, params = {}, opts = {}) {
if (!this.nav) {
console.error('<ion-overlay></ion-overlay> required in root template (app.html) to use: ' + overlayType);
return Promise.reject();
}
let resolve, reject;
let promise = new Promise((res, rej) => { resolve = res; reject = rej; });
try {
this.anchor.append(componentType).then(ref => {
let instance = ref && ref.instance;
if (!instance) {
return reject();
}
opts.animation = opts.enterAnimation;
opts.animateFirst = true;
instance._zIndex = ROOT_Z_INDEX;
for (let i = 0; i < this.refs.length; i++) {
if (this.refs[i].instance._zIndex >= ref.instance._zIndex) {
ref.instance._zIndex = this.refs[i].instance._zIndex + 1;
}
}
this.renderer.setElementAttribute(ref.location, 'role', 'dialog');
util.extend(instance, opts);
ref._type = overlayType;
ref._handle = opts.handle || (overlayType + ref._z);
this.add(ref);
instance.close = (closeOpts={}) => {
this.close(ref, util.extend(opts, closeOpts));
this.nav.push(componentType, params, opts).then(enteringView => {
if (enteringView && enteringView.instance) {
enteringView.instance.close = (closeOpts={}) => {
extend(opts, closeOpts);
opts.animation = opts.leaveAnimation;
this.nav.pop(opts);
};
instance.onPageLoaded && instance.onPageLoaded();
instance.onPageWillEnter && instance.onPageWillEnter();
let animation = Animation.create(ref.location.nativeElement, opts.enterAnimation);
if (this.config.get('animate') === false) {
animation.duration(0);
}
animation.before.addClass(overlayType);
if (overlayType == 'modal') {
animation.before.addClass('show-page');
}
this.app.setEnabled(false, animation.duration());
this.app.setTransitioning(true, animation.duration());
this.zone.runOutsideAngular(() => {
animation.play().then(() => {
animation.dispose();
this.zone.run(() => {
this.app.setEnabled(true);
this.app.setTransitioning(false);
instance.onPageDidEnter && instance.onPageDidEnter();
resolve(instance);
});
});
});
}).catch(err => {
console.error(err);
});
} catch (e) {
console.error(e);
}
}
resolve();
})
return promise;
}
close(ref, opts) {
let resolve;
let promise = new Promise(res => { resolve = res; });
let instance = ref.instance;
instance.onPageWillLeave && instance.onPageWillLeave();
instance.onPageWillUnload && instance.onPageWillUnload();
let animation = Animation.create(ref.location.nativeElement, opts.leaveAnimation);
if (this.config.get('animate') === false) {
animation.duration(0);
}
this.app.setEnabled(false, animation.duration());
this.app.setTransitioning(true, animation.duration());
this.zone.runOutsideAngular(() => {
animation.play().then(() => {
animation.dispose();
this.zone.run(() => {
instance.onPageDidLeave && instance.onPageDidLeave();
instance.onPageDidUnload && instance.onPageDidUnload();
this.app.setEnabled(true);
this.app.setTransitioning(false);
this.remove(ref);
resolve();
});
});
});
return promise;
}
add(ref) {
this.refs.push(ref);
}
remove(ref) {
util.array.remove(this.refs, ref);
ref.dispose && ref.dispose();
}
getByType(overlayType) {
for (let i = this.refs.length - 1; i >= 0; i--) {
if (overlayType === this.refs[i]._type) {
return this.refs[i].instance;
}
}
return null;
let overlay = this.nav.getByType(overlayType);
return overlay && overlay.instance;
}
getByHandle(handle, overlayType) {
for (let i = this.refs.length - 1; i >= 0; i--) {
if (handle === this.refs[i]._handle && overlayType === this.refs[i]._type) {
return this.refs[i].instance;
}
}
return null;
let overlay = this.nav.getByHandle(handle);
return overlay && overlay.instance;
}
}

View File

@ -1,33 +1,35 @@
import {Component, ElementRef, DynamicComponentLoader} from 'angular2/angular2';
import {Component, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, NgZone, Renderer} from 'angular2/angular2';
import {IonicApp} from '../app/app';
import {Config} from '../../config/config';
import {OverlayController} from './overlay-controller';
import {NavController} from '../nav/nav-controller';
/**
* @private
*/
@Component({
selector: 'ion-overlay',
template: '<template #contents></template>'
})
export class OverlayAnchor {
export class OverlayNav extends NavController {
constructor(
overlayCtrl: OverlayController,
app: IonicApp,
config: Config,
elementRef: ElementRef,
loader: DynamicComponentLoader
compiler: Compiler,
loader: DynamicComponentLoader,
viewManager: AppViewManager,
zone: NgZone,
renderer: Renderer
) {
super(null, app, config, elementRef, compiler, loader, viewManager, zone, renderer);
if (overlayCtrl.anchor) {
throw ('An app should only have one <ion-overlay></ion-overlay>');
}
this.elementRef = elementRef;
this.loader = loader;
overlayCtrl.anchor = this;
overlayCtrl.nav = this;
}
append(componentType) {
return this.loader.loadIntoLocation(componentType, this.elementRef, 'contents').catch(err => {
console.error(err);
});
}
}

View File

@ -1,11 +1,12 @@
import {FORM_DIRECTIVES, NgControl, NgControlGroup,
Component, ElementRef, Injectable, NgClass, NgIf, NgFor} from 'angular2/angular2';
Component, ElementRef, Injectable, NgClass, NgIf, NgFor, Renderer} from 'angular2/angular2';
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 * as util from 'ionic/util';
import {extend} from '../../util/util';
/**
@ -66,10 +67,7 @@ export class Popup {
constructor(ctrl: OverlayController, config: Config) {
this.ctrl = ctrl;
this._defaults = {
enterAnimation: config.get('popupEnter'),
leaveAnimation: config.get('popupLeave'),
};
this.config = config;
}
/**
@ -82,9 +80,13 @@ export class Popup {
opts.promiseResolve = resolve;
opts.promiseReject = reject;
let defaults = util.merge({}, this._defaults);
opts = extend({
pageType: OVERLAY_TYPE,
enterAnimation: this.config.get('popupEnter'),
leaveAnimation: this.config.get('popupLeave')
}, opts);
return this.ctrl.open(OVERLAY_TYPE, PopupCmp, util.extend(defaults, opts));
return this.ctrl.open(PopupCmp, opts, opts);
});
}
@ -122,7 +124,7 @@ export class Popup {
//resolve();
}
};
opts = util.extend({
opts = extend({
showPrompt: false,
cancel: () => {
//reject();
@ -178,7 +180,7 @@ export class Popup {
// Allow it to close
}
}
opts = util.extend({
opts = extend({
showPrompt: false,
cancel: () => {
},
@ -237,7 +239,7 @@ export class Popup {
}
}
opts = util.extend({
opts = extend({
showPrompt: true,
promptPlaceholder: '',
cancel: () => {
@ -256,7 +258,7 @@ export class Popup {
*/
get(handle) {
if (handle) {
return this.ctrl.getByHandle(handle, OVERLAY_TYPE);
return this.ctrl.getByHandle(handle);
}
return this.ctrl.getByType(OVERLAY_TYPE);
}
@ -265,34 +267,40 @@ export class Popup {
const OVERLAY_TYPE = 'popup';
// TODO add button type to button: [type]="button.type"
@Component({
selector: 'ion-popup',
template:
'<backdrop (click)="_cancel($event)" tappable disable-activated></backdrop>' +
'<popup-wrapper [ng-class]="cssClass">' +
'<backdrop (click)="cancel($event)" tappable disable-activated></backdrop>' +
'<popup-wrapper>' +
'<div class="popup-head">' +
'<h2 class="popup-title" [inner-html]="title" *ng-if="title"></h2>' +
'<h3 class="popup-sub-title" [inner-html]="subTitle" *ng-if="subTitle"></h3>' +
'<h2 class="popup-title" [inner-html]="d.title" *ng-if="d.title"></h2>' +
'<h3 class="popup-sub-title" [inner-html]="d.subTitle" *ng-if="d.subTitle"></h3>' +
'</div>' +
'<div class="popup-body">' +
'<div [inner-html]="template" *ng-if="template"></div>' +
'<input type="{{inputType || \'text\'}}" placeholder="{{inputPlaceholder}}" *ng-if="showPrompt" class="prompt-input">' +
'<div [inner-html]="d.template" *ng-if="d.template"></div>' +
'<input type="{{d.inputType || \'text\'}}" placeholder="{{d.inputPlaceholder}}" *ng-if="d.showPrompt" class="prompt-input">' +
'</div>' +
'<div class="popup-buttons" *ng-if="buttons.length">' +
'<button *ng-for="#button of buttons" (click)="buttonTapped(button, $event)" [inner-html]="button.text"></button>' +
'<div class="popup-buttons" *ng-if="d.buttons.length">' +
'<button *ng-for="#btn of d.buttons" (click)="buttonTapped(btn, $event)" [inner-html]="btn.text"></button>' +
'</div>' +
'</popup-wrapper>',
'</popup-wrapper>',
host: {
'[style.zIndex]': '_zIndex'
'[style.zIndex]': '_zIndex',
'role': 'dialog'
},
directives: [FORM_DIRECTIVES, NgClass, NgIf, NgFor, Button]
})
class PopupCmp {
constructor(elementRef: ElementRef) {
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);
}
}
onInit() {
@ -305,90 +313,118 @@ class PopupCmp {
});
}
buttonTapped(button, event) {
buttonTapped(button, ev) {
let promptValue = this.promptInput && this.promptInput.value;
let retVal = button.onTap && button.onTap(event, this, {
let retVal = button.onTap && button.onTap(ev, this, {
promptValue: promptValue
});
// If the event.preventDefault() wasn't called, close
if (!event.defaultPrevented) {
if (!ev.defaultPrevented) {
// If this is a cancel button, reject the promise
if (button.isCancel) {
this.promiseReject();
this.d.promiseReject();
} else {
// Resolve with the prompt value
this.promiseResolve(promptValue);
this.d.promiseResolve(promptValue);
}
return this.close();
}
}
_cancel(event) {
this.cancel && this.cancel(event);
cancel(ev) {
this.d.cancel && this.d.cancel(event);
if (!event.defaultPrevented) {
this.promiseReject();
if (!ev.defaultPrevented) {
this.d.promiseReject();
return this.close();
}
}
}
class PopupAnimation extends Animation {
constructor(element) {
super(element);
this
.easing('ease-in-out')
.duration(200);
this.backdrop = new Animation(element.querySelector('backdrop'));
this.wrapper = new Animation(element.querySelector('popup-wrapper'));
this.add(this.backdrop, this.wrapper);
}
}
/**
* Animations for popups
*/
class PopupPopIn extends PopupAnimation {
constructor(element) {
super(element);
this.wrapper.fromTo('opacity', '0.01', '1')
this.wrapper.fromTo('scale', '1.1', '1');
class PopupPopIn extends Animation {
constructor(enteringView, leavingView, opts) {
super(null, opts);
this.backdrop.fromTo('opacity', '0', '0.3')
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 PopupAnimation {
constructor(element) {
super(element);
this.wrapper.fromTo('opacity', '1', '0')
this.wrapper.fromTo('scale', '1', '0.9');
this.backdrop.fromTo('opacity', '0.3', '0')
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 PopupPopIn {
constructor(element) {
super(element);
this.backdrop.fromTo('opacity', '0.01', '0.5')
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 PopupPopOut {
constructor(element) {
super(element);
this.backdrop.fromTo('opacity', '0.5', '0')
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);

View File

@ -115,7 +115,6 @@ export class Tabs extends Ion {
this.app = app;
this.subPages = config.get('tabSubPages');
// collection of children "Tab" instances, which extends NavController
this.tabs = [];
// Tabs may also be an actual ViewController which was navigated to

View File

@ -18,7 +18,7 @@ export class RippleActivator extends Activator {
// create a new ripple element
this.expandSpeed = EXPAND_DOWN_PLAYBACK_RATE;
rafFrames(2, () => {
raf(() => {
let clientRect = activatableEle.getBoundingClientRect();
raf(() => {

View File

@ -1,6 +1,6 @@
import {CORE_DIRECTIVES, FORM_DIRECTIVES, forwardRef} from 'angular2/angular2'
import {OverlayAnchor} from '../components/overlay/overlay';
import {OverlayNav} from '../components/overlay/overlay';
import {Menu} from '../components/menu/menu';
import {MenuToggle} from '../components/menu/menu-toggle';
import {MenuClose} from '../components/menu/menu-close';
@ -42,7 +42,7 @@ export const IONIC_DIRECTIVES = [
FORM_DIRECTIVES,
// Content
OverlayAnchor,
OverlayNav,
Menu,
MenuToggle,
MenuClose,

View File

@ -21,7 +21,7 @@ Config.setModeConfig('ios', {
modalEnter: 'modal-slide-in',
modalLeave: 'modal-slide-out',
pageTransition: 'ios',
pageTransition: 'ios-transition',
pageTransitionDelay: 16,
popupEnter: 'popup-pop-in',
@ -50,7 +50,7 @@ Config.setModeConfig('md', {
modalEnter: 'modal-md-slide-in',
modalLeave: 'modal-md-slide-out',
pageTransition: 'md',
pageTransition: 'md-transition',
pageTransitionDelay: 120,
popupEnter: 'popup-md-pop-in',

View File

@ -16,10 +16,8 @@ export * from './util/events'
export * from './animations/animation'
export * from './animations/builtins'
export * from './transitions/transition'
export * from './transitions/ios-transition'
export * from './transitions/md-transition'
export * from './animations/ios-transition'
export * from './animations/md-transition'
export * from './translation/translate'
export * from './translation/translate_pipe'

View File

@ -1,22 +0,0 @@
export class Transition {
static create(navCtrl, opts = {}) {
const name = opts.animation || 'ios';
let TransitionClass = transitionRegistry[name];
if (!TransitionClass) {
TransitionClass = transitionRegistry.ios;
}
return new TransitionClass(navCtrl, opts);
}
static register(name, TransitionClass) {
transitionRegistry[name] = TransitionClass;
}
}
let transitionRegistry = {};

View File

@ -118,24 +118,6 @@ export function nextUid() {
return ++uid;
}
/**
* A simple logger class.
*/
export class Log {
static log(...args) {
console.log.apply(console, args);
}
static info(...args) {
console.info.apply(console, args);
}
static warn(...args) {
console.warn.apply(console, args);
}
static error(...args) {
console.error.apply(console, args);
}
}
export const array = {
find(arr, cb) {
for (let i = 0, ii = arr.length; i < ii; i++) {

View File

@ -1,17 +1,15 @@
import {FormBuilder, Validators} from 'angular2/angular2';
import {Log} from 'ionic/util'
import {Page, NavController} from 'ionic/ionic'
@Page({
templateUrl: 'app/<%= fileName %>/<%= fileName %>.html'
})
class <%= jsClassName %> {
constructor(nav: NavController ) {
this.nav = nav;
this.nav = nav
Log.log('LOGIN PAGE', this)
var fb = new FormBuilder()
var fb = new FormBuilder();
this.loginForm = fb.group({
email: ['', Validators.required],
@ -20,13 +18,12 @@ class <%= jsClassName %> {
}
doLogin(event) {
Log.log('Doing login')
event.preventDefault();
doLogin() {
console.log(this.loginForm.value);
}
doSignup(event) {
doSignup() {
this.nav.push(SignupPage)
}
}

View File

@ -1,6 +1,5 @@
import {FormBuilder, Validators} from 'angular2/angular2';
import {Log} from 'ionic/util'
import {Page, NavController} from 'ionic/ionic'
import {Page, NavController} from 'ionic/ionic';
@Page({
@ -8,11 +7,9 @@ import {Page, NavController} from 'ionic/ionic'
})
export class <%= jsClassName %> {
constructor(nav: NavController) {
this.nav = nav
this.nav = nav;
Log.log('SIGNUP PAGE')
var fb = new FormBuilder()
var fb = new FormBuilder();
this.signupForm = fb.group({
name: ['', Validators.required],
@ -21,14 +18,14 @@ export class <%= jsClassName %> {
});
}
doLogin(event) {
doLogin() {
this.nav.pop()
}
doSignup(event) {
Log.log('Doing signup')
event.preventDefault();
doSignup() {
console.log(this.signupForm.value);
this.nav.push(AppPage)
this.nav.push(AppPage);
}
}