Merge remote-tracking branch 'origin/master'

Conflicts:
	src/components/app/_scaffolding.scss
This commit is contained in:
Adam Bradley
2015-04-09 09:51:46 -05:00
10 changed files with 318 additions and 91 deletions

1
.gitignore vendored
View File

@ -26,3 +26,4 @@ temp
dist
.idea
/src/components/split-view/test/settings/main.js

View File

@ -73,7 +73,9 @@ gulp.task('ionic-js', ['ionic-compile'], function() {
return gulp.src(buildConfig.distLib + '/ionic2.js')
.pipe(through2.obj(function(file, enc, next) {
var contents = file.contents.toString()
contents = contents.replace(/"src\//g, '"ionic2/')
contents = contents
.replace(/"src\//g, '"ionic2/')
.replace(new RegExp(' = void 0 in ','g'), ' in ');
file.contents = new Buffer(contents)
next(null, file)
}))

View File

@ -0,0 +1,95 @@
html {
height: 100%;
}
[ion-app] {
@include flex-display();
@include flex-direction(column);
overflow: hidden;
height: 100%;
max-width: 100%;
max-height: 100%;
margin: 0;
padding: 0;
.nav-viewport {
<<<<<<< HEAD
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
.nav-viewport.tab {
position: relative;
}
.nav-view {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
=======
/* position: absolute; */
/* width: 100%; */
/* height: 100%; */
position: relative;
flex: 1;
>>>>>>> origin/master
}
.pane {
position: relative;
height: 100%;
width: 100%;
@include flex-display();
@include flex-direction(column);
@include flex(1);
}
.view-cover {
height: 100vh !important;
.tab-bar {
z-index: 1
}
}
.pane > .pane-container {
position: relative;
overflow: hidden;
@include flex-display();
@include flex-order(40);
@include flex(1);
@include flex-direction(column);
}
.pane-container > .pane {
position: absolute;
min-height: 100%;
}
.pane > .pane-container > .content {
position: relative;
z-index: $z-index-content;
@include flex(1);
}
.scroll-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
}

View File

@ -30,7 +30,9 @@ export class NavView {
set item(navItem) {
if (this.initialized) return;
this.initialized = true;
this.Class = navItem.Class;
this.loader.load(navItem.Class, this.location).then(instance => {
this.instance = instance
navItem.finishSetup(this, instance)
})
}
@ -45,16 +47,12 @@ export class NavView {
/**
* Go back
*/
pop() {
return this.viewport.pop()
pop(opts) {
return this.viewport.pop(opts)
}
popTo(index: Number) {
if (this._stack.length < index + 1) return
while (tab._stack.length > index + 1) {
tab.pop({ sync: true }) // pop with no animation
}
return tab.pop() //pop last one with animation
popTo(index, opts) {
return this.viewport.popTo(index, opts)
}
}

View File

@ -35,6 +35,15 @@ export class NavViewport {
return this._ngForLoopArray
}
containsClass(Class) {
for (let i = 0; i < this._stack.length; i++) {
if (this._stack[i].Class === Class) {
return true
}
}
return false
}
set initial(Class) {
if (!this.initialized) {
this.initialized = true
@ -54,15 +63,18 @@ export class NavViewport {
// 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: Function, { sync = this._stack.length === 0 } = {}) {
let opts = {sync}
push(Class: Function, opts = {}) {
util.defaults(opts, {
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)
current && current.leave( util.extend({reverse:true}, opts) )
let current = this._getPrevious(pushedItem)
current && current.leaveReverse(opts)
return pushedItem.enter(opts)
})
}
@ -72,27 +84,71 @@ export class NavViewport {
*
* @param shouldAnimate whether to animate
*/
pop({ sync = false } = {}) {
let opts = {sync}
pop(opts = {}) {
util.defaults(opts, {
sync: false
})
let current = this._stack.pop()
let previous = this._stack[this._stack.length - 1]
let dest = this.peek()
previous && previous.enter( util.extend({reverse:true}, opts) )
return current && current.leave(opts).then(remove)
dest && dest.enterReverse(opts)
return current && current.leave(opts).then(() => this._destroy(current))
}
getPrevious(item) {
peek() {
return this._stack[this._stack.length - 1]
}
popAll() {
while (this._stack.length) {
const item = this._stack.pop()
this._destroy(item)
}
}
// Pop from the current item to the item at the specified index.
// Removes every item in the stack between the current and the given index,
// then performs a normal pop.
popTo(index, opts = {}) {
// Abort if we're already here.
if (this._stack.length <= index + 1) {
return Promise.resolve()
}
// Save the current navItem, and remove all the other ones in front of our
// target nav item.
const current = this._stack.pop()
while (this._stack.length > index + 1) {
const item = this._stack.pop()
this._destroy(item)
}
// Now put the current navItem back on the stack and run a normal pop animation.
this._stack.push(current)
return this.pop(opts)
}
setStack(stack) {
this._stack = stack.slice()
this._ngForLoopArray = stack.slice()
}
remove(index) {
const item = this._stack[index]
this._stack.splice(index, 1)
this._destroy(item)
}
_destroy(navItem) {
console.warn(
`Component "${navItem.Class.name}" was popped from the nav stack, But we're keeping its element in the DOM for now because of an ng2 bug.`
);
//util.array.remove(this._ngForLoopArray, navItem)
}
_getPrevious(item) {
return this._stack[ this._stack.indexOf(item) - 1 ]
}
// Animate a new view *in*
_animateIn(view) {
}
// Animate an old view *out*
_animateOut(view) {
}
}
class NavItem {
@ -139,6 +195,9 @@ class NavItem {
return Promise.resolve()
}
}
enterReverse(opts) {
return this.enter( util.extend({reverse: true}, opts) )
}
enter({ reverse = false, sync = false } = {}) {
return this._animate({
isShown: true,
@ -151,4 +210,7 @@ class NavItem {
animation: sync ? null : (reverse ? 'leave-reverse' : 'leave')
})
}
leaveReverse(opts) {
return this.leave( util.extend({reverse: true}, opts) )
}
}

View File

@ -2,6 +2,9 @@ import {Component, Parent, Decorator, Template, NgElement} from 'angular2/angula
import {NavViewport} from 'ionic2/components/nav-viewport/nav-viewport'
import {View} from 'ionic2/components/view/view'
import {NavView} from 'ionic2/components/nav-view/nav-view'
import * as util from 'ionic2/util'
// TODO consider more explicit API, a la tabs
/**
* SplitViewportDecorator is temporary until the SplitView is able to query
@ -23,18 +26,34 @@ class SplitViewportDecorator {
selector: 'ion-split-view',
bind: {
defaultView: 'defaultView',
viewTitle: 'viewTitle'
}
navTitle: 'navTitle'
},
})
@Template({
inline: `
<ion-view [view-title]="viewTitle">
<div class="split-pane-container">
<ion-view [nav-title]="navTitle" class="split-view">
<div class="pane-container">
<content></content>
</div>
</ion-view>
<ion-nav-viewport split-viewport>
</ion-nav-viewport>
<style>
ion-split-view {
width: 100%;
height: 100%;
display: flex;
}
ion-split-view > .view.split-view {
max-width: 300px;
border-right: 1px solid black;
z-index: 1;
}
ion-split-view > ion-nav-viewport[split-viewport] {
flex: 1;
}
</style>
`,
directives: [SplitViewportDecorator, NavViewport, View]
})
@ -45,34 +64,57 @@ export class SplitView {
) {
this.domElement = element.domElement
this.navView = navView
// TODO mq.addEventListener() doesn't work with zone.js
// let checkScreen = () => {
// const mq = window.matchMedia('(min-width: 720px)')
// this.setEnabled(mq.matches)
// }
// window.addEventListener('resize', checkScreen)
// checkScreen()
this.setEnabled(true)
}
set defaultView(def) {
this.splitViewport.push(def)
// Sets the first view to be shown in the viewport to the right of the splitView.
set defaultView(DefaultClass) {
this.splitViewport.push(DefaultClass, {sync: true})
}
isActive(Class) {
for (let item of this.splitViewport._stack) {
if (item.Class === Class) return true
}
return false
}
setNavViewport(viewport) {
this.splitViewport = viewport
this.navView.push = function(Class, opts) {
opts = opts || {}
util.defaults(opts, { sync: true })
if (this.splitViewport._stack.indexOf(Class) !== -1) {
this.splitViewport.popTo(0)
} else {
while (this.splitViewport._stack.length) {
this.splitViewport.pop({sync: true})
this.navView.__$push = this.navView.push
this.navView.push = (Class, opts) => {
if (this.isEnabled) {
opts = opts || {}
util.defaults(opts, { sync: true })
if (this.splitViewport.containsClass(Class)) {
return this.splitViewport.popTo(0)
} else {
this.splitViewport.popAll()
return this.splitViewport.push(Class, opts)
}
this.splitViewport.push(Class, opts)
} else {
return this.navView.__$push(Class, opts)
}
}
};
}
// TODO set enabled depending on some condition (media query in this case)
setEnabled(isEnabled) {
this.isSplitView = isEnabled
if (isEnabled) {
if (isEnabled !== this.isEnabled) {
if (isEnabled) {
this.splitViewport
}
this.isEnabled = isEnabled
}
}
}

View File

@ -6,7 +6,7 @@ import {View} from 'ionic2/components'
})
@Template({
inline: `
<ion-view view-title="General">
<ion-view nav-title="General Stuff">
General Settings
</ion-view>
`,

View File

@ -0,0 +1,70 @@
import {Component, Template} from 'angular2/angular2'
import {View, NavView} from 'ionic2/components'
@Component({ selector: 'privacy-settings' })
@Template({
inline: `
<ion-view nav-title="Privacy">
Privacy
<button class="button button-primary" (click)="next()">
Next
</button>
</ion-view>`,
directives: [View]
})
export class SettingsPrivacy {
constructor(navView: NavView) {
this.navView = navView
}
next() {
this.navView.push(PrivacyP1)
}
}
@Component({ selector: 'privp1' })
@Template({
inline: `
<ion-view view-title="Privacy Page 1">
This is page 1
<button class="button button-primary" (click)="next()">
Next
</button>
<button class="button" (click)="pop()">
Back
</button>
</ion-view>
`,
directives: [View]
})
class PrivacyP1 {
constructor(navView: NavView) {
this.navView = navView
}
next() {
this.navView.push(PrivacyP2)
}
pop() {
this.navView.pop()
}
}
@Component({ selector: 'privp2' })
@Template({
inline: `
<ion-view view-title="Privacy Page 2">
Page 2 here
<button class="button" (click)="pop()">
Back
</button>
</ion-view>
`,
directives: [View]
})
class PrivacyP2 {
constructor(navView: NavView) {
this.navView = navView
}
pop() {
this.navView.pop()
}
}

View File

@ -1,38 +0,0 @@
import {Component, Template, bootstrap} from 'angular2/angular2'
import {SplitView, NavViewport} from 'ionic2/components'
import {SettingsGeneral} from 'app/groups/general'
@Component({
selector: 'settings-split'
})
@Template({
inline: `
<ion-split-view view-title="Settings" [default-view]="default">
Hello, split
</ion-split-view>
`,
directives: [SplitView]
})
class SettingsSplit {
constructor() {
this.default = SettingsGeneral
}
}
@Component({
selector: '[ion-app]'
})
@Template({
inline: `
<ion-nav-viewport [initial]="initial">
</ion-nav-viewport>
`,
directives: [NavViewport]
})
class App {
constructor() {
this.initial = SettingsSplit
}
}
bootstrap(App)

View File

@ -36,11 +36,9 @@ export class Tabs {
@NgElement() ngElement: NgElement
) {
this.domElement = ngElement.domElement
this.domElement.classList.add('pane')
this.config = Tabs.config.invoke(this)
this.tabs = []
}
@ -56,10 +54,7 @@ export class Tabs {
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
tab.popTo(0)
}
}