Skip to content

Commit 7ec73f5

Browse files
committed
Merge pull request #426 from alancutter/timingTypeErrors
Throw TypeErrors on invalid inputs to AnimationEffectTiming
2 parents baaa3d9 + 6be5b10 commit 7ec73f5

File tree

3 files changed

+56
-24
lines changed

3 files changed

+56
-24
lines changed

src/timing-utilities.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
var fills = 'backwards|forwards|both|none'.split('|');
1818
var directions = 'reverse|alternate|alternate-reverse'.split('|');
19+
var linear = function(x) { return x; };
1920

2021
function cloneTimingInput(timingInput) {
2122
if (typeof timingInput == 'number') {
@@ -38,6 +39,7 @@
3839
this._playbackRate = 1;
3940
this._direction = 'normal';
4041
this._easing = 'linear';
42+
this._easingFunction = linear;
4143
}
4244

4345
AnimationEffectTiming.prototype = {
@@ -74,12 +76,18 @@
7476
return this._fill;
7577
},
7678
set iterationStart(value) {
79+
if (isNaN(value) || value < 0) {
80+
throw new TypeError('iterationStart must be a non-negative number, received: ' + timing.iterationStart);
81+
}
7782
this._setMember('iterationStart', value);
7883
},
7984
get iterationStart() {
8085
return this._iterationStart;
8186
},
8287
set duration(value) {
88+
if (value != 'auto' && (isNaN(value) || value < 0)) {
89+
throw new TypeError('duration must be non-negative or auto, received: ' + value);
90+
}
8391
this._setMember('duration', value);
8492
},
8593
get duration() {
@@ -92,12 +100,16 @@
92100
return this._direction;
93101
},
94102
set easing(value) {
103+
this._easingFunction = toTimingFunction(value);
95104
this._setMember('easing', value);
96105
},
97106
get easing() {
98107
return this._easing;
99108
},
100109
set iterations(value) {
110+
if (isNaN(value) || value < 0) {
111+
throw new TypeError('iterations must be non-negative, received: ' + value);
112+
}
101113
this._setMember('iterations', value);
102114
},
103115
get iterations() {
@@ -150,9 +162,7 @@
150162

151163
function normalizeTimingInput(timingInput, forGroup) {
152164
timingInput = shared.numericTimingToObject(timingInput);
153-
var timing = makeTiming(timingInput, forGroup);
154-
timing._easingFunction = toTimingFunction(timing.easing);
155-
return timing;
165+
return makeTiming(timingInput, forGroup);
156166
}
157167

158168
function cubic(a, b, c, d) {
@@ -209,25 +219,28 @@
209219
var numberString = '\\s*(-?\\d+\\.?\\d*|-?\\.\\d+)\\s*';
210220
var cubicBezierRe = new RegExp('cubic-bezier\\(' + numberString + ',' + numberString + ',' + numberString + ',' + numberString + '\\)');
211221
var stepRe = /steps\(\s*(\d+)\s*,\s*(start|middle|end)\s*\)/;
212-
var linear = function(x) { return x; };
213222

214223
function toTimingFunction(easing) {
215224
if (!styleForCleaning) {
216225
styleForCleaning = document.createElement('div').style;
217226
}
218227
styleForCleaning.animationTimingFunction = '';
219228
styleForCleaning.animationTimingFunction = easing;
220-
easing = styleForCleaning.animationTimingFunction;
229+
var validatedEasing = styleForCleaning.animationTimingFunction;
230+
231+
if (validatedEasing == '') {
232+
throw new TypeError(easing + ' is not a valid value for easing');
233+
}
221234

222-
var cubicData = cubicBezierRe.exec(easing);
235+
var cubicData = cubicBezierRe.exec(validatedEasing);
223236
if (cubicData) {
224237
return cubic.apply(this, cubicData.slice(1).map(Number));
225238
}
226-
var stepData = stepRe.exec(easing);
239+
var stepData = stepRe.exec(validatedEasing);
227240
if (stepData) {
228241
return step(Number(stepData[1]), {'start': Start, 'middle': Middle, 'end': End}[stepData[2]]);
229242
}
230-
var preset = presets[easing];
243+
var preset = presets[validatedEasing];
231244
if (preset) {
232245
return preset;
233246
}

test/js/keyframes.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -442,16 +442,13 @@ suite('keyframes', function() {
442442
assert.equal(typeof interpolations[1].interpolation, 'function');
443443
});
444444

445-
test('Make interpolations with invalid easing.', function() {
446-
var interpolations;
447-
assert.doesNotThrow(function() {
448-
interpolations = makeInterpolations(makePropertySpecificKeyframeGroups(normalizeKeyframes([
445+
test('Make interpolations with invalid easing should throw.', function() {
446+
assert.throws(function() {
447+
makeInterpolations(makePropertySpecificKeyframeGroups(normalizeKeyframes([
449448
{left: '0px', easing: 'pants and ducks'},
450449
{left: '200px'},
451450
])));
452451
});
453-
assert.equal(interpolations.length, 1);
454-
assert.equal(interpolations[0].easing.toString(), 'function (x) { return x; }');
455452
});
456453
});
457454

test/js/timing-utilities.js

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,17 @@ suite('timing-utilities', function() {
3333
f = toTimingFunction('cubic-bezier(0, 1, 1, 0)');
3434
assert.closeTo(f(0.104), 0.392, 0.01);
3535

36-
function assertIsLinear(easing) {
37-
var f = toTimingFunction(easing);
38-
for (var i = 0; i <= 1; i += 0.1) {
39-
assert.equal(f(i), i, easing + ' is linear');
40-
}
36+
function assertInvalidEasingThrows(easing) {
37+
assert.throws(function() {
38+
toTimingFunction(easing);
39+
}, easing);
4140
}
4241

43-
assertIsLinear('cubic-bezier(.25, 0.1, 0.25, 1.)');
44-
assertIsLinear('cubic-bezier(0, 1, -1, 1)');
45-
assertIsLinear('an elephant');
46-
assertIsLinear('cubic-bezier(-1, 1, 1, 1)');
47-
assertIsLinear('cubic-bezier(1, 1, 1)');
42+
assertInvalidEasingThrows('cubic-bezier(.25, 0.1, 0.25, 1.)');
43+
assertInvalidEasingThrows('cubic-bezier(0, 1, -1, 1)');
44+
assertInvalidEasingThrows('an elephant');
45+
assertInvalidEasingThrows('cubic-bezier(-1, 1, 1, 1)');
46+
assertInvalidEasingThrows('cubic-bezier(1, 1, 1)');
4847

4948
f = toTimingFunction('steps(10, end)');
5049
assert.equal(f(0), 0);
@@ -119,4 +118,27 @@ suite('timing-utilities', function() {
119118
assert.equal(effectTF(6000), 0.5);
120119
assert.closeTo(effectTF2(6000), 0.8, 0.005);
121120
});
121+
test('TypeErrors', function() {
122+
var timing = normalizeTimingInput({
123+
iterationStart: 123,
124+
iterations: 456,
125+
duration: 789,
126+
easing: 'ease',
127+
});
128+
129+
assert.throws(function() { timing.iterationStart = -1; });
130+
assert.throws(function() { timing.iterationStart = 'ponies'; });
131+
assert.equal(timing.iterationStart, 123);
132+
133+
assert.throws(function() { timing.iterations = -1; });
134+
assert.throws(function() { timing.iterations = 'pidgeons'; });
135+
assert.equal(timing.iterations, 456);
136+
137+
assert.throws(function() { timing.duration = -1; });
138+
assert.throws(function() { timing.duration = 'pawprints'; });
139+
assert.equal(timing.duration, 789);
140+
141+
assert.throws(function() { timing.easing = 'invalid timing function'; });
142+
assert.equal(timing.easing, 'ease');
143+
});
122144
});

0 commit comments

Comments
 (0)