angularjs-rails 1.2.22 → 1.2.25

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.22
2
+ * @license AngularJS v1.2.25
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.22
2
+ * @license AngularJS v1.2.25
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.22/' +
71
+ message = message + '\nhttp://errors.angularjs.org/1.2.25/' +
72
72
  (module ? module + '/' : '') + code;
73
73
  for (i = 2; i < arguments.length; i++) {
74
74
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -899,9 +899,13 @@ function copy(source, destination, stackSource, stackDest) {
899
899
  }
900
900
  } else {
901
901
  var h = destination.$$hashKey;
902
- forEach(destination, function(value, key) {
903
- delete destination[key];
904
- });
902
+ if (isArray(destination)) {
903
+ destination.length = 0;
904
+ } else {
905
+ forEach(destination, function(value, key) {
906
+ delete destination[key];
907
+ });
908
+ }
905
909
  for ( var key in source) {
906
910
  result = copy(source[key], null, stackSource, stackDest);
907
911
  if (isObject(source[key])) {
@@ -986,7 +990,8 @@ function equals(o1, o2) {
986
990
  return true;
987
991
  }
988
992
  } else if (isDate(o1)) {
989
- return isDate(o2) && o1.getTime() == o2.getTime();
993
+ if (!isDate(o2)) return false;
994
+ return (isNaN(o1.getTime()) && isNaN(o2.getTime())) || (o1.getTime() === o2.getTime());
990
995
  } else if (isRegExp(o1) && isRegExp(o2)) {
991
996
  return o1.toString() == o2.toString();
992
997
  } else {
@@ -1424,7 +1429,11 @@ function bootstrap(element, modules) {
1424
1429
 
1425
1430
  if (element.injector()) {
1426
1431
  var tag = (element[0] === document) ? 'document' : startingTag(element);
1427
- throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
1432
+ //Encode angle brackets to prevent input from being sanitized to empty string #8683
1433
+ throw ngMinErr(
1434
+ 'btstrpd',
1435
+ "App Already Bootstrapped with this Element '{0}'",
1436
+ tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1428
1437
  }
1429
1438
 
1430
1439
  modules = modules || [];
@@ -1688,7 +1697,7 @@ function setupModuleLoader(window) {
1688
1697
  * @ngdoc property
1689
1698
  * @name angular.Module#requires
1690
1699
  * @module ng
1691
- * @returns {Array.<string>} List of module names which must be loaded before this module.
1700
+ *
1692
1701
  * @description
1693
1702
  * Holds the list of modules which the injector will load before the current module is
1694
1703
  * loaded.
@@ -1699,8 +1708,9 @@ function setupModuleLoader(window) {
1699
1708
  * @ngdoc property
1700
1709
  * @name angular.Module#name
1701
1710
  * @module ng
1702
- * @returns {string} Name of the module.
1711
+ *
1703
1712
  * @description
1713
+ * Name of the module.
1704
1714
  */
1705
1715
  name: name,
1706
1716
 
@@ -1977,11 +1987,11 @@ function setupModuleLoader(window) {
1977
1987
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
1978
1988
  */
1979
1989
  var version = {
1980
- full: '1.2.22', // all of these placeholder strings will be replaced by grunt's
1990
+ full: '1.2.25', // all of these placeholder strings will be replaced by grunt's
1981
1991
  major: 1, // package task
1982
1992
  minor: 2,
1983
- dot: 22,
1984
- codeName: 'finicky-pleasure'
1993
+ dot: 25,
1994
+ codeName: 'hypnotic-gesticulation'
1985
1995
  };
1986
1996
 
1987
1997
 
@@ -4572,6 +4582,13 @@ function Browser(window, document, $log, $sniffer) {
4572
4582
  return callback;
4573
4583
  };
4574
4584
 
4585
+ /**
4586
+ * Checks whether the url has changed outside of Angular.
4587
+ * Needs to be exported to be able to check for changes that have been done in sync,
4588
+ * as hashchange/popstate events fire in async.
4589
+ */
4590
+ self.$$checkUrlChange = fireUrlChange;
4591
+
4575
4592
  //////////////////////////////////////////////////////////////
4576
4593
  // Misc API
4577
4594
  //////////////////////////////////////////////////////////////
@@ -4788,8 +4805,10 @@ function $BrowserProvider(){
4788
4805
  $scope.keys = [];
4789
4806
  $scope.cache = $cacheFactory('cacheId');
4790
4807
  $scope.put = function(key, value) {
4791
- $scope.cache.put(key, value);
4792
- $scope.keys.push(key);
4808
+ if ($scope.cache.get(key) === undefined) {
4809
+ $scope.keys.push(key);
4810
+ }
4811
+ $scope.cache.put(key, value === undefined ? null : value);
4793
4812
  };
4794
4813
  }]);
4795
4814
  </file>
@@ -5309,9 +5328,9 @@ function $TemplateCacheProvider() {
5309
5328
  *
5310
5329
  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
5311
5330
  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
5312
- * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
5313
- * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
5314
- * `link` fn if not found.
5331
+ * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
5332
+ * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
5333
+ * `null` to the `link` fn if not found.
5315
5334
  *
5316
5335
  *
5317
5336
  * #### `controllerAs`
@@ -7129,8 +7148,10 @@ function directiveNormalize(name) {
7129
7148
  /**
7130
7149
  * @ngdoc property
7131
7150
  * @name $compile.directive.Attributes#$attr
7132
- * @returns {object} A map of DOM element attribute names to the normalized name. This is
7133
- * needed to do reverse lookup from normalized name back to actual name.
7151
+ *
7152
+ * @description
7153
+ * A map of DOM element attribute names to the normalized name. This is
7154
+ * needed to do reverse lookup from normalized name back to actual name.
7134
7155
  */
7135
7156
 
7136
7157
 
@@ -7885,7 +7906,7 @@ function $HttpProvider() {
7885
7906
  * that only JavaScript running on your domain could have sent the request. The token must be
7886
7907
  * unique for each user and must be verifiable by the server (to prevent the JavaScript from
7887
7908
  * making up its own tokens). We recommend that the token is a digest of your site's
7888
- * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
7909
+ * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
7889
7910
  * for added security.
7890
7911
  *
7891
7912
  * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
@@ -8393,7 +8414,7 @@ function $HttpProvider() {
8393
8414
  if (isObject(v)) {
8394
8415
  if (isDate(v)){
8395
8416
  v = v.toISOString();
8396
- } else if (isObject(v)) {
8417
+ } else {
8397
8418
  v = toJson(v);
8398
8419
  }
8399
8420
  }
@@ -8843,7 +8864,7 @@ function $InterpolateProvider() {
8843
8864
  * @description
8844
8865
  * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
8845
8866
  *
8846
- * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
8867
+ * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
8847
8868
  * the symbol.
8848
8869
  *
8849
8870
  * @returns {string} start symbol.
@@ -8859,7 +8880,7 @@ function $InterpolateProvider() {
8859
8880
  * @description
8860
8881
  * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
8861
8882
  *
8862
- * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
8883
+ * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
8863
8884
  * the symbol.
8864
8885
  *
8865
8886
  * @returns {string} end symbol.
@@ -8951,7 +8972,7 @@ function $IntervalProvider() {
8951
8972
  * };
8952
8973
  *
8953
8974
  * $scope.$on('$destroy', function() {
8954
- * // Make sure that the interval nis destroyed too
8975
+ * // Make sure that the interval is destroyed too
8955
8976
  * $scope.stopFight();
8956
8977
  * });
8957
8978
  * }])
@@ -9449,17 +9470,16 @@ LocationHashbangInHtml5Url.prototype =
9449
9470
  * Change path, search and hash, when called with parameter and return `$location`.
9450
9471
  *
9451
9472
  * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
9452
- * @param {string=} replace The path that will be changed
9453
9473
  * @return {string} url
9454
9474
  */
9455
- url: function(url, replace) {
9475
+ url: function(url) {
9456
9476
  if (isUndefined(url))
9457
9477
  return this.$$url;
9458
9478
 
9459
9479
  var match = PATH_MATCH.exec(url);
9460
9480
  if (match[1]) this.path(decodeURIComponent(match[1]));
9461
9481
  if (match[2] || match[1]) this.search(match[3] || '');
9462
- this.hash(match[5] || '', replace);
9482
+ this.hash(match[5] || '');
9463
9483
 
9464
9484
  return this;
9465
9485
  },
@@ -9517,10 +9537,11 @@ LocationHashbangInHtml5Url.prototype =
9517
9537
  * Note: Path should always begin with forward slash (/), this method will add the forward slash
9518
9538
  * if it is missing.
9519
9539
  *
9520
- * @param {string=} path New path
9540
+ * @param {(string|number)=} path New path
9521
9541
  * @return {string} path
9522
9542
  */
9523
9543
  path: locationGetterSetter('$$path', function(path) {
9544
+ path = path ? path.toString() : '';
9524
9545
  return path.charAt(0) == '/' ? path : '/' + path;
9525
9546
  }),
9526
9547
 
@@ -9556,7 +9577,7 @@ LocationHashbangInHtml5Url.prototype =
9556
9577
  * If the argument is a hash object containing an array of values, these values will be encoded
9557
9578
  * as duplicate search parameters in the url.
9558
9579
  *
9559
- * @param {(string|Array<string>|boolean)=} paramValue If `search` is a string, then `paramValue`
9580
+ * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
9560
9581
  * will override only a single search property.
9561
9582
  *
9562
9583
  * If `paramValue` is an array, it will override the property of the `search` component of
@@ -9575,7 +9596,8 @@ LocationHashbangInHtml5Url.prototype =
9575
9596
  case 0:
9576
9597
  return this.$$search;
9577
9598
  case 1:
9578
- if (isString(search)) {
9599
+ if (isString(search) || isNumber(search)) {
9600
+ search = search.toString();
9579
9601
  this.$$search = parseKeyValue(search);
9580
9602
  } else if (isObject(search)) {
9581
9603
  // remove object undefined or null properties
@@ -9612,10 +9634,12 @@ LocationHashbangInHtml5Url.prototype =
9612
9634
  *
9613
9635
  * Change hash fragment when called with parameter and return `$location`.
9614
9636
  *
9615
- * @param {string=} hash New hash fragment
9637
+ * @param {(string|number)=} hash New hash fragment
9616
9638
  * @return {string} hash
9617
9639
  */
9618
- hash: locationGetterSetter('$$hash', identity),
9640
+ hash: locationGetterSetter('$$hash', function(hash) {
9641
+ return hash ? hash.toString() : '';
9642
+ }),
9619
9643
 
9620
9644
  /**
9621
9645
  * @ngdoc method
@@ -9799,7 +9823,7 @@ function $LocationProvider(){
9799
9823
  // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
9800
9824
  var href = elm.attr('href') || elm.attr('xlink:href');
9801
9825
 
9802
- if (href.indexOf('://') < 0) { // Ignore absolute URLs
9826
+ if (href && href.indexOf('://') < 0) { // Ignore absolute URLs
9803
9827
  var prefix = '#' + hashPrefix;
9804
9828
  if (href[0] == '/') {
9805
9829
  // absolute path - replace old path
@@ -9811,6 +9835,7 @@ function $LocationProvider(){
9811
9835
  // relative path - join with current path
9812
9836
  var stack = $location.path().split("/"),
9813
9837
  parts = href.split("/");
9838
+ if (stack.length === 2 && !stack[1]) stack.length = 1;
9814
9839
  for (var i=0; i<parts.length; i++) {
9815
9840
  if (parts[i] == ".")
9816
9841
  continue;
@@ -10809,7 +10834,7 @@ Parser.prototype = {
10809
10834
  var context = contextGetter ? contextGetter(scope, locals) : scope;
10810
10835
 
10811
10836
  for (var i = 0; i < argsFn.length; i++) {
10812
- args.push(argsFn[i](scope, locals));
10837
+ args.push(ensureSafeObject(argsFn[i](scope, locals), parser.text));
10813
10838
  }
10814
10839
  var fnPtr = fn(scope, locals, context) || noop;
10815
10840
 
@@ -10897,13 +10922,15 @@ Parser.prototype = {
10897
10922
  //////////////////////////////////////////////////
10898
10923
 
10899
10924
  function setter(obj, path, setValue, fullExp, options) {
10925
+ ensureSafeObject(obj, fullExp);
10926
+
10900
10927
  //needed?
10901
10928
  options = options || {};
10902
10929
 
10903
10930
  var element = path.split('.'), key;
10904
10931
  for (var i = 0; element.length > 1; i++) {
10905
10932
  key = ensureSafeMemberName(element.shift(), fullExp);
10906
- var propertyObj = obj[key];
10933
+ var propertyObj = ensureSafeObject(obj[key], fullExp);
10907
10934
  if (!propertyObj) {
10908
10935
  propertyObj = {};
10909
10936
  obj[key] = propertyObj;
@@ -10923,7 +10950,6 @@ function setter(obj, path, setValue, fullExp, options) {
10923
10950
  }
10924
10951
  }
10925
10952
  key = ensureSafeMemberName(element.shift(), fullExp);
10926
- ensureSafeObject(obj, fullExp);
10927
10953
  ensureSafeObject(obj[key], fullExp);
10928
10954
  obj[key] = setValue;
10929
10955
  return setValue;
@@ -11987,10 +12013,26 @@ function $RootScopeProvider(){
11987
12013
  /**
11988
12014
  * @ngdoc property
11989
12015
  * @name $rootScope.Scope#$id
11990
- * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
11991
- * debugging.
12016
+ *
12017
+ * @description
12018
+ * Unique scope ID (monotonically increasing) useful for debugging.
11992
12019
  */
11993
12020
 
12021
+ /**
12022
+ * @ngdoc property
12023
+ * @name $rootScope.Scope#$parent
12024
+ *
12025
+ * @description
12026
+ * Reference to the parent scope.
12027
+ */
12028
+
12029
+ /**
12030
+ * @ngdoc property
12031
+ * @name $rootScope.Scope#$root
12032
+ *
12033
+ * @description
12034
+ * Reference to the root scope.
12035
+ */
11994
12036
 
11995
12037
  Scope.prototype = {
11996
12038
  constructor: Scope,
@@ -12002,9 +12044,8 @@ function $RootScopeProvider(){
12002
12044
  * @description
12003
12045
  * Creates a new child {@link ng.$rootScope.Scope scope}.
12004
12046
  *
12005
- * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
12006
- * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
12007
- * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
12047
+ * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
12048
+ * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
12008
12049
  *
12009
12050
  * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
12010
12051
  * desired for the scope and its child scopes to be permanently detached from the parent and
@@ -12457,6 +12498,8 @@ function $RootScopeProvider(){
12457
12498
  logIdx, logMsg, asyncTask;
12458
12499
 
12459
12500
  beginPhase('$digest');
12501
+ // Check for changes to browser url that happened in sync before the call to $digest
12502
+ $browser.$$checkUrlChange();
12460
12503
 
12461
12504
  lastDirtyWatch = null;
12462
12505
 
@@ -13003,7 +13046,7 @@ function $RootScopeProvider(){
13003
13046
  */
13004
13047
  function $$SanitizeUriProvider() {
13005
13048
  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
13006
- imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
13049
+ imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file):|data:image\/)/;
13007
13050
 
13008
13051
  /**
13009
13052
  * @description
@@ -14510,16 +14553,6 @@ function $WindowProvider(){
14510
14553
  * For more information about how angular filters work, and how to create your own filters, see
14511
14554
  * {@link guide/filter Filters} in the Angular Developer Guide.
14512
14555
  */
14513
- /**
14514
- * @ngdoc method
14515
- * @name $filterProvider#register
14516
- * @description
14517
- * Register filter factory function.
14518
- *
14519
- * @param {String} name Name of the filter.
14520
- * @param {Function} fn The filter factory function which is injectable.
14521
- */
14522
-
14523
14556
 
14524
14557
  /**
14525
14558
  * @ngdoc service
@@ -14558,7 +14591,7 @@ function $FilterProvider($provide) {
14558
14591
 
14559
14592
  /**
14560
14593
  * @ngdoc method
14561
- * @name $controllerProvider#register
14594
+ * @name $filterProvider#register
14562
14595
  * @param {string|Object} name Name of the filter function, or an object map of filters where
14563
14596
  * the keys are the filter names and the values are the filter factories.
14564
14597
  * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
@@ -14631,7 +14664,9 @@ function $FilterProvider($provide) {
14631
14664
  * which have property `name` containing "M" and property `phone` containing "1". A special
14632
14665
  * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
14633
14666
  * property of the object. That's equivalent to the simple substring match with a `string`
14634
- * as described above.
14667
+ * as described above. The predicate can be negated by prefixing the string with `!`.
14668
+ * For Example `{name: "!M"}` predicate will return an array of items which have property `name`
14669
+ * not containing "M".
14635
14670
  *
14636
14671
  * - `function(value)`: A predicate function can be used to write arbitrary filters. The function is
14637
14672
  * called for each element of `array`. The final result is an array of those elements that
@@ -14980,6 +15015,10 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14980
15015
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
14981
15016
  number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
14982
15017
 
15018
+ if (number === 0) {
15019
+ isNegative = false;
15020
+ }
15021
+
14983
15022
  var fraction = ('' + number).split(DECIMAL_SEP);
14984
15023
  var whole = fraction[0];
14985
15024
  fraction = fraction[1] || '';
@@ -15149,8 +15188,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
15149
15188
  * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
15150
15189
  * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
15151
15190
  *
15152
- * `format` string can contain literal values. These need to be quoted with single quotes (e.g.
15153
- * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
15191
+ * `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
15192
+ * `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
15154
15193
  * (e.g. `"h 'o''clock'"`).
15155
15194
  *
15156
15195
  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
@@ -15170,6 +15209,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
15170
15209
  <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
15171
15210
  <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
15172
15211
  <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
15212
+ <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
15213
+ <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
15173
15214
  </file>
15174
15215
  <file name="protractor.js" type="protractor">
15175
15216
  it('should format date', function() {
@@ -15179,6 +15220,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
15179
15220
  toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
15180
15221
  expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
15181
15222
  toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
15223
+ expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
15224
+ toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
15182
15225
  });
15183
15226
  </file>
15184
15227
  </example>
@@ -15443,9 +15486,13 @@ function limitToFilter(){
15443
15486
  *
15444
15487
  * - `function`: Getter function. The result of this function will be sorted using the
15445
15488
  * `<`, `=`, `>` operator.
15446
- * - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
15447
- * to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
15448
- * ascending or descending sort order (for example, +name or -name).
15489
+ * - `string`: An Angular expression. The result of this expression is used to compare elements
15490
+ * (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
15491
+ * 3 first characters of a property called `name`). The result of a constant expression
15492
+ * is interpreted as a property name to be used in comparisons (for example `"special name"`
15493
+ * to sort object by the value of their `special name` property). An expression can be
15494
+ * optionally prefixed with `+` or `-` to control ascending or descending sort order
15495
+ * (for example, `+name` or `-name`).
15449
15496
  * - `Array`: An array of function or string predicates. The first predicate in the array
15450
15497
  * is used for sorting, but when two items are equivalent, the next predicate is used.
15451
15498
  *
@@ -15536,7 +15583,7 @@ function limitToFilter(){
15536
15583
  orderByFilter.$inject = ['$parse'];
15537
15584
  function orderByFilter($parse){
15538
15585
  return function(array, sortPredicate, reverseOrder) {
15539
- if (!isArray(array)) return array;
15586
+ if (!(isArrayLike(array))) return array;
15540
15587
  if (!sortPredicate) return array;
15541
15588
  sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
15542
15589
  sortPredicate = map(sortPredicate, function(predicate){
@@ -15813,7 +15860,7 @@ var htmlAnchorDirective = valueFn({
15813
15860
  *
15814
15861
  * @description
15815
15862
  *
15816
- * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15863
+ * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
15817
15864
  * ```html
15818
15865
  * <div ng-init="scope = { isDisabled: false }">
15819
15866
  * <button disabled="{{scope.isDisabled}}">Disabled</button>
@@ -16033,8 +16080,12 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
16033
16080
  }
16034
16081
 
16035
16082
  attr.$observe(normalized, function(value) {
16036
- if (!value)
16037
- return;
16083
+ if (!value) {
16084
+ if (attrName === 'href') {
16085
+ attr.$set(name, null);
16086
+ }
16087
+ return;
16088
+ }
16038
16089
 
16039
16090
  attr.$set(name, value);
16040
16091
 
@@ -16119,8 +16170,9 @@ function FormController(element, attrs, $scope, $animate) {
16119
16170
  // convenience method for easy toggling of classes
16120
16171
  function toggleValidCss(isValid, validationErrorKey) {
16121
16172
  validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
16122
- $animate.removeClass(element, (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
16123
- $animate.addClass(element, (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
16173
+ $animate.setClass(element,
16174
+ (isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey,
16175
+ (isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey);
16124
16176
  }
16125
16177
 
16126
16178
  /**
@@ -16335,8 +16387,6 @@ function FormController(element, attrs, $scope, $animate) {
16335
16387
  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
16336
16388
  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
16337
16389
  *
16338
- * @param {string=} name Name of the form. If specified, the form controller will be published into
16339
- * related scope, under this name.
16340
16390
  *
16341
16391
  * ## Animation Hooks
16342
16392
  *
@@ -16414,6 +16464,8 @@ function FormController(element, attrs, $scope, $animate) {
16414
16464
  </file>
16415
16465
  </example>
16416
16466
  *
16467
+ * @param {string=} name Name of the form. If specified, the form controller will be published into
16468
+ * related scope, under this name.
16417
16469
  */
16418
16470
  var formDirectiveFactory = function(isNgForm) {
16419
16471
  return ['$timeout', function($timeout) {
@@ -16492,7 +16544,9 @@ var inputType = {
16492
16544
  * @name input[text]
16493
16545
  *
16494
16546
  * @description
16495
- * Standard HTML text input with angular data binding.
16547
+ * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
16548
+ *
16549
+ * *NOTE* Not every feature offered is available for all input types.
16496
16550
  *
16497
16551
  * @param {string} ngModel Assignable angular expression to data-bind to.
16498
16552
  * @param {string=} name Property name of the form under which the control is published.
@@ -16510,6 +16564,8 @@ var inputType = {
16510
16564
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
16511
16565
  * interaction with the input element.
16512
16566
  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
16567
+ * This parameter is ignored for input[type=password] controls, which will never trim the
16568
+ * input.
16513
16569
  *
16514
16570
  * @example
16515
16571
  <example name="text-input-directive" module="textInputExample">
@@ -16949,6 +17005,7 @@ function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, va
16949
17005
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16950
17006
  var validity = element.prop(VALIDITY_STATE_PROPERTY);
16951
17007
  var placeholder = element[0].placeholder, noevent = {};
17008
+ var type = lowercase(element[0].type);
16952
17009
  ctrl.$$validityState = validity;
16953
17010
 
16954
17011
  // In composition mode, users are still inputing intermediate text buffer,
@@ -16982,8 +17039,8 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16982
17039
 
16983
17040
  // By default we will trim the value
16984
17041
  // If the attribute ng-trim exists we will avoid trimming
16985
- // e.g. <input ng-model="foo" ng-trim="false">
16986
- if (toBoolean(attr.ngTrim || 'T')) {
17042
+ // If input type is 'password', the value is never trimmed
17043
+ if (type !== 'password' && (toBoolean(attr.ngTrim || 'T'))) {
16987
17044
  value = trim(value);
16988
17045
  }
16989
17046
 
@@ -16992,7 +17049,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
16992
17049
  // a row.
16993
17050
  var revalidate = validity && ctrl.$$hasNativeValidators;
16994
17051
  if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
16995
- if (scope.$$phase) {
17052
+ if (scope.$root.$$phase) {
16996
17053
  ctrl.$setViewValue(value);
16997
17054
  } else {
16998
17055
  scope.$apply(function() {
@@ -17258,6 +17315,8 @@ function checkboxInputType(scope, element, attr, ctrl) {
17258
17315
  * HTML input element control with angular data-binding. Input control follows HTML5 input types
17259
17316
  * and polyfills the HTML5 validation behavior for older browsers.
17260
17317
  *
17318
+ * *NOTE* Not every feature offered is available for all input types.
17319
+ *
17261
17320
  * @param {string} ngModel Assignable angular expression to data-bind to.
17262
17321
  * @param {string=} name Property name of the form under which the control is published.
17263
17322
  * @param {string=} required Sets `required` validation error key if the value is not entered.
@@ -17271,6 +17330,9 @@ function checkboxInputType(scope, element, attr, ctrl) {
17271
17330
  * patterns defined as scope expressions.
17272
17331
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
17273
17332
  * interaction with the input element.
17333
+ * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
17334
+ * This parameter is ignored for input[type=password] controls, which will never trim the
17335
+ * input.
17274
17336
  *
17275
17337
  * @example
17276
17338
  <example name="input-directive" module="inputExample">
@@ -18260,7 +18322,6 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
18260
18322
  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
18261
18323
  *
18262
18324
  * @example
18263
- Try it here: enter text in text box and watch the greeting change.
18264
18325
 
18265
18326
  <example module="bindHtmlExample" deps="angular-sanitize.js">
18266
18327
  <file name="index.html">
@@ -19030,7 +19091,9 @@ var ngControllerDirective = [function() {
19030
19091
  <button ng-click="count = count + 1" ng-init="count=0">
19031
19092
  Increment
19032
19093
  </button>
19033
- count: {{count}}
19094
+ <span>
19095
+ count: {{count}}
19096
+ <span>
19034
19097
  </file>
19035
19098
  <file name="protractor.js" type="protractor">
19036
19099
  it('should check ng-click', function() {
@@ -19048,19 +19111,32 @@ var ngControllerDirective = [function() {
19048
19111
  * Events that are handled via these handler are always configured not to propagate further.
19049
19112
  */
19050
19113
  var ngEventDirectives = {};
19114
+
19115
+ // For events that might fire synchronously during DOM manipulation
19116
+ // we need to execute their event handlers asynchronously using $evalAsync,
19117
+ // so that they are not executed in an inconsistent state.
19118
+ var forceAsyncEvents = {
19119
+ 'blur': true,
19120
+ 'focus': true
19121
+ };
19051
19122
  forEach(
19052
19123
  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
19053
- function(name) {
19054
- var directiveName = directiveNormalize('ng-' + name);
19055
- ngEventDirectives[directiveName] = ['$parse', function($parse) {
19124
+ function(eventName) {
19125
+ var directiveName = directiveNormalize('ng-' + eventName);
19126
+ ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
19056
19127
  return {
19057
19128
  compile: function($element, attr) {
19058
19129
  var fn = $parse(attr[directiveName]);
19059
19130
  return function ngEventHandler(scope, element) {
19060
- element.on(lowercase(name), function(event) {
19061
- scope.$apply(function() {
19131
+ element.on(eventName, function(event) {
19132
+ var callback = function() {
19062
19133
  fn(scope, {$event:event});
19063
- });
19134
+ };
19135
+ if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
19136
+ scope.$evalAsync(callback);
19137
+ } else {
19138
+ scope.$apply(callback);
19139
+ }
19064
19140
  });
19065
19141
  };
19066
19142
  }
@@ -19377,6 +19453,10 @@ forEach(
19377
19453
  * @description
19378
19454
  * Specify custom behavior on focus event.
19379
19455
  *
19456
+ * Note: As the `focus` event is executed synchronously when calling `input.focus()`
19457
+ * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
19458
+ * during an `$apply` to ensure a consistent state.
19459
+ *
19380
19460
  * @element window, input, select, textarea, a
19381
19461
  * @priority 0
19382
19462
  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
@@ -19393,6 +19473,14 @@ forEach(
19393
19473
  * @description
19394
19474
  * Specify custom behavior on blur event.
19395
19475
  *
19476
+ * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
19477
+ * an element has lost focus.
19478
+ *
19479
+ * Note: As the `blur` event is executed synchronously also during DOM manipulations
19480
+ * (e.g. removing a focussed input),
19481
+ * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
19482
+ * during an `$apply` to ensure a consistent state.
19483
+ *
19396
19484
  * @element window, input, select, textarea, a
19397
19485
  * @priority 0
19398
19486
  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
@@ -20473,8 +20561,9 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20473
20561
  if (block && block.scope) lastBlockMap[block.id] = block;
20474
20562
  });
20475
20563
  // This is a duplicate and we need to throw an error
20476
- throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
20477
- expression, trackById);
20564
+ throw ngRepeatMinErr('dupes',
20565
+ "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
20566
+ expression, trackById, toJson(value));
20478
20567
  } else {
20479
20568
  // new never before seen block
20480
20569
  nextBlockOrder[index] = { id: trackById };
@@ -20565,8 +20654,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20565
20654
  *
20566
20655
  * @description
20567
20656
  * The `ngShow` directive shows or hides the given HTML element based on the expression
20568
- * provided to the ngShow attribute. The element is shown or hidden by removing or adding
20569
- * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20657
+ * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
20658
+ * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20570
20659
  * in AngularJS and sets the display style to none (using an !important flag).
20571
20660
  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
20572
20661
  *
@@ -20578,8 +20667,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20578
20667
  * <div ng-show="myValue" class="ng-hide"></div>
20579
20668
  * ```
20580
20669
  *
20581
- * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
20582
- * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
20670
+ * When the `ngShow` expression evaluates to false then the `.ng-hide` CSS class is added to the class attribute
20671
+ * on the element causing it to become hidden. When true, the `.ng-hide` CSS class is removed
20583
20672
  * from the element causing the element not to appear hidden.
20584
20673
  *
20585
20674
  * <div class="alert alert-warning">
@@ -20589,7 +20678,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20589
20678
  *
20590
20679
  * ## Why is !important used?
20591
20680
  *
20592
- * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20681
+ * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
20593
20682
  * can be easily overridden by heavier selectors. For example, something as simple
20594
20683
  * as changing the display style on a HTML list item would make hidden elements appear visible.
20595
20684
  * This also becomes a bigger issue when dealing with CSS frameworks.
@@ -20598,7 +20687,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20598
20687
  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20599
20688
  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20600
20689
  *
20601
- * ### Overriding .ng-hide
20690
+ * ### Overriding `.ng-hide`
20602
20691
  *
20603
20692
  * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20604
20693
  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
@@ -20616,7 +20705,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20616
20705
  *
20617
20706
  * By default you don't need to override in CSS anything and the animations will work around the display style.
20618
20707
  *
20619
- * ## A note about animations with ngShow
20708
+ * ## A note about animations with `ngShow`
20620
20709
  *
20621
20710
  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20622
20711
  * is true and false. This system works like the animation system present with ngClass except that
@@ -20641,8 +20730,8 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
20641
20730
  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20642
20731
  *
20643
20732
  * @animations
20644
- * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
20645
- * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
20733
+ * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
20734
+ * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
20646
20735
  *
20647
20736
  * @element ANY
20648
20737
  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
@@ -20722,7 +20811,7 @@ var ngShowDirective = ['$animate', function($animate) {
20722
20811
  *
20723
20812
  * @description
20724
20813
  * The `ngHide` directive shows or hides the given HTML element based on the expression
20725
- * provided to the ngHide attribute. The element is shown or hidden by removing or adding
20814
+ * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
20726
20815
  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
20727
20816
  * in AngularJS and sets the display style to none (using an !important flag).
20728
20817
  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
@@ -20735,8 +20824,8 @@ var ngShowDirective = ['$animate', function($animate) {
20735
20824
  * <div ng-hide="myValue"></div>
20736
20825
  * ```
20737
20826
  *
20738
- * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
20739
- * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
20827
+ * When the `.ngHide` expression evaluates to true then the `.ng-hide` CSS class is added to the class attribute
20828
+ * on the element causing it to become hidden. When false, the `.ng-hide` CSS class is removed
20740
20829
  * from the element causing the element not to appear hidden.
20741
20830
  *
20742
20831
  * <div class="alert alert-warning">
@@ -20746,7 +20835,7 @@ var ngShowDirective = ['$animate', function($animate) {
20746
20835
  *
20747
20836
  * ## Why is !important used?
20748
20837
  *
20749
- * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
20838
+ * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
20750
20839
  * can be easily overridden by heavier selectors. For example, something as simple
20751
20840
  * as changing the display style on a HTML list item would make hidden elements appear visible.
20752
20841
  * This also becomes a bigger issue when dealing with CSS frameworks.
@@ -20755,7 +20844,7 @@ var ngShowDirective = ['$animate', function($animate) {
20755
20844
  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
20756
20845
  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
20757
20846
  *
20758
- * ### Overriding .ng-hide
20847
+ * ### Overriding `.ng-hide`
20759
20848
  *
20760
20849
  * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
20761
20850
  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
@@ -20773,7 +20862,7 @@ var ngShowDirective = ['$animate', function($animate) {
20773
20862
  *
20774
20863
  * By default you don't need to override in CSS anything and the animations will work around the display style.
20775
20864
  *
20776
- * ## A note about animations with ngHide
20865
+ * ## A note about animations with `ngHide`
20777
20866
  *
20778
20867
  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
20779
20868
  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
@@ -20797,8 +20886,8 @@ var ngShowDirective = ['$animate', function($animate) {
20797
20886
  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
20798
20887
  *
20799
20888
  * @animations
20800
- * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
20801
- * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
20889
+ * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
20890
+ * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
20802
20891
  *
20803
20892
  * @element ANY
20804
20893
  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
@@ -21651,6 +21740,19 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
21651
21740
  ctrl.$render = render;
21652
21741
 
21653
21742
  scope.$watchCollection(valuesFn, render);
21743
+ scope.$watchCollection(function () {
21744
+ var locals = {},
21745
+ values = valuesFn(scope);
21746
+ if (values) {
21747
+ var toDisplay = new Array(values.length);
21748
+ for (var i = 0, ii = values.length; i < ii; i++) {
21749
+ locals[valueName] = values[i];
21750
+ toDisplay[i] = displayFn(scope, locals);
21751
+ }
21752
+ return toDisplay;
21753
+ }
21754
+ }, render);
21755
+
21654
21756
  if ( multiple ) {
21655
21757
  scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
21656
21758
  }