diff --git a/ionic/components/nav/nav-base.js b/ionic/components/nav/nav-base.js index 65c820e954..12e71f38b3 100644 --- a/ionic/components/nav/nav-base.js +++ b/ionic/components/nav/nav-base.js @@ -15,6 +15,7 @@ import {NavPane, NavBarSection} from './nav-pane'; import {Transition, ClickBlock} from 'ionic/ionic'; import * as util from 'ionic/util'; +let itemsIds = -1; export class NavBase { @@ -39,6 +40,9 @@ export class NavBase { this.sbTransition = null; this.sbActive = false; this.panes = {}; + + this.id = ++itemsIds; + this.childIds = -1; } initial(initial) { @@ -109,8 +113,8 @@ export class NavBase { } } - push(Component, params = {}, opts = {}) { - if (!Component || this.isTransitioning()) { + push(ComponentClass, params = {}, opts = {}) { + if (!ComponentClass || this.isTransitioning()) { return Promise.reject(); } @@ -136,13 +140,13 @@ export class NavBase { leavingItem.willCache(); // create a new NavStackItem - let enteringItem = new NavItem(this, Component, params); + let enteringItem = new NavItem(this, ComponentClass, params); // set that this item is staged (it's not ready to be animated in yet) enteringItem.state = STAGED_STATE; // add the item to the stack - this.items.push(enteringItem); + this.add(enteringItem); // start the transition this.transition(enteringItem, leavingItem, opts, () => { @@ -193,7 +197,25 @@ export class NavBase { return promise; } + switchActive(enteringItem, opts = {}) { + opts.animation = 'none'; + + let leavingItem = this.getActive() || new NavItem(); + leavingItem.shouldDestroy = false; + leavingItem.shouldCache = true; + leavingItem.willCache(); + + this.transition(enteringItem, leavingItem, opts, () => { + // transition completed, destroy the leaving item + console.log('switchActive comlete') + }); + } + transition(enteringItem, leavingItem, opts, callback) { + if (!enteringItem || enteringItem === leavingItem) { + return callback(); + } + opts.isAnimated = (opts.animation !== 'none'); this.transitionStart(opts); @@ -409,16 +431,6 @@ export class NavBase { return false; } - clear() { - let pops = []; - for(let item of this.items) { - pops.push(this.pop({ - animate: false - })); - } - return Promise.all(pops); - } - getActive() { for (let i = 0, ii = this.items.length; i < ii; i++) { if (this.items[i].state === ACTIVE_STATE) { @@ -428,6 +440,15 @@ export class NavBase { return null; } + findByInstance(instance) { + for (let i = 0, ii = this.items.length; i < ii; i++) { + if (this.items[i].instance === instance) { + return this.items[i]; + } + } + return null; + } + getPrevious(item) { if (item) { return this.items[ this.items.indexOf(item) - 1 ]; @@ -457,10 +478,43 @@ export class NavBase { return this.domElement; } + add(item) { + item.id = this.id + '' + (++this.childIds); + this.items.push(item); + } + remove(itemOrIndex) { util.array.remove(this.items, itemOrIndex); } + length() { + return this.items.length; + } + + isActive(item) { + return (item && item.stage === ACTIVE_STATE); + } + + clear() { + let pops = []; + for (let item of this.items) { + pops.push(this.pop({ + animate: false + })); + } + return Promise.all(pops); + } + + instances() { + let instances = []; + for (let item of this.items) { + if (item.instance) { + instances.push(item.instance); + } + } + return instances + } + width() { return this.domElement.offsetWidth; } diff --git a/ionic/components/nav/nav-item.js b/ionic/components/nav/nav-item.js index f24d30e4b4..14aaf1140a 100644 --- a/ionic/components/nav/nav-item.js +++ b/ionic/components/nav/nav-item.js @@ -11,11 +11,12 @@ import {TabPane, NavPane, NavPaneSection} from './nav'; export class NavItem { - constructor(navBase, Component, params = {}) { + constructor(navBase, ComponentClass, params = {}) { this.navBase = navBase; - this.Component = Component; + this.ComponentClass = ComponentClass; this.params = params; - this.id = util.nextUid(); + this.instance = null; + this._titleEle = undefined; this._backBtn = undefined; this.disposals = []; @@ -40,7 +41,7 @@ export class NavItem { } // compile the Component - this.navBase.compiler.compileInHost(this.Component).then(componentProtoViewRef => { + this.navBase.compiler.compileInHost(this.ComponentClass).then(componentProtoViewRef => { // figure out the sturcture of this Component // does it have a navbar? Is it tabs? Should it not have a navbar or any toolbars? diff --git a/ionic/components/tabs/tab.js b/ionic/components/tabs/tab.js index 03a27e5879..ef697d7897 100644 --- a/ionic/components/tabs/tab.js +++ b/ionic/components/tabs/tab.js @@ -50,18 +50,24 @@ export class Tab { injector: Injector, viewContainerRef: ViewContainerRef ) { + this.navBase = new NavBase(parentNavBase, compiler, elementRef, loader, injector); + this.parentNavBase = parentNavBase; + + this.tabItem = new NavItem(parentNavBase); + this.tabItem.instance = this + tabs.addTab(this.tabItem); + + this.panelId = 'tab-panel-' + this.tabItem.id; + this.labeledBy = 'tab-button-' + this.tabItem.id; + + this.elementRef = elementRef; this.viewContainerRef = viewContainerRef; this.sections = parentNavBase.panes['_n'].sections; this.navBase.panes['_n'] = this; - this.isSelected = false; - - tabs.addTab(this); - this.panelId = 'tab-panel-' + this.id; - this.labeledBy = 'tab-button-' + this.id; this.domElement = elementRef.domElement; this.config = Nav.config.invoke(this); @@ -69,19 +75,8 @@ export class Tab { console.log('Tab constructor', this.id, ' parentNavBase:', parentNavBase); } - onInit() { - this.navBase.initial(this.initial); - } - - select(shouldSelect) { - if (shouldSelect && !this.isSelected) { - console.log('Select tab', this.id); - - } else if (!shouldSelect && this.isSelected) { - console.log('Deselect tab', this.id); - } - - this.isSelected = shouldSelect; + get isSelected() { + return this.parentNavBase.isActive(this); } } diff --git a/ionic/components/tabs/tabs.js b/ionic/components/tabs/tabs.js index 14f5ff1615..52fe2b38cc 100644 --- a/ionic/components/tabs/tabs.js +++ b/ionic/components/tabs/tabs.js @@ -1,8 +1,9 @@ import {Ancestor, Parent} from 'angular2/src/core/annotations_impl/visibility'; import {Optional} from 'angular2/src/di/annotations_impl' -import {Directive, Component, onInit} from 'angular2/src/core/annotations_impl/annotations'; +import {Directive, Component} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; import {ElementRef} from 'angular2/src/core/compiler/element_ref'; +import {Compiler} from 'angular2/angular2'; import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; import {Injector} from 'angular2/di'; import {NgFor} from 'angular2/angular2'; @@ -14,17 +15,15 @@ import {TabButton} from './tab-button'; import {Icon} from '../icon/icon'; import {Nav, NavPane} from '../nav/nav'; import {NavItem} from '../nav/nav-item'; +import {NavBase} from '../nav/nav-base'; -let tabsId = -1; - @Component({ selector: 'ion-tabs', properties: [ 'tabBarPlacement', 'tabBarIcons' - ], - lifecycle: [onInit] + ] }) @View({ template: ` @@ -43,46 +42,35 @@ let tabsId = -1; directives: [NgFor, TabButton, Icon] }) export class Tabs { - constructor(elementRef: ElementRef) { - this.id = ++tabsId; - this.tabIds = 0; - this.tabs = []; - this._selected = null; + constructor( + @Optional() parentNavBase: NavBase, + compiler: Compiler, + elementRef: ElementRef, + loader: DynamicComponentLoader, + injector: Injector + ) { + this.navBase = new NavBase(parentNavBase, compiler, elementRef, loader, injector); this.domElement = elementRef.domElement; this.config = Tabs.config.invoke(this); - - console.log('Tabs constructor', this.id); } - onInit() { - if (this.tabs.length > 0) { - this.selectTab(this.tabs[0]); + addTab(tabItem) { + this.navBase.add(tabItem); + + if (this.navBase.length() === 1) { + this.selectTab(tabItem.instance); } } - addTab(tab) { - tab.id = this.id + '' + (++this.tabIds); - this.tabs.push(tab); + get tabs() { + return this.navBase.instances(); } - selectTab(tabToSelect) { - if (typeof tabToSelect === 'number') { - let index = tabToSelect; - tabToSelect = null; - if (index < this.tabs.length) { - tabToSelect = this.tabs[index]; - } - } - if (!tabToSelect || this._selected === tabToSelect) return; + selectTab(tabInstance) { + let enteringItem = this.navBase.findByInstance(tabInstance); - let tabToDeselect = this._selected; - - this.tabs.forEach(tab => { - tab.select( (tab === tabToSelect) ); - }); - - this._selected = tabToSelect; + this.navBase.switchActive(enteringItem); } }