angular-gem 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  /**