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

Commit 2430347

Browse files
matskomhevery
authored andcommitted
fix(ngAnimate): make sure that the class value passed into addClass/removeClass is the base class string value
1 parent f61ff69 commit 2430347

File tree

2 files changed

+137
-104
lines changed

2 files changed

+137
-104
lines changed

src/ngAnimate/animate.js

+105-104
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@ angular.module('ngAnimate', ['ng'])
489489
done:done
490490
});
491491

492+
var baseClassName = className;
492493
if(event == 'addClass') {
493494
className = suffixClasses(className, '-add');
494495
} else if(event == 'removeClass') {
@@ -504,7 +505,7 @@ angular.module('ngAnimate', ['ng'])
504505

505506
if(animation.start) {
506507
if(event == 'addClass' || event == 'removeClass') {
507-
animation.endFn = animation.start(element, className, fn);
508+
animation.endFn = animation.start(element, baseClassName, fn);
508509
} else {
509510
animation.endFn = animation.start(element, fn);
510511
}
@@ -520,17 +521,6 @@ angular.module('ngAnimate', ['ng'])
520521
});
521522
}
522523

523-
function suffixClasses(classes, suffix) {
524-
var className = '';
525-
classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
526-
forEach(classes, function(klass, i) {
527-
if(klass && klass.length > 0) {
528-
className += (i > 0 ? ' ' : '') + klass + suffix;
529-
}
530-
});
531-
return className;
532-
}
533-
534524
function progress(index) {
535525
animations[index].done = true;
536526
(animations[index].endFn || noop)();
@@ -550,117 +540,128 @@ angular.module('ngAnimate', ['ng'])
550540
}
551541
}
552542
}]);
553-
}])
554543

555-
.animation('', ['$window','$sniffer', '$timeout', function($window, $sniffer, $timeout) {
556-
var noop = angular.noop;
557-
var forEach = angular.forEach;
558-
function animate(element, className, done) {
559-
if (!($sniffer.transitions || $sniffer.animations)) {
560-
done();
561-
} else {
562-
var activeClassName = '';
563-
$timeout(startAnimation, 1, false);
564-
565-
//this acts as the cancellation function in case
566-
//a new animation is triggered while another animation
567-
//is still going on (otherwise the active className
568-
//would still hang around until the timer is complete).
569-
return onEnd;
570-
}
544+
$animateProvider.register('', ['$window','$sniffer', '$timeout', function($window, $sniffer, $timeout) {
545+
var noop = angular.noop;
546+
var forEach = angular.forEach;
547+
function animate(element, className, done) {
548+
if (!($sniffer.transitions || $sniffer.animations)) {
549+
done();
550+
} else {
551+
var activeClassName = '';
552+
$timeout(startAnimation, 1, false);
553+
554+
//this acts as the cancellation function in case
555+
//a new animation is triggered while another animation
556+
//is still going on (otherwise the active className
557+
//would still hang around until the timer is complete).
558+
return onEnd;
559+
}
571560

572-
function parseMaxTime(str) {
573-
var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : [];
574-
forEach(values, function(value) {
575-
total = Math.max(parseFloat(value) || 0, total);
576-
});
577-
return total;
578-
}
561+
function parseMaxTime(str) {
562+
var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : [];
563+
forEach(values, function(value) {
564+
total = Math.max(parseFloat(value) || 0, total);
565+
});
566+
return total;
567+
}
579568

580-
function startAnimation() {
581-
var duration = 0;
582-
forEach(className.split(' '), function(klass, i) {
583-
activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
584-
});
569+
function startAnimation() {
570+
var duration = 0;
571+
forEach(className.split(' '), function(klass, i) {
572+
activeClassName += (i > 0 ? ' ' : '') + klass + '-active';
573+
});
585574

586-
element.addClass(activeClassName);
575+
element.addClass(activeClassName);
587576

588-
//one day all browsers will have these properties
589-
var w3cAnimationProp = 'animation';
590-
var w3cTransitionProp = 'transition';
577+
//one day all browsers will have these properties
578+
var w3cAnimationProp = 'animation';
579+
var w3cTransitionProp = 'transition';
591580

592-
//but some still use vendor-prefixed styles
593-
var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation';
594-
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
581+
//but some still use vendor-prefixed styles
582+
var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation';
583+
var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';
595584

596-
var durationKey = 'Duration',
597-
delayKey = 'Delay',
598-
animationIterationCountKey = 'IterationCount';
585+
var durationKey = 'Duration',
586+
delayKey = 'Delay',
587+
animationIterationCountKey = 'IterationCount';
599588

600-
//we want all the styles defined before and after
601-
var ELEMENT_NODE = 1;
602-
forEach(element, function(element) {
603-
if (element.nodeType == ELEMENT_NODE) {
604-
var elementStyles = $window.getComputedStyle(element) || {};
589+
//we want all the styles defined before and after
590+
var ELEMENT_NODE = 1;
591+
forEach(element, function(element) {
592+
if (element.nodeType == ELEMENT_NODE) {
593+
var elementStyles = $window.getComputedStyle(element) || {};
605594

606-
var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]),
607-
parseMaxTime(elementStyles[vendorTransitionProp + delayKey]));
595+
var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]),
596+
parseMaxTime(elementStyles[vendorTransitionProp + delayKey]));
608597

609-
var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]),
610-
parseMaxTime(elementStyles[vendorAnimationProp + delayKey]));
598+
var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]),
599+
parseMaxTime(elementStyles[vendorAnimationProp + delayKey]));
611600

612-
var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]),
613-
parseMaxTime(elementStyles[vendorTransitionProp + durationKey]));
601+
var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]),
602+
parseMaxTime(elementStyles[vendorTransitionProp + durationKey]));
614603

