angularjs-rails 1.4.3 → 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e415c6214199950a129801cafbc7caeee6afe3e7
4
- data.tar.gz: be9aeaa63ef0422053789da8db652a507c78cfe4
3
+ metadata.gz: 37c8e1b04bad364744d395f5bfdf6a037c367097
4
+ data.tar.gz: 68c9df5a22bfa5d8aa55e44d3bd369dd4c769375
5
5
  SHA512:
6
- metadata.gz: d90e9fde02d67527fe34246cdbe6dfece26a167cd94fde26a2de945e0305fb033484818632f70fffb7d0bb1e4ea7554e5c79bb3e6caefdb7403be4086da15182
7
- data.tar.gz: 6d1492649ddf5ce4d3dce214930f8c727135bb816b1b2f7989eda16575e97464b16e503882409efa2ff7398cf7420eb035f291da92087c6b2fb29a81d0291ba3
6
+ metadata.gz: 5602e1bf4c213d6642d2a07a13139f14c1d07efa3db4d06fbdb88a7ebda77739efacc0e068694b5fb09ea4640eb1fd10993ec94411bd41c67b4d231115659f64
7
+ data.tar.gz: 43cb6417936b9847a8db5101a9eb3f74d6a6ce3e4bd4eec0faa9762e014ecfa3aed3724e8f566e9d5973e21700ed48adf2d3a064186c97f0584dd08ff5e10fba
data/README.md CHANGED
@@ -19,12 +19,7 @@ If you desire to require (optional) Angular files, you may include them as well
19
19
 
20
20
  To use the 'unstable' branch, add the following directive to your JavaScript manifest file (application.js):
21
21
 
22
- //= require unstable/angular
23
-
24
- And similarly, for optional Angular assets:
25
-
26
- //= require unstable/angular-animate
27
- //= require unstable/angular-resource
22
+ //= require unstable/angular2
28
23
 
29
24
  ## Versioning
30
25
 
@@ -1,6 +1,6 @@
1
1
  module AngularJS
2
2
  module Rails
3
- VERSION = "1.4.3"
4
- UNSTABLE_VERSION = "2.0.0-alpha.31"
3
+ VERSION = "1.4.4"
4
+ UNSTABLE_VERSION = "2.0.0-alpha.34"
5
5
  end
6
6
  end
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.4.3
2
+ * @license AngularJS v1.4.4
3
3
  * (c) 2010-2015 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -21,12 +21,60 @@ var isElement = angular.isElement;
21
21
  var ELEMENT_NODE = 1;
22
22
  var COMMENT_NODE = 8;
23
23
 
24
+ var ADD_CLASS_SUFFIX = '-add';
25
+ var REMOVE_CLASS_SUFFIX = '-remove';
26
+ var EVENT_CLASS_PREFIX = 'ng-';
27
+ var ACTIVE_CLASS_SUFFIX = '-active';
28
+
24
29
  var NG_ANIMATE_CLASSNAME = 'ng-animate';
25
30
  var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren';
26
31
 
32
+ // Detect proper transitionend/animationend event names.
33
+ var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
34
+
35
+ // If unprefixed events are not supported but webkit-prefixed are, use the latter.
36
+ // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
37
+ // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
38
+ // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
39
+ // Register both events in case `window.onanimationend` is not supported because of that,
40
+ // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
41
+ // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
42
+ // therefore there is no reason to test anymore for other vendor prefixes:
43
+ // http://caniuse.com/#search=transition
44
+ if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
45
+ CSS_PREFIX = '-webkit-';
46
+ TRANSITION_PROP = 'WebkitTransition';
47
+ TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
48
+ } else {
49
+ TRANSITION_PROP = 'transition';
50
+ TRANSITIONEND_EVENT = 'transitionend';
51
+ }
52
+
53
+ if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
54
+ CSS_PREFIX = '-webkit-';
55
+ ANIMATION_PROP = 'WebkitAnimation';
56
+ ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
57
+ } else {
58
+ ANIMATION_PROP = 'animation';
59
+ ANIMATIONEND_EVENT = 'animationend';
60
+ }
61
+
62
+ var DURATION_KEY = 'Duration';
63
+ var PROPERTY_KEY = 'Property';
64
+ var DELAY_KEY = 'Delay';
65
+ var TIMING_KEY = 'TimingFunction';
66
+ var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
67
+ var ANIMATION_PLAYSTATE_KEY = 'PlayState';
68
+ var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
69
+
70
+ var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
71
+ var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
72
+ var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
73
+ var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
74
+
27
75
  var isPromiseLike = function(p) {
28
76
  return p && p.then ? true : false;
29
- }
77
+ };
30
78
 
31
79
  function assertArg(arg, name, reason) {
32
80
  if (!arg) {
@@ -177,8 +225,21 @@ function mergeAnimationOptions(element, target, newOptions) {
177
225
  var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');
178
226
  var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);
179
227
 
228
+ if (newOptions.preparationClasses) {
229
+ target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);
230
+ delete newOptions.preparationClasses;
231
+ }
232
+
233
+ // noop is basically when there is no callback; otherwise something has been set
234
+ var realDomOperation = target.domOperation !== noop ? target.domOperation : null;
235
+
180
236
  extend(target, newOptions);
181
237
 
238
+ // TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.
239
+ if (realDomOperation) {
240
+ target.domOperation = realDomOperation;
241
+ }
242
+
182
243
  if (classes.addClass) {
183
244
  target.addClass = classes.addClass;
184
245
  } else {
@@ -256,63 +317,67 @@ function getDomNode(element) {
256
317
  return (element instanceof angular.element) ? element[0] : element;
257
318
  }
258
319
 
259
- var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
260
- var tickQueue = [];
261
- var cancelFn;
262
-
263
- function scheduler(tasks) {
264
- // we make a copy since RAFScheduler mutates the state
265
- // of the passed in array variable and this would be difficult
266
- // to track down on the outside code
267
- tickQueue.push([].concat(tasks));
268
- nextTick();
320
+ function applyGeneratedPreparationClasses(element, event, options) {
321
+ var classes = '';
322
+ if (event) {
323
+ classes = pendClasses(event, EVENT_CLASS_PREFIX, true);
324
+ }
325
+ if (options.addClass) {
326
+ classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));
327
+ }
328
+ if (options.removeClass) {
329
+ classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));
269
330
  }
