Skip to content

Commit

Permalink
Added "reverse" command, might want tweaking, but definitely wants fe…
Browse files Browse the repository at this point in the history
…edback first.
  • Loading branch information
Rycochet committed Feb 4, 2018
1 parent 0e7ac84 commit c7fc314
Show file tree
Hide file tree
Showing 13 changed files with 237 additions and 163 deletions.
2 changes: 1 addition & 1 deletion V2_CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* There are APIs for extending Velocity - see the various register* commands.
* Display - This is a property, no longer an option.
* Visibility - This is a property, no longer an option.
* Reverse - Now reverses the last animation at time of adding, not when playing.

# Currently disabled / not updated:

* UI-Pack
* Reverse
* Scroll (working, but not happy with interface - it's a property if people want to play, alias of scrollTop, there's also scrollLeft)
19 changes: 13 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -788,16 +788,23 @@ interface VelocityChain {
(action: "resume", queue?: string): VelocityResult;
}

////////////////////
// Action: Resume //
////////////////////
/////////////////////
// Action: Reverse //
/////////////////////
interface Velocity {
(action: "resume", queue?: string): VelocityResult;
(elements: VelocityElements, action: "resume", queue?: string): VelocityResult;
(elements: VelocityElements, action: "reverse", complete?: () => void): VelocityResult;
(elements: VelocityElements, action: "reverse", duration?: number | "fast" | "normal" | "slow", complete?: () => void): VelocityResult;
(elements: VelocityElements, action: "reverse", duration?: number | "fast" | "normal" | "slow", easing?: string | number[], complete?: () => void): VelocityResult;
(elements: VelocityElements, action: "reverse", easing?: string | number[], complete?: () => void): VelocityResult;
(elements: VelocityElements, action: "reverse", options?: VelocityOptions): VelocityResult;
}

interface VelocityChain {
(action: "resume", queue?: string): VelocityResult;
(action: "reverse", complete?: () => void): VelocityResult;
(action: "reverse", duration?: number | "fast" | "normal" | "slow", complete?: () => void): VelocityResult;
(action: "reverse", duration?: number | "fast" | "normal" | "slow", easing?: string | number[], complete?: () => void): VelocityResult;
(action: "reverse", easing?: string | number[], complete?: () => void): VelocityResult;
(action: "reverse", options?: VelocityOptions): VelocityResult;
}

//////////////////
Expand Down
19 changes: 9 additions & 10 deletions src/Velocity/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,8 @@ namespace VelocityStatic {
State.firstNew = animation;
}
const element = animation.element,
data = Data(element),
queue = animation.queue == null ? animation.options.queue : animation.queue;
data = Data(element);

