add initial split view, build to es5

This commit is contained in:
Andrew
2015-04-07 17:09:38 -06:00
parent ca85b7be2c
commit 065214526f
22 changed files with 312 additions and 91 deletions

View File

@@ -1,7 +1,3 @@
//
// Mostly stolen from https://github.com/pkozlowski-opensource/ng2-play
//
var _ = require('lodash')
var buildConfig = require('./scripts/build/config')
var SystemJsBuilder = require('systemjs-builder')
@@ -55,9 +51,33 @@ gulp.task('dependencies', function() {
.pipe(gulp.dest(buildConfig.distLib))
})
gulp.task('ionic-js', function() {
return gulp.src(['src/**/*.js', '!src/**/test/*/**/*.js'])
.pipe(gulp.dest(buildConfig.distLib + '/ionic2'))
gulp.task('ionic-compile', function() {
var builder = new SystemJsBuilder()
builder.config({
traceurOptions: buildConfig.traceurOptions,
meta: {
'angular2/angular2': { build: false },
'angular2/src/di/annotations': { build: false },
'angular2/src/core/compiler/private_component_loader': { build: false },
'angular2/src/core/compiler/private_component_location': { build: false },
'hammer': { build: false },
},
map: {
'ionic2': 'src'
}
})
return builder.build('ionic2/ionic2', buildConfig.distLib + '/ionic2.js')
})
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/')
file.contents = new Buffer(contents)
next(null, file)
}))
.pipe(gulp.dest(buildConfig.distLib))
})
gulp.task('sass', function(done) {

View File

@@ -29,6 +29,7 @@ module.exports = {
'long-stack-trace-zone.js',
'hammer.js',
'angular2.js',
'ionic2.js',
],
traceurOptions: {

View File

@@ -10,6 +10,7 @@ export * from 'ionic2/components/item/item'
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/split-view/split-view'
export * from 'ionic2/components/tabs/tabs'
export * from 'ionic2/components/tabs/tab'
export * from 'ionic2/components/toolbar/toolbar'

View File

@@ -1,9 +1,13 @@
import {Component, Template, Inject, Parent, NgElement} from 'angular2/angular2'
import {Component, Template, Inject, Parent, NgElement, EventEmitter} from 'angular2/angular2'
import * as types from 'ionic2/components/aside/extensions/types'
import * as gestures from 'ionic2/components/aside/extensions/gestures';
import * as gestures from 'ionic2/components/aside/extensions/gestures'
import {dom} from 'ionic2/util'
import {IonicComponent} from 'ionic2/config/component'
/**
* TODO (?) add docs about how to have a root aside and a nested aside, then hide the root one
*/
@Component({
selector: 'ion-aside',
bind: {

View File

@@ -15,7 +15,7 @@ class AsideGesture extends SlideEdgeGesture {
this.slideElement = slideElement;
this.listen();
}
canStart(ev) {
// Only restrict edges if the aside is closed
return this.aside.isOpen ? true : super.canStart(ev);
@@ -89,4 +89,3 @@ export class BottomAsideGesture extends TopAsideGesture {
};
}
}

View File

@@ -1,7 +1,7 @@
import {DynamicComponent, Ancestor, NgElement} from 'angular2/angular2'
import {DynamicComponent, Parent, NgElement} from 'angular2/angular2'
import {Optional} from 'angular2/src/di/annotations'
import {NavViewport} from 'ionic2/components/nav-viewport/nav-viewport'
import {Tabs} from 'ionic2/components/tabs/tabs'
import {Tab} from 'ionic2/components/tabs/tab'
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader'
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location'
@@ -18,18 +18,64 @@ export class NavView {
@NgElement() element: NgElement,
// FIXME: this is temporary until ng2 lets us inject tabs as a NavViewport
@Optional() @Ancestor() viewportNav: NavViewport,
@Optional() @Ancestor() viewportTabs: Tabs
@Optional() @Parent() viewportNav: NavViewport,
@Optional() @Parent() viewportTab: Tab
) {
this.loader = loader
this.location = location
this.viewport = viewportTabs || viewportNav
this.viewport = viewportTab || viewportNav
this.domElement = element.domElement
}
set item(navItem) {
if (this.initialized) return;
this.initialized = true;
this.loader.load(navItem.Class, this.location).then(instance => {
navItem.finishSetup(this, instance)
})
}
/**
* Push out of this view into another view
*/
push(Class: Function, opts = {}) {
return this.viewport.push(Class, opts)
}
/**
* Go back
*/
pop() {
return this.viewport.pop()
}
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
}
}
/*
beforePush()
beforePop()
beforeReenter()
beforePushedOut()
beforeEnter()
afterEnter()
beforeLeave()
afterLeave()
splitView:
beforeEnter: setup this view as the side view, next view in main area.
- any time a push happens in this view, bring the new component into the main view.
- any time a pop happens in this view, actually pop the stack (if we can).
any time a push happens in the main view, act normally.
the main view thinks it is the first component in the stack (does it have its own nav-viewport?)
*/

View File

@@ -1,13 +1,13 @@
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, isFunction} from 'ionic2/util'
import * as util from 'ionic2/util'
@Component({
selector: 'ion-nav-viewport',
bind: {
initial: 'initial'
},
}
})
@Template({
inline: `
@@ -26,7 +26,7 @@ export class NavViewport {
// is removed even if it's still animating out.
this._stack = []
// _ngForLoopArray is actually adds/removes components from the dom. It won't
// _ngForLoopArray is actually adds/removes components from the dom. It won't
// remove a component until it's done animating out.
this._ngForLoopArray = []
}
@@ -41,6 +41,7 @@ export class NavViewport {
this.push(Class)
}
}
//TODO let the view handle enter/leave so splitview can override
/**
* Push a new view into the history stack.
@@ -54,19 +55,15 @@ export class NavViewport {
// 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}
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()
}
current && current.leave( util.extend({reverse:true}, opts) )
return pushedItem.enter(opts)
})
}
@@ -76,18 +73,12 @@ export class NavViewport {
* @param shouldAnimate whether to animate
*/
pop({ sync = false } = {}) {
let opts = {sync}
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)
}
previous && previous.enter( util.extend({reverse:true}, opts) )
return current && current.leave(opts).then(remove)
}
getPrevious(item) {
@@ -102,7 +93,6 @@ export class NavViewport {
// Animate an old view *out*
_animateOut(view) {
}
}
class NavItem {
@@ -137,33 +127,28 @@ class NavItem {
_animate({ isShown, animation }) {
this.setAnimation(animation)
this.setShown(isShown)
// We have to wait two rafs for the element to show. Yawn.
return domUtil.rafPromise().then(domUtil.rafPromise).then(() => {
this.startAnimation()
return domUtil.transitionEndPromise(this.navView.domElement).then(() => {
this.setAnimation(null)
if (animation) {
// We have to wait two rafs for the element to show. Yawn.
return util.dom.rafPromise().then(util.dom.rafPromise).then(() => {
this.startAnimation()
return util.dom.transitionEndPromise(this.navView.domElement).then(() => {
this.setAnimation(null)
})
})
} else {
return Promise.resolve()
}
}
enter({ reverse = false, sync = false } = {}) {
return this._animate({
isShown: true,
animation: sync ? null : (reverse ? 'enter-reverse' : 'enter')
})
}
enterSync() {
this.setAnimation(null)
return this.setShown(true)
}
leaveSync() {
this.setAnimation(null)
return this.setShown(false)
}
enter() {
return this._animate({ isShown: true, animation: 'enter' })
}
enterReverse() {
return this._animate({ isShown: true, animation: 'enter-reverse' })
}
leave() {
return this._animate({ isShown: false, animation: 'leave' })
}
leaveReverse() {
return this._animate({ isShown: false, animation: 'leave-reverse' })
leave({ reverse = false, sync = false } = {}) {
return this._animate({
isShown: false,
animation: sync ? null : (reverse ? 'leave-reverse' : 'leave')
})
}
}

View File

@@ -0,0 +1,4 @@
export class SplitNavView extends NavView {
}

View File

@@ -0,0 +1,78 @@
import {Component, Parent, Decorator, Template, NgElement} from 'angular2/angular2'
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'
/**
* SplitViewportDecorator is temporary until the SplitView is able to query
* its children for viewports.
*/
@Decorator({
selector: 'ion-nav-viewport[split-viewport]'
})
class SplitViewportDecorator {
constructor(
@Parent() splitView: SplitView,
navViewport: NavViewport
) {
splitView.setNavViewport(navViewport)
}
}
@Component({
selector: 'ion-split-view',
bind: {
defaultView: 'defaultView',
viewTitle: 'viewTitle'
}
})
@Template({
inline: `
<ion-view [view-title]="viewTitle">
<div class="split-pane-container">
<content></content>
</div>
</ion-view>
<ion-nav-viewport split-viewport>
</ion-nav-viewport>
`,
directives: [SplitViewportDecorator, NavViewport, View]
})
export class SplitView {
constructor(
element: NgElement,
@Parent() navView: NavView
) {
this.domElement = element.domElement
this.navView = navView
}
set defaultView(def) {
this.splitViewport.push(def)
}
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.splitViewport.push(Class, opts)
}
}
}
// TODO set enabled depending on some condition (media query in this case)
setEnabled(isEnabled) {
this.isSplitView = isEnabled
if (isEnabled) {
}
}
}

View File

@@ -0,0 +1,16 @@
import {Component, Template} from 'angular2/angular2'
import {View} from 'ionic2/components'
@Component({
selector: 'settings-general'
})
@Template({
inline: `
<ion-view view-title="General">
General Settings
</ion-view>
`,
directives: [View]
})
export class SettingsGeneral {
}

View File

@@ -0,0 +1,2 @@
<ion-nav-viewport [initial]="initial">
</ion-nav-viewport>

View File

@@ -0,0 +1,38 @@
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

@@ -46,5 +46,4 @@ export class Tab extends NavViewport {
}
}
new IonicComponent(Tab, {
})
new IonicComponent(Tab, {})

View File

@@ -1,5 +1,5 @@
<ion-aside side="left" [content]="viewport">
Hello!
Hello! I'm a side menu in the root.
</ion-aside>
<ion-nav-viewport #viewport [initial]="initial">
</ion-nav-viewport>

View File

@@ -3,7 +3,7 @@ import {NavViewport, Aside} from 'ionic2/components'
import {SignInPage} from 'app/pages/sign-in'
@Component({
selector: '[ion-app]'
selector: '[ion-app]',
})
@Template({
url: 'main.html',

View File

@@ -1,5 +1,5 @@
import {Component, Template, Parent} from 'angular2/angular2'
import {View, NavViewport} from 'ionic2/components'
import {Component, Template} from 'angular2/angular2'
import {View, NavView} from 'ionic2/components'
import {TabsPage} from 'app/pages/tabs'
@Component({
@@ -11,11 +11,11 @@ import {TabsPage} from 'app/pages/tabs'
})
export class SignInPage {
constructor(
@Parent() viewport: NavViewport
navView: NavView
) {
this.viewport = viewport
this.navView = navView
}
signIn() {
this.viewport.push(TabsPage)
this.navView.push(TabsPage)
}
}

View File

@@ -1,6 +1,6 @@
import {Component, Template, Parent} from 'angular2/angular2'
import {View, Tabs, Tab} from 'ionic2/components'
import {NavViewport} from 'ionic2/components'
import {View, Tabs, Tab, Aside} from 'ionic2/components'
import {NavView} from 'ionic2/components'
@Component({
selector: 'tabs-page'
@@ -26,11 +26,11 @@ export class TabsPage {
directives: [View]
})
class Tab1Page1 {
constructor(@Parent() tab: Tab) {
this.tab = tab
constructor(navView: NavView) {
this.navView = navView
}
next() {
this.tab.push(Tab1Page2)
this.navView.push(Tab1Page2)
}
}
@@ -40,8 +40,10 @@ class Tab1Page1 {
directives: [View]
})
class Tab1Page2 {
constructor(@Parent() tab: Tab) { this.tab = tab }
pop() { this.tab.pop() }
constructor(navView: NavView) {
this.navView = navView
}
pop() { this.navView.pop() }
}
@@ -50,15 +52,22 @@ class Tab1Page2 {
//
@Component({ selector: 't2p1' })
@Template({
inline: '<ion-view nav-title="Tab 2 Page 1"><br/><br/>Tab 2 Page 1. <button (click)="next()">Next</button></ion-view>',
directives: [View]
inline: `
<ion-aside side="left" [content]="view">Hello, I'm a deeper aside.</ion-aside>
<ion-view nav-title="Tab 2 Page 1" #view>
<br/><br/>Tab 2 Page 1.
<button (click)="next()">Next</button>
<br/><span style="color:red">I've got an aside on the left.</span>
</ion-view>
`,
directives: [View, Aside]
})
class Tab2Page1 {
constructor(@Parent() tab: Tab) {
this.tab = tab
constructor(navView: NavView) {
this.navView = navView
}
next() {
this.tab.push(Tab2Page2)
this.navView.push(Tab1Page2)
}
}
@@ -68,6 +77,8 @@ class Tab2Page1 {
directives: [View]
})
class Tab2Page2 {
constructor(@Parent() tab: Tab) { this.tab = tab }
pop() { this.tab.pop() }
constructor(navView: NavView) {
this.navView = navView
}
pop() { this.navView.pop() }
}

View File

@@ -17,17 +17,20 @@ export class DragGesture extends Gesture {
if (this.onDragStart(ev) !== false) {
this.dragging = true;
}
});
// ev.stopPropagation();
})
this.on('panmove', ev => {
if (!this.dragging) return;
if (this.onDrag(ev) === false) {
this.dragging = false;
}
// ev.stopPropagation()
});
this.on('panend', ev => {
if (!this.dragging) return;
this.onDragEnd(ev);
this.dragging = false;
// ev.stopPropagation()
});
}
onDrag() {}

View File

@@ -3,6 +3,9 @@ import Hammer from 'hammer';
export class Gesture {
constructor(element, opts = {}) {
util.defaults(opts, {
domEvents: true
});
this.element = element;
// Map 'x' or 'y' string to hammerjs opts
@@ -12,14 +15,17 @@ export class Gesture {
Hammer.DIRECTION_VERTICAL;
this._options = opts;
this._callbacks = {};
}
options(opts = {}) {
util.extend(this._options, opts);
}
on(...args) {
return this.hammertime.on.apply(this.hammertime, args)
on(type, cb) {
this.hammertime.on(type, util.noop);
(this._callbacks[type] || (this._callbacks[type] = [])).push(cb);
this.element.addEventListener(type, cb);
}
listen() {
@@ -28,6 +34,12 @@ export class Gesture {
unlisten() {
this.hammertime.destroy();
this.hammertime = null;
for (let type in this._callbacks) {
for (let i = 0; i < this._callbacks[type].length; i++) {
this.element.removeEventListener(type, this._callbacks[type][i]);
}
}
this._callbacks = {}
}
destroy() {
this.unlisten()

View File

@@ -15,7 +15,7 @@ export class SlideEdgeGesture extends SlideGesture {
canStart(ev) {
this._containerRect = this.getContainerDimensions();
return this.edges.every(edge => this._checkEdge(edge, ev.center));
return this.edges.every(edge => this._checkEdge(edge, ev.gesture.center));
}
getContainerDimensions() {

View File

@@ -40,7 +40,7 @@ export class SlideGesture extends DragGesture {
this.slide.min = min;
this.slide.max = max;
this.slide.elementStartPos = this.getElementStartPos(this.slide, ev);
this.slide.pointerStartPos = ev.center[this.direction];
this.slide.pointerStartPos = ev.gesture.center[this.direction];
this.slide.started = true;
this.onSlideStart(this.slide, ev);
}).catch(() => {
@@ -49,7 +49,7 @@ export class SlideGesture extends DragGesture {
}
onDrag(ev) {
if (!this.slide || !this.slide.started) return;
this.slide.pos = ev.center[this.direction];
this.slide.pos = ev.gesture.center[this.direction];
this.slide.distance = util.clamp(
this.slide.min,
this.slide.pos - this.slide.pointerStartPos + this.slide.elementStartPos,

2
src/ionic2.js Normal file
View File

@@ -0,0 +1,2 @@
export * from 'ionic2/components'