diff --git a/gulpfile.js b/gulpfile.js
index 760f9e28b8..dd3f1c9cd6 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -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) {
diff --git a/scripts/build/config.js b/scripts/build/config.js
index 803174c84f..4105f453e0 100644
--- a/scripts/build/config.js
+++ b/scripts/build/config.js
@@ -29,6 +29,7 @@ module.exports = {
'long-stack-trace-zone.js',
'hammer.js',
'angular2.js',
+ 'ionic2.js',
],
traceurOptions: {
diff --git a/src/components.js b/src/components.js
index 4698481368..3e693abec7 100644
--- a/src/components.js
+++ b/src/components.js
@@ -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'
diff --git a/src/components/aside/aside.js b/src/components/aside/aside.js
index 512465efab..33c69f85d1 100644
--- a/src/components/aside/aside.js
+++ b/src/components/aside/aside.js
@@ -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: {
diff --git a/src/components/aside/extensions/gestures.js b/src/components/aside/extensions/gestures.js
index 6d3e44303a..69ebc861d1 100644
--- a/src/components/aside/extensions/gestures.js
+++ b/src/components/aside/extensions/gestures.js
@@ -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 {
};
}
}
-
diff --git a/src/components/nav-view/nav-view.js b/src/components/nav-view/nav-view.js
index 1d63c56623..b2c8feb694 100644
--- a/src/components/nav-view/nav-view.js
+++ b/src/components/nav-view/nav-view.js
@@ -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?)
+ */
diff --git a/src/components/nav-viewport/nav-viewport.js b/src/components/nav-viewport/nav-viewport.js
index 959785066b..f0770a729b 100644
--- a/src/components/nav-viewport/nav-viewport.js
+++ b/src/components/nav-viewport/nav-viewport.js
@@ -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')
+ })
}
}
-
diff --git a/src/components/split-view/split-nav-view.js b/src/components/split-view/split-nav-view.js
new file mode 100644
index 0000000000..5141b587fe
--- /dev/null
+++ b/src/components/split-view/split-nav-view.js
@@ -0,0 +1,4 @@
+
+export class SplitNavView extends NavView {
+
+}
diff --git a/src/components/split-view/split-view.js b/src/components/split-view/split-view.js
new file mode 100644
index 0000000000..d048a42007
--- /dev/null
+++ b/src/components/split-view/split-view.js
@@ -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: `
+
+
+
+
+
+
+
+ `,
+ 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) {
+ }
+ }
+}
diff --git a/src/components/split-view/test/settings/groups/general.js b/src/components/split-view/test/settings/groups/general.js
new file mode 100644
index 0000000000..182c02ddf2
--- /dev/null
+++ b/src/components/split-view/test/settings/groups/general.js
@@ -0,0 +1,16 @@
+import {Component, Template} from 'angular2/angular2'
+import {View} from 'ionic2/components'
+
+@Component({
+ selector: 'settings-general'
+})
+@Template({
+ inline: `
+
+ General Settings
+
+ `,
+ directives: [View]
+})
+export class SettingsGeneral {
+}
diff --git a/src/components/split-view/test/settings/main.html b/src/components/split-view/test/settings/main.html
new file mode 100644
index 0000000000..9de8f8a062
--- /dev/null
+++ b/src/components/split-view/test/settings/main.html
@@ -0,0 +1,2 @@
+
+
diff --git a/src/components/split-view/test/settings/main.js b/src/components/split-view/test/settings/main.js
new file mode 100644
index 0000000000..9d9ec72f40
--- /dev/null
+++ b/src/components/split-view/test/settings/main.js
@@ -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: `
+
+ Hello, split
+
+ `,
+ directives: [SplitView]
+})
+class SettingsSplit {
+ constructor() {
+ this.default = SettingsGeneral
+ }
+}
+
+@Component({
+ selector: '[ion-app]'
+})
+@Template({
+ inline: `
+
+
+ `,
+ directives: [NavViewport]
+})
+class App {
+ constructor() {
+ this.initial = SettingsSplit
+ }
+}
+
+bootstrap(App)
diff --git a/src/components/tabs/tab.js b/src/components/tabs/tab.js
index 5edf451e21..2fc3de83e9 100644
--- a/src/components/tabs/tab.js
+++ b/src/components/tabs/tab.js
@@ -46,5 +46,4 @@ export class Tab extends NavViewport {
}
}
-new IonicComponent(Tab, {
-})
+new IonicComponent(Tab, {})
diff --git a/src/components/tabs/test/advanced/main.html b/src/components/tabs/test/advanced/main.html
index 4757597ce9..1569d08797 100644
--- a/src/components/tabs/test/advanced/main.html
+++ b/src/components/tabs/test/advanced/main.html
@@ -1,5 +1,5 @@
- Hello!
+ Hello! I'm a side menu in the root.
diff --git a/src/components/tabs/test/advanced/main.js b/src/components/tabs/test/advanced/main.js
index ce0fca7ab8..46ccf1d2c2 100644
--- a/src/components/tabs/test/advanced/main.js
+++ b/src/components/tabs/test/advanced/main.js
@@ -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',
diff --git a/src/components/tabs/test/advanced/pages/sign-in.js b/src/components/tabs/test/advanced/pages/sign-in.js
index f4cb94ef8f..8674d413cd 100644
--- a/src/components/tabs/test/advanced/pages/sign-in.js
+++ b/src/components/tabs/test/advanced/pages/sign-in.js
@@ -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)
}
}
diff --git a/src/components/tabs/test/advanced/pages/tabs.js b/src/components/tabs/test/advanced/pages/tabs.js
index 7b77a0c6b5..2977dde5bf 100644
--- a/src/components/tabs/test/advanced/pages/tabs.js
+++ b/src/components/tabs/test/advanced/pages/tabs.js
@@ -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: '
Tab 2 Page 1. ',
- directives: [View]
+ inline: `
+ Hello, I'm a deeper aside.
+
+
Tab 2 Page 1.
+
+
I've got an aside on the left.
+
+ `,
+ 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() }
}
diff --git a/src/gestures/drag-gesture.js b/src/gestures/drag-gesture.js
index 9f974926c1..1530dc43a7 100644
--- a/src/gestures/drag-gesture.js
+++ b/src/gestures/drag-gesture.js
@@ -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() {}
diff --git a/src/gestures/gesture.js b/src/gestures/gesture.js
index 3d212d0c34..c9228e9b7e 100644
--- a/src/gestures/gesture.js
+++ b/src/gestures/gesture.js
@@ -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()
diff --git a/src/gestures/slide-edge-gesture.js b/src/gestures/slide-edge-gesture.js
index ad70fbf428..6656eeb7a9 100644
--- a/src/gestures/slide-edge-gesture.js
+++ b/src/gestures/slide-edge-gesture.js
@@ -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() {
diff --git a/src/gestures/slide-gesture.js b/src/gestures/slide-gesture.js
index e1965bf1bf..3d3f2e9e38 100644
--- a/src/gestures/slide-gesture.js
+++ b/src/gestures/slide-gesture.js
@@ -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,
diff --git a/src/ionic2.js b/src/ionic2.js
new file mode 100644
index 0000000000..5eaa385732
--- /dev/null
+++ b/src/ionic2.js
@@ -0,0 +1,2 @@
+
+export * from 'ionic2/components'