331
+ if (classes.length) {
332
+ options.preparationClasses = classes;
333
+ element.addClass(classes);
334
+ }
335
+ }
270
336
 
271
- /* waitUntilQuiet does two things:
272
- * 1. It will run the FINAL `fn` value only when an uncancelled RAF has passed through
273
- * 2. It will delay the next wave of tasks from running until the quiet `fn` has run.
274
- *
275
- * The motivation here is that animation code can request more time from the scheduler
276
- * before the next wave runs. This allows for certain DOM properties such as classes to
277
- * be resolved in time for the next animation to run.
278
- */
279
- scheduler.waitUntilQuiet = function(fn) {
280
- if (cancelFn) cancelFn();
281
-
282
- cancelFn = $$rAF(function() {
283
- cancelFn = null;
284
- fn();
285
- nextTick();
286
- });
287
- };
337
+ function clearGeneratedClasses(element, options) {
338
+ if (options.preparationClasses) {
339
+ element.removeClass(options.preparationClasses);
340
+ options.preparationClasses = null;
341
+ }
342
+ if (options.activeClasses) {
343
+ element.removeClass(options.activeClasses);
344
+ options.activeClasses = null;
345
+ }
346
+ }
288
347
 
289
- return scheduler;
348
+ function blockTransitions(node, duration) {
349
+ // we use a negative delay value since it performs blocking
350
+ // yet it doesn't kill any existing transitions running on the
351
+ // same element which makes this safe for class-based animations
352
+ var value = duration ? '-' + duration + 's' : '';
353
+ applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
354
+ return [TRANSITION_DELAY_PROP, value];
355
+ }
290
356
 
291
- function nextTick() {
292
- if (!tickQueue.length) return;
357
+ function blockKeyframeAnimations(node, applyBlock) {
358
+ var value = applyBlock ? 'paused' : '';
359
+ var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
360
+ applyInlineStyle(node, [key, value]);
361
+ return [key, value];
362
+ }
293
363
 
294
- var updatedQueue = [];
295
- for (var i = 0; i < tickQueue.length; i++) {
296
- var innerQueue = tickQueue[i];
297
- runNextTask(innerQueue);
298
- if (innerQueue.length) {
299
- updatedQueue.push(innerQueue);
300
- }
301
- }
302
- tickQueue = updatedQueue;
364
+ function applyInlineStyle(node, styleTuple) {
365
+ var prop = styleTuple[0];
366
+ var value = styleTuple[1];
367
+ node.style[prop] = value;
368
+ }
303
369
 
304
- if (!cancelFn) {
305
- $$rAF(function() {
306
- if (!cancelFn) nextTick();
307
- });
308
- }
309
- }
370
+ function concatWithSpace(a,b) {
371
+ if (!a) return b;
372
+ if (!b) return a;
373
+ return a + ' ' + b;
374
+ }
310
375
 
311
- function runNextTask(tasks) {
312
- var nextTask = tasks.shift();
313
- nextTask();
314
- }
315
- }];
376
+ function $$BodyProvider() {
377
+ this.$get = ['$document', function($document) {
378
+ return jqLite($document[0].body);
379
+ }];
380
+ }
316
381
 
317
382
  var $$AnimateChildrenDirective = [function() {
318
383
  return function(scope, element, attrs) {
@@ -528,63 +593,19 @@ var $$AnimateChildrenDirective = [function() {
528
593
  * * `stagger` - A numeric time value representing the delay between successively animated elements
529
594
  * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})
530
595
  * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a
531
- * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
532
- * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.)
596
+ * * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)
597
+ * * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occuring on the classes being added and removed.)
533
598
  *
534
599
  * @return {object} an object with start and end methods and details about the animation.
535
600
  *
536
601
  * * `start` - The method to start the animation. This will return a `Promise` when called.
537
602
  * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.
538
603
  */
539
-
540
- // Detect proper transitionend/animationend event names.
541
- var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
542
-
543
- // If unprefixed events are not supported but webkit-prefixed are, use the latter.
544
- // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
545
- // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
546
- // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
547
- // Register both events in case `window.onanimationend` is not supported because of that,
548
- // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
549
- // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
550
- // therefore there is no reason to test anymore for other vendor prefixes:
551
- // http://caniuse.com/#search=transition
552
- if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
553
- CSS_PREFIX = '-webkit-';
554
- TRANSITION_PROP = 'WebkitTransition';
555
- TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
556
- } else {
557
- TRANSITION_PROP = 'transition';
558
- TRANSITIONEND_EVENT = 'transitionend';
559
- }
560
-
561
- if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
562
- CSS_PREFIX = '-webkit-';
563
- ANIMATION_PROP = 'WebkitAnimation';
564
- ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
565
- } else {
566
- ANIMATION_PROP = 'animation';
567
- ANIMATIONEND_EVENT = 'animationend';
568
- }
569
-
570
- var DURATION_KEY = 'Duration';
571
- var PROPERTY_KEY = 'Property';
572
- var DELAY_KEY = 'Delay';
573
- var TIMING_KEY = 'TimingFunction';
574
- var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
575
- var ANIMATION_PLAYSTATE_KEY = 'PlayState';
576
- var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
577
- var CLOSING_TIME_BUFFER = 1.5;
578
604
  var ONE_SECOND = 1000;