615-
var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]),
616-
parseMaxTime(elementStyles[vendorAnimationProp + durationKey]));
604+
var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]),
605+
parseMaxTime(elementStyles[vendorAnimationProp + durationKey]));
617606

618-
if(animationDuration > 0) {
619-
animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0,
620-
parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0,
621-
1);
607+
if(animationDuration > 0) {
608+
animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0,
609+
parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0,
610+
1);
611+
}
612+
613+
duration = Math.max(animationDelay + animationDuration,
614+
transitionDelay + transitionDuration,
615+
duration);
622616
}
617+
});
623618

624-
duration = Math.max(animationDelay + animationDuration,
625-
transitionDelay + transitionDuration,
626-
duration);
627-
}
628-
});
619+
$timeout(done, duration * 1000, false);
620+
}
629621

630-
$timeout(done, duration * 1000, false);
622+
//this will automatically be called by $animate so
623+
//there is no need to attach this internally to the
624+
//timeout done method
625+
function onEnd(cancelled) {
626+
element.removeClass(activeClassName);
627+
628+
//only when the animation is cancelled is the done()
629+
//function not called for this animation therefore
630+
//this must be also called
631+
if(cancelled) {
632+
done();
633+
}
634+
}
631635
}
632636

633-
//this will automatically be called by $animate so
634-
//there is no need to attach this internally to the
635-
//timeout done method
636-
function onEnd(cancelled) {
637-
element.removeClass(activeClassName);
638-
639-
//only when the animation is cancelled is the done()
640-
//function not called for this animation therefore
641-
//this must be also called
642-
if(cancelled) {
643-
done();
637+
return {
638+
enter : function(element, done) {
639+
return animate(element, 'ng-enter', done);
640+
},
641+
leave : function(element, done) {
642+
return animate(element, 'ng-leave', done);
643+
},
644+
move : function(element, done) {
645+
return animate(element, 'ng-move', done);
646+
},
647+
addClass : function(element, className, done) {
648+
return animate(element, suffixClasses(className, '-add'), done);
649+
},
650+
removeClass : function(element, className, done) {
651+
return animate(element, suffixClasses(className, '-remove'), done);
644652
}
645-
}
646-
}
653+
};
647654

648-
return {
649-
enter : function(element, done) {
650-
return animate(element, 'ng-enter', done);
651-
},
652-
leave : function(element, done) {
653-
return animate(element, 'ng-leave', done);
654-
},
655-
move : function(element, done) {
656-
return animate(element, 'ng-move', done);
657-
},
658-
addClass : function(element, className, done) {
659-
return animate(element, className, done);
660-
},
661-
removeClass : function(element, className, done) {
662-
return animate(element, className, done);
663-
}
664-
};
655+
}]);
665656

657+
function suffixClasses(classes, suffix) {
658+
var className = '';
659+
classes = angular.isArray(classes) ? classes : classes.split(/\s+/);
660+
forEach(classes, function(klass, i) {
661+
if(klass && klass.length > 0) {
662+
className += (i > 0 ? ' ' : '') + klass + suffix;
663+
}
664+
});
665+
return className;
666+
}
666667
}]);

test/ngAnimate/animateSpec.js

+32
Original file line numberDiff line numberDiff line change
@@ -1513,4 +1513,36 @@ describe("ngAnimate", function() {
15131513
});
15141514
});
15151515

1516+
it("should provide the correct CSS class to the addClass and removeClass callbacks within a JS animation", function() {
1517+
module(function($animateProvider) {
1518+
$animateProvider.register('.classify', function($timeout) {
1519+
return {
1520+
removeClass : function(element, className, done) {
1521+
element.data('classify','remove-' + className);
1522+
done();
1523+
},
1524+
addClass : function(element, className, done) {
1525+
element.data('classify','add-' + className);
1526+
done();
1527+
}
1528+
}
1529+
});
1530+
})
1531+
inject(function($compile, $rootScope, $animate, $timeout) {
1532+
var element = html($compile('<div class="classify"></div>')($rootScope));
1533+
1534+
$animate.addClass(element, 'super');
1535+
expect(element.data('classify')).toBe('add-super');
1536+
$timeout.flush();
1537+
1538+
$animate.removeClass(element, 'super');
1539+
expect(element.data('classify')).toBe('remove-super');
1540+
$timeout.flush();
1541+
1542+
$animate.addClass(element, 'superguy');
1543+
expect(element.data('classify')).toBe('add-superguy');
1544+
$timeout.flush();
1545+
});
1546+
});
1547+
15161548
});

0 commit comments

Comments
 (0)