Skip to content

Commit db1738c

Browse files
matskoNarretz
authored andcommitted
fix(core): ensure animate runner is the same with and without animations
The $$AnimateRunner class is now the same for the core $animate service and the ngAnimate $animate service. Previously, the core used a different implementation that didn't match the ngAnimate behavior with regard to callbacks. Closes angular#13205 Closes angular#13347
1 parent 75e8764 commit db1738c

8 files changed

+188
-235
lines changed

angularFiles.js

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var angularFiles = {
1414

1515
'src/ng/anchorScroll.js',
1616
'src/ng/animate.js',
17+
'src/ng/animateRunner.js',
1718
'src/ng/animateCss.js',
1819
'src/ng/browser.js',
1920
'src/ng/cacheFactory.js',

src/AngularPublic.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
$AnimateProvider,
5858
$CoreAnimateCssProvider,
5959
$$CoreAnimateQueueProvider,
60-
$$CoreAnimateRunnerProvider,
60+
$$AnimateRunnerProvider,
61+
$$AnimateAsyncRunFactoryProvider,
6162
$BrowserProvider,
6263
$CacheFactoryProvider,
6364
$ControllerProvider,
@@ -217,7 +218,8 @@ function publishExternalAPI(angular) {
217218
$animate: $AnimateProvider,
218219
$animateCss: $CoreAnimateCssProvider,
219220
$$animateQueue: $$CoreAnimateQueueProvider,
220-
$$AnimateRunner: $$CoreAnimateRunnerProvider,
221+
$$AnimateRunner: $$AnimateRunnerFactoryProvider,
222+
$$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
221223
$browser: $BrowserProvider,
222224
$cacheFactory: $CacheFactoryProvider,
223225
$controller: $ControllerProvider,

src/ng/animate.js

+6-24
Original file line numberDiff line numberDiff line change
@@ -53,29 +53,6 @@ function prepareAnimateOptions(options) {
5353
: {};
5454
}
5555

56-
var $$CoreAnimateRunnerProvider = function() {
57-
this.$get = ['$q', '$$rAF', function($q, $$rAF) {
58-
function AnimateRunner() {}
59-
AnimateRunner.all = noop;
60-
AnimateRunner.chain = noop;
61-
AnimateRunner.prototype = {
62-
end: noop,
63-
cancel: noop,
64-
resume: noop,
65-
pause: noop,
66-
complete: noop,
67-
then: function(pass, fail) {
68-
return $q(function(resolve) {
69-
$$rAF(function() {
70-
resolve();
71-
});
72-
}).then(pass, fail);
73-
}
74-
};
75-
return AnimateRunner;
76-
}];
77-
};
78-
7956
// this is prefixed with Core since it conflicts with
8057
// the animateQueueProvider defined in ngAnimate/animateQueue.js
8158
var $$CoreAnimateQueueProvider = function() {
@@ -101,7 +78,12 @@ var $$CoreAnimateQueueProvider = function() {
10178
addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
10279
}
10380

104-
return new $$AnimateRunner(); // jshint ignore:line
81+
var runner = new $$AnimateRunner(); // jshint ignore:line
82+
83+
// since there are no animations to run the runner needs to be
84+
// notified that the animation call is complete.
85+
runner.complete();
86+
return runner;
10587
}
10688
};
10789

src/ng/animateCss.js

+5-34
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,7 @@
1212
* Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
1313
*/
1414
var $CoreAnimateCssProvider = function() {
15-
this.$get = ['$$rAF', '$q', function($$rAF, $q) {
16-
17-
var RAFPromise = function() {};
18-
RAFPromise.prototype = {
19-
done: function(cancel) {
20-
this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
21-
},
22-
end: function() {
23-
this.done();
24-
},
25-
cancel: function() {
26-
this.done(true);
27-
},
28-
getPromise: function() {
29-
if (!this.defer) {
30-
this.defer = $q.defer();
31-
}
32-
return this.defer.promise;
33-
},
34-
then: function(f1,f2) {
35-
return this.getPromise().then(f1,f2);
36-
},
37-
'catch': function(f1) {
38-
return this.getPromise()['catch'](f1);
39-
},
40-
'finally': function(f1) {
41-
return this.getPromise()['finally'](f1);
42-
}
43-
};
44-
15+
this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
4516
return function(element, options) {
4617
// there is no point in applying the styles since
4718
// there is no animation that goes on at all in
@@ -55,24 +26,24 @@ var $CoreAnimateCssProvider = function() {
5526
options.from = null;
5627
}
5728

58-
var closed, runner = new RAFPromise();
29+
var closed, runner = new $$AnimateRunner();
5930
return {
6031
start: run,
6132
end: run
6233
};
6334

6435
function run() {
6536
$$rAF(function() {
66-
close();
37+
applyAnimationContents();
6738
if (!closed) {
68-
runner.done();
39+
runner.complete();
6940
}
7041
closed = true;
7142
});
7243
return runner;
7344
}
7445

75-
function close() {
46+
function applyAnimationContents() {
7647
if (options.addClass) {
7748
element.addClass(options.addClass);
7849
options.addClass = null;

src/ng/animateRunner.js

+170
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
'use strict';
2+
3+
var $$AnimateAsyncRunFactoryProvider = function() {
4+
this.$get = ['$$rAF', function($$rAF) {
5+
var waitQueue = [];
6+
7+
function waitForTick(fn) {
8+
waitQueue.push(fn);
9+
if (waitQueue.length > 1) return;
10+
$$rAF(function() {
11+
for (var i = 0; i < waitQueue.length; i++) {
12+
waitQueue[i]();
13+
}
14+
waitQueue = [];
15+
});
16+
}
17+
18+
return function() {
19+
var passed = false;
20+
waitForTick(function() {
21+
passed = true;
22+
});
23+
return function(callback) {
24+
passed ? callback() : waitForTick(callback);
25+
};
26+
};
27+
}];
28+
};
29+
30+
var $$AnimateRunnerFactoryProvider = function() {
31+
this.$get = ['$q', '$sniffer', '$$animateAsyncRun',
32+
function($q, $sniffer, $$animateAsyncRun) {
33+
34+
var INITIAL_STATE = 0;
35+
var DONE_PENDING_STATE = 1;
36+
var DONE_COMPLETE_STATE = 2;
37+
38+
AnimateRunner.chain = function(chain, callback) {
39+
var index = 0;
40+
41+
next();
42+
function next() {
43+
if (index === chain.length) {
44+
callback(true);
45+
return;
46+
}
47+
48+
chain[index](function(response) {
49+
if (response === false) {
50+
callback(false);
51+
return;
52+
}
53+
index++;
54+
next();
55+
});
56+
}
57+
};
58+
59+
AnimateRunner.all = function(runners, callback) {
60+
var count = 0;
61+
var status = true;
62+
forEach(runners, function(runner) {
63+
runner.done(onProgress);
64+
});
65+
66+
function onProgress(response) {
67+
status = status && response;
68+
if (++count === runners.length) {
69+
callback(status);
70+
}
71+
}
72+
};
73+
74+
function AnimateRunner(host) {
75+
this.setHost(host);
76+
77+
this._doneCallbacks = [];
78+
this._runInAnimationFrame = $$animateAsyncRun();
79+
this._state = 0;
80+
}
81+
82+
AnimateRunner.prototype = {
83+
setHost: function(host) {
84+
this.host = host || {};
85+
},
86+
87+
done: function(fn) {
88+
if (this._state === DONE_COMPLETE_STATE) {
89+
fn();
90+
} else {
91+
this._doneCallbacks.push(fn);
92+
}
93+
},
94+
95+
progress: noop,
96+
97+
getPromise: function() {
98+
if (!this.promise) {
99+
var self = this;
100+
this.promise = $q(function(resolve, reject) {
101+
self.done(function(status) {
102+
status === false ? reject() : resolve();
103+
});
104+
});
105+
}
106+
return this.promise;
107+
},
108+
109+
then: function(resolveHandler, rejectHandler) {
110+
return this.getPromise().then(resolveHandler, rejectHandler);
111+
},
112+
113+
'catch': function(handler) {
114+
return this.getPromise()['catch'](handler);
115+
},
116+
117+
'finally': function(handler) {
118+
return this.getPromise()['finally'](handler);
119+
},
120+
121+
pause: function() {
122+
if (this.host.pause) {
123+
this.host.pause();
124+
}
125+
},
126+
127+
resume: function() {
128+
if (this.host.resume) {
129+
this.host.resume();
130+
}
131+
},
132+
133+
end: function() {
134+
if (this.host.end) {
135+
this.host.end();
136+
}
137+
this._resolve(true);
138+
},
139+
140+
cancel: function() {
141+
if (this.host.cancel) {
142+
this.host.cancel();
143+
}
144+
this._resolve(false);
145+
},
146+
147+
complete: function(response) {
148+
var self = this;
149+
if (self._state === INITIAL_STATE) {
150+
self._state = DONE_PENDING_STATE;
151+
self._runInAnimationFrame(function() {
152+
self._resolve(response);
153+
});
154+
}
155+
},
156+
157+
_resolve: function(response) {
158+
if (this._state !== DONE_COMPLETE_STATE) {
159+
forEach(this._doneCallbacks, function(fn) {
160+
fn(response);
161+
});
162+
this._doneCallbacks.length = 0;
163+
this._state = DONE_COMPLETE_STATE;
164+
}
165+
}
166+
};
167+
168+
return AnimateRunner;
169+
}];
170+
};

0 commit comments

Comments
 (0)