|
|
|
@@ -1,4 +1,4 @@
|
|
|
|
|
import {Compiler, ElementRef, Injector, provide, NgZone, AppViewManager, Renderer, ResolvedProvider, Type} from 'angular2/core';
|
|
|
|
|
import {Compiler, ElementRef, Injector, provide, NgZone, AppViewManager, Renderer, ResolvedProvider, Type, Input} from 'angular2/core';
|
|
|
|
|
import {wtfLeave, wtfCreateScope, WtfScopeFn, wtfStartTimeRange, wtfEndTimeRange} from 'angular2/instrumentation';
|
|
|
|
|
|
|
|
|
|
import {Config} from '../../config/config';
|
|
|
|
@@ -7,7 +7,7 @@ import {IonicApp} from '../app/app';
|
|
|
|
|
import {Keyboard} from '../../util/keyboard';
|
|
|
|
|
import {NavParams} from './nav-params';
|
|
|
|
|
import {NavRouter} from './nav-router';
|
|
|
|
|
import {pascalCaseToDashCase} from '../../util/util';
|
|
|
|
|
import {pascalCaseToDashCase, isTrueProperty} from '../../util/util';
|
|
|
|
|
import {raf} from '../../util/dom';
|
|
|
|
|
import {SwipeBackGesture} from './swipe-back';
|
|
|
|
|
import {Transition} from '../../transitions/transition';
|
|
|
|
@@ -106,11 +106,12 @@ import {ViewController} from './view-controller';
|
|
|
|
|
export class NavController extends Ion {
|
|
|
|
|
private _transIds = 0;
|
|
|
|
|
private _init = false;
|
|
|
|
|
private _lastTrans: Transition;
|
|
|
|
|
private _trans: Transition;
|
|
|
|
|
private _sbGesture: SwipeBackGesture;
|
|
|
|
|
private _sbEnabled: boolean;
|
|
|
|
|
private _sbThreshold: number;
|
|
|
|
|
|
|
|
|
|
protected _ids: number = -1;
|
|
|
|
|
protected _sbEnabled: any;
|
|
|
|
|
protected _sbThreshold: any;
|
|
|
|
|
protected _sbTrans: Transition = null;
|
|
|
|
|
protected _trnsDelay: any;
|
|
|
|
|
protected _trnsTime: number = 0;
|
|
|
|
|
protected _views: Array<ViewController> = [];
|
|
|
|
@@ -133,12 +134,7 @@ export class NavController extends Ion {
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
sbGesture: any;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
parent;
|
|
|
|
|
parent: any;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
@@ -164,7 +160,7 @@ export class NavController extends Ion {
|
|
|
|
|
|
|
|
|
|
this._trnsDelay = config.get('pageTransitionDelay');
|
|
|
|
|
|
|
|
|
|
this._sbEnabled = config.get('swipeBackEnabled') || false;
|
|
|
|
|
this._sbEnabled = config.getBoolean('swipeBackEnabled') || false;
|
|
|
|
|
this._sbThreshold = config.get('swipeBackThreshold') || 40;
|
|
|
|
|
|
|
|
|
|
this.id = ++ctrlIds;
|
|
|
|
@@ -261,7 +257,7 @@ export class NavController extends Ion {
|
|
|
|
|
*/
|
|
|
|
|
setPages(pages: Array<{page: Type, params?: any}>, opts: NavOptions = {}): Promise<any> {
|
|
|
|
|
if (!pages || !pages.length) {
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
return Promise.resolve(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deprecated warning
|
|
|
|
@@ -296,9 +292,9 @@ export class NavController extends Ion {
|
|
|
|
|
let promise = new Promise(res => { resolve = res; });
|
|
|
|
|
|
|
|
|
|
// start the transition, fire resolve when done...
|
|
|
|
|
this._transition(enteringView, leavingView, opts, () => {
|
|
|
|
|
this._transition(enteringView, leavingView, opts, (hasCompleted: boolean) => {
|
|
|
|
|
// transition has completed!!
|
|
|
|
|
resolve(enteringView);
|
|
|
|
|
resolve(hasCompleted);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
@@ -533,9 +529,9 @@ export class NavController extends Ion {
|
|
|
|
|
let leavingView = this.getByState(STATE_INIT_LEAVE);
|
|
|
|
|
|
|
|
|
|
// start the transition, fire resolve when done...
|
|
|
|
|
this._transition(enteringView, leavingView, opts, () => {
|
|
|
|
|
this._transition(enteringView, leavingView, opts, (hasCompleted: boolean) => {
|
|
|
|
|
// transition has completed!!
|
|
|
|
|
resolve(enteringView);
|
|
|
|
|
resolve(hasCompleted);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
@@ -697,21 +693,21 @@ export class NavController extends Ion {
|
|
|
|
|
opts.animation = forcedActive.getTransitionName(opts.direction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this._lastTrans) {
|
|
|
|
|
this._lastTrans
|
|
|
|
|
if (this._trans) {
|
|
|
|
|
this._trans
|
|
|
|
|
.onFinish(() => {
|
|
|
|
|
opts.animate = false;
|
|
|
|
|
this._transition(forcedActive, null, opts, () => {
|
|
|
|
|
this._transition(forcedActive, null, opts, (hasCompleted: boolean) => {
|
|
|
|
|
// transition has completed!!
|
|
|
|
|
resolve();
|
|
|
|
|
resolve(hasCompleted);
|
|
|
|
|
});
|
|
|
|
|
}, false, true)
|
|
|
|
|
.stop();
|
|
|
|
|
this._lastTrans.destroy();
|
|
|
|
|
this._lastTrans = null;
|
|
|
|
|
this._trans.destroy();
|
|
|
|
|
this._trans = null;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
resolve();
|
|
|
|
|
resolve(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
@@ -732,9 +728,9 @@ export class NavController extends Ion {
|
|
|
|
|
let enteringView = this.getByState(STATE_INIT_ENTER);
|
|
|
|
|
|
|
|
|
|
// start the transition, fire resolve when done...
|
|
|
|
|
this._transition(enteringView, leavingView, opts, () => {
|
|
|
|
|
this._transition(enteringView, leavingView, opts, (hasCompleted: boolean) => {
|
|
|
|
|
// transition has completed!!
|
|
|
|
|
resolve();
|
|
|
|
|
resolve(hasCompleted);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return promise;
|
|
|
|
@@ -744,7 +740,7 @@ export class NavController extends Ion {
|
|
|
|
|
// there's still an active view after _remove() figured out states
|
|
|
|
|
// so this means views that were only removed before the active
|
|
|
|
|
// view, so auto-resolve since no transition needs to happen
|
|
|
|
|
return Promise.resolve();
|
|
|
|
|
return Promise.resolve(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -856,8 +852,8 @@ export class NavController extends Ion {
|
|
|
|
|
|
|
|
|
|
if (enteringView === leavingView) {
|
|
|
|
|
// if the entering view and leaving view are the same thing don't continue
|
|
|
|
|
this._transComplete(transId, enteringView, leavingView, null);
|
|
|
|
|
return done(enteringView);
|
|
|
|
|
this._transFinish(transId, enteringView, leavingView, null, false);
|
|
|
|
|
return done(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// lets time this sucker, ready go
|
|
|
|
@@ -888,10 +884,10 @@ export class NavController extends Ion {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// begin the multiple async process of transitioning to the entering view
|
|
|
|
|
this._render(transId, enteringView, leavingView, opts, () => {
|
|
|
|
|
this._transComplete(transId, enteringView, leavingView, opts.direction);
|
|
|
|
|
this._render(transId, enteringView, leavingView, opts, (hasCompleted: boolean) => {
|
|
|
|
|
this._transFinish(transId, enteringView, leavingView, opts.direction, hasCompleted);
|
|
|
|
|
wtfEndTimeRange(wtfScope);
|
|
|
|
|
done(enteringView);
|
|
|
|
|
done(hasCompleted);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -985,19 +981,13 @@ export class NavController extends Ion {
|
|
|
|
|
enteringView.willEnter();
|
|
|
|
|
leavingView.willLeave();
|
|
|
|
|
|
|
|
|
|
// lifecycle events may have updated some data
|
|
|
|
|
// wait one frame and allow the raf to do a change detection
|
|
|
|
|
// before kicking off the transition and showing the new view
|
|
|
|
|
raf(() => {
|
|
|
|
|
this._beforeTrans(enteringView, leavingView, opts, done);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// this view is being preloaded, don't call lifecycle events
|
|
|
|
|
// transition does not need to animate
|
|
|
|
|
opts.animate = false;
|
|
|
|
|
this._beforeTrans(enteringView, leavingView, opts, done);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._beforeTrans(enteringView, leavingView, opts, done);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -1034,8 +1024,8 @@ export class NavController extends Ion {
|
|
|
|
|
leavingView,
|
|
|
|
|
transitionOpts);
|
|
|
|
|
|
|
|
|
|
this._lastTrans && this._lastTrans.destroy();
|
|
|
|
|
this._lastTrans = transAnimation;
|
|
|
|
|
this._trans && this._trans.destroy();
|
|
|
|
|
this._trans = transAnimation;
|
|
|
|
|
|
|
|
|
|
if (opts.animate === false) {
|
|
|
|
|
// force it to not animate the elements, just apply the "to" styles
|
|
|
|
@@ -1054,24 +1044,34 @@ export class NavController extends Ion {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create a callback for when the animation is done
|
|
|
|
|
transAnimation.onFinish(() => {
|
|
|
|
|
transAnimation.onFinish((hasCompleted: boolean) => {
|
|
|
|
|
// transition animation has ended
|
|
|
|
|
|
|
|
|
|
// dispose the animation and it's element references
|
|
|
|
|
// destroy the animation and it's element references
|
|
|
|
|
transAnimation.destroy();
|
|
|
|
|
|
|
|
|
|
this._afterTrans(enteringView, leavingView, opts, done);
|
|
|
|
|
this._afterTrans(enteringView, leavingView, opts, hasCompleted, done);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// cool, let's do this, start the transition
|
|
|
|
|
transAnimation.play();
|
|
|
|
|
if (opts.progressAnimation) {
|
|
|
|
|
// this is a swipe to go back, just get the transition progress ready
|
|
|
|
|
// kick off the swipe animation start
|
|
|
|
|
transAnimation.progressStart();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
// this is a normal animation
|
|
|
|
|
// kick it off and let it play through
|
|
|
|
|
transAnimation.play();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
private _afterTrans(enteringView: ViewController, leavingView: ViewController, opts: NavOptions, done: Function) {
|
|
|
|
|
private _afterTrans(enteringView: ViewController, leavingView: ViewController, opts: NavOptions, hasCompleted: boolean, done: Function) {
|
|
|
|
|
// transition has completed, update each view's state
|
|
|
|
|
// place back into the zone, run didEnter/didLeave
|
|
|
|
|
// call the final callback when done
|
|
|
|
@@ -1079,7 +1079,7 @@ export class NavController extends Ion {
|
|
|
|
|
// run inside of the zone again
|
|
|
|
|
this._zone.run(() => {
|
|
|
|
|
|
|
|
|
|
if (!opts.preload) {
|
|
|
|
|
if (!opts.preload && hasCompleted) {
|
|
|
|
|
enteringView.didEnter();
|
|
|
|
|
leavingView.didLeave();
|
|
|
|
|
}
|
|
|
|
@@ -1087,7 +1087,7 @@ export class NavController extends Ion {
|
|
|
|
|
if (enteringView.state === STATE_INACTIVE) {
|
|
|
|
|
// this entering view is already set to inactive, so this
|
|
|
|
|
// transition must be canceled, so don't continue
|
|
|
|
|
return done();
|
|
|
|
|
return done(hasCompleted);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts.keyboardClose !== false && this._keyboard.isOpen()) {
|
|
|
|
@@ -1097,12 +1097,12 @@ export class NavController extends Ion {
|
|
|
|
|
this._keyboard.onClose(() => {
|
|
|
|
|
|
|
|
|
|
// keyboard has finished closing, transition complete
|
|
|
|
|
done();
|
|
|
|
|
done(hasCompleted);
|
|
|
|
|
}, 32);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// all good, transition complete
|
|
|
|
|
done();
|
|
|
|
|
done(hasCompleted);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@@ -1110,51 +1110,67 @@ export class NavController extends Ion {
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
private _transComplete(transId: number, enteringView: ViewController, leavingView: ViewController, direction: string) {
|
|
|
|
|
private _transFinish(transId: number, enteringView: ViewController, leavingView: ViewController, direction: string, hasCompleted: boolean) {
|
|
|
|
|
// a transition has completed, but not sure if it's the last one or not
|
|
|
|
|
// check if this transition is the most recent one or not
|
|
|
|
|
|
|
|
|
|
if (transId === this._transIds) {
|
|
|
|
|
// ok, good news, there were no other transitions that kicked
|
|
|
|
|
// off during the time this transition started and ended
|
|
|
|
|
// so the entering one is now officially the active transition
|
|
|
|
|
// and the leaving transition is now just inactive
|
|
|
|
|
|
|
|
|
|
if (enteringView.state !== STATE_REMOVE_AFTER_TRANS) {
|
|
|
|
|
enteringView.state = STATE_ACTIVE;
|
|
|
|
|
}
|
|
|
|
|
if (hasCompleted) {
|
|
|
|
|
// this transition has completed as normal
|
|
|
|
|
// so the entering one is now the active view
|
|
|
|
|
// and the leaving view is now just inactive
|
|
|
|
|
if (enteringView.state !== STATE_REMOVE_AFTER_TRANS) {
|
|
|
|
|
enteringView.state = STATE_ACTIVE;
|
|
|
|
|
}
|
|
|
|
|
if (leavingView.state !== STATE_REMOVE_AFTER_TRANS) {
|
|
|
|
|
leavingView.state = STATE_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (leavingView.state !== STATE_REMOVE_AFTER_TRANS) {
|
|
|
|
|
leavingView.state = STATE_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
// only need to do all this clean up if the transition
|
|
|
|
|
// completed, otherwise nothing actually changed
|
|
|
|
|
// destroy all of the views that come after the active view
|
|
|
|
|
this._cleanup();
|
|
|
|
|
|
|
|
|
|
// destroy all of the views that come after the active view
|
|
|
|
|
this._cleanup();
|
|
|
|
|
// make sure only this entering view and PREVIOUS view are the
|
|
|
|
|
// only two views that are not display:none
|
|
|
|
|
leavingView = this.getPrevious(enteringView);
|
|
|
|
|
this._views.forEach(view => {
|
|
|
|
|
let shouldShow = (view === enteringView) || (view === leavingView);
|
|
|
|
|
view.domCache(shouldShow, this._renderer);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// make sure only this entering view and PREVIOUS view are the
|
|
|
|
|
// only two views that are not display:none
|
|
|
|
|
leavingView = this.getPrevious(enteringView);
|
|
|
|
|
this._views.forEach(view => {
|
|
|
|
|
let shouldShow = (view === enteringView) || (view === leavingView);
|
|
|
|
|
view.domCache(shouldShow, this._renderer);
|
|
|
|
|
});
|
|
|
|
|
// this check only needs to happen once, which will add the css
|
|
|
|
|
// class to the nav when it's finished its first transition
|
|
|
|
|
if (!this._init) {
|
|
|
|
|
this._init = true;
|
|
|
|
|
this._renderer.setElementClass(this.elementRef.nativeElement, 'has-views', true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this check only needs to happen once, which will add the css
|
|
|
|
|
// class to the nav when it's finished its first transition
|
|
|
|
|
if (!this._init) {
|
|
|
|
|
this._init = true;
|
|
|
|
|
this._renderer.setElementClass(this.elementRef.nativeElement, 'has-views', true);
|
|
|
|
|
} else {
|
|
|
|
|
// this transition has not completed, meaning the
|
|
|
|
|
// entering view did not end up as the active view
|
|
|
|
|
// this would happen when swipe to go back started
|
|
|
|
|
// but the user did not complete the swipe and the
|
|
|
|
|
// what was the active view stayed as the active view
|
|
|
|
|
leavingView.state = STATE_ACTIVE;
|
|
|
|
|
enteringView.state = STATE_INACTIVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// allow clicks and enable the app again
|
|
|
|
|
this._app && this._app.setEnabled(true);
|
|
|
|
|
this.setTransitioning(false);
|
|
|
|
|
|
|
|
|
|
if (this.router && direction !== null) {
|
|
|
|
|
if (this.router && direction !== null && hasCompleted) {
|
|
|
|
|
// notify router of the state change if a direction was provided
|
|
|
|
|
this.router.stateChange(direction, enteringView);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// see if we should add the swipe back gesture listeners or not
|
|
|
|
|
this._sbCheck();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// darn, so this wasn't the most recent transition
|
|
|
|
|
// so while this one did end, there's another more recent one
|
|
|
|
@@ -1189,6 +1205,7 @@ export class NavController extends Ion {
|
|
|
|
|
this._views.splice(this.indexOf(view), 1);
|
|
|
|
|
view.destroy();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -1269,156 +1286,100 @@ export class NavController extends Ion {
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
swipeBackStart() {
|
|
|
|
|
return;
|
|
|
|
|
if (!this._app.isEnabled() || !this.canSwipeBack()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// disables the app during the transition
|
|
|
|
|
this._app.setEnabled(false);
|
|
|
|
|
this.setTransitioning(true);
|
|
|
|
|
|
|
|
|
|
// default the direction to "back"
|
|
|
|
|
let opts = {
|
|
|
|
|
direction: 'back'
|
|
|
|
|
let opts: NavOptions = {
|
|
|
|
|
direction: 'back',
|
|
|
|
|
progressAnimation: true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 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();
|
|
|
|
|
leavingView.willLeave();
|
|
|
|
|
leavingView.willUnload();
|
|
|
|
|
// figure out the states of each view in the stack
|
|
|
|
|
let leavingView = this._remove(this._views.length - 1, 1);
|
|
|
|
|
|
|
|
|
|
// the entering view is now the new last view
|
|
|
|
|
let enteringView = this.getPrevious(leavingView);
|
|
|
|
|
enteringView.willEnter();
|
|
|
|
|
if (leavingView) {
|
|
|
|
|
opts.animation = leavingView.getTransitionName(opts.direction);
|
|
|
|
|
|
|
|
|
|
// wait for the new view to complete setup
|
|
|
|
|
this._render(0, enteringView, leavingView, {}, () => {
|
|
|
|
|
// get the view thats ready to enter
|
|
|
|
|
let enteringView = this.getByState(STATE_INIT_ENTER);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
// start the transition, fire callback when done...
|
|
|
|
|
this._transition(enteringView, leavingView, opts, (hasCompleted: boolean) => {
|
|
|
|
|
// swipe back has finished!!
|
|
|
|
|
console.debug('swipeBack, hasCompleted', hasCompleted);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
swipeBackProgress(value) {
|
|
|
|
|
return;
|
|
|
|
|
if (this._sbTrans) {
|
|
|
|
|
swipeBackProgress(stepValue: number) {
|
|
|
|
|
if (this._trans && this._sbGesture) {
|
|
|
|
|
// continue to disable the app while actively dragging
|
|
|
|
|
this._app.setEnabled(false, 4000);
|
|
|
|
|
this.setTransitioning(true, 4000);
|
|
|
|
|
|
|
|
|
|
// set the transition animation's progress
|
|
|
|
|
this._sbTrans.progressStep(value);
|
|
|
|
|
this._trans.progressStep(stepValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
swipeBackEnd(completeSwipeBack, rate) {
|
|
|
|
|
return;
|
|
|
|
|
if (!this._sbTrans) return;
|
|
|
|
|
|
|
|
|
|
// disables the app during the transition
|
|
|
|
|
this._app.setEnabled(false);
|
|
|
|
|
this.setTransitioning(true);
|
|
|
|
|
|
|
|
|
|
this._sbTrans.onFinish(() => {
|
|
|
|
|
this._zone.run(() => {
|
|
|
|
|
// find the views that were entering and leaving
|
|
|
|
|
let enteringView = null;// this._getStagedEntering();
|
|
|
|
|
let leavingView = null;//this._getStagedLeaving();
|
|
|
|
|
|
|
|
|
|
if (enteringView && leavingView) {
|
|
|
|
|
// finish up the animation
|
|
|
|
|
|
|
|
|
|
if (completeSwipeBack) {
|
|
|
|
|
// swipe back has completed navigating back
|
|
|
|
|
// update each view's state
|
|
|
|
|
enteringView.state = STATE_ACTIVE;
|
|
|
|
|
leavingView.state = STATE_INACTIVE;
|
|
|
|
|
|
|
|
|
|
enteringView.didEnter();
|
|
|
|
|
leavingView.didLeave();
|
|
|
|
|
|
|
|
|
|
if (this.router) {
|
|
|
|
|
// notify router of the pop state change
|
|
|
|
|
this.router.stateChange('pop', enteringView);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
// cancelled the swipe back, they didn't end up going back
|
|
|
|
|
// return views to their original state
|
|
|
|
|
leavingView.state = STATE_ACTIVE;
|
|
|
|
|
enteringView.state = STATE_INACTIVE;
|
|
|
|
|
|
|
|
|
|
leavingView.willEnter();
|
|
|
|
|
leavingView.didEnter();
|
|
|
|
|
enteringView.didLeave();
|
|
|
|
|
|
|
|
|
|
leavingView.shouldDestroy = false;
|
|
|
|
|
enteringView.shouldDestroy = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// empty out and dispose the swipe back transition animation
|
|
|
|
|
this._sbTrans && this._sbTrans.destroy();
|
|
|
|
|
this._sbTrans = null;
|
|
|
|
|
|
|
|
|
|
// all done!
|
|
|
|
|
//this._transComplete();
|
|
|
|
|
});
|
|
|
|
|
}, true);
|
|
|
|
|
|
|
|
|
|
this._sbTrans.progressEnd(completeSwipeBack, 0.5);
|
|
|
|
|
swipeBackEnd(shouldComplete: boolean, currentStepValue: number) {
|
|
|
|
|
if (this._trans && this._sbGesture) {
|
|
|
|
|
// the swipe back gesture has ended
|
|
|
|
|
this._trans.progressEnd(shouldComplete, currentStepValue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @private
|
|
|
|
|
*/
|
|
|
|
|
private _sbComplete() {
|
|
|
|
|
return;
|
|
|
|
|
if (this.canSwipeBack()) {
|
|
|
|
|
// it is possible to swipe back
|
|
|
|
|
private _sbCheck() {
|
|
|
|
|
if (this._sbEnabled) {
|
|
|
|
|
// this nav controller can have swipe to go back
|
|
|
|
|
|
|
|
|
|
if (this.sbGesture) {
|
|
|
|
|
// this is already an active gesture, don't create another one
|
|
|
|
|
return;
|
|
|
|
|
if (!this._sbGesture) {
|
|
|
|
|
// create the swipe back gesture if we haven't already
|
|
|
|
|
let opts = {
|
|
|
|
|
edge: 'left',
|
|
|
|
|
threshold: this._sbThreshold
|
|
|
|
|
};
|
|
|
|
|
this._sbGesture = new SwipeBackGesture(this.getNativeElement(), opts, this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let opts = {
|
|
|
|
|
edge: 'left',
|
|
|
|
|
threshold: this._sbThreshold
|
|
|
|
|
};
|
|
|
|
|
this.sbGesture = new SwipeBackGesture(this.getNativeElement(), opts, this);
|
|
|
|
|
console.debug('SwipeBackGesture listen');
|
|
|
|
|
this.sbGesture.listen();
|
|
|
|
|
if (this.canSwipeBack()) {
|
|
|
|
|
// it is be possible to swipe back
|
|
|
|
|
if (!this._sbGesture.isListening) {
|
|
|
|
|
this._zone.runOutsideAngular(() => {
|
|
|
|
|
// start listening if it's not already
|
|
|
|
|
console.debug('swipeBack gesture, listen');
|
|
|
|
|
this._sbGesture.listen();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (this.sbGesture) {
|
|
|
|
|
// it is not possible to swipe back and there is an
|
|
|
|
|
// active sbGesture, so unlisten it
|
|
|
|
|
console.debug('SwipeBackGesture unlisten');
|
|
|
|
|
this.sbGesture.unlisten();
|
|
|
|
|
this.sbGesture = null;
|
|
|
|
|
} else if (this._sbGesture.isListening) {
|
|
|
|
|
// it should not be possible to swipe back
|
|
|
|
|
// but the gesture is still listening
|
|
|
|
|
console.debug('swipeBack gesture, unlisten');
|
|
|
|
|
this._sbGesture.unlisten();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check to see if swipe-to-go-back is enabled
|
|
|
|
|
* @param {boolean} isSwipeBackEnabled Set whether or not swipe-to-go-back is enabled
|
|
|
|
|
* @returns {boolean} Whether swipe-to-go-back is enabled
|
|
|
|
|
* @input {boolean} Whether it's possible to swipe-to-go-back on this nav controller or not.
|
|
|
|
|
*/
|
|
|
|
|
isSwipeBackEnabled(val?: boolean): boolean {
|
|
|
|
|
if (arguments.length) {
|
|
|
|
|
this._sbEnabled = !!val;
|
|
|
|
|
}
|
|
|
|
|
@Input()
|
|
|
|
|
get swipeBackEnabled(): boolean {
|
|
|
|
|
return this._sbEnabled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set swipeBackEnabled(val: boolean) {
|
|
|
|
|
this._sbEnabled = isTrueProperty(val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* If it's possible to use swipe back or not. If it's not possible
|
|
|
|
|
* to go back, or swipe back is not enable then this will return false.
|
|
|
|
@@ -1427,7 +1388,7 @@ export class NavController extends Ion {
|
|
|
|
|
* @returns {boolean} Whether you can swipe to go back
|
|
|
|
|
*/
|
|
|
|
|
canSwipeBack(): boolean {
|
|
|
|
|
return (this._sbEnabled && this.canGoBack());
|
|
|
|
|
return (this._sbEnabled && !this.isTransitioning() && this._app.isEnabled() && this.canGoBack());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -1594,7 +1555,8 @@ export interface NavOptions {
|
|
|
|
|
keyboardClose?: boolean;
|
|
|
|
|
preload?: boolean;
|
|
|
|
|
transitionDelay?: number;
|
|
|
|
|
postLoad?: Function
|
|
|
|
|
postLoad?: Function;
|
|
|
|
|
progressAnimation?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const STATE_ACTIVE = 'active';
|
|
|
|
|