mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
refactor(Tabs): Tabs no longer extends NavController
This commit is contained in:
@ -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
|
||||
|
@ -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: '<template content-anchor></template><ng-content></ng-content>',
|
||||
@ -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 => {
|
||||
|
@ -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;
|
||||
|
@ -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';
|
||||
'</ion-navbar-section>' +
|
||||
'<ion-tab-bar-section>' +
|
||||
'<tab-bar role="tablist">' +
|
||||
'<a *ng-for="#t of tabs" [tab]="t" class="tab-button" role="tab">' +
|
||||
'<a *ng-for="#t of _tabs" [tab]="t" class="tab-button" role="tab">' +
|
||||
'<icon [name]="t.tabIcon" [is-active]="t.isSelected" class="tab-button-icon"></icon>' +
|
||||
'<span class="tab-button-text">{{t.tabTitle}}</span>' +
|
||||
'</a>' +
|
||||
@ -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);
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user