Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 15389b0

Browse files
matskomhevery
authored andcommitted
fix(ngAnimate): $timeout integration and cancel callbacks added
1 parent 7d69d52 commit 15389b0

File tree

5 files changed

+423
-429
lines changed

5 files changed

+423
-429
lines changed

docs/component-spec/annotationsSpec.js

+22-17
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ describe('Docs Annotations', function() {
6969
beforeEach(function() {
7070
module(function($provide, $animateProvider) {
7171
$provide.value('$window', window = angular.mock.createMockWindow());
72-
$animateProvider.register('.foldout', function($window) {
72+
$animateProvider.register('.foldout', function($timeout) {
7373
return {
7474
enter : function(element, done) {
75-
$window.setTimeout(done, 1000);
75+
$timeout(done, 1000);
7676
},
7777
removeClass : function(element, className, done) {
78-
$window.setTimeout(done, 500);
78+
$timeout(done, 500);
7979
},
8080
addClass : function(element, className, done) {
81-
$window.setTimeout(done, 200);
81+
$timeout(done, 200);
8282
}
8383
}
8484
});
@@ -112,41 +112,46 @@ describe('Docs Annotations', function() {
112112
expect(foldout.html()).toContain('loading');
113113
}));
114114

115-
it('should download a foldout HTML page and animate the contents', inject(function($httpBackend) {
115+
it('should download a foldout HTML page and animate the contents', inject(function($httpBackend, $timeout) {
116116
$httpBackend.expect('GET', url).respond('hello');
117117

118118
element.triggerHandler('click');
119119
$httpBackend.flush();
120120

121-
window.setTimeout.expect(1).process();
122-
window.setTimeout.expect(1000).process();
121+
$timeout.flushNext(0);
122+
$timeout.flushNext(1);
123+
$timeout.flushNext(0);
124+
$timeout.flushNext(1000);
123125

124126
var kids = body.children();
125127
var foldout = angular.element(kids[kids.length-1]);
126128
expect(foldout.text()).toContain('hello');
127129
}));
128130

129-
it('should hide then show when clicked again', inject(function($httpBackend) {
131+
it('should hide then show when clicked again', inject(function($httpBackend, $timeout) {
130132
$httpBackend.expect('GET', url).respond('hello');
131133

132134
//enter
133135
element.triggerHandler('click');
134136
$httpBackend.flush();
135-
window.setTimeout.expect(1).process();
136-
window.setTimeout.expect(1000).process();
137-
window.setTimeout.expect(0).process();
137+
$timeout.flushNext(0);
138+
$timeout.flushNext(1);
139+
$timeout.flushNext(0);
140+
$timeout.flushNext(1000);
138141

139142
//hide
140143
element.triggerHandler('click');
141-
window.setTimeout.expect(1).process();
142-
window.setTimeout.expect(200).process();
143-
window.setTimeout.expect(0).process();
144+
$timeout.flushNext(1);
145+
$timeout.flushNext(0);
146+
$timeout.flushNext(200);
147+
$timeout.flushNext(0);
144148

145149
//show
146150
element.triggerHandler('click');
147-
window.setTimeout.expect(1).process();
148-
window.setTimeout.expect(500).process();
149-
window.setTimeout.expect(0).process();
151+
$timeout.flushNext(1);
152+
$timeout.flushNext(0);
153+
$timeout.flushNext(500);
154+
$timeout.flushNext(0);
150155
}));
151156

152157
});

src/ng/animate.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ var $AnimateProvider = ['$provide', function($provide) {
5656
$provide.factory(name, factory);
5757
};
5858

59-
this.$get = function() {
59+
this.$get = ['$timeout', function($timeout) {
6060
return {
6161
enter : function(element, parent, after, done) {
6262
var afterNode = after && after[after.length - 1];
@@ -66,12 +66,12 @@ var $AnimateProvider = ['$provide', function($provide) {
6666
forEach(element, function(node) {
6767
parentNode.insertBefore(node, afterNextSibling);
6868
});
69-
(done || noop)();
69+
$timeout(done || noop, 0, false);
7070
},
7171

7272
leave : function(element, done) {
7373
element.remove();
74-
(done || noop)();
74+
$timeout(done || noop, 0, false);
7575
},
7676

7777
move : function(element, parent, after, done) {
@@ -85,18 +85,18 @@ var $AnimateProvider = ['$provide', function($provide) {
8585
className :
8686
isArray(className) ? className.join(' ') : '';
8787
element.addClass(className);
88-
(done || noop)();
88+
$timeout(done || noop, 0, false);
8989
},
9090

9191
removeClass : function(element, className, done) {
9292
className = isString(className) ?
9393
className :
9494
isArray(className) ? className.join(' ') : '';
9595
element.removeClass(className);
96-
(done || noop)();
96+
$timeout(done || noop, 0, false);
9797
},
9898

9999
enabled : noop
100100
};
101-
};
101+
}];
102102
}];

src/ngAnimate/animate.js

+71-69
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,15 @@ angular.module('ngAnimate', ['ng'])
203203
var NG_ANIMATE_STATE = '$$ngAnimateState';
204204
var rootAnimateState = {running:true};
205205

206-
$provide.decorator('$animate', ['$delegate', '$injector', '$window', '$sniffer', '$rootElement',
207-
function($delegate, $injector, $window, $sniffer, $rootElement) {
206+
$provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement',
207+
function($delegate, $injector, $sniffer, $rootElement) {
208208

209209
var noop = angular.noop;
210210
var forEach = angular.forEach;
211211

212212
$rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
213213

214-
function lookup(name) {
214+
function lookup(name) {
215215
if (name) {
216216
var classes = name.substr(1).split('.'),
217217
classMap = {};
@@ -241,7 +241,7 @@ angular.module('ngAnimate', ['ng'])
241241
/**
242242
* @ngdoc object
243243
* @name ngAnimate.$animate
244-
* @requires $window, $sniffer, $rootElement
244+
* @requires $timeout, $sniffer, $rootElement
245245
* @function
246246
*
247247
* @description
@@ -444,80 +444,72 @@ angular.module('ngAnimate', ['ng'])
444444
and the onComplete callback will be fired once the animation is fully complete.
445445
*/
446446
function performAnimation(event, className, element, parent, after, onComplete) {
447-
if(nothingToAnimate(className, element)) {
448-
(onComplete || noop)();
449-
} else {
450-
var classes = ((element.attr('class') || '') + ' ' + className),
451-
animationLookup = (' ' + classes).replace(/\s+/g,'.'),
452-
animations = [];
453-
forEach(lookup(animationLookup), function(animation, index) {
454-
animations.push({
455-
start : animation[event],
456-
done : false
457-
});
447+
var classes = ((element.attr('class') || '') + ' ' + className),
448+
animationLookup = (' ' + classes).replace(/\s+/g,'.'),
449+
animations = [];
450+
forEach(lookup(animationLookup), function(animation, index) {
451+
animations.push({
452+
start : animation[event]
458453
});
454+
});
459455

460-
if (!parent) {
461-
parent = after ? after.parent() : element.parent();
462-
}
463-
var disabledAnimation = { running : true };
456+
if (!parent) {
457+
parent = after ? after.parent() : element.parent();
458+
}
459+
var disabledAnimation = { running : true };
464460

465-
//skip the animation if animations are disabled, a parent is already being animated
466-
//or the element is not currently attached to the document body.
467-
if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running) {
468-
//avoid calling done() since there is no need to remove any
469-
//data or className values since this happens earlier than that
470-
(onComplete || noop)();
471-
return;
472-
}
461+
//skip the animation if animations are disabled, a parent is already being animated
462+
//or the element is not currently attached to the document body.
463+
if ((parent.inheritedData(NG_ANIMATE_STATE) || disabledAnimation).running) {
464+
//avoid calling done() since there is no need to remove any
465+
//data or className values since this happens earlier than that
466+
(onComplete || noop)();
467+
return;
468+
}
473469

474-
var animationData = element.data(NG_ANIMATE_STATE) || {};
470+
var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
475471

476-
//if an animation is currently running on the element then lets take the steps
477-
//to cancel that animation and fire any required callbacks
478-
if(animationData.running) {
479-
cancelAnimations(animationData.animations);
480-
animationData.done();
481-
}
472+
//if an animation is currently running on the element then lets take the steps
473+
//to cancel that animation and fire any required callbacks
474+
if(ngAnimateState.running) {
475+
cancelAnimations(ngAnimateState.animations);
476+
ngAnimateState.done();
477+
}
482478

483-
element.data(NG_ANIMATE_STATE, {
484-
running:true,
485-
animations:animations,
486-
done:done
487-
});
479+
element.data(NG_ANIMATE_STATE, {
480+
running:true,
481+
animations:animations,
482+
done:done
483+
});
488484

489-
if(event == 'addClass') {
490-
className = suffixClasses(className, '-add');
491-
} else if(event == 'removeClass') {
492-
className = suffixClasses(className, '-remove');
493-
}
485+
if(event == 'addClass') {
486+
className = suffixClasses(className, '-add');
487+
} else if(event == 'removeClass') {
488+
className = suffixClasses(className, '-remove');
489+
}
494490

495-
element.addClass(className);
491+
element.addClass(className);
496492

497-
forEach(animations, function(animation, index) {
498-
var fn = function() {
499-
progress(index);
500-
};
493+
forEach(animations, function(animation, index) {
494+
var fn = function() {
495+
progress(index);
496+
};
501497

502-
if(animation.start) {
503-
if(event == 'addClass' || event == 'removeClass') {
504-
animation.cancel = animation.start(element, className, fn);
505-
} else {
506-
animation.cancel = animation.start(element, fn);
507-
}
498+
if(animation.start) {
499+
if(event == 'addClass' || event == 'removeClass') {
500+
animation.endFn = animation.start(element, className, fn);
508501
} else {
509-
fn();
502+
animation.endFn = animation.start(element, fn);
510503
}
511-
});
512-
}
513-
514-
function nothingToAnimate(className, element) {
515-
return !(className && className.length > 0 && element.length > 0);
516-
}
504+
} else {
505+
fn();
506+
}
507+
});
517508

518509
function cancelAnimations(animations) {
510+
var isCancelledFlag = true;
519511
forEach(animations, function(animation) {
520-
(animation.cancel || noop)(element);
512+
(animation.endFn || noop)(isCancelledFlag);
521513
});
522514
}
523515

@@ -534,6 +526,7 @@ angular.module('ngAnimate', ['ng'])
534526

535527
function progress(index) {
536528
animations[index].done = true;
529+
(animations[index].endFn || noop)();
537530
for(var i=0;i<animations.length;i++) {
538531
if(!animations[i].done) return;
539532
}
@@ -552,7 +545,7 @@ angular.module('ngAnimate', ['ng'])
552545
}]);
553546
}])
554547

555-
.animation('', ['$window','$sniffer', function($window, $sniffer) {
548+
.animation('', ['$window','$sniffer', '$timeout', function($window, $sniffer, $timeout) {
556549
return {
557550
enter : function(element, done) {
558551
return animate(element, 'ng-enter', done);
@@ -576,13 +569,13 @@ angular.module('ngAnimate', ['ng'])
576569
done();
577570
} else {
578571
var activeClassName = '';
579-
$window.setTimeout(startAnimation, 1);
572+
$timeout(startAnimation, 1, false);
580573

581574
//this acts as the cancellation function in case
582575
//a new animation is triggered while another animation
583576
//is still going on (otherwise the active className
584577
//would still hang around until the timer is complete).
585-
return onComplete;
578+
return onEnd;
586579
}
587580

588581
function parseMaxTime(str) {
@@ -643,12 +636,21 @@ angular.module('ngAnimate', ['ng'])
643636
}
644637
});
645638

646-
$window.setTimeout(onComplete, duration * 1000);
639+
$timeout(done, duration * 1000, false);
647640
}
648641

649-
function onComplete() {
642+
//this will automatically be called by $animate so
643+
//there is no need to attach this internally to the
644+
//timeout done method
645+
function onEnd(cancelled) {
650646
element.removeClass(activeClassName);
651-
done();
647+
648+
//only when the animation is cancelled is the done()
649+
//function not called for this animation therefore
650+
//this must be also called
651+
if(cancelled) {
652+
done();
653+
}
652654
};
653655
};
654656
}]);

0 commit comments

Comments
 (0)