From 77772370bf0a53fc91eddb92250c2dec1f9384e9 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Thu, 7 Apr 2016 20:45:51 -0500 Subject: [PATCH] feat(app): getActiveNav() method --- ionic/components/app/app.ts | 41 ++++++++- ionic/components/app/test/app.spec.ts | 112 +++++++++++++++++++++++++ ionic/components/nav/nav-controller.ts | 26 +++++- ionic/components/nav/nav.ts | 13 ++- ionic/components/tabs/tab.ts | 2 +- ionic/components/tabs/tabs.ts | 18 +++- 6 files changed, 201 insertions(+), 11 deletions(-) create mode 100644 ionic/components/app/test/app.spec.ts diff --git a/ionic/components/app/app.ts b/ionic/components/app/app.ts index b9a0592894..04d8c57cf3 100644 --- a/ionic/components/app/app.ts +++ b/ionic/components/app/app.ts @@ -1,9 +1,10 @@ -import {Injectable, NgZone} from 'angular2/core'; +import {Injectable} from 'angular2/core'; import {Title} from 'angular2/platform/browser'; import {Config} from '../../config/config'; import {ClickBlock} from '../../util/click-block'; -import {rafFrames} from '../../util/dom'; +import {Nav} from '../nav/nav'; +import {Tabs} from '../tabs/tabs'; /** @@ -18,11 +19,11 @@ export class IonicApp { private _title: string = ''; private _titleSrv: Title = new Title(); private _isProd: boolean = false; + private _rootNav: any = null; constructor( private _config: Config, - private _clickBlock: ClickBlock, - private _zone: NgZone + private _clickBlock: ClickBlock ) {} /** @@ -98,6 +99,38 @@ export class IonicApp { return (this._scrollTime + 64 > Date.now()); } + /** + * @private + */ + getActiveNav(): Nav | Tabs { + var nav = this._rootNav || null; + var activeChildNav; + + while (nav) { + activeChildNav = nav.getActiveChildNav(); + if (!activeChildNav) { + break; + } + nav = activeChildNav; + } + + return nav; + } + + /** + * @private + */ + getRootNav(): any { + return this._rootNav; + } + + /** + * @private + */ + setRootNav(nav: any) { + this._rootNav = nav; + } + /** * @private * Register a known component with a key, for easy lookups later. diff --git a/ionic/components/app/test/app.spec.ts b/ionic/components/app/test/app.spec.ts new file mode 100644 index 0000000000..62a4496ce8 --- /dev/null +++ b/ionic/components/app/test/app.spec.ts @@ -0,0 +1,112 @@ +import {IonicApp, Nav, Tabs, Tab, NavOptions, Config, ViewController} from '../../../../ionic'; + +export function run() { + + +describe('IonicApp', () => { + + describe('getActiveNav', () => { + + it('should get active NavController when using tabs with nested nav', () => { + let nav = mockNav(); + app.setRootNav(nav); + + let tabs = mockTabs(); + let tab1 = mockTab(tabs); + let tab2 = mockTab(tabs); + nav.registerChildNav(tabs); + + tab2.setSelected(true); + let nav2 = mockNav(); + let nav3 = mockNav(); + let nav4 = mockNav(); + tab1.registerChildNav(nav4); + tab2.registerChildNav(nav2); + tab2.registerChildNav(nav3); + + expect(app.getActiveNav()).toBe(nav3); + }); + + it('should get active NavController when using tabs', () => { + let nav = mockNav(); + app.setRootNav(nav); + + let tabs = mockTabs(); + let tab1 = mockTab(tabs); + let tab2 = mockTab(tabs); + let tab3 = mockTab(tabs); + nav.registerChildNav(tabs); + + tab2.setSelected(true); + + expect(app.getActiveNav()).toBe(tab2); + + tab2.setSelected(false); + tab3.setSelected(true); + expect(app.getActiveNav()).toBe(tab3); + }); + + it('should get active NavController when nested 3 deep', () => { + let nav1 = mockNav(); + let nav2 = mockNav(); + let nav3 = mockNav(); + app.setRootNav(nav1); + + nav1.registerChildNav(nav2); + nav2.registerChildNav(nav3); + + expect(app.getActiveNav()).toBe(nav3); + }); + + it('should get active NavController when nested 2 deep', () => { + let nav1 = mockNav(); + let nav2 = mockNav(); + app.setRootNav(nav1); + + nav1.registerChildNav(nav2); + expect(app.getActiveNav()).toBe(nav2); + }); + + it('should get active NavController when only one nav controller', () => { + let nav = mockNav(); + app.setRootNav(nav); + expect(app.getActiveNav()).toBe(nav); + }); + + it('should set/get the root nav controller', () => { + let nav = mockNav(); + app.setRootNav(nav); + expect(app.getRootNav()).toBe(nav); + }); + + it('should not get an active NavController if there is not root set', () => { + expect(app.getActiveNav()).toBeNull(); + expect(app.getRootNav()).toBeNull(); + }); + + }); + + var app: IonicApp; + var config: Config; + + function mockNav(): Nav { + return new Nav(null,null,null,config,null,null,null,null,null,null); + } + + function mockTabs(): Tabs { + return new Tabs(null, null, null, config, null, null, null); + } + + function mockTab(parentTabs: Tabs): Tab { + return new Tab(parentTabs,null,config,null,null,null,null,null,null); + } + + beforeEach(() => { + config = new Config(); + app = new IonicApp(config, null); + }); + +}); + + +} \ No newline at end of file diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index 7fb6d1c717..a3fe7fa32b 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -110,6 +110,7 @@ export class NavController extends Ion { private _sbGesture: SwipeBackGesture; private _sbThreshold: number; private _portal: Portal; + private _children: any[] = []; protected _sbEnabled: boolean; protected _ids: number = -1; @@ -166,8 +167,8 @@ export class NavController extends Ion { this._trnsDelay = config.get('pageTransitionDelay'); - this._sbEnabled = config.getBoolean('swipeBackEnabled') || false; - this._sbThreshold = config.get('swipeBackThreshold') || 40; + this._sbEnabled = config.getBoolean('swipeBackEnabled'); + this._sbThreshold = config.getNumber('swipeBackThreshold', 40); this.id = (++ctrlIds).toString(); @@ -1322,6 +1323,21 @@ export class NavController extends Ion { } } + getActiveChildNav(): any { + return this._children[this._children.length - 1]; + } + + registerChildNav(nav: any) { + this._children.push(nav); + } + + unregisterChildNav(nav: any) { + let index = this._children.indexOf(nav); + if (index > -1) { + this._children.splice(index, 1); + } + } + /** * @private */ @@ -1329,7 +1345,11 @@ export class NavController extends Ion { for (var i = this._views.length - 1; i >= 0; i--) { this._views[i].destroy(); } - this._views = []; + this._views.length = 0; + + if (this.parent) { + this.parent.unregisterChildNav(this); + } } /** diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index ef7451a3c5..483c6fbbb2 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -113,7 +113,7 @@ export class Nav extends NavController { private _hasInit: boolean = false; constructor( - @Optional() hostNavCtrl: NavController, + @Optional() parent: NavController, @Optional() viewCtrl: ViewController, app: IonicApp, config: Config, @@ -124,7 +124,7 @@ export class Nav extends NavController { zone: NgZone, renderer: Renderer ) { - super(hostNavCtrl, app, config, keyboard, elementRef, 'contents', compiler, viewManager, zone, renderer); + super(parent, app, config, keyboard, elementRef, 'contents', compiler, viewManager, zone, renderer); if (viewCtrl) { // an ion-nav can also act as an ion-page within a parent ion-nav @@ -132,6 +132,15 @@ export class Nav extends NavController { viewCtrl.setContent(this); viewCtrl.setContentRef(elementRef); } + + if (parent) { + // this Nav has a parent Nav + parent.registerChildNav(this); + + } else if (app) { + // this is the root navcontroller for the entire app + this._app.setRootNav(this); + } } /** diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index 81f278c46a..f2f8a7ccbd 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -92,7 +92,7 @@ export class Tab extends NavController { private _panelId: string; private _btnId: string; private _loaded: boolean; - private _loadTmr: number; + private _loadTmr: any; /** * @private diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 74a381f42b..d3473df5e0 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -135,8 +135,8 @@ export class Tabs extends Ion { parent: any; constructor( - @Optional() viewCtrl: ViewController, @Optional() parent: NavController, + @Optional() viewCtrl: ViewController, private _app: IonicApp, private _config: Config, private _elementRef: ElementRef, @@ -149,6 +149,15 @@ export class Tabs extends Ion { this.subPages = _config.getBoolean('tabSubPages'); this._useHighlight = _config.getBoolean('tabbarHighlight'); + if (parent) { + // this Tabs has a parent Nav + parent.registerChildNav(this); + + } else if (this._app) { + // this is the root navcontroller for the entire app + this._app.setRootNav(this); + } + // Tabs may also be an actual ViewController which was navigated to // if Tabs is static and not navigated to within a NavController // then skip this and don't treat it as it's own ViewController @@ -308,6 +317,13 @@ export class Tabs extends Ion { return null; } + /** + * @private + */ + getActiveChildNav() { + return this.getSelected(); + } + /** * @private */