angularjs-rails 1.6.8 → 1.8.0

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: d0346663d08de97950aad209fbb29e10a07aba4e
4
- data.tar.gz: 1df11a0d515a6f1f6b89b60086ac4c1d03d99618
3
+ metadata.gz: b29491e1b540e7e1d87b0d88f3fbb5b4c9323ad1
4
+ data.tar.gz: b13e9fd5f9ac54ddf962b54cb69b14b5b2c5b0ad
5
5
  SHA512:
6
- metadata.gz: cc80cc06c5356f0d6db204b91bc19aed73200f352270bf28dbc709ee01d3a73dfe279fe2dcc7d9bb7c8d610e41d004ca5ae7bb0f06594d310b7a72b32ab04f27
7
- data.tar.gz: dc410a57c0a4c62b9921f4a44370d72368052799acf1783a3fc4ef3cd4e1134c76607a42de00fca3fcc3ab947b9d3a24491003f618362b1e62f0e1dc35ff6aba
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.
@@ -1,6 +1,6 @@
1
1
  module AngularJS
2
2
  module Rails
3
- VERSION = "1.6.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.6.8
3
- * (c) 2010-2017 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';
@@ -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
 
@@ -532,7 +534,7 @@ var ANIMATE_TIMER_KEY = '$$animateCss';
532
534
  * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that
533
535
  * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,
534
536
  * any automatic control over cancelling animations and/or preventing animations from being run on
535
- * 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
536
538
  * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger
537
539
  * the CSS animation.
538
540
  *
@@ -814,33 +816,6 @@ function getCssTransitionDurationStyle(duration, applyOnlyDuration) {
814
816
  return [style, value];
815
817
  }
816
818
 
817
- function createLocalCacheLookup() {
818
- var cache = Object.create(null);
819
- return {
820
- flush: function() {
821
- cache = Object.create(null);
822
- },
823
-
824
- count: function(key) {
825
- var entry = cache[key];
826
- return entry ? entry.total : 0;
827
- },
828
-
829
- get: function(key) {
830
- var entry = cache[key];
831
- return entry && entry.value;
832
- },
833
-
834
- put: function(key, value) {
835
- if (!cache[key]) {
836
- cache[key] = { total: 1, value: value };
837
- } else {
838
- cache[key].total++;
839
- }
840
- }
841
- };
842
- }
843
-
844
819
  // we do not reassign an already present style value since
845
820
  // if we detect the style property value again we may be
846
821
  // detecting styles that were added via the `from` styles.
@@ -859,26 +834,16 @@ function registerRestorableStyles(backup, node, properties) {
859
834
  }
860
835
 
861
836
  var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animateProvider) {
862
- var gcsLookup = createLocalCacheLookup();
863
- var gcsStaggerLookup = createLocalCacheLookup();
864
837
 
865
- this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout',
838
+ this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$animateCache',
866
839
  '$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue',
867
- function($window, $$jqLite, $$AnimateRunner, $timeout,
840
+ function($window, $$jqLite, $$AnimateRunner, $timeout, $$animateCache,
868
841
  $$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {
869
842
 
870
843
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
871
844
 
872
- var parentCounter = 0;
873
- function gcsHashFn(node, extraClasses) {
874
- var KEY = '$$ngAnimateParentKey';
875
- var parentNode = node.parentNode;
876
- var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);
877
- return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;
878
- }
879
-
880
- function computeCachedCssStyles(node, className, cacheKey, properties) {
881
- var timings = gcsLookup.get(cacheKey);
845
+ function computeCachedCssStyles(node, className, cacheKey, allowNoDuration, properties) {
846
+ var timings = $$animateCache.get(cacheKey);
882
847
 
883
848
  if (!timings) {
884
849
  timings = computeCssStyles($window, node, properties);
@@ -887,20 +852,26 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
887
852
  }
888
853
  }
889
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
+
890
859
  // we keep putting this in multiple times even though the value and the cacheKey are the same
891
860
  // because we're keeping an internal tally of how many duplicate animations are detected.
892
- gcsLookup.put(cacheKey, timings);
861
+ $$animateCache.put(cacheKey, timings, hasDuration);
862
+
893
863
  return timings;
894
864
  }
895
865
 
896
866
  function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {
897
867
  var stagger;
868
+ var staggerCacheKey = 'stagger-' + cacheKey;
898
869
 
899
870
  // if we have one or more existing matches of matching elements
900
871
  // containing the same parent + CSS styles (which is how cacheKey works)
901
872
  // then staggering is possible
902
- if (gcsLookup.count(cacheKey) > 0) {
903
- stagger = gcsStaggerLookup.get(cacheKey);
873
+ if ($$animateCache.count(cacheKey) > 0) {
874
+ stagger = $$animateCache.get(staggerCacheKey);
904
875
 
905
876
  if (!stagger) {
906
877
  var staggerClassName = pendClasses(className, '-stagger');
@@ -915,7 +886,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
915
886
 
916
887
  $$jqLite.removeClass(node, staggerClassName);
917
888
 
918
- gcsStaggerLookup.put(cacheKey, stagger);
889
+ $$animateCache.put(staggerCacheKey, stagger, true);
919
890
  }
920
891
  }
921
892
 
@@ -926,8 +897,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
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', /** @this */ function($animatePro
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', /** @this */ function($animatePro
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', /** @this */ function($animatePro
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', /** @this */ function($animatePro
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', /** @this */ function($animatePro
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', /** @this */ function($animatePro
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;
@@ -1140,6 +1113,8 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
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
1120
  if (typeof options.delay !== 'boolean') {
@@ -1183,7 +1158,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
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
@@ -1227,13 +1202,16 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
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.
@@ -1284,7 +1262,7 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
1284
1262
 
1285
1263
  function applyBlocking(duration) {
1286
1264
  if (flags.blockTransition) {
1287
- blockTransitions(node, duration);
1265
+ helpers.blockTransitions(node, duration);
1288
1266
  }
1289
1267
 
1290
1268
  if (flags.blockKeyframeAnimation) {
@@ -1414,9 +1392,9 @@ var $AnimateCssProvider = ['$animateProvider', /** @this */ function($animatePro
1414
1392
 
1415
1393
  if (flags.recalculateTimingStyles) {
1416
1394
  fullClassName = node.getAttribute('class') + ' ' + preparationClasses;
1417
- cacheKey = gcsHashFn(node, fullClassName);
1395
+ cacheKey = $$animateCache.cacheKey(node, method, options.addClass, options.removeClass);
1418
1396
 
1419
- timings = computeTimings(node, fullClassName, cacheKey);
1397
+ timings = computeTimings(node, fullClassName, cacheKey, false);
1420
1398
  relativeDelay = timings.maxDelay;
1421
1399
  maxDelay = Math.max(relativeDelay, 0);
1422
1400
  maxDuration = timings.maxDuration;
@@ -2153,6 +2131,15 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2153
2131
  join: []
2154
2132
  };
2155
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
+
2156
2143
  function makeTruthyCssClassMap(classString) {
2157
2144
  if (!classString) {
2158
2145
  return null;
@@ -2251,6 +2238,10 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2251
2238
  var disabledElementsLookup = new $$Map();
2252
2239
  var animationsEnabled = null;
2253
2240
 
2241
+ function removeFromDisabledElementsLookup(evt) {
2242
+ disabledElementsLookup.delete(evt.target);
2243
+ }
2244
+
2254
2245
  function postDigestTaskFactory() {
2255
2246
  var postDigestCalled = false;
2256
2247
  return function(fn) {
@@ -2434,6 +2425,11 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2434
2425
  bool = !disabledElementsLookup.get(node);
2435
2426
  } else {
2436
2427
  // (element, bool) - Element setter
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
+ }
2437
2433
  disabledElementsLookup.set(node, !bool);
2438
2434
  }
2439
2435
  }
@@ -2519,9 +2515,9 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2519
2515
 
2520
2516
  if (skipAnimations) {
2521
2517
  // Callbacks should fire even if the document is hidden (regression fix for issue #14120)
2522
- if (documentHidden) notifyProgress(runner, event, 'start');
2518
+ if (documentHidden) notifyProgress(runner, event, 'start', getEventData(options));
2523
2519
  close();
2524
- if (documentHidden) notifyProgress(runner, event, 'close');
2520
+ if (documentHidden) notifyProgress(runner, event, 'close', getEventData(options));
2525
2521
  return runner;
2526
2522
  }
2527
2523
 
@@ -2578,7 +2574,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2578
2574
  if (existingAnimation.state === RUNNING_STATE) {
2579
2575
  normalizeAnimationDetails(element, newAnimation);
2580
2576
  } else {
2581
- applyGeneratedPreparationClasses(element, isStructural ? event : null, options);
2577
+ applyGeneratedPreparationClasses($$jqLite, element, isStructural ? event : null, options);
2582
2578
 
2583
2579
  event = newAnimation.event = existingAnimation.event;
2584
2580
  options = mergeAnimationDetails(element, existingAnimation, newAnimation);
@@ -2683,7 +2679,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2683
2679
  // this will update the runner's flow-control events based on
2684
2680
  // the `realRunner` object.
2685
2681
  runner.setHost(realRunner);
2686
- notifyProgress(runner, event, 'start', {});
2682
+ notifyProgress(runner, event, 'start', getEventData(options));
2687
2683
 
2688
2684
  realRunner.done(function(status) {
2689
2685
  close(!status);
@@ -2691,7 +2687,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2691
2687
  if (animationDetails && animationDetails.counter === counter) {
2692
2688
  clearElementAnimationState(node);
2693
2689
  }
2694
- notifyProgress(runner, event, 'close', {});
2690
+ notifyProgress(runner, event, 'close', getEventData(options));
2695
2691
  });
2696
2692
  });
2697
2693
 
@@ -2774,7 +2770,7 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2774
2770
 
2775
2771
  while (parentNode) {
2776
2772
  if (!rootNodeDetected) {
2777
- // angular doesn't want to attempt to animate elements outside of the application
2773
+ // AngularJS doesn't want to attempt to animate elements outside of the application
2778
2774
  // therefore we need to ensure that the rootElement is an ancestor of the current element
2779
2775
  rootNodeDetected = (parentNode === rootNode);
2780
2776
  }
@@ -2857,6 +2853,62 @@ var $$AnimateQueueProvider = ['$animateProvider', /** @this */ function($animate
2857
2853
  }];
2858
2854
  }];
2859
2855
 
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
+
2860
2912
  /* exported $$AnimationProvider */
2861
2913
 
2862
2914
  var $$AnimationProvider = ['$animateProvider', /** @this */ function($animateProvider) {
@@ -2865,6 +2917,7 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
2865
2917
  var drivers = this.drivers = [];
2866
2918
 
2867
2919
  var RUNNER_STORAGE_KEY = '$$animationRunner';
2920
+ var PREPARE_CLASSES_KEY = '$$animatePrepareClasses';
2868
2921
 
2869
2922
  function setRunner(element, runner) {
2870
2923
  element.data(RUNNER_STORAGE_KEY, runner);
@@ -2878,8 +2931,8 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
2878
2931
  return element.data(RUNNER_STORAGE_KEY);
2879
2932
  }
2880
2933
 
2881
- this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler',
2882
- function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$Map, $$rAFScheduler) {
2934
+ this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$Map', '$$rAFScheduler', '$$animateCache',
2935
+ function($$jqLite, $rootScope, $injector, $$AnimateRunner, $$Map, $$rAFScheduler, $$animateCache) {
2883
2936
 
2884
2937
  var animationQueue = [];
2885
2938
  var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);
@@ -2894,6 +2947,7 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
2894
2947
  var animation = animations[i];
2895
2948
  lookup.set(animation.domNode, animations[i] = {
2896
2949
  domNode: animation.domNode,
2950
+ element: animation.element,
2897
2951
  fn: animation.fn,
2898
2952
  children: []
2899
2953
  });
@@ -2950,7 +3004,7 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
2950
3004
  result.push(row);
2951
3005
  row = [];
2952
3006
  }
2953
- row.push(entry.fn);
3007
+ row.push(entry);
2954
3008
  entry.children.forEach(function(childEntry) {
2955
3009
  nextLevelEntries++;
2956
3010
  queue.push(childEntry);
@@ -2985,8 +3039,6 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
2985
3039
  return runner;
2986
3040
  }
2987
3041
 
2988
- setRunner(element, runner);
2989
-
2990
3042
  var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));
2991
3043
  var tempClasses = options.tempClasses;
2992
3044
  if (tempClasses) {
@@ -2994,12 +3046,12 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
2994
3046
  options.tempClasses = null;
2995
3047
  }
2996
3048
 
2997
- var prepareClassName;
2998
3049
  if (isStructural) {
2999
- prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX;
3000
- $$jqLite.addClass(element, prepareClassName);
3050
+ element.data(PREPARE_CLASSES_KEY, 'ng-' + event + PREPARE_CLASS_SUFFIX);
3001
3051
  }
3002
3052
 
3053
+ setRunner(element, runner);
3054
+
3003
3055
  animationQueue.push({
3004
3056
  // this data is used by the postDigest code and passed into
3005
3057
  // the driver step function
@@ -3039,16 +3091,31 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
3039
3091
  var toBeSortedAnimations = [];
3040
3092
 
3041
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
+
3042
3100
  toBeSortedAnimations.push({
3043
- domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),
3101
+ element: element,
3102
+ domNode: getDomNode(element),
3044
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
+
3045
3114
  // it's important that we apply the `ng-animate` CSS class and the
3046
3115
  // temporary classes before we do any driver invoking since these
3047
3116
  // CSS classes may be required for proper CSS detection.
3048
3117
  animationEntry.beforeStart();
3049
3118
 
3050
- var startAnimationFn, closeFn = animationEntry.close;
3051
-
3052
3119
  // in the event that the element was removed before the digest runs or
3053
3120
  // during the RAF sequencing then we should not trigger the animation.
3054
3121
  var targetElement = animationEntry.anchors
@@ -3078,7 +3145,32 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
3078
3145
  // we need to sort each of the animations in order of parent to child
3079
3146
  // relationships. This ensures that the child classes are applied at the
3080
3147
  // right time.
3081
- $$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);
3082
3174
  });
3083
3175
 
3084
3176
  return runner;
@@ -3216,10 +3308,10 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
3216
3308
  }
3217
3309
 
3218
3310
  function beforeStart() {
3219
- element.addClass(NG_ANIMATE_CLASSNAME);
3220
- if (tempClasses) {
3221
- $$jqLite.addClass(element, tempClasses);
3222
- }
3311
+ tempClasses = (tempClasses ? (tempClasses + ' ') : '') + NG_ANIMATE_CLASSNAME;
3312
+ $$jqLite.addClass(element, tempClasses);
3313
+
3314
+ var prepareClassName = element.data(PREPARE_CLASSES_KEY);
3223
3315
  if (prepareClassName) {
3224
3316
  $$jqLite.removeClass(element, prepareClassName);
3225
3317
  prepareClassName = null;
@@ -3259,7 +3351,6 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
3259
3351
  $$jqLite.removeClass(element, tempClasses);
3260
3352
  }
3261
3353
 
3262
- element.removeClass(NG_ANIMATE_CLASSNAME);
3263
3354
  runner.complete(!rejected);
3264
3355
  }
3265
3356
  };
@@ -3353,12 +3444,13 @@ var $$AnimationProvider = ['$animateProvider', /** @this */ function($animatePro
3353
3444
  * </file>
3354
3445
  * </example>
3355
3446
  */
3356
- var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $rootScope) {
3447
+ var ngAnimateSwapDirective = ['$animate', function($animate) {
3357
3448
  return {
3358
3449
  restrict: 'A',
3359
3450
  transclude: 'element',
3360
3451
  terminal: true,
3361
- 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).
3362
3454
  link: function(scope, $element, attrs, ctrl, $transclude) {
3363
3455
  var previousElement, previousScope;
3364
3456
  scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function(value) {
@@ -3370,10 +3462,10 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3370
3462
  previousScope = null;
3371
3463
  }
3372
3464
  if (value || value === 0) {
3373
- previousScope = scope.$new();
3374
- $transclude(previousScope, function(element) {
3375
- previousElement = element;
3376
- $animate.enter(element, null, $element);
3465
+ $transclude(function(clone, childScope) {
3466
+ previousElement = clone;
3467
+ previousScope = childScope;
3468
+ $animate.enter(clone, null, $element);
3377
3469
  });
3378
3470
  }
3379
3471
  });
@@ -3387,7 +3479,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3387
3479
  * @description
3388
3480
  *
3389
3481
  * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via
3390
- * 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.
3391
3483
  *
3392
3484
  * ## Usage
3393
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
@@ -3398,25 +3490,33 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3398
3490
  * ## Directive Support
3399
3491
  * The following directives are "animation aware":
3400
3492
  *
3401
- * | Directive | Supported Animations |
3402
- * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
3403
- * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |
3404
- * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
3405
- * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
3406
- * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
3407
- * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
3408
- * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) |
3409
- * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) |
3410
- * | {@link ng.directive:form#animations form} & {@link ng.directive:ngModel#animations ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
3411
- * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) |
3412
- * | {@link module:ngMessages#animations ngMessage} | enter and leave |
3413
- *
3414
- * (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}.
3415
3515
  *
3416
3516
  * ## CSS-based Animations
3417
3517
  *
3418
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
3419
- * and CSS code we can create an animation that will be picked up by Angular when an 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.
3420
3520
  *
3421
3521
  * The example below shows how an `enter` animation can be made possible on an element using `ng-if`:
3422
3522
  *
@@ -3648,9 +3748,22 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3648
3748
  * .message.ng-enter-prepare {
3649
3749
  * opacity: 0;
3650
3750
  * }
3651
- *
3652
3751
  * ```
3653
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
+ *
3654
3767
  * ## JavaScript-based Animations
3655
3768
  *
3656
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
@@ -3675,7 +3788,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3675
3788
  * enter: function(element, doneFn) {
3676
3789
  * jQuery(element).fadeIn(1000, doneFn);
3677
3790
  *
3678
- * // remember to call doneFn so that angular
3791
+ * // remember to call doneFn so that AngularJS
3679
3792
  * // knows that the animation has concluded
3680
3793
  * },
3681
3794
  *
@@ -3723,7 +3836,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
3723
3836
  *
3724
3837
  * ## CSS + JS Animations Together
3725
3838
  *
3726
- * 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,
3727
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
3728
3841
  * charge of the animation**:
3729
3842
  *
@@ -4039,7 +4152,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
4039
4152
  *
4040
4153
  * ## Using $animate in your directive code
4041
4154
  *
4042
- * 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?
4043
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
4044
4157
  * imagine we have a greeting box that shows and hides itself when the data changes
4045
4158
  *
@@ -4082,7 +4195,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
4082
4195
  * });
4083
4196
  * ```
4084
4197
  *
4085
- * (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
4086
4199
  * anymore.)
4087
4200
  *
4088
4201
  * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering
@@ -4097,7 +4210,7 @@ var ngAnimateSwapDirective = ['$animate', '$rootScope', function($animate, $root
4097
4210
  * }])
4098
4211
  * ```
4099
4212
  *
4100
- * (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.)
4101
4214
  */
4102
4215
 
4103
4216
  var copy;
@@ -4124,7 +4237,7 @@ var noop;
4124
4237
  * Click here {@link ng.$animate to learn more about animations with `$animate`}.
4125
4238
  */
4126
4239
  angular.module('ngAnimate', [], function initAngularHelpers() {
4127
- // Access helpers from angular core.
4240
+ // Access helpers from AngularJS core.
4128
4241
  // Do it inside a `config` block to ensure `window.angular` is available.
4129
4242
  noop = angular.noop;
4130
4243
  copy = angular.copy;
@@ -4139,13 +4252,14 @@ angular.module('ngAnimate', [], function initAngularHelpers() {
4139
4252
  isFunction = angular.isFunction;
4140
4253
  isElement = angular.isElement;
4141
4254
  })
4142
- .info({ angularVersion: '1.6.8' })
4255
+ .info({ angularVersion: '1.8.0' })
4143
4256
  .directive('ngAnimateSwap', ngAnimateSwapDirective)
4144
4257
 
4145
4258
  .directive('ngAnimateChildren', $$AnimateChildrenDirective)
4146
4259
  .factory('$$rAFScheduler', $$rAFSchedulerFactory)
4147
4260
 
4148
4261
  .provider('$$animateQueue', $$AnimateQueueProvider)
4262
+ .provider('$$animateCache', $$AnimateCacheProvider)
4149
4263
  .provider('$$animation', $$AnimationProvider)
4150
4264
 
4151
4265
  .provider('$animateCss', $AnimateCssProvider)