Skip to content

Commit

Permalink
fix($animate): ensure staggering animations understand multiple delay…
Browse files Browse the repository at this point in the history
… values
  • Loading branch information
matsko authored and jamesdaily committed Jan 27, 2014
1 parent 2ceb180 commit bd519b2
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 12 deletions.
47 changes: 36 additions & 11 deletions src/ngAnimate/animate.js
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,8 @@ angular.module('ngAnimate', ['ng'])
var data = cacheKey ? lookupCache[cacheKey] : null;
if(!data) {
var transitionDuration = 0, transitionDelay = 0,
animationDuration = 0, animationDelay = 0;
animationDuration = 0, animationDelay = 0,
transitionDelayStyle, animationDelayStyle;

//we want all the styles defined before and after
forEach(element, function(element) {
Expand All @@ -799,9 +800,13 @@ angular.module('ngAnimate', ['ng'])
transitionDuration = Math.max(parseMaxTime(elementStyles[transitionProp + durationKey]), transitionDuration);

if(!onlyCheckTransition) {
transitionDelay = Math.max(parseMaxTime(elementStyles[transitionProp + delayKey]), transitionDelay);
transitionDelayStyle = elementStyles[transitionProp + delayKey];

animationDelay = Math.max(parseMaxTime(elementStyles[animationProp + delayKey]), animationDelay);
transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);

animationDelayStyle = elementStyles[animationProp + delayKey];

animationDelay = Math.max(parseMaxTime(animationDelayStyle), animationDelay);

var aDuration = parseMaxTime(elementStyles[animationProp + durationKey]);

Expand All @@ -815,9 +820,11 @@ angular.module('ngAnimate', ['ng'])
});
data = {
total : 0,
transitionDelayStyle: transitionDelayStyle,
transitionDelay : transitionDelay,
animationDelay : animationDelay,
transitionDuration : transitionDuration,
animationDelayStyle: animationDelayStyle,
animationDelay : animationDelay,
animationDuration : animationDuration
};
if(cacheKey) {
Expand Down Expand Up @@ -905,16 +912,25 @@ angular.module('ngAnimate', ['ng'])

if(timings.transitionDuration > 0) {
node.style[transitionProp + propertyKey] = '';
if(ii > 0 && stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
formerStyle = applyStyle(node, prefix + 'transition-delay: ' +
(ii * stagger.transitionDelay + timings.transitionDelay) + 's');
}
}

if(ii > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0) {
formerStyle = applyStyle(node, prefix + 'animation-delay: ' +
(ii * stagger.animationDelay + timings.animationDelay) + 's');
if(ii > 0) {
var staggerStyle = '';
if(stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
staggerStyle += prefix + 'transition-delay: ' +
prepareStaggerDelay(timings.transitionDelayStyle, stagger.transitionDelay, ii) + '; ';
}

if(stagger.animationDelay > 0 && stagger.animationDuration === 0) {
staggerStyle += prefix + 'animation-delay: ' +
prepareStaggerDelay(timings.animationDelayStyle, stagger.animationDelay, ii) + '; ';
}

if(staggerStyle.length > 0) {
formerStyle = applyStyle(node, staggerStyle);
}
}

element.addClass(activeClassName);
});

Expand Down Expand Up @@ -948,6 +964,15 @@ angular.module('ngAnimate', ['ng'])
done();
}

function prepareStaggerDelay(delayStyle, staggerDelay, index) {
var style = '';
angular.forEach(delayStyle.split(','), function(val, i) {
style += (i > 0 ? ',' : '') +
(index * staggerDelay + parseInt(val, 10)) + 's';
});
return style;
}

function onAnimationProgress(event) {
event.stopPropagation();
var ev = event.originalEvent || event;
Expand Down
116 changes: 115 additions & 1 deletion test/ngAnimate/animateSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ describe("ngAnimate", function() {

ss.addRule('.ani.ng-enter, .ani.ng-leave, .ani-fake.ng-enter, .ani-fake.ng-leave',
'-webkit-animation:1s my_animation;' +
'transition:1s my_animation;');
'animation:1s my_animation;');

ss.addRule('.ani.ng-enter-stagger, .ani.ng-leave-stagger',
'-webkit-animation-delay:0.1s;' +
Expand Down Expand Up @@ -747,6 +747,40 @@ describe("ngAnimate", function() {
expect(elements[3].attr('style')).not.toMatch(/animation-delay: 0\.3\d*s/);
expect(elements[4].attr('style')).not.toMatch(/animation-delay: 0\.4\d*s/);
}));

it("should stagger items when multiple animation durations/delays are defined",
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {

if(!$sniffer.transitions) return;

$animate.enabled(true);

ss.addRule('.ani.ng-enter, .ani.ng-leave',
'-webkit-animation:my_animation 1s 1s, your_animation 1s 2s;' +
'animation:my_animation 1s 1s, your_animation 1s 2s;');

ss.addRule('.ani.ng-enter-stagger, .ani.ng-leave-stagger',
'-webkit-animation-delay:0.1s;' +
'animation-delay:0.1s;');

var container = $compile(html('<div></div>'))($rootScope);

var elements = [];
for(var i = 0; i < 4; i++) {
var newScope = $rootScope.$new();
var element = $compile('<div class="ani"></div>')(newScope);
$animate.enter(element, container);
elements.push(element);
};

$rootScope.$digest();
$timeout.flush();

expect(elements[0].attr('style')).toBeFalsy();
expect(elements[1].attr('style')).toMatch(/animation-delay: 1\.1\d*s,\s*2\.1\d*s/);
expect(elements[2].attr('style')).toMatch(/animation-delay: 1\.2\d*s,\s*2\.2\d*s/);
expect(elements[3].attr('style')).toMatch(/animation-delay: 1\.3\d*s,\s*2\.3\d*s/);
}));
});

