initial version of switching with animations. needs work for logic

This commit is contained in:
Andrew
2015-04-01 18:07:52 -06:00
parent c20e510147
commit 48f7d6bd26
18 changed files with 280 additions and 178 deletions

View File

@ -35,5 +35,11 @@
"rx": "^2.4.6",
"traceur": "0.0.87",
"zone.js": "0.4.1"
},
"registry": "jspm",
"directories": {
"baseURL": "n",
"lib": "n",
"packages": "n/jspm_packages"
}
}

View File

@ -5,6 +5,7 @@ export * from 'ionic2/components/icon/icon'
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/tabs/tabs'
export * from 'ionic2/components/toolbar/toolbar'
export * from 'ionic2/components/view/view'

View File

@ -32,6 +32,7 @@
"../item/item",
"../list/list",
"../modal/modal",
"../nav-view/nav-view",
"../radio/radio",
"../search-bar/search-bar",
"../switch/switch",

View File

@ -10,14 +10,11 @@ export class ItemPrimarySwipeButtons {
@NgElement() element: NgElement,
@Parent() item: Item
) {
item.primarySwipeButtons = this
this.domElement = element.domElement
this.parentItem = item
this.gesture = new ItemSlideGesture(this)
this.gesture.listen()
this.domElement.addEventListener('transitionend', () => {
this.domElement.classList.remove('changing')
})
}
setOpen(isOpen) {

View File

@ -27,20 +27,82 @@ import {
<content select="ion-secondary-options"></content>
<content select="ion-secondary-swipe-buttons"></content>
`,
direcetives: [
directives: [
ItemPrimarySwipeButtons,
ItemSecondarySwipeButtons,
ItemPrimaryOptions,
ItemSecondaryOptions
// ItemSecondarySwipeButtons,
// ItemPrimaryOptions,
// ItemSecondaryOptions
]
})
export class Item {
constructor(
@NgElement() ele:NgElement
) {
this._isOpen = false
this._isSlideActive = false
this._isTransitioning = false
this._transform = ''
this.domElement = ele.domElement
this.swipeButtons = {}
this.optionButtons = {}
Item.config.invoke(this)
}
}
new IonicComponent(Item, {})
function clsSetter(el, name) {
return (isSet) => el.classList[isSet?'add':'remove'](name)
}
import {dom} from 'ionic2/util'
class Slideable {
constructor(slideElement: Element) {
}
// override
onTransform(str: String) {}
// override
onTransitionActive(active: Boolean) {}
//override
onSlideActive(active: boolean) {}
transform(str: String) {
if (arguments.length && str !== this._transform) {
this.onTransform()
}
}
isTransitionActive(active: Boolean) {
if (arguments.length && active !== this._isTransitionActive) {
this._isTransitionActive = active
this.onSetTransitionActive(active)
}
return this._isTransitioning
}
isSlideActive(active: Boolean) {
if (arguments.length && active !== this._isSlideActive) {
this._isSlideActive = active
this.onSetDragActive(active)
}
return this._isSlideActive
}
isOpen(open: Boolean) {
if (arguments.length && open !== this._isOpen) {
this.isTransitionActive(true)
dom.rafPromise().then(() => {
this.isOpen = isOpen
this.onSetIsOpen(open)
})
}
}
}
class ItemSlideGesture {
}

View File

@ -1,171 +1,30 @@
import {Component, Template, NgElement} from 'angular2/angular2'
import {ComponentConfig} from 'ionic2/config/component-config'
import {Log} from 'ionic2/util'
import {Compiler} from 'angular2/src/core/compiler/compiler'
import {EventManager} from 'angular2/src/core/events/event_manager'
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location'
import {DynamicComponent, Parent, NgElement} from 'angular2/angular2'
import {NavViewport} from 'ionic2/components'
import {PrivateComponentLoader} from 'angular2/src/core/compiler/private_component_loader'
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'
import {ShadowDomStrategy} from 'angular2/src/core/compiler/shadow_dom_strategy'
import {PrivateComponentLocation} from 'angular2/src/core/compiler/private_component_location'
@Component({
selector: 'ion-nav',
@DynamicComponent({
selector: '.nav-view',
bind: {
initial: 'initial'
},
services: []
})
@Template({
inline: `<content></content>`
item: 'item'
}
})
export class NavView {
constructor(
@NgElement() element: NgElement,
eventManager: EventManager,
compiler: Compiler,
location: PrivateComponentLocation,
loader: PrivateComponentLoader,
directiveMetadataReader: DirectiveMetadataReader,
shadowDomStrategy: ShadowDomStrategy
location: PrivateComponentLocation,
@Parent() viewport: NavViewport,
@NgElement() element: NgElement
) {
this.attacher = new Attacher({
compiler,
element,
location,
loader,
directiveMetadataReader,
eventManager,
shadowDomStrategy
})
this._children = []
console.log('Nav View constructed')
}
set initial(Type) {
if (!this.initialized) {
this.initialized = true
this.push(Type)
}
}
/**
* Push a new view into the history stack.
*
* @param view the new view
* @param shouldAnimate whether to animate
*/
push(Type, shouldAnimate) {
//TODO animation
let current = this._children[this._children.length - 1]
current && current.hide()
this.attacher.attachComponent(Type).then(child => {
this._children.push(child)
})
Log.log('NAV: PUSH', Type.name, 'Animate?', shouldAnimate)
}
/**
* Pop a view off the history
*
* @param shouldAnimate whether to animate
*/
pop(shouldAnimate) {
// TODO animation
let current = this._children.pop()
if (current) {
current.remove()
}
let last = this._children[this._children.length - 1]
if (last) {
last.show()
}
return last
}
get views() {
return this._views
}
/**
* Set the view stack explicitly.
*/
set views(v) {
this._views = v
}
// Animate a new view *in*
_animateIn(view) {
}
// Animate an old view *out*
_animateOut(view) {
}
}
class Attacher {
constructor({
location,
element,
directiveMetadataReader,
compiler,
shadowDomStrategy,
eventManager
}) {
this.loader = loader
this.location = location
this.element = element
this.directiveMetadataReader = directiveMetadataReader
this.compiler = compiler
this.shadowDomStrategy = shadowDomStrategy
this.eventManager = eventManager
this.viewport = viewport
this.domElement = element.domElement
}
attachComponent(Type) {
let parentInjector = this.location._elementInjector
let childInjector = parentInjector._proto.instantiate(
/* parent */ parentInjector,
/* host */ null
)
let childContainer = document.createElement('div')
childContainer.classList.add('test-child-container')
this.element.domElement.appendChild(childContainer)
let childNgElement = new NgElement(childContainer)
childInjector._preBuiltObjects = parentInjector._preBuiltObjects
childInjector._preBuiltObjects.element = childNgElement
let annotation = this.directiveMetadataReader.read(Type).annotation
return this.compiler.compile(Type).then((protoView) => {
let context = childInjector.createPrivateComponent(Type, annotation);
let view = protoView.instantiate(childInjector, this.eventManager)
view.hydrate(parentInjector.getShadowDomAppInjector(), childInjector, null, context, null)
this.shadowDomStrategy.attachTemplate(childNgElement.domElement, view)
this.location._view.componentChildViews.push(view)
this.location._view.changeDetector.addChild(view.changeDetector)
return {
remove() {
// TODO actually remove it from the angular tree
// setTimeout(() => { view.dehydrate() })
childContainer.parentNode.removeChild(childContainer)
},
hide() {
// view.dehydrate()
childContainer.style.display = 'none'
},
show() {
childContainer.style.display = ''
// view.hydrate()
},
}
set item(navItem) {
this.loader.load(navItem.Class, this.location).then(instance => {
navItem.finishSetup(this, instance)
})
}
}

View File

@ -0,0 +1,16 @@
.nav-view {
opacity: 0;
transition: 0.25s;
width: 100%;
height: 100%;
}
.nav-view.in {
opacity: 1;
}
.nav-view.out {
position: absolute;
top: 0;
left: 0;
opacity: 0;
}

View File

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

View File

@ -0,0 +1,143 @@
import {Component, Template, For} from 'angular2/angular2'
import {ComponentConfig} from 'ionic2/config/component-config'
import {NavView} from 'ionic2/components/nav-view/nav-view'
import * as util from 'ionic2/util'
@Component({
selector: 'ion-nav-viewport',
bind: {
initial: 'initial'
},
})
@Template({
inline: `
<section class="nav-view" *for="#item of stack.rawItems()" [item]="item">
</section>
`,
directives: [NavView, For]
})
export class NavViewport {
constructor(
) {
this.stack = new NavStack();
}
set initial(Class) {
if (!this.initialized) {
this.initialized = true
this.push(Class)
}
}
getAnimation(opts) {
return 'fade'
}
/**
* Push a new view into the history stack.
*
* @param view the new view
* @param shouldAnimate whether to animate
*/
push(Class, opts = {}) {
//TODO animation
return this.stack.push(Class)
}
/**
* Pop a view off the history
*
* @param shouldAnimate whether to animate
*/
pop() {
// TODO animation
return this.stack.pop()
}
// Animate a new view *in*
_animateIn(view) {
}
// Animate an old view *out*
_animateOut(view) {
}
}
class NavStack {
constructor(navView) {
// array to communicate with angular for loop. When an element is in this array, it really
// exists in the DOM.
this._array = []
}
rawItems() {
return this._array
}
push(ComponentClass) {
const item = new NavStackItem(ComponentClass)
let last = this._array[this._array.length - 1]
this._array.push(item)
return item.setupPromise.then(() => {
// Once the item is successfully instantiated, add it to our public history
item.animateIn()
last && last.animateOut()
})
}
pop() {
// public registry: instantly remove to make the removal seem 'synchronous' for our data
const current = this._array[this._array.length - 1]
const previous = this._array[this._array.length - 2]
current.animateOut().then(() => {
util.array.remove(current)
})
return previous && previous.animateIn()
}
}
class NavStackItem {
constructor(ComponentClass) {
this.setupPromise = new Promise((resolve) => {
this.finishSetup = (navView, componentInstance) => {
this.navView = navView
this.instance = componentInstance
resolve()
}
})
this.Class = ComponentClass
}
setInstance(instance) {
this.instance = instance
}
setNavView(navView) {
this.navView = navView
}
animateIn() {
this.navView.domElement.classList.remove('out')
this.navView.domElement.classList.add('in')
return new Promise(resolve => {
this.navView.domElement.addEventListener('transitionend', (ev) => {
if (ev.target !== this.navView.domElement) {
return
}
resolve()
})
})
}
animateOut() {
this.navView.domElement.classList.add('out')
this.navView.domElement.classList.remove('in')
return new Promise(resolve => {
this.navView.domElement.addEventListener('transitionend', (ev) => {
if (ev.target !== this.navView.domElement) {
return
}
resolve()
})
})
}
}

View File

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

View File

@ -1,12 +1,12 @@
import {bootstrap} from 'angular2/core'
import {Component, Template} from 'angular2/angular2'
import {NavView} from 'ionic2/components/nav-view/nav-view'
import {NavViewport} from 'ionic2/components'
import {Log} from 'ionic2/util'
import {FirstPage} from 'app/pages/first-page'
@Component({ selector: '[ion-app]' })
@Template({
directives: [NavView],
directives: [NavViewport],
url: 'main.html'
})
class IonicApp {

View File

@ -1,5 +1,5 @@
import {Component, Template, Parent} from 'angular2/angular2'
import {NavView} from 'ionic2/components/nav-view/nav-view'
import {NavViewport} from 'ionic2/components'
import {View} from 'ionic2/components/view/view'
import {SecondPage} from 'app/pages/second-page'
@ -12,12 +12,12 @@ import {SecondPage} from 'app/pages/second-page'
})
export class FirstPage {
constructor(
@Parent() navView: NavView
@Parent() viewport: NavViewport
) {
this.navView = navView
this.viewport = viewport
}
nextPage() {
this.navView.push(SecondPage)
this.viewport.push(SecondPage)
}
}

View File

@ -1,5 +1,5 @@
import {Component, Template, Parent} from 'angular2/angular2'
import {NavView} from 'ionic2/components/nav-view/nav-view'
import {NavViewport} from 'ionic2/components'
import {View} from 'ionic2/components/view/view'
@Component({
@ -11,11 +11,11 @@ import {View} from 'ionic2/components/view/view'
})
export class SecondPage {
constructor(
@Parent() navView: NavView
@Parent() viewport: NavViewport
) {
this.navView = navView
this.viewport = viewport
}
prevPage() {
this.navView.pop()
this.viewport.pop()
}
}

View File

@ -12,7 +12,6 @@ export const raf = nativeRaf || function(callback) {
export const rafCancel = nativeRaf ? nativeCancelRaf : function(id) {
return window.cancelTimeout(id)
}
export function rafPromise() {
return new Promise(resolve => raf(resolve))
}
@ -25,9 +24,11 @@ export let css = {}
if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
css.prefix = 'webkit'
css.transition = 'webkitTransition'
css.transform = 'webkitTransform'
css.transitionEnd = 'webkitTransitionEnd transitionend'
} else {
css.prefix = ''
css.transform = 'transform'
css.transition = 'transition'
css.transitionEnd = 'tranistionend'
}

View File

@ -55,6 +55,22 @@ export class Log {
}
}
export let array = {
find(arr, cb) {
for (let i = 0, ii = arr.length; i < ii; i++) {
if (cb(arr[i], i)) return arr[i];
}
},
remove(arr, item) {
const index = arr.indexOf(item)
if (index === -1) {
return false
}
arr.splice(index, 1)
return true
}
}
export function readQueryParams() {
var queryParams = {}
const startIndex = window.location.href.indexOf('?')