refactor(transition): create transition controller

This commit is contained in:
Adam Bradley
2016-09-13 15:12:14 -05:00
parent aaa09bb96e
commit 41a7e07651
8 changed files with 886 additions and 805 deletions

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +0,0 @@
import { Animation } from './animation';
class SlideIn extends Animation {
constructor(element: any) {
super(element);
this
.easing('cubic-bezier(0.1,0.7,0.1,1)')
.duration(400)
.fromTo('translateY', '100%', '0%');
}
}
Animation.register('slide-in', SlideIn);
class SlideOut extends Animation {
constructor(element: any) {
super(element);
this
.easing('ease-out')
.duration(250)
.fromTo('translateY', '0%', '100%');
}
}
Animation.register('slide-out', SlideOut);
class FadeIn extends Animation {
constructor(element: any) {
super(element);
this
.easing('ease-in')
.duration(400)
.fromTo('opacity', 0.001, 1, true);
}
}
Animation.register('fade-in', FadeIn);
class FadeOut extends Animation {
constructor(element: any) {
super(element);
this
.easing('ease-out')
.duration(250)
.fromTo('opacity', 0.999, 0);
}
}
Animation.register('fade-out', FadeOut);

View File

@@ -1,9 +1,6 @@
import { Animation } from '../animations/animation';
import { closest } from '../util/dom';
import { Content } from '../components/content/content';
import { Tabs } from '../components/tabs/tabs';
import { Transition, TransitionOptions } from './transition';
import { ViewController } from '../components/nav/view-controller';
import { Transition } from './transition';
/**
@@ -12,22 +9,21 @@ import { ViewController } from '../components/nav/view-controller';
export class PageTransition extends Transition {
enteringPage: Animation;
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
super(enteringView, leavingView, opts);
init() {
if (this.enteringView) {
this.enteringPage = new Animation(this.enteringView.pageRef());
this.add(this.enteringPage.beforeAddClass('show-page'));
this.enteringPage = new Animation(this.enteringView.pageRef());
this.enteringPage.before.addClass('show-page');
this.add(this.enteringPage);
this.before.addDomReadFn(this.readDimensions.bind(this));
this.before.addDomWriteFn(this.writeDimensions.bind(this));
this.beforeAddRead(this.readDimensions.bind(this));
this.beforeAddWrite(this.writeDimensions.bind(this));
}
}
/**
* DOM READ
*/
readDimensions() {
let content = <Content>this.enteringView.getContent();
const content = <Content>this.enteringView.getContent();
if (content && content instanceof Content) {
content.readDimensions();
}
@@ -37,7 +33,7 @@ export class PageTransition extends Transition {
* DOM WRITE
*/
writeDimensions() {
let content = <Content>this.enteringView.getContent();
const content = <Content>this.enteringView.getContent();
if (content && content instanceof Content) {
content.writeDimensions();
}
@@ -45,11 +41,7 @@ export class PageTransition extends Transition {
destroy() {
super.destroy();
this.enteringView = this.enteringPage = null;
this.enteringPage = null;
}
}
function parsePxUnit(val: string): number {
return (val.indexOf('px') > 0) ? parseInt(val, 10) : 0;
}

View File

@@ -0,0 +1,53 @@
import { AnimationOptions } from '../animations/animation';
import { isPresent } from '../util/util';
import { NavControllerBase } from '../navigation/nav-controller-base';
import { Transition } from './transition';
import { ViewController } from '../navigation/view-controller';
/**
* @private
*/
export class TransitionController {
private _ids = 0;
private _trns: {[key: number]: Transition} = {};
getRootTrnsId(nav: NavControllerBase): number {
let parent = <NavControllerBase>nav.parent;
while (parent) {
if (isPresent(parent._trnsId)) {
return parent._trnsId;
}
parent = parent.parent;
}
return null;
}
nextId() {
return this._ids++;
}
get(trnsId: number, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions) {
const trns = Transition.createTransition(opts.animation, enteringView, leavingView, opts);
trns.trnsId = trnsId;
if (!this._trns[trnsId]) {
// we haven't created the root transition yet
this._trns[trnsId] = trns;
} else {
// we already have a root transition created
// add this new transition as a child to the root
this._trns[trnsId].add(trns);
}
return trns;
}
destroy(trnsId: number) {
if (this._trns[trnsId]) {
this._trns[trnsId].destroy();
delete this._trns[trnsId];
}
}
}

View File

@@ -1,7 +1,6 @@
import { Animation } from '../animations/animation';
import { isPresent } from '../util/util';
import { PageTransition } from './page-transition';
import { TransitionOptions } from './transition';
import { ViewController } from '../components/nav/view-controller';
const DURATION = 500;
const EASING = 'cubic-bezier(0.36,0.66,0.04,1)';
@@ -14,117 +13,126 @@ const OFF_OPACITY = 0.8;
const SHOW_BACK_BTN_CSS = 'show-back-button';
class IOSTransition extends PageTransition {
export class IOSTransition extends PageTransition {
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
super(enteringView, leavingView, opts);
init() {
super.init();
this.duration(opts.duration || DURATION);
this.easing(opts.easing || EASING);
const enteringView = this.enteringView;
const leavingView = this.leavingView;
const opts = this.opts;
// what direction is the transition going
let backDirection = (opts.direction === 'back');
this.duration(isPresent(opts.duration) ? opts.duration : DURATION);
this.easing(isPresent(opts.easing) ? opts.easing : EASING);
// do they have navbars?
let enteringHasNavbar = enteringView.hasNavbar();
let leavingHasNavbar = leavingView && leavingView.hasNavbar();
const backDirection = (opts.direction === 'back');
const enteringHasNavbar = (enteringView && enteringView.hasNavbar());
const leavingHasNavbar = (leavingView && leavingView.hasNavbar());
// entering content
let enteringContent = new Animation(enteringView.contentRef());
enteringContent.element(enteringView.toolbarRefs());
this.add(enteringContent);
if (enteringView) {
// get the native element for the entering page
const enteringPageEle: Element = enteringView.pageRef().nativeElement;
if (backDirection) {
// entering content, back direction
enteringContent
.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true)
.fromTo(OPACITY, OFF_OPACITY, 1, true);
// entering content
const enteringContent = new Animation(enteringView.contentRef());
enteringContent.element(enteringPageEle.querySelectorAll('ion-header > *:not(ion-navbar),ion-footer > *'));
this.add(enteringContent);
} else {
// entering content, forward direction
enteringContent
.before.clearStyles([OPACITY])
.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
}
if (enteringHasNavbar) {
// entering page has a navbar
let enteringNavBar = new Animation(enteringView.navbarRef());
enteringNavBar.before.addClass('show-navbar');
this.add(enteringNavBar);
let enteringTitle = new Animation(enteringView.titleRef());
let enteringNavbarItems = new Animation(enteringView.navbarItemRefs());
let enteringNavbarBg = new Animation(enteringView.navbarBgRef());
let enteringBackButton = new Animation(enteringView.backBtnRef());
enteringNavBar
.add(enteringTitle)
.add(enteringNavbarItems)
.add(enteringNavbarBg)
.add(enteringBackButton);
enteringTitle.fromTo(OPACITY, 0.01, 1, true);
enteringNavbarItems.fromTo(OPACITY, 0.01, 1, true);
// set properties depending on direction
if (backDirection) {
// entering navbar, back direction
enteringTitle.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true);
if (enteringView.enableBack()) {
// back direction, entering page has a back button
enteringBackButton
.before.addClass(SHOW_BACK_BTN_CSS)
.fromTo(OPACITY, 0.01, 1, true);
}
// entering content, back direction
enteringContent
.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true)
.fromTo(OPACITY, OFF_OPACITY, 1, true);
} else {
// entering navbar, forward direction
enteringTitle.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
// entering content, forward direction
enteringContent
.beforeClearStyles([OPACITY])
.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
}
if (leavingHasNavbar) {
// entering navbar, forward direction, and there's a leaving navbar
// should just fade in, no sliding
enteringNavbarBg
.before.clearStyles([TRANSLATEX])
.fromTo(OPACITY, 0.01, 1, true);
if (enteringHasNavbar) {
// entering page has a navbar
const enteringNavbarEle = enteringPageEle.querySelector('ion-navbar');
const enteringNavBar = new Animation(enteringNavbarEle);
this.add(enteringNavBar);
const enteringTitle = new Animation(enteringNavbarEle.querySelector('ion-title'));
const enteringNavbarItems = new Animation(enteringNavbarEle.querySelectorAll('ion-buttons,[menuToggle]'));
const enteringNavbarBg = new Animation(enteringNavbarEle.querySelector('.toolbar-background'));
const enteringBackButton = new Animation(enteringNavbarEle.querySelector('.back-button'));
enteringNavBar
.add(enteringTitle)
.add(enteringNavbarItems)
.add(enteringNavbarBg)
.add(enteringBackButton);
enteringTitle.fromTo(OPACITY, 0.01, 1, true);
enteringNavbarItems.fromTo(OPACITY, 0.01, 1, true);
// set properties depending on direction
if (backDirection) {
// entering navbar, back direction
enteringTitle.fromTo(TRANSLATEX, OFF_LEFT, CENTER, true);
if (enteringView.enableBack()) {
// back direction, entering page has a back button
enteringBackButton
.beforeAddClass(SHOW_BACK_BTN_CSS)
.fromTo(OPACITY, 0.01, 1, true);
}
} else {
// entering navbar, forward direction, and there's no leaving navbar
// should just slide in, no fading in
enteringNavbarBg
.before.clearStyles([OPACITY])
.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
}
// entering navbar, forward direction
enteringTitle.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
if (leavingHasNavbar) {
// entering navbar, forward direction, and there's a leaving navbar
// should just fade in, no sliding
enteringNavbarBg
.beforeClearStyles([TRANSLATEX])
.fromTo(OPACITY, 0.01, 1, true);
} else {
// entering navbar, forward direction, and there's no leaving navbar
// should just slide in, no fading in
enteringNavbarBg
.beforeClearStyles([OPACITY])
.fromTo(TRANSLATEX, OFF_RIGHT, CENTER, true);
}
if (enteringView.enableBack()) {
// forward direction, entering page has a back button
enteringBackButton
.before.addClass(SHOW_BACK_BTN_CSS)
.fromTo(OPACITY, 0.01, 1, true);
if (enteringView.enableBack()) {
// forward direction, entering page has a back button
enteringBackButton
.beforeAddClass(SHOW_BACK_BTN_CSS)
.fromTo(OPACITY, 0.01, 1, true);
let enteringBackBtnText = new Animation(enteringView.backBtnTextRef());
enteringBackBtnText.fromTo(TRANSLATEX, '100px', '0px');
enteringNavBar.add(enteringBackBtnText);
const enteringBackBtnText = new Animation(enteringNavbarEle.querySelector('.back-button-text'));
enteringBackBtnText.fromTo(TRANSLATEX, '100px', '0px');
enteringNavBar.add(enteringBackBtnText);
} else {
enteringBackButton.before.removeClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
}
}
}
}
// setup leaving view
if (leavingView) {
if (leavingView && leavingView.pageRef()) {
// leaving content
let leavingContent = new Animation(leavingView.contentRef());
leavingContent.element(leavingView.toolbarRefs());
const leavingPageEle: Element = leavingView.pageRef().nativeElement;
const leavingContent = new Animation(leavingView.contentRef());
leavingContent.element(leavingPageEle.querySelectorAll('ion-header > *:not(ion-navbar),ion-footer > *'));
this.add(leavingContent);
if (backDirection) {
// leaving content, back direction
leavingContent
.before.clearStyles([OPACITY])
.beforeClearStyles([OPACITY])
.fromTo(TRANSLATEX, CENTER, '100%');
} else {
@@ -136,16 +144,18 @@ class IOSTransition extends PageTransition {
if (leavingHasNavbar) {
// leaving page has a navbar
let leavingNavBar = new Animation(leavingView.navbarRef());
let leavingBackButton = new Animation(leavingView.backBtnRef());
let leavingTitle = new Animation(leavingView.titleRef());
let leavingNavbarItems = new Animation(leavingView.navbarItemRefs());
let leavingNavbarBg = new Animation(leavingView.navbarBgRef());
const leavingNavbarEle: Element = leavingPageEle.querySelector('ion-navbar');
const leavingNavBar = new Animation(leavingNavbarEle);
const leavingTitle = new Animation(leavingNavbarEle.querySelector('ion-title'));
const leavingNavbarItems = new Animation(leavingNavbarEle.querySelectorAll('ion-buttons,[menuToggle]'));
const leavingNavbarBg = new Animation(leavingNavbarEle.querySelector('.toolbar-background'));
const leavingBackButton = new Animation(leavingNavbarEle.querySelector('.back-button'));
leavingNavBar
.add(leavingBackButton)
.add(leavingTitle)
.add(leavingNavbarItems)
.add(leavingBackButton)
.add(leavingNavbarBg);
this.add(leavingNavBar);
@@ -162,18 +172,18 @@ class IOSTransition extends PageTransition {
// leaving navbar, back direction, and there's an entering navbar
// should just fade out, no sliding
leavingNavbarBg
.before.clearStyles([TRANSLATEX])
.beforeClearStyles([TRANSLATEX])
.fromTo('opacity', 0.99, 0);
} else {
// leaving navbar, back direction, and there's no entering navbar
// should just slide out, no fading out
leavingNavbarBg
.before.clearStyles([OPACITY])
.beforeClearStyles([OPACITY])
.fromTo(TRANSLATEX, CENTER, '100%');
}
let leavingBackBtnText = new Animation(leavingView.backBtnTextRef());
let leavingBackBtnText = new Animation(leavingNavbarEle.querySelector('.back-button-text'));
leavingBackBtnText.fromTo(TRANSLATEX, CENTER, (300) + 'px');
leavingNavBar.add(leavingBackBtnText);
@@ -187,5 +197,3 @@ class IOSTransition extends PageTransition {
}
}
PageTransition.register('ios-transition', IOSTransition);

View File

@@ -1,7 +1,6 @@
import { Animation } from '../animations/animation';
import { isPresent } from '../util/util';
import { PageTransition } from './page-transition';
import { TransitionOptions } from './transition';
import { ViewController } from '../components/nav/view-controller';
const TRANSLATEY = 'translateY';
const OFF_BOTTOM = '40px';
@@ -9,40 +8,44 @@ const CENTER = '0px';
const SHOW_BACK_BTN_CSS = 'show-back-button';
class MDTransition extends PageTransition {
export class MDTransition extends PageTransition {
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
super(enteringView, leavingView, opts);
init() {
super.init();
const enteringView = this.enteringView;
const leavingView = this.leavingView;
const opts = this.opts;
// what direction is the transition going
let backDirection = (opts.direction === 'back');
const backDirection = (opts.direction === 'back');
// do they have navbars?
let enteringHasNavbar = enteringView.hasNavbar();
let leavingHasNavbar = leavingView && leavingView.hasNavbar();
if (enteringView) {
if (backDirection) {
this.duration(isPresent(opts.duration) ? opts.duration : 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
this.enteringPage.beforeClearStyles([TRANSLATEY]);
if (backDirection) {
this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
this.enteringPage.before.clearStyles([TRANSLATEY]);
} else {
this.duration(opts.duration || 280).easing('cubic-bezier(0.36,0.66,0.04,1)');
this.enteringPage
.fromTo(TRANSLATEY, OFF_BOTTOM, CENTER, true)
.fromTo('opacity', 0.01, 1, true);
}
if (enteringHasNavbar) {
let enteringNavBar = new Animation(enteringView.navbarRef());
enteringNavBar.before.addClass('show-navbar');
this.add(enteringNavBar);
let enteringBackButton = new Animation(enteringView.backBtnRef());
this.add(enteringBackButton);
if (enteringView.enableBack()) {
enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.before.removeClass(SHOW_BACK_BTN_CSS);
this.duration(isPresent(opts.duration) ? opts.duration : 280).easing('cubic-bezier(0.36,0.66,0.04,1)');
this.enteringPage
.fromTo(TRANSLATEY, OFF_BOTTOM, CENTER, true)
.fromTo('opacity', 0.01, 1, true);
}
if (enteringView.hasNavbar()) {
const enteringPageEle: Element = enteringView.pageRef().nativeElement;
const enteringNavbarEle: Element = enteringPageEle.querySelector('ion-navbar');
const enteringNavBar = new Animation(enteringNavbarEle);
this.add(enteringNavBar);
const enteringBackButton = new Animation(enteringNavbarEle.querySelector('.back-button'));
this.add(enteringBackButton);
if (enteringView.enableBack()) {
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
}
}
}
@@ -50,12 +53,10 @@ class MDTransition extends PageTransition {
if (leavingView && backDirection) {
// leaving content
this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
let leavingPage = new Animation(leavingView.pageRef());
const leavingPage = new Animation(leavingView.pageRef());
this.add(leavingPage.fromTo(TRANSLATEY, CENTER, OFF_BOTTOM).fromTo('opacity', 0.99, 0));
}
}
}
PageTransition.register('md-transition', MDTransition);

View File

@@ -1,46 +1,49 @@
import { Animation } from '../animations/animation';
import { isPresent } from '../util/util';
import { PageTransition } from './page-transition';
import { TransitionOptions } from './transition';
import { ViewController } from '../components/nav/view-controller';
const SHOW_BACK_BTN_CSS = 'show-back-button';
const SCALE_SMALL = .95;
class WPTransition extends PageTransition {
export class WPTransition extends PageTransition {
constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
super(enteringView, leavingView, opts);
init() {
super.init();
const enteringView = this.enteringView;
const leavingView = this.leavingView;
const opts = this.opts;
// what direction is the transition going
let backDirection = (opts.direction === 'back');
const backDirection = (opts.direction === 'back');
// do they have navbars?
let enteringHasNavbar = enteringView.hasNavbar();
let leavingHasNavbar = leavingView && leavingView.hasNavbar();
if (enteringView) {
if (backDirection) {
this.duration(isPresent(opts.duration) ? opts.duration : 120).easing('cubic-bezier(0.47,0,0.745,0.715)');
this.enteringPage.beforeClearStyles(['scale']);
if (backDirection) {
this.duration(opts.duration || 120).easing('cubic-bezier(0.47,0,0.745,0.715)');
this.enteringPage.before.clearStyles(['scale']);
} else {
this.duration(opts.duration || 280).easing('cubic-bezier(0,0 0.05,1)');
this.enteringPage
.fromTo('scale', SCALE_SMALL, 1, true)
.fromTo('opacity', 0.01, 1, true);
}
if (enteringHasNavbar) {
let enteringNavBar = new Animation(enteringView.navbarRef());
enteringNavBar.before.addClass('show-navbar');
this.add(enteringNavBar);
let enteringBackButton = new Animation(enteringView.backBtnRef());
this.add(enteringBackButton);
if (enteringView.enableBack()) {
enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.before.removeClass(SHOW_BACK_BTN_CSS);
this.duration(isPresent(opts.duration) ? opts.duration : 280).easing('cubic-bezier(0,0 0.05,1)');
this.enteringPage
.fromTo('scale', SCALE_SMALL, 1, true)
.fromTo('opacity', 0.01, 1, true);
}
if (enteringView.hasNavbar()) {
const enteringPageEle: Element = enteringView.pageRef().nativeElement;
const enteringNavbarEle: Element = enteringPageEle.querySelector('ion-navbar');
const enteringNavBar = new Animation(enteringNavbarEle);
this.add(enteringNavBar);
const enteringBackButton = new Animation(enteringNavbarEle.querySelector('.back-button'));
this.add(enteringBackButton);
if (enteringView.enableBack()) {
enteringBackButton.beforeAddClass(SHOW_BACK_BTN_CSS);
} else {
enteringBackButton.beforeRemoveClass(SHOW_BACK_BTN_CSS);
}
}
}
@@ -48,12 +51,10 @@ class WPTransition extends PageTransition {
if (leavingView && backDirection) {
// leaving content
this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
let leavingPage = new Animation(leavingView.pageRef());
const leavingPage = new Animation(leavingView.pageRef());
this.add(leavingPage.fromTo('scale', 1, SCALE_SMALL).fromTo('opacity', 0.99, 0));
}
}
}
PageTransition.register('wp-transition', WPTransition);

View File

@@ -1,8 +1,5 @@
import { Animation } from '../animations/animation';
import { closest } from '../util/dom';
import { Content } from '../components/content/content';
import { Tabs } from '../components/tabs/tabs';
import { ViewController } from '../components/nav/view-controller';
import { Animation, AnimationOptions } from '../animations/animation';
import { ViewController } from '../navigation/view-controller';
/**
@@ -21,15 +18,35 @@ import { ViewController } from '../components/nav/view-controller';
* - set inline TO styles - DOM WRITE
*/
export class Transition extends Animation {
_trnsStart: Function;
constructor(public enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) {
super(null, {
renderDelay: opts.renderDelay
});
parent: Transition;
hasChildTrns: boolean;
trnsId: number;
constructor(public enteringView: ViewController, public leavingView: ViewController, opts: AnimationOptions, raf?: Function) {
super(null, opts, raf);
}
static createTransition(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions): Transition {
let TransitionClass = TransitionRegistry[opts.animation];
init() {}
registerStart(trnsStart: Function) {
this._trnsStart = trnsStart;
}
start() {
this._trnsStart && this._trnsStart();
this._trnsStart = null;
}
destroy() {
super.destroy();
this.enteringView = this.leavingView = this._trnsStart = null;
}
static createTransition(transitionName: string, enteringView: ViewController, leavingView: ViewController, opts: AnimationOptions): Transition {
let TransitionClass: any = TransitionRegistry[transitionName];
if (!TransitionClass) {
// didn't find a transition animation, default to ios-transition
TransitionClass = TransitionRegistry['ios-transition'];
@@ -44,14 +61,4 @@ export class Transition extends Animation {
}
export interface TransitionOptions {
animation: string;
duration: number;
easing: string;
direction: string;
renderDelay?: number;
isRTL?: boolean;
ev?: any;
}
let TransitionRegistry: any = {};
let TransitionRegistry: {[key: string]: Transition} = {};