diff --git a/ionic/collide/animation.js b/ionic/collide/animation.js
index f820eb5dc5..50e5889b1d 100644
--- a/ionic/collide/animation.js
+++ b/ionic/collide/animation.js
@@ -9,32 +9,45 @@ const data = Collide.data;
export class Animation {
- constructor() {
+ constructor(ele) {
this.parent = null;
- this._elements = null;
this._options = {};
this._properties = {};
this._resolve = null;
this._call = null;
this.children = [];
+
+ this.elements(ele);
}
- addChild(animation) {
- animation.parent = this;
- this.children.push(animation);
+ addChild(childAnimation) {
+ childAnimation.parent = this;
+ this.children.push(childAnimation);
+ return this;
+ }
+
+ setChildren(childAnimations) {
+ for (let i = 0; i < childAnimations.length; i++) {
+ this.addChild(childAnimations[i]);
+ }
return this;
}
elements(ele) {
- if (ele && ele.length > 0) {
- this._elements = ele;
+ this._ele = [];
- } else if (ele && ele.nodeType) {
- this._elements = [ele];
+ if (ele) {
+ if (typeof ele === 'string') {
+ ele = document.querySelectorAll(ele);
+ }
- } else {
- this._elements = null;
+ if (ele.length) {
+ this._ele = ele;
+
+ } else if (ele.nodeType) {
+ this._ele.push(ele);
+ }
}
return this;
@@ -51,8 +64,8 @@ export class Animation {
this.stop();
}
- if (this._elements && this._elements.length) {
- this._promise = new Promise(res => {
+ if (this._ele.length) {
+ let promise = new Promise(res => {
this._resolve = res;
});
@@ -85,35 +98,35 @@ export class Animation {
var opts = util.extend({}, Collide.defaults);
- if (this.parent && this.parent._options) {
+ if (this.parent) {
opts = util.extend(opts, this.parent._options);
}
this._options = util.extend(opts, this._options);
// get the elements ready
- for (var i = 0, ii = this._elements.length; i < ii; i++) {
+ for (var i = 0, ii = this._ele.length; i < ii; i++) {
processElement('start', this, i, clearCache);
}
onNextFrame();
});
- } else {
- this._promise = Promise.resolve();
+ return promise;
}
+ return Promise.resolve();
}
_queueAnimation() {
- if (this._elements) {
+ if (this._ele.length) {
if (this._call === null) {
return;
}
var eleData;
- for (var i = 0, ii = this._elements.length, element; i < ii && (element = this._elements[i]); i++) {
+ for (var i = 0, ii = this._ele.length, element; i < ii && (element = this._ele[i]); i++) {
if (element) {
eleData = data(element);
if (eleData) {
@@ -141,7 +154,7 @@ export class Animation {
/* Add the current call plus its associated metadata (the element set and the call's options) onto the global call container.
Anything on this call container is subjected to tick() processing. */
Collide.State.calls.push([ this._call,
- this._elements,
+ this._ele,
this._options,
null,
this._resolve ]);
@@ -160,12 +173,12 @@ export class Animation {
var clearCache = (this._aniType !== 'start');
- this._setupElements(clearCache, () => {
+ var promise = this._setupElements(clearCache, () => {
this._aniType = 'start';
this._queueAnimation();
});
- promises.push(this._promise);
+ promises.push(promise);
return Promise.all(promises);
}
@@ -178,25 +191,25 @@ export class Animation {
);
}
- var clearCache = (this._aniType !== 'percent');
+ var clearCache = (this._aniType !== 'progress');
- this._setupElements(clearCache, () => {
- this._aniType = 'percent';
+ var promise = this._setupElements(clearCache, () => {
+ this._aniType = 'progress';
});
- promises.push(this._promise);
+ promises.push(promise);
return Promise.all(promises);
}
- percent(percentComplete) {
+ progress(value) {
// go to and stop at a specific point in the animation
- if (this._aniType = 'percent') {
- this._options.percentComplete = percentComplete;
+ if (this._aniType = 'progress') {
+ this._options.percentComplete = value;
for (var i = 0; i < this.children.length; i++) {
- this.children[i].percent(percentComplete);
+ this.children[i].progress(value);
}
this._queueAnimation();
@@ -205,21 +218,21 @@ export class Animation {
stop() {
// immediately stop where it's at
- animationStop(this._elements, 'stop');
+ animationStop(this._ele, 'stop');
return this;
}
finish() {
// immediately go to the end of the animation
- animationStop(this._elements, 'finish');
+ animationStop(this._ele, 'finish');
return this;
}
isAnimating() {
var eleData;
- if (this._elements) {
- for (var i = 0, ii = this._elements.length; i < ii; i++) {
- eleData = data(this._elements[i]);
+ if (this._ele) {
+ for (var i = 0, ii = this._ele.length; i < ii; i++) {
+ eleData = data(this._ele[i]);
if (eleData && eleData.isAnimating) {
return true;
}
@@ -242,11 +255,6 @@ export class Animation {
return this;
}
- removeOption(key) {
- delete this._options[key];
- return this;
- }
-
duration(val) {
this._options.duration = val;
return this;
@@ -257,23 +265,40 @@ export class Animation {
return this;
}
+ display(val) {
+ this._options.display = val;
+ return this;
+ }
+
/***************
Properties
***************/
+ from(propertyName, value) {
+ // [endValue, easing, startValue]
+ let prop = this.getProperty(propertyName);
+ prop[2] = value;
+ return this;
+ }
+
to() {
+ // [endValue, easing, startValue]
if (arguments.length > 1) {
- this._properties[ arguments[0] ] = arguments[1];
+ let prop = this.getProperty(arguments[0]);
+ prop[0] = arguments[1];
} else {
this._properties = arguments[0] || {};
}
return this;
}
- removeProperty(key) {
- delete this._properties[key];
- return this;
+ getProperty(propertyName) {
+ // [endValue, easing, startValue]
+ if (!this._properties[propertyName]) {
+ this._properties[propertyName] = [null, null, null];
+ }
+ return this._properties[propertyName];
}
diff --git a/ionic/collide/process-element.js b/ionic/collide/process-element.js
index 42dfe709e0..d3113171dc 100644
--- a/ionic/collide/process-element.js
+++ b/ionic/collide/process-element.js
@@ -20,7 +20,7 @@ const data = Collide.data;
*/
export function processElement(action, animation, elementIndex, clearCache) {
- var elements = animation._elements;
+ var elements = animation._ele;
var elementsLength = elements.length;
var element = elements[elementIndex];
@@ -254,36 +254,9 @@ export function processElement(action, animation, elementIndex, clearCache) {
The optional third parameter is a forcefed startValue to be used instead of querying the DOM for
the element's current value. */
function parsePropertyValue(valueData, skipResolvingEasing) {
- var endValue = undefined,
- easing = undefined,
- startValue = undefined;
-
- /* Handle the array format, which can be structured as one of three potential overloads:
- A) [ endValue, easing, startValue ], B) [ endValue, easing ], or C) [ endValue, startValue ] */
- if (Array.isArray(valueData)) {
- /* endValue is always the first item in the array. Don't bother validating endValue's value now
- since the ensuing property cycling logic does that. */
- endValue = valueData[0];
-
- /* Two-item array format: If the second item is a number, function, or hex string, treat it as a
- start value since easings can only be non-hex strings or arrays. */
- if ((!Array.isArray(valueData[1]) && /^[\d-]/.test(valueData[1])) || typeof valueData[1] === 'function' || CSS.RegEx.isHex.test(valueData[1])) {
- startValue = valueData[1];
-
- /* Two or three-item array: If the second item is a non-hex string or an array, treat it as an easing. */
- } else if ((util.isString(valueData[1]) && !CSS.RegEx.isHex.test(valueData[1])) || Array.isArray(valueData[1])) {
- easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration);
-
- /* Don't bother validating startValue's value now since the ensuing property cycling logic inherently does that. */
- if (valueData[2] !== undefined) {
- startValue = valueData[2];
- }
- }
-
- } else {
- /* Handle the single-value format. */
- endValue = valueData;
- }
+ var endValue = valueData[0];
+ var easing = skipResolvingEasing ? valueData[1] : getEasing(valueData[1], opts.duration);
+ var startValue = valueData[2];
/* Default to the call's easing if a per-property easing type was not defined. */
if (!skipResolvingEasing) {
diff --git a/ionic/components/nav/test/basic/main.html b/ionic/components/nav/test/basic/main.html
index a942ebb790..946b4caa4a 100644
--- a/ionic/components/nav/test/basic/main.html
+++ b/ionic/components/nav/test/basic/main.html
@@ -1,2 +1,14 @@
+
+
diff --git a/ionic/transitions/ios-transition.js b/ionic/transitions/ios-transition.js
index 7f8fb1e623..6f433cdf64 100644
--- a/ionic/transitions/ios-transition.js
+++ b/ionic/transitions/ios-transition.js
@@ -6,6 +6,12 @@ import {Transition} from './transition'
const EASING_FN = [.36, .66, .04, 1];
const DURATION = 500;
+const OFF_RIGHT = '100%';
+const OFF_LEFT = '-33%';
+const OFF_OPACITY = 0.8;
+
+const TRANSLATE_X = 'translateX';
+const OPACITY = 'opacity';
class IOSTransition extends Animation {
@@ -13,6 +19,7 @@ class IOSTransition extends Animation {
constructor(navCtrl, opts) {
super();
+ // global duration and easing for all child animations
this.duration(DURATION);
this.easing('ios');
@@ -20,30 +27,52 @@ class IOSTransition extends Animation {
this.enteringItem = navCtrl.getStagedEnteringItem();
this.leavingItem = navCtrl.getStagedLeavingItem();
- // create animation for entering item
- let enteringItemAnimation = new Animation();
- enteringItemAnimation.elements(this.enteringItem.navItem.domElement);
+ // create animation for the entering item
+ let enteringItemAnimation = new Animation(this.enteringItem.navItem.domElement);
- // show the item
- this.enteringItem.navItem.domElement.style.display = 'block';
+ // create animation for the leaving item
+ // leavingItem could be null, but the animation instance knows to do nothing
+ let leavingItemAnimation = new Animation(this.leavingItem && this.leavingItem.navItem.domElement);
+ // entering item moves to center
+ // before starting, set enteringItem to display: block
+ enteringItemAnimation
+ .display('block')
+ .to(TRANSLATE_X, 0)
+ .to(OPACITY, 1);
+
+ // leaving view moves off screen
+ // when completed, set leavingItem to display: none
+ leavingItemAnimation
+ .from(TRANSLATE_X, 0)
+ .from(OPACITY, 1)
+ .display('none');
+
+ // set properties depending on direction
if (opts.direction === 'back') {
// back direction
- this.enteringItem.navItem.domElement.style.transform = 'translateX(-33%)';
- if (this.leavingItem) {
- this.leavingItem.navItem.domElement.style.display = '';
- }
+ enteringItemAnimation
+ .from(TRANSLATE_X, OFF_LEFT)
+ .from(OPACITY, OFF_OPACITY)
+ .to(OPACITY, 1);
+
+ leavingItemAnimation
+ .to(TRANSLATE_X, OFF_RIGHT)
+ .to(OPACITY, 1);
} else {
// forward direction
- this.enteringItem.navItem.domElement.style.transform = 'translateX(100%)';
+ enteringItemAnimation
+ .from(TRANSLATE_X, OFF_RIGHT)
+ .from(OPACITY, 1);
+ leavingItemAnimation
+ .to(TRANSLATE_X, OFF_LEFT)
+ .to(OPACITY, OFF_OPACITY);
}
- // entering item moves to dead center
- enteringItemAnimation.to('translateX', ['0%', '100%']);
-
- this.addChild(enteringItemAnimation);
+ // set child animations
+ this.setChildren([enteringItemAnimation, leavingItemAnimation]);
}
stage() {