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;
|
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
|
* TODO
|
||||||
* @param {TODO} index 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 {IonicApp} from '../app/app';
|
||||||
import {IonicConfig} from '../../config/config';
|
import {IonicConfig} from '../../config/config';
|
||||||
@ -60,8 +60,8 @@ import {Tabs} from './tabs';
|
|||||||
],
|
],
|
||||||
host: {
|
host: {
|
||||||
'[attr.id]': 'panelId',
|
'[attr.id]': 'panelId',
|
||||||
'[attr.aria-labelledby]': 'labeledBy',
|
'[attr.aria-labelledby]': 'btnId',
|
||||||
'[attr.aria-hidden]': 'isNotSelected',
|
'[class.show-tab]': 'isSelected',
|
||||||
'role': 'tabpanel'
|
'role': 'tabpanel'
|
||||||
},
|
},
|
||||||
template: '<template content-anchor></template><ng-content></ng-content>',
|
template: '<template content-anchor></template><ng-content></ng-content>',
|
||||||
@ -69,13 +69,6 @@ import {Tabs} from './tabs';
|
|||||||
})
|
})
|
||||||
export class Tab extends NavController {
|
export class Tab extends NavController {
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
* @param {Tabs} tabs TODO
|
|
||||||
* @param {ElementRef} elementRef TODO
|
|
||||||
* @param {Injector} injector TODO
|
|
||||||
* @param {NgZone} zone TODO
|
|
||||||
*/
|
|
||||||
constructor(
|
constructor(
|
||||||
@Host() tabs: Tabs,
|
@Host() tabs: Tabs,
|
||||||
app: IonicApp,
|
app: IonicApp,
|
||||||
@ -86,44 +79,18 @@ export class Tab extends NavController {
|
|||||||
viewManager: AppViewManager,
|
viewManager: AppViewManager,
|
||||||
zone: NgZone
|
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
|
// A Tab is a NavController for its child pages
|
||||||
super(tabs, app, config, elementRef, compiler, loader, viewManager, zone);
|
super(tabs, app, config, elementRef, compiler, loader, viewManager, zone);
|
||||||
this.tabs = tabs;
|
this.tabs = tabs;
|
||||||
|
|
||||||
let viewCtrl = this.viewCtrl = new ViewController(tabs);
|
this._isInitial = tabs.add(this);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onInit() {
|
onInit() {
|
||||||
console.log('Tab onInit');
|
console.debug('Tab onInit');
|
||||||
|
|
||||||
if (this._initTab) {
|
if (this._isInitial) {
|
||||||
this.tabs.select(this);
|
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,
|
animate: false,
|
||||||
navbar: false
|
navbar: false
|
||||||
};
|
};
|
||||||
this.push(this.root, null, opts).then(() => {
|
this.push(this.root, null, opts).then(callback);
|
||||||
callback && callback();
|
|
||||||
});
|
|
||||||
this._loaded = true;
|
this._loaded = true;
|
||||||
|
|
||||||
} else {
|
} 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) {
|
loadContainer(componentType, hostProtoViewRef, viewCtrl, done) {
|
||||||
|
|
||||||
this.loadNextToAnchor(componentType, this.contentAnchorRef, viewCtrl).then(componentRef => {
|
this.loadNextToAnchor(componentType, this.contentAnchorRef, viewCtrl).then(componentRef => {
|
||||||
|
@ -37,7 +37,7 @@ ion-tab {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
display: none;
|
display: none;
|
||||||
&.show-view {
|
&.show-tab {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,6 +46,10 @@ ion-tabs > ion-navbar-section {
|
|||||||
order: $flex-order-tab-bar-navbar;
|
order: $flex-order-tab-bar-navbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-tabs ion-navbar.toolbar.deselected-tab {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
ion-tab-bar-section {
|
ion-tab-bar-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
order: $flex-order-tab-bar-bottom;
|
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 {Ion} from '../ion';
|
||||||
import {IonicApp} from '../app/app';
|
import {IonicApp} from '../app/app';
|
||||||
import {IonicConfig} from '../../config/config';
|
import {IonicConfig} from '../../config/config';
|
||||||
import {NavController} from '../nav/nav-controller';
|
|
||||||
import {ViewController} from '../nav/view-controller';
|
import {ViewController} from '../nav/view-controller';
|
||||||
import {ConfigComponent} from '../../config/decorators';
|
import {ConfigComponent} from '../../config/decorators';
|
||||||
import {Icon} from '../icon/icon';
|
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-navbar-section>' +
|
||||||
'<ion-tab-bar-section>' +
|
'<ion-tab-bar-section>' +
|
||||||
'<tab-bar role="tablist">' +
|
'<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>' +
|
'<icon [name]="t.tabIcon" [is-active]="t.isSelected" class="tab-button-icon"></icon>' +
|
||||||
'<span class="tab-button-text">{{t.tabTitle}}</span>' +
|
'<span class="tab-button-text">{{t.tabTitle}}</span>' +
|
||||||
'</a>' +
|
'</a>' +
|
||||||
@ -90,71 +88,50 @@ import * as dom from 'ionic/util/dom';
|
|||||||
forwardRef(() => TabNavBarAnchor)
|
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(
|
constructor(
|
||||||
@Optional() hostNavCtrl: NavController,
|
|
||||||
@Optional() viewCtrl: ViewController,
|
|
||||||
app: IonicApp,
|
app: IonicApp,
|
||||||
config: IonicConfig,
|
config: IonicConfig,
|
||||||
elementRef: ElementRef,
|
elementRef: ElementRef,
|
||||||
compiler: Compiler,
|
@Optional() viewCtrl: ViewController
|
||||||
loader: DynamicComponentLoader,
|
|
||||||
viewManager: AppViewManager,
|
|
||||||
zone: NgZone
|
|
||||||
) {
|
) {
|
||||||
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
|
// Tabs may also be an actual ViewController which was navigated to
|
||||||
// if Tabs is static and not navigated to within a NavController
|
// if Tabs is static and not navigated to within a NavController
|
||||||
// then skip this and don't treat it as it's own ViewController
|
// then skip this and don't treat it as it's own ViewController
|
||||||
if (viewCtrl) {
|
if (viewCtrl) {
|
||||||
this.viewCtrl = viewCtrl;
|
this._ready = new Promise(res => { this._isReady = res; });
|
||||||
|
|
||||||
// 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
viewCtrl.onReady = () => {
|
viewCtrl.onReady = () => {
|
||||||
return this._ready;
|
return this._ready;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* TODO
|
|
||||||
*/
|
*/
|
||||||
addTab(tab) {
|
add(tab) {
|
||||||
this._add(tab.viewCtrl);
|
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._tabs.length === 1);
|
||||||
return (this.length() === 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,42 +139,66 @@ export class Tabs extends NavController {
|
|||||||
* @param {Tab} tab TODO
|
* @param {Tab} tab TODO
|
||||||
* @returns {TODO} TODO
|
* @returns {TODO} TODO
|
||||||
*/
|
*/
|
||||||
select(tab) {
|
select(tabOrIndex) {
|
||||||
let enteringView = null;
|
let selectedTab = null;
|
||||||
if (typeof tab === 'number') {
|
|
||||||
enteringView = this.getByIndex(tab);
|
if (typeof tabOrIndex === 'number') {
|
||||||
|
selectedTab = this.getByIndex(tabOrIndex);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
enteringView = this.getByInstance(tab)
|
selectedTab = tabOrIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we select the same tab as the active one, do some magic.
|
if (!selectedTab || !this.app.isEnabled()) {
|
||||||
if(enteringView === this.getActive()) {
|
|
||||||
this._touchActive(tab);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!enteringView || !enteringView.instance || !this.app.isEnabled()) {
|
|
||||||
return Promise.reject();
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise(resolve => {
|
let deselectedTab = this.getSelected();
|
||||||
enteringView.instance.load(() => {
|
|
||||||
let opts = {
|
|
||||||
animate: false
|
|
||||||
};
|
|
||||||
|
|
||||||
let leavingView = this.getActive() || new ViewController();
|
if (selectedTab === deselectedTab) {
|
||||||
leavingView.shouldDestroy = false;
|
// no change
|
||||||
leavingView.shouldCache = true;
|
return this._touchActive(selectedTab);
|
||||||
|
}
|
||||||
|
|
||||||
this.transition(enteringView, leavingView, opts, () => {
|
console.debug('select tab', selectedTab.id);
|
||||||
this.highlight && this.highlight.select(tab);
|
|
||||||
this._isReady();
|
selectedTab.load(() => {
|
||||||
resolve();
|
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) {
|
if(stateLen > 1) {
|
||||||
// Pop to the root view
|
// Pop to the root view
|
||||||
tab.popToRoot();
|
return tab.popToRoot();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
return Promise.resolve();
|
||||||
* TODO
|
|
||||||
* @return TODO
|
|
||||||
*/
|
|
||||||
get tabs() {
|
|
||||||
return this.instances();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _tabIds = -1;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* TODO
|
* TODO
|
||||||
@ -232,8 +230,8 @@ export class Tabs extends NavController {
|
|||||||
selector: '.tab-button',
|
selector: '.tab-button',
|
||||||
inputs: ['tab'],
|
inputs: ['tab'],
|
||||||
host: {
|
host: {
|
||||||
'[attr.id]': 'btnId',
|
'[attr.id]': 'tab.btnId',
|
||||||
'[attr.aria-controls]': 'panelId',
|
'[attr.aria-controls]': 'tab.panelId',
|
||||||
'[attr.aria-selected]': 'tab.isSelected',
|
'[attr.aria-selected]': 'tab.isSelected',
|
||||||
'[class.has-title]': 'hasTitle',
|
'[class.has-title]': 'hasTitle',
|
||||||
'[class.has-icon]': 'hasIcon',
|
'[class.has-icon]': 'hasIcon',
|
||||||
@ -254,10 +252,6 @@ class TabButton extends Ion {
|
|||||||
|
|
||||||
onInit() {
|
onInit() {
|
||||||
this.tab.btn = this;
|
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.hasTitle = !!this.tab.tabTitle;
|
||||||
this.hasIcon = !!this.tab.tabIcon;
|
this.hasIcon = !!this.tab.tabIcon;
|
||||||
this.hasTitleOnly = (this.hasTitle && !this.hasIcon);
|
this.hasTitleOnly = (this.hasTitle && !this.hasIcon);
|
||||||
|
@ -104,7 +104,7 @@ class IOSTransition extends Animation {
|
|||||||
this.add(leavingContent);
|
this.add(leavingContent);
|
||||||
leavingContent
|
leavingContent
|
||||||
.before.addClass(SHOW_VIEW_CSS)
|
.before.addClass(SHOW_VIEW_CSS)
|
||||||
.before.setStyles({ zIndex: leavingView.index })
|
.before.setStyles({ zIndex: leavingView.index });
|
||||||
|
|
||||||
if (backDirection) {
|
if (backDirection) {
|
||||||
leavingContent
|
leavingContent
|
||||||
|
Reference in New Issue
Block a user