579
605
  var BASE_TEN = 10;
580
606
 
581
- var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;
582
-
583
- var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;
584
- var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;
585
-
586
- var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;
587
- var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
607
+ var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
608
+ var CLOSING_TIME_BUFFER = 1.5;
588
609
 
589
610
  var DETECT_CSS_PROPERTIES = {
590
611
  transitionDuration: TRANSITION_DURATION_PROP,
@@ -602,6 +623,15 @@ var DETECT_STAGGER_CSS_PROPERTIES = {
602
623
  animationDelay: ANIMATION_DELAY_PROP
603
624
  };
604
625
 
626
+ function getCssKeyframeDurationStyle(duration) {
627
+ return [ANIMATION_DURATION_PROP, duration + 's'];
628
+ }
629
+
630
+ function getCssDelayStyle(delay, isKeyframeAnimation) {
631
+ var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
632
+ return [prop, delay + 's'];
633
+ }
634
+
605
635
  function computeCssStyles($window, element, properties) {
606
636
  var styles = Object.create(null);
607
637
  var detectedStyles = $window.getComputedStyle(element) || {};
@@ -658,37 +688,6 @@ function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
658
688
  return [style, value];
659
689
  }
660
690
 
661
- function getCssKeyframeDurationStyle(duration) {
662
- return [ANIMATION_DURATION_PROP, duration + 's'];
663
- }
664
-
665
- function getCssDelayStyle(delay, isKeyframeAnimation) {
666
- var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;
667
- return [prop, delay + 's'];
668
- }
669
-
670
- function blockTransitions(node, duration) {
671
- // we use a negative delay value since it performs blocking
672
- // yet it doesn't kill any existing transitions running on the
673
- // same element which makes this safe for class-based animations
674
- var value = duration ? '-' + duration + 's' : '';
675
- applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
676
- return [TRANSITION_DELAY_PROP, value];
677
- }
678
-
679
- function blockKeyframeAnimations(node, applyBlock) {
680
- var value = applyBlock ? 'paused' : '';
681
- var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
682
- applyInlineStyle(node, [key, value]);
683
- return [key, value];
684
- }
685
-
686
- function applyInlineStyle(node, styleTuple) {
687
- var prop = styleTuple[0];
688
- var value = styleTuple[1];
689
- node.style[prop] = value;
690
- }
691
-
692
691
  function createLocalCacheLookup() {
693
692
  var cache = Object.create(null);
694
693
  return {
@@ -720,10 +719,8 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
720
719
  var gcsLookup = createLocalCacheLookup();
721
720
  var gcsStaggerLookup = createLocalCacheLookup();
722
721
 
723
- this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
724
- '$document', '$sniffer', '$$rAFScheduler',
725
- function($window, $$jqLite, $$AnimateRunner, $timeout,
726
- $document, $sniffer, $$rAFScheduler) {
722
+ this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$forceReflow', '$sniffer', '$$rAF',
723
+ function($window, $$jqLite, $$AnimateRunner, $timeout, $$forceReflow, $sniffer, $$rAF) {
727
724
 
728
725
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
729
726
 
@@ -780,28 +777,26 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
780
777
  return stagger || {};
781
778
  }
782
779
 
783
- var bod = getDomNode($document).body;
780
+ var cancelLastRAFRequest;
784
781
  var rafWaitQueue = [];
785
782
  function waitUntilQuiet(callback) {
783
+ if (cancelLastRAFRequest) {
784
+ cancelLastRAFRequest(); //cancels the request
785
+ }
786
786
  rafWaitQueue.push(callback);
787
- $$rAFScheduler.waitUntilQuiet(function() {
787
+ cancelLastRAFRequest = $$rAF(function() {
788
+ cancelLastRAFRequest = null;
788
789
  gcsLookup.flush();
789
790
  gcsStaggerLookup.flush();
790
791
 
791
- //the line below will force the browser to perform a repaint so
792
- //that all the animated elements within the animation frame will
793
- //be properly updated and drawn on screen. This is required to
794
- //ensure that the preparation animation is properly flushed so that
795
- //the active state picks up from there. DO NOT REMOVE THIS LINE.
796
- //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
797
- //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
798
- //WILL TAKE YEARS AWAY FROM YOUR LIFE.
799
- var width = bod.offsetWidth + 1;
792
+ // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.
793
+ // PLEASE EXAMINE THE `$$forceReflow` service to understand why.
794
+ var pageWidth = $$forceReflow();
800
795
 
801
796
  // we use a for loop to ensure that if the queue is changed
802
797
  // during this looping then it will consider new requests
803
798
  for (var i = 0; i < rafWaitQueue.length; i++) {
804
- rafWaitQueue[i](width);
799
+ rafWaitQueue[i](pageWidth);
805
800
  }
806
801
  rafWaitQueue.length = 0;
807
802
  });
@@ -857,20 +852,20 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
857
852
  var addRemoveClassName = '';
858
853
 
859
854
  if (isStructural) {
860
- structuralClassName = pendClasses(method, 'ng-', true);
855
+ structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true);
861
856
  } else if (method) {
862
857
  structuralClassName = method;
863
858
  }
864
859
 
865
860
  if (options.addClass) {
866
- addRemoveClassName += pendClasses(options.addClass, '-add');
861
+ addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX);
867
862
  }
868
863
 
869
864
  if (options.removeClass) {
870
865
  if (addRemoveClassName.length) {
871
866
  addRemoveClassName += ' ';
872
867
  }
873
- addRemoveClassName += pendClasses(options.removeClass, '-remove');
868
+ addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX);
874
869
  }
875
870
 
876
871
  // there may be a situation where a structural animation is combined together
@@ -884,9 +879,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
884
879
  addRemoveClassName = '';
885
880
  }
886
881
 
887
- var setupClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
888
- var fullClassName = classes + ' ' + setupClasses;
889
- var activeClasses = pendClasses(setupClasses, '-active');
882
+ var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
883
+ var fullClassName = classes + ' ' + preparationClasses;
884
+ var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
890
885
  var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
891
886
  var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
892
887
 
@@ -895,7 +890,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
895
890
  // unless there a is raw keyframe value that is applied to the element.
896
891
  if (!containsKeyframeAnimation
897
892
  && !hasToStyles
898
- && !setupClasses) {
893
+ && !preparationClasses) {
899
894
  return closeAndReturnNoopAnimator();
900
895
  }
901
896
 
@@ -910,10 +905,12 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
910
905
  };
911
906
  } else {
912
907
  cacheKey = gcsHashFn(node, fullClassName);
913
- stagger = computeCachedCssStaggerStyles(node, setupClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
908
+ stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
914
909
  }
915
910
 
916
- $$jqLite.addClass(element, setupClasses);
911
+ if (!options.$$skipPreparationClasses) {
912
+ $$jqLite.addClass(element, preparationClasses);
913
+ }
917
914
 
918
915
  var applyOnlyDuration;
919
916
 
@@ -952,7 +949,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
952
949
  // transition delay to allow for the transition to naturally do it's thing. The beauty here is
953
950
  // that if there is no transition defined then nothing will happen and this will also allow
954
951
  // other transitions to be stacked on top of each other without any chopping them out.
955
- if (isFirst) {
952
+ if (isFirst && !options.skipBlocking) {
956
953
  blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
957
954
  }
958
955
 
@@ -1011,12 +1008,13 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1011
1008
  }
1012
1009
 
1013
1010
  applyAnimationFromStyles(element, options);
1014
- if (!flags.blockTransition) {
1011
+
1012
+ if (flags.blockTransition || flags.blockKeyframeAnimation) {
1013
+ applyBlocking(maxDuration);
1014
+ } else if (!options.skipBlocking) {
1015
1015
  blockTransitions(node, false);
1016
1016
  }
1017
1017
 
1018
- applyBlocking(maxDuration);
1019
-
1020
1018
  // TODO(matsko): for 1.5 change this code to have an animator object for better debugging
1021
1019
  return {
1022
1020
  $$willAnimate: true,
@@ -1058,7 +1056,9 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1058
1056
  animationClosed = true;
1059
1057
  animationPaused = false;
1060
1058
 
1061
- $$jqLite.removeClass(element, setupClasses);
1059
+ if (!options.$$skipPreparationClasses) {
1060
+ $$jqLite.removeClass(element, preparationClasses);
1061
+ }
1062
1062
  $$jqLite.removeClass(element, activeClasses);
1063
1063
 
1064
1064
  blockKeyframeAnimations(node, false);
@@ -1185,7 +1185,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1185
1185
  $$jqLite.addClass(element, activeClasses);
1186
1186
 
1187
1187
  if (flags.recalculateTimingStyles) {
1188
- fullClassName = node.className + ' ' + setupClasses;
1188
+ fullClassName = node.className + ' ' + preparationClasses;
1189
1189
  cacheKey = gcsHashFn(node, fullClassName);
1190
1190
 
1191
1191
  timings = computeTimings(node, fullClassName, cacheKey);
@@ -1252,7 +1252,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1252
1252
 
1253
1253
  startTime = Date.now();
1254
1254
  element.on(events.join(' '), onAnimationProgress);
1255
- $timeout(onAnimationExpired, maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime);
1255
+ $timeout(onAnimationExpired, maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime, false);
1256
1256
 
1257
1257
  applyAnimationToStyles(element, options);
1258
1258
  }
@@ -1301,24 +1301,26 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
1301
1301
  var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';
1302
1302
  var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';
1303
1303
 
1304
- this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$document', '$sniffer',
1305
- function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $document, $sniffer) {
1304
+ this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$$body', '$sniffer', '$$jqLite',
1305
+ function($animateCss, $rootScope, $$AnimateRunner, $rootElement, $$body, $sniffer, $$jqLite) {
1306
1306
 
1307
1307
  // only browsers that support these properties can render animations
1308
1308
  if (!$sniffer.animations && !$sniffer.transitions) return noop;
1309
1309
 
1310
- var bodyNode = getDomNode($document).body;
1310
+ var bodyNode = getDomNode($$body);
1311
1311
  var rootNode = getDomNode($rootElement);
1312
1312
 
1313
1313
  var rootBodyElement = jqLite(bodyNode.parentNode === rootNode ? bodyNode : rootNode);
1314
1314
 
1315
- return function initDriverFn(animationDetails) {
1315
+ var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
1316
+
1317
+ return function initDriverFn(animationDetails, onBeforeClassesAppliedCb) {
1316
1318
  return animationDetails.from && animationDetails.to
1317
1319
  ? prepareFromToAnchorAnimation(animationDetails.from,
1318
1320
  animationDetails.to,
1319
1321
  animationDetails.classes,
1320
1322
  animationDetails.anchors)
1321
- : prepareRegularAnimation(animationDetails);
1323
+ : prepareRegularAnimation(animationDetails, onBeforeClassesAppliedCb);
1322
1324
  };
1323
1325
 
1324
1326
  function filterCssClasses(classes) {
@@ -1462,8 +1464,8 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
1462
1464
  }
1463
1465
 
1464
1466
  function prepareFromToAnchorAnimation(from, to, classes, anchors) {
1465
- var fromAnimation = prepareRegularAnimation(from);
1466
- var toAnimation = prepareRegularAnimation(to);
1467
+ var fromAnimation = prepareRegularAnimation(from, noop);
1468
+ var toAnimation = prepareRegularAnimation(to, noop);
1467
1469
 
1468
1470
  var anchorAnimations = [];
1469
1471
  forEach(anchors, function(anchor) {
@@ -1514,24 +1516,40 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
1514
1516
  };
1515
1517
  }
1516
1518
 
1517
- function prepareRegularAnimation(animationDetails) {
1519
+ function prepareRegularAnimation(animationDetails, onBeforeClassesAppliedCb) {
1518
1520
  var element = animationDetails.element;
1519
1521
  var options = animationDetails.options || {};
1520
1522
 
1523
+ // since the ng-EVENT, class-ADD and class-REMOVE classes are applied inside
1524
+ // of the animateQueue pre and postDigest stages then there is no need to add
1525
+ // then them here as well.
1526
+ options.$$skipPreparationClasses = true;
1527
+
1528
+ // during the pre/post digest stages inside of animateQueue we also performed
1529
+ // the blocking (transition:-9999s) so there is no point in doing that again.
1530
+ options.skipBlocking = true;
1531
+
1521
1532
  if (animationDetails.structural) {
1522
- // structural animations ensure that the CSS classes are always applied
1523
- // before the detection starts.
1524
- options.structural = options.applyClassesEarly = true;
1533
+ options.event = animationDetails.event;
1525
1534
 
1526
1535
  // we special case the leave animation since we want to ensure that
1527
1536
  // the element is removed as soon as the animation is over. Otherwise
1528
1537
  // a flicker might appear or the element may not be removed at all
1529
- options.event = animationDetails.event;
1530
- if (options.event === 'leave') {
1538
+ if (animationDetails.event === 'leave') {
1531
1539
  options.onDone = options.domOperation;
1532
1540
  }
1533
- } else {
1534
- options.event = null;
1541
+ }
1542
+
1543
+ // we apply the classes right away since the pre-digest took care of the
1544
+ // preparation classes.
1545
+ onBeforeClassesAppliedCb(element);
1546
+ applyAnimationClasses(element, options);
1547
+
1548
+ // We assign the preparationClasses as the actual animation event since
1549
+ // the internals of $animateCss will just suffix the event token values
1550
+ // with `-active` to trigger the animation.
1551
+ if (options.preparationClasses) {
1552
+ options.event = concatWithSpace(options.event, options.preparationClasses);
1535
1553
  }
1536
1554
 
1537
1555
  var animator = $animateCss(element, options);
@@ -1908,8 +1926,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
1908
1926
  });
1909
1927
 
1910
1928
  rules.skip.push(function(element, newAnimation, currentAnimation) {
1911
- // if there is a current animation then skip the class-based animation
1912
- return currentAnimation.structural && !newAnimation.structural;
1929
+ // if there is an ongoing current animation then don't even bother running the class-based animation
1930
+ return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;
1913
1931
  });
1914
1932
 
1915
1933
  rules.cancel.push(function(element, newAnimation, currentAnimation) {
@@ -1931,14 +1949,13 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
1931
1949
  return (nO.addClass && nO.addClass === cO.removeClass) || (nO.removeClass && nO.removeClass === cO.addClass);
1932
1950
  });
1933
1951
 
1934
- this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
1935
- '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite',
1936
- function($$rAF, $rootScope, $rootElement, $document, $$HashMap,
1937
- $$animation, $$AnimateRunner, $templateRequest, $$jqLite) {
1952
+ this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$body', '$$HashMap',
1953
+ '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',
1954
+ function($$rAF, $rootScope, $rootElement, $document, $$body, $$HashMap,
1955
+ $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) {
1938
1956
 
1939
1957
  var activeAnimationsLookup = new $$HashMap();
1940
1958
  var disabledElementsLookup = new $$HashMap();
1941
-
1942
1959
  var animationsEnabled = null;
1943
1960
 
1944
1961
  // Wait until all directive and route-related templates are downloaded and
@@ -1970,8 +1987,6 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
1970
1987
  }
1971
1988
  );
1972
1989
 
1973
- var bodyElement = jqLite($document[0].body);
1974
-
1975
1990
  var callbackRegistry = {};
1976
1991
 
1977
1992
  // remember that the classNameFilter is set during the provider/config
@@ -2107,22 +2122,22 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2107
2122
  // These methods will become available after the digest has passed
2108
2123
  var runner = new $$AnimateRunner();
2109
2124
 
2110
- // there are situations where a directive issues an animation for
2111
- // a jqLite wrapper that contains only comment nodes... If this
2112
- // happens then there is no way we can perform an animation
2113
- if (!node) {
2114
- close();
2115
- return runner;
2116
- }
2117
-
2118
2125
  if (isArray(options.addClass)) {
2119
2126
  options.addClass = options.addClass.join(' ');
2120
2127
  }
2121
2128
 
2129
+ if (options.addClass && !isString(options.addClass)) {
2130
+ options.addClass = null;
2131
+ }
2132
+
2122
2133
  if (isArray(options.removeClass)) {
2123
2134
  options.removeClass = options.removeClass.join(' ');
2124
2135
  }
2125
2136
 
2137
+ if (options.removeClass && !isString(options.removeClass)) {
2138
+ options.removeClass = null;
2139
+ }
2140
+
2126
2141
  if (options.from && !isObject(options.from)) {
2127
2142
  options.from = null;
2128
2143
  }
@@ -2131,6 +2146,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2131
2146
  options.to = null;
2132
2147
  }
2133
2148
 
2149
+ // there are situations where a directive issues an animation for
2150
+ // a jqLite wrapper that contains only comment nodes... If this
2151
+ // happens then there is no way we can perform an animation
2152
+ if (!node) {
2153
+ close();
2154
+ return runner;
2155
+ }
2156
+
2134
2157
  var className = [node.className, options.addClass, options.removeClass].join(' ');
2135
2158
  if (!isAnimatableClassName(className)) {
2136
2159
  close();
@@ -2195,8 +2218,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2195
2218
  // method which will call the runner methods in async.
2196
2219
  existingAnimation.close();
2197
2220
  } else {
2198
- // this will merge the existing animation options into this new follow-up animation
2199
- mergeAnimationOptions(element, newAnimation.options, existingAnimation.options);
2221
+ // this will merge the new animation options into existing animation options
2222
+ mergeAnimationOptions(element, existingAnimation.options, newAnimation.options);
2223
+ return existingAnimation.runner;
2200
2224
  }
2201
2225
  } else {
2202
2226
  // a joined animation means that this animation will take over the existing one
@@ -2207,9 +2231,14 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2207
2231
  if (existingAnimation.state === RUNNING_STATE) {
2208
2232
  normalizeAnimationOptions(element, options);
2209
2233
  } else {
2234
+ applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
2235
+
2210
2236
  event = newAnimation.event = existingAnimation.event;
2211
2237
  options = mergeAnimationOptions(element, existingAnimation.options, newAnimation.options);
2212
- return runner;
2238
+
2239
+ //we return the same runner since only the option values of this animation will
2240
+ //be fed into the `existingAnimation`.
2241
+ return existingAnimation.runner;
2213
2242
  }
2214
2243
  }
2215
2244
  }
@@ -2235,9 +2264,8 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2235
2264
  return runner;
2236
2265
  }
2237
2266
 
2238
- if (isStructural) {
2239
- closeParentClassBasedAnimations(parent);
2240
- }
2267
+ applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
2268
+ blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
2241
2269
 
2242
2270
  // the counter keeps track of cancelled animations
2243
2271
  var counter = (existingAnimation.counter || 0) + 1;
@@ -2296,12 +2324,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2296
2324
  ? 'setClass'
2297
2325
  : animationDetails.event;
2298
2326
 
2299
- if (animationDetails.structural) {
2300
- closeParentClassBasedAnimations(parentElement);
2301
- }
2302
-
2303
2327
  markElementAnimationState(element, RUNNING_STATE);
2304
- var realRunner = $$animation(element, event, animationDetails.options);
2328
+ var realRunner = $$animation(element, event, animationDetails.options, function(e) {
2329
+ $$forceReflow();
2330
+ blockTransitions(getDomNode(e), false);
2331
+ });
2332
+
2305
2333
  realRunner.done(function(status) {
2306
2334
  close(!status);
2307
2335
  var animationDetails = activeAnimationsLookup.get(node);
@@ -2325,6 +2353,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2325
2353
  }
2326
2354
 
2327
2355
  function close(reject) { // jshint ignore:line
2356
+ clearGeneratedClasses(element, options);
2328
2357
  applyAnimationClasses(element, options);
2329
2358
  applyAnimationStyles(element, options);
2330
2359
  options.domOperation();
@@ -2361,36 +2390,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2361
2390
  return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);
2362
2391
  }
2363
2392
 
2364
- function closeParentClassBasedAnimations(startingElement) {
2365
- var parentNode = getDomNode(startingElement);
2366
- do {
2367
- if (!parentNode || parentNode.nodeType !== ELEMENT_NODE) break;
2368
-
2369
- var animationDetails = activeAnimationsLookup.get(parentNode);
2370
- if (animationDetails) {
2371
- examineParentAnimation(parentNode, animationDetails);
2372
- }
2373
-
2374
- parentNode = parentNode.parentNode;
2375
- } while (true);
2376
-
2377
- // since animations are detected from CSS classes, we need to flush all parent
2378
- // class-based animations so that the parent classes are all present for child
2379
- // animations to properly function (otherwise any CSS selectors may not work)
2380
- function examineParentAnimation(node, animationDetails) {
2381
- // enter/leave/move always have priority
2382
- if (animationDetails.structural || !hasAnimationClasses(animationDetails.options)) return;
2383
-
2384
- if (animationDetails.state === RUNNING_STATE) {
2385
- animationDetails.runner.end();
2386
- }
2387
- clearElementAnimationState(node);
2388
- }
2389
- }
2390
-
2391
2393
  function areAnimationsAllowed(element, parentElement, event) {
2392
- var bodyElementDetected = false;
2393
- var rootElementDetected = false;
2394
+ var bodyElementDetected = isMatchingElement(element, $$body) || element[0].nodeName === 'HTML';
2395
+ var rootElementDetected = isMatchingElement(element, $rootElement);
2394
2396
  var parentAnimationDetected = false;
2395
2397
  var animateChildren;
2396
2398
 
@@ -2445,7 +2447,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2445
2447
  if (!bodyElementDetected) {
2446
2448
  // we also need to ensure that the element is or will be apart of the body element
2447
2449
  // otherwise it is pointless to even issue an animation to be rendered
2448
- bodyElementDetected = isMatchingElement(parentElement, bodyElement);
2450
+ bodyElementDetected = isMatchingElement(parentElement, $$body);
2449
2451
  }
2450
2452
 
2451
2453
  parentElement = parentElement.parent();
@@ -2640,18 +2642,95 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2640
2642
  return element.data(RUNNER_STORAGE_KEY);
2641
2643
  }
2642
2644
 
2643
- this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$rAFScheduler',
2644
- function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$rAFScheduler) {
2645
+ this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap',
2646
+ function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap) {
2645
2647
 
2646
2648
  var animationQueue = [];
2647
2649
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
2648
2650
 
2649
- var totalPendingClassBasedAnimations = 0;
2650
- var totalActiveClassBasedAnimations = 0;
2651
- var classBasedAnimationsQueue = [];
2651
+ function sortAnimations(animations) {
2652
+ var tree = { children: [] };
2653
+ var i, lookup = new $$HashMap();
2654
+
2655
+ // this is done first beforehand so that the hashmap
2656
+ // is filled with a list of the elements that will be animated
2657
+ for (i = 0; i < animations.length; i++) {
2658
+ var animation = animations[i];
2659
+ lookup.put(animation.domNode, animations[i] = {
2660
+ domNode: animation.domNode,
2661
+ fn: animation.fn,
2662
+ children: []
2663
+ });
2664
+ }
2665
+
2666
+ for (i = 0; i < animations.length; i++) {
2667
+ processNode(animations[i]);
2668
+ }
2669
+
2670
+ return flatten(tree);
2671
+
2672
+ function processNode(entry) {
2673
+ if (entry.processed) return entry;
2674
+ entry.processed = true;
2675
+
2676
+ var elementNode = entry.domNode;
2677
+ var parentNode = elementNode.parentNode;
2678
+ lookup.put(elementNode, entry);
2679
+
2680
+ var parentEntry;
2681
+ while (parentNode) {
2682
+ parentEntry = lookup.get(parentNode);
2683
+ if (parentEntry) {
2684
+ if (!parentEntry.processed) {
2685
+ parentEntry = processNode(parentEntry);
2686
+ }
2687
+ break;
2688
+ }
2689
+ parentNode = parentNode.parentNode;
2690
+ }
2691
+
2692
+ (parentEntry || tree).children.push(entry);
2693
+ return entry;
2694
+ }
2695
+
2696
+ function flatten(tree) {
2697
+ var result = [];
2698
+ var queue = [];
2699
+ var i;
2700
+
2701
+ for (i = 0; i < tree.children.length; i++) {
2702
+ queue.push(tree.children[i]);
2703
+ }
2704
+
2705
+ var remainingLevelEntries = queue.length;
2706
+ var nextLevelEntries = 0;
2707
+ var row = [];
2708
+
2709
+ for (i = 0; i < queue.length; i++) {
2710
+ var entry = queue[i];
2711
+ if (remainingLevelEntries <= 0) {
2712
+ remainingLevelEntries = nextLevelEntries;
2713
+ nextLevelEntries = 0;
2714
+ result = result.concat(row);
2715
+ row = [];
2716
+ }
2717
+ row.push(entry.fn);
2718
+ forEach(entry.children, function(childEntry) {
2719
+ nextLevelEntries++;
2720
+ queue.push(childEntry);
2721
+ });
2722
+ remainingLevelEntries--;
2723
+ }
2724
+
2725
+ if (row.length) {
2726
+ result = result.concat(row);
2727
+ }
2728
+ return result;
2729
+ }
2730
+ }
2652
2731
 
2653
2732
  // TODO(matsko): document the signature in a better way
2654
- return function(element, event, options) {
2733
+ return function(element, event, options, onBeforeClassesAppliedCb) {
2655
2734
  options = prepareAnimationOptions(options);
2656
2735
  var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
2657
2736
 
@@ -2678,19 +2757,12 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2678
2757
  options.tempClasses = null;
2679
2758
  }
2680
2759
 
2681
- var classBasedIndex;
2682
- if (!isStructural) {
2683
- classBasedIndex = totalPendingClassBasedAnimations;
2684
- totalPendingClassBasedAnimations += 1;
2685
- }
2686
-
2687
2760
  animationQueue.push({
2688
2761
  // this data is used by the postDigest code and passed into
2689
2762
  // the driver step function
2690
2763
  element: element,
2691
2764
  classes: classes,
2692
2765
  event: event,
2693
- classBasedIndex: classBasedIndex,
2694
2766
  structural: isStructural,
2695
2767
  options: options,
2696
2768
  beforeStart: beforeStart,
@@ -2705,77 +2777,67 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2705
2777
  if (animationQueue.length > 1) return runner;
2706
2778
 
2707
2779
  $rootScope.$$postDigest(function() {
2708
- totalActiveClassBasedAnimations = totalPendingClassBasedAnimations;
2709
- totalPendingClassBasedAnimations = 0;
2710
- classBasedAnimationsQueue.length = 0;
2711
-
2712
2780
  var animations = [];
2713
2781
  forEach(animationQueue, function(entry) {
2714
2782
  // the element was destroyed early on which removed the runner
2715
2783
  // form its storage. This means we can't animate this element
2716
2784
  // at all and it already has been closed due to destruction.
2717
- if (getRunner(entry.element)) {
2785
+ var elm = entry.element;
2786
+ if (getRunner(elm) && getDomNode(elm).parentNode) {
2718
2787
  animations.push(entry);
2788
+ } else {
2789
+ entry.close();
2719
2790
  }
2720
2791
  });
2721
2792
 
2722
2793
  // now any future animations will be in another postDigest
2723
2794
  animationQueue.length = 0;
2724
2795
 
2725
- forEach(groupAnimations(animations), function(animationEntry) {
2726
- if (animationEntry.structural) {
2727
- triggerAnimationStart();
2728
- } else {
2729
- classBasedAnimationsQueue.push({
2730
- node: getDomNode(animationEntry.element),
2731
- fn: triggerAnimationStart
2732
- });
2733
-
2734
- if (animationEntry.classBasedIndex === totalActiveClassBasedAnimations - 1) {
2735
- // we need to sort each of the animations in order of parent to child
2736
- // relationships. This ensures that the child classes are applied at the
2737
- // right time.
2738
- classBasedAnimationsQueue = classBasedAnimationsQueue.sort(function(a,b) {
2739
- return b.node.contains(a.node);
2740
- }).map(function(entry) {
2741
- return entry.fn;
2742
- });
2743
-
2744
- $$rAFScheduler(classBasedAnimationsQueue);
2745
- }
2746
- }
2747
-
2748
- function triggerAnimationStart() {
2749
- // it's important that we apply the `ng-animate` CSS class and the
2750
- // temporary classes before we do any driver invoking since these
2751
- // CSS classes may be required for proper CSS detection.
2752
- animationEntry.beforeStart();
2753
-
2754
- var startAnimationFn, closeFn = animationEntry.close;
2755
-
2756
- // in the event that the element was removed before the digest runs or
2757
- // during the RAF sequencing then we should not trigger the animation.
2758
- var targetElement = animationEntry.anchors
2759
- ? (animationEntry.from.element || animationEntry.to.element)
2760
- : animationEntry.element;
2796
+ var groupedAnimations = groupAnimations(animations);
2797
+ var toBeSortedAnimations = [];
2798
+
2799
+ forEach(groupedAnimations, function(animationEntry) {
2800
+ toBeSortedAnimations.push({
2801
+ domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),
2802
+ fn: function triggerAnimationStart() {
2803
+ // it's important that we apply the `ng-animate` CSS class and the
2804
+ // temporary classes before we do any driver invoking since these
2805
+ // CSS classes may be required for proper CSS detection.
2806
+ animationEntry.beforeStart();
2807
+
2808
+ var startAnimationFn, closeFn = animationEntry.close;
2809
+
2810
+ // in the event that the element was removed before the digest runs or
2811
+ // during the RAF sequencing then we should not trigger the animation.
2812
+ var targetElement = animationEntry.anchors
2813
+ ? (animationEntry.from.element || animationEntry.to.element)
2814
+ : animationEntry.element;
2815
+
2816
+ if (getRunner(targetElement)) {
2817
+ var operation = invokeFirstDriver(animationEntry, onBeforeClassesAppliedCb);
2818
+ if (operation) {
2819
+ startAnimationFn = operation.start;
2820
+ }
2821
+ }
2761
2822
 
2762
- if (getRunner(targetElement) && getDomNode(targetElement).parentNode) {
2763
- var operation = invokeFirstDriver(animationEntry);
2764
- if (operation) {
2765
- startAnimationFn = operation.start;
2823
+ if (!startAnimationFn) {
2824
+ closeFn();
2825
+ } else {
2826
+ var animationRunner = startAnimationFn();
2827
+ animationRunner.done(function(status) {
2828
+ closeFn(!status);
2829
+ });
2830
+ updateAnimationRunners(animationEntry, animationRunner);
2766
2831
  }
2767
2832
  }
2833
+ });
2834
+ });
2768
2835
 
2769
- if (!startAnimationFn) {
2770
- closeFn();
2771
- } else {
2772
- var animationRunner = startAnimationFn();
2773
- animationRunner.done(function(status) {
2774
- closeFn(!status);
2775
- });
2776
- updateAnimationRunners(animationEntry, animationRunner);
2777
- }
2778
- }
2836
+ // we need to sort each of the animations in order of parent to child
2837
+ // relationships. This ensures that the parent to child classes are
2838
+ // applied at the right time.
2839
+ forEach(sortAnimations(toBeSortedAnimations), function(triggerAnimation) {
2840
+ triggerAnimation();
2779
2841
  });
2780
2842
  });
2781
2843
 
@@ -2846,7 +2908,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2846
2908
  var lookupKey = from.animationID.toString();
2847
2909
  if (!anchorGroups[lookupKey]) {
2848
2910
  var group = anchorGroups[lookupKey] = {
2849
- structural: true,
2911
+ // TODO(matsko): double-check this code
2850
2912
  beforeStart: function() {
2851
2913
  fromAnimation.beforeStart();
2852
2914
  toAnimation.beforeStart();
@@ -2900,7 +2962,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2900
2962
  return matches.join(' ');
2901
2963
  }
2902
2964
 
2903
- function invokeFirstDriver(animationDetails) {
2965
+ function invokeFirstDriver(animationDetails, onBeforeClassesAppliedCb) {
2904
2966
  // we loop in reverse order since the more general drivers (like CSS and JS)
2905
2967
  // may attempt more elements, but custom drivers are more particular
2906
2968
  for (var i = drivers.length - 1; i >= 0; i--) {
@@ -2908,7 +2970,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2908
2970
  if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check
2909
2971
 
2910
2972
  var factory = $injector.get(driverName);
2911
- var driver = factory(animationDetails);
2973
+ var driver = factory(animationDetails, onBeforeClassesAppliedCb);
2912
2974
  if (driver) {
2913
2975
  return driver;
2914
2976
  }
@@ -2963,8 +3025,8 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2963
3025
 
2964
3026
  /* global angularAnimateModule: true,
2965
3027
 
3028
+ $$BodyProvider,
2966
3029
  $$rAFMutexFactory,
2967
- $$rAFSchedulerFactory,
2968
3030
  $$AnimateChildrenDirective,
2969
3031
  $$AnimateRunnerFactory,
2970
3032
  $$AnimateQueueProvider,
@@ -3348,6 +3410,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3348
3410
  * enter: function(element, doneFn) {
3349
3411
  * var runner = $animateCss(element, {
3350
3412
  * event: 'enter',
3413
+ * structural: true,
3351
3414
  * addClass: 'maroon-setting',
3352
3415
  * from: { height:0 },
3353
3416
  * to: { height: 200 }
@@ -3701,10 +3764,11 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3701
3764
  * Click here {@link ng.$animate $animate to learn more about animations with `$animate`}.
3702
3765
  */
3703
3766
  angular.module('ngAnimate', [])
3767
+ .provider('$$body', $$BodyProvider)
3768
+
3704
3769
  .directive('ngAnimateChildren', $$AnimateChildrenDirective)
3705
3770
 
3706
3771
  .factory('$$rAFMutex', $$rAFMutexFactory)
3707
- .factory('$$rAFScheduler', $$rAFSchedulerFactory)
3708
3772
 
3709
3773
  .factory('$$AnimateRunner', $$AnimateRunnerFactory)
3710
3774