if (queue !== false) {
// Store the last animation added so we can use it for the
// beginning of the next one.
data.lastAnimationList[queue] = animation;
}
if (!data.count++) {

////////////////////////
Expand All @@ -49,14 +43,20 @@ namespace VelocityStatic {
/**
* Add an item to an animation queue.
*/
export function queue(element: HTMLorSVGElement, animation: AnimationCall, queue?: string | false): void {
export function queue(element: HTMLorSVGElement, animation: AnimationCall, queue: string | false): void {
const data = Data(element);

if (queue !== false) {
// Store the last animation added so we can use it for the
// beginning of the next one.
data.lastAnimationList[queue] = animation;
}
if (queue === false) {
animate(animation);
} else {
if (!isString(queue)) {
queue = "";
}
const data = Data(element);
let last = data.queueList[queue];

if (!last) {
Expand Down Expand Up @@ -129,7 +129,6 @@ namespace VelocityStatic {
const data = Data(animation.element);

if (data) {
data.lastAnimationList[queue] = animation;
animation._next = animation._prev = undefined;
}
}
Expand Down
64 changes: 36 additions & 28 deletions src/Velocity/tweens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ namespace VelocityStatic {
* pre-allocates the array as it is then the correct size and slightly
* faster to access.
*/
export function expandProperties(animation: AnimationCall, properties: VelocityProperties) {
export function expandProperties(animation: AnimationCall, properties: VelocityProperties, reverse?: boolean) {
const tweens = animation.tweens = Object.create(null),
elements = animation.elements,
element = animation.element,
Expand Down Expand Up @@ -115,38 +115,46 @@ namespace VelocityStatic {
continue;
}
const tween: VelocityTween = tweens[propertyName] = new Array(Tween.length) as any;
let endValue: string,
startValue: string;
if (reverse) {
tween[Tween.START] = valueData[Tween.END];
tween[Tween.EASING] = valueData[Tween.EASING];
tween[Tween.END] = valueData[Tween.START];
tween[Tween.PATTERN] = valueData[Tween.PATTERN];
tween[Tween.ROUNDING] = valueData[Tween.ROUNDING];
} else {
let endValue: string,
startValue: string;

if (isFunction(valueData)) {
// If we have a function as the main argument then resolve
// it first, in case it returns an array that needs to be
// split.
valueData = (valueData as VelocityPropertyFn).call(element, elementArrayIndex, elements.length, elements);
}
if (Array.isArray(valueData)) {
// valueData is an array in the form of
// [ endValue, [, easing] [, startValue] ]
const arr1 = valueData[1],
arr2 = valueData[2];
if (isFunction(valueData)) {
// If we have a function as the main argument then resolve
// it first, in case it returns an array that needs to be
// split.
valueData = (valueData as VelocityPropertyFn).call(element, elementArrayIndex, elements.length, elements);
}
if (Array.isArray(valueData)) {
// valueData is an array in the form of
// [ endValue, [, easing] [, startValue] ]
const arr1 = valueData[1],
arr2 = valueData[2];

endValue = valueData[0] as any;
if ((isString(arr1) && (/^[\d-]/.test(arr1) || CSS.RegEx.isHex.test(arr1))) || isFunction(arr1) || isNumber(arr1)) {
startValue = arr1 as any;
} else if ((isString(arr1) && Easing.Easings[arr1]) || Array.isArray(arr1)) {
tween[Tween.EASING] = arr1 as any;
startValue = arr2 as any;
endValue = valueData[0] as any;
if ((isString(arr1) && (/^[\d-]/.test(arr1) || CSS.RegEx.isHex.test(arr1))) || isFunction(arr1) || isNumber(arr1)) {
startValue = arr1 as any;
} else if ((isString(arr1) && Easing.Easings[arr1]) || Array.isArray(arr1)) {
tween[Tween.EASING] = arr1 as any;
startValue = arr2 as any;
} else {
startValue = arr1 || arr2 as any;
}
} else {
startValue = arr1 || arr2 as any;
endValue = valueData as any;
}
} else {
endValue = valueData as any;
}
tween[Tween.END] = commands.get(typeof endValue)(endValue, element, elements, elementArrayIndex, propertyName) as any;
if (startValue != null || (queue === false || data.queueList[queue] === undefined)) {
tween[Tween.START] = commands.get(typeof startValue)(startValue, element, elements, elementArrayIndex, propertyName) as any;
tween[Tween.END] = commands.get(typeof endValue)(endValue, element, elements, elementArrayIndex, propertyName) as any;
if (startValue != null || (queue === false || data.queueList[queue] === undefined)) {
tween[Tween.START] = commands.get(typeof startValue)(startValue, element, elements, elementArrayIndex, propertyName) as any;
}
explodeTween(propertyName, tween, duration, !!startValue);
}
explodeTween(propertyName, tween, duration, !!startValue);
}
}

Expand Down
56 changes: 33 additions & 23 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
}
// Get any options map passed in as arguments first, expand any direct
// options if possible.
const isAction = isString(propertiesMap),
const isReverse = propertiesMap === "reverse",
isAction = !isReverse && isString(propertiesMap),
opts = syntacticSugar ? getValue(args0.options, args0.o) : _arguments[argumentIndex];

if (isPlainObject(opts)) {
Expand Down Expand Up @@ -193,10 +194,9 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
return promise as any;
}

// TODO: exception for the special "reverse" property
// NOTE: Can't use isAction here due to type inference - there are callbacks
// between so the type isn't considered safe.
if (isString(propertiesMap)) {
if (isAction) {
const args: any[] = [],
promiseHandler: VelocityPromise = promise && {
_promise: promise,
Expand All @@ -214,19 +214,19 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
// There is one special case - "reverse" - which is handled differently,
// by being stored on the animation and then expanded when the animation
// starts.
const action = propertiesMap.replace(/\..*$/, ""),
const action = (propertiesMap as string).replace(/\..*$/, ""),
callback = VelocityStatic.Actions[action] || VelocityStatic.Actions["default"];

if (callback) {
const result = callback(args, elements, promiseHandler, propertiesMap);
const result = callback(args, elements, promiseHandler, propertiesMap as string);

if (result !== undefined) {
return result;
}
} else {
console.warn("VelocityJS: Unknown action:", propertiesMap);
}
} else if (isPlainObject(propertiesMap)) {
} else if (isPlainObject(propertiesMap) || isReverse) {
/**
* The options for this set of animations.
*/
Expand Down Expand Up @@ -268,13 +268,15 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
/* Note: You can read more about the use of mobileHA in Velocity's documentation: VelocityJS.org/#mobileHA. */
options.mobileHA = true;
}
if (optionsMap.display != null) {
(propertiesMap as VelocityProperties).display = optionsMap.display as string;
console.error("Deprecated 'options.display' used, this is now a property:", optionsMap.display);
}
if (optionsMap.visibility != null) {
(propertiesMap as VelocityProperties).visibility = optionsMap.visibility as string;
console.error("Deprecated 'options.visibility' used, this is now a property:", optionsMap.visibility);
if (!isReverse) {
if (optionsMap.display != null) {
(propertiesMap as VelocityProperties).display = optionsMap.display as string;
console.error("Deprecated 'options.display' used, this is now a property:", optionsMap.display);
}
if (optionsMap.visibility != null) {
(propertiesMap as VelocityProperties).visibility = optionsMap.visibility as string;
console.error("Deprecated 'options.visibility' used, this is now a property:", optionsMap.visibility);
}
}
// TODO: Allow functional options for different options per element
const optionsBegin = validateBegin(optionsMap.begin),
Expand Down Expand Up @@ -343,16 +345,24 @@ function VelocityFn(this: VelocityElements | void, ...__args: any[]): VelocityRe
const element = elements[index];

if (isNode(element)) {
const tweens = Object.create(null),
animation: AnimationCall = Object.assign({
element: element,
tweens: tweens
}, rootAnimation);

options._total++;
animations.push(animation);
VelocityStatic.expandProperties(animation, propertiesMap);
VelocityStatic.queue(element, animation, getValue(animation.queue, options.queue));
if (isReverse && options.queue !== false) {
const lastAnimation = Data(element).lastAnimationList[options.queue];

propertiesMap = lastAnimation && lastAnimation.tweens;
}
if (propertiesMap) {
const tweens = Object.create(null),
animation: AnimationCall = Object.assign({
element: element,
tweens: tweens
}, rootAnimation);

options._total++;
animations.push(animation);

VelocityStatic.expandProperties(animation, propertiesMap, isReverse);
VelocityStatic.queue(element, animation, getValue(animation.queue, options.queue));
}
}
}
if (VelocityStatic.State.isTicking === false) {
Expand Down
58 changes: 39 additions & 19 deletions test/src/3. Command/Command Reverse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,47 @@
* Licensed under the MIT license. See LICENSE file in the project root for details.
*/

QUnit.skip("Reverse", function(assert) {
var done = assert.async(1),
testEasing = "spring",
$target = getTarget();

assert.expect(4);
Velocity($target, {opacity: defaultProperties.opacity, width: defaultProperties.width}, {easing: testEasing});
Velocity($target, "reverse", function() {
// assert.equal(parseFloat(Velocity.CSS.getPropertyValue($target, "opacity")), defaultStyles.opacity, "Reversed to initial property #1.");
// assert.equal(parseFloat(Velocity.CSS.getPropertyValue($target, "width")), defaultStyles.width, "Reversed to initial property #2.");
//
// done();
QUnit.test("Reverse", function(assert) {
var $target = getTarget(),
opacity = $target.velocity("style", "opacity"),
width = $target.velocity("style", "width");

if (width === "0") {
// Browsers don't always suffix, but Velocity does.
width = "0px";
}
async(assert, 2, function(done) {
Velocity($target, defaultProperties, {
complete: function(elements) {
assert.equal(elements[0].velocity("style", "opacity"), defaultProperties.opacity, "Initial property #1 set correctly.");
assert.equal(elements[0].velocity("style", "width"), defaultProperties.width, "Initial property #2 set correctly.");

done();
}
});
});

async(assert, 2, function(done) {
Velocity($target, "reverse", {
complete: function(elements) {
assert.equal(elements[0].velocity("style", "opacity"), opacity, "Reversed property #1 set correctly.");
assert.equal(elements[0].velocity("style", "width"), width, "Reversed property #2 set correctly.");

done();
}
});
});
/* Check chained reverses. */
Velocity($target, "reverse", function() {
assert.equal(parseFloat(Velocity.CSS.getPropertyValue($target, "opacity") as string), defaultProperties.opacity, "Reversed to reversed property #1.");
assert.equal(parseFloat(Velocity.CSS.getPropertyValue($target, "width") as string), defaultProperties.width, "Reversed to reversed property #2.");

/* Ensure the options were passed through until the end. */
// assert.equal(Data($target).opts.easing, testEasing, "Options object passed through.");
async(assert, 2, function(done) {
Velocity($target, "reverse", {
complete: function(elements) {
assert.equal(elements[0].velocity("style", "opacity"), defaultProperties.opacity, "Chained reversed property #1 set correctly.");
assert.equal(elements[0].velocity("style", "width"), defaultProperties.width, "Chained reversed property #2 set correctly.");

done();
done();
}
});
});

assert.expect(async());
});
2 changes: 1 addition & 1 deletion test/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const defaultStyles = {
textShadowBlur: 3
},
defaultProperties: VelocityProperties = {
opacity: defaultStyles.opacity / 2 + "px",
opacity: String(defaultStyles.opacity / 2),
width: defaultStyles.width * 2 + "px",
height: defaultStyles.height * 2 + "px"
},
Expand Down
Loading

0 comments on commit c7fc314

Please sign in to comment.