mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 11:41:20 +08:00
animation refactor
This commit is contained in:
@ -1,10 +1,10 @@
|
||||
/* Ported from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
/* Forked from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import * as util from 'ionic/util/util'
|
||||
import {Collide} from 'ionic/collide/collide'
|
||||
import {CSS} from 'ionic/collide/css'
|
||||
import {getEasing} from 'ionic/collide/easing'
|
||||
import {tick} from 'ionic/collide/tick'
|
||||
import {Collide} from './collide'
|
||||
import {CSS} from './css'
|
||||
import {getEasing} from './easing'
|
||||
import {tick} from './tick'
|
||||
|
||||
const data = Collide.data;
|
||||
|
||||
@ -18,7 +18,7 @@ const data = Collide.data;
|
||||
3) Pushing: Consolidation of the tween data followed by its push onto the global in-progress calls container.
|
||||
*/
|
||||
|
||||
export function elementProcess(action, elements, elementsIndex, options, propertiesMap) {
|
||||
export function animationProcess(action, elements, elementsIndex, options, propertiesMap, callUnitConversionData, call) {
|
||||
var resolve;
|
||||
var promise = new Promise(function(res) {
|
||||
resolve = res;
|
||||
@ -28,31 +28,6 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
var elementsLength = elements.length;
|
||||
|
||||
|
||||
/**************************
|
||||
Call-Wide Variables
|
||||
**************************/
|
||||
|
||||
/* A container for CSS unit conversion ratios (e.g. %, rem, and em ==> px) that is used to cache ratios across all elements
|
||||
being animated in a single Collide call. Calculating unit ratios necessitates DOM querying and updating, and is therefore
|
||||
avoided (via caching) wherever possible. This container is call-wide instead of page-wide to avoid the risk of using stale
|
||||
conversion metrics across Collide animations that are not immediately consecutively chained. */
|
||||
var callUnitConversionData = {
|
||||
lastParent: null,
|
||||
lastPosition: null,
|
||||
lastFontSize: null,
|
||||
lastPercentToPxWidth: null,
|
||||
lastPercentToPxHeight: null,
|
||||
lastEmToPx: null,
|
||||
remToPx: null,
|
||||
vwToPx: null,
|
||||
vhToPx: null
|
||||
};
|
||||
|
||||
/* A container for all the ensuing tween data and metadata associated with this call. This container gets pushed to the page-wide
|
||||
Collide.State.calls array that is processed during animation ticking. */
|
||||
var call = [];
|
||||
|
||||
|
||||
/*************************
|
||||
Part I: Pre-Queueing
|
||||
*************************/
|
||||
@ -84,8 +59,6 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
******************/
|
||||
|
||||
/* Since queue:false doesn't respect the item's existing queue, we avoid injecting its delay here (it's set later on). */
|
||||
/* Note: Collide rolls its own delay function since jQuery doesn't have a utility alias for $.fn.delay()
|
||||
(and thus requires jQuery element creation, which we avoid since its overhead includes DOM querying). */
|
||||
if (parseFloat(opts.delay) && opts.queue !== false) {
|
||||
Collide.queue(element, opts.queue, function(next) {
|
||||
// This is a flag used to indicate to the upcoming completeCall() function that this queue entry was initiated by Collide.
|
||||
@ -195,21 +168,19 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
/* Scroll also uniquely takes an optional 'container' option, which indicates the parent element that should be scrolled --
|
||||
as opposed to the browser window itself. This is useful for scrolling toward an element that's inside an overflowing parent element. */
|
||||
if (opts.container) {
|
||||
/* Ensure that either a jQuery object or a raw DOM element was passed in. */
|
||||
if (util.isWrapped(opts.container) || util.isNode(opts.container)) {
|
||||
/* Extract the raw DOM element from the jQuery wrapper. */
|
||||
opts.container = opts.container[0] || opts.container;
|
||||
/* Ensure that a raw DOM element was passed in. */
|
||||
if (opts.container.nodeType) {
|
||||
/* Note: Unlike other properties in Collide, the browser's scroll position is never cached since it so frequently changes
|
||||
(due to the user's natural interaction with the page). */
|
||||
scrollPositionCurrent = opts.container['scroll' + scrollDirection]; /* GET */
|
||||
|
||||
/* $.position() values are relative to the container's currently viewable area (without taking into account the container's true dimensions
|
||||
-- say, for example, if the container was not overflowing). Thus, the scroll end value is the sum of the child element's position *and*
|
||||
the scroll container's current scroll position. */
|
||||
scrollPositionEnd = (scrollPositionCurrent + $(element).position()[scrollDirection.toLowerCase()]) + scrollOffset; /* GET */
|
||||
/* CSS.position(element) values are relative to the container's currently viewable area (without taking into
|
||||
account the container's true dimensions, for example, if the container was not overflowing). Thus, the scroll end
|
||||
value is the sum of the child element's position *and* the scroll container's current scroll position. */
|
||||
scrollPositionEnd = (scrollPositionCurrent + CSS.position(element)[scrollDirection.toLowerCase()]) + scrollOffset; /* GET */
|
||||
|
||||
} else {
|
||||
/* If a value other than a jQuery object or a raw DOM element was passed in, default to null so that this option is ignored. */
|
||||
/* If a value other than a raw DOM element was passed in, default to null so that this option is ignored. */
|
||||
opts.container = null;
|
||||
}
|
||||
|
||||
@ -217,12 +188,13 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
/* If the window itself is being scrolled -- not a containing element -- perform a live scroll position lookup using
|
||||
the appropriate cached property names (which differ based on browser type). */
|
||||
scrollPositionCurrent = Collide.State.scrollAnchor[Collide.State['scrollProperty' + scrollDirection]]; /* GET */
|
||||
|
||||
/* When scrolling the browser window, cache the alternate axis's current value since window.scrollTo() doesn't let us change only one value at a time. */
|
||||
scrollPositionCurrentAlternate = Collide.State.scrollAnchor[Collide.State['scrollProperty' + (scrollDirection === 'Left' ? 'Top' : 'Left')]]; /* GET */
|
||||
|
||||
/* Unlike $.position(), $.offset() values are relative to the browser window's true dimensions -- not merely its currently viewable area --
|
||||
and therefore end values do not need to be compounded onto current values. */
|
||||
scrollPositionEnd = $(element).offset()[scrollDirection.toLowerCase()] + scrollOffset; /* GET */
|
||||
/* Unlike CSS.position(element), CSS.offset(element) values are relative to the browser window's true dimensions
|
||||
-- not merely its currently viewable area -- and therefore end values do not need to be compounded onto current values. */
|
||||
scrollPositionEnd = CSS.offset(element)[scrollDirection.toLowerCase()] + scrollOffset; /* GET */
|
||||
}
|
||||
|
||||
/* Since there's only one format that scroll's associated tweensContainer can take, we create it manually. */
|
||||
@ -243,6 +215,8 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
element: element
|
||||
};
|
||||
|
||||
if (Collide.debug) console.log("tweensContainer (scroll): ", tweensContainer.scroll, element);
|
||||
|
||||
|
||||
/******************************************
|
||||
Tween Data Construction (for Reverse)
|
||||
@ -319,6 +293,8 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
if (!util.isEmptyObject(options)) {
|
||||
lastTweensContainer[lastTween].easing = opts.easing;
|
||||
}
|
||||
|
||||
if (Collide.debug) console.log("reverse tweensContainer (" + lastTween + "): " + JSON.stringify(lastTweensContainer[lastTween]), element);
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,7 +337,7 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
/* Property map values can either take the form of 1) a single value representing the end value,
|
||||
or 2) an array in the form of [ endValue, [, easing] [, startValue] ].
|
||||
The optional third parameter is a forcefed startValue to be used instead of querying the DOM for
|
||||
the element's current value. Read Velocity's docmentation to learn more about forcefeeding: VelocityJS.org/#forcefeeding */
|
||||
the element's current value. */
|
||||
function parsePropertyValue(valueData, skipResolvingEasing) {
|
||||
var endValue = undefined,
|
||||
easing = undefined,
|
||||
@ -482,7 +458,7 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
/* Note: Since SVG elements have some of their properties directly applied as HTML attributes,
|
||||
there is no way to check for their explicit browser support, and so we skip skip this check for them. */
|
||||
if (!data(element).isSVG && rootProperty !== 'tween' && CSS.Names.prefixCheck(rootProperty)[1] === false && CSS.Normalizations.registered[rootProperty] === undefined) {
|
||||
//if (Collide.debug) console.log('Skipping [' + rootProperty + '] due to a lack of browser support.');
|
||||
if (Collide.debug) console.log('Skipping [' + rootProperty + '] due to a lack of browser support.');
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -729,7 +705,7 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
unitRatios.vwToPx = callUnitConversionData.vwToPx;
|
||||
unitRatios.vhToPx = callUnitConversionData.vhToPx;
|
||||
|
||||
//if (Collide.debug >= 1) console.log('Unit ratios: ' + JSON.stringify(unitRatios), element);
|
||||
if (Collide.debug >= 1) console.log('Unit ratios: ' + JSON.stringify(unitRatios), element);
|
||||
|
||||
return unitRatios;
|
||||
|
||||
@ -842,7 +818,7 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
easing: easing
|
||||
};
|
||||
|
||||
//if (Collide.debug) console.log('tweensContainer (' + property + '): ' + JSON.stringify(tweensContainer[property]), element);
|
||||
if (Collide.debug) console.log('tweensContainer (' + property + '): ' + JSON.stringify(tweensContainer[property]), element);
|
||||
}
|
||||
|
||||
/* Along with its property data, store a reference to the element itself onto tweensContainer. */
|
||||
@ -878,14 +854,6 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
Anything on this call container is subjected to tick() processing. */
|
||||
Collide.State.calls.push([ call, elements, opts, null, resolve ]);
|
||||
|
||||
/* If the animation tick isn't running, start it. (Collide shuts it off when there are no active calls to process.) */
|
||||
if (Collide.State.isTicking === false) {
|
||||
Collide.State.isTicking = true;
|
||||
|
||||
/* Start the tick loop. */
|
||||
tick();
|
||||
}
|
||||
|
||||
} else {
|
||||
elementsIndex++;
|
||||
}
|
||||
@ -930,13 +898,11 @@ export function elementProcess(action, elements, elementsIndex, options, propert
|
||||
|
||||
/* To fire the first non-custom-queue entry on an element, the element
|
||||
must be dequeued if its queue stack consists *solely* of the current call. (This can be determined by checking
|
||||
for the 'inprogress' item that jQuery prepends to active queue stack arrays.) Regardless, whenever the element's
|
||||
queue is further appended with additional items -- including $.delay()'s or even $.animate() calls, the queue's
|
||||
for the 'inprogress' item that is prepended to active queue stack arrays.) Regardless, whenever the element's
|
||||
queue is further appended with additional items -- including delay()'s calls, the queue's
|
||||
first entry is automatically fired. This behavior contrasts that of custom queues, which never auto-fire. */
|
||||
/* Note: When an element set is being subjected to a non-parallel Collide call, the animation will not begin until
|
||||
each one of the elements in the set has reached the end of its individually pre-existing queue chain. */
|
||||
/* Note: Unfortunately, most people don't fully grasp jQuery's powerful, yet quirky, Collide.queue() function.
|
||||
Lean more here: http://stackoverflow.com/questions/1058158/can-somebody-explain-jquery-queue-to-me */
|
||||
if ((opts.queue === '' || opts.queue === 'fx') && Collide.queue(element)[0] !== 'inprogress') {
|
||||
Collide.dequeue(element);
|
||||
}
|
64
ionic/collide/animation-start.js
Normal file
64
ionic/collide/animation-start.js
Normal file
@ -0,0 +1,64 @@
|
||||
/* Forked from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from './collide'
|
||||
import {animationProcess} from './animation-process'
|
||||
|
||||
|
||||
export function animationStart(elements, options, propertiesMap) {
|
||||
|
||||
if (!elements || !elements.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/* The length of the element set (in the form of a nodeList or an array of elements) is defaulted to 1 in case a
|
||||
single raw DOM element is passed in (which doesn't contain a length property). */
|
||||
var elementsLength = elements.length;
|
||||
var elementsIndex = 0;
|
||||
var eleData;
|
||||
|
||||
|
||||
/**********************************
|
||||
Animation Call-Wide Variables
|
||||
**********************************/
|
||||
|
||||
/* A container for CSS unit conversion ratios (e.g. %, rem, and em ==> px) that is used to cache ratios across all elements
|
||||
being animated in a single Collide call. Calculating unit ratios necessitates DOM querying and updating, and is therefore
|
||||
avoided (via caching) wherever possible. This container is call-wide instead of page-wide to avoid the risk of using stale
|
||||
conversion metrics across Collide animations that are not immediately consecutively chained. */
|
||||
var callUnitConversionData = {
|
||||
lastParent: null,
|
||||
lastPosition: null,
|
||||
lastFontSize: null,
|
||||
lastPercentToPxWidth: null,
|
||||
lastPercentToPxHeight: null,
|
||||
lastEmToPx: null,
|
||||
remToPx: null,
|
||||
vwToPx: null,
|
||||
vhToPx: null
|
||||
};
|
||||
|
||||
/* A container for all the ensuing tween data and metadata associated with this call. This container gets pushed to the page-wide
|
||||
Collide.State.calls array that is processed during animation ticking. */
|
||||
var call = [];
|
||||
|
||||
|
||||
/**************************
|
||||
Element Set Iteration
|
||||
**************************/
|
||||
|
||||
var promises = [];
|
||||
|
||||
if (elements && elements.length) {
|
||||
for (var i = 0, l = elements.length; i < l; i++) {
|
||||
if (elements[i] && elements[i].parentElement) {
|
||||
|
||||
promises.push(
|
||||
animationProcess('start', elements, i, options, propertiesMap, callUnitConversionData, call)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
125
ionic/collide/animation-stop.js
Normal file
125
ionic/collide/animation-stop.js
Normal file
@ -0,0 +1,125 @@
|
||||
/* Forked from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from './collide'
|
||||
|
||||
|
||||
export function animationStop(elements, options, propertiesMap) {
|
||||
|
||||
if (!elements || !elements.length) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
var eleData;
|
||||
|
||||
|
||||
/******************
|
||||
Action: Stop
|
||||
*******************/
|
||||
|
||||
/* Clear the currently-active delay on each targeted element. */
|
||||
for (var x = 0; x < elements.length; x++) {
|
||||
eleData = Collide.data(elements[x]);
|
||||
|
||||
if (eleData && eleData.delayTimer) {
|
||||
/* Stop the timer from triggering its cached next() function. */
|
||||
clearTimeout(eleData.delayTimer.setTimeout);
|
||||
|
||||
/* Manually call the next() function so that the subsequent queue items can progress. */
|
||||
if (eleData.delayTimer.next) {
|
||||
eleData.delayTimer.next();
|
||||
}
|
||||
|
||||
delete eleData.delayTimer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var callsToStop = [];
|
||||
var activeCall;
|
||||
|
||||
/* When the stop action is triggered, the elements' currently active call is immediately stopped. The active call might have
|
||||
been applied to multiple elements, in which case all of the call's elements will be stopped. When an element
|
||||
is stopped, the next item in its animation queue is immediately triggered. */
|
||||
/* An additional argument may be passed in to clear an element's remaining queued calls. Either true (which defaults to the 'fx' queue)
|
||||
or a custom queue string can be passed in. */
|
||||
/* Note: The stop command runs prior to Collide's Queueing phase since its behavior is intended to take effect *immediately*,
|
||||
regardless of the element's current queue state. */
|
||||
|
||||
/* Iterate through every active call. */
|
||||
for (var x = 0, callsLength = Collide.State.calls.length; x < callsLength; x++) {
|
||||
|
||||
/* Inactive calls are set to false by the logic inside completeCall(). Skip them. */
|
||||
activeCall = Collide.State.calls[x];
|
||||
if (activeCall) {
|
||||
|
||||
/* Iterate through the active call's targeted elements. */
|
||||
|
||||
$.each(activeCall[1], function(k, activeElement) {
|
||||
/* If true was passed in as a secondary argument, clear absolutely all calls on this element. Otherwise, only
|
||||
clear calls associated with the relevant queue. */
|
||||
/* Call stopping logic works as follows:
|
||||
- options === true --> stop current default queue calls (and queue:false calls), including remaining queued ones.
|
||||
- options === undefined --> stop current queue:'' call and all queue:false calls.
|
||||
- options === false --> stop only queue:false calls.
|
||||
- options === 'custom' --> stop current queue:'custom' call, including remaining queued ones (there is no functionality to only clear the currently-running queue:'custom' call). */
|
||||
var queueName = (options === undefined) ? '' : options;
|
||||
|
||||
if (queueName !== true && (activeCall[2].queue !== queueName) && !(options === undefined && activeCall[2].queue === false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Iterate through the calls targeted by the stop command. */
|
||||
$.each(elements, function(l, element) {
|
||||
/* Check that this call was applied to the target element. */
|
||||
if (element === activeElement) {
|
||||
/* Optionally clear the remaining queued calls. */
|
||||
if (options === true || Type.isString(options)) {
|
||||
/* Iterate through the items in the element's queue. */
|
||||
$.each($.queue(element, Type.isString(options) ? options : ''), function(_, item) {
|
||||
/* The queue array can contain an 'inprogress' string, which we skip. */
|
||||
if (Type.isFunction(item)) {
|
||||
/* Pass the item's callback a flag indicating that we want to abort from the queue call.
|
||||
(Specifically, the queue will resolve the call's associated promise then abort.) */
|
||||
item(null, true);
|
||||
}
|
||||
});
|
||||
|
||||
/* Clearing the $.queue() array is achieved by resetting it to []. */
|
||||
$.queue(element, Type.isString(options) ? options : '', []);
|
||||
}
|
||||
|
||||
if (propertiesMap === 'stop') {
|
||||
/* Since 'reverse' uses cached start values (the previous call's endValues), these values must be
|
||||
changed to reflect the final value that the elements were actually tweened to. */
|
||||
/* Note: If only queue:false animations are currently running on an element, it won't have a tweensContainer
|
||||
object. Also, queue:false animations can't be reversed. */
|
||||
if (Data(element) && Data(element).tweensContainer && queueName !== false) {
|
||||
$.each(Data(element).tweensContainer, function(m, activeTween) {
|
||||
activeTween.endValue = activeTween.currentValue;
|
||||
});
|
||||
}
|
||||
|
||||
callsToStop.push(i);
|
||||
} else if (propertiesMap === 'finish') {
|
||||
/* To get active tweens to finish immediately, we forcefully shorten their durations to 1ms so that
|
||||
they finish upon the next rAf tick then proceed with normal call completion logic. */
|
||||
activeCall[2].duration = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
} // END: for (var x = 0, l = Collide.State.calls.length; x < l; x++) {
|
||||
|
||||
/* Prematurely call completeCall() on each matched active call. Pass an additional flag for 'stop' to indicate
|
||||
that the complete callback and display:none setting should be skipped since we're completing prematurely. */
|
||||
if (propertiesMap === 'stop') {
|
||||
$.each(callsToStop, function(i, j) {
|
||||
completeCall(j, true);
|
||||
});
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
};
|
84
ionic/collide/animation.js
Normal file
84
ionic/collide/animation.js
Normal file
@ -0,0 +1,84 @@
|
||||
import {Collide} from './collide'
|
||||
import {animationStart} from './animation-start'
|
||||
import {animationStop} from './animation-stop'
|
||||
|
||||
|
||||
export class Animation {
|
||||
constructor() {
|
||||
this._elements = null
|
||||
|
||||
this._options = {}
|
||||
this._properties = {}
|
||||
|
||||
this.isRunning = false
|
||||
}
|
||||
|
||||
elements(ele) {
|
||||
if (!ele) {
|
||||
this._elements = null
|
||||
} else {
|
||||
this._elements = !ele.length ? [ele] : ele
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************
|
||||
Actions
|
||||
*************/
|
||||
|
||||
start() {
|
||||
let promise = animationStart(this._elements, this._options, this._properties)
|
||||
|
||||
Collide.startTick();
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
stop() {
|
||||
let promise = animationStop(this._elements, this._options, this._properties)
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
Options
|
||||
***********************/
|
||||
options(val) {
|
||||
this._options = val || {}
|
||||
}
|
||||
|
||||
option(key, val) {
|
||||
this._options[key] = val
|
||||
}
|
||||
|
||||
removeOption(key) {
|
||||
delete this._options[key]
|
||||
}
|
||||
|
||||
duration(val) {
|
||||
this._options.duration = val
|
||||
}
|
||||
|
||||
easing(val) {
|
||||
this._options.easing = val
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
Properties
|
||||
**************************/
|
||||
|
||||
properties(val) {
|
||||
this._properties = val || {}
|
||||
}
|
||||
|
||||
property(key, val) {
|
||||
this._properties[key] = val
|
||||
}
|
||||
|
||||
removeProperty(key) {
|
||||
delete this._properties[key]
|
||||
}
|
||||
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
/* Forked from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {dom} from 'ionic/util'
|
||||
|
||||
|
||||
@ -53,6 +55,17 @@ export let Collide = {
|
||||
/* Set to 1 or 2 (most verbose) to output debug info to console. */
|
||||
debug: false,
|
||||
|
||||
startTick: function() {
|
||||
/* If the animation tick isn't running, start it.
|
||||
Collide shuts it off when there are no active calls to process. */
|
||||
if (Collide.State.isTicking === false) {
|
||||
Collide.State.isTicking = true;
|
||||
|
||||
/* Start the tick loop. */
|
||||
tick();
|
||||
}
|
||||
},
|
||||
|
||||
/* initialize element data */
|
||||
initData: function(element) {
|
||||
element.$collide = {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Ported from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
/* Forked from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from 'ionic/collide/collide'
|
||||
import {CSS} from 'ionic/collide/css'
|
||||
import {Collide} from './collide'
|
||||
import {CSS} from './css'
|
||||
|
||||
|
||||
/***************************
|
||||
@ -136,7 +136,7 @@ export function completeCall (callIndex, isStopped) {
|
||||
|
||||
/* Fire the next call in the queue so long as this call's queue wasn't set to false (to trigger a parallel animation),
|
||||
which would have already caused the next call to fire. Note: Even if the end of the animation queue has been reached,
|
||||
Collide.dequeue() must still be called in order to completely clear jQuery's animation queue. */
|
||||
Collide.dequeue() must still be called in order to completely clear animation queue. */
|
||||
if (opts.queue !== false) {
|
||||
Collide.dequeue(element, opts.queue);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Ported from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
/* Forked from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from 'ionic/collide/collide'
|
||||
import {Collide} from './collide'
|
||||
|
||||
const data = Collide.data;
|
||||
|
||||
@ -9,9 +9,8 @@ const data = Collide.data;
|
||||
CSS Stack
|
||||
*****************/
|
||||
|
||||
/* The CSS object is a highly condensed and performant CSS stack that fully replaces jQuery's.
|
||||
It handles the validation, getting, and setting of both standard CSS properties and CSS property hooks. */
|
||||
/* Note: A 'CSS' shorthand is aliased so that our code is easier to read. */
|
||||
/* The CSS object handles the validation, getting, and setting of both standard
|
||||
CSS properties and CSS property hooks. */
|
||||
export var CSS = {
|
||||
|
||||
|
||||
@ -690,14 +689,10 @@ export var CSS = {
|
||||
if (computedValue === 'auto' && /^(top|right|bottom|left)$/i.test(property)) {
|
||||
var position = computePropertyValue(element, 'position'); /* GET */
|
||||
|
||||
/* For absolute positioning, jQuery's $.position() only returns values for top and left;
|
||||
/* For absolute positioning, CSS.position(element) only returns values for top and left;
|
||||
right and bottom will have their 'auto' value reverted to 0. */
|
||||
/* Note: A jQuery object must be created here since jQuery doesn't have a low-level alias for $.position().
|
||||
Not a big deal since we're currently in a GET batch anyway. */
|
||||
if (position === 'fixed' || (position === 'absolute' && /top|left/i.test(property))) {
|
||||
/* Note: jQuery strips the pixel unit from its returned values; we re-add it here to conform with computePropertyValue's behavior. */
|
||||
// TODO!!!!
|
||||
computedValue = $(element).position()[property] + 'px'; /* GET */
|
||||
computedValue = CSS.position(element)[property] + 'px'; /* GET */
|
||||
}
|
||||
}
|
||||
|
||||
@ -785,6 +780,8 @@ export var CSS = {
|
||||
propertyValue = 0;
|
||||
}
|
||||
|
||||
if (Collide.debug >= 2) console.log('Get ' + property + ': ' + propertyValue);
|
||||
|
||||
return propertyValue;
|
||||
},
|
||||
|
||||
@ -853,7 +850,7 @@ export var CSS = {
|
||||
element.style[propertyName] = propertyValue;
|
||||
}
|
||||
|
||||
//if (Collide.debug >= 2) console.log('Set ' + property + ' (' + propertyName + '): ' + propertyValue);
|
||||
if (Collide.debug >= 2) console.log('Set ' + property + ' (' + propertyName + '): ' + propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -889,6 +886,44 @@ export var CSS = {
|
||||
}
|
||||
|
||||
CSS.setPropertyValue(element, 'transform', transformString);
|
||||
},
|
||||
|
||||
offset: function(element) {
|
||||
var box = element.getBoundingClientRect ? element.getBoundingClientRect() : { top: 0, left: 0 };
|
||||
|
||||
return {
|
||||
top: box.top + (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || 0),
|
||||
left: box.left + (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || 0)
|
||||
};
|
||||
},
|
||||
|
||||
position: function(element) {
|
||||
function offsetParent() {
|
||||
var offsetParent = this.offsetParent || document;
|
||||
|
||||
while (offsetParent && (!offsetParent.nodeType.toLowerCase === 'html' && offsetParent.style.position === 'static')) {
|
||||
offsetParent = offsetParent.offsetParent;
|
||||
}
|
||||
|
||||
return offsetParent || document;
|
||||
}
|
||||
|
||||
var offsetParent = offsetParent.apply(element),
|
||||
offset = this.offset(element),
|
||||
parentOffset = /^(?:body|html)$/i.test(offsetParent.nodeName) ? { top: 0, left: 0 } : this.offset(offsetParent)
|
||||
|
||||
offset.top -= parseFloat(element.style.marginTop) || 0;
|
||||
offset.left -= parseFloat(element.style.marginLeft) || 0;
|
||||
|
||||
if (offsetParent.style) {
|
||||
parentOffset.top += parseFloat(offsetParent.style.borderTopWidth) || 0
|
||||
parentOffset.left += parseFloat(offsetParent.style.borderLeftWidth) || 0
|
||||
}
|
||||
|
||||
return {
|
||||
top: offset.top - parentOffset.top,
|
||||
left: offset.left - parentOffset.left
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* Ported from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
/* Forked from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import * as util from 'ionic/util/util'
|
||||
import {Collide} from 'ionic/collide/collide'
|
||||
import {Collide} from './collide'
|
||||
|
||||
|
||||
/**************
|
||||
|
@ -1,9 +1,9 @@
|
||||
/* Ported from Velocity.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
/* Forked from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from 'ionic/collide/collide'
|
||||
import {CSS} from 'ionic/collide/css'
|
||||
import {completeCall} from 'ionic/collide/complete-call'
|
||||
import {dom} from 'ionic/util'
|
||||
import {Collide} from './collide'
|
||||
import {CSS} from './css'
|
||||
import {completeCall} from './complete-call'
|
||||
|
||||
|
||||
/************
|
||||
|
@ -1,155 +0,0 @@
|
||||
/* Ported from Collide.js, MIT License. Julian Shapiro http://twitter.com/shapiro */
|
||||
|
||||
import {Collide} from 'ionic/collide/collide'
|
||||
import {elementProcess} from 'ionic/collide/element-process'
|
||||
|
||||
|
||||
export function transitionAction(action, elements, options, propertiesMap) {
|
||||
|
||||
elements = elements && !elements.length ? [elements] : elements
|
||||
|
||||
if (!elements) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
/* The length of the element set (in the form of a nodeList or an array of elements) is defaulted to 1 in case a
|
||||
single raw DOM element is passed in (which doesn't contain a length property). */
|
||||
var elementsLength = elements.length;
|
||||
var elementsIndex = 0;
|
||||
var eleData;
|
||||
|
||||
|
||||
if (action === 'stop') {
|
||||
/******************
|
||||
Action: Stop
|
||||
*******************/
|
||||
|
||||
/* Clear the currently-active delay on each targeted element. */
|
||||
for (var x = 0; x < elements.length; x++) {
|
||||
eleData = Collide.data(elements[x]);
|
||||
|
||||
if (eleData && eleData.delayTimer) {
|
||||
/* Stop the timer from triggering its cached next() function. */
|
||||
clearTimeout(eleData.delayTimer.setTimeout);
|
||||
|
||||
/* Manually call the next() function so that the subsequent queue items can progress. */
|
||||
if (eleData.delayTimer.next) {
|
||||
eleData.delayTimer.next();
|
||||
}
|
||||
|
||||
delete eleData.delayTimer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var callsToStop = [];
|
||||
var activeCall;
|
||||
|
||||
/* When the stop action is triggered, the elements' currently active call is immediately stopped. The active call might have
|
||||
been applied to multiple elements, in which case all of the call's elements will be stopped. When an element
|
||||
is stopped, the next item in its animation queue is immediately triggered. */
|
||||
/* An additional argument may be passed in to clear an element's remaining queued calls. Either true (which defaults to the 'fx' queue)
|
||||
or a custom queue string can be passed in. */
|
||||
/* Note: The stop command runs prior to Collide's Queueing phase since its behavior is intended to take effect *immediately*,
|
||||
regardless of the element's current queue state. */
|
||||
|
||||
/* Iterate through every active call. */
|
||||
for (var x = 0, callsLength = Collide.State.calls.length; x < callsLength; x++) {
|
||||
|
||||
/* Inactive calls are set to false by the logic inside completeCall(). Skip them. */
|
||||
activeCall = Collide.State.calls[x];
|
||||
if (activeCall) {
|
||||
|
||||
/* Iterate through the active call's targeted elements. */
|
||||
|
||||
$.each(activeCall[1], function(k, activeElement) {
|
||||
/* If true was passed in as a secondary argument, clear absolutely all calls on this element. Otherwise, only
|
||||
clear calls associated with the relevant queue. */
|
||||
/* Call stopping logic works as follows:
|
||||
- options === true --> stop current default queue calls (and queue:false calls), including remaining queued ones.
|
||||
- options === undefined --> stop current queue:'' call and all queue:false calls.
|
||||
- options === false --> stop only queue:false calls.
|
||||
- options === 'custom' --> stop current queue:'custom' call, including remaining queued ones (there is no functionality to only clear the currently-running queue:'custom' call). */
|
||||
var queueName = (options === undefined) ? '' : options;
|
||||
|
||||
if (queueName !== true && (activeCall[2].queue !== queueName) && !(options === undefined && activeCall[2].queue === false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Iterate through the calls targeted by the stop command. */
|
||||
$.each(elements, function(l, element) {
|
||||
/* Check that this call was applied to the target element. */
|
||||
if (element === activeElement) {
|
||||
/* Optionally clear the remaining queued calls. */
|
||||
if (options === true || Type.isString(options)) {
|
||||
/* Iterate through the items in the element's queue. */
|
||||
$.each($.queue(element, Type.isString(options) ? options : ''), function(_, item) {
|
||||
/* The queue array can contain an 'inprogress' string, which we skip. */
|
||||
if (Type.isFunction(item)) {
|
||||
/* Pass the item's callback a flag indicating that we want to abort from the queue call.
|
||||
(Specifically, the queue will resolve the call's associated promise then abort.) */
|
||||
item(null, true);
|
||||
}
|
||||
});
|
||||
|
||||
/* Clearing the $.queue() array is achieved by resetting it to []. */
|
||||
$.queue(element, Type.isString(options) ? options : '', []);
|
||||
}
|
||||
|
||||
if (propertiesMap === 'stop') {
|
||||
/* Since 'reverse' uses cached start values (the previous call's endValues), these values must be
|
||||
changed to reflect the final value that the elements were actually tweened to. */
|
||||
/* Note: If only queue:false animations are currently running on an element, it won't have a tweensContainer
|
||||
object. Also, queue:false animations can't be reversed. */
|
||||
if (Data(element) && Data(element).tweensContainer && queueName !== false) {
|
||||
$.each(Data(element).tweensContainer, function(m, activeTween) {
|
||||
activeTween.endValue = activeTween.currentValue;
|
||||
});
|
||||
}
|
||||
|
||||
callsToStop.push(i);
|
||||
} else if (propertiesMap === 'finish') {
|
||||
/* To get active tweens to finish immediately, we forcefully shorten their durations to 1ms so that
|
||||
they finish upon the next rAf tick then proceed with normal call completion logic. */
|
||||
activeCall[2].duration = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
} // END: for (var x = 0, l = Collide.State.calls.length; x < l; x++) {
|
||||
|
||||
/* Prematurely call completeCall() on each matched active call. Pass an additional flag for 'stop' to indicate
|
||||
that the complete callback and display:none setting should be skipped since we're completing prematurely. */
|
||||
if (propertiesMap === 'stop') {
|
||||
$.each(callsToStop, function(i, j) {
|
||||
completeCall(j, true);
|
||||
});
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************
|
||||
Element Set Iteration
|
||||
**************************/
|
||||
|
||||
var promises = [];
|
||||
|
||||
if (elements && elements.length) {
|
||||
for (var i = 0, l = elements.length; i < l; i++) {
|
||||
if (elements[i] && elements[i].parentElement) {
|
||||
|
||||
promises.push(
|
||||
elementProcess(action, elements, i, options, propertiesMap)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
};
|
@ -1,66 +0,0 @@
|
||||
import {transitionAction} from 'ionic/collide/transition-action'
|
||||
|
||||
|
||||
export class Transition {
|
||||
constructor(ele) {
|
||||
console.log('Transition', ele)
|
||||
|
||||
if (!ele || ele.length === 0) return
|
||||
|
||||
this.elements = !ele.length ? [ele] : ele
|
||||
ele = null
|
||||
|
||||
// Animations that happen to this element
|
||||
this.animations = []
|
||||
|
||||
// Sub transitions that happen to sub elements
|
||||
this.transitions = []
|
||||
|
||||
this.options = {}
|
||||
this.propertiesMap = {}
|
||||
|
||||
this.isRunning = false
|
||||
}
|
||||
|
||||
start() {
|
||||
var p = transitionAction('start', this.elements, this.options, this.propertiesMap)
|
||||
|
||||
p.then(() => {
|
||||
console.log('start success done')
|
||||
}).catch(() => {
|
||||
console.log('start error done')
|
||||
})
|
||||
}
|
||||
|
||||
stop() {
|
||||
transitionAction('stop', this.elements, this.options, this.propertiesMap)
|
||||
}
|
||||
|
||||
properties(val) {
|
||||
this.propertiesMap = val || {}
|
||||
}
|
||||
|
||||
property(key, val) {
|
||||
this.propertiesMap[key] = val
|
||||
}
|
||||
|
||||
removeProperty(key) {
|
||||
delete this.propertiesMap[key]
|
||||
}
|
||||
|
||||
duration(val) {
|
||||
this.options.duration = val
|
||||
}
|
||||
|
||||
easing(val) {
|
||||
this.options.easing = val
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export class IOSTransition extends Transition {
|
||||
constructor(ele) {
|
||||
super(ele)
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import {Component, Decorator, View as NgView, NgElement, bootstrap} from 'angular2/angular2';
|
||||
import {Transition, IOSTransition} from 'ionic/ionic';
|
||||
import {Animation} from 'ionic/ionic';
|
||||
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ class IonicApp {
|
||||
@NgElement ngElement:NgElement
|
||||
) {
|
||||
|
||||
this.trans = new Transition( ngElement.domElement.querySelector('.square') )
|
||||
this.trans = new Animation( ngElement.domElement.querySelector('.square') )
|
||||
|
||||
this.trans.duration(500)
|
||||
this.trans.easing('linear')
|
@ -13,4 +13,4 @@ export * from 'ionic/webview/webview'
|
||||
export * from 'ionic/webview/cordova/cordova'
|
||||
export * from 'ionic/webview/node-webkit/node-webkit'
|
||||
export * from 'ionic/util/focus'
|
||||
export * from 'ionic/collide/transition'
|
||||
export * from 'ionic/collide/animation'
|
||||
|
Reference in New Issue
Block a user