From ffc5a5e2cebd934fd1b10a53b63b6d9b63662078 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Sun, 11 Oct 2015 22:44:18 -0500 Subject: [PATCH] refactor(Tabs): Tabs no longer extends NavController --- ionic/components/nav/nav-controller.ts | 16 --- ionic/components/tabs/tab.ts | 59 ++------- ionic/components/tabs/tabs.scss | 6 +- ionic/components/tabs/tabs.ts | 164 ++++++++++++------------- ionic/transitions/ios-transition.ts | 2 +- 5 files changed, 93 insertions(+), 154 deletions(-) diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index e9e7cc89cf..8706a8e97e 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -862,22 +862,6 @@ export class NavController extends Ion { return null; } - /** - * TODO - * @param {TODO} instance TODO - * @returns {TODO} TODO - */ - getByInstance(instance) { - if (instance) { - for (let i = 0, ii = this._views.length; i < ii; i++) { - if (this._views[i].instance === instance) { - return this._views[i]; - } - } - } - return null; - } - /** * TODO * @param {TODO} index TODO diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index c606c14e64..080eead1e9 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -1,4 +1,4 @@ -import {Directive, Component, Host, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, forwardRef, Injector, NgZone, ViewContainerRef} from 'angular2/angular2'; +import {Component, Directive, Host, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, forwardRef, NgZone} from 'angular2/angular2'; import {IonicApp} from '../app/app'; import {IonicConfig} from '../../config/config'; @@ -60,8 +60,8 @@ import {Tabs} from './tabs'; ], host: { '[attr.id]': 'panelId', - '[attr.aria-labelledby]': 'labeledBy', - '[attr.aria-hidden]': 'isNotSelected', + '[attr.aria-labelledby]': 'btnId', + '[class.show-tab]': 'isSelected', 'role': 'tabpanel' }, template: '', @@ -69,13 +69,6 @@ import {Tabs} from './tabs'; }) export class Tab extends NavController { - /** - * TODO - * @param {Tabs} tabs TODO - * @param {ElementRef} elementRef TODO - * @param {Injector} injector TODO - * @param {NgZone} zone TODO - */ constructor( @Host() tabs: Tabs, app: IonicApp, @@ -86,44 +79,18 @@ export class Tab extends NavController { viewManager: AppViewManager, zone: NgZone ) { - // A Tab is both a container of many pages, and is a page itself. - // A Tab is one page within it's Host Tabs (which also extends NavController) // A Tab is a NavController for its child pages super(tabs, app, config, elementRef, compiler, loader, viewManager, zone); this.tabs = tabs; - let viewCtrl = this.viewCtrl = new ViewController(tabs); - viewCtrl.setInstance(this); - viewCtrl.setContentRef(elementRef); - this._initTab = tabs.addTab(this); - - this.getNavbar = viewCtrl.getNavbar = () => { - let activeView = this.getActive(); - return activeView && activeView.getNavbar(); - }; - - viewCtrl.enableBack = () => { - // override ViewController's enableBack(), should use the - // active child nav item's enableBack() instead - let activeView = this.getActive(); - return (activeView && activeView.enableBack()); - }; - - this.panelId = 'tab-panel-' + viewCtrl.id; - this.labeledBy = 'tab-button-' + viewCtrl.id; + this._isInitial = tabs.add(this); } onInit() { - console.log('Tab onInit'); + console.debug('Tab onInit'); - if (this._initTab) { + if (this._isInitial) { this.tabs.select(this); - - } else { - // TODO: OPTIONAL PRELOAD OTHER TABS! - // setTimeout(() => { - // this.load(); - // }, 300); } } @@ -133,24 +100,14 @@ export class Tab extends NavController { animate: false, navbar: false }; - this.push(this.root, null, opts).then(() => { - callback && callback(); - }); + this.push(this.root, null, opts).then(callback); this._loaded = true; } else { - callback && callback(); + callback(); } } - get isSelected() { - return this.tabs.isActive(this.viewCtrl); - } - - get isNotSelected() { - return !this.tabs.isActive(this.viewCtrl); - } - loadContainer(componentType, hostProtoViewRef, viewCtrl, done) { this.loadNextToAnchor(componentType, this.contentAnchorRef, viewCtrl).then(componentRef => { diff --git a/ionic/components/tabs/tabs.scss b/ionic/components/tabs/tabs.scss index 0c8c263f5d..003493df98 100644 --- a/ionic/components/tabs/tabs.scss +++ b/ionic/components/tabs/tabs.scss @@ -37,7 +37,7 @@ ion-tab { flex-direction: column; display: none; - &.show-view { + &.show-tab { display: flex; } } @@ -46,6 +46,10 @@ ion-tabs > ion-navbar-section { order: $flex-order-tab-bar-navbar; } +ion-tabs ion-navbar.toolbar.deselected-tab { + display: none; +} + ion-tab-bar-section { position: relative; order: $flex-order-tab-bar-bottom; diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 6a569613a0..413b83f430 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -1,13 +1,11 @@ -import {Component, Directive, Injector, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, NgZone, Optional, Host, NgFor, forwardRef, ViewContainerRef} from 'angular2/angular2'; +import {Directive, ElementRef, Optional, Host, NgFor, forwardRef, ViewContainerRef} from 'angular2/angular2'; import {Ion} from '../ion'; import {IonicApp} from '../app/app'; import {IonicConfig} from '../../config/config'; -import {NavController} from '../nav/nav-controller'; import {ViewController} from '../nav/view-controller'; import {ConfigComponent} from '../../config/decorators'; import {Icon} from '../icon/icon'; -import * as dom from 'ionic/util/dom'; /** @@ -72,7 +70,7 @@ import * as dom from 'ionic/util/dom'; '' + '' + '' + - '' + + '' + '' + '{{t.tabTitle}}' + '' + @@ -90,71 +88,50 @@ import * as dom from 'ionic/util/dom'; forwardRef(() => TabNavBarAnchor) ] }) -export class Tabs extends NavController { +export class Tabs extends Ion { + /** - * TODO + * Hi, I'm "Tabs". I'm really just another Page, with a few special features. + * "Tabs" can be a sibling to other pages that can be navigated to, which those + * sibling pages may or may not have their own tab bars (doesn't matter). The fact + * that "Tabs" can happen to have children "Tab" classes, and each "Tab" can have + * children pages with their own "ViewController" instance, as nothing to do with the + * point that "Tabs" is itself is just a page with its own instance of ViewController. */ constructor( - @Optional() hostNavCtrl: NavController, - @Optional() viewCtrl: ViewController, app: IonicApp, config: IonicConfig, elementRef: ElementRef, - compiler: Compiler, - loader: DynamicComponentLoader, - viewManager: AppViewManager, - zone: NgZone + @Optional() viewCtrl: ViewController ) { - super(hostNavCtrl, app, config, elementRef, compiler, loader, viewManager, zone); + super(elementRef, config); + this.app = app; - this._ready = new Promise(res => { this._isReady = res; }); + // collection of children "Tab" instances, which extends NavController + this._tabs = []; // 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 if (viewCtrl) { - this.viewCtrl = viewCtrl; - - // special overrides for the Tabs ViewController - // the Tabs ViewController does not have it's own navbar - // so find the navbar it should use within it's active Tab - viewCtrl.getNavbar = () => { - let activeTab = this.getActive(); - if (activeTab && activeTab.instance) { - return activeTab.instance.getNavbar(); - } - }; - - viewCtrl.contentRef = () => { - let activeTab = this.getActive(); - if (activeTab && activeTab.instance) { - return activeTab.instance.viewCtrl.contentRef(); - } - }; - - // a Tabs ViewController should not have a back button - // enableBack back button will later be determined - // by the active ViewController that has a navbar - viewCtrl.enableBack = () => { - return false; - }; + this._ready = new Promise(res => { this._isReady = res; }); viewCtrl.onReady = () => { return this._ready; }; } - } /** * @private - * TODO */ - addTab(tab) { - this._add(tab.viewCtrl); + add(tab) { + tab.id = ++_tabIds; + tab.btnId = 'tab-' + tab.id; + tab.panelId = 'tabpanel-' + tab.id; + this._tabs.push(tab); - // return true/false if it's the initial tab - return (this.length() === 1); + return (this._tabs.length === 1); } /** @@ -162,42 +139,66 @@ export class Tabs extends NavController { * @param {Tab} tab TODO * @returns {TODO} TODO */ - select(tab) { - let enteringView = null; - if (typeof tab === 'number') { - enteringView = this.getByIndex(tab); + select(tabOrIndex) { + let selectedTab = null; + + if (typeof tabOrIndex === 'number') { + selectedTab = this.getByIndex(tabOrIndex); + } else { - enteringView = this.getByInstance(tab) + selectedTab = tabOrIndex; } - // If we select the same tab as the active one, do some magic. - if(enteringView === this.getActive()) { - this._touchActive(tab); - return; - } - - if (!enteringView || !enteringView.instance || !this.app.isEnabled()) { + if (!selectedTab || !this.app.isEnabled()) { return Promise.reject(); } - return new Promise(resolve => { - enteringView.instance.load(() => { - let opts = { - animate: false - }; + let deselectedTab = this.getSelected(); - let leavingView = this.getActive() || new ViewController(); - leavingView.shouldDestroy = false; - leavingView.shouldCache = true; + if (selectedTab === deselectedTab) { + // no change + return this._touchActive(selectedTab); + } - this.transition(enteringView, leavingView, opts, () => { - this.highlight && this.highlight.select(tab); - this._isReady(); - resolve(); - }); - }); + console.debug('select tab', selectedTab.id); + selectedTab.load(() => { + this._isReady && this._isReady(); }); + + this._tabs.forEach(tab => { + tab.isSelected = (tab === selectedTab); + + tab._views.forEach(viewCtrl => { + let navbarRef = viewCtrl.navbarRef(); + if (navbarRef) { + navbarRef.nativeElement.classList[tab.isSelected ? 'remove': 'add']('deselected-tab'); + } + }); + }); + + this.highlight && this.highlight.select(selectedTab); + } + + /** + * TODO + * @param {TODO} index TODO + * @returns {TODO} TODO + */ + getByIndex(index) { + if (index < this._tabs.length && index > -1) { + return this._tabs[index]; + } + return null; + } + + getSelected() { + for (let i = 0; i < this._tabs.length; i++) { + if (this._tabs[i].isSelected) { + return this._tabs[i]; + } + } + return null; } /** @@ -210,20 +211,17 @@ export class Tabs extends NavController { if(stateLen > 1) { // Pop to the root view - tab.popToRoot(); + return tab.popToRoot(); } - } - /** - * TODO - * @return TODO - */ - get tabs() { - return this.instances(); + return Promise.resolve(); } } +let _tabIds = -1; + + /** * @private * TODO @@ -232,8 +230,8 @@ export class Tabs extends NavController { selector: '.tab-button', inputs: ['tab'], host: { - '[attr.id]': 'btnId', - '[attr.aria-controls]': 'panelId', + '[attr.id]': 'tab.btnId', + '[attr.aria-controls]': 'tab.panelId', '[attr.aria-selected]': 'tab.isSelected', '[class.has-title]': 'hasTitle', '[class.has-icon]': 'hasIcon', @@ -254,10 +252,6 @@ class TabButton extends Ion { onInit() { this.tab.btn = this; - let id = this.tab.viewCtrl.id; - this.btnId = 'tab-button-' + id; - this.panelId = 'tab-panel-' + id; - this.hasTitle = !!this.tab.tabTitle; this.hasIcon = !!this.tab.tabIcon; this.hasTitleOnly = (this.hasTitle && !this.hasIcon); diff --git a/ionic/transitions/ios-transition.ts b/ionic/transitions/ios-transition.ts index d1b4a886de..c09b460f63 100644 --- a/ionic/transitions/ios-transition.ts +++ b/ionic/transitions/ios-transition.ts @@ -104,7 +104,7 @@ class IOSTransition extends Animation { this.add(leavingContent); leavingContent .before.addClass(SHOW_VIEW_CSS) - .before.setStyles({ zIndex: leavingView.index }) + .before.setStyles({ zIndex: leavingView.index }); if (backDirection) { leavingContent