angularjs-rails 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
  */
@@ -68,7 +68,7 @@ function minErr(module) {
68
68
  return match;
69
69
  });
70
70
 
71
- message = message + '\nhttp://errors.angularjs.org/1.2.3/' +
71
+ message = message + '\nhttp://errors.angularjs.org/1.2.4/' +
72
72
  (module ? module + '/' : '') + code;
73
73
  for (i = 2; i < arguments.length; i++) {
74
74
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -644,9 +644,9 @@ var trim = (function() {
644
644
  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
645
645
  */
646
646
  function isElement(node) {
647
- return node &&
647
+ return !!(node &&
648
648
  (node.nodeName // we are a direct element
649
- || (node.on && node.find)); // we have an on and find method part of jQuery API
649
+ || (node.on && node.find))); // we have an on and find method part of jQuery API
650
650
  }
651
651
 
652
652
  /**
@@ -847,7 +847,7 @@ function shallowCopy(src, dst) {
847
847
 
848
848
  for(var key in src) {
849
849
  // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src
850
- // so we don't need to worry hasOwnProperty here
850
+ // so we don't need to worry about using our custom hasOwnProperty here
851
851
  if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
852
852
  dst[key] = src[key];
853
853
  }
@@ -1409,23 +1409,25 @@ function getter(obj, path, bindFnToScope) {
1409
1409
  }
1410
1410
 
1411
1411
  /**
1412
- * Return the siblings between `startNode` and `endNode`, inclusive
1413
- * @param {Object} object with `startNode` and `endNode` properties
1412
+ * Return the DOM siblings between the first and last node in the given array.
1413
+ * @param {Array} array like object
1414
1414
  * @returns jQlite object containing the elements
1415
1415
  */
1416
- function getBlockElements(block) {
1417
- if (block.startNode === block.endNode) {
1418
- return jqLite(block.startNode);
1416
+ function getBlockElements(nodes) {
1417
+ var startNode = nodes[0],
1418
+ endNode = nodes[nodes.length - 1];
1419
+ if (startNode === endNode) {
1420
+ return jqLite(startNode);
1419
1421
  }
1420
1422
 
1421
- var element = block.startNode;
1423
+ var element = startNode;
1422
1424
  var elements = [element];
1423
1425
 
1424
1426
  do {
1425
1427
  element = element.nextSibling;
1426
1428
  if (!element) break;
1427
1429
  elements.push(element);
1428
- } while (element !== block.endNode);
1430
+ } while (element !== endNode);
1429
1431
 
1430
1432
  return jqLite(elements);
1431
1433
  }
@@ -1826,11 +1828,11 @@ function setupModuleLoader(window) {
1826
1828
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1827
1829
  */
1828
1830
  var version = {
1829
- full: '1.2.3', // all of these placeholder strings will be replaced by grunt's
1831
+ full: '1.2.4', // all of these placeholder strings will be replaced by grunt's
1830
1832
  major: 1, // package task
1831
1833
  minor: 2,
1832
- dot: 3,
1833
- codeName: 'unicorn-zapper'
1834
+ dot: 4,
1835
+ codeName: 'wormhole-baster'
1834
1836
  };
1835
1837
 
1836
1838
 
@@ -2771,7 +2773,11 @@ forEach({
2771
2773
  },
2772
2774
 
2773
2775
  find: function(element, selector) {
2774
- return element.getElementsByTagName(selector);
2776
+ if (element.getElementsByTagName) {
2777
+ return element.getElementsByTagName(selector);
2778
+ } else {
2779
+ return [];
2780
+ }
2775
2781
  },
2776
2782
 
2777
2783
  clone: jqLiteClone,
@@ -3101,7 +3107,7 @@ function annotate(fn) {
3101
3107
  * // ...
3102
3108
  * }
3103
3109
  * // Define function dependencies
3104
- * MyController.$inject = ['$scope', '$route'];
3110
+ * MyController['$inject'] = ['$scope', '$route'];
3105
3111
  *
3106
3112
  * // Then
3107
3113
  * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
@@ -4803,7 +4809,7 @@ function $TemplateCacheProvider() {
4803
4809
  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
4804
4810
  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
4805
4811
  * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
4806
- * * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the
4812
+ * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
4807
4813
  * `link` fn if not found.
4808
4814
  *
4809
4815
  *
@@ -5542,7 +5548,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5542
5548
  createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
5543
5549
  );
5544
5550
  } else {
5545
- nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
5551
+ nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
5546
5552
  }
5547
5553
  } else if (childLinkFn) {
5548
5554
  childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
@@ -6049,13 +6055,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6049
6055
  // we are out of sync and need to copy
6050
6056
  if (parentValue !== lastValue) {
6051
6057
  // parent changed and it has precedence
6052
- lastValue = isolateScope[scopeName] = parentValue;
6058
+ isolateScope[scopeName] = parentValue;
6053
6059
  } else {
6054
6060
  // if the parent can be assigned then do so
6055
- parentSet(scope, parentValue = lastValue = isolateScope[scopeName]);
6061
+ parentSet(scope, parentValue = isolateScope[scopeName]);
6056
6062
  }
6057
6063
  }
6058
- return parentValue;
6064
+ return lastValue = parentValue;
6059
6065
  });
6060
6066
  break;
6061
6067
 
@@ -8048,8 +8054,8 @@ function $InterpolateProvider() {
8048
8054
  *
8049
8055
  <pre>
8050
8056
  var $interpolate = ...; // injected
8051
- var exp = $interpolate('Hello {{name}}!');
8052
- expect(exp({name:'Angular'}).toEqual('Hello Angular!');
8057
+ var exp = $interpolate('Hello {{name | uppercase}}!');
8058
+ expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
8053
8059
  </pre>
8054
8060
  *
8055
8061
  *
@@ -9247,23 +9253,24 @@ function ensureSafeMemberName(name, fullExpression) {
9247
9253
 
9248
9254
  function ensureSafeObject(obj, fullExpression) {
9249
9255
  // nifty check if obj is Function that is fast and works across iframes and other contexts
9250
- if (obj && obj.constructor === obj) {
9251
- throw $parseMinErr('isecfn',
9252
- 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
9253
- fullExpression);
9254
- } else if (// isWindow(obj)
9255
- obj && obj.document && obj.location && obj.alert && obj.setInterval) {
9256
- throw $parseMinErr('isecwindow',
9257
- 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
9258
- fullExpression);
9259
- } else if (// isElement(obj)
9260
- obj && (obj.nodeName || (obj.on && obj.find))) {
9261
- throw $parseMinErr('isecdom',
9262
- 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
9263
- fullExpression);
9264
- } else {
9265
- return obj;
9256
+ if (obj) {
9257
+ if (obj.constructor === obj) {
9258
+ throw $parseMinErr('isecfn',
9259
+ 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
9260
+ fullExpression);
9261
+ } else if (// isWindow(obj)
9262
+ obj.document && obj.location && obj.alert && obj.setInterval) {
9263
+ throw $parseMinErr('isecwindow',
9264
+ 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
9265
+ fullExpression);
9266
+ } else if (// isElement(obj)
9267
+ obj.children && (obj.nodeName || (obj.on && obj.find))) {
9268
+ throw $parseMinErr('isecdom',
9269
+ 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
9270
+ fullExpression);
9271
+ }
9266
9272
  }
9273
+ return obj;
9267
9274
  }
9268
9275
 
9269
9276
  var OPERATORS = {
@@ -11021,6 +11028,7 @@ function qFactory(nextTick, exceptionHandler) {
11021
11028
  function $RootScopeProvider(){
11022
11029
  var TTL = 10;
11023
11030
  var $rootScopeMinErr = minErr('$rootScope');
11031
+ var lastDirtyWatch = null;
11024
11032
 
11025
11033
  this.digestTtl = function(value) {
11026
11034
  if (arguments.length) {
@@ -11122,7 +11130,7 @@ function $RootScopeProvider(){
11122
11130
  *
11123
11131
  */
11124
11132
  $new: function(isolate) {
11125
- var Child,
11133
+ var ChildScope,
11126
11134
  child;
11127
11135
 
11128
11136
  if (isolate) {
@@ -11132,11 +11140,11 @@ function $RootScopeProvider(){
11132
11140
  child.$$asyncQueue = this.$$asyncQueue;
11133
11141
  child.$$postDigestQueue = this.$$postDigestQueue;
11134
11142
  } else {
11135
- Child = function() {}; // should be anonymous; This is so that when the minifier munges
11143
+ ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
11136
11144
  // the name it does not become random set of chars. This will then show up as class
11137
11145
  // name in the debugger.
11138
- Child.prototype = this;
11139
- child = new Child();
11146
+ ChildScope.prototype = this;
11147
+ child = new ChildScope();
11140
11148
  child.$id = nextUid();
11141
11149
  }
11142
11150
  child['this'] = child;
@@ -11216,7 +11224,7 @@ function $RootScopeProvider(){
11216
11224
 
11217
11225
 
11218
11226
 
11219
- // Using a listener function
11227
+ // Using a listener function
11220
11228
  var food;
11221
11229
  scope.foodCounter = 0;
11222
11230
  expect(scope.foodCounter).toEqual(0);
@@ -11241,7 +11249,7 @@ function $RootScopeProvider(){
11241
11249
  // Update food and run digest. Now the counter will increment
11242
11250
  food = 'cheeseburger';
11243
11251
  scope.$digest();
11244
- expect(scope.foodCounter).toEqual(1);
11252
+ expect(scope.foodCounter).toEqual(1);
11245
11253
 
11246
11254
  * </pre>
11247
11255
  *
@@ -11275,6 +11283,8 @@ function $RootScopeProvider(){
11275
11283
  eq: !!objectEquality
11276
11284
  };
11277
11285
 
11286
+ lastDirtyWatch = null;
11287
+
11278
11288
  // in the case user pass string, we need to compile it, do we really need this ?
11279
11289
  if (!isFunction(listener)) {
11280
11290
  var listenFn = compileToFn(listener || noop, 'listener');
@@ -11503,6 +11513,8 @@ function $RootScopeProvider(){
11503
11513
 
11504
11514
  beginPhase('$digest');
11505
11515
 
11516
+ lastDirtyWatch = null;
11517
+
11506
11518
  do { // "while dirty" loop
11507
11519
  dirty = false;
11508
11520
  current = target;
@@ -11512,10 +11524,13 @@ function $RootScopeProvider(){
11512
11524
  asyncTask = asyncQueue.shift();
11513
11525
  asyncTask.scope.$eval(asyncTask.expression);
11514
11526
  } catch (e) {
11527
+ clearPhase();
11515
11528
  $exceptionHandler(e);
11516
11529
  }
11530
+ lastDirtyWatch = null;
11517
11531
  }
11518
11532
 
11533
+ traverseScopesLoop:
11519
11534
  do { // "traverse the scopes" loop
11520
11535
  if ((watchers = current.$$watchers)) {
11521
11536
  // process our watches
@@ -11525,25 +11540,34 @@ function $RootScopeProvider(){
11525
11540
  watch = watchers[length];
11526
11541
  // Most common watches are on primitives, in which case we can short
11527
11542
  // circuit it with === operator, only when === fails do we use .equals
11528
- if (watch && (value = watch.get(current)) !== (last = watch.last) &&
11529
- !(watch.eq
11530
- ? equals(value, last)
11531
- : (typeof value == 'number' && typeof last == 'number'
11532
- && isNaN(value) && isNaN(last)))) {
11533
- dirty = true;
11534
- watch.last = watch.eq ? copy(value) : value;
11535
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
11536
- if (ttl < 5) {
11537
- logIdx = 4 - ttl;
11538
- if (!watchLog[logIdx]) watchLog[logIdx] = [];
11539
- logMsg = (isFunction(watch.exp))
11540
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
11541
- : watch.exp;
11542
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
11543
- watchLog[logIdx].push(logMsg);
11543
+ if (watch) {
11544
+ if ((value = watch.get(current)) !== (last = watch.last) &&
11545
+ !(watch.eq
11546
+ ? equals(value, last)
11547
+ : (typeof value == 'number' && typeof last == 'number'
11548
+ && isNaN(value) && isNaN(last)))) {
11549
+ dirty = true;
11550
+ lastDirtyWatch = watch;
11551
+ watch.last = watch.eq ? copy(value) : value;
11552
+ watch.fn(value, ((last === initWatchVal) ? value : last), current);
11553
+ if (ttl < 5) {
11554
+ logIdx = 4 - ttl;
11555
+ if (!watchLog[logIdx]) watchLog[logIdx] = [];
11556
+ logMsg = (isFunction(watch.exp))
11557
+ ? 'fn: ' + (watch.exp.name || watch.exp.toString())
11558
+ : watch.exp;
11559
+ logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
11560
+ watchLog[logIdx].push(logMsg);
11561
+ }
11562
+ } else if (watch === lastDirtyWatch) {
11563
+ // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
11564
+ // have already been tested.
11565
+ dirty = false;
11566
+ break traverseScopesLoop;
11544
11567
  }
11545
11568
  }
11546
11569
  } catch (e) {
11570
+ clearPhase();
11547
11571
  $exceptionHandler(e);
11548
11572
  }
11549
11573
  }
@@ -11552,13 +11576,16 @@ function $RootScopeProvider(){
11552
11576
  // Insanity Warning: scope depth-first traversal
11553
11577
  // yes, this code is a bit crazy, but it works and we have tests to prove it!
11554
11578
  // this piece should be kept in sync with the traversal in $broadcast
11555
- if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
11579
+ if (!(next = (current.$$childHead ||
11580
+ (current !== target && current.$$nextSibling)))) {
11556
11581
  while(current !== target && !(next = current.$$nextSibling)) {
11557
11582
  current = current.$parent;
11558
11583
  }
11559
11584
  }
11560
11585
  } while ((current = next));
11561
11586
 
11587
+ // `break traverseScopesLoop;` takes us to here
11588
+
11562
11589
  if(dirty && !(ttl--)) {
11563
11590
  clearPhase();
11564
11591
  throw $rootScopeMinErr('infdig',
@@ -11566,6 +11593,7 @@ function $RootScopeProvider(){
11566
11593
  'Watchers fired in the last 5 iterations: {1}',
11567
11594
  TTL, toJson(watchLog));
11568
11595
  }
11596
+
11569
11597
  } while (dirty || asyncQueue.length);
11570
11598
 
11571
11599
  clearPhase();
@@ -11618,11 +11646,12 @@ function $RootScopeProvider(){
11618
11646
  */
11619
11647
  $destroy: function() {
11620
11648
  // we can't destroy the root scope or a scope that has been already destroyed
11621
- if ($rootScope == this || this.$$destroyed) return;
11649
+ if (this.$$destroyed) return;
11622
11650
  var parent = this.$parent;
11623
11651
 
11624
11652
  this.$broadcast('$destroy');
11625
11653
  this.$$destroyed = true;
11654
+ if (this === $rootScope) return;
11626
11655
 
11627
11656
  if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
11628
11657
  if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
@@ -11660,7 +11689,7 @@ function $RootScopeProvider(){
11660
11689
  *
11661
11690
  * - `string`: execute using the rules as defined in {@link guide/expression expression}.
11662
11691
  * - `function(scope)`: execute the function with the current `scope` parameter.
11663
- *
11692
+ *
11664
11693
  * @param {(object)=} locals Local variables object, useful for overriding values in scope.
11665
11694
  * @returns {*} The result of evaluating the expression.
11666
11695
  */
@@ -13528,13 +13557,15 @@ function urlIsSameOrigin(requestUrl) {
13528
13557
  <doc:source>
13529
13558
  <script>
13530
13559
  function Ctrl($scope, $window) {
13531
- $scope.$window = $window;
13532
13560
  $scope.greeting = 'Hello, World!';
13561
+ $scope.doGreeting = function(greeting) {
13562
+ $window.alert(greeting);
13563
+ };
13533
13564
  }
13534
13565
  </script>
13535
13566
  <div ng-controller="Ctrl">
13536
13567
  <input type="text" ng-model="greeting" />
13537
- <button ng-click="$window.alert(greeting)">ALERT</button>
13568
+ <button ng-click="doGreeting(greeting)">ALERT</button>
13538
13569
  </div>
13539
13570
  </doc:source>
13540
13571
  <doc:scenario>
@@ -15041,9 +15072,22 @@ var nullFormCtrl = {
15041
15072
  * @property {Object} $error Is an object hash, containing references to all invalid controls or
15042
15073
  * forms, where:
15043
15074
  *
15044
- * - keys are validation tokens (error names) — such as `required`, `url` or `email`,
15045
- * - values are arrays of controls or forms that are invalid with given error.
15075
+ * - keys are validation tokens (error names),
15076
+ * - values are arrays of controls or forms that are invalid for given error name.
15046
15077
  *
15078
+ *
15079
+ * Built-in validation tokens:
15080
+ *
15081
+ * - `email`
15082
+ * - `max`
15083
+ * - `maxlength`
15084
+ * - `min`
15085
+ * - `minlength`
15086
+ * - `number`
15087
+ * - `pattern`
15088
+ * - `required`
15089
+ * - `url`
15090
+ *
15047
15091
  * @description
15048
15092
  * `FormController` keeps track of all its controls and nested forms as well as state of them,
15049
15093
  * such as being valid/invalid or dirty/pristine.
@@ -16337,39 +16381,6 @@ var VALID_CLASS = 'ng-valid',
16337
16381
  </file>
16338
16382
  * </example>
16339
16383
  *
16340
- * ## Isolated Scope Pitfall
16341
- *
16342
- * Note that if you have a directive with an isolated scope, you cannot require `ngModel`
16343
- * since the model value will be looked up on the isolated scope rather than the outer scope.
16344
- * When the directive updates the model value, calling `ngModel.$setViewValue()` the property
16345
- * on the outer scope will not be updated. However you can get around this by using $parent.
16346
- *
16347
- * Here is an example of this situation. You'll notice that the first div is not updating the input.
16348
- * However the second div can update the input properly.
16349
- *
16350
- * <example module="badIsolatedDirective">
16351
- <file name="script.js">
16352
- angular.module('badIsolatedDirective', []).directive('isolate', function() {
16353
- return {
16354
- require: 'ngModel',
16355
- scope: { },
16356
- template: '<input ng-model="innerModel">',
16357
- link: function(scope, element, attrs, ngModel) {
16358
- scope.$watch('innerModel', function(value) {
16359
- console.log(value);
16360
- ngModel.$setViewValue(value);
16361
- });
16362
- }
16363
- };
16364
- });
16365
- </file>
16366
- <file name="index.html">
16367
- <input ng-model="someModel"/>
16368
- <div isolate ng-model="someModel"></div>
16369
- <div isolate ng-model="$parent.someModel"></div>
16370
- </file>
16371
- * </example>
16372
- *
16373
16384
  *
16374
16385
  */
16375
16386
  var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
@@ -16516,7 +16527,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
16516
16527
  * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
16517
16528
  * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
16518
16529
  * `$modelValue` and the **expression** specified in the `ng-model` attribute.
16519
- *
16530
+ *
16520
16531
  * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
16521
16532
  *
16522
16533
  * Note that calling this function does not trigger a `$digest`.
@@ -16573,6 +16584,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
16573
16584
  ctrl.$render();
16574
16585
  }
16575
16586
  }
16587
+
16588
+ return value;
16576
16589
  });
16577
16590
  }];
16578
16591
 
@@ -18066,9 +18079,12 @@ var ngIfDirective = ['$animate', function($animate) {
18066
18079
  if (!childScope) {
18067
18080
  childScope = $scope.$new();
18068
18081
  $transclude(childScope, function (clone) {
18082
+ clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
18083
+ // Note: We only need the first/last node of the cloned nodes.
18084
+ // However, we need to keep the reference to the jqlite wrapper as it might be changed later
18085
+ // by a directive with templateUrl when it's template arrives.
18069
18086
  block = {
18070
- startNode: clone[0],
18071
- endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
18087
+ clone: clone
18072
18088
  };
18073
18089
  $animate.enter(clone, $element.parent(), $element);
18074
18090
  });
@@ -18081,7 +18097,7 @@ var ngIfDirective = ['$animate', function($animate) {
18081
18097
  }
18082
18098
 
18083
18099
  if (block) {
18084
- $animate.leave(getBlockElements(block));
18100
+ $animate.leave(getBlockElements(block.clone));
18085
18101
  block = null;
18086
18102
  }
18087
18103
  }
@@ -18324,6 +18340,8 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
18324
18340
  * to initialize values on a scope.
18325
18341
  * </div>
18326
18342
  *
18343
+ * @priority 450
18344
+ *
18327
18345
  * @element ANY
18328
18346
  * @param {expression} ngInit {@link guide/expression Expression} to eval.
18329
18347
  *
@@ -18355,6 +18373,7 @@ var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$compile'
18355
18373
  </doc:example>
18356
18374
  */
18357
18375
  var ngInitDirective = ngDirective({
18376
+ priority: 450,
18358
18377
  compile: function() {
18359
18378
  return {
18360
18379
  pre: function(scope, element, attrs) {
@@ -18912,7 +18931,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18912
18931
  } else if (nextBlockMap.hasOwnProperty(trackById)) {
18913
18932
  // restore lastBlockMap
18914
18933
  forEach(nextBlockOrder, function(block) {
18915
- if (block && block.startNode) lastBlockMap[block.id] = block;
18934
+ if (block && block.scope) lastBlockMap[block.id] = block;
18916
18935
  });
18917
18936
  // This is a duplicate and we need to throw an error
18918
18937
  throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
@@ -18929,7 +18948,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18929
18948
  // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
18930
18949
  if (lastBlockMap.hasOwnProperty(key)) {
18931
18950
  block = lastBlockMap[key];
18932
- elementsToRemove = getBlockElements(block);
18951
+ elementsToRemove = getBlockElements(block.clone);
18933
18952
  $animate.leave(elementsToRemove);
18934
18953
  forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
18935
18954
  block.scope.$destroy();
@@ -18941,9 +18960,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18941
18960
  key = (collection === collectionKeys) ? index : collectionKeys[index];
18942
18961
  value = collection[key];
18943
18962
  block = nextBlockOrder[index];
18944
- if (nextBlockOrder[index - 1]) previousNode = nextBlockOrder[index - 1].endNode;
18963
+ if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
18945
18964
 
18946
- if (block.startNode) {
18965
+ if (block.scope) {
18947
18966
  // if we have already seen this object, then we need to reuse the
18948
18967
  // associated scope/element
18949
18968
  childScope = block.scope;
@@ -18953,11 +18972,11 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18953
18972
  nextNode = nextNode.nextSibling;
18954
18973
  } while(nextNode && nextNode[NG_REMOVED]);
18955
18974
 
18956
- if (block.startNode != nextNode) {
18975
+ if (getBlockStart(block) != nextNode) {
18957
18976
  // existing item which got moved
18958
- $animate.move(getBlockElements(block), null, jqLite(previousNode));
18977
+ $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
18959
18978
  }
18960
- previousNode = block.endNode;
18979
+ previousNode = getBlockEnd(block);
18961
18980
  } else {
18962
18981
  // new item which we don't know about
18963
18982
  childScope = $scope.$new();
@@ -18973,14 +18992,16 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18973
18992
  childScope.$odd = !(childScope.$even = (index&1) === 0);
18974
18993
  // jshint bitwise: true
18975
18994
 
18976
- if (!block.startNode) {
18995
+ if (!block.scope) {
18977
18996
  $transclude(childScope, function(clone) {
18978
18997
  clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
18979
18998
  $animate.enter(clone, null, jqLite(previousNode));
18980
18999
  previousNode = clone;
18981
19000
  block.scope = childScope;
18982
- block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
18983
- block.endNode = clone[clone.length - 1];
19001
+ // Note: We only need the first/last node of the cloned nodes.
19002
+ // However, we need to keep the reference to the jqlite wrapper as it might be changed later
19003
+ // by a directive with templateUrl when it's template arrives.
19004
+ block.clone = clone;
18984
19005
  nextBlockMap[block.id] = block;
18985
19006
  });
18986
19007
  }
@@ -18989,6 +19010,14 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
18989
19010
  });
18990
19011
  }
18991
19012
  };
19013
+
19014
+ function getBlockStart(block) {
19015
+ return block.clone[0];
19016
+ }
19017
+
19018
+ function getBlockEnd(block) {
19019
+ return block.clone[block.clone.length - 1];
19020
+ }
18992
19021
  }];
18993
19022
 
18994
19023
  /**