From 669d31dc964bed429e499f444253e42e718173b8 Mon Sep 17 00:00:00 2001 From: Christoph Burgdorf Date: Fri, 12 Apr 2013 01:11:21 +0200 Subject: [PATCH 1/2] fix:(animator): Correctly handle multiple durations In case multiple durations are specified like so: transition-duration: 0.5s, 3000ms; transition-property: left, height; The animator will pick the longest duration. Fixes #2373 --- src/ng/animator.js | 15 +++++++++++++-- test/ng/animatorSpec.js | 9 +++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/ng/animator.js b/src/ng/animator.js index 536c93c13b7d..ac5da628e2a8 100644 --- a/src/ng/animator.js +++ b/src/ng/animator.js @@ -261,6 +261,17 @@ var $AnimatorProvider = function() { // $window.setTimeout(beginAnimation, 0); this was causing the element not to animate // keep at 1 for animation dom rerender $window.setTimeout(beginAnimation, 1); + + function getMaxDuration(durationString){ + if (isUndefined(durationString)){ + return 0; + } + + var normalizedValues = map(durationString.split(','), function(val){ + return parseFloat(val); + }); + return Math.max.apply(null, normalizedValues); + } function beginAnimation() { element.addClass(startClass); @@ -276,8 +287,8 @@ var $AnimatorProvider = function() { forEach(element, function(element) { var globalStyles = $window.getComputedStyle(element) || {}; duration = Math.max( - parseFloat(globalStyles[w3cTransitionProp + durationKey]) || - parseFloat(globalStyles[vendorTransitionProp + durationKey]) || + getMaxDuration(globalStyles[w3cTransitionProp + durationKey]) || + getMaxDuration(globalStyles[vendorTransitionProp + durationKey]) || 0, duration); }); diff --git a/test/ng/animatorSpec.js b/test/ng/animatorSpec.js index 1b393e9114f3..35b54d0d758b 100644 --- a/test/ng/animatorSpec.js +++ b/test/ng/animatorSpec.js @@ -309,10 +309,10 @@ describe("$animator", function() { }) }); - it("should skip animations if disabled and run when enabled", - inject(function($animator, $rootScope, $compile, $sniffer) { + it("should skip animations if disabled and run when enabled picking the longest specified duration", + inject(function($animator, $rootScope, $compile, $sniffer) { $animator.enabled(false); - element = $compile(html('
1
'))($rootScope); + element = $compile(html('
foo
'))($rootScope); var animator = $animator($rootScope, { ngAnimate : '{show: \'inline-show\'}' }); @@ -330,10 +330,11 @@ describe("$animator", function() { animator.show(element); if ($sniffer.supportsTransitions) { window.setTimeout.expect(1).process(); - window.setTimeout.expect(1000).process(); + window.setTimeout.expect(2000).process(); } expect(element[0].style.display).toBe(''); })); + }); it("should throw an error when an invalid ng-animate syntax is provided", inject(function($compile, $rootScope) { From d96e19f887c4369f4c7e3af55dec2d8031246886 Mon Sep 17 00:00:00 2001 From: romiem Date: Sat, 13 Apr 2013 15:44:37 +0200 Subject: [PATCH 2/2] fix(animation): handle transition-delay property correctly The code also handles situations with multiple different delay and duration values. E.g. in the following example, the correct duration would be 3 seconds: property | duration | delay height | 1s | 2s left | 2s | 1s opacity | 1s | 2s --- src/Angular.js | 4 ++++ src/ng/animator.js | 35 ++++++++++++++++++++++------------- test/ng/animatorSpec.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/src/Angular.js b/src/Angular.js index bf64c6c27de5..945849757182 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -185,6 +185,10 @@ function reverseParams(iteratorFn) { return function(value, key) { iteratorFn(key, value) }; } +function safelySplitByComma(str){ + return isUndefined(str) ? [] : str.split(','); +} + /** * A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric * characters such as '012ABC'. The reason why we are not using simply a number counter is that diff --git a/src/ng/animator.js b/src/ng/animator.js index ac5da628e2a8..c7224981bfff 100644 --- a/src/ng/animator.js +++ b/src/ng/animator.js @@ -262,15 +262,19 @@ var $AnimatorProvider = function() { // keep at 1 for animation dom rerender $window.setTimeout(beginAnimation, 1); - function getMaxDuration(durationString){ - if (isUndefined(durationString)){ - return 0; - } - - var normalizedValues = map(durationString.split(','), function(val){ - return parseFloat(val); - }); - return Math.max.apply(null, normalizedValues); + function getMaxDuration(durationString, delayString) { + var durations = safelySplitByComma(durationString), + delays = safelySplitByComma(delayString), + overallTimeSpent = 0; + + for (var i = 0, ii = Math.max(durations.length, delays.length); i < ii; i++) { + var combinedDuration = (parseFloat(durations.shift() || 0) + parseFloat(delays.shift() || 0)); + if (combinedDuration > overallTimeSpent) { + overallTimeSpent = combinedDuration; + } + } + + return overallTimeSpent; } function beginAnimation() { @@ -281,14 +285,19 @@ var $AnimatorProvider = function() { var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; var w3cTransitionProp = 'transition'; //one day all browsers will have this - var durationKey = 'Duration'; - var duration = 0; + var durationKey = 'Duration', + delayKey = 'Delay', + duration = 0; + //we want all the styles defined before and after forEach(element, function(element) { var globalStyles = $window.getComputedStyle(element) || {}; duration = Math.max( - getMaxDuration(globalStyles[w3cTransitionProp + durationKey]) || - getMaxDuration(globalStyles[vendorTransitionProp + durationKey]) || + getMaxDuration(globalStyles[w3cTransitionProp + durationKey], + globalStyles[w3cTransitionProp + delayKey]) || + + getMaxDuration(globalStyles[vendorTransitionProp + durationKey], + globalStyles[vendorTransitionProp + delayKey]) || 0, duration); }); diff --git a/test/ng/animatorSpec.js b/test/ng/animatorSpec.js index 35b54d0d758b..0911b36d7da1 100644 --- a/test/ng/animatorSpec.js +++ b/test/ng/animatorSpec.js @@ -335,6 +335,36 @@ describe("$animator", function() { expect(element[0].style.display).toBe(''); })); + it("should skip animations if disabled and run when enabled picking the longest specified duration/delay combination", + inject(function($animator, $rootScope, $compile, $sniffer) { + $animator.enabled(false); + element = $compile(html('
foo
'))($rootScope); + + var animator = $animator($rootScope, { + ngAnimate : '{show: \'inline-show\'}' + }); + + element.css('display','none'); + expect(element.css('display')).toBe('none'); + animator.show(element); + expect(element[0].style.display).toBe(''); + + $animator.enabled(true); + + element.css('display','none'); + expect(element.css('display')).toBe('none'); + + animator.show(element); + if ($sniffer.supportsTransitions) { + window.setTimeout.expect(1).process(); + window.setTimeout.expect(3000).process(); + } + expect(element[0].style.display).toBe(''); + })); + }); it("should throw an error when an invalid ng-animate syntax is provided", inject(function($compile, $rootScope) {