angularjs-rails 1.5.8 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d04d5e9d07101020a4ff8ce65da72f687ae662ac
4
- data.tar.gz: a331710f55c8863f808ff55b19e13f7fbea622d9
3
+ metadata.gz: b29491e1b540e7e1d87b0d88f3fbb5b4c9323ad1
4
+ data.tar.gz: b13e9fd5f9ac54ddf962b54cb69b14b5b2c5b0ad
5
5
  SHA512:
6
- metadata.gz: 6a6f1fd278f3a44256c869257be4ba5ce847847dd1f7061bb0e8d865207a7a628bfec0549ed5e7217987325bc5f3423d1bd7306dff786dc39a4d796d1ff46387
7
- data.tar.gz: ac1409c3a42f91f5801b8084e8ade1a5f9f06e2519c55100ff7f2817210d92d88ad890a16037d03f9019e0aa74a8fabba2881f1687d7e743b797f79884d31e24
6
+ metadata.gz: 10e912a2d702bf2ad0b87351940ae8e36fd4c6c5af5293c451dfb08ffc5184b171c66e4f527c378203a1519f28e91c2222d9f46ac700ac1b2956eaace08fa3ff
7
+ data.tar.gz: ea1946717238ceb9794c24141d470c49a681ad3937df953ebbb58d1270c025df4aeb073c61de03863a14f7a928d516c2a9a9baeb47bbbcd82aa41b10f2bc0c5e
data/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  angularjs-rails wraps the [Angular.js](http://angularjs.org) library for use in Rails 3.1 and above. Assets will minify automatically during production.
4
4
 
5
+ **If you find this gem useful, please consider donating - your contributions will help me keep this gem updated.**
6
+
7
+ [![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=NCT7TZEFY2T9Y)
8
+
9
+
5
10
  ## Usage
6
11
 
7
12
  Add the following to your Gemfile:
@@ -29,4 +34,4 @@ The major, minor, and patch version numbers will always represent the Angular.js
29
34
 
30
35
  ## IMPORTANT: Requesting upgrades for new Angular.js versions
31
36
 
32
- Thanks to Nick Clark, we have an auto-upgrader that will upgrade the package to the latest version. To request that the latest version of Angular.JS be pushed as a gem to RubyGems, please create a new issue instead of pull requests.
37
+ To request that the latest version of Angular.JS be pushed as a gem to RubyGems, please create a new issue instead of pull requests.
@@ -3,4 +3,4 @@ module AngularJS
3
3
  class Engine < ::Rails::Engine
4
4
  end
5
5
  end
6
- end
6
+ end
@@ -1,6 +1,6 @@
1
1
  module AngularJS
2
2
  module Rails
3
- VERSION = "1.5.8"
3
+ VERSION = "1.8.0"
4
4
  UNSTABLE_VERSION = "2.0.0-beta.17"
5
5
  end
6
6
  end
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
3
- * (c) 2010-2016 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.8.0
3
+ * (c) 2010-2020 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, angular) {'use strict';
@@ -29,7 +29,7 @@ var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMA
29
29
  // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
30
30
  // therefore there is no reason to test anymore for other vendor prefixes:
31
31
  // http://caniuse.com/#search=transition
32
- if ((window.ontransitionend === void 0) && (window.onwebkittransitionend !== void 0)) {
32
+ if ((window.ontransitionend === undefined) && (window.onwebkittransitionend !== undefined)) {
33
33
  CSS_PREFIX = '-webkit-';
34
34
  TRANSITION_PROP = 'WebkitTransition';
35
35
  TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
@@ -38,7 +38,7 @@ if ((window.ontransitionend === void 0) && (window.onwebkittransitionend !== voi
38
38
  TRANSITIONEND_EVENT = 'transitionend';
39
39
  }
40
40
 
41
- if ((window.onanimationend === void 0) && (window.onwebkitanimationend !== void 0)) {
41
+ if ((window.onanimationend === undefined) && (window.onwebkitanimationend !== undefined)) {
42
42
  CSS_PREFIX = '-webkit-';
43
43
  ANIMATION_PROP = 'WebkitAnimation';
44
44
  ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
@@ -63,7 +63,7 @@ var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;
63
63
  var ngMinErr = angular.$$minErr('ng');
64
64
  function assertArg(arg, name, reason) {
65
65
  if (!arg) {
66
- throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
66
+ throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required'));
67
67
  }
68
68
  return arg;
69
69
  }
@@ -139,7 +139,7 @@ function extractElementNode(element) {
139
139
  if (!element[0]) return element;
140
140
  for (var i = 0; i < element.length; i++) {
141
141
  var elm = element[i];
142
- if (elm.nodeType == ELEMENT_NODE) {
142
+ if (elm.nodeType === ELEMENT_NODE) {
143
143
  return elm;
144
144
  }
145
145
  }
@@ -306,7 +306,7 @@ function getDomNode(element) {
306
306
  return (element instanceof jqLite) ? element[0] : element;
307
307
  }
308
308
 
309
- function applyGeneratedPreparationClasses(element, event, options) {
309
+ function applyGeneratedPreparationClasses($$jqLite, element, event, options) {
310
310
  var classes = '';
311
311
  if (event) {
312
312
  classes = pendClasses(event, EVENT_CLASS_PREFIX, true);
@@ -334,15 +334,6 @@ function clearGeneratedClasses(element, options) {
334
334
  }
335
335
  }
336
336
 
337
- function blockTransitions(node, duration) {
338
- // we use a negative delay value since it performs blocking
339
- // yet it doesn't kill any existing transitions running on the
340
- // same element which makes this safe for class-based animations
341
- var value = duration ? '-' + duration + 's' : '';
342
- applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
343
- return [TRANSITION_DELAY_PROP, value];
344
- }
345
-
346
337
  function blockKeyframeAnimations(node, applyBlock) {
347
338
  var value = applyBlock ? 'paused' : '';
348
339
  var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;
@@ -362,6 +353,17 @@ function concatWithSpace(a,b) {
362
353
  return a + ' ' + b;
363
354
  }
364
355
 
356
+ var helpers = {
357
+ blockTransitions: function(node, duration) {
358
+ // we use a negative delay value since it performs blocking
359
+ // yet it doesn't kill any existing transitions running on the
360
+ // same element which makes this safe for class-based animations
361
+ var value = duration ? '-' + duration + 's' : '';
362
+ applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);
363
+ return [TRANSITION_DELAY_PROP, value];
364
+ }
365
+ };
366
+
365
367
  var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
366
368
  var queue, cancelFn;
367
369
 
@@ -423,7 +425,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
423
425
  * of the children's parents are currently animating. By default, when an element has an active `enter`, `leave`, or `move`
424
426
  * (structural) animation, child elements that also have an active structural animation are not animated.
425
427
  *
426
- * Note that even if `ngAnimteChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).
428
+ * Note that even if `ngAnimateChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).
427
429
  *
428
430
  *
429
431
  * @param {string} ngAnimateChildren If the value is empty, `true` or `on`,
@@ -432,7 +434,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
432
434
  * @example
433
435
  * <example module="ngAnimateChildren" name="ngAnimateChildren" deps="angular-animate.js" animations="true">
434
436
  <file name="index.html">
435
- <div ng-controller="mainController as main">
437
+ <div ng-controller="MainController as main">
436
438
  <label>Show container? <input type="checkbox" ng-model="main.enterElement" /></label>
437
439
  <label>Animate children? <input type="checkbox" ng-model="main.animateChildren" /></label>
438
440
  <hr>
@@ -482,7 +484,7 @@ var $$rAFSchedulerFactory = ['$$rAF', function($$rAF) {
482
484
  </file>
483
485
  <file name="script.js">
484
486
  angular.module('ngAnimateChildren', ['ngAnimate'])
485
- .controller('mainController', function() {
487
+ .controller('MainController', function MainController() {
486
488
  this.animateChildren = false;
487
489
  this.enterElement = false;
488
490
  });
@@ -510,6 +512,8 @@ var $$AnimateChildrenDirective = ['$interpolate', function($interpolate) {
510
512
  };
511
513
  }];
512
514
 
515
+ /* exported $AnimateCssProvider */
516
+
513
517
  var ANIMATE_TIMER_KEY = '$$animateCss';
514
518
 
515
519
  /**
@@ -526,11 +530,11 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
526
530
  * Note that only browsers that support CSS transitions and/or keyframe animations are capable of
527
531
  * rendering animations triggered via `$animateCss` (bad news for IE9 and lower).
528
532
  *
529
- * ## Usage
533
+ * ## General Use
530
534
  * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that
531
535
  * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,
532
536
  * any automatic control over cancelling animations and/or preventing animations from being run on
533
- * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to
537
+ * child elements will not be handled by AngularJS. For this to work as expected, please use `$animate` to
534
538
  * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger
535
539
  * the CSS animation.
536
540
  *
@@ -727,7 +731,6 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
727
731
  * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.
728
732
  */
729
733
  var ONE_SECOND = 1000;
730
- var BASE_TEN = 10;
731
734
 
732
735
  var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
733
736
  var CLOSING_TIME_BUFFER = 1.5;
@@ -789,7 +792,7 @@ function parseMaxTime(str) {
789
792
  forEach(values, function(value) {
790
793
  // it's always safe to consider only second values and omit `ms` values since
791
794
  // getComputedStyle will always handle the conversion for us
792
- if (value.charAt(value.length - 1) == 's') {
795
+ if (value.charAt(value.length - 1) === 's') {
793
796
  value = value.substring(0, value.length - 1);
794
797
  }
795
798
  value = parseFloat(value) || 0;
@@ -813,33 +816,6 @@ function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
813
816
  return [style, value];
814
817
  }
815
818
 
816
- function createLocalCacheLookup() {
817
- var cache = Object.create(null);
818
- return {
819
- flush: function() {
820
- cache = Object.create(null);
821
- },
822
-
823
- count: function(key) {
824
- var entry = cache[key];
825
- return entry ? entry.total : 0;
826
- },
827
-
828
- get: function(key) {
829
- var entry = cache[key];
830
- return entry && entry.value;
831
- },
832
-
833
- put: function(key, value) {
834
- if (!cache[key]) {
835
- cache[key] = { total: 1, value: value };
836
- } else {
837
- cache[key].total++;
838
- }
839
- }
840
- };
841
- }
842
-
843
819
  // we do not reassign an already present style value since
844
820
  // if we detect the style property value again we may be
845
821
  // detecting styles that were added via the `from` styles.
@@ -857,27 +833,17 @@ function registerRestorableStyles(backup, node, properties) {
857
833
  });
858
834
  }
859
835
 
860
- var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
861
- var gcsLookup = createLocalCacheLookup();
862
- var gcsStaggerLookup = createLocalCacheLookup();
836
+ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animateProvider) {
863
837
 
864
- this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
838
+ this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$animateCache',
865
839
  '$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',
866
- function($window, $$jqLite, $$AnimateRunner, $timeout,
840
+ function($window, $$jqLite, $$AnimateRunner, $timeout, $$animateCache,
867
841
  $$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {
868
842
 
869
843
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
870
844
 
871
- var parentCounter = 0;
872
- function gcsHashFn(node, extraClasses) {
873
- var KEY = "$$ngAnimateParentKey";
874
- var parentNode = node.parentNode;
875
- var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
876
- return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;
877
- }
878
-
879
- function computeCachedCssStyles(node, className, cacheKey, properties) {
880
- var timings = gcsLookup.get(cacheKey);
845
+ function computeCachedCssStyles(node, className, cacheKey, allowNoDuration, properties) {
846
+ var timings = $$animateCache.get(cacheKey);
881
847
 
882
848
  if (!timings) {
883
849
  timings = computeCssStyles($window, node, properties);
@@ -886,20 +852,26 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
886
852
  }
887
853
  }
888
854
 
855
+ // if a css animation has no duration we
856
+ // should mark that so that repeated addClass/removeClass calls are skipped
857
+ var hasDuration = allowNoDuration || (timings.transitionDuration > 0 || timings.animationDuration > 0);
858
+
889
859
  // we keep putting this in multiple times even though the value and the cacheKey are the same
890
860
  // because we're keeping an internal tally of how many duplicate animations are detected.
891
- gcsLookup.put(cacheKey, timings);
861
+ $$animateCache.put(cacheKey, timings, hasDuration);
862
+
892
863
  return timings;
893
864
  }
894
865
 
895
866
  function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {
896
867
  var stagger;
868
+ var staggerCacheKey = 'stagger-' + cacheKey;
897
869
 
898
870
  // if we have one or more existing matches of matching elements
899
871
  // containing the same parent + CSS styles (which is how cacheKey works)
900
872
  // then staggering is possible
901
- if (gcsLookup.count(cacheKey) > 0) {
902
- stagger = gcsStaggerLookup.get(cacheKey);
873
+ if ($$animateCache.count(cacheKey) > 0) {
874
+ stagger = $$animateCache.get(staggerCacheKey);
903
875
 
904
876
  if (!stagger) {
905
877
  var staggerClassName = pendClasses(className, '-stagger');
@@ -914,20 +886,18 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
914
886
 
915
887
  $$jqLite.removeClass(node, staggerClassName);
916
888
 
917
- gcsStaggerLookup.put(cacheKey, stagger);
889
+ $$animateCache.put(staggerCacheKey, stagger, true);
918
890
  }
919
891
  }
920
892
 
921
893
  return stagger || {};
922
894
  }
923
895
 
924
- var cancelLastRAFRequest;
925
896
  var rafWaitQueue = [];
926
897
  function waitUntilQuiet(callback) {
927
898
  rafWaitQueue.push(callback);
928
899
  $$rAFScheduler.waitUntilQuiet(function() {
929
- gcsLookup.flush();
930
- gcsStaggerLookup.flush();
900
+ $$animateCache.flush();
931
901
 
932
902
  // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.
933
903
  // PLEASE EXAMINE THE `$$forceReflow` service to understand why.
@@ -942,8 +912,8 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
942
912
  });
943
913
  }
944
914
 
945
- function computeTimings(node, className, cacheKey) {
946
- var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);
915
+ function computeTimings(node, className, cacheKey, allowNoDuration) {
916
+ var timings = computeCachedCssStyles(node, className, cacheKey, allowNoDuration, DETECT_CSS_PROPERTIES);
947
917
  var aD = timings.animationDelay;
948
918
  var tD = timings.transitionDelay;
949
919
  timings.maxDelay = aD && tD
@@ -1030,7 +1000,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1030
1000
 
1031
1001
  var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();
1032
1002
  var fullClassName = classes + ' ' + preparationClasses;
1033
- var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
1034
1003
  var hasToStyles = styles.to && Object.keys(styles.to).length > 0;
1035
1004
  var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0;
1036
1005
 
@@ -1043,7 +1012,12 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1043
1012
  return closeAndReturnNoopAnimator();
1044
1013
  }
1045
1014
 
1046
- var cacheKey, stagger;
1015
+ var stagger, cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass);
1016
+ if ($$animateCache.containsCachedAnimationWithoutDuration(cacheKey)) {
1017
+ preparationClasses = null;
1018
+ return closeAndReturnNoopAnimator();
1019
+ }
1020
+
1047
1021
  if (options.stagger > 0) {
1048
1022
  var staggerVal = parseFloat(options.stagger);
1049
1023
  stagger = {
@@ -1053,7 +1027,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1053
1027
  animationDuration: 0
1054
1028
  };
1055
1029
  } else {
1056
- cacheKey = gcsHashFn(node, fullClassName);
1057
1030
  stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);
1058
1031
  }
1059
1032
 
@@ -1087,7 +1060,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1087
1060
  var itemIndex = stagger
1088
1061
  ? options.staggerIndex >= 0
1089
1062
  ? options.staggerIndex
1090
- : gcsLookup.count(cacheKey)
1063
+ : $$animateCache.count(cacheKey)
1091
1064
  : 0;
1092
1065
 
1093
1066
  var isFirst = itemIndex === 0;
@@ -1099,10 +1072,10 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1099
1072
  // that if there is no transition defined then nothing will happen and this will also allow
1100
1073
  // other transitions to be stacked on top of each other without any chopping them out.
1101
1074
  if (isFirst && !options.skipBlocking) {
1102
- blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
1075
+ helpers.blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);
1103
1076
  }
1104
1077
 
1105
- var timings = computeTimings(node, fullClassName, cacheKey);
1078
+ var timings = computeTimings(node, fullClassName, cacheKey, !isStructural);
1106
1079
  var relativeDelay = timings.maxDelay;
1107
1080
  maxDelay = Math.max(relativeDelay, 0);
1108
1081
  maxDuration = timings.maxDuration;
@@ -1110,7 +1083,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1110
1083
  var flags = {};
1111
1084
  flags.hasTransitions = timings.transitionDuration > 0;
1112
1085
  flags.hasAnimations = timings.animationDuration > 0;
1113
- flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all';
1086
+ flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty === 'all';
1114
1087
  flags.applyTransitionDuration = hasToStyles && (
1115
1088
  (flags.hasTransitions && !flags.hasTransitionAll)
1116
1089
  || (flags.hasAnimations && !flags.hasTransitions));
@@ -1140,9 +1113,11 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1140
1113
  return closeAndReturnNoopAnimator();
1141
1114
  }
1142
1115
 
1116
+ var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);
1117
+
1143
1118
  if (options.delay != null) {
1144
1119
  var delayStyle;
1145
- if (typeof options.delay !== "boolean") {
1120
+ if (typeof options.delay !== 'boolean') {
1146
1121
  delayStyle = parseFloat(options.delay);
1147
1122
  // number in options.delay means we have to recalculate the delay for the closing timeout
1148
1123
  maxDelay = Math.max(delayStyle, 0);
@@ -1183,7 +1158,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1183
1158
  if (flags.blockTransition || flags.blockKeyframeAnimation) {
1184
1159
  applyBlocking(maxDuration);
1185
1160
  } else if (!options.skipBlocking) {
1186
- blockTransitions(node, false);
1161
+ helpers.blockTransitions(node, false);
1187
1162
  }
1188
1163
 
1189
1164
  // TODO(matsko): for 1.5 change this code to have an animator object for better debugging
@@ -1220,20 +1195,23 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1220
1195
  close(true);
1221
1196
  }
1222
1197
 
1223
- function close(rejected) { // jshint ignore:line
1198
+ function close(rejected) {
1224
1199
  // if the promise has been called already then we shouldn't close
1225
1200
  // the animation again
1226
1201
  if (animationClosed || (animationCompleted && animationPaused)) return;
1227
1202
  animationClosed = true;
1228
1203
  animationPaused = false;
1229
1204
 
1230
- if (!options.$$skipPreparationClasses) {
1205
+ if (preparationClasses && !options.$$skipPreparationClasses) {
1231
1206
  $$jqLite.removeClass(element, preparationClasses);
1232
1207
  }
1233
- $$jqLite.removeClass(element, activeClasses);
1208
+
1209
+ if (activeClasses) {
1210
+ $$jqLite.removeClass(element, activeClasses);
1211
+ }
1234
1212
 
1235
1213
  blockKeyframeAnimations(node, false);
1236
- blockTransitions(node, false);
1214
+ helpers.blockTransitions(node, false);
1237
1215
 
1238
1216
  forEach(temporaryStyles, function(entry) {
1239
1217
  // There is only one way to remove inline style properties entirely from elements.
@@ -1247,8 +1225,11 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1247
1225
 
1248
1226
  if (Object.keys(restoreStyles).length) {
1249
1227
  forEach(restoreStyles, function(value, prop) {
1250
- value ? node.style.setProperty(prop, value)
1251
- : node.style.removeProperty(prop);
1228
+ if (value) {
1229
+ node.style.setProperty(prop, value);
1230
+ } else {
1231
+ node.style.removeProperty(prop);
1232
+ }
1252
1233
  });
1253
1234
  }
1254
1235
 
@@ -1281,7 +1262,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1281
1262
 
1282
1263
  function applyBlocking(duration) {
1283
1264
  if (flags.blockTransition) {
1284
- blockTransitions(node, duration);
1265
+ helpers.blockTransitions(node, duration);
1285
1266
  }
1286
1267
 
1287
1268
  if (flags.blockKeyframeAnimation) {
@@ -1312,6 +1293,12 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1312
1293
  event.stopPropagation();
1313
1294
  var ev = event.originalEvent || event;
1314
1295
 
1296
+ if (ev.target !== node) {
1297
+ // Since TransitionEvent / AnimationEvent bubble up,
1298
+ // we have to ignore events by finished child animations
1299
+ return;
1300
+ }
1301
+
1315
1302
  // we now always use `Date.now()` due to the recent changes with
1316
1303
  // event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)
1317
1304
  var timeStamp = ev.$manualTimeStamp || Date.now();
@@ -1351,9 +1338,11 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1351
1338
  animationPaused = !playAnimation;
1352
1339
  if (timings.animationDuration) {
1353
1340
  var value = blockKeyframeAnimations(node, animationPaused);
1354
- animationPaused
1355
- ? temporaryStyles.push(value)
1356
- : removeFromArray(temporaryStyles, value);
1341
+ if (animationPaused) {
1342
+ temporaryStyles.push(value);
1343
+ } else {
1344
+ removeFromArray(temporaryStyles, value);
1345
+ }
1357
1346
  }
1358
1347
  } else if (animationPaused && playAnimation) {
1359
1348
  animationPaused = false;
@@ -1402,10 +1391,10 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1402
1391
  $$jqLite.addClass(element, activeClasses);
1403
1392
 
1404
1393
  if (flags.recalculateTimingStyles) {
1405
- fullClassName = node.className + ' ' + preparationClasses;
1406
- cacheKey = gcsHashFn(node, fullClassName);
1394
+ fullClassName = node.getAttribute('class') + ' ' + preparationClasses;
1395
+ cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass);
1407
1396
 
1408
- timings = computeTimings(node, fullClassName, cacheKey);
1397
+ timings = computeTimings(node, fullClassName, cacheKey, false);
1409
1398
  relativeDelay = timings.maxDelay;
1410
1399
  maxDelay = Math.max(relativeDelay, 0);
1411
1400
  maxDuration = timings.maxDuration;
@@ -1420,7 +1409,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1420
1409
  }
1421
1410
 
1422
1411
  if (flags.applyAnimationDelay) {
1423
- relativeDelay = typeof options.delay !== "boolean" && truthyTimingValue(options.delay)
1412
+ relativeDelay = typeof options.delay !== 'boolean' && truthyTimingValue(options.delay)
1424
1413
  ? parseFloat(options.delay)
1425
1414
  : relativeDelay;
1426
1415
 
@@ -1512,7 +1501,7 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
1512
1501
  }];
1513
1502
  }];
1514
1503
 
1515
- var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationProvider) {
1504
+ var $$AnimateCssDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) {
1516
1505
  $$animationProvider.drivers.push('$$animateCssDriver');
1517
1506
 
1518
1507
  var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';
@@ -1541,8 +1530,6 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
1541
1530
  isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode
1542
1531
  );
1543
1532
 
1544
- var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
1545
-
1546
1533
  return function initDriverFn(animationDetails) {
1547
1534
  return animationDetails.from && animationDetails.to
1548
1535
  ? prepareFromToAnchorAnimation(animationDetails.from,
@@ -1784,7 +1771,7 @@ var $$AnimateCssDriverProvider = ['$$animationProvider', function($$animationPro
1784
1771
  // TODO(matsko): add documentation
1785
1772
  // by the time...
1786
1773
 
1787
- var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
1774
+ var $$AnimateJsProvider = ['$animateProvider', /** @this */ function($animateProvider) {
1788
1775
  this.$get = ['$injector', '$$AnimateRunner', '$$jqLite',
1789
1776
  function($injector, $$AnimateRunner, $$jqLite) {
1790
1777
 
@@ -1823,7 +1810,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
1823
1810
  var before, after;
1824
1811
  if (animations.length) {
1825
1812
  var afterFn, beforeFn;
1826
- if (event == 'leave') {
1813
+ if (event === 'leave') {
1827
1814
  beforeFn = 'leave';
1828
1815
  afterFn = 'afterLeave'; // TODO(matsko): get rid of this
1829
1816
  } else {
@@ -2008,7 +1995,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
2008
1995
  function packageAnimations(element, event, options, animations, fnName) {
2009
1996
  var operations = groupEventedAnimations(element, event, options, animations, fnName);
2010
1997
  if (operations.length === 0) {
2011
- var a,b;
1998
+ var a, b;
2012
1999
  if (fnName === 'beforeSetClass') {
2013
2000
  a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');
2014
2001
  b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');
@@ -2036,11 +2023,19 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
2036
2023
  });
2037
2024
  }
2038
2025
 
2039
- runners.length ? $$AnimateRunner.all(runners, callback) : callback();
2026
+ if (runners.length) {
2027
+ $$AnimateRunner.all(runners, callback);
2028
+ } else {
2029
+ callback();
2030
+ }
2040
2031
 
2041
2032
  return function endFn(reject) {
2042
2033
  forEach(runners, function(runner) {
2043
- reject ? runner.cancel() : runner.end();
2034
+ if (reject) {
2035
+ runner.cancel();
2036
+ } else {
2037
+ runner.end();
2038
+ }
2044
2039
  });
2045
2040
  };
2046
2041
  };
@@ -2050,7 +2045,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
2050
2045
  function lookupAnimations(classes) {
2051
2046
  classes = isArray(classes) ? classes : classes.split(' ');
2052
2047
  var matches = [], flagMap = {};
2053
- for (var i=0; i < classes.length; i++) {
2048
+ for (var i = 0; i < classes.length; i++) {
2054
2049
  var klass = classes[i],
2055
2050
  animationFactory = $animateProvider.$$registeredAnimations[klass];
2056
2051
  if (animationFactory && !flagMap[klass]) {
@@ -2063,7 +2058,7 @@ var $$AnimateJsProvider = ['$animateProvider', function($animateProvider) {
2063
2058
  }];
2064
2059
  }];
2065
2060
 
2066
- var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProvider) {
2061
+ var $$AnimateJsDriverProvider = ['$$animationProvider', /** @this */ function($$animationProvider) {
2067
2062
  $$animationProvider.drivers.push('$$animateJsDriver');
2068
2063
  this.$get = ['$$animateJs', '$$AnimateRunner', function($$animateJs, $$AnimateRunner) {
2069
2064
  return function initDriverFn(animationDetails) {
@@ -2125,7 +2120,7 @@ var $$AnimateJsDriverProvider = ['$$animationProvider', function($$animationProv
2125
2120
 
2126
2121
  var NG_ANIMATE_ATTR_NAME = 'data-ng-animate';
2127
2122
  var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';
2128
- var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2123
+ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animateProvider) {
2129
2124
  var PRE_DIGEST_STATE = 1;
2130
2125
  var RUNNING_STATE = 2;
2131
2126
  var ONE_SPACE = ' ';
@@ -2136,6 +2131,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2136
2131
  join: []
2137
2132
  };
2138
2133
 
2134
+ function getEventData(options) {
2135
+ return {
2136
+ addClass: options.addClass,
2137
+ removeClass: options.removeClass,
2138
+ from: options.from,
2139
+ to: options.to
2140
+ };
2141
+ }
2142
+
2139
2143
  function makeTruthyCssClassMap(classString) {
2140
2144
  if (!classString) {
2141
2145
  return null;
@@ -2159,9 +2163,9 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2159
2163
  }
2160
2164
  }
2161
2165
 
2162
- function isAllowed(ruleType, element, currentAnimation, previousAnimation) {
2166
+ function isAllowed(ruleType, currentAnimation, previousAnimation) {
2163
2167
  return rules[ruleType].some(function(fn) {
2164
- return fn(element, currentAnimation, previousAnimation);
2168
+ return fn(currentAnimation, previousAnimation);
2165
2169
  });
2166
2170
  }
2167
2171
 
@@ -2171,40 +2175,40 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2171
2175
  return and ? a && b : a || b;
2172
2176
  }
2173
2177
 
2174
- rules.join.push(function(element, newAnimation, currentAnimation) {
2178
+ rules.join.push(function(newAnimation, currentAnimation) {
2175
2179
  // if the new animation is class-based then we can just tack that on
2176
2180
  return !newAnimation.structural && hasAnimationClasses(newAnimation);
2177
2181
  });
2178
2182
 
2179
- rules.skip.push(function(element, newAnimation, currentAnimation) {
2183
+ rules.skip.push(function(newAnimation, currentAnimation) {
2180
2184
  // there is no need to animate anything if no classes are being added and
2181
2185
  // there is no structural animation that will be triggered
2182
2186
  return !newAnimation.structural && !hasAnimationClasses(newAnimation);
2183
2187
  });
2184
2188
 
2185
- rules.skip.push(function(element, newAnimation, currentAnimation) {
2189
+ rules.skip.push(function(newAnimation, currentAnimation) {
2186
2190
  // why should we trigger a new structural animation if the element will
2187
2191
  // be removed from the DOM anyway?
2188
- return currentAnimation.event == 'leave' && newAnimation.structural;
2192
+ return currentAnimation.event === 'leave' && newAnimation.structural;
2189
2193
  });
2190
2194
 
2191
- rules.skip.push(function(element, newAnimation, currentAnimation) {
2195
+ rules.skip.push(function(newAnimation, currentAnimation) {
2192
2196
  // if there is an ongoing current animation then don't even bother running the class-based animation
2193
2197
  return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;
2194
2198
  });
2195
2199
 
2196
- rules.cancel.push(function(element, newAnimation, currentAnimation) {
2200
+ rules.cancel.push(function(newAnimation, currentAnimation) {
2197
2201
  // there can never be two structural animations running at the same time
2198
2202
  return currentAnimation.structural && newAnimation.structural;
2199
2203
  });
2200
2204
 
2201
- rules.cancel.push(function(element, newAnimation, currentAnimation) {
2205
+ rules.cancel.push(function(newAnimation, currentAnimation) {
2202
2206
  // if the previous animation is already running, but the new animation will
2203
2207
  // be triggered, but the new animation is structural
2204
2208
  return currentAnimation.state === RUNNING_STATE && newAnimation.structural;
2205
2209
  });
2206
2210
 
2207
- rules.cancel.push(function(element, newAnimation, currentAnimation) {
2211
+ rules.cancel.push(function(newAnimation, currentAnimation) {
2208
2212
  // cancel the animation if classes added / removed in both animation cancel each other out,
2209
2213
  // but only if the current animation isn't structural
2210
2214
 
@@ -2223,15 +2227,21 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2223
2227
  return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);
2224
2228
  });
2225
2229
 
2226
- this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap',
2230
+ this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$Map',
2227
2231
  '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow',
2228
- function($$rAF, $rootScope, $rootElement, $document, $$HashMap,
2229
- $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) {
2232
+ '$$isDocumentHidden',
2233
+ function($$rAF, $rootScope, $rootElement, $document, $$Map,
2234
+ $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow,
2235
+ $$isDocumentHidden) {
2230
2236
 
2231
- var activeAnimationsLookup = new $$HashMap();
2232
- var disabledElementsLookup = new $$HashMap();
2237
+ var activeAnimationsLookup = new $$Map();
2238
+ var disabledElementsLookup = new $$Map();
2233
2239
  var animationsEnabled = null;
2234
2240
 
2241
+ function removeFromDisabledElementsLookup(evt) {
2242
+ disabledElementsLookup.delete(evt.target);
2243
+ }
2244
+
2235
2245
  function postDigestTaskFactory() {
2236
2246
  var postDigestCalled = false;
2237
2247
  return function(fn) {
@@ -2281,14 +2291,17 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2281
2291
 
2282
2292
  var callbackRegistry = Object.create(null);
2283
2293
 
2284
- // remember that the classNameFilter is set during the provider/config
2285
- // stage therefore we can optimize here and setup a helper function
2294
+ // remember that the `customFilter`/`classNameFilter` are set during the
2295
+ // provider/config stage therefore we can optimize here and setup helper functions
2296
+ var customFilter = $animateProvider.customFilter();
2286
2297
  var classNameFilter = $animateProvider.classNameFilter();
2287
- var isAnimatableClassName = !classNameFilter
2288
- ? function() { return true; }
2289
- : function(className) {
2290
- return classNameFilter.test(className);
2291
- };
2298
+ var returnTrue = function() { return true; };
2299
+
2300
+ var isAnimatableByFilter = customFilter || returnTrue;
2301
+ var isAnimatableClassName = !classNameFilter ? returnTrue : function(node, options) {
2302
+ var className = [node.getAttribute('class'), options.addClass, options.removeClass].join(' ');
2303
+ return classNameFilter.test(className);
2304
+ };
2292
2305
 
2293
2306
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
2294
2307
 
@@ -2297,16 +2310,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2297
2310
  }
2298
2311
 
2299
2312
  // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2300
- var contains = window.Node.prototype.contains || function(arg) {
2301
- // jshint bitwise: false
2313
+ var contains = window.Node.prototype.contains || /** @this */ function(arg) {
2314
+ // eslint-disable-next-line no-bitwise
2302
2315
  return this === arg || !!(this.compareDocumentPosition(arg) & 16);
2303
- // jshint bitwise: true
2304
2316
  };
2305
2317
 
2306
- function findCallbacks(parent, element, event) {
2307
- var targetNode = getDomNode(element);
2308
- var targetParentNode = getDomNode(parent);
2309
-
2318
+ function findCallbacks(targetParentNode, targetNode, event) {
2310
2319
  var matches = [];
2311
2320
  var entries = callbackRegistry[event];
2312
2321
  if (entries) {
@@ -2331,11 +2340,11 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2331
2340
  });
2332
2341
  }
2333
2342
 
2334
- function cleanupEventListeners(phase, element) {
2335
- if (phase === 'close' && !element[0].parentNode) {
2343
+ function cleanupEventListeners(phase, node) {
2344
+ if (phase === 'close' && !node.parentNode) {
2336
2345
  // If the element is not attached to a parentNode, it has been removed by
2337
2346
  // the domOperation, and we can safely remove the event callbacks
2338
- $animate.off(element);
2347
+ $animate.off(node);
2339
2348
  }
2340
2349
  }
2341
2350
 
@@ -2416,7 +2425,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2416
2425
  bool = !disabledElementsLookup.get(node);
2417
2426
  } else {
2418
2427
  // (element, bool) - Element setter
2419
- disabledElementsLookup.put(node, !bool);
2428
+ if (!disabledElementsLookup.has(node)) {
2429
+ // The element is added to the map for the first time.
2430
+ // Create a listener to remove it on `$destroy` (to avoid memory leak).
2431
+ jqLite(element).on('$destroy', removeFromDisabledElementsLookup);
2432
+ }
2433
+ disabledElementsLookup.set(node, !bool);
2420
2434
  }
2421
2435
  }
2422
2436
  }
@@ -2427,18 +2441,15 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2427
2441
 
2428
2442
  return $animate;
2429
2443
 
2430
- function queueAnimation(element, event, initialOptions) {
2444
+ function queueAnimation(originalElement, event, initialOptions) {
2431
2445
  // we always make a copy of the options since
2432
2446
  // there should never be any side effects on
2433
2447
  // the input data when running `$animateCss`.
2434
2448
  var options = copy(initialOptions);
2435
2449
 
2436
- var node, parent;
2437
- element = stripCommentsFromElement(element);
2438
- if (element) {
2439
- node = getDomNode(element);
2440
- parent = element.parent();
2441
- }
2450
+ var element = stripCommentsFromElement(originalElement);
2451
+ var node = getDomNode(element);
2452
+ var parentNode = node && node.parentNode;
2442
2453
 
2443
2454
  options = prepareAnimationOptions(options);
2444
2455
 
@@ -2473,49 +2484,45 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2473
2484
  options.to = null;
2474
2485
  }
2475
2486
 
2476
- // there are situations where a directive issues an animation for
2477
- // a jqLite wrapper that contains only comment nodes... If this
2478
- // happens then there is no way we can perform an animation
2479
- if (!node) {
2480
- close();
2481
- return runner;
2482
- }
2483
-
2484
- var className = [node.className, options.addClass, options.removeClass].join(' ');
2485
- if (!isAnimatableClassName(className)) {
2487
+ // If animations are hard-disabled for the whole application there is no need to continue.
2488
+ // There are also situations where a directive issues an animation for a jqLite wrapper that
2489
+ // contains only comment nodes. In this case, there is no way we can perform an animation.
2490
+ if (!animationsEnabled ||
2491
+ !node ||
2492
+ !isAnimatableByFilter(node, event, initialOptions) ||
2493
+ !isAnimatableClassName(node, options)) {
2486
2494
  close();
2487
2495
  return runner;
2488
2496
  }
2489
2497
 
2490
2498
  var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0;
2491
2499
 
2492
- var documentHidden = $document[0].hidden;
2500
+ var documentHidden = $$isDocumentHidden();
2493
2501
 
2494
- // this is a hard disable of all animations for the application or on
2495
- // the element itself, therefore there is no need to continue further
2496
- // past this point if not enabled
2502
+ // This is a hard disable of all animations the element itself, therefore there is no need to
2503
+ // continue further past this point if not enabled
2497
2504
  // Animations are also disabled if the document is currently hidden (page is not visible
2498
2505
  // to the user), because browsers slow down or do not flush calls to requestAnimationFrame
2499
- var skipAnimations = !animationsEnabled || documentHidden || disabledElementsLookup.get(node);
2506
+ var skipAnimations = documentHidden || disabledElementsLookup.get(node);
2500
2507
  var existingAnimation = (!skipAnimations && activeAnimationsLookup.get(node)) || {};
2501
2508
  var hasExistingAnimation = !!existingAnimation.state;
2502
2509
 
2503
2510
  // there is no point in traversing the same collection of parent ancestors if a followup
2504
2511
  // animation will be run on the same element that already did all that checking work
2505
- if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state != PRE_DIGEST_STATE)) {
2506
- skipAnimations = !areAnimationsAllowed(element, parent, event);
2512
+ if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state !== PRE_DIGEST_STATE)) {
2513
+ skipAnimations = !areAnimationsAllowed(node, parentNode, event);
2507
2514
  }
2508
2515
 
2509
2516
  if (skipAnimations) {
2510
2517
  // Callbacks should fire even if the document is hidden (regression fix for issue #14120)
2511
- if (documentHidden) notifyProgress(runner, event, 'start');
2518
+ if (documentHidden) notifyProgress(runner, event, 'start', getEventData(options));
2512
2519
  close();
2513
- if (documentHidden) notifyProgress(runner, event, 'close');
2520
+ if (documentHidden) notifyProgress(runner, event, 'close', getEventData(options));
2514
2521
  return runner;
2515
2522
  }
2516
2523
 
2517
2524
  if (isStructural) {
2518
- closeChildAnimations(element);
2525
+ closeChildAnimations(node);
2519
2526
  }
2520
2527
 
2521
2528
  var newAnimation = {
@@ -2530,7 +2537,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2530
2537
  };
2531
2538
 
2532
2539
  if (hasExistingAnimation) {
2533
- var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation);
2540
+ var skipAnimationFlag = isAllowed('skip', newAnimation, existingAnimation);
2534
2541
  if (skipAnimationFlag) {
2535
2542
  if (existingAnimation.state === RUNNING_STATE) {
2536
2543
  close();
@@ -2540,7 +2547,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2540
2547
  return existingAnimation.runner;
2541
2548
  }
2542
2549
  }
2543
- var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);
2550
+ var cancelAnimationFlag = isAllowed('cancel', newAnimation, existingAnimation);
2544
2551
  if (cancelAnimationFlag) {
2545
2552
  if (existingAnimation.state === RUNNING_STATE) {
2546
2553
  // this will end the animation right away and it is safe
@@ -2562,12 +2569,12 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2562
2569
  // a joined animation means that this animation will take over the existing one
2563
2570
  // so an example would involve a leave animation taking over an enter. Then when
2564
2571
  // the postDigest kicks in the enter will be ignored.
2565
- var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);
2572
+ var joinAnimationFlag = isAllowed('join', newAnimation, existingAnimation);
2566
2573
  if (joinAnimationFlag) {
2567
2574
  if (existingAnimation.state === RUNNING_STATE) {
2568
2575
  normalizeAnimationDetails(element, newAnimation);
2569
2576
  } else {
2570
- applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
2577
+ applyGeneratedPreparationClasses($$jqLite, element, isStructural ? event : null, options);
2571
2578
 
2572
2579
  event = newAnimation.event = existingAnimation.event;
2573
2580
  options = mergeAnimationDetails(element, existingAnimation, newAnimation);
@@ -2596,7 +2603,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2596
2603
 
2597
2604
  if (!isValidAnimation) {
2598
2605
  close();
2599
- clearElementAnimationState(element);
2606
+ clearElementAnimationState(node);
2600
2607
  return runner;
2601
2608
  }
2602
2609
 
@@ -2604,9 +2611,18 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2604
2611
  var counter = (existingAnimation.counter || 0) + 1;
2605
2612
  newAnimation.counter = counter;
2606
2613
 
2607
- markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation);
2614
+ markElementAnimationState(node, PRE_DIGEST_STATE, newAnimation);
2608
2615
 
2609
2616
  $rootScope.$$postDigest(function() {
2617
+ // It is possible that the DOM nodes inside `originalElement` have been replaced. This can
2618
+ // happen if the animated element is a transcluded clone and also has a `templateUrl`
2619
+ // directive on it. Therefore, we must recreate `element` in order to interact with the
2620
+ // actual DOM nodes.
2621
+ // Note: We still need to use the old `node` for certain things, such as looking up in
2622
+ // HashMaps where it was used as the key.
2623
+
2624
+ element = stripCommentsFromElement(originalElement);
2625
+
2610
2626
  var animationDetails = activeAnimationsLookup.get(node);
2611
2627
  var animationCancelled = !animationDetails;
2612
2628
  animationDetails = animationDetails || {};
@@ -2645,7 +2661,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2645
2661
  // isn't allowed to animate from here then we need to clear the state of the element
2646
2662
  // so that any future animations won't read the expired animation data.
2647
2663
  if (!isValidAnimation) {
2648
- clearElementAnimationState(element);
2664
+ clearElementAnimationState(node);
2649
2665
  }
2650
2666
 
2651
2667
  return;
@@ -2657,21 +2673,21 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2657
2673
  ? 'setClass'
2658
2674
  : animationDetails.event;
2659
2675
 
2660
- markElementAnimationState(element, RUNNING_STATE);
2676
+ markElementAnimationState(node, RUNNING_STATE);
2661
2677
  var realRunner = $$animation(element, event, animationDetails.options);
2662
2678
 
2663
2679
  // this will update the runner's flow-control events based on
2664
2680
  // the `realRunner` object.
2665
2681
  runner.setHost(realRunner);
2666
- notifyProgress(runner, event, 'start', {});
2682
+ notifyProgress(runner, event, 'start', getEventData(options));
2667
2683
 
2668
2684
  realRunner.done(function(status) {
2669
2685
  close(!status);
2670
2686
  var animationDetails = activeAnimationsLookup.get(node);
2671
2687
  if (animationDetails && animationDetails.counter === counter) {
2672
- clearElementAnimationState(getDomNode(element));
2688
+ clearElementAnimationState(node);
2673
2689
  }
2674
- notifyProgress(runner, event, 'close', {});
2690
+ notifyProgress(runner, event, 'close', getEventData(options));
2675
2691
  });
2676
2692
  });
2677
2693
 
@@ -2679,7 +2695,7 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2679
2695
 
2680
2696
  function notifyProgress(runner, event, phase, data) {
2681
2697
  runInNextPostDigestOrNow(function() {
2682
- var callbacks = findCallbacks(parent, element, event);
2698
+ var callbacks = findCallbacks(parentNode, node, event);
2683
2699
  if (callbacks.length) {
2684
2700
  // do not optimize this call here to RAF because
2685
2701
  // we don't know how heavy the callback code here will
@@ -2689,16 +2705,16 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2689
2705
  forEach(callbacks, function(callback) {
2690
2706
  callback(element, phase, data);
2691
2707
  });
2692
- cleanupEventListeners(phase, element);
2708
+ cleanupEventListeners(phase, node);
2693
2709
  });
2694
2710
  } else {
2695
- cleanupEventListeners(phase, element);
2711
+ cleanupEventListeners(phase, node);
2696
2712
  }
2697
2713
  });
2698
2714
  runner.progress(event, phase, data);
2699
2715
  }
2700
2716
 
2701
- function close(reject) { // jshint ignore:line
2717
+ function close(reject) {
2702
2718
  clearGeneratedClasses(element, options);
2703
2719
  applyAnimationClasses(element, options);
2704
2720
  applyAnimationStyles(element, options);
@@ -2707,11 +2723,10 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2707
2723
  }
2708
2724
  }
2709
2725
 
2710
- function closeChildAnimations(element) {
2711
- var node = getDomNode(element);
2726
+ function closeChildAnimations(node) {
2712
2727
  var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');
2713
2728
  forEach(children, function(child) {
2714
- var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));
2729
+ var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME), 10);
2715
2730
  var animationDetails = activeAnimationsLookup.get(child);
2716
2731
  if (animationDetails) {
2717
2732
  switch (state) {
@@ -2719,21 +2734,16 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2719
2734
  animationDetails.runner.end();
2720
2735
  /* falls through */
2721
2736
  case PRE_DIGEST_STATE:
2722
- activeAnimationsLookup.remove(child);
2737
+ activeAnimationsLookup.delete(child);
2723
2738
  break;
2724
2739
  }
2725
2740
  }
2726
2741
  });
2727
2742
  }
2728
2743
 
2729
- function clearElementAnimationState(element) {
2730
- var node = getDomNode(element);
2744
+ function clearElementAnimationState(node) {
2731
2745
  node.removeAttribute(NG_ANIMATE_ATTR_NAME);
2732
- activeAnimationsLookup.remove(node);
2733
- }
2734
-
2735
- function isMatchingElement(nodeOrElmA, nodeOrElmB) {
2736
- return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);
2746
+ activeAnimationsLookup.delete(node);
2737
2747
  }
2738
2748
 
2739
2749
  /**
@@ -2743,54 +2753,54 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2743
2753
  * c) the element is not a child of the body
2744
2754
  * d) the element is not a child of the $rootElement
2745
2755
  */
2746
- function areAnimationsAllowed(element, parentElement, event) {
2747
- var bodyElement = jqLite($document[0].body);
2748
- var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';
2749
- var rootElementDetected = isMatchingElement(element, $rootElement);
2756
+ function areAnimationsAllowed(node, parentNode, event) {
2757
+ var bodyNode = $document[0].body;
2758
+ var rootNode = getDomNode($rootElement);
2759
+
2760
+ var bodyNodeDetected = (node === bodyNode) || node.nodeName === 'HTML';
2761
+ var rootNodeDetected = (node === rootNode);
2750
2762
  var parentAnimationDetected = false;
2763
+ var elementDisabled = disabledElementsLookup.get(node);
2751
2764
  var animateChildren;
2752
- var elementDisabled = disabledElementsLookup.get(getDomNode(element));
2753
2765
 
2754
- var parentHost = jqLite.data(element[0], NG_ANIMATE_PIN_DATA);
2766
+ var parentHost = jqLite.data(node, NG_ANIMATE_PIN_DATA);
2755
2767
  if (parentHost) {
2756
- parentElement = parentHost;
2768
+ parentNode = getDomNode(parentHost);
2757
2769
  }
2758
2770
 
2759
- parentElement = getDomNode(parentElement);
2760
-
2761
- while (parentElement) {
2762
- if (!rootElementDetected) {
2763
- // angular doesn't want to attempt to animate elements outside of the application
2771
+ while (parentNode) {
2772
+ if (!rootNodeDetected) {
2773
+ // AngularJS doesn't want to attempt to animate elements outside of the application
2764
2774
  // therefore we need to ensure that the rootElement is an ancestor of the current element
2765
- rootElementDetected = isMatchingElement(parentElement, $rootElement);
2775
+ rootNodeDetected = (parentNode === rootNode);
2766
2776
  }
2767
2777
 
2768
- if (parentElement.nodeType !== ELEMENT_NODE) {
2778
+ if (parentNode.nodeType !== ELEMENT_NODE) {
2769
2779
  // no point in inspecting the #document element
2770
2780
  break;
2771
2781
  }
2772
2782
 
2773
- var details = activeAnimationsLookup.get(parentElement) || {};
2783
+ var details = activeAnimationsLookup.get(parentNode) || {};
2774
2784
  // either an enter, leave or move animation will commence
2775
2785
  // therefore we can't allow any animations to take place
2776
2786
  // but if a parent animation is class-based then that's ok
2777
2787
  if (!parentAnimationDetected) {
2778
- var parentElementDisabled = disabledElementsLookup.get(parentElement);
2788
+ var parentNodeDisabled = disabledElementsLookup.get(parentNode);
2779
2789
 
2780
- if (parentElementDisabled === true && elementDisabled !== false) {
2790
+ if (parentNodeDisabled === true && elementDisabled !== false) {
2781
2791
  // disable animations if the user hasn't explicitly enabled animations on the
2782
2792
  // current element
2783
2793
  elementDisabled = true;
2784
2794
  // element is disabled via parent element, no need to check anything else
2785
2795
  break;
2786
- } else if (parentElementDisabled === false) {
2796
+ } else if (parentNodeDisabled === false) {
2787
2797
  elementDisabled = false;
2788
2798
  }
2789
2799
  parentAnimationDetected = details.structural;
2790
2800
  }
2791
2801
 
2792
2802
  if (isUndefined(animateChildren) || animateChildren === true) {
2793
- var value = jqLite.data(parentElement, NG_ANIMATE_CHILDREN_DATA);
2803
+ var value = jqLite.data(parentNode, NG_ANIMATE_CHILDREN_DATA);
2794
2804
  if (isDefined(value)) {
2795
2805
  animateChildren = value;
2796
2806
  }
@@ -2799,57 +2809,115 @@ var $$AnimateQueueProvider = ['$animateProvider', function($animateProvider) {
2799
2809
  // there is no need to continue traversing at this point
2800
2810
  if (parentAnimationDetected && animateChildren === false) break;
2801
2811
 
2802
- if (!bodyElementDetected) {
2812
+ if (!bodyNodeDetected) {
2803
2813
  // we also need to ensure that the element is or will be a part of the body element
2804
2814
  // otherwise it is pointless to even issue an animation to be rendered
2805
- bodyElementDetected = isMatchingElement(parentElement, bodyElement);
2815
+ bodyNodeDetected = (parentNode === bodyNode);
2806
2816
  }
2807
2817
 
2808
- if (bodyElementDetected && rootElementDetected) {
2818
+ if (bodyNodeDetected && rootNodeDetected) {
2809
2819
  // If both body and root have been found, any other checks are pointless,
2810
2820
  // as no animation data should live outside the application
2811
2821
  break;
2812
2822
  }
2813
2823
 
2814
- if (!rootElementDetected) {
2815
- // If no rootElement is detected, check if the parentElement is pinned to another element
2816
- parentHost = jqLite.data(parentElement, NG_ANIMATE_PIN_DATA);
2824
+ if (!rootNodeDetected) {
2825
+ // If `rootNode` is not detected, check if `parentNode` is pinned to another element
2826
+ parentHost = jqLite.data(parentNode, NG_ANIMATE_PIN_DATA);
2817
2827
  if (parentHost) {
2818
2828
  // The pin target element becomes the next parent element
2819
- parentElement = getDomNode(parentHost);
2829
+ parentNode = getDomNode(parentHost);
2820
2830
  continue;
2821
2831
  }
2822
2832
  }
2823
2833
 
2824
- parentElement = parentElement.parentNode;
2834
+ parentNode = parentNode.parentNode;
2825
2835
  }
2826
2836
 
2827
2837
  var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;
2828
- return allowAnimation && rootElementDetected && bodyElementDetected;
2838
+ return allowAnimation && rootNodeDetected && bodyNodeDetected;
2829
2839
  }
2830
2840
 
2831
- function markElementAnimationState(element, state, details) {
2841
+ function markElementAnimationState(node, state, details) {
2832
2842
  details = details || {};
2833
2843
  details.state = state;
2834
2844
 
2835
- var node = getDomNode(element);
2836
2845
  node.setAttribute(NG_ANIMATE_ATTR_NAME, state);
2837
2846
 
2838
2847
  var oldValue = activeAnimationsLookup.get(node);
2839
2848
  var newValue = oldValue
2840
2849
  ? extend(oldValue, details)
2841
2850
  : details;
2842
- activeAnimationsLookup.put(node, newValue);
2851
+ activeAnimationsLookup.set(node, newValue);
2843
2852
  }
2844
2853
  }];
2845
2854
  }];
2846
2855
 
2847
- var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2856
+ /** @this */
2857
+ var $$AnimateCacheProvider = function() {
2858
+
2859
+ var KEY = '$$ngAnimateParentKey';
2860
+ var parentCounter = 0;
2861
+ var cache = Object.create(null);
2862
+
2863
+ this.$get = [function() {
2864
+ return {
2865
+ cacheKey: function(node, method, addClass, removeClass) {
2866
+ var parentNode = node.parentNode;
2867
+ var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
2868
+ var parts = [parentID, method, node.getAttribute('class')];
2869
+ if (addClass) {
2870
+ parts.push(addClass);
2871
+ }
2872
+ if (removeClass) {
2873
+ parts.push(removeClass);
2874
+ }
2875
+ return parts.join(' ');
2876
+ },
2877
+
2878
+ containsCachedAnimationWithoutDuration: function(key) {
2879
+ var entry = cache[key];
2880
+
2881
+ // nothing cached, so go ahead and animate
2882
+ // otherwise it should be a valid animation
2883
+ return (entry && !entry.isValid) || false;
2884
+ },
2885
+
2886
+ flush: function() {
2887
+ cache = Object.create(null);
2888
+ },
2889
+
2890
+ count: function(key) {
2891
+ var entry = cache[key];
2892
+ return entry ? entry.total : 0;
2893
+ },
2894
+
2895
+ get: function(key) {
2896
+ var entry = cache[key];
2897
+ return entry && entry.value;
2898
+ },
2899
+
2900
+ put: function(key, value, isValid) {
2901
+ if (!cache[key]) {
2902
+ cache[key] = { total: 1, value: value, isValid: isValid };
2903
+ } else {
2904
+ cache[key].total++;
2905
+ cache[key].value = value;
2906
+ }
2907
+ }
2908
+ };
2909
+ }];
2910
+ };
2911
+
2912
+ /* exported $$AnimationProvider */
2913
+
2914
+ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animateProvider) {
2848
2915
  var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';
2849
2916
 
2850
2917
  var drivers = this.drivers = [];
2851
2918
 
2852
2919
  var RUNNER_STORAGE_KEY = '$$animationRunner';
2920
+ var PREPARE_CLASSES_KEY = '$$animatePrepareClasses';
2853
2921
 
2854
2922
  function setRunner(element, runner) {
2855
2923
  element.data(RUNNER_STORAGE_KEY, runner);
@@ -2863,22 +2931,23 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2863
2931
  return element.data(RUNNER_STORAGE_KEY);
2864
2932
  }
2865
2933
 
2866
- this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap', '$$rAFScheduler',
2867
- function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap, $$rAFScheduler) {
2934
+ this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler', '$$animateCache',
2935
+ function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$Map, $$rAFScheduler, $$animateCache) {
2868
2936
 
2869
2937
  var animationQueue = [];
2870
2938
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
2871
2939
 
2872
2940
  function sortAnimations(animations) {
2873
2941
  var tree = { children: [] };
2874
- var i, lookup = new $$HashMap();
2942
+ var i, lookup = new $$Map();
2875
2943
 
2876
- // this is done first beforehand so that the hashmap
2944
+ // this is done first beforehand so that the map
2877
2945
  // is filled with a list of the elements that will be animated
2878
2946
  for (i = 0; i < animations.length; i++) {
2879
2947
  var animation = animations[i];
2880
- lookup.put(animation.domNode, animations[i] = {
2948
+ lookup.set(animation.domNode, animations[i] = {
2881
2949
  domNode: animation.domNode,
2950
+ element: animation.element,
2882
2951
  fn: animation.fn,
2883
2952
  children: []
2884
2953
  });
@@ -2896,7 +2965,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2896
2965
 
2897
2966
  var elementNode = entry.domNode;
2898
2967
  var parentNode = elementNode.parentNode;
2899
- lookup.put(elementNode, entry);
2968
+ lookup.set(elementNode, entry);
2900
2969
 
2901
2970
  var parentEntry;
2902
2971
  while (parentNode) {
@@ -2935,7 +3004,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2935
3004
  result.push(row);
2936
3005
  row = [];
2937
3006
  }
2938
- row.push(entry.fn);
3007
+ row.push(entry);
2939
3008
  entry.children.forEach(function(childEntry) {
2940
3009
  nextLevelEntries++;
2941
3010
  queue.push(childEntry);
@@ -2970,8 +3039,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2970
3039
  return runner;
2971
3040
  }
2972
3041
 
2973
- setRunner(element, runner);
2974
-
2975
3042
  var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));
2976
3043
  var tempClasses = options.tempClasses;
2977
3044
  if (tempClasses) {
@@ -2979,12 +3046,12 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
2979
3046
  options.tempClasses = null;
2980
3047
  }
2981
3048
 
2982
- var prepareClassName;
2983
3049
  if (isStructural) {
2984
- prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX;
2985
- $$jqLite.addClass(element, prepareClassName);
3050
+ element.data(PREPARE_CLASSES_KEY, 'ng-' + event + PREPARE_CLASS_SUFFIX);
2986
3051
  }
2987
3052
 
3053
+ setRunner(element, runner);
3054
+
2988
3055
  animationQueue.push({
2989
3056
  // this data is used by the postDigest code and passed into
2990
3057
  // the driver step function
@@ -3024,16 +3091,31 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3024
3091
  var toBeSortedAnimations = [];
3025
3092
 
3026
3093
  forEach(groupedAnimations, function(animationEntry) {
3094
+ var element = animationEntry.from ? animationEntry.from.element : animationEntry.element;
3095
+ var extraClasses = options.addClass;
3096
+
3097
+ extraClasses = (extraClasses ? (extraClasses + ' ') : '') + NG_ANIMATE_CLASSNAME;
3098
+ var cacheKey = $$animateCache.cacheKey(element[0], animationEntry.event, extraClasses, options.removeClass);
3099
+
3027
3100
  toBeSortedAnimations.push({
3028
- domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),
3101
+ element: element,
3102
+ domNode: getDomNode(element),
3029
3103
  fn: function triggerAnimationStart() {
3104
+ var startAnimationFn, closeFn = animationEntry.close;
3105
+
3106
+ // in the event that we've cached the animation status for this element
3107
+ // and it's in fact an invalid animation (something that has duration = 0)
3108
+ // then we should skip all the heavy work from here on
3109
+ if ($$animateCache.containsCachedAnimationWithoutDuration(cacheKey)) {
3110
+ closeFn();
3111
+ return;
3112
+ }
3113
+
3030
3114
  // it's important that we apply the `ng-animate` CSS class and the
3031
3115
  // temporary classes before we do any driver invoking since these
3032
3116
  // CSS classes may be required for proper CSS detection.
3033
3117
  animationEntry.beforeStart();
3034
3118
 
3035
- var startAnimationFn, closeFn = animationEntry.close;
3036
-
3037
3119
  // in the event that the element was removed before the digest runs or
3038
3120
  // during the RAF sequencing then we should not trigger the animation.
3039
3121
  var targetElement = animationEntry.anchors
@@ -3063,7 +3145,32 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3063
3145
  // we need to sort each of the animations in order of parent to child
3064
3146
  // relationships. This ensures that the child classes are applied at the
3065
3147
  // right time.
3066
- $$rAFScheduler(sortAnimations(toBeSortedAnimations));
3148
+ var finalAnimations = sortAnimations(toBeSortedAnimations);
3149
+ for (var i = 0; i < finalAnimations.length; i++) {
3150
+ var innerArray = finalAnimations[i];
3151
+ for (var j = 0; j < innerArray.length; j++) {
3152
+ var entry = innerArray[j];
3153
+ var element = entry.element;
3154
+
3155
+ // the RAFScheduler code only uses functions
3156
+ finalAnimations[i][j] = entry.fn;
3157
+
3158
+ // the first row of elements shouldn't have a prepare-class added to them
3159
+ // since the elements are at the top of the animation hierarchy and they
3160
+ // will be applied without a RAF having to pass...
3161
+ if (i === 0) {
3162
+ element.removeData(PREPARE_CLASSES_KEY);
3163
+ continue;
3164
+ }
3165
+
3166
+ var prepareClassName = element.data(PREPARE_CLASSES_KEY);
3167
+ if (prepareClassName) {
3168
+ $$jqLite.addClass(element, prepareClassName);
3169
+ }
3170
+ }
3171
+ }
3172
+
3173
+ $$rAFScheduler(finalAnimations);
3067
3174
  });
3068
3175
 
3069
3176
  return runner;
@@ -3201,10 +3308,10 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3201
3308
  }
3202
3309
 
3203
3310
  function beforeStart() {
3204
- element.addClass(NG_ANIMATE_CLASSNAME);
3205
- if (tempClasses) {
3206
- $$jqLite.addClass(element, tempClasses);
3207
- }
3311
+ tempClasses = (tempClasses ? (tempClasses + ' ') : '') + NG_ANIMATE_CLASSNAME;
3312
+ $$jqLite.addClass(element, tempClasses);
3313
+
3314
+ var prepareClassName = element.data(PREPARE_CLASSES_KEY);
3208
3315
  if (prepareClassName) {
3209
3316
  $$jqLite.removeClass(element, prepareClassName);
3210
3317
  prepareClassName = null;
@@ -3232,7 +3339,7 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3232
3339
  }
3233
3340
  }
3234
3341
 
3235
- function close(rejected) { // jshint ignore:line
3342
+ function close(rejected) {
3236
3343
  element.off('$destroy', handleDestroyedElement);
3237
3344
  removeRunner(element);
3238
3345
 
@@ -3244,7 +3351,6 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3244
3351
  $$jqLite.removeClass(element, tempClasses);
3245
3352
  }
3246
3353
 
3247
- element.removeClass(NG_ANIMATE_CLASSNAME);
3248
3354
  runner.complete(!rejected);
3249
3355
  }
3250
3356
  };
@@ -3338,12 +3444,13 @@ var $$AnimationProvider = ['$animateProvider', function($animateProvider) {
3338
3444
  * </file>
3339
3445
  * </example>
3340
3446
  */
3341
- var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
3447
+ var ngAnimateSwapDirective = ['$animate', function($animate) {
3342
3448
  return {
3343
3449
  restrict: 'A',
3344
3450
  transclude: 'element',
3345
3451
  terminal: true,
3346
- priority: 600, // we use 600 here to ensure that the directive is caught before others
3452
+ priority: 550, // We use 550 here to ensure that the directive is caught before others,
3453
+ // but after `ngIf` (at priority 600).
3347
3454
  link: function(scope, $element, attrs, ctrl, $transclude) {
3348
3455
  var previousElement, previousScope;
3349
3456
  scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {
@@ -3355,10 +3462,10 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3355
3462
  previousScope = null;
3356
3463
  }
3357
3464
  if (value || value === 0) {
3358
- previousScope = scope.$new();
3359
- $transclude(previousScope, function(element) {
3360
- previousElement = element;
3361
- $animate.enter(element, null, $element);
3465
+ $transclude(function(clone, childScope) {
3466
+ previousElement = clone;
3467
+ previousScope = childScope;
3468
+ $animate.enter(clone, null, $element);
3362
3469
  });
3363
3470
  }
3364
3471
  });
@@ -3372,11 +3479,9 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3372
3479
  * @description
3373
3480
  *
3374
3481
  * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via
3375
- * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an Angular app.
3482
+ * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an AngularJS app.
3376
3483
  *
3377
- * <div doc-module-components="ngAnimate"></div>
3378
- *
3379
- * # Usage
3484
+ * ## Usage
3380
3485
  * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based
3381
3486
  * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For
3382
3487
  * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within
@@ -3385,25 +3490,33 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3385
3490
  * ## Directive Support
3386
3491
  * The following directives are "animation aware":
3387
3492
  *
3388
- * | Directive | Supported Animations |
3389
- * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
3390
- * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |
3391
- * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
3392
- * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
3393
- * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
3394
- * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
3395
- * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) |
3396
- * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) |
3397
- * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
3398
- * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) |
3399
- * | {@link module:ngMessages#animations ngMessage} | enter and leave |
3400
- *
3401
- * (More information can be found by visiting each the documentation associated with each directive.)
3493
+ * | Directive | Supported Animations |
3494
+ * |-------------------------------------------------------------------------------|---------------------------------------------------------------------------|
3495
+ * | {@link ng.directive:form#animations form / ngForm} | add and remove ({@link ng.directive:form#css-classes various classes}) |
3496
+ * | {@link ngAnimate.directive:ngAnimateSwap#animations ngAnimateSwap} | enter and leave |
3497
+ * | {@link ng.directive:ngClass#animations ngClass / {{class&#125;&#8203;&#125;} | add and remove |
3498
+ * | {@link ng.directive:ngClassEven#animations ngClassEven} | add and remove |
3499
+ * | {@link ng.directive:ngClassOdd#animations ngClassOdd} | add and remove |
3500
+ * | {@link ng.directive:ngHide#animations ngHide} | add and remove (the `ng-hide` class) |
3501
+ * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
3502
+ * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
3503
+ * | {@link module:ngMessages#animations ngMessage / ngMessageExp} | enter and leave |
3504
+ * | {@link module:ngMessages#animations ngMessages} | add and remove (the `ng-active`/`ng-inactive` classes) |
3505
+ * | {@link ng.directive:ngModel#animations ngModel} | add and remove ({@link ng.directive:ngModel#css-classes various classes}) |
3506
+ * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave, and move |
3507
+ * | {@link ng.directive:ngShow#animations ngShow} | add and remove (the `ng-hide` class) |
3508
+ * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
3509
+ * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
3510
+ *
3511
+ * (More information can be found by visiting the documentation associated with each directive.)
3512
+ *
3513
+ * For a full breakdown of the steps involved during each animation event, refer to the
3514
+ * {@link ng.$animate `$animate` API docs}.
3402
3515
  *
3403
3516
  * ## CSS-based Animations
3404
3517
  *
3405
3518
  * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML
3406
- * and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation.
3519
+ * and CSS code we can create an animation that will be picked up by AngularJS when an underlying directive performs an operation.
3407
3520
  *
3408
3521
  * The example below shows how an `enter` animation can be made possible on an element using `ng-if`:
3409
3522
  *
@@ -3543,6 +3656,10 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3543
3656
  * /&#42; As of 1.4.4, this must always be set: it signals ngAnimate
3544
3657
  * to not accidentally inherit a delay property from another CSS class &#42;/
3545
3658
  * transition-duration: 0s;
3659
+ *
3660
+ * /&#42; if you are using animations instead of transitions you should configure as follows:
3661
+ * animation-delay: 0.1s;
3662
+ * animation-duration: 0s; &#42;/
3546
3663
  * }
3547
3664
  * .my-animation.ng-enter.ng-enter-active {
3548
3665
  * /&#42; standard transition styles &#42;/
@@ -3631,9 +3748,22 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3631
3748
  * .message.ng-enter-prepare {
3632
3749
  * opacity: 0;
3633
3750
  * }
3634
- *
3635
3751
  * ```
3636
3752
  *
3753
+ * ### Animating between value changes
3754
+ *
3755
+ * Sometimes you need to animate between different expression states, whose values
3756
+ * don't necessary need to be known or referenced in CSS styles.
3757
+ * Unless possible with another {@link ngAnimate#directive-support "animation aware" directive},
3758
+ * that specific use case can always be covered with {@link ngAnimate.directive:ngAnimateSwap} as
3759
+ * can be seen in {@link ngAnimate.directive:ngAnimateSwap#examples this example}.
3760
+ *
3761
+ * Note that {@link ngAnimate.directive:ngAnimateSwap} is a *structural directive*, which means it
3762
+ * creates a new instance of the element (including any other/child directives it may have) and
3763
+ * links it to a new scope every time *swap* happens. In some cases this might not be desirable
3764
+ * (e.g. for performance reasons, or when you wish to retain internal state on the original
3765
+ * element instance).
3766
+ *
3637
3767
  * ## JavaScript-based Animations
3638
3768
  *
3639
3769
  * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared
@@ -3658,7 +3788,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3658
3788
  * enter: function(element, doneFn) {
3659
3789
  * jQuery(element).fadeIn(1000, doneFn);
3660
3790
  *
3661
- * // remember to call doneFn so that angular
3791
+ * // remember to call doneFn so that AngularJS
3662
3792
  * // knows that the animation has concluded
3663
3793
  * },
3664
3794
  *
@@ -3706,7 +3836,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3706
3836
  *
3707
3837
  * ## CSS + JS Animations Together
3708
3838
  *
3709
- * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,
3839
+ * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of AngularJS,
3710
3840
  * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking
3711
3841
  * charge of the animation**:
3712
3842
  *
@@ -3898,7 +4028,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3898
4028
  deps="angular-animate.js;angular-route.js"
3899
4029
  animations="true">
3900
4030
  <file name="index.html">
3901
- <a href="#/">Home</a>
4031
+ <a href="#!/">Home</a>
3902
4032
  <hr />
3903
4033
  <div class="view-container">
3904
4034
  <div ng-view class="view"></div>
@@ -3918,22 +4048,23 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3918
4048
  }])
3919
4049
  .run(['$rootScope', function($rootScope) {
3920
4050
  $rootScope.records = [
3921
- { id:1, title: "Miss Beulah Roob" },
3922
- { id:2, title: "Trent Morissette" },
3923
- { id:3, title: "Miss Ava Pouros" },
3924
- { id:4, title: "Rod Pouros" },
3925
- { id:5, title: "Abdul Rice" },
3926
- { id:6, title: "Laurie Rutherford Sr." },
3927
- { id:7, title: "Nakia McLaughlin" },
3928
- { id:8, title: "Jordon Blanda DVM" },
3929
- { id:9, title: "Rhoda Hand" },
3930
- { id:10, title: "Alexandrea Sauer" }
4051
+ { id: 1, title: 'Miss Beulah Roob' },
4052
+ { id: 2, title: 'Trent Morissette' },
4053
+ { id: 3, title: 'Miss Ava Pouros' },
4054
+ { id: 4, title: 'Rod Pouros' },
4055
+ { id: 5, title: 'Abdul Rice' },
4056
+ { id: 6, title: 'Laurie Rutherford Sr.' },
4057
+ { id: 7, title: 'Nakia McLaughlin' },
4058
+ { id: 8, title: 'Jordon Blanda DVM' },
4059
+ { id: 9, title: 'Rhoda Hand' },
4060
+ { id: 10, title: 'Alexandrea Sauer' }
3931
4061
  ];
3932
4062
  }])
3933
4063
  .controller('HomeController', [function() {
3934
4064
  //empty
3935
4065
  }])
3936
- .controller('ProfileController', ['$rootScope', '$routeParams', function($rootScope, $routeParams) {
4066
+ .controller('ProfileController', ['$rootScope', '$routeParams',
4067
+ function ProfileController($rootScope, $routeParams) {
3937
4068
  var index = parseInt($routeParams.id, 10);
3938
4069
  var record = $rootScope.records[index - 1];
3939
4070
 
@@ -3945,7 +4076,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3945
4076
  <h2>Welcome to the home page</h1>
3946
4077
  <p>Please click on an element</p>
3947
4078
  <a class="record"
3948
- ng-href="#/profile/{{ record.id }}"
4079
+ ng-href="#!/profile/{{ record.id }}"
3949
4080
  ng-animate-ref="{{ record.id }}"
3950
4081
  ng-repeat="record in records">
3951
4082
  {{ record.title }}
@@ -4021,7 +4152,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
4021
4152
  *
4022
4153
  * ## Using $animate in your directive code
4023
4154
  *
4024
- * So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application?
4155
+ * So far we've explored how to feed in animations into an AngularJS application, but how do we trigger animations within our own directives in our application?
4025
4156
  * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's
4026
4157
  * imagine we have a greeting box that shows and hides itself when the data changes
4027
4158
  *
@@ -4064,7 +4195,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
4064
4195
  * });
4065
4196
  * ```
4066
4197
  *
4067
- * (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case
4198
+ * (Note that earlier versions of AngularJS prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case
4068
4199
  * anymore.)
4069
4200
  *
4070
4201
  * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering
@@ -4079,7 +4210,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
4079
4210
  * }])
4080
4211
  * ```
4081
4212
  *
4082
- * (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.)
4213
+ * (Note that you will need to trigger a digest within the callback to get AngularJS to notice any scope-related changes.)
4083
4214
  */
4084
4215
 
4085
4216
  var copy;
@@ -4106,7 +4237,7 @@ var noop;
4106
4237
  * Click here {@link ng.$animate to learn more about animations with `$animate`}.
4107
4238
  */
4108
4239
  angular.module('ngAnimate', [], function initAngularHelpers() {
4109
- // Access helpers from angular core.
4240
+ // Access helpers from AngularJS core.
4110
4241
  // Do it inside a `config` block to ensure `window.angular` is available.
4111
4242
  noop = angular.noop;
4112
4243
  copy = angular.copy;
@@ -4121,12 +4252,14 @@ angular.module('ngAnimate', [], function initAngularHelpers() {
4121
4252
  isFunction = angular.isFunction;
4122
4253
  isElement = angular.isElement;
4123
4254
  })
4255
+ .info({ angularVersion: '1.8.0' })
4124
4256
  .directive('ngAnimateSwap', ngAnimateSwapDirective)
4125
4257
 
4126
4258
  .directive('ngAnimateChildren', $$AnimateChildrenDirective)
4127
4259
  .factory('$$rAFScheduler', $$rAFSchedulerFactory)
4128
4260
 
4129
4261
  .provider('$$animateQueue', $$AnimateQueueProvider)
4262
+ .provider('$$animateCache', $$AnimateCacheProvider)
4130
4263
  .provider('$$animation', $$AnimationProvider)
4131
4264
 
4132
4265
  .provider('$animateCss', $AnimateCssProvider)