describe("Transitions", function() {
Expand Down Expand Up @@ -950,7 +984,87 @@ describe("ngAnimate", function() {
expect(elements[3].attr('style')).not.toMatch(/transition-delay: 0\.3\d*s/);
expect(elements[4].attr('style')).not.toMatch(/transition-delay: 0\.4\d*s/);
}));

it("should stagger items when multiple transition durations/delays are defined",
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {

if(!$sniffer.transitions) return;

$animate.enabled(true);

ss.addRule('.ani.ng-enter, .ani.ng-leave',
'-webkit-transition:1s linear color 2s, 3s linear font-size 4s;' +
'transition:1s linear color 2s, 3s linear font-size 4s;');

ss.addRule('.ani.ng-enter-stagger, .ani.ng-leave-stagger',
'-webkit-transition-delay:0.1s;' +
'transition-delay:0.1s;');

var container = $compile(html('<div></div>'))($rootScope);

var elements = [];
for(var i = 0; i < 4; i++) {
var newScope = $rootScope.$new();
var element = $compile('<div class="ani"></div>')(newScope);
$animate.enter(element, container);
elements.push(element);
};

$rootScope.$digest();
$timeout.flush();

expect(elements[0].attr('style')).toBeFalsy();
expect(elements[1].attr('style')).toMatch(/transition-delay: 2\.1\d*s,\s*4\.1\d*s/);
expect(elements[2].attr('style')).toMatch(/transition-delay: 2\.2\d*s,\s*4\.2\d*s/);
expect(elements[3].attr('style')).toMatch(/transition-delay: 2\.3\d*s,\s*4\.3\d*s/);
}));
});

it("should apply staggering to both transitions and keyframe animations when used within the same animation",
inject(function($animate, $rootScope, $compile, $sniffer, $timeout, $document, $rootElement) {

if(!$sniffer.transitions) return;

$animate.enabled(true);

ss.addRule('.ani.ng-enter, .ani.ng-leave',
'-webkit-animation:my_animation 1s 1s, your_animation 1s 2s;' +
'animation:my_animation 1s 1s, your_animation 1s 2s;' +
'-webkit-transition:1s linear all 0s;' +
'transition:1s linear all 1s;');

ss.addRule('.ani.ng-enter-stagger, .ani.ng-leave-stagger',
'-webkit-transition-delay:0.1s;' +
'transition-delay:0.1s;' +
'-webkit-animation-delay:0.2s;' +
'animation-delay:0.2s;');

var container = $compile(html('<div></div>'))($rootScope);

var elements = [];
for(var i = 0; i < 3; i++) {
var newScope = $rootScope.$new();
var element = $compile('<div class="ani"></div>')(newScope);
$animate.enter(element, container);
elements.push(element);
};

$rootScope.$digest();
$timeout.flush();

expect(elements[0].attr('style')).toBeFalsy();

expect(elements[1].attr('style')).toMatch(/transition-delay:\s+1.1\d*/);
expect(elements[1].attr('style')).toMatch(/animation-delay: 1\.2\d*s,\s*2\.2\d*s/);

expect(elements[2].attr('style')).toMatch(/transition-delay:\s+1.2\d*/);
expect(elements[2].attr('style')).toMatch(/animation-delay: 1\.4\d*s,\s*2\.4\d*s/);

for(var i = 0; i < 3; i++) {
browserTrigger(elements[i],'transitionend', { timeStamp: Date.now() + 22000, elapsedTime: 22000 });
expect(elements[i].attr('style')).toBeFalsy();
}
}));
});

describe('animation evaluation', function () {
Expand Down

0 comments on commit bd519b2

Please sign in to comment.