From 2f7fad5f9f629c48b93c710ab5fdf8a85c3396e3 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Mon, 4 Sep 2017 19:26:44 +0200 Subject: [PATCH 1/2] fix(ngMock.browserTrigger): add 'bubbles' to Transition/Animation Event When the event objects are created synthetically, the bubbles property is set to false if not explicitly defined --- src/ngMock/browserTrigger.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ngMock/browserTrigger.js b/src/ngMock/browserTrigger.js index e2483204d467..13b2592fea03 100644 --- a/src/ngMock/browserTrigger.js +++ b/src/ngMock/browserTrigger.js @@ -55,25 +55,25 @@ if (/transitionend/.test(eventType)) { if (window.WebKitTransitionEvent) { evnt = new window.WebKitTransitionEvent(eventType, eventData); - evnt.initEvent(eventType, false, true); + evnt.initEvent(eventType, eventData.bubbles, true); } else { try { evnt = new window.TransitionEvent(eventType, eventData); } catch (e) { evnt = window.document.createEvent('TransitionEvent'); - evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0); + evnt.initTransitionEvent(eventType, eventData.bubbles, null, null, eventData.elapsedTime || 0); } } } else if (/animationend/.test(eventType)) { if (window.WebKitAnimationEvent) { evnt = new window.WebKitAnimationEvent(eventType, eventData); - evnt.initEvent(eventType, false, true); + evnt.initEvent(eventType, eventData.bubbles, true); } else { try { evnt = new window.AnimationEvent(eventType, eventData); } catch (e) { evnt = window.document.createEvent('AnimationEvent'); - evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0); + evnt.initAnimationEvent(eventType, eventData.bubbles, null, null, eventData.elapsedTime || 0); } } } else if (/touch/.test(eventType) && supportsTouchEvents()) { From 20590c0bd007fda6b7a2f9b4eaf44dcf995ba8bb Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Mon, 4 Sep 2017 19:42:38 +0200 Subject: [PATCH 2/2] fix(ngAnimate): don't close animations when child transitions close --- src/ngAnimate/animateCss.js | 6 ++++ test/ngAnimate/animateCssSpec.js | 54 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/ngAnimate/animateCss.js b/src/ngAnimate/animateCss.js index b61b8aa28ef6..b64cda7e0afe 100644 --- a/src/ngAnimate/animateCss.js +++ b/src/ngAnimate/animateCss.js @@ -805,6 +805,12 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro event.stopPropagation(); var ev = event.originalEvent || event; + if (ev.target !== node) { + // Since TransitionEvent / AnimationEvent bubble up, + // we have to ignore events by finished child animations + return; + } + // we now always use `Date.now()` due to the recent changes with // event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info) var timeStamp = ev.$manualTimeStamp || Date.now(); diff --git a/test/ngAnimate/animateCssSpec.js b/test/ngAnimate/animateCssSpec.js index b274de05f18a..d22100f7cf83 100644 --- a/test/ngAnimate/animateCssSpec.js +++ b/test/ngAnimate/animateCssSpec.js @@ -532,6 +532,60 @@ describe('ngAnimate $animateCss', function() { assertAnimationComplete(true); })); + it('should not close a transition when a child element fires the transitionend event', + inject(function($animateCss) { + + ss.addPossiblyPrefixedRule('.ng-enter', 'transition:4s linear all;'); + ss.addPossiblyPrefixedRule('.non-angular-animation', 'transition:5s linear all;'); + + var child = angular.element('
'); + element.append(child); + + var animator = $animateCss(element, options); + animator.start(); + triggerAnimationStartFrame(); + + browserTrigger(child, 'transitionend', { + timeStamp: Date.now(), + elapsedTime: 5, + bubbles: true + }); + + transitionProgress(element, 1); + + assertAnimationComplete(false); + + transitionProgress(element, 4); + assertAnimationComplete(true); + })); + + it('should not close a keyframe animation when a child element fires the animationend event', + inject(function($animateCss) { + + ss.addPossiblyPrefixedRule('.ng-enter', 'animation:animation 4s;'); + ss.addPossiblyPrefixedRule('.non-angular-animation', 'animation:animation 5s;'); + + var child = angular.element('
'); + element.append(child); + + var animator = $animateCss(element, options); + animator.start(); + triggerAnimationStartFrame(); + + browserTrigger(child, 'animationend', { + timeStamp: Date.now(), + elapsedTime: 5, + bubbles: true + }); + + keyframeProgress(element, 1); + + assertAnimationComplete(false); + + keyframeProgress(element, 4); + assertAnimationComplete(true); + })); + it('should use the highest keyframe duration value detected in the CSS class', inject(function($animateCss) { ss.addPossiblyPrefixedRule('.ng-enter', 'animation:animation 1s, animation 2s, animation 3s;');