mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
add advanced tabs testg
This commit is contained in:
@ -98,16 +98,16 @@ gulp.task('e2e', ['ionic-js', 'sass'], function() {
|
||||
.pipe(rename(function(file) {
|
||||
file.dirname = file.dirname.replace(path.sep + 'test' + path.sep, path.sep)
|
||||
}))
|
||||
.pipe(gulpif(/main.html$/, processMainHtml()))
|
||||
.pipe(gulpif(/main.js$/, processMain()))
|
||||
.pipe(gulpif(/e2e.js$/, createPlatformTests()))
|
||||
.pipe(gulp.dest(buildConfig.dist + '/e2e'))
|
||||
|
||||
function processMainHtml() {
|
||||
function processMain() {
|
||||
return through2.obj(function(file, enc, next) {
|
||||
this.push(new VinylFile({
|
||||
base: file.base,
|
||||
contents: new Buffer(indexContents),
|
||||
path: file.path.replace(/main.html$/, 'index.html'),
|
||||
path: file.path.replace(/main.js$/, 'index.html'),
|
||||
}))
|
||||
next(null, file)
|
||||
})
|
||||
|
@ -10,5 +10,6 @@ export * from 'ionic2/components/list/list'
|
||||
export * from 'ionic2/components/nav-view/nav-view'
|
||||
export * from 'ionic2/components/nav-viewport/nav-viewport'
|
||||
export * from 'ionic2/components/tabs/tabs'
|
||||
export * from 'ionic2/components/tabs/tab'
|
||||
export * from 'ionic2/components/toolbar/toolbar'
|
||||
export * from 'ionic2/components/view/view'
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {DynamicComponent, Parent, NgElement} from 'angular2/angular2'
|
||||
import {NavViewport} from 'ionic2/components'
|
||||
import {DynamicComponent, Ancestor, NgElement} from 'angular2/angular2'
|
||||
import {Optional} from 'angular2/src/di/annotations'
|
||||
import {NavViewport, Tabs} from 'ionic2/components'
|
||||
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader'
|
||||
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location'
|
||||
|
||||
@ -13,12 +14,15 @@ export class NavView {
|
||||
constructor(
|
||||
loader: PrivateComponentLoader,
|
||||
location: PrivateComponentLocation,
|
||||
@Parent() viewport: NavViewport,
|
||||
@NgElement() element: NgElement
|
||||
@NgElement() element: NgElement,
|
||||
|
||||
// FIXME: this is temporary until ng2 lets us inject tabs as a NavViewport
|
||||
@Optional() @Ancestor() viewportNav: NavViewport,
|
||||
@Optional() @Ancestor() viewportTabs: Tabs
|
||||
) {
|
||||
this.loader = loader
|
||||
this.location = location
|
||||
this.viewport = viewport
|
||||
this.viewport = viewportTabs || viewportNav
|
||||
this.domElement = element.domElement
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,9 @@
|
||||
.nav-viewport {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.nav-view {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -1,33 +1,41 @@
|
||||
import {Component, Template, For} from 'angular2/angular2'
|
||||
import {Component, Template, For, NgElement} from 'angular2/angular2'
|
||||
import {ComponentConfig} from 'ionic2/config/component-config'
|
||||
import {NavView} from 'ionic2/components/nav-view/nav-view'
|
||||
import {array as arrayUtil, dom as domUtil} from 'ionic2/util'
|
||||
import {array as arrayUtil, dom as domUtil, isFunction} from 'ionic2/util'
|
||||
|
||||
@Component({
|
||||
selector: 'ion-nav-viewport',
|
||||
bind: {
|
||||
initialComponent: 'initialComponent'
|
||||
initial: 'initial'
|
||||
},
|
||||
})
|
||||
@Template({
|
||||
inline: `
|
||||
<section class="nav-view" *for="#item of _ngForLoopArray" [item]="item">
|
||||
<section class="nav-view" *for="#item of getRawNavStack()" [item]="item">
|
||||
</section>
|
||||
`,
|
||||
directives: [NavView, For]
|
||||
})
|
||||
export class NavViewport {
|
||||
constructor() {
|
||||
// stack is our public stack of items. This is synchronous and says an item
|
||||
constructor(
|
||||
element: NgElement
|
||||
) {
|
||||
this.domElement = element.domElement
|
||||
this.domElement.classList.add('nav-viewport')
|
||||
// stack is our sane stack of items. This is synchronous and says an item
|
||||
// is removed even if it's still animating out.
|
||||
this.stack = []
|
||||
this._stack = []
|
||||
|
||||
// _ngForLoopArray is our loop that actually adds/removes components. It doesn't
|
||||
// _ngForLoopArray is actually adds/removes components from the dom. It won't
|
||||
// remove a component until it's done animating out.
|
||||
this._ngForLoopArray = []
|
||||
}
|
||||
|
||||
set initialComponent(Class) {
|
||||
getRawNavStack() {
|
||||
return this._ngForLoopArray
|
||||
}
|
||||
|
||||
set initial(Class) {
|
||||
if (!this.initialized) {
|
||||
this.initialized = true
|
||||
this.push(Class)
|
||||
@ -40,18 +48,25 @@ export class NavViewport {
|
||||
* @param view the new view
|
||||
* @param shouldAnimate whether to animate
|
||||
*/
|
||||
// TODO don't push same component twice if one is already pushing
|
||||
// TODO only animate if state hasn't changed
|
||||
// TODO make sure the timing is together
|
||||
// TODO allow starting an animation in the middle (eg gestures). Leave
|
||||
// most of this up to the animation's implementation.
|
||||
push(Class, opts = {}) {
|
||||
let item = new NavItem(Class, opts)
|
||||
this.stack.push(item)
|
||||
this._ngForLoopArray.push(item)
|
||||
return item.waitForSetup().then(() => {
|
||||
let current = this.getPrevious(item)
|
||||
current && current.leaveReverse()
|
||||
return item.enter()
|
||||
push(Class: Function, { sync = this._stack.length === 0 } = {}) {
|
||||
let pushedItem = new NavItem(Class)
|
||||
this._stack.push(pushedItem)
|
||||
this._ngForLoopArray.push(pushedItem)
|
||||
|
||||
return pushedItem.waitForSetup().then(() => {
|
||||
let current = this.getPrevious(pushedItem)
|
||||
if (sync) {
|
||||
current && current.leaveSync()
|
||||
pushedItem.enterSync()
|
||||
} else {
|
||||
current && current.leaveReverse()
|
||||
return pushedItem.enter()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -60,18 +75,23 @@ export class NavViewport {
|
||||
*
|
||||
* @param shouldAnimate whether to animate
|
||||
*/
|
||||
pop() {
|
||||
let current = this.stack.pop()
|
||||
let previous = this.stack[this.stack.length - 1]
|
||||
previous.enterReverse()
|
||||
return current.leave().then(() => {
|
||||
// The animation is done, remove it from the dom
|
||||
pop({ sync = false } = {}) {
|
||||
let current = this._stack.pop()
|
||||
let previous = this._stack[this._stack.length - 1]
|
||||
if (sync) {
|
||||
previous && previous.enterSync()
|
||||
return Promise.resolve(remove())
|
||||
} else {
|
||||
previous && previous.enterReverse()
|
||||
return current.leave().then(remove)
|
||||
}
|
||||
function remove() {
|
||||
arrayUtil.remove(this._ngForLoopArray, current)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getPrevious(item) {
|
||||
return this.stack[ this.stack.indexOf(item) - 1 ]
|
||||
return this._stack[ this._stack.indexOf(item) - 1 ]
|
||||
}
|
||||
|
||||
// Animate a new view *in*
|
||||
@ -125,6 +145,14 @@ class NavItem {
|
||||
})
|
||||
})
|
||||
}
|
||||
enterSync() {
|
||||
this.setAnimation(null)
|
||||
return this.setShown(true)
|
||||
}
|
||||
leaveSync() {
|
||||
this.setAnimation(null)
|
||||
return this.setShown(false)
|
||||
}
|
||||
enter() {
|
||||
return this._animate({ isShown: true, animation: 'enter' })
|
||||
}
|
||||
|
@ -1,19 +1,48 @@
|
||||
import {NgElement, Component, Template, Parent} from 'angular2/angular2';
|
||||
import {
|
||||
NgElement,
|
||||
Component,
|
||||
Template,
|
||||
Ancestor,
|
||||
PropertySetter,
|
||||
For
|
||||
} from 'angular2/angular2';
|
||||
import {NavViewport, NavView, Tabs} from 'ionic2/components'
|
||||
import {IonicComponent} from 'ionic2/config/component'
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'ion-tab',
|
||||
bind: {
|
||||
tabTitle: 'tab-title'
|
||||
title: 'tab-title',
|
||||
initial: 'initial'
|
||||
}
|
||||
})
|
||||
@Template({
|
||||
inline: `
|
||||
<div [hidden]="!isSelected">
|
||||
<content></content>
|
||||
</div>
|
||||
`
|
||||
<section class="nav-view" *for="#item of getRawNavStack()" [item]="item">
|
||||
</section>
|
||||
`,
|
||||
directives: [For, NavView]
|
||||
})
|
||||
export class Tab {
|
||||
export class Tab extends NavViewport {
|
||||
constructor(
|
||||
element: NgElement,
|
||||
@Ancestor() tabs: Tabs,
|
||||
@PropertySetter('class.hide') setHidden: Function
|
||||
) {
|
||||
super(element)
|
||||
this.config = Tab.config.invoke(this)
|
||||
this.setHidden = setHidden
|
||||
|
||||
this.setSelected(false)
|
||||
tabs.addTab(this)
|
||||
}
|
||||
|
||||
setSelected(isSelected) {
|
||||
this.isSelected = !!isSelected
|
||||
this.setHidden(!this.isSelected)
|
||||
}
|
||||
}
|
||||
|
||||
new IonicComponent(Tab, {
|
||||
})
|
||||
|
@ -1,40 +1,66 @@
|
||||
import {NgElement, Component, Template, Foreach, Parent} from 'angular2/angular2'
|
||||
import {NavViewport} from 'ionic2/components'
|
||||
import {NgElement, Component, Template, Parent, For} from 'angular2/angular2'
|
||||
import {IonicComponent} from 'ionic2/config/component'
|
||||
|
||||
@Component({
|
||||
selector: 'ion-tabs',
|
||||
bind: {
|
||||
placement: 'placement'
|
||||
},
|
||||
}
|
||||
})
|
||||
@Template({
|
||||
inline: `
|
||||
<div class="toolbar tab-bar toolbar-ios toolbar-bottom">
|
||||
<div class="tab-bar-content">
|
||||
<a class="tab-bar-item tab-active" href="#">
|
||||
Tab 1
|
||||
</a>
|
||||
<a class="tab-bar-item" href="#">
|
||||
Tab 2
|
||||
</a>
|
||||
<a class="tab-bar-item" href="#">
|
||||
Tab 3
|
||||
<a *for="#tab of tabs"
|
||||
class="tab-bar-item tab-active"
|
||||
[class.active]="tab.isSelected"
|
||||
(click)="onClickTabItem($event, tab)">
|
||||
{{tab.title}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<content></content>
|
||||
`,
|
||||
directives: []
|
||||
directives: [For]
|
||||
})
|
||||
export class Tabs extends NavViewport {
|
||||
export class Tabs {
|
||||
constructor(
|
||||
element: NgElement
|
||||
) {
|
||||
super()
|
||||
this.domElement = element.domElement
|
||||
this.domElement.classList.add('pane')
|
||||
this.config = Tabs.config.invoke(this)
|
||||
|
||||
this.tabs = []
|
||||
}
|
||||
|
||||
addTab(tab) {
|
||||
this.tabs.push(tab)
|
||||
if (this.tabs.length == 1) {
|
||||
this.select(tab)
|
||||
}
|
||||
}
|
||||
|
||||
onClickTabItem(ev, tab) {
|
||||
ev.preventDefault()
|
||||
if (this.selectedTab !== tab) {
|
||||
this.select(tab)
|
||||
} else if (tab._stack.length >= 2) {
|
||||
while (tab._stack.length > 2) {
|
||||
tab.pop({ sync: true }) // pop with no animation
|
||||
}
|
||||
tab.pop() //pop last one with animation
|
||||
}
|
||||
}
|
||||
|
||||
select(tab) {
|
||||
this.tabs.forEach(otherTab => {
|
||||
otherTab.setSelected(false)
|
||||
})
|
||||
tab.setSelected(true)
|
||||
this.selectedTab = tab
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new IonicComponent(Tabs, {
|
||||
|
@ -20,3 +20,7 @@
|
||||
min-width: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab-bar-item.active {
|
||||
color: red;
|
||||
}
|
||||
|
17
src/components/tabs/test/advanced/main.js
Normal file
17
src/components/tabs/test/advanced/main.js
Normal file
@ -0,0 +1,17 @@
|
||||
import {Component, Template, bootstrap} from 'angular2/angular2'
|
||||
import {NavViewport} from 'ionic2/components'
|
||||
import {SignInPage} from 'app/pages/sign-in'
|
||||
|
||||
@Component({
|
||||
selector: '[ion-app]'
|
||||
})
|
||||
@Template({
|
||||
inline: '<ion-nav-viewport [initial]="initial"></ion-nav-viewport>',
|
||||
directives: [NavViewport]
|
||||
})
|
||||
class App {
|
||||
constructor() {
|
||||
this.initial = SignInPage
|
||||
}
|
||||
}
|
||||
bootstrap(App)
|
5
src/components/tabs/test/advanced/pages/sign-in.html
Normal file
5
src/components/tabs/test/advanced/pages/sign-in.html
Normal file
@ -0,0 +1,5 @@
|
||||
<ion-view nav-title="Sign In">
|
||||
<button class="button-positive" (click)="signIn()">
|
||||
Sign In
|
||||
</button>
|
||||
</ion-view>
|
21
src/components/tabs/test/advanced/pages/sign-in.js
Normal file
21
src/components/tabs/test/advanced/pages/sign-in.js
Normal file
@ -0,0 +1,21 @@
|
||||
import {Component, Template, Parent} from 'angular2/angular2'
|
||||
import {View, NavViewport} from 'ionic2/components'
|
||||
import {TabsPage} from 'app/pages/tabs'
|
||||
|
||||
@Component({
|
||||
selector: 'sign-in-page'
|
||||
})
|
||||
@Template({
|
||||
url: 'pages/sign-in.html',
|
||||
directives: [View]
|
||||
})
|
||||
export class SignInPage {
|
||||
constructor(
|
||||
@Parent() viewport: NavViewport
|
||||
) {
|
||||
this.viewport = viewport
|
||||
}
|
||||
signIn() {
|
||||
this.viewport.push(TabsPage)
|
||||
}
|
||||
}
|
8
src/components/tabs/test/advanced/pages/tabs.html
Normal file
8
src/components/tabs/test/advanced/pages/tabs.html
Normal file
@ -0,0 +1,8 @@
|
||||
<ion-view view-title="Tabs">
|
||||
<ion-tabs>
|
||||
<ion-tab [initial]="tab1Initial" tab-title="Tab 1">
|
||||
</ion-tab>
|
||||
<ion-tab [initial]="tab2Initial" tab-title="Tab 2">
|
||||
</ion-tab>
|
||||
</ion-tabs>
|
||||
</ion-view>
|
73
src/components/tabs/test/advanced/pages/tabs.js
Normal file
73
src/components/tabs/test/advanced/pages/tabs.js
Normal file
@ -0,0 +1,73 @@
|
||||
import {Component, Template, Parent} from 'angular2/angular2'
|
||||
import {View, Tabs, Tab} from 'ionic2/components'
|
||||
import {NavViewport} from 'ionic2/components'
|
||||
|
||||
@Component({
|
||||
selector: 'tabs-page'
|
||||
})
|
||||
@Template({
|
||||
url: 'pages/tabs.html',
|
||||
directives: [Tabs, Tab]
|
||||
})
|
||||
export class TabsPage {
|
||||
constructor() {
|
||||
this.tab1Initial = Tab1Page1
|
||||
this.tab2Initial = Tab2Page1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// tab 1
|
||||
//
|
||||
@Component({ selector: 't1p1' })
|
||||
@Template({
|
||||
inline: '<ion-view>Tab 1 Page 1.<br/><br/><button (click)="next()">Next</button></ion-view>',
|
||||
directives: [View]
|
||||
})
|
||||
class Tab1Page1 {
|
||||
constructor(@Parent() tab: Tab) {
|
||||
this.tab = tab
|
||||
}
|
||||
next() {
|
||||
this.tab.push(Tab1Page2)
|
||||
}
|
||||
}
|
||||
|
||||
@Component({ selector: 't1p2' })
|
||||
@Template({
|
||||
inline: '<ion-view>Tab 1<br/>Page 2.<br/></br><button (click)="pop()">Pop</button></ion-view>',
|
||||
directives: [View]
|
||||
})
|
||||
class Tab1Page2 {
|
||||
constructor(@Parent() tab: Tab) { this.tab = tab }
|
||||
pop() { this.tab.pop() }
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// tab 2
|
||||
//
|
||||
@Component({ selector: 't2p1' })
|
||||
@Template({
|
||||
inline: '<ion-view><br/><br/>Tab 2 Page 1. <button (click)="next()">Next</button></ion-view>',
|
||||
directives: [View]
|
||||
})
|
||||
class Tab2Page1 {
|
||||
constructor(@Parent() tab: Tab) {
|
||||
this.tab = tab
|
||||
}
|
||||
next() {
|
||||
this.tab.push(Tab2Page2)
|
||||
}
|
||||
}
|
||||
|
||||
@Component({ selector: 't2p2' })
|
||||
@Template({
|
||||
inline: '<ion-view><br/><br/>Tab 2<br/>Page 2. <button (click)="pop()">Pop</button></ion-view>',
|
||||
directives: [View]
|
||||
})
|
||||
class Tab2Page2 {
|
||||
constructor(@Parent() tab: Tab) { this.tab = tab }
|
||||
pop() { this.tab.pop() }
|
||||
}
|
@ -3,8 +3,11 @@
|
||||
|
||||
<ion-tabs>
|
||||
|
||||
<ion-tab>
|
||||
Tab 1 Content
|
||||
<ion-tab tab-title="Tab 1">
|
||||
Tab 1 Content<br/>.
|
||||
</ion-tab>
|
||||
<ion-tab tab-title="Tab 2">
|
||||
.<br/>Tab 2 Content
|
||||
</ion-tab>
|
||||
|
||||
</ion-tabs>
|
||||
|
@ -1,13 +1,12 @@
|
||||
import {bootstrap} from 'angular2/core';
|
||||
import {Component, Template} from 'angular2/angular2';
|
||||
import {View} from 'ionic2/components/view/view';
|
||||
import {Tabs} from 'ionic2/components/tabs/tabs';
|
||||
import {View, Tabs, Tab} from 'ionic2/components';
|
||||
|
||||
|
||||
@Component({ selector: '[ion-app]' })
|
||||
@Template({
|
||||
url: 'main.html',
|
||||
directives: [View, Tabs]
|
||||
directives: [View, Tabs, Tab]
|
||||
})
|
||||
class IonicApp {
|
||||
constructor() {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import {NgElement, Component, Template} from 'angular2/angular2'
|
||||
import {NgElement, Component, Template, Ancestor} from 'angular2/angular2'
|
||||
import {Optional} from 'angular2/src/di/annotations'
|
||||
import {BackButton} from 'ionic2/components/toolbar/back-button'
|
||||
import {Tabs, NavViewport, NavView} from 'ionic2/components'
|
||||
import {ComponentConfig} from 'ionic2/config/component-config'
|
||||
import {raf} from 'ionic2/util/dom'
|
||||
|
||||
@ -32,7 +34,10 @@ export let ToolbarConfig = new ComponentConfig('toolbar')
|
||||
directives: [BackButton]
|
||||
})
|
||||
export class Toolbar {
|
||||
constructor(@NgElement() ngEle:NgElement, configFactory: ToolbarConfig) {
|
||||
constructor(
|
||||
@NgElement() ngEle:NgElement,
|
||||
configFactory: ToolbarConfig
|
||||
) {
|
||||
this.domElement = ngEle.domElement
|
||||
|
||||
this.config = configFactory.create(this);
|
||||
@ -76,4 +81,10 @@ export class Toolbar {
|
||||
})
|
||||
}
|
||||
|
||||
back() {
|
||||
if (this.viewport && this.viewport._stack.length) {
|
||||
this.viewport.pop()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
import {NgElement, Component, Template, Parent} from 'angular2/angular2'
|
||||
import {NgElement, Component, Template, Parent, Ancestor} from 'angular2/angular2'
|
||||
import {Toolbar} from 'ionic2/components/toolbar/toolbar'
|
||||
import {ComponentConfig} from 'ionic2/config/component-config'
|
||||
|
||||
import {Tabs, NavViewport, NavView} from 'ionic2/components'
|
||||
import {Optional} from 'angular2/src/di/annotations'
|
||||
|
||||
export let ViewConfig = new ComponentConfig('view')
|
||||
|
||||
@Component({
|
||||
|
Reference in New Issue
Block a user