angular-gem 1.2.23 → 1.2.24

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.23
2
+ * @license AngularJS v1.2.24
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.23
2
+ * @license AngularJS v1.2.24
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.23
2
+ * @license AngularJS v1.2.24
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.23/' +
72
+ message = message + '\nhttp://errors.angularjs.org/1.2.24/' +
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.23
2
+ * @license AngularJS v1.2.24
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -63,6 +63,8 @@ angular.mock.$Browser = function() {
63
63
  return listener;
64
64
  };
65
65
 
66
+ self.$$checkUrlChange = angular.noop;
67
+
66
68
  self.cookieHash = {};
67
69
  self.lastCookieHash = {};
68
70
  self.deferredFns = [];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.23
2
+ * @license AngularJS v1.2.24
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.23
2
+ * @license AngularJS v1.2.24
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.23
2
+ * @license AngularJS v1.2.24
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -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.23
9793
+ * @license AngularJS v1.2.24
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.23/' +
9863
+ message = message + '\nhttp://errors.angularjs.org/1.2.24/' +
9864
9864
  (module ? module + '/' : '') + code;
9865
9865
  for (i = 2; i < arguments.length; i++) {
9866
9866
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -11779,11 +11779,11 @@ function setupModuleLoader(window) {
11779
11779
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11780
11780
  */
11781
11781
  var version = {
11782
- full: '1.2.23', // all of these placeholder strings will be replaced by grunt's
11782
+ full: '1.2.24', // all of these placeholder strings will be replaced by grunt's
11783
11783
  major: 1, // package task
11784
11784
  minor: 2,
11785
- dot: 23,
11786
- codeName: 'superficial-malady'
11785
+ dot: 24,
11786
+ codeName: 'static-levitation'
11787
11787
  };
11788
11788
 
11789
11789
 
@@ -14374,6 +14374,13 @@ function Browser(window, document, $log, $sniffer) {
14374
14374
  return callback;
14375
14375
  };
14376
14376
 
14377
+ /**
14378
+ * Checks whether the url has changed outside of Angular.
14379
+ * Needs to be exported to be able to check for changes that have been done in sync,
14380
+ * as hashchange/popstate events fire in async.
14381
+ */
14382
+ self.$$checkUrlChange = fireUrlChange;
14383
+
14377
14384
  //////////////////////////////////////////////////////////////
14378
14385
  // Misc API
14379
14386
  //////////////////////////////////////////////////////////////
@@ -18199,7 +18206,7 @@ function $HttpProvider() {
18199
18206
  if (isObject(v)) {
18200
18207
  if (isDate(v)){
18201
18208
  v = v.toISOString();
18202
- } else if (isObject(v)) {
18209
+ } else {
18203
18210
  v = toJson(v);
18204
18211
  }
18205
18212
  }
@@ -18649,7 +18656,7 @@ function $InterpolateProvider() {
18649
18656
  * @description
18650
18657
  * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
18651
18658
  *
18652
- * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
18659
+ * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
18653
18660
  * the symbol.
18654
18661
  *
18655
18662
  * @returns {string} start symbol.
@@ -18665,7 +18672,7 @@ function $InterpolateProvider() {
18665
18672
  * @description
18666
18673
  * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
18667
18674
  *
18668
- * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
18675
+ * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
18669
18676
  * the symbol.
18670
18677
  *
18671
18678
  * @returns {string} end symbol.
@@ -19255,17 +19262,16 @@ LocationHashbangInHtml5Url.prototype =
19255
19262
  * Change path, search and hash, when called with parameter and return `$location`.
19256
19263
  *
19257
19264
  * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
19258
- * @param {string=} replace The path that will be changed
19259
19265
  * @return {string} url
19260
19266
  */
19261
- url: function(url, replace) {
19267
+ url: function(url) {
19262
19268
  if (isUndefined(url))
19263
19269
  return this.$$url;
19264
19270
 
19265
19271
  var match = PATH_MATCH.exec(url);
19266
19272
  if (match[1]) this.path(decodeURIComponent(match[1]));
19267
19273
  if (match[2] || match[1]) this.search(match[3] || '');
19268
- this.hash(match[5] || '', replace);
19274
+ this.hash(match[5] || '');
19269
19275
 
19270
19276
  return this;
19271
19277
  },
@@ -19323,10 +19329,11 @@ LocationHashbangInHtml5Url.prototype =
19323
19329
  * Note: Path should always begin with forward slash (/), this method will add the forward slash
19324
19330
  * if it is missing.
19325
19331
  *
19326
- * @param {string=} path New path
19332
+ * @param {(string|number)=} path New path
19327
19333
  * @return {string} path
19328
19334
  */
19329
19335
  path: locationGetterSetter('$$path', function(path) {
19336
+ path = path ? path.toString() : '';
19330
19337
  return path.charAt(0) == '/' ? path : '/' + path;
19331
19338
  }),
19332
19339
 
@@ -19362,7 +19369,7 @@ LocationHashbangInHtml5Url.prototype =
19362
19369
  * If the argument is a hash object containing an array of values, these values will be encoded
19363
19370
  * as duplicate search parameters in the url.
19364
19371
  *
19365
- * @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue`
19372
+ * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
19366
19373
  * will override only a single search property.
19367
19374
  *
19368
19375
  * If `paramValue` is an array, it will override the property of the `search` component of
@@ -19381,7 +19388,8 @@ LocationHashbangInHtml5Url.prototype =
19381
19388
  case 0:
19382
19389
  return this.$$search;
19383
19390
  case 1:
19384
- if (isString(search)) {
19391
+ if (isString(search) || isNumber(search)) {
19392
+ search = search.toString();
19385
19393
  this.$$search = parseKeyValue(search);
19386
19394
  } else if (isObject(search)) {
19387
19395
  // remove object undefined or null properties
@@ -19418,10 +19426,12 @@ LocationHashbangInHtml5Url.prototype =
19418
19426
  *
19419
19427
  * Change hash fragment when called with parameter and return `$location`.
19420
19428
  *
19421
- * @param {string=} hash New hash fragment
19429
+ * @param {(string|number)=} hash New hash fragment
19422
19430
  * @return {string} hash
19423
19431
  */
19424
- hash: locationGetterSetter('$$hash', identity),
19432
+ hash: locationGetterSetter('$$hash', function(hash) {
19433
+ return hash ? hash.toString() : '';
19434
+ }),
19425
19435
 
19426
19436
  /**
19427
19437
  * @ngdoc method
@@ -20616,7 +20626,7 @@ Parser.prototype = {
20616
20626
  var context = contextGetter ? contextGetter(scope, locals) : scope;
20617
20627
 
20618
20628
  for (var i = 0; i < argsFn.length; i++) {
20619
- args.push(argsFn[i](scope, locals));
20629
+ args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
20620
20630
  }
20621
20631
  var fnPtr = fn(scope, locals, context) || noop;
20622
20632
 
@@ -20704,13 +20714,15 @@ Parser.prototype = {
20704
20714
  //////////////////////////////////////////////////
20705
20715
 
20706
20716
  function setter(obj, path, setValue, fullExp, options) {
20717
+ ensureSafeObject(obj, fullExp);
20718
+
20707
20719
  //needed?
20708
20720
  options = options || {};
20709
20721
 
20710
20722
  var element = path.split('.'), key;
20711
20723
  for (var i = 0; element.length > 1; i++) {
20712
20724
  key = ensureSafeMemberName(element.shift(), fullExp);
20713
- var propertyObj = obj[key];
20725
+ var propertyObj = ensureSafeObject(obj[key], fullExp);
20714
20726
  if (!propertyObj) {
20715
20727
  propertyObj = {};
20716
20728
  obj[key] = propertyObj;
@@ -20730,7 +20742,6 @@ function setter(obj, path, setValue, fullExp, options) {
20730
20742
  }
20731
20743
  }
20732
20744
  key = ensureSafeMemberName(element.shift(), fullExp);
20733
- ensureSafeObject(obj, fullExp);
20734
20745
  ensureSafeObject(obj[key], fullExp);
20735
20746
  obj[key] = setValue;
20736
20747
  return setValue;
@@ -21794,10 +21805,26 @@ function $RootScopeProvider(){
21794
21805
  /**
21795
21806
  * @ngdoc property
21796
21807
  * @name $rootScope.Scope#$id
21797
- * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
21798
- * debugging.
21808
+ *
21809
+ * @description
21810
+ * Unique scope ID (monotonically increasing) useful for debugging.
21799
21811
  */
21800
21812
 
21813
+ /**
21814
+ * @ngdoc property
21815
+ * @name $rootScope.Scope#$parent
21816
+ *
21817
+ * @description
21818
+ * Reference to the parent scope.
21819
+ */
21820
+
21821
+ /**
21822
+ * @ngdoc property
21823
+ * @name $rootScope.Scope#$root
21824
+ *
21825
+ * @description
21826
+ * Reference to the root scope.
21827
+ */
21801
21828
 
21802
21829
  Scope.prototype = {
21803
21830
  constructor: Scope,
@@ -21809,9 +21836,8 @@ function $RootScopeProvider(){
21809
21836
  * @description
21810
21837
  * Creates a new child {@link ng.$rootScope.Scope scope}.
21811
21838
  *
21812
- * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
21813
- * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
21814
- * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
21839
+ * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
21840
+ * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
21815
21841
  *
21816
21842
  * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
21817
21843
  * desired for the scope and its child scopes to be permanently detached from the parent and
@@ -22264,6 +22290,8 @@ function $RootScopeProvider(){
22264
22290
  logIdx, logMsg, asyncTask;
22265
22291
 
22266
22292
  beginPhase('$digest');
22293
+ // Check for changes to browser url that happened in sync before the call to $digest
22294
+ $browser.$$checkUrlChange();
22267
22295
 
22268
22296
  lastDirtyWatch = null;
22269
22297
 
@@ -24317,16 +24345,6 @@ function $WindowProvider(){
24317
24345
  * For more information about how angular filters work, and how to create your own filters, see
24318
24346
  * {@link guide/filter Filters} in the Angular Developer Guide.
24319
24347
  */
24320
- /**
24321
- * @ngdoc method
24322
- * @name $filterProvider#register
24323
- * @description
24324
- * Register filter factory function.
24325
- *
24326
- * @param {String} name Name of the filter.
24327
- * @param {Function} fn The filter factory function which is injectable.
24328
- */
24329
-
24330
24348
 
24331
24349
  /**
24332
24350
  * @ngdoc service
@@ -24365,7 +24383,7 @@ function $FilterProvider($provide) {
24365
24383
 
24366
24384
  /**
24367
24385
  * @ngdoc method
24368
- * @name $controllerProvider#register
24386
+ * @name $filterProvider#register
24369
24387
  * @param {string|Object} name Name of the filter function, or an object map of filters where
24370
24388
  * the keys are the filter names and the values are the filter factories.
24371
24389
  * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
@@ -24438,7 +24456,9 @@ function $FilterProvider($provide) {
24438
24456
  * which have property `name` containing "M" and property `phone` containing "1". A special
24439
24457
  * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
24440
24458
  * property of the object. That's equivalent to the simple substring match with a `string`
24441
- * as described above.
24459
+ * as described above. The predicate can be negated by prefixing the string with `!`.
24460
+ * For Example `{name: "!M"}` predicate will return an array of items which have property `name`
24461
+ * not containing "M".
24442
24462
  *
24443
24463
  * - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
24444
24464
  * called for each element of `array`. The final result is an array of those elements that
@@ -24787,6 +24807,10 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
24787
24807
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
24788
24808
  number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
24789
24809
 
24810
+ if (number === 0) {
24811
+ isNegative = false;
24812
+ }
24813
+
24790
24814
  var fraction = ('' + number).split(DECIMAL_SEP);
24791
24815
  var whole = fraction[0];
24792
24816
  fraction = fraction[1] || '';
@@ -24956,8 +24980,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
24956
24980
  * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
24957
24981
  * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
24958
24982
  *
24959
- * `format` string can contain literal values. These need to be quoted with single quotes (e.g.
24960
- * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
24983
+ * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
24984
+ * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
24961
24985
  * (e.g. `"h 'o''clock'"`).
24962
24986
  *
24963
24987
  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
@@ -24977,6 +25001,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
24977
25001
  <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
24978
25002
  <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
24979
25003
  <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
25004
+ <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
25005
+ <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
24980
25006
  </file>
24981
25007
  <file name="protractor.js" type="protractor">
24982
25008
  it('should format date', function() {
@@ -24986,6 +25012,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
24986
25012
  toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
24987
25013
  expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
24988
25014
  toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
25015
+ expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
25016
+ toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
24989
25017
  });
24990
25018
  </file>
24991
25019
  </example>
@@ -25347,7 +25375,7 @@ function limitToFilter(){
25347
25375
  orderByFilter.$inject = ['$parse'];
25348
25376
  function orderByFilter($parse){
25349
25377
  return function(array, sortPredicate, reverseOrder) {
25350
- if (!isArray(array)) return array;
25378
+ if (!(isArrayLike(array))) return array;
25351
25379
  if (!sortPredicate) return array;
25352
25380
  sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
25353
25381
  sortPredicate = map(sortPredicate, function(predicate){
@@ -25934,8 +25962,9 @@ function FormController(element, attrs, $scope, $animate) {
25934
25962
  // convenience method for easy toggling of classes
25935
25963
  function toggleValidCss(isValid, validationErrorKey) {
25936
25964
  validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
25937
- $animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
25938
- $animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
25965
+ $animate.setClass(element,
25966
+ (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
25967
+ (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
25939
25968
  }
25940
25969
 
25941
25970
  /**
@@ -26150,8 +26179,6 @@ function FormController(element, attrs, $scope, $animate) {
26150
26179
  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
26151
26180
  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
26152
26181
  *
26153
- * @param {string=} name Name of the form. If specified, the form controller will be published into
26154
- * related scope, under this name.
26155
26182
  *
26156
26183
  * ## Animation Hooks
26157
26184
  *
@@ -26229,6 +26256,8 @@ function FormController(element, attrs, $scope, $animate) {
26229
26256
  </file>
26230
26257
  </example>
26231
26258
  *
26259
+ * @param {string=} name Name of the form. If specified, the form controller will be published into
26260
+ * related scope, under this name.
26232
26261
  */
26233
26262
  var formDirectiveFactory = function(isNgForm) {
26234
26263
  return ['$timeout', function($timeout) {
@@ -26812,7 +26841,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
26812
26841
  // a row.
26813
26842
  var revalidate = validity && ctrl.$$hasNativeValidators;
26814
26843
  if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
26815
- if (scope.$$phase) {
26844
+ if (scope.$root.$$phase) {
26816
26845
  ctrl.$setViewValue(value);
26817
26846
  } else {
26818
26847
  scope.$apply(function() {
@@ -28854,7 +28883,9 @@ var ngControllerDirective = [function() {
28854
28883
  <button ng-click="count = count + 1" ng-init="count=0">
28855
28884
  Increment
28856
28885
  </button>
28857
- count: {{count}}
28886
+ <span>
28887
+ count: {{count}}
28888
+ <span>
28858
28889
  </file>
28859
28890
  <file name="protractor.js" type="protractor">
28860
28891
  it('should check ng-click', function() {
@@ -28872,19 +28903,33 @@ var ngControllerDirective = [function() {
28872
28903
  * Events that are handled via these handler are always configured not to propagate further.
28873
28904
  */
28874
28905
  var ngEventDirectives = {};
28906
+
28907
+ // For events that might fire synchronously during DOM manipulation
28908
+ // we need to execute their event handlers asynchronously using $evalAsync,
28909
+ // so that they are not executed in an inconsistent state.
28910
+ var forceAsyncEvents = {
28911
+ 'blur': true,
28912
+ 'focus': true
28913
+ };
28875
28914
  forEach(
28876
28915
  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
28877
28916
  function(name) {
28878
28917
  var directiveName = directiveNormalize('ng-' + name);
28879
- ngEventDirectives[directiveName] = ['$parse', function($parse) {
28918
+ ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
28880
28919
  return {
28881
28920
  compile: function($element, attr) {
28882
28921
  var fn = $parse(attr[directiveName]);
28883
28922
  return function ngEventHandler(scope, element) {
28884
- element.on(lowercase(name), function(event) {
28885
- scope.$apply(function() {
28923
+ var eventName = lowercase(name);
28924
+ element.on(eventName, function(event) {
28925
+ var callback = function() {
28886
28926
  fn(scope, {$event:event});
28887
- });
28927
+ };
28928
+ if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
28929
+ scope.$evalAsync(callback);
28930
+ } else {
28931
+ scope.$apply(callback);
28932
+ }
28888
28933
  });
28889
28934
  };
28890
28935
  }
@@ -29201,6 +29246,10 @@ forEach(
29201
29246
  * @description
29202
29247
  * Specify custom behavior on focus event.
29203
29248
  *
29249
+ * Note: As the `focus` event is executed synchronously when calling `input.focus()`
29250
+ * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
29251
+ * during an `$apply` to ensure a consistent state.
29252
+ *
29204
29253
  * @element window, input, select, textarea, a
29205
29254
  * @priority 0
29206
29255
  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
@@ -29217,6 +29266,14 @@ forEach(
29217
29266
  * @description
29218
29267
  * Specify custom behavior on blur event.
29219
29268
  *
29269
+ * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
29270
+ * an element has lost focus.
29271
+ *
29272
+ * Note: As the `blur` event is executed synchronously also during DOM manipulations
29273
+ * (e.g. removing a focussed input),
29274
+ * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
29275
+ * during an `$apply` to ensure a consistent state.
29276
+ *
29220
29277
  * @element window, input, select, textarea, a
29221
29278
  * @priority 0
29222
29279
  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
@@ -30297,8 +30354,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
30297
30354
  if (block && block.scope) lastBlockMap[block.id] = block;
30298
30355
  });
30299
30356
  // This is a duplicate and we need to throw an error
30300
- throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
30301
- expression, trackById);
30357
+ throw ngRepeatMinErr('dupes',
30358
+ "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
30359
+ expression, trackById, toJson(value));
30302
30360
  } else {
30303
30361
  // new never before seen block
30304
30362
  nextBlockOrder[index] = { id: trackById };