1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | (function(shared, scope, testing) {
|
16 |
|
17 | var disassociate = function(effect) {
|
18 | effect._animation = undefined;
|
19 | if (effect instanceof window.SequenceEffect || effect instanceof window.GroupEffect) {
|
20 | for (var i = 0; i < effect.children.length; i++) {
|
21 | disassociate(effect.children[i]);
|
22 | }
|
23 | }
|
24 | };
|
25 |
|
26 | scope.removeMulti = function(effects) {
|
27 | var oldParents = [];
|
28 | for (var i = 0; i < effects.length; i++) {
|
29 | var effect = effects[i];
|
30 | if (effect._parent) {
|
31 | if (oldParents.indexOf(effect._parent) == -1) {
|
32 | oldParents.push(effect._parent);
|
33 | }
|
34 | effect._parent.children.splice(effect._parent.children.indexOf(effect), 1);
|
35 | effect._parent = null;
|
36 | disassociate(effect);
|
37 | } else if (effect._animation && (effect._animation.effect == effect)) {
|
38 | effect._animation.cancel();
|
39 | effect._animation.effect = new KeyframeEffect(null, []);
|
40 | if (effect._animation._callback) {
|
41 | effect._animation._callback._animation = null;
|
42 | }
|
43 | effect._animation._rebuildUnderlyingAnimation();
|
44 | disassociate(effect);
|
45 | }
|
46 | }
|
47 | for (i = 0; i < oldParents.length; i++) {
|
48 | oldParents[i]._rebuild();
|
49 | }
|
50 | };
|
51 |
|
52 | function KeyframeList(effectInput) {
|
53 | this._frames = shared.normalizeKeyframes(effectInput);
|
54 | }
|
55 |
|
56 | scope.KeyframeEffect = function(target, effectInput, timingInput, id) {
|
57 | this.target = target;
|
58 | this._parent = null;
|
59 |
|
60 | timingInput = shared.numericTimingToObject(timingInput);
|
61 | this._timingInput = shared.cloneTimingInput(timingInput);
|
62 | this._timing = shared.normalizeTimingInput(timingInput);
|
63 |
|
64 | this.timing = shared.makeTiming(timingInput, false, this);
|
65 | this.timing._effect = this;
|
66 | if (typeof effectInput == 'function') {
|
67 | shared.deprecated('Custom KeyframeEffect', '2015-06-22', 'Use KeyframeEffect.onsample instead.');
|
68 | this._normalizedKeyframes = effectInput;
|
69 | } else {
|
70 | this._normalizedKeyframes = new KeyframeList(effectInput);
|
71 | }
|
72 | this._keyframes = effectInput;
|
73 | this.activeDuration = shared.calculateActiveDuration(this._timing);
|
74 | this._id = id;
|
75 | return this;
|
76 | };
|
77 |
|
78 | scope.KeyframeEffect.prototype = {
|
79 | getFrames: function() {
|
80 | if (typeof this._normalizedKeyframes == 'function')
|
81 | return this._normalizedKeyframes;
|
82 | return this._normalizedKeyframes._frames;
|
83 | },
|
84 | set onsample(callback) {
|
85 | if (typeof this.getFrames() == 'function') {
|
86 | throw new Error('Setting onsample on custom effect KeyframeEffect is not supported.');
|
87 | }
|
88 | this._onsample = callback;
|
89 | if (this._animation) {
|
90 | this._animation._rebuildUnderlyingAnimation();
|
91 | }
|
92 | },
|
93 | get parent() {
|
94 | return this._parent;
|
95 | },
|
96 | clone: function() {
|
97 | if (typeof this.getFrames() == 'function') {
|
98 | throw new Error('Cloning custom effects is not supported.');
|
99 | }
|
100 | var clone = new KeyframeEffect(this.target, [], shared.cloneTimingInput(this._timingInput), this._id);
|
101 | clone._normalizedKeyframes = this._normalizedKeyframes;
|
102 | clone._keyframes = this._keyframes;
|
103 | return clone;
|
104 | },
|
105 | remove: function() {
|
106 | scope.removeMulti([this]);
|
107 | }
|
108 | };
|
109 |
|
110 | var originalElementAnimate = Element.prototype.animate;
|
111 | Element.prototype.animate = function(effectInput, options) {
|
112 | var id = '';
|
113 | if (options && options.id) {
|
114 | id = options.id;
|
115 | }
|
116 | return scope.timeline._play(new scope.KeyframeEffect(this, effectInput, options, id));
|
117 | };
|
118 |
|
119 | var nullTarget = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
120 | scope.newUnderlyingAnimationForKeyframeEffect = function(keyframeEffect) {
|
121 | if (keyframeEffect) {
|
122 | var target = keyframeEffect.target || nullTarget;
|
123 | var keyframes = keyframeEffect._keyframes;
|
124 | if (typeof keyframes == 'function') {
|
125 | keyframes = [];
|
126 | }
|
127 | var options = keyframeEffect._timingInput;
|
128 | options.id = keyframeEffect._id;
|
129 | } else {
|
130 | var target = nullTarget;
|
131 | var keyframes = [];
|
132 | var options = 0;
|
133 | }
|
134 | return originalElementAnimate.apply(target, [keyframes, options]);
|
135 | };
|
136 |
|
137 |
|
138 | scope.bindAnimationForKeyframeEffect = function(animation) {
|
139 | if (animation.effect && typeof animation.effect._normalizedKeyframes == 'function') {
|
140 | scope.bindAnimationForCustomEffect(animation);
|
141 | }
|
142 | };
|
143 |
|
144 | var pendingGroups = [];
|
145 | scope.awaitStartTime = function(groupAnimation) {
|
146 | if (groupAnimation.startTime !== null || !groupAnimation._isGroup)
|
147 | return;
|
148 | if (pendingGroups.length == 0) {
|
149 | requestAnimationFrame(updatePendingGroups);
|
150 | }
|
151 | pendingGroups.push(groupAnimation);
|
152 | };
|
153 | function updatePendingGroups() {
|
154 | var updated = false;
|
155 | while (pendingGroups.length) {
|
156 | var group = pendingGroups.shift();
|
157 | group._updateChildren();
|
158 | updated = true;
|
159 | }
|
160 | return updated;
|
161 | }
|
162 | var originalGetComputedStyle = window.getComputedStyle;
|
163 | Object.defineProperty(window, 'getComputedStyle', {
|
164 | configurable: true,
|
165 | enumerable: true,
|
166 | value: function() {
|
167 | scope.timeline._updateAnimationsPromises();
|
168 | var result = originalGetComputedStyle.apply(this, arguments);
|
169 | if (updatePendingGroups())
|
170 | result = originalGetComputedStyle.apply(this, arguments);
|
171 | scope.timeline._updateAnimationsPromises();
|
172 | return result;
|
173 | },
|
174 | });
|
175 |
|
176 | window.KeyframeEffect = scope.KeyframeEffect;
|
177 | window.Element.prototype.getAnimations = function() {
|
178 | return document.timeline.getAnimations().filter(function(animation) {
|
179 | return animation.effect !== null && animation.effect.target == this;
|
180 | }.bind(this));
|
181 | };
|
182 |
|
183 | }(webAnimationsShared, webAnimationsNext, webAnimationsTesting));
|