angularjs-rails 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd54c3a101761dbfafa3b97c77da203426125d33
4
- data.tar.gz: f537ae1f3de7b40608e74a9f07f12e1e3b0a033f
3
+ metadata.gz: 7464ee812eb37b7b320da7b9f1bbcfd9a39c31d0
4
+ data.tar.gz: 1ac57e83a6f1cbc43110e0c868b00246508c6c04
5
5
  SHA512:
6
- metadata.gz: e8a33c5c70a2f02d0dcc0d0f7f0585c2a3353a672e448e77f2500302b17f098b7dc7e2d20ed9331f0ae0d1e53add84a73eac0a73881001af1de99eedb1d6b1d1
7
- data.tar.gz: e2da37ab0aae7bacfc91484e7e6fc7ed603ea647d1f041f4dd9b6fe1b66d47d037dca3042ef59adbb9755693e8645548bd8e98313c69a1cfab49dcf3a02702b6
6
+ metadata.gz: 9eba877ece40de60cae7aba754d76cc8764e7d2465c2f1445dab8ddbf3ac61bcf01ff8e4c612346fe5188b383ef08472cf642648de665f39a8db0ba55d5af2e7
7
+ data.tar.gz: 2c41860d1aae295a2a6fabcd301930271d1b3462102cbc15c5acb652e382c374300d4a5054c34c2d9cd2e9e075169755b8b4ad5b32c3eba669080b4d9f550f14
data/README.md CHANGED
@@ -31,3 +31,7 @@ And similarly, for optional Angular assets:
31
31
  Every attempt is made to mirror the currently shipping Angular.js version number wherever possible.
32
32
 
33
33
  The major, minor, and patch version numbers will always represent the Angular.js version.
34
+
35
+ ## IMPORTANT: Requesting upgrades for new Angular.js versions
36
+
37
+ 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.
@@ -1,6 +1,6 @@
1
1
  module AngularJS
2
2
  module Rails
3
- VERSION = "1.2.3"
3
+ VERSION = "1.2.4"
4
4
  UNSTABLE_VERSION = "1.1.5"
5
5
  end
6
6
  end
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -196,7 +196,7 @@
196
196
  *
197
197
  * <pre>
198
198
  * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
199
- * var ngModule = angular.module('YourApp', []);
199
+ * var ngModule = angular.module('YourApp', ['ngAnimate']);
200
200
  * ngModule.animation('.my-crazy-animation', function() {
201
201
  * return {
202
202
  * enter: function(element, done) {
@@ -205,8 +205,8 @@
205
205
  * //this (optional) function will be called when the animation
206
206
  * //completes or when the animation is cancelled (the cancelled
207
207
  * //flag will be set to true if cancelled).
208
- * }
209
- * }
208
+ * };
209
+ * },
210
210
  * leave: function(element, done) { },
211
211
  * move: function(element, done) { },
212
212
  *
@@ -221,7 +221,7 @@
221
221
  *
222
222
  * //animation that can be triggered after the class is removed
223
223
  * removeClass: function(element, className, done) { }
224
- * }
224
+ * };
225
225
  * });
226
226
  * </pre>
227
227
  *
@@ -264,6 +264,19 @@ angular.module('ngAnimate', ['ng'])
264
264
  var NG_ANIMATE_CLASS_NAME = 'ng-animate';
265
265
  var rootAnimateState = {running: true};
266
266
 
267
+ function extractElementNode(element) {
268
+ for(var i = 0; i < element.length; i++) {
269
+ var elm = element[i];
270
+ if(elm.nodeType == ELEMENT_NODE) {
271
+ return elm;
272
+ }
273
+ }
274
+ }
275
+
276
+ function isMatchingElement(elm1, elm2) {
277
+ return extractElementNode(elm1) == extractElementNode(elm2);
278
+ }
279
+
267
280
  $provide.decorator('$animate', ['$delegate', '$injector', '$sniffer', '$rootElement', '$timeout', '$rootScope', '$document',
268
281
  function($delegate, $injector, $sniffer, $rootElement, $timeout, $rootScope, $document) {
269
282
 
@@ -376,7 +389,7 @@ angular.module('ngAnimate', ['ng'])
376
389
  * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
377
390
  * the animation is started, the following CSS classes will be added for the duration of the animation:
378
391
  *
379
- * Below is a breakdown of each step that occurs during enter animation:
392
+ * Below is a breakdown of each step that occurs during leave animation:
380
393
  *
381
394
  * | Animation Step | What the element class attribute looks like |
382
395
  * |----------------------------------------------------------------------------------------------|---------------------------------------------|
@@ -562,7 +575,16 @@ angular.module('ngAnimate', ['ng'])
562
575
  and the onComplete callback will be fired once the animation is fully complete.
563
576
  */
564
577
  function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, doneCallback) {
565
- var currentClassName = element.attr('class') || '';
578
+ var node = extractElementNode(element);
579
+ //transcluded directives may sometimes fire an animation using only comment nodes
580
+ //best to catch this early on to prevent any animation operations from occurring
581
+ if(!node) {
582
+ fireDOMOperation();
583
+ closeAnimation();
584
+ return;
585
+ }
586
+
587
+ var currentClassName = node.className;
566
588
  var classes = currentClassName + ' ' + className;
567
589
  var animationLookup = (' ' + classes).replace(/\s+/g,'.');
568
590
  if (!parentElement) {
@@ -766,11 +788,7 @@ angular.module('ngAnimate', ['ng'])
766
788
  }
767
789
 
768
790
  function cancelChildAnimations(element) {
769
- var node = element[0];
770
- if(node.nodeType != ELEMENT_NODE) {
771
- return;
772
- }
773
-
791
+ var node = extractElementNode(element);
774
792
  forEach(node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME), function(element) {
775
793
  element = angular.element(element);
776
794
  var data = element.data(NG_ANIMATE_STATE);
@@ -794,7 +812,7 @@ angular.module('ngAnimate', ['ng'])
794
812
  }
795
813
 
796
814
  function cleanup(element) {
797
- if(element[0] == $rootElement[0]) {
815
+ if(isMatchingElement(element, $rootElement)) {
798
816
  if(!rootAnimateState.disabled) {
799
817
  rootAnimateState.running = false;
800
818
  rootAnimateState.structural = false;
@@ -808,7 +826,7 @@ angular.module('ngAnimate', ['ng'])
808
826
  function animationsDisabled(element, parentElement) {
809
827
  if (rootAnimateState.disabled) return true;
810
828
 
811
- if(element[0] == $rootElement[0]) {
829
+ if(isMatchingElement(element, $rootElement)) {
812
830
  return rootAnimateState.disabled || rootAnimateState.running;
813
831
  }
814
832
 
@@ -818,7 +836,7 @@ angular.module('ngAnimate', ['ng'])
818
836
  //any animations on it
819
837
  if(parentElement.length === 0) break;
820
838
 
821
- var isRoot = parentElement[0] == $rootElement[0];
839
+ var isRoot = isMatchingElement(parentElement, $rootElement);
822
840
  var state = isRoot ? rootAnimateState : parentElement.data(NG_ANIMATE_STATE);
823
841
  var result = state && (!!state.disabled || !!state.running);
824
842
  if(isRoot || result) {
@@ -871,6 +889,7 @@ angular.module('ngAnimate', ['ng'])
871
889
  var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
872
890
  var NG_ANIMATE_FALLBACK_CLASS_NAME = 'ng-animate-start';
873
891
  var NG_ANIMATE_FALLBACK_ACTIVE_CLASS_NAME = 'ng-animate-active';
892
+ var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
874
893
 
875
894
  var lookupCache = {};
876
895
  var parentCounter = 0;
@@ -965,7 +984,7 @@ angular.module('ngAnimate', ['ng'])
965
984
  parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
966
985
  parentID = parentCounter;
967
986
  }
968
- return parentID + '-' + element[0].className;
987
+ return parentID + '-' + extractElementNode(element).className;
969
988
  }
970
989
 
971
990
  function animateSetup(element, className) {
@@ -1000,7 +1019,6 @@ angular.module('ngAnimate', ['ng'])
1000
1019
  return false;
1001
1020
  }
1002
1021
 
1003
- var node = element[0];
1004
1022
  //temporarily disable the transition so that the enter styles
1005
1023
  //don't animate twice (this is here to avoid a bug in Chrome/FF).
1006
1024
  var activeClassName = '';
@@ -1030,35 +1048,37 @@ angular.module('ngAnimate', ['ng'])
1030
1048
  }
1031
1049
 
1032
1050
  function blockTransitions(element) {
1033
- element[0].style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
1051
+ extractElementNode(element).style[TRANSITION_PROP + PROPERTY_KEY] = 'none';
1034
1052
  }
1035
1053
 
1036
1054
  function blockKeyframeAnimations(element) {
1037
- element[0].style[ANIMATION_PROP] = 'none 0s';
1055
+ extractElementNode(element).style[ANIMATION_PROP] = 'none 0s';
1038
1056
  }
1039
1057
 
1040
1058
  function unblockTransitions(element) {
1041
- var node = element[0], prop = TRANSITION_PROP + PROPERTY_KEY;
1059
+ var prop = TRANSITION_PROP + PROPERTY_KEY;
1060
+ var node = extractElementNode(element);
1042
1061
  if(node.style[prop] && node.style[prop].length > 0) {
1043
1062
  node.style[prop] = '';
1044
1063
  }
1045
1064
  }
1046
1065
 
1047
1066
  function unblockKeyframeAnimations(element) {
1048
- var node = element[0], prop = ANIMATION_PROP;
1067
+ var prop = ANIMATION_PROP;
1068
+ var node = extractElementNode(element);
1049
1069
  if(node.style[prop] && node.style[prop].length > 0) {
1050
- element[0].style[prop] = '';
1070
+ node.style[prop] = '';
1051
1071
  }
1052
1072
  }
1053
1073
 
1054
1074
  function animateRun(element, className, activeAnimationComplete) {
1055
1075
  var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
1056
- if(!element.hasClass(className) || !data) {
1076
+ var node = extractElementNode(element);
1077
+ if(node.className.indexOf(className) == -1 || !data) {
1057
1078
  activeAnimationComplete();
1058
1079
  return;
1059
1080
  }
1060
1081
 
1061
- var node = element[0];
1062
1082
  var timings = data.timings;
1063
1083
  var stagger = data.stagger;
1064
1084
  var maxDuration = data.maxDuration;
@@ -1101,6 +1121,9 @@ angular.module('ngAnimate', ['ng'])
1101
1121
  }
1102
1122
 
1103
1123
  if(appliedStyles.length > 0) {
1124
+ //the element being animated may sometimes contain comment nodes in
1125
+ //the jqLite object, so we're safe to use a single variable to house
1126
+ //the styles since there is always only one element being animated
1104
1127
  var oldStyle = node.getAttribute('style') || '';
1105
1128
  node.setAttribute('style', oldStyle + ' ' + style);
1106
1129
  }
@@ -1115,6 +1138,7 @@ angular.module('ngAnimate', ['ng'])
1115
1138
  element.off(css3AnimationEvents, onAnimationProgress);
1116
1139
  element.removeClass(activeClassName);
1117
1140
  animateClose(element, className);
1141
+ var node = extractElementNode(element);
1118
1142
  for (var i in appliedStyles) {
1119
1143
  node.style.removeProperty(appliedStyles[i]);
1120
1144
  }
@@ -1124,6 +1148,11 @@ angular.module('ngAnimate', ['ng'])
1124
1148
  event.stopPropagation();
1125
1149
  var ev = event.originalEvent || event;
1126
1150
  var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
1151
+
1152
+ /* Firefox (or possibly just Gecko) likes to not round values up
1153
+ * when a ms measurement is used for the animation */
1154
+ var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
1155
+
1127
1156
  /* $manualTimeStamp is a mocked timeStamp value which is set
1128
1157
  * within browserTrigger(). This is only here so that tests can
1129
1158
  * mock animations properly. Real events fallback to event.timeStamp,
@@ -1131,7 +1160,7 @@ angular.module('ngAnimate', ['ng'])
1131
1160
  * We're checking to see if the timeStamp surpasses the expected delay,
1132
1161
  * but we're using elapsedTime instead of the timeStamp on the 2nd
1133
1162
  * pre-condition since animations sometimes close off early */
1134
- if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && ev.elapsedTime >= maxDuration) {
1163
+ if(Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
1135
1164
  activeAnimationComplete();
1136
1165
  }
1137
1166
  }
@@ -1209,7 +1238,7 @@ angular.module('ngAnimate', ['ng'])
1209
1238
  }
1210
1239
 
1211
1240
  var parentElement = element.parent();
1212
- var clone = angular.element(element[0].cloneNode());
1241
+ var clone = angular.element(extractElementNode(element).cloneNode());
1213
1242
 
1214
1243
  //make the element super hidden and override any CSS style values
1215
1244
  clone.attr('style','position:absolute; top:-9999px; left:-9999px');
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -69,7 +69,7 @@ function minErr(module) {
69
69
  return match;
70
70
  });
71
71
 
72
- message = message + '\nhttp://errors.angularjs.org/1.2.3/' +
72
+ message = message + '\nhttp://errors.angularjs.org/1.2.4/' +
73
73
  (module ? module + '/' : '') + code;
74
74
  for (i = 2; i < arguments.length; i++) {
75
75
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.3
2
+ * @license AngularJS v1.2.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -365,25 +365,32 @@ function htmlParser( html, handler ) {
365
365
  }
366
366
  }
367
367
 
368
+ var hiddenPre=document.createElement("pre");
369
+ var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
368
370
  /**
369
371
  * decodes all entities into regular string
370
372
  * @param value
371
373
  * @returns {string} A string with decoded entities.
372
374
  */
373
- var hiddenPre=document.createElement("pre");
374
375
  function decodeEntities(value) {
375
- if (!value) {
376
- return '';
377
- }
376
+ if (!value) { return ''; }
377
+
378
378
  // Note: IE8 does not preserve spaces at the start/end of innerHTML
379
- var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/;
379
+ // so we must capture them and reattach them afterward
380
380
  var parts = spaceRe.exec(value);
381
- parts[0] = '';
382
- if (parts[2]) {
383
- hiddenPre.innerHTML=parts[2].replace(/</g,"&lt;");
384
- parts[2] = hiddenPre.innerText || hiddenPre.textContent;
381
+ var spaceBefore = parts[1];
382
+ var spaceAfter = parts[3];
383
+ var content = parts[2];
384
+ if (content) {
385
+ hiddenPre.innerHTML=content.replace(/</g,"&lt;");
386
+ // innerText depends on styling as it doesn't display hidden elements.
387
+ // Therefore, it's better to use textContent not to cause unnecessary
388
+ // reflows. However, IE<9 don't support textContent so the innerText
389
+ // fallback is necessary.
390
+ content = 'textContent' in hiddenPre ?
391
+ hiddenPre.textContent : hiddenPre.innerText;
385
392
  }
386
- return parts.join('');
393
+ return spaceBefore + content + spaceAfter;
387
394
  }
388
395
 
389
396
  /**
@@ -9790,7 +9790,7 @@ if ( typeof module === "object" && module && typeof module.exports === "object"
9790
9790
  })( window );
9791
9791
 
9792
9792
  /**
9793
- * @license AngularJS v1.2.3
9793
+ * @license AngularJS v1.2.4
9794
9794
  * (c) 2010-2014 Google, Inc. http://angularjs.org
9795
9795
  * License: MIT
9796
9796
  */
@@ -9860,7 +9860,7 @@ function minErr(module) {
9860
9860
  return match;
9861
9861
  });
9862
9862
 
9863
- message = message + '\nhttp://errors.angularjs.org/1.2.3/' +
9863
+ message = message + '\nhttp://errors.angularjs.org/1.2.4/' +
9864
9864
  (module ? module + '/' : '') + code;
9865
9865
  for (i = 2; i < arguments.length; i++) {
9866
9866
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -10436,9 +10436,9 @@ var trim = (function() {
10436
10436
  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
10437
10437
  */
10438
10438
  function isElement(node) {
10439
- return node &&
10439
+ return !!(node &&
10440
10440
  (node.nodeName // we are a direct element
10441
- || (node.on && node.find)); // we have an on and find method part of jQuery API
10441
+ || (node.on && node.find))); // we have an on and find method part of jQuery API
10442
10442
  }
10443
10443
 
10444
10444
  /**
@@ -10639,7 +10639,7 @@ function shallowCopy(src, dst) {
10639
10639
 
10640
10640
  for(var key in src) {
10641
10641
  // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
10642
- // so we don't need to worry hasOwnProperty here
10642
+ // so we don't need to worry about using our custom hasOwnProperty here
10643
10643
  if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
10644
10644
  dst[key] = src[key];
10645
10645
  }
@@ -11201,23 +11201,25 @@ function getter(obj, path, bindFnToScope) {
11201
11201
  }
11202
11202
 
11203
11203
  /**
11204
- * Return the siblings between `startNode` and `endNode`, inclusive
11205
- * @param {Object} object with `startNode` and `endNode` properties
11204
+ * Return the DOM siblings between the first and last node in the given array.
11205
+ * @param {Array} array like object
11206
11206
  * @returns jQlite object containing the elements
11207
11207
  */
11208
- function getBlockElements(block) {
11209
- if (block.startNode === block.endNode) {
11210
- return jqLite(block.startNode);
11208
+ function getBlockElements(nodes) {
11209
+ var startNode = nodes[0],
11210
+ endNode = nodes[nodes.length - 1];
11211
+ if (startNode === endNode) {
11212
+ return jqLite(startNode);
11211
11213
  }
11212
11214
 
11213
- var element = block.startNode;
11215
+ var element = startNode;
11214
11216
  var elements = [element];
11215
11217
 
11216
11218
  do {
11217
11219
  element = element.nextSibling;
11218
11220
  if (!element) break;
11219
11221
  elements.push(element);
11220
- } while (element !== block.endNode);
11222
+ } while (element !== endNode);
11221
11223
 
11222
11224
  return jqLite(elements);
11223
11225
  }
@@ -11618,11 +11620,11 @@ function setupModuleLoader(window) {
11618
11620
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11619
11621
  */
11620
11622
  var version = {
11621
- full: '1.2.3', // all of these placeholder strings will be replaced by grunt's
11623
+ full: '1.2.4', // all of these placeholder strings will be replaced by grunt's
11622
11624
  major: 1, // package task
11623
11625
  minor: 2,
11624
- dot: 3,
11625
- codeName: 'unicorn-zapper'
11626
+ dot: 4,
11627
+ codeName: 'wormhole-baster'
11626
11628
  };
11627
11629
 
11628
11630
 
@@ -12563,7 +12565,11 @@ forEach({
12563
12565
  },
12564
12566
 
12565
12567
  find: function(element, selector) {
12566
- return element.getElementsByTagName(selector);
12568
+ if (element.getElementsByTagName) {
12569
+ return element.getElementsByTagName(selector);
12570
+ } else {
12571
+ return [];
12572
+ }
12567
12573
  },
12568
12574
 
12569
12575
  clone: jqLiteClone,
@@ -12893,7 +12899,7 @@ function annotate(fn) {
12893
12899
  * // ...
12894
12900
  * }
12895
12901
  * // Define function dependencies
12896
- * MyController.$inject = ['$scope', '$route'];
12902
+ * MyController['$inject'] = ['$scope', '$route'];
12897
12903
  *
12898
12904
  * // Then
12899
12905
  * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
@@ -14595,7 +14601,7 @@ function $TemplateCacheProvider() {
14595
14601
  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
14596
14602
  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
14597
14603
  * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
14598
- * * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the
14604
+ * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
14599
14605
  * `link` fn if not found.
14600
14606
  *
14601
14607
  *
@@ -15334,7 +15340,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15334
15340
  createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
15335
15341
  );
15336
15342
  } else {
15337
- nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
15343
+ nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
15338
15344
  }
15339
15345
  } else if (childLinkFn) {
15340
15346
  childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
@@ -15841,13 +15847,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15841
15847
  // we are out of sync and need to copy
15842
15848
  if (parentValue !== lastValue) {
15843
15849
  // parent changed and it has precedence
15844
- lastValue = isolateScope[scopeName] = parentValue;
15850
+ isolateScope[scopeName] = parentValue;
15845
15851
  } else {
15846
15852
  // if the parent can be assigned then do so
15847
- parentSet(scope, parentValue = lastValue = isolateScope[scopeName]);
15853
+ parentSet(scope, parentValue = isolateScope[scopeName]);
15848
15854
  }
15849
15855
  }
15850
- return parentValue;
15856
+ return lastValue = parentValue;
15851
15857
  });
15852
15858
  break;
15853
15859
 
@@ -17840,8 +17846,8 @@ function $InterpolateProvider() {
17840
17846
  *
17841
17847
  <pre>
17842
17848
  var $interpolate = ...; // injected
17843
- var exp = $interpolate('Hello {{name}}!');
17844
- expect(exp({name:'Angular'}).toEqual('Hello Angular!');
17849
+ var exp = $interpolate('Hello {{name | uppercase}}!');
17850
+ expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
17845
17851
  </pre>
17846
17852
  *
17847
17853
  *
@@ -19039,23 +19045,24 @@ function ensureSafeMemberName(name, fullExpression) {
19039
19045
 
19040
19046
  function ensureSafeObject(obj, fullExpression) {
19041
19047
  // nifty check if obj is Function that is fast and works across iframes and other contexts
19042
- if (obj && obj.constructor === obj) {
19043
- throw $parseMinErr('isecfn',
19044
- 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
19045
- fullExpression);
19046
- } else if (// isWindow(obj)
19047
- obj && obj.document && obj.location && obj.alert && obj.setInterval) {
19048
- throw $parseMinErr('isecwindow',
19049
- 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
19050
- fullExpression);
19051
- } else if (// isElement(obj)
19052
- obj && (obj.nodeName || (obj.on && obj.find))) {
19053
- throw $parseMinErr('isecdom',
19054
- 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
19055
- fullExpression);
19056
- } else {
19057
- return obj;
19048
+ if (obj) {
19049
+ if (obj.constructor === obj) {
19050
+ throw $parseMinErr('isecfn',
19051
+ 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
19052
+ fullExpression);
19053
+ } else if (// isWindow(obj)
19054
+ obj.document && obj.location && obj.alert && obj.setInterval) {
19055
+ throw $parseMinErr('isecwindow',
19056
+ 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
19057
+ fullExpression);
19058
+ } else if (// isElement(obj)
19059
+ obj.children && (obj.nodeName || (obj.on && obj.find))) {
19060
+ throw $parseMinErr('isecdom',
19061
+ 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
19062
+ fullExpression);
19063
+ }
19058
19064
  }
19065
+ return obj;
19059
19066
  }
19060
19067
 
19061
19068
  var OPERATORS = {
@@ -20813,6 +20820,7 @@ function qFactory(nextTick, exceptionHandler) {
20813
20820
  function $RootScopeProvider(){
20814
20821
  var TTL = 10;
20815
20822
  var $rootScopeMinErr = minErr('$rootScope');
20823
+ var lastDirtyWatch = null;
20816
20824
 
20817
20825
  this.digestTtl = function(value) {
20818
20826
  if (arguments.length) {
@@ -20914,7 +20922,7 @@ function $RootScopeProvider(){
20914
20922
  *
20915
20923
  */
20916
20924
  $new: function(isolate) {
20917
- var Child,
20925
+ var ChildScope,
20918
20926
  child;
20919
20927
 
20920
20928
  if (isolate) {
@@ -20924,11 +20932,11 @@ function $RootScopeProvider(){
20924
20932
  child.$$asyncQueue = this.$$asyncQueue;
20925
20933
  child.$$postDigestQueue = this.$$postDigestQueue;
20926
20934
  } else {
20927
- Child = function() {}; // should be anonymous; This is so that when the minifier munges
20935
+ ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
20928
20936
  // the name it does not become random set of chars. This will then show up as class
20929
20937
  // name in the debugger.
20930
- Child.prototype = this;
20931
- child = new Child();
20938
+ ChildScope.prototype = this;
20939
+ child = new ChildScope();
20932
20940
  child.$id = nextUid();
20933
20941
  }
20934
20942
  child['this'] = child;
@@ -21008,7 +21016,7 @@ function $RootScopeProvider(){
21008
21016
 
21009
21017
 
21010
21018
 
21011
- // Using a listener function
21019
+ // Using a listener function
21012
21020
  var food;
21013
21021
  scope.foodCounter = 0;
21014
21022
  expect(scope.foodCounter).toEqual(0);
@@ -21033,7 +21041,7 @@ function $RootScopeProvider(){
21033
21041
  // Update food and run digest. Now the counter will increment
21034
21042
  food = 'cheeseburger';
21035
21043
  scope.$digest();
21036
- expect(scope.foodCounter).toEqual(1);
21044
+ expect(scope.foodCounter).toEqual(1);
21037
21045
 
21038
21046
  * </pre>
21039
21047
  *
@@ -21067,6 +21075,8 @@ function $RootScopeProvider(){
21067
21075
  eq: !!objectEquality
21068
21076
  };
21069
21077
 
21078
+ lastDirtyWatch = null;
21079
+
21070
21080
  // in the case user pass string, we need to compile it, do we really need this ?
21071
21081
  if (!isFunction(listener)) {
21072
21082
  var listenFn = compileToFn(listener || noop, 'listener');
@@ -21295,6 +21305,8 @@ function $RootScopeProvider(){
21295
21305
 
21296
21306
  beginPhase('$digest');
21297
21307
 
21308
+ lastDirtyWatch = null;
21309
+
21298
21310
  do { // "while dirty" loop
21299
21311
  dirty = false;
21300
21312
  current = target;
@@ -21304,10 +21316,13 @@ function $RootScopeProvider(){
21304
21316
  asyncTask = asyncQueue.shift();
21305
21317
  asyncTask.scope.$eval(asyncTask.expression);
21306
21318
  } catch (e) {
21319
+ clearPhase();
21307
21320
  $exceptionHandler(e);
21308
21321
  }
21322
+ lastDirtyWatch = null;
21309
21323
  }
21310
21324
 
21325
+ traverseScopesLoop:
21311
21326
  do { // "traverse the scopes" loop
21312
21327
  if ((watchers = current.$$watchers)) {
21313
21328
  // process our watches
@@ -21317,25 +21332,34 @@ function $RootScopeProvider(){
21317
21332
  watch = watchers[length];
21318
21333
  // Most common watches are on primitives, in which case we can short
21319
21334
  // circuit it with === operator, only when === fails do we use .equals
21320
- if (watch && (value = watch.get(current)) !== (last = watch.last) &&
21321
- !(watch.eq
21322
- ? equals(value, last)
21323
- : (typeof value == 'number' && typeof last == 'number'
21324
- && isNaN(value) && isNaN(last)))) {
21325
- dirty = true;
21326
- watch.last = watch.eq ? copy(value) : value;
21327
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
21328
- if (ttl < 5) {
21329
- logIdx = 4 - ttl;
21330
- if (!watchLog[logIdx]) watchLog[logIdx] = [];
21331
- logMsg = (isFunction(watch.exp))
21332
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
21333
- : watch.exp;
21334
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
21335
- watchLog[logIdx].push(logMsg);
21335
+ if (watch) {
21336
+ if ((value = watch.get(current)) !== (last = watch.last) &&
21337
+ !(watch.eq
21338
+ ? equals(value, last)
21339
+ : (typeof value == 'number' && typeof last == 'number'
21340
+ && isNaN(value) && isNaN(last)))) {
21341
+ dirty = true;
21342
+ lastDirtyWatch = watch;
21343
+ watch.last = watch.eq ? copy(value) : value;
21344
+ watch.fn(value, ((last === initWatchVal) ? value : last), current);
21345
+ if (ttl < 5) {
21346
+ logIdx = 4 - ttl;
21347
+ if (!watchLog[logIdx]) watchLog[logIdx] = [];
21348
+ logMsg = (isFunction(watch.exp))
21349
+ ? 'fn: ' + (watch.exp.name || watch.exp.toString())
21350
+ : watch.exp;
21351
+ logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
21352
+ watchLog[logIdx].push(logMsg);
21353
+ }
21354
+ } else if (watch === lastDirtyWatch) {
21355
+ // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
21356
+ // have already been tested.
21357
+ dirty = false;
21358
+ break traverseScopesLoop;
21336
21359
  }
21337
21360
  }
21338
21361
  } catch (e) {
21362
+ clearPhase();
21339
21363
  $exceptionHandler(e);
21340
21364
  }
21341
21365
  }
@@ -21344,13 +21368,16 @@ function $RootScopeProvider(){
21344
21368
  // Insanity Warning: scope depth-first traversal
21345
21369
  // yes, this code is a bit crazy, but it works and we have tests to prove it!
21346
21370
  // this piece should be kept in sync with the traversal in $broadcast
21347
- if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
21371
+ if (!(next = (current.$$childHead ||
21372
+ (current !== target && current.$$nextSibling)))) {
21348
21373
  while(current !== target && !(next = current.$$nextSibling)) {
21349
21374
  current = current.$parent;
21350
21375
  }
21351
21376
  }
21352
21377
  } while ((current = next));
21353
21378
 
21379
+ // `break traverseScopesLoop;` takes us to here
21380
+
21354
21381
  if(dirty && !(ttl--)) {
21355
21382
  clearPhase();
21356
21383
  throw $rootScopeMinErr('infdig',
@@ -21358,6 +21385,7 @@ function $RootScopeProvider(){
21358
21385
  'Watchers fired in the last 5 iterations: {1}',
21359
21386
  TTL, toJson(watchLog));
21360
21387
  }
21388
+
21361
21389
  } while (dirty || asyncQueue.length);
21362
21390
 
21363
21391
  clearPhase();
@@ -21410,11 +21438,12 @@ function $RootScopeProvider(){
21410
21438
  */
21411
21439
  $destroy: function() {
21412
21440
  // we can't destroy the root scope or a scope that has been already destroyed
21413
- if ($rootScope == this || this.$$destroyed) return;
21441
+ if (this.$$destroyed) return;
21414
21442
  var parent = this.$parent;
21415
21443
 
21416
21444
  this.$broadcast('$destroy');
21417
21445
  this.$$destroyed = true;
21446
+ if (this === $rootScope) return;
21418
21447
 
21419
21448
  if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
21420
21449
  if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
@@ -21452,7 +21481,7 @@ function $RootScopeProvider(){
21452
21481
  *
21453
21482
  * - `string`: execute using the rules as defined in {@link guide/expression expression}.
21454
21483
  * - `function(scope)`: execute the function with the current `scope` parameter.
21455
- *
21484
+ *
21456
21485
  * @param {(object)=} locals Local variables object, useful for overriding values in scope.
21457
21486
  * @returns {*} The result of evaluating the expression.
21458
21487
  */
@@ -23320,13 +23349,15 @@ function urlIsSameOrigin(requestUrl) {
23320
23349
  <doc:source>
23321
23350
  <script>
23322
23351
  function Ctrl($scope, $window) {
23323
- $scope.$window = $window;
23324
23352
  $scope.greeting = 'Hello, World!';
23353
+ $scope.doGreeting = function(greeting) {
23354
+ $window.alert(greeting);
23355
+ };
23325
23356
  }
23326
23357
  </script>
23327
23358
  <div ng-controller="Ctrl">
23328
23359
  <input type="text" ng-model="greeting" />
23329
- <button ng-click="$window.alert(greeting)">ALERT</button>
23360
+ <button ng-click="doGreeting(greeting)">ALERT</button>
23330
23361
  </div>
23331
23362
  </doc:source>
23332
23363
  <doc:scenario>
@@ -24833,9 +24864,22 @@ var nullFormCtrl = {
24833
24864
  * @property {Object} $error Is an object hash, containing references to all invalid controls or
24834
24865
  * forms, where:
24835
24866
  *
24836
- * - keys are validation tokens (error names) — such as `required`, `url` or `email`,
24837
- * - values are arrays of controls or forms that are invalid with given error.
24867
+ * - keys are validation tokens (error names),
24868
+ * - values are arrays of controls or forms that are invalid for given error name.
24838
24869
  *
24870
+ *
24871
+ * Built-in validation tokens:
24872
+ *
24873
+ * - `email`
24874
+ * - `max`
24875
+ * - `maxlength`
24876
+ * - `min`
24877
+ * - `minlength`
24878
+ * - `number`
24879
+ * - `pattern`
24880
+ * - `required`
24881
+ * - `url`
24882
+ *
24839
24883
  * @description
24840
24884
  * `FormController` keeps track of all its controls and nested forms as well as state of them,
24841
24885
  * such as being valid/invalid or dirty/pristine.
@@ -26129,39 +26173,6 @@ var VALID_CLASS = 'ng-valid',
26129
26173
  </file>
26130
26174
  * </example>
26131
26175
  *
26132
- * ## Isolated Scope Pitfall
26133
- *
26134
- * Note that if you have a directive with an isolated scope, you cannot require `ngModel`
26135
- * since the model value will be looked up on the isolated scope rather than the outer scope.
26136
- * When the directive updates the model value, calling `ngModel.$setViewValue()` the property
26137
- * on the outer scope will not be updated. However you can get around this by using $parent.
26138
- *
26139
- * Here is an example of this situation. You'll notice that the first div is not updating the input.
26140
- * However the second div can update the input properly.
26141
- *
26142
- * <example module="badIsolatedDirective">
26143
- <file name="script.js">
26144
- angular.module('badIsolatedDirective', []).directive('isolate', function() {
26145
- return {
26146
- require: 'ngModel',
26147
- scope: { },
26148
- template: '<input ng-model="innerModel">',
26149
- link: function(scope, element, attrs, ngModel) {
26150
- scope.$watch('innerModel', function(value) {
26151
- console.log(value);
26152
- ngModel.$setViewValue(value);
26153
- });
26154
- }
26155
- };
26156
- });
26157
- </file>
26158
- <file name="index.html">
26159
- <input ng-model="someModel"/>
26160
- <div isolate ng-model="someModel"></div>
26161
- <div isolate ng-model="$parent.someModel"></div>
26162
- </file>
26163
- * </example>
26164
- *
26165
26176
  *
26166
26177
  */
26167
26178
  var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
@@ -26308,7 +26319,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
26308
26319
  * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
26309
26320
  * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
26310
26321
  * `$modelValue` and the **expression** specified in the `ng-model` attribute.
26311
- *
26322
+ *
26312
26323
  * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
26313
26324
  *
26314
26325
  * Note that calling this function does not trigger a `$digest`.
@@ -26365,6 +26376,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
26365
26376
  ctrl.$render();
26366
26377
  }
26367
26378
  }
26379
+
26380
+ return value;
26368
26381
  });
26369
26382
  }];
26370
26383
 
@@ -27858,9 +27871,12 @@ var ngIfDirective = ['$animate', function($animate) {
27858
27871
  if (!childScope) {
27859
27872
  childScope = $scope.$new();
27860
27873
  $transclude(childScope, function (clone) {
27874
+ clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
27875
+ // Note: We only need the first/last node of the cloned nodes.
27876
+ // However, we need to keep the reference to the jqlite wrapper as it might be changed later
27877
+ // by a directive with templateUrl when it's template arrives.
27861
27878
  block = {
27862
- startNode: clone[0],
27863
- endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
27879
+ clone: clone
27864
27880
  };
27865
27881
  $animate.enter(clone, $element.parent(), $element);
27866
27882
  });
@@ -27873,7 +27889,7 @@ var ngIfDirective = ['$animate', function($animate) {
27873
27889
  }
27874
27890
 
27875
27891
  if (block) {
27876
- $animate.leave(getBlockElements(block));
27892
+ $animate.leave(getBlockElements(block.clone));
27877
27893
  block = null;
27878
27894
  }
27879
27895
  }
@@ -28116,6 +28132,8 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
28116
28132
  * to initialize values on a scope.
28117
28133
  * </div>
28118
28134
  *
28135
+ * @priority 450
28136
+ *
28119
28137
  * @element ANY
28120
28138
  * @param {expression} ngInit {@link guide/expression Expression} to eval.
28121
28139
  *
@@ -28147,6 +28165,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
28147
28165
  </doc:example>
28148
28166
  */
28149
28167
  var ngInitDirective = ngDirective({
28168
+ priority: 450,
28150
28169
  compile: function() {
28151
28170
  return {
28152
28171
  pre: function(scope, element, attrs) {
@@ -28704,7 +28723,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28704
28723
  } else if (nextBlockMap.hasOwnProperty(trackById)) {
28705
28724
  // restore lastBlockMap
28706
28725
  forEach(nextBlockOrder, function(block) {
28707
- if (block && block.startNode) lastBlockMap[block.id] = block;
28726
+ if (block && block.scope) lastBlockMap[block.id] = block;
28708
28727
  });
28709
28728
  // This is a duplicate and we need to throw an error
28710
28729
  throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
@@ -28721,7 +28740,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28721
28740
  // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
28722
28741
  if (lastBlockMap.hasOwnProperty(key)) {
28723
28742
  block = lastBlockMap[key];
28724
- elementsToRemove = getBlockElements(block);
28743
+ elementsToRemove = getBlockElements(block.clone);
28725
28744
  $animate.leave(elementsToRemove);
28726
28745
  forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
28727
28746
  block.scope.$destroy();
@@ -28733,9 +28752,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28733
28752
  key = (collection === collectionKeys) ? index : collectionKeys[index];
28734
28753
  value = collection[key];
28735
28754
  block = nextBlockOrder[index];
28736
- if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;
28755
+ if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
28737
28756
 
28738
- if (block.startNode) {
28757
+ if (block.scope) {
28739
28758
  // if we have already seen this object, then we need to reuse the
28740
28759
  // associated scope/element
28741
28760
  childScope = block.scope;
@@ -28745,11 +28764,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28745
28764
  nextNode = nextNode.nextSibling;
28746
28765
  } while(nextNode && nextNode[NG_REMOVED]);
28747
28766
 
28748
- if (block.startNode != nextNode) {
28767
+ if (getBlockStart(block) != nextNode) {
28749
28768
  // existing item which got moved
28750
- $animate.move(getBlockElements(block), null, jqLite(previousNode));
28769
+ $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
28751
28770
  }
28752
- previousNode = block.endNode;
28771
+ previousNode = getBlockEnd(block);
28753
28772
  } else {
28754
28773
  // new item which we don't know about
28755
28774
  childScope = $scope.$new();
@@ -28765,14 +28784,16 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28765
28784
  childScope.$odd = !(childScope.$even = (index&1) === 0);
28766
28785
  // jshint bitwise: true
28767
28786
 
28768
- if (!block.startNode) {
28787
+ if (!block.scope) {
28769
28788
  $transclude(childScope, function(clone) {
28770
28789
  clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
28771
28790
  $animate.enter(clone, null, jqLite(previousNode));
28772
28791
  previousNode = clone;
28773
28792
  block.scope = childScope;
28774
- block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
28775
- block.endNode = clone[clone.length - 1];
28793
+ // Note: We only need the first/last node of the cloned nodes.
28794
+ // However, we need to keep the reference to the jqlite wrapper as it might be changed later
28795
+ // by a directive with templateUrl when it's template arrives.
28796
+ block.clone = clone;
28776
28797
  nextBlockMap[block.id] = block;
28777
28798
  });
28778
28799
  }
@@ -28781,6 +28802,14 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
28781
28802
  });
28782
28803
  }
28783
28804
  };
28805
+
28806
+ function getBlockStart(block) {
28807
+ return block.clone[0];
28808
+ }
28809
+
28810
+ function getBlockEnd(block) {
28811
+ return block.clone[block.clone.length - 1];
28812
+ }
28784
28813
  }];
28785
28814
 
28786
28815
  /**