mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
refactor(NavController): improve transitions, view stages
This refactor made it so view transitions do no step on one another when a new transition happens during an active transition.
This commit is contained in:
@@ -554,7 +554,7 @@ export class Animation {
|
||||
/*
|
||||
STATIC CLASSES
|
||||
*/
|
||||
static create(element, name) {
|
||||
static create(name) {
|
||||
let AnimationClass = AnimationRegistry[name];
|
||||
|
||||
if (!AnimationClass) {
|
||||
@@ -562,7 +562,7 @@ export class Animation {
|
||||
// fallback to just the base Animation class
|
||||
AnimationClass = Animation;
|
||||
}
|
||||
return new AnimationClass(element);
|
||||
return new AnimationClass();
|
||||
}
|
||||
|
||||
static createTransition(enteringView: ViewController, leavingView: ViewController, opts: any = {}) {
|
||||
|
||||
@@ -16,8 +16,8 @@ class IOSTransition extends Animation {
|
||||
constructor(enteringView, leavingView, opts) {
|
||||
super(null, opts);
|
||||
|
||||
this.duration(DURATION);
|
||||
this.easing(EASING);
|
||||
this.duration(opts.duration || DURATION);
|
||||
this.easing(opts.easing || EASING);
|
||||
|
||||
// what direction is the transition going
|
||||
let backDirection = (opts.direction === 'back');
|
||||
|
||||
@@ -24,11 +24,11 @@ class MDTransition extends Animation {
|
||||
this.add(enteringPage);
|
||||
|
||||
if (backDirection) {
|
||||
this.duration(200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
enteringPage.fromTo(TRANSLATEY, CENTER, CENTER);
|
||||
|
||||
} else {
|
||||
this.duration(280).easing('cubic-bezier(0.36,0.66,0.04,1)');
|
||||
this.duration(opts.duration || 280).easing('cubic-bezier(0.36,0.66,0.04,1)');
|
||||
enteringPage
|
||||
.fromTo(TRANSLATEY, OFF_BOTTOM, CENTER)
|
||||
.fadeIn();
|
||||
@@ -51,7 +51,7 @@ class MDTransition extends Animation {
|
||||
// setup leaving view
|
||||
if (leavingView && backDirection) {
|
||||
// leaving content
|
||||
this.duration(200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
|
||||
let leavingPage = new Animation(leavingView.pageRef());
|
||||
this.add(leavingPage.fromTo(TRANSLATEY, CENTER, OFF_BOTTOM).fadeOut());
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export * from './components/modal/modal'
|
||||
export * from './components/nav/nav'
|
||||
export * from './components/nav/nav-controller'
|
||||
export * from './components/nav/view-controller'
|
||||
export * from './components/nav/nav-params'
|
||||
export * from './components/nav/nav-push'
|
||||
export * from './components/nav/nav-router'
|
||||
export * from './components/navbar/navbar'
|
||||
|
||||
@@ -315,7 +315,7 @@ class AlertCmp {
|
||||
|
||||
if (this.d.message) {
|
||||
this.descId = this.msgId;
|
||||
|
||||
|
||||
} else if (this.d.subTitle) {
|
||||
this.descId = this.subHdrId;
|
||||
}
|
||||
@@ -379,7 +379,7 @@ class AlertCmp {
|
||||
if (activeElement) {
|
||||
activeElement.blur();
|
||||
}
|
||||
|
||||
|
||||
if (this.d.inputs.length) {
|
||||
let firstInput = this._elementRef.nativeElement.querySelector('input');
|
||||
if (firstInput) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ import {
|
||||
Location} from 'angular2/router';
|
||||
|
||||
import {Nav} from './nav';
|
||||
import {ViewController} from './view-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -16,11 +17,11 @@ import {Nav} from './nav';
|
||||
})
|
||||
export class NavRouter extends RouterOutlet {
|
||||
private _activeViewId;
|
||||
|
||||
|
||||
constructor(
|
||||
_elementRef: ElementRef,
|
||||
_elementRef: ElementRef,
|
||||
_loader: DynamicComponentLoader,
|
||||
_parentRouter: Router,
|
||||
_parentRouter: Router,
|
||||
@Attribute('name') nameAttr: string,
|
||||
private _nav: Nav
|
||||
) {
|
||||
@@ -38,10 +39,10 @@ export class NavRouter extends RouterOutlet {
|
||||
* @param {ComponentInstruction} instruction TODO
|
||||
*/
|
||||
activate(nextInstruction: ComponentInstruction): Promise<any> {
|
||||
var previousInstruction = this._currentInstruction;
|
||||
this._currentInstruction = nextInstruction;
|
||||
var previousInstruction = this['_currentInstruction'];
|
||||
this['_currentInstruction'] = nextInstruction;
|
||||
var componentType = nextInstruction.componentType;
|
||||
var childRouter = this._parentRouter.childRouter(componentType);
|
||||
var childRouter = this['_parentRouter'].childRouter(componentType);
|
||||
|
||||
// prevent double navigations to the same view
|
||||
var lastView = this._nav.last();
|
||||
@@ -58,11 +59,11 @@ export class NavRouter extends RouterOutlet {
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} type TODO
|
||||
* @param {TODO} viewCtrl TODO
|
||||
* Called by Ionic after a transition has completed.
|
||||
* @param {string} direction The direction of the state change
|
||||
* @param {ViewController} viewCtrl The entering ViewController
|
||||
*/
|
||||
stateChange(type, viewCtrl) {
|
||||
stateChange(direction: string, viewCtrl: ViewController) {
|
||||
// stateChange is called by Ionic's NavController
|
||||
// type could be "push" or "pop"
|
||||
// viewCtrl is Ionic's ViewController class, which has the properties "componentType" and "params"
|
||||
@@ -79,9 +80,9 @@ export class NavRouter extends RouterOutlet {
|
||||
let componentInstruction = pathRecognizer.generate(viewCtrl.data);
|
||||
|
||||
// create a ResolvedInstruction from the componentInstruction
|
||||
let instruction = new ResolvedInstruction(componentInstruction, null);
|
||||
let instruction = new ResolvedInstruction(componentInstruction, null, null);
|
||||
|
||||
this._parentRouter.navigateByInstruction(instruction);
|
||||
this['_parentRouter'].navigateByInstruction(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +93,7 @@ export class NavRouter extends RouterOutlet {
|
||||
*/
|
||||
getPathRecognizerByComponent(componentType) {
|
||||
// given a componentType, figure out the best PathRecognizer to use
|
||||
let rules = this._parentRouter.registry._rules;
|
||||
let rules = this['_parentRouter'].registry._rules;
|
||||
|
||||
let pathRecognizer = null;
|
||||
rules.forEach((rule) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Component} from 'angular2/core';
|
||||
import {Component, Type} from 'angular2/core';
|
||||
import {App, NavController} from 'ionic/ionic';
|
||||
import {Page, Config, IonicApp} from 'ionic/ionic';
|
||||
import {NavParams, NavController, ViewController, IONIC_DIRECTIVES} from 'ionic/ionic';
|
||||
@@ -37,7 +37,7 @@ class MyCmpTest{}
|
||||
<ion-label>Text Input</ion-label>
|
||||
<textarea></textarea>
|
||||
</ion-input>
|
||||
|
||||
|
||||
<button ion-item [navPush]="[pushPage, {id: 42}]">Push FullPage w/ [navPush] array</button>
|
||||
<button ion-item [navPush]="pushPage" [navParams]="{id:40}">Push w/ [navPush] and [navParams]</button>
|
||||
<button ion-item [navPush]="[\'FirstPage\', {id: 22}]">Push w/ [navPush] array and string view name</button>
|
||||
@@ -45,6 +45,8 @@ class MyCmpTest{}
|
||||
<button ion-item (click)="setPages()">setPages() (Go to PrimaryHeaderPage)</button>
|
||||
<button ion-item (click)="setRoot()">setRoot(PrimaryHeaderPage) (Go to PrimaryHeaderPage)</button>
|
||||
<button ion-item (click)="nav.pop()">Pop</button>
|
||||
<button ion-item (click)="quickPush()">New push during transition</button>
|
||||
<button ion-item (click)="quickPop()">New pop during transition</button>
|
||||
<button ion-item (click)="reload()">Reload</button>
|
||||
|
||||
<button *ngFor="#i of pages" ion-item (click)="pushPrimaryHeaderPage()">Page {{i}}</button>
|
||||
@@ -54,17 +56,17 @@ class MyCmpTest{}
|
||||
directives: [MyCmpTest]
|
||||
})
|
||||
class FirstPage {
|
||||
pushPage;
|
||||
title = 'First Page';
|
||||
pages: Array<number> = [];
|
||||
|
||||
constructor(
|
||||
nav: NavController,
|
||||
private nav: NavController,
|
||||
app: IonicApp,
|
||||
config: Config
|
||||
) {
|
||||
this.nav = nav;
|
||||
this.title = 'First Page';
|
||||
|
||||
this.pushPage = FullPage;
|
||||
|
||||
this.pages = [];
|
||||
for (var i = 1; i <= 50; i++) {
|
||||
this.pages.push(i);
|
||||
}
|
||||
@@ -72,7 +74,7 @@ class FirstPage {
|
||||
|
||||
setPages() {
|
||||
let items = [
|
||||
PrimaryHeaderPage
|
||||
{page: PrimaryHeaderPage}
|
||||
];
|
||||
|
||||
this.nav.setPages(items);
|
||||
@@ -94,6 +96,20 @@ class FirstPage {
|
||||
this.nav.push(AnotherPage);
|
||||
}
|
||||
|
||||
quickPush() {
|
||||
this.nav.push(AnotherPage);
|
||||
setTimeout(() => {
|
||||
this.nav.push(PrimaryHeaderPage);
|
||||
}, 150);
|
||||
}
|
||||
|
||||
quickPop() {
|
||||
this.nav.push(AnotherPage);
|
||||
setTimeout(() => {
|
||||
this.nav.remove(1, 1);
|
||||
}, 250);
|
||||
}
|
||||
|
||||
reload() {
|
||||
window.location.reload();
|
||||
}
|
||||
@@ -116,17 +132,14 @@ class FirstPage {
|
||||
})
|
||||
class FullPage {
|
||||
constructor(
|
||||
nav: NavController,
|
||||
params: NavParams
|
||||
) {
|
||||
this.nav = nav;
|
||||
this.params = params;
|
||||
}
|
||||
private nav: NavController,
|
||||
private params: NavParams
|
||||
) {}
|
||||
|
||||
setPages() {
|
||||
let items = [
|
||||
FirstPage,
|
||||
PrimaryHeaderPage
|
||||
{page: FirstPage},
|
||||
{page: PrimaryHeaderPage}
|
||||
];
|
||||
|
||||
this.nav.setPages(items);
|
||||
@@ -157,6 +170,7 @@ class FullPage {
|
||||
<p><button (click)="pushAnother()">Push to AnotherPage</button></p>
|
||||
<p><button (click)="pushFullPage()">Push to FullPage</button></p>
|
||||
<p><button (click)="setRoot()">setRoot(AnotherPage)</button></p>
|
||||
<p><button (click)="nav.popToRoot()">Pop to root</button></p>
|
||||
<p><button id="insert" (click)="insert()">Insert first page into history before this</button></p>
|
||||
<p><button id="remove" (click)="removeSecond()">Remove second page in history</button></p>
|
||||
<div class="yellow"><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f><f></f></div>
|
||||
@@ -165,12 +179,9 @@ class FullPage {
|
||||
})
|
||||
class PrimaryHeaderPage {
|
||||
constructor(
|
||||
nav: NavController,
|
||||
viewCtrl: ViewController
|
||||
) {
|
||||
this.nav = nav;
|
||||
this.viewCtrl = viewCtrl;
|
||||
}
|
||||
private nav: NavController,
|
||||
private viewCtrl: ViewController
|
||||
) {}
|
||||
|
||||
onPageWillEnter() {
|
||||
this.viewCtrl.setBackButtonText('Previous');
|
||||
@@ -225,15 +236,13 @@ class PrimaryHeaderPage {
|
||||
`
|
||||
})
|
||||
class AnotherPage {
|
||||
bbHideToggleVal = false;
|
||||
bbCount = 0;
|
||||
|
||||
constructor(
|
||||
nav: NavController,
|
||||
viewCtrl: ViewController
|
||||
) {
|
||||
this.nav = nav;
|
||||
this.viewCtrl = viewCtrl;
|
||||
this.bbHideToggleVal = false;
|
||||
this._bbCount = 0;
|
||||
}
|
||||
private nav: NavController,
|
||||
private viewCtrl: ViewController
|
||||
) {}
|
||||
|
||||
pushFullPage() {
|
||||
this.nav.push(FullPage);
|
||||
@@ -259,12 +268,12 @@ class AnotherPage {
|
||||
setBackButtonText() {
|
||||
let backButtonText = 'Messages';
|
||||
|
||||
if (this._bbCount > 0) {
|
||||
backButtonText += ` (${this._bbCount})`;
|
||||
if (this.bbCount > 0) {
|
||||
backButtonText += ` (${this.bbCount})`;
|
||||
}
|
||||
|
||||
this.viewCtrl.setBackButtonText(backButtonText);
|
||||
++this._bbCount;
|
||||
++this.bbCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,6 +286,8 @@ class AnotherPage {
|
||||
}
|
||||
})
|
||||
class E2EApp {
|
||||
root;
|
||||
|
||||
constructor() {
|
||||
this.root = FirstPage;
|
||||
}
|
||||
|
||||
@@ -1,301 +1,268 @@
|
||||
import {
|
||||
NavController,
|
||||
Config,
|
||||
Page,
|
||||
ViewController
|
||||
} from 'ionic/ionic';
|
||||
|
||||
import {NavController, Config, ViewController} from 'ionic/ionic';
|
||||
|
||||
export function run() {
|
||||
describe("NavController", () => {
|
||||
let nav;
|
||||
describe('NavController', () => {
|
||||
|
||||
class FirstPage {}
|
||||
class SecondPage {}
|
||||
class ThirdPage {}
|
||||
describe('popToRoot', () => {
|
||||
|
||||
function mockTransitionFn(enteringView, leavingView, opts, cb) {
|
||||
let destroys = [];
|
||||
it('should go back to root', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INACTIVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INACTIVE;
|
||||
let view4 = new ViewController(Page4);
|
||||
view4.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2, view3, view4];
|
||||
|
||||
nav._views.forEach(view => {
|
||||
if (view) {
|
||||
if (view.shouldDestroy) {
|
||||
destroys.push(view);
|
||||
nav.popToRoot();
|
||||
expect(nav.length()).toBe(2);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page4);
|
||||
|
||||
} else if (view.state === 2 && view.shouldCache) {
|
||||
view.shouldCache = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
destroys.forEach(view => {
|
||||
nav._remove(view);
|
||||
view.destroy();
|
||||
});
|
||||
cb();
|
||||
}
|
||||
|
||||
function mockCanGoBackFn() {
|
||||
return true;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
nav = new NavController(null, null, new Config(), null, null, null, null, null, null, null);
|
||||
nav._renderer = {
|
||||
setElementAttribute: function(){},
|
||||
setElementStyle: function(){}
|
||||
};
|
||||
});
|
||||
|
||||
it('should exist', () => {
|
||||
expect(nav).not.toBeUndefined();
|
||||
});
|
||||
|
||||
describe("getActive", () => {
|
||||
it('should return null if there is no active view', () => {
|
||||
var active = nav.getActive();
|
||||
expect(active).toBe(null);
|
||||
});
|
||||
|
||||
it('should return the last active page', () => {
|
||||
let activeView = new ViewController();
|
||||
activeView.state = 1; // ACTIVE_STATE
|
||||
nav._add(activeView);
|
||||
|
||||
expect(nav.getActive()).toBe(activeView);
|
||||
|
||||
let secondActiveView = new ViewController();
|
||||
secondActiveView.state = 1; // ACTIVE_STATE
|
||||
nav._add(secondActiveView);
|
||||
|
||||
expect(nav.getActive()).toBe(secondActiveView);
|
||||
});
|
||||
|
||||
it('should return the last active page thats not shouldDestroy', () => {
|
||||
let view1 = new ViewController();
|
||||
view1.state = 1; // ACTIVE_STATE
|
||||
nav._add(view1);
|
||||
expect(nav.getActive()).toBe(view1);
|
||||
|
||||
let view2 = new ViewController();
|
||||
view2.state = 1; // ACTIVE_STATE
|
||||
view2.shouldDestroy = true;
|
||||
nav._add(view2);
|
||||
expect(nav.getActive()).toBe(view1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("push", () => {
|
||||
it('should return a rejected Promise if page is falsy', done => {
|
||||
let s = jasmine.createSpy('success');
|
||||
let f = jasmine.createSpy('fail');
|
||||
|
||||
let promise = nav.push(undefined, {}, {});
|
||||
|
||||
promise.then(s, f).then(() => {
|
||||
expect(s).not.toHaveBeenCalled();
|
||||
expect(f).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error if page truthy, but is not a function', () => {
|
||||
let push = () => nav.push({}, {}, {});
|
||||
expect(push).toThrow();
|
||||
|
||||
push = () => nav.push("string", {}, {});
|
||||
expect(push).toThrow();
|
||||
|
||||
push = () => nav.push(42, {}, {});
|
||||
expect(push).toThrow();
|
||||
|
||||
push = () => nav.push(true, {}, {});
|
||||
expect(push).toThrow();
|
||||
});
|
||||
|
||||
it('to add the pushed page to the nav stack', (done) => {
|
||||
expect(FirstPage).toBeDefined();
|
||||
expect(nav._views.length).toBe(0);
|
||||
|
||||
spyOn(nav, '_add').and.callThrough();
|
||||
|
||||
nav._transition = mockTransitionFn;
|
||||
nav.push(FirstPage, {}, {}).then(() => {
|
||||
expect(nav._add).toHaveBeenCalled();
|
||||
expect(nav._views.length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("setPages", () => {
|
||||
it('should return a resolved Promise if components is falsy', done => {
|
||||
let s = jasmine.createSpy('success');
|
||||
let f = jasmine.createSpy('fail');
|
||||
|
||||
let promise = nav.setPages();
|
||||
|
||||
promise.then(s, f).then(() => {
|
||||
expect(s).toHaveBeenCalled();
|
||||
expect(f).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('replace views with the supplied views', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(),
|
||||
vc3 = new ViewController();
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
let arr = [{page: FirstPage}, {page:SecondPage}, {page:ThirdPage}];
|
||||
|
||||
nav._transition = mockTransitionFn;
|
||||
nav.setPages(arr);
|
||||
|
||||
//_views[0] will be transitioned out of
|
||||
expect(nav._views[1].componentType).toBe(FirstPage);
|
||||
expect(nav._views[2].componentType).toBe(SecondPage);
|
||||
expect(nav._views[3].componentType).toBe(ThirdPage);
|
||||
expect(view2.state).toBe(STATE_REMOVE);
|
||||
expect(view3.state).toBe(STATE_REMOVE);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("insert", () => {
|
||||
it('insert page at the specified index', () => {
|
||||
let view1 = new ViewController();
|
||||
view1._loaded = true;
|
||||
let view2 = new ViewController();
|
||||
view2._loaded = true;
|
||||
let view3 = new ViewController();
|
||||
view3._loaded = true;
|
||||
describe('popTo', () => {
|
||||
|
||||
it('should go back two views', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INACTIVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INACTIVE;
|
||||
let view4 = new ViewController(Page4);
|
||||
view4.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2, view3, view4];
|
||||
|
||||
nav.popTo(view2);
|
||||
|
||||
expect(nav.length()).toBe(3);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(view3.state).toBe(STATE_REMOVE);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page4);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('_remove', () => {
|
||||
|
||||
it('should reassign activily transitioning leave that isnt getting removed, to become force active', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_TRANS_LEAVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_TRANS_ENTER;
|
||||
nav._views = [view1, view2, view3];
|
||||
expect(nav._views[2].componentType).toBeUndefined();
|
||||
nav.insert(2, FirstPage);
|
||||
expect(nav._views[2].componentType).toBe(FirstPage);
|
||||
|
||||
nav._remove(2, 1);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_FORCE_ACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_REMOVE_AFTER_TRANS);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('push page if index >= _views.length', () => {
|
||||
let view1 = new ViewController();
|
||||
view1._loaded = true;
|
||||
let view2 = new ViewController();
|
||||
view2._loaded = true;
|
||||
let view3 = new ViewController();
|
||||
view3._loaded = true;
|
||||
|
||||
it('should reassign activily transitioning views that should be removed to STATE_REMOVE_AFTER_TRANS', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_TRANS_ENTER;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_TRANS_LEAVE;
|
||||
nav._views = [view1, view2, view3];
|
||||
spyOn(nav, 'push').and.callThrough();
|
||||
nav.insert(2, FirstPage);
|
||||
expect(nav.push).not.toHaveBeenCalled();
|
||||
|
||||
nav._transition = mockTransitionFn;
|
||||
nav.insert(4, FirstPage);
|
||||
expect(nav._views[4].componentType).toBe(FirstPage);
|
||||
expect(nav.push).toHaveBeenCalled();
|
||||
|
||||
nav.setTransitioning(false);
|
||||
|
||||
nav.insert(10, FirstPage);
|
||||
expect(nav._views[5].componentType).toBe(FirstPage);
|
||||
nav._remove(1, 2);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_REMOVE_AFTER_TRANS);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_REMOVE_AFTER_TRANS);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('another insert happened before last insert rendered, abort previous insert enter', () => {
|
||||
let view1 = new ViewController();
|
||||
view1._loaded = true;
|
||||
view1.state = NavController.STATE_ABORT;
|
||||
let view2 = new ViewController();
|
||||
view2._loaded = true;
|
||||
it('should keep same init leave, but set previous init enter to inactive', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INIT_ENTER;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INIT_LEAVE;
|
||||
nav._views = [view1, view2, view3];
|
||||
|
||||
nav._remove(1, 1);
|
||||
expect(nav.length()).toBe(2);
|
||||
expect(view1.state).toBe(STATE_INIT_ENTER);
|
||||
expect(view2.state).toBe(STATE_REMOVE);
|
||||
expect(view3.state).toBe(STATE_INIT_LEAVE);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('should set to pop the active and enter the previous', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
nav._remove(1, 1);
|
||||
expect(view1.state).toBe(STATE_INIT_ENTER);
|
||||
expect(view2.state).toBe(STATE_INIT_LEAVE);
|
||||
});
|
||||
|
||||
});
|
||||
it('should set to remove 2 views before active one, active stays the same', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INACTIVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INACTIVE;
|
||||
let view4 = new ViewController(Page4);
|
||||
view4.state = STATE_INACTIVE;
|
||||
let view5 = new ViewController(Page5);
|
||||
view5.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2, view3, view4, view5];
|
||||
|
||||
describe("setRoot", () => {
|
||||
it('remove previous views and set root', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(),
|
||||
vc3 = new ViewController();
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
expect(nav._views.length).toBe(3);
|
||||
nav._remove(2, 2);
|
||||
expect(nav.length()).toBe(3);
|
||||
expect(view1.state).toBe(STATE_INACTIVE);
|
||||
expect(view2.state).toBe(STATE_INACTIVE);
|
||||
expect(view3.state).toBe(STATE_REMOVE);
|
||||
expect(view4.state).toBe(STATE_REMOVE);
|
||||
expect(view5.state).toBe(STATE_ACTIVE);
|
||||
|
||||
nav._transition = mockTransitionFn;
|
||||
nav.setRoot(FirstPage);
|
||||
//_views[0] will be transitioned out of
|
||||
expect(nav._views.length).toBe(2);
|
||||
expect(nav._views[1].componentType).toBe(FirstPage);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_ACTIVE);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page5);
|
||||
});
|
||||
|
||||
it('should set to remove all views other than the first', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INACTIVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INACTIVE;
|
||||
let view4 = new ViewController(Page4);
|
||||
view4.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2, view3, view4];
|
||||
|
||||
nav._remove(1, 9999);
|
||||
expect(nav.length()).toBe(2);
|
||||
expect(view1.state).toBe(STATE_INIT_ENTER);
|
||||
expect(view2.state).toBe(STATE_REMOVE);
|
||||
expect(view3.state).toBe(STATE_REMOVE);
|
||||
expect(view4.state).toBe(STATE_INIT_LEAVE);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page4);
|
||||
});
|
||||
|
||||
it('should set to remove 3 views and enter the first inactive one, remove includes active one', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INACTIVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INACTIVE;
|
||||
let view4 = new ViewController(Page4);
|
||||
view4.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2, view3, view4];
|
||||
|
||||
nav._remove(1, 3);
|
||||
expect(nav.length()).toBe(2);
|
||||
expect(view1.state).toBe(STATE_INIT_ENTER);
|
||||
expect(view2.state).toBe(STATE_REMOVE);
|
||||
expect(view3.state).toBe(STATE_REMOVE);
|
||||
expect(view4.state).toBe(STATE_INIT_LEAVE);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page4);
|
||||
});
|
||||
|
||||
it('should set to remove the active and enter the previous', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
nav._remove(1, 1);
|
||||
expect(view1.state).toBe(STATE_INIT_ENTER);
|
||||
expect(view2.state).toBe(STATE_INIT_LEAVE);
|
||||
});
|
||||
|
||||
it('should set to remove the only view in the stack', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_ACTIVE;
|
||||
nav._views = [view1];
|
||||
|
||||
nav._remove(0, 1);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
});
|
||||
});
|
||||
|
||||
describe("first", () => {
|
||||
it('should get the first item', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(FirstPage),
|
||||
vc3 = new ViewController(SecondPage);
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
describe('_cleanup', () => {
|
||||
it('should destroy views that are inactive after the active view', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_ACTIVE;
|
||||
let view3 = new ViewController(Page3);
|
||||
view3.state = STATE_INACTIVE;
|
||||
let view4 = new ViewController(Page4);
|
||||
view4.state = STATE_TRANS_ENTER;
|
||||
let view5 = new ViewController(Page5);
|
||||
view5.state = STATE_INACTIVE;
|
||||
nav._views = [view1, view2, view3, view4, view5];
|
||||
nav._cleanup();
|
||||
|
||||
expect(nav.first()).toBe(vc1);
|
||||
expect(nav.length()).toBe(3);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_ACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_TRANS_ENTER);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page4);
|
||||
});
|
||||
it('should get the first item that isnt being destroyed', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(),
|
||||
vc3 = new ViewController();
|
||||
vc1.shouldDestroy = true;
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
|
||||
expect(nav.first()).toBe(vc2);
|
||||
it('should not destroy any views since the last is active', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2];
|
||||
nav._cleanup();
|
||||
expect(nav.length()).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("popTo", () => {
|
||||
it('should popTo 1st view', () => {
|
||||
let vc1 = new ViewController(FirstPage),
|
||||
vc2 = new ViewController(SecondPage),
|
||||
vc3 = new ViewController(ThirdPage);
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
|
||||
nav._transition = mockTransitionFn;
|
||||
nav.popTo(vc1);
|
||||
|
||||
expect(nav._views.length).toBe(1);
|
||||
expect(nav._views[0].componentType).toBe(FirstPage);
|
||||
});
|
||||
});
|
||||
|
||||
describe("remove", () => {
|
||||
it('should remove the view at the specified index', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(FirstPage),
|
||||
vc3 = new ViewController(SecondPage);
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
expect(nav._views.length).toBe(3);
|
||||
expect(nav._views[1].componentType).toBe(FirstPage);
|
||||
|
||||
nav.remove(1);
|
||||
|
||||
expect(nav._views.length).toBe(2);
|
||||
expect(nav._views[1].componentType).toBe(SecondPage);
|
||||
});
|
||||
|
||||
it('should pop if index is of active view', () => {
|
||||
let vc1 = new ViewController(),
|
||||
vc2 = new ViewController(FirstPage),
|
||||
vc3 = new ViewController(SecondPage);
|
||||
|
||||
vc3.state = 1; //ACTIVE_STATE
|
||||
nav._views = [vc1, vc2, vc3];
|
||||
|
||||
spyOn(nav, 'pop').and.callThrough();
|
||||
|
||||
nav.remove(1);
|
||||
expect(nav.pop).not.toHaveBeenCalled();
|
||||
|
||||
nav.remove(1);
|
||||
expect(nav.pop).toHaveBeenCalled();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe("_setZIndex", () => {
|
||||
describe('_setZIndex', () => {
|
||||
it('should set zIndex 10 on first entering view', () => {
|
||||
let enteringView = new ViewController();
|
||||
enteringView.setPageRef({});
|
||||
@@ -324,5 +291,360 @@ export function run() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('_transComplete', () => {
|
||||
|
||||
it('should not entering/leaving state, after transition that isnt the most recent, and state already changed', () => {
|
||||
let enteringView = new ViewController(Page1);
|
||||
enteringView.state = 'somethingelse';
|
||||
let leavingView = new ViewController(Page2);
|
||||
leavingView.state = 'somethingelse';
|
||||
|
||||
nav._transIds = 2;
|
||||
|
||||
nav._transComplete(1, enteringView, leavingView);
|
||||
|
||||
expect(enteringView.state).toBe('somethingelse');
|
||||
expect(leavingView.state).toBe('somethingelse');
|
||||
});
|
||||
|
||||
it('should set entering/leaving to inactive, after transition that isnt the most recent', () => {
|
||||
let enteringView = new ViewController(Page1);
|
||||
enteringView.state = STATE_TRANS_ENTER;
|
||||
let leavingView = new ViewController(Page2);
|
||||
leavingView.state = STATE_TRANS_LEAVE;
|
||||
|
||||
nav._transIds = 2;
|
||||
|
||||
nav._transComplete(1, enteringView, leavingView);
|
||||
|
||||
expect(enteringView.state).toBe(STATE_INACTIVE);
|
||||
expect(leavingView.state).toBe(STATE_INACTIVE);
|
||||
});
|
||||
|
||||
it('should set entering active, leaving inactive, after transition', () => {
|
||||
let enteringView = new ViewController(Page1);
|
||||
enteringView.state = STATE_TRANS_ENTER;
|
||||
let leavingView = new ViewController(Page2);
|
||||
leavingView.state = STATE_TRANS_LEAVE;
|
||||
|
||||
nav._transIds = 1;
|
||||
|
||||
nav._transComplete(1, enteringView, leavingView);
|
||||
|
||||
expect(enteringView.state).toBe(STATE_ACTIVE);
|
||||
expect(leavingView.state).toBe(STATE_INACTIVE);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('_insert', () => {
|
||||
|
||||
it('should push page when previous transition is still actively transitioning', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_TRANS_ENTER;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_TRANS_LEAVE;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
let view3 = new ViewController(Page3);
|
||||
nav._insert(-1, [view3]);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_TRANS_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_TRANS_LEAVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('should push page when previous transition views init, but havent transitioned yet', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INIT_LEAVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INIT_ENTER;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
let view3 = new ViewController(Page3);
|
||||
nav._insert(-1, [view3]);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('should insert multiple pages, back to back, with a starting active page', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_ACTIVE;
|
||||
nav._views = [view1];
|
||||
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._insert(-1, [view2]);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
|
||||
let view3 = new ViewController(Page3);
|
||||
nav._insert(-1, [view3]);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('should insert multiple pages, back to back, no starting active page', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
nav._insert(-1, [view1]);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._insert(-1, [view2]);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
|
||||
let view3 = new ViewController(Page3);
|
||||
nav._insert(1, [view3]);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page3);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page2);
|
||||
});
|
||||
|
||||
it('should push a page, and abort previous init', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INIT_LEAVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INIT_ENTER;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
let view3 = new ViewController(Page3);
|
||||
nav._insert(-1, [view3]);
|
||||
expect(nav.length()).toBe(3);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
});
|
||||
|
||||
it('should insert a page between the first and second', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INACTIVE;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_ACTIVE;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
let view3 = new ViewController(Page3);
|
||||
nav._insert(1, [view3]);
|
||||
expect(nav.length()).toBe(3);
|
||||
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page3);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page2);
|
||||
});
|
||||
|
||||
it('should insert a page before the first', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_ACTIVE;
|
||||
nav._views = [view1];
|
||||
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._insert(0, [view2]);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page1);
|
||||
});
|
||||
|
||||
it('should insert 3 pages', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_ACTIVE;
|
||||
nav._views = [view1];
|
||||
|
||||
let insertViews = [
|
||||
new ViewController(Page2),
|
||||
new ViewController(Page3),
|
||||
new ViewController(Page4)
|
||||
];
|
||||
nav._insert(-1, insertViews);
|
||||
expect(nav.length()).toBe(4);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
expect(nav.getByIndex(2).state).toBe(STATE_INACTIVE);
|
||||
expect(nav.getByIndex(2).componentType).toBe(Page3);
|
||||
expect(nav.getByIndex(3).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(3).componentType).toBe(Page4);
|
||||
});
|
||||
|
||||
it('should push the second page', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_ACTIVE;
|
||||
nav._views = [view1];
|
||||
|
||||
let view2 = new ViewController(Page2)
|
||||
nav._insert(-1, [view2]);
|
||||
expect(nav.length()).toBe(2);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_LEAVE);
|
||||
expect(nav.getByIndex(0).componentType).toBe(Page1);
|
||||
expect(nav.getByIndex(1).state).toBe(STATE_INIT_ENTER);
|
||||
expect(nav.getByIndex(1).componentType).toBe(Page2);
|
||||
});
|
||||
|
||||
it('should push the first page, using a number greater than the length', () => {
|
||||
let view1 = new ViewController(Page1)
|
||||
nav._insert(8675309, [view1]);
|
||||
|
||||
expect(nav.length()).toBe(1);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
});
|
||||
|
||||
it('should push the first page, using -1', () => {
|
||||
let view1 = new ViewController(Page1)
|
||||
nav._insert(-1, [view1]);
|
||||
|
||||
expect(nav.getByIndex(0).id).toBeDefined();
|
||||
expect(nav.length()).toBe(1);
|
||||
expect(nav.getByIndex(0).state).toBe(STATE_INIT_ENTER);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('should getActive()', () => {
|
||||
expect(nav.getActive()).toBe(null);
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INIT_ENTER;
|
||||
nav._views = [view1];
|
||||
expect(nav.getActive()).toBe(null);
|
||||
view1.state = STATE_ACTIVE;
|
||||
expect(nav.getActive()).toBe(view1);
|
||||
});
|
||||
|
||||
it('should getByState()', () => {
|
||||
expect(nav.getByState()).toBe(null);
|
||||
|
||||
let view1 = new ViewController(Page1);
|
||||
view1.state = STATE_INIT_ENTER;
|
||||
let view2 = new ViewController(Page2);
|
||||
view2.state = STATE_INIT_ENTER;
|
||||
nav._views = [view1, view2];
|
||||
|
||||
expect(nav.getByState('whatever')).toBe(null);
|
||||
expect(nav.getByState(STATE_INIT_ENTER)).toBe(view2);
|
||||
|
||||
view2.state = STATE_INACTIVE;
|
||||
expect(nav.getByState(STATE_INIT_ENTER)).toBe(view1);
|
||||
|
||||
view2.state = STATE_ACTIVE;
|
||||
expect(nav.getActive()).toBe(view2);
|
||||
});
|
||||
|
||||
it('should getPrevious()', () => {
|
||||
expect(nav.getPrevious(null)).toBe(null);
|
||||
|
||||
let view1 = new ViewController(Page1);
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._views = [view1, view2];
|
||||
|
||||
expect(nav.getPrevious(view1)).toBe(null);
|
||||
expect(nav.getPrevious(view2)).toBe(view1);
|
||||
});
|
||||
|
||||
it('should get first()', () => {
|
||||
expect(nav.first()).toBe(null);
|
||||
let view1 = new ViewController(Page1);
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._views = [view1];
|
||||
expect(nav.first()).toBe(view1);
|
||||
nav._views = [view1, view2];
|
||||
expect(nav.first()).toBe(view1);
|
||||
});
|
||||
|
||||
it('should get last()', () => {
|
||||
expect(nav.last()).toBe(null);
|
||||
let view1 = new ViewController(Page1);
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._views = [view1];
|
||||
expect(nav.last()).toBe(view1);
|
||||
nav._views = [view1, view2];
|
||||
expect(nav.last()).toBe(view2);
|
||||
});
|
||||
|
||||
it('should get indexOf()', () => {
|
||||
let view1 = new ViewController(Page1);
|
||||
let view2 = new ViewController(Page2);
|
||||
|
||||
expect(nav.length()).toBe(0);
|
||||
expect(nav.indexOf(view1)).toBe(-1);
|
||||
|
||||
nav._views = [view1, view2];
|
||||
expect(nav.indexOf(view1)).toBe(0);
|
||||
expect(nav.indexOf(view2)).toBe(1);
|
||||
expect(nav.length()).toBe(2);
|
||||
});
|
||||
|
||||
it('should get getByIndex()', () => {
|
||||
expect(nav.getByIndex(-99)).toBe(null);
|
||||
expect(nav.getByIndex(99)).toBe(null);
|
||||
|
||||
let view1 = new ViewController(Page1);
|
||||
let view2 = new ViewController(Page2);
|
||||
nav._views = [view1, view2];
|
||||
|
||||
expect(nav.getByIndex(-1)).toBe(null);
|
||||
expect(nav.getByIndex(0)).toBe(view1);
|
||||
expect(nav.getByIndex(1)).toBe(view2);
|
||||
expect(nav.getByIndex(2)).toBe(null);
|
||||
});
|
||||
|
||||
// setup stuff
|
||||
let nav;
|
||||
let config = new Config();
|
||||
|
||||
class Page1 {}
|
||||
class Page2 {}
|
||||
class Page3 {}
|
||||
class Page4 {}
|
||||
class Page5 {}
|
||||
|
||||
beforeEach(() => {
|
||||
nav = new NavController(null, null, config, null, null, null, null, null, null, null);
|
||||
nav._renderer = {
|
||||
setElementAttribute: function(){},
|
||||
setElementClass: function(){},
|
||||
setElementStyle: function(){}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
const STATE_ACTIVE = 'active';
|
||||
const STATE_INACTIVE = 'inactive';
|
||||
const STATE_INIT_ENTER = 'init_enter';
|
||||
const STATE_INIT_LEAVE = 'init_leave';
|
||||
const STATE_TRANS_ENTER = 'trans_enter';
|
||||
const STATE_TRANS_LEAVE = 'trans_leave';
|
||||
const STATE_REMOVE = 'remove';
|
||||
const STATE_REMOVE_AFTER_TRANS = 'remove_after_trans';
|
||||
const STATE_FORCE_ACTIVE = 'force_active';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Output, EventEmitter, Type, TemplateRef, ViewContainerRef, ElementRef} from 'angular2/core';
|
||||
import {Output, EventEmitter, Type, TemplateRef, ViewContainerRef, ElementRef, Renderer} from 'angular2/core';
|
||||
|
||||
import {Navbar} from '../navbar/navbar';
|
||||
import {NavController} from './nav-controller';
|
||||
@@ -21,26 +21,26 @@ import {NavParams} from './nav-params';
|
||||
* ```
|
||||
*/
|
||||
export class ViewController {
|
||||
private _cntDir: any;
|
||||
private _cntDir;
|
||||
private _cntRef: ElementRef;
|
||||
private _destroys: Array<Function> = [];
|
||||
private _hdAttr = null;
|
||||
private _leavingOpts = null;
|
||||
private _loaded: boolean = false;
|
||||
private _leavingOpts: any = null;
|
||||
private _nbDir: Navbar;
|
||||
private _nbTmpRef: TemplateRef;
|
||||
private _nbVwRef: ViewContainerRef;
|
||||
private _onDismiss: Function = null;
|
||||
private _pgRef: ElementRef;
|
||||
protected _nav: NavController;
|
||||
|
||||
|
||||
id: string;
|
||||
instance: any = {};
|
||||
state: number = 0;
|
||||
shouldDestroy: boolean = false;
|
||||
shouldCache: boolean = false;
|
||||
state: string = '';
|
||||
viewType: string = '';
|
||||
onReady: any;
|
||||
|
||||
zIndex: number;
|
||||
|
||||
@Output() private _emitter: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
constructor(public componentType?: Type, public data: any = {}) {}
|
||||
@@ -59,7 +59,7 @@ export class ViewController {
|
||||
|
||||
dismiss(data) {
|
||||
this._onDismiss && this._onDismiss(data);
|
||||
return this._nav.remove(this._nav.indexOf(this), this._leavingOpts);
|
||||
return this._nav.remove(this._nav.indexOf(this), 1, this._leavingOpts);
|
||||
}
|
||||
|
||||
setNav(navCtrl) {
|
||||
@@ -89,7 +89,7 @@ export class ViewController {
|
||||
let previousItem = this._nav.getPrevious(this);
|
||||
// the previous view may exist, but if it's about to be destroyed
|
||||
// it shouldn't be able to go back to
|
||||
return !!(previousItem && !previousItem.shouldDestroy);
|
||||
return !!(previousItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -151,6 +151,36 @@ export class ViewController {
|
||||
this._destroys = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
domCache(shouldShow: boolean, renderer: Renderer) {
|
||||
// using hidden element attribute to display:none and not render views
|
||||
// renderAttr of '' means the hidden attribute will be added
|
||||
// renderAttr of null means the hidden attribute will be removed
|
||||
// doing checks to make sure we only make an update to the element when needed
|
||||
if (this._pgRef &&
|
||||
(shouldShow && this._hdAttr === '' ||
|
||||
!shouldShow && this._hdAttr !== '')) {
|
||||
|
||||
this._hdAttr = (shouldShow ? null : '');
|
||||
|
||||
renderer.setElementAttribute(this._pgRef, 'hidden', this._hdAttr);
|
||||
|
||||
let navbarRef = this.navbarRef();
|
||||
if (navbarRef) {
|
||||
renderer.setElementAttribute(navbarRef, 'hidden', this._hdAttr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setZIndex(zIndex: number, renderer: Renderer) {
|
||||
if (this._pgRef && zIndex !== this.zIndex) {
|
||||
this.zIndex = zIndex;
|
||||
renderer.setElementStyle(this._pgRef, 'z-index', zIndex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@@ -358,9 +388,7 @@ export class ViewController {
|
||||
*/
|
||||
loaded() {
|
||||
this._loaded = true;
|
||||
if (!this.shouldDestroy) {
|
||||
ctrlFn(this, 'onPageLoaded');
|
||||
}
|
||||
ctrlFn(this, 'onPageLoaded');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,9 +396,7 @@ export class ViewController {
|
||||
* The view is about to enter and become the active view.
|
||||
*/
|
||||
willEnter() {
|
||||
if (!this.shouldDestroy) {
|
||||
ctrlFn(this, 'onPageWillEnter');
|
||||
}
|
||||
ctrlFn(this, 'onPageWillEnter');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -153,7 +153,9 @@ export class Tab extends NavController {
|
||||
*/
|
||||
load(opts, done?: Function) {
|
||||
if (!this._loaded && this.root) {
|
||||
this.push(this.root, null, opts, done);
|
||||
this.push(this.root, null, opts).then(() => {
|
||||
done();
|
||||
});
|
||||
this._loaded = true;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,7 @@ module.exports = function(config) {
|
||||
'node_modules/rxjs/bundles/Rx.min.js',
|
||||
'dist/bundles/ionic.system.js',
|
||||
//'node_modules/angular2/bundles/test_lib.js',
|
||||
{ pattern: 'dist/tests/**/*.spec.js', included: false },
|
||||
{ pattern: 'dist/tests/**/nav-controller.spec.js', included: false },
|
||||
'scripts/karma/test-main.js'
|
||||
],
|
||||
|
||||
|
||||
Reference in New Issue
Block a user