angular-gem 1.3.2 → 1.3.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.
Files changed (27) hide show
  1. checksums.yaml +8 -8
  2. data/lib/angular-gem/version.rb +1 -1
  3. data/vendor/assets/javascripts/1.3.4/angular-animate.js +2136 -0
  4. data/vendor/assets/javascripts/1.3.4/angular-aria.js +321 -0
  5. data/vendor/assets/javascripts/1.3.4/angular-cookies.js +206 -0
  6. data/vendor/assets/javascripts/1.3.4/angular-loader.js +405 -0
  7. data/vendor/assets/javascripts/1.3.4/angular-messages.js +400 -0
  8. data/vendor/assets/javascripts/1.3.4/angular-mocks.js +2380 -0
  9. data/vendor/assets/javascripts/1.3.4/angular-resource.js +667 -0
  10. data/vendor/assets/javascripts/1.3.4/angular-route.js +996 -0
  11. data/vendor/assets/javascripts/1.3.4/angular-sanitize.js +678 -0
  12. data/vendor/assets/javascripts/1.3.4/angular-scenario.js +37269 -0
  13. data/vendor/assets/javascripts/1.3.4/angular-touch.js +622 -0
  14. data/vendor/assets/javascripts/1.3.4/angular.js +25915 -0
  15. data/vendor/assets/javascripts/angular-animate.js +15 -15
  16. data/vendor/assets/javascripts/angular-aria.js +83 -23
  17. data/vendor/assets/javascripts/angular-cookies.js +1 -1
  18. data/vendor/assets/javascripts/angular-loader.js +6 -23
  19. data/vendor/assets/javascripts/angular-messages.js +1 -1
  20. data/vendor/assets/javascripts/angular-mocks.js +21 -17
  21. data/vendor/assets/javascripts/angular-resource.js +1 -1
  22. data/vendor/assets/javascripts/angular-route.js +21 -7
  23. data/vendor/assets/javascripts/angular-sanitize.js +26 -26
  24. data/vendor/assets/javascripts/angular-scenario.js +646 -453
  25. data/vendor/assets/javascripts/angular-touch.js +3 -3
  26. data/vendor/assets/javascripts/angular.js +641 -448
  27. metadata +14 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.2
2
+ * @license AngularJS v1.3.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -301,7 +301,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
301
301
  // Splices out the allowable region from the list after it has been used.
302
302
  function checkAllowableRegions(touchCoordinates, x, y) {
303
303
  for (var i = 0; i < touchCoordinates.length; i += 2) {
304
- if (hit(touchCoordinates[i], touchCoordinates[i+1], x, y)) {
304
+ if (hit(touchCoordinates[i], touchCoordinates[i + 1], x, y)) {
305
305
  touchCoordinates.splice(i, i + 2);
306
306
  return true; // allowable region
307
307
  }
@@ -366,7 +366,7 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement',
366
366
  $timeout(function() {
367
367
  // Remove the allowable region.
368
368
  for (var i = 0; i < touchCoordinates.length; i += 2) {
369
- if (touchCoordinates[i] == x && touchCoordinates[i+1] == y) {
369
+ if (touchCoordinates[i] == x && touchCoordinates[i + 1] == y) {
370
370
  touchCoordinates.splice(i, i + 2);
371
371
  return;
372
372
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.2
2
+ * @license AngularJS v1.3.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -42,40 +42,23 @@ function minErr(module, ErrorConstructor) {
42
42
  prefix = '[' + (module ? module + ':' : '') + code + '] ',
43
43
  template = arguments[1],
44
44
  templateArgs = arguments,
45
- stringify = function(obj) {
46
- if (typeof obj === 'function') {
47
- return obj.toString().replace(/ \{[\s\S]*$/, '');
48
- } else if (typeof obj === 'undefined') {
49
- return 'undefined';
50
- } else if (typeof obj !== 'string') {
51
- return JSON.stringify(obj);
52
- }
53
- return obj;
54
- },
45
+
55
46
  message, i;
56
47
 
57
48
  message = prefix + template.replace(/\{\d+\}/g, function(match) {
58
49
  var index = +match.slice(1, -1), arg;
59
50
 
60
51
  if (index + 2 < templateArgs.length) {
61
- arg = templateArgs[index + 2];
62
- if (typeof arg === 'function') {
63
- return arg.toString().replace(/ ?\{[\s\S]*$/, '');
64
- } else if (typeof arg === 'undefined') {
65
- return 'undefined';
66
- } else if (typeof arg !== 'string') {
67
- return toJson(arg);
68
- }
69
- return arg;
52
+ return toDebugString(templateArgs[index + 2]);
70
53
  }
71
54
  return match;
72
55
  });
73
56
 
74
- message = message + '\nhttp://errors.angularjs.org/1.3.2/' +
57
+ message = message + '\nhttp://errors.angularjs.org/1.3.4/' +
75
58
  (module ? module + '/' : '') + code;
76
59
  for (i = 2; i < arguments.length; i++) {
77
- message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
78
- encodeURIComponent(stringify(arguments[i]));
60
+ message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
61
+ encodeURIComponent(toDebugString(arguments[i]));
79
62
  }
80
63
  return new ErrorConstructor(message);
81
64
  };
@@ -443,7 +426,7 @@ function int(str) {
443
426
 
444
427
 
445
428
  function inherit(parent, extra) {
446
- return extend(new (extend(function() {}, {prototype:parent}))(), extra);
429
+ return extend(Object.create(parent), extra);
447
430
  }
448
431
 
449
432
  /**
@@ -706,7 +689,7 @@ function makeMap(str) {
706
689
 
707
690
 
708
691
  function nodeName_(element) {
709
- return lowercase(element.nodeName || element[0].nodeName);
692
+ return lowercase(element.nodeName || (element[0] && element[0].nodeName));
710
693
  }
711
694
 
712
695
  function includes(array, obj) {
@@ -715,7 +698,7 @@ function includes(array, obj) {
715
698
 
716
699
  function arrayRemove(array, value) {
717
700
  var index = array.indexOf(value);
718
- if (index >=0)
701
+ if (index >= 0)
719
702
  array.splice(index, 1);
720
703
  return value;
721
704
  }
@@ -916,7 +899,7 @@ function equals(o1, o2) {
916
899
  if (isArray(o1)) {
917
900
  if (!isArray(o2)) return false;
918
901
  if ((length = o1.length) == o2.length) {
919
- for (key=0; key<length; key++) {
902
+ for (key = 0; key < length; key++) {
920
903
  if (!equals(o1[key], o2[key])) return false;
921
904
  }
922
905
  return true;
@@ -1002,7 +985,7 @@ function bind(self, fn) {
1002
985
  return curryArgs.length
1003
986
  ? function() {
1004
987
  return arguments.length
1005
- ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
988
+ ? fn.apply(self, concat(curryArgs, arguments, 0))
1006
989
  : fn.apply(self, curryArgs);
1007
990
  }
1008
991
  : function() {
@@ -1202,7 +1185,7 @@ var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1202
1185
  function getNgAttribute(element, ngAttr) {
1203
1186
  var attr, i, ii = ngAttrPrefixes.length;
1204
1187
  element = jqLite(element);
1205
- for (i=0; i<ii; ++i) {
1188
+ for (i = 0; i < ii; ++i) {
1206
1189
  attr = ngAttrPrefixes[i] + ngAttr;
1207
1190
  if (isString(attr = element.attr(attr))) {
1208
1191
  return attr;
@@ -1412,8 +1395,8 @@ function angularInit(element, bootstrap) {
1412
1395
  * @param {Object=} config an object for defining configuration options for the application. The
1413
1396
  * following keys are supported:
1414
1397
  *
1415
- * - `strictDi`: disable automatic function annotation for the application. This is meant to
1416
- * assist in finding bugs which break minified code.
1398
+ * * `strictDi` - disable automatic function annotation for the application. This is meant to
1399
+ * assist in finding bugs which break minified code. Defaults to `false`.
1417
1400
  *
1418
1401
  * @returns {auto.$injector} Returns the newly created injector for this app.
1419
1402
  */
@@ -1987,6 +1970,34 @@ function setupModuleLoader(window) {
1987
1970
 
1988
1971
  }
1989
1972
 
1973
+ /* global: toDebugString: true */
1974
+
1975
+ function serializeObject(obj) {
1976
+ var seen = [];
1977
+
1978
+ return JSON.stringify(obj, function(key, val) {
1979
+ val = toJsonReplacer(key, val);
1980
+ if (isObject(val)) {
1981
+
1982
+ if (seen.indexOf(val) >= 0) return '<<already seen>>';
1983
+
1984
+ seen.push(val);
1985
+ }
1986
+ return val;
1987
+ });
1988
+ }
1989
+
1990
+ function toDebugString(obj) {
1991
+ if (typeof obj === 'function') {
1992
+ return obj.toString().replace(/ \{[\s\S]*$/, '');
1993
+ } else if (typeof obj === 'undefined') {
1994
+ return 'undefined';
1995
+ } else if (typeof obj !== 'string') {
1996
+ return serializeObject(obj);
1997
+ }
1998
+ return obj;
1999
+ }
2000
+
1990
2001
  /* global angularModule: true,
1991
2002
  version: true,
1992
2003
 
@@ -2089,11 +2100,11 @@ function setupModuleLoader(window) {
2089
2100
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2090
2101
  */
2091
2102
  var version = {
2092
- full: '1.3.2', // all of these placeholder strings will be replaced by grunt's
2103
+ full: '1.3.4', // all of these placeholder strings will be replaced by grunt's
2093
2104
  major: 1, // package task
2094
2105
  minor: 3,
2095
- dot: 2,
2096
- codeName: 'cardiovasculatory-magnification'
2106
+ dot: 4,
2107
+ codeName: 'highfalutin-petroglyph'
2097
2108
  };
2098
2109
 
2099
2110
 
@@ -2316,10 +2327,12 @@ function publishExternalAPI(angular) {
2316
2327
  * `'ngModel'`).
2317
2328
  * - `injector()` - retrieves the injector of the current element or its parent.
2318
2329
  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2319
- * element or its parent.
2330
+ * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2331
+ * be enabled.
2320
2332
  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2321
2333
  * current element. This getter should be used only on elements that contain a directive which starts a new isolate
2322
2334
  * scope. Calling `scope()` on this element always returns the original non-isolate scope.
2335
+ * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2323
2336
  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2324
2337
  * parent element is reached.
2325
2338
  *
@@ -2826,7 +2839,7 @@ forEach({
2826
2839
  }
2827
2840
  } else {
2828
2841
  return (element[name] ||
2829
- (element.attributes.getNamedItem(name)|| noop).specified)
2842
+ (element.attributes.getNamedItem(name) || noop).specified)
2830
2843
  ? lowercasedName
2831
2844
  : undefined;
2832
2845
  }
@@ -3314,9 +3327,10 @@ HashMap.prototype = {
3314
3327
  * Creates an injector object that can be used for retrieving services as well as for
3315
3328
  * dependency injection (see {@link guide/di dependency injection}).
3316
3329
  *
3317
-
3318
3330
  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3319
- * {@link angular.module}. The `ng` module must be explicitly added.
3331
+ * {@link angular.module}. The `ng` module must be explicitly added.
3332
+ * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3333
+ * disallows argument name annotation inference.
3320
3334
  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3321
3335
  *
3322
3336
  * @example
@@ -3462,8 +3476,10 @@ function annotate(fn, strictDi, name) {
3462
3476
  * ## Inference
3463
3477
  *
3464
3478
  * In JavaScript calling `toString()` on a function returns the function definition. The definition
3465
- * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3466
- * minification, and obfuscation tools since these tools change the argument names.
3479
+ * can then be parsed and the function arguments can be extracted. This method of discovering
3480
+ * annotations is disallowed when the injector is in strict mode.
3481
+ * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
3482
+ * argument names.
3467
3483
  *
3468
3484
  * ## `$inject` Annotation
3469
3485
  * By adding an `$inject` property onto a function the injection parameters can be specified.
@@ -3548,6 +3564,8 @@ function annotate(fn, strictDi, name) {
3548
3564
  * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3549
3565
  * ```
3550
3566
  *
3567
+ * You can disallow this method by using strict injection mode.
3568
+ *
3551
3569
  * This method does not work with code minification / obfuscation. For this reason the following
3552
3570
  * annotation strategies are supported.
3553
3571
  *
@@ -3600,6 +3618,8 @@ function annotate(fn, strictDi, name) {
3600
3618
  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3601
3619
  * be retrieved as described above.
3602
3620
  *
3621
+ * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
3622
+ *
3603
3623
  * @returns {Array.<string>} The names of the services which the function requires.
3604
3624
  */
3605
3625
 
@@ -4119,14 +4139,11 @@ function createInjector(modulesToLoad, strictDi) {
4119
4139
  }
4120
4140
 
4121
4141
  function instantiate(Type, locals, serviceName) {
4122
- var Constructor = function() {},
4123
- instance, returnedValue;
4124
-
4125
4142
  // Check if Type is annotated and use just the given function at n-1 as parameter
4126
4143
  // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4127
- Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
4128
- instance = new Constructor();
4129
- returnedValue = invoke(Type, instance, locals, serviceName);
4144
+ // Object creation: http://jsperf.com/create-constructor/2
4145
+ var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype);
4146
+ var returnedValue = invoke(Type, instance, locals, serviceName);
4130
4147
 
4131
4148
  return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4132
4149
  }
@@ -4162,7 +4179,7 @@ function $AnchorScrollProvider() {
4162
4179
  * @name $anchorScrollProvider#disableAutoScrolling
4163
4180
  *
4164
4181
  * @description
4165
- * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically will detect changes to
4182
+ * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4166
4183
  * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4167
4184
  * Use this method to disable automatic scrolling.
4168
4185
  *
@@ -4811,8 +4828,7 @@ function $$AsyncCallbackProvider() {
4811
4828
  /**
4812
4829
  * @param {object} window The global window object.
4813
4830
  * @param {object} document jQuery wrapped document.
4814
- * @param {function()} XHR XMLHttpRequest constructor.
4815
- * @param {object} $log console.log or an object with the same interface.
4831
+ * @param {object} $log window.console or an object with the same interface.
4816
4832
  * @param {object} $sniffer $sniffer service
4817
4833
  */
4818
4834
  function Browser(window, document, $log, $sniffer) {
@@ -4963,7 +4979,7 @@ function Browser(window, document, $log, $sniffer) {
4963
4979
  // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
4964
4980
  // See https://github.com/angular/angular.js/commit/ffb2701
4965
4981
  if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
4966
- return;
4982
+ return self;
4967
4983
  }
4968
4984
  var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
4969
4985
  lastBrowserUrl = url;
@@ -5162,8 +5178,8 @@ function Browser(window, document, $log, $sniffer) {
5162
5178
  // - 20 cookies per unique domain
5163
5179
  // - 4096 bytes per cookie
5164
5180
  if (cookieLength > 4096) {
5165
- $log.warn("Cookie '"+ name +
5166
- "' possibly not set or overflowed because it was too large ("+
5181
+ $log.warn("Cookie '" + name +
5182
+ "' possibly not set or overflowed because it was too large (" +
5167
5183
  cookieLength + " > 4096 bytes)!");
5168
5184
  }
5169
5185
  }
@@ -5828,7 +5844,7 @@ function $TemplateCacheProvider() {
5828
5844
  *
5829
5845
  *
5830
5846
  * #### `bindToController`
5831
- * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController` will
5847
+ * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
5832
5848
  * allow a component to have its properties bound to the controller, rather than to scope. When the controller
5833
5849
  * is instantiated, the initial values of the isolate scope bindings are already available.
5834
5850
  *
@@ -6677,16 +6693,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6677
6693
 
6678
6694
  // for each tuples
6679
6695
  var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
6680
- for (var i=0; i<nbrUrisWith2parts; i++) {
6681
- var innerIdx = i*2;
6696
+ for (var i = 0; i < nbrUrisWith2parts; i++) {
6697
+ var innerIdx = i * 2;
6682
6698
  // sanitize the uri
6683
6699
  result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
6684
6700
  // add the descriptor
6685
- result += (" " + trim(rawUris[innerIdx+1]));
6701
+ result += (" " + trim(rawUris[innerIdx + 1]));
6686
6702
  }
6687
6703
 
6688
6704
  // split the last item into uri and descriptor
6689
- var lastTuple = trim(rawUris[i*2]).split(/\s/);
6705
+ var lastTuple = trim(rawUris[i * 2]).split(/\s/);
6690
6706
 
6691
6707
  // sanitize the last uri
6692
6708
  result += $$sanitizeUri(trim(lastTuple[0]), true);
@@ -6880,7 +6896,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6880
6896
  if (!node) {
6881
6897
  return 'html';
6882
6898
  } else {
6883
- return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg': 'html';
6899
+ return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
6884
6900
  }
6885
6901
  }
6886
6902
 
@@ -7693,7 +7709,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7693
7709
  var match = null;
7694
7710
  if (hasDirectives.hasOwnProperty(name)) {
7695
7711
  for (var directive, directives = $injector.get(name + Suffix),
7696
- i = 0, ii = directives.length; i<ii; i++) {
7712
+ i = 0, ii = directives.length; i < ii; i++) {
7697
7713
  try {
7698
7714
  directive = directives[i];
7699
7715
  if ((maxPriority === undefined || maxPriority > directive.priority) &&
@@ -7722,7 +7738,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7722
7738
  function directiveIsMultiElement(name) {
7723
7739
  if (hasDirectives.hasOwnProperty(name)) {
7724
7740
  for (var directive, directives = $injector.get(name + Suffix),
7725
- i = 0, ii = directives.length; i<ii; i++) {
7741
+ i = 0, ii = directives.length; i < ii; i++) {
7726
7742
  directive = directives[i];
7727
7743
  if (directive.multiElement) {
7728
7744
  return true;
@@ -7875,10 +7891,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7875
7891
  var childBoundTranscludeFn = boundTranscludeFn;
7876
7892
  if (scope.$$destroyed) return;
7877
7893
  if (linkQueue) {
7878
- linkQueue.push(scope);
7879
- linkQueue.push(node);
7880
- linkQueue.push(rootElement);
7881
- linkQueue.push(childBoundTranscludeFn);
7894
+ linkQueue.push(scope,
7895
+ node,
7896
+ rootElement,
7897
+ childBoundTranscludeFn);
7882
7898
  } else {
7883
7899
  if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
7884
7900
  childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
@@ -7941,7 +7957,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7941
7957
  case 'svg':
7942
7958
  case 'math':
7943
7959
  var wrapper = document.createElement('div');
7944
- wrapper.innerHTML = '<'+type+'>'+template+'</'+type+'>';
7960
+ wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
7945
7961
  return wrapper.childNodes[0].childNodes;
7946
7962
  default:
7947
7963
  return template;
@@ -8298,6 +8314,10 @@ function $ControllerProvider() {
8298
8314
  * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
8299
8315
  * `window` object (not recommended)
8300
8316
  *
8317
+ * The string can use the `controller as property` syntax, where the controller instance is published
8318
+ * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
8319
+ * to work correctly.
8320
+ *
8301
8321
  * @param {Object} locals Injection locals for Controller.
8302
8322
  * @return {Object} Instance of given controller.
8303
8323
  *
@@ -8343,10 +8363,10 @@ function $ControllerProvider() {
8343
8363
  //
8344
8364
  // This feature is not intended for use by applications, and is thus not documented
8345
8365
  // publicly.
8346
- var Constructor = function() {};
8347
- Constructor.prototype = (isArray(expression) ?
8366
+ // Object creation: http://jsperf.com/create-constructor/2
8367
+ var controllerPrototype = (isArray(expression) ?
8348
8368
  expression[expression.length - 1] : expression).prototype;
8349
- instance = new Constructor();
8369
+ instance = Object.create(controllerPrototype);
8350
8370
 
8351
8371
  if (identifier) {
8352
8372
  addIdentifier(locals, identifier, instance, constructor || expression.name);
@@ -8472,7 +8492,7 @@ function defaultHttpResponseTransform(data, headers) {
8472
8492
  // strip json vulnerability protection prefix
8473
8493
  data = data.replace(JSON_PROTECTION_PREFIX, '');
8474
8494
  var contentType = headers('Content-Type');
8475
- if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
8495
+ if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0 && data.trim()) ||
8476
8496
  (JSON_START.test(data) && JSON_END.test(data))) {
8477
8497
  data = fromJson(data);
8478
8498
  }
@@ -8487,7 +8507,7 @@ function defaultHttpResponseTransform(data, headers) {
8487
8507
  * @returns {Object} Parsed headers as key value object
8488
8508
  */
8489
8509
  function parseHeaders(headers) {
8490
- var parsed = {}, key, val, i;
8510
+ var parsed = createMap(), key, val, i;
8491
8511
 
8492
8512
  if (!headers) return parsed;
8493
8513
 
@@ -8524,7 +8544,11 @@ function headersGetter(headers) {
8524
8544
  if (!headersObj) headersObj = parseHeaders(headers);
8525
8545
 
8526
8546
  if (name) {
8527
- return headersObj[lowercase(name)] || null;
8547
+ var value = headersObj[lowercase(name)];
8548
+ if (value === void 0) {
8549
+ value = null;
8550
+ }
8551
+ return value;
8528
8552
  }
8529
8553
 
8530
8554
  return headersObj;
@@ -8573,6 +8597,11 @@ function $HttpProvider() {
8573
8597
  *
8574
8598
  * Object containing default values for all {@link ng.$http $http} requests.
8575
8599
  *
8600
+ * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
8601
+ * that will provide the cache for all requests who set their `cache` property to `true`.
8602
+ * If you set the `default.cache = false` then only requests that specify their own custom
8603
+ * cache object will be cached. See {@link $http#caching $http Caching} for more information.
8604
+ *
8576
8605
  * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
8577
8606
  * Defaults value is `'XSRF-TOKEN'`.
8578
8607
  *
@@ -8586,6 +8615,7 @@ function $HttpProvider() {
8586
8615
  * - **`defaults.headers.post`**
8587
8616
  * - **`defaults.headers.put`**
8588
8617
  * - **`defaults.headers.patch`**
8618
+ *
8589
8619
  **/
8590
8620
  var defaults = this.defaults = {
8591
8621
  // transform incoming response data
@@ -8800,6 +8830,21 @@ function $HttpProvider() {
8800
8830
  * In addition, you can supply a `headers` property in the config object passed when
8801
8831
  * calling `$http(config)`, which overrides the defaults without changing them globally.
8802
8832
  *
8833
+ * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
8834
+ * Use the `headers` property, setting the desired header to `undefined`. For example:
8835
+ *
8836
+ * ```js
8837
+ * var req = {
8838
+ * method: 'POST',
8839
+ * url: 'http://example.com',
8840
+ * headers: {
8841
+ * 'Content-Type': undefined
8842
+ * },
8843
+ * data: { test: 'test' },
8844
+ * }
8845
+ *
8846
+ * $http(req).success(function(){...}).error(function(){...});
8847
+ * ```
8803
8848
  *
8804
8849
  * ## Transforming Requests and Responses
8805
8850
  *
@@ -9179,6 +9224,10 @@ function $HttpProvider() {
9179
9224
  };
9180
9225
  var headers = mergeHeaders(requestConfig);
9181
9226
 
9227
+ if (!angular.isObject(requestConfig)) {
9228
+ throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
9229
+ }
9230
+
9182
9231
  extend(config, requestConfig);
9183
9232
  config.headers = headers;
9184
9233
  config.method = uppercase(config.method);
@@ -10043,7 +10092,8 @@ function $InterpolateProvider() {
10043
10092
 
10044
10093
  function parseStringifyInterceptor(value) {
10045
10094
  try {
10046
- return stringify(getValue(value));
10095
+ value = getValue(value);
10096
+ return allOrNothing && !isDefined(value) ? value : stringify(value);
10047
10097
  } catch (err) {
10048
10098
  var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
10049
10099
  err.toString());
@@ -10367,8 +10417,8 @@ function encodePath(path) {
10367
10417
  return segments.join('/');
10368
10418
  }
10369
10419
 
10370
- function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
10371
- var parsedUrl = urlResolve(absoluteUrl, appBase);
10420
+ function parseAbsoluteUrl(absoluteUrl, locationObj) {
10421
+ var parsedUrl = urlResolve(absoluteUrl);
10372
10422
 
10373
10423
  locationObj.$$protocol = parsedUrl.protocol;
10374
10424
  locationObj.$$host = parsedUrl.hostname;
@@ -10376,12 +10426,12 @@ function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
10376
10426
  }
10377
10427
 
10378
10428
 
10379
- function parseAppUrl(relativeUrl, locationObj, appBase) {
10429
+ function parseAppUrl(relativeUrl, locationObj) {
10380
10430
  var prefixed = (relativeUrl.charAt(0) !== '/');
10381
10431
  if (prefixed) {
10382
10432
  relativeUrl = '/' + relativeUrl;
10383
10433
  }
10384
- var match = urlResolve(relativeUrl, appBase);
10434
+ var match = urlResolve(relativeUrl);
10385
10435
  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
10386
10436
  match.pathname.substring(1) : match.pathname);
10387
10437
  locationObj.$$search = parseKeyValue(match.search);
@@ -10436,7 +10486,7 @@ function LocationHtml5Url(appBase, basePrefix) {
10436
10486
  this.$$html5 = true;
10437
10487
  basePrefix = basePrefix || '';
10438
10488
  var appBaseNoFile = stripFile(appBase);
10439
- parseAbsoluteUrl(appBase, this, appBase);
10489
+ parseAbsoluteUrl(appBase, this);
10440
10490
 
10441
10491
 
10442
10492
  /**
@@ -10451,7 +10501,7 @@ function LocationHtml5Url(appBase, basePrefix) {
10451
10501
  appBaseNoFile);
10452
10502
  }
10453
10503
 
10454
- parseAppUrl(pathUrl, this, appBase);
10504
+ parseAppUrl(pathUrl, this);
10455
10505
 
10456
10506
  if (!this.$$path) {
10457
10507
  this.$$path = '/';
@@ -10514,7 +10564,7 @@ function LocationHtml5Url(appBase, basePrefix) {
10514
10564
  function LocationHashbangUrl(appBase, hashPrefix) {
10515
10565
  var appBaseNoFile = stripFile(appBase);
10516
10566
 
10517
- parseAbsoluteUrl(appBase, this, appBase);
10567
+ parseAbsoluteUrl(appBase, this);
10518
10568
 
10519
10569
 
10520
10570
  /**
@@ -10534,7 +10584,7 @@ function LocationHashbangUrl(appBase, hashPrefix) {
10534
10584
  throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
10535
10585
  hashPrefix);
10536
10586
  }
10537
- parseAppUrl(withoutHashUrl, this, appBase);
10587
+ parseAppUrl(withoutHashUrl, this);
10538
10588
 
10539
10589
  this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
10540
10590
 
@@ -10672,6 +10722,13 @@ var locationPrototype = {
10672
10722
  * Return full url representation with all segments encoded according to rules specified in
10673
10723
  * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
10674
10724
  *
10725
+ *
10726
+ * ```js
10727
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10728
+ * var absUrl = $location.absUrl();
10729
+ * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
10730
+ * ```
10731
+ *
10675
10732
  * @return {string} full url
10676
10733
  */
10677
10734
  absUrl: locationGetter('$$absUrl'),
@@ -10687,6 +10744,13 @@ var locationPrototype = {
10687
10744
  *
10688
10745
  * Change path, search and hash, when called with parameter and return `$location`.
10689
10746
  *
10747
+ *
10748
+ * ```js
10749
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10750
+ * var url = $location.url();
10751
+ * // => "/some/path?foo=bar&baz=xoxo"
10752
+ * ```
10753
+ *
10690
10754
  * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
10691
10755
  * @return {string} url
10692
10756
  */
@@ -10695,8 +10759,8 @@ var locationPrototype = {
10695
10759
  return this.$$url;
10696
10760
 
10697
10761
  var match = PATH_MATCH.exec(url);
10698
- if (match[1]) this.path(decodeURIComponent(match[1]));
10699
- if (match[2] || match[1]) this.search(match[3] || '');
10762
+ if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
10763
+ if (match[2] || match[1] || url === '') this.search(match[3] || '');
10700
10764
  this.hash(match[5] || '');
10701
10765
 
10702
10766
  return this;
@@ -10711,6 +10775,13 @@ var locationPrototype = {
10711
10775
  *
10712
10776
  * Return protocol of current url.
10713
10777
  *
10778
+ *
10779
+ * ```js
10780
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10781
+ * var protocol = $location.protocol();
10782
+ * // => "http"
10783
+ * ```
10784
+ *
10714
10785
  * @return {string} protocol of current url
10715
10786
  */
10716
10787
  protocol: locationGetter('$$protocol'),
@@ -10724,6 +10795,13 @@ var locationPrototype = {
10724
10795
  *
10725
10796
  * Return host of current url.
10726
10797
  *
10798
+ *
10799
+ * ```js
10800
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10801
+ * var host = $location.host();
10802
+ * // => "example.com"
10803
+ * ```
10804
+ *
10727
10805
  * @return {string} host of current url.
10728
10806
  */
10729
10807
  host: locationGetter('$$host'),
@@ -10737,6 +10815,13 @@ var locationPrototype = {
10737
10815
  *
10738
10816
  * Return port of current url.
10739
10817
  *
10818
+ *
10819
+ * ```js
10820
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10821
+ * var port = $location.port();
10822
+ * // => 80
10823
+ * ```
10824
+ *
10740
10825
  * @return {Number} port
10741
10826
  */
10742
10827
  port: locationGetter('$$port'),
@@ -10755,6 +10840,13 @@ var locationPrototype = {
10755
10840
  * Note: Path should always begin with forward slash (/), this method will add the forward slash
10756
10841
  * if it is missing.
10757
10842
  *
10843
+ *
10844
+ * ```js
10845
+ * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
10846
+ * var path = $location.path();
10847
+ * // => "/some/path"
10848
+ * ```
10849
+ *
10758
10850
  * @param {(string|number)=} path New path
10759
10851
  * @return {string} path
10760
10852
  */
@@ -10780,10 +10872,9 @@ var locationPrototype = {
10780
10872
  * var searchObject = $location.search();
10781
10873
  * // => {foo: 'bar', baz: 'xoxo'}
10782
10874
  *
10783
- *
10784
10875
  * // set foo to 'yipee'
10785
10876
  * $location.search('foo', 'yipee');
10786
- * // => $location
10877
+ * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
10787
10878
  * ```
10788
10879
  *
10789
10880
  * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
@@ -10853,6 +10944,13 @@ var locationPrototype = {
10853
10944
  *
10854
10945
  * Change hash fragment when called with parameter and return `$location`.
10855
10946
  *
10947
+ *
10948
+ * ```js
10949
+ * // given url http://example.com/some/path?foo=bar&baz=xoxo#hashValue
10950
+ * var hash = $location.hash();
10951
+ * // => "hashValue"
10952
+ * ```
10953
+ *
10856
10954
  * @param {(string|number)=} hash New hash fragment
10857
10955
  * @return {string} hash
10858
10956
  */
@@ -11174,11 +11272,19 @@ function $LocationProvider() {
11174
11272
  $rootScope.$evalAsync(function() {
11175
11273
  var oldUrl = $location.absUrl();
11176
11274
  var oldState = $location.$$state;
11275
+ var defaultPrevented;
11177
11276
 
11178
11277
  $location.$$parse(newUrl);
11179
11278
  $location.$$state = newState;
11180
- if ($rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11181
- newState, oldState).defaultPrevented) {
11279
+
11280
+ defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11281
+ newState, oldState).defaultPrevented;
11282
+
11283
+ // if the location was changed by a `$locationChangeStart` handler then stop
11284
+ // processing this location change
11285
+ if ($location.absUrl() !== newUrl) return;
11286
+
11287
+ if (defaultPrevented) {
11182
11288
  $location.$$parse(oldUrl);
11183
11289
  $location.$$state = oldState;
11184
11290
  setBrowserUrlWithFallback(oldUrl, false, oldState);
@@ -11202,13 +11308,20 @@ function $LocationProvider() {
11202
11308
  initializing = false;
11203
11309
 
11204
11310
  $rootScope.$evalAsync(function() {
11205
- if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl,
11206
- $location.$$state, oldState).defaultPrevented) {
11311
+ var newUrl = $location.absUrl();
11312
+ var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
11313
+ $location.$$state, oldState).defaultPrevented;
11314
+
11315
+ // if the location was changed by a `$locationChangeStart` handler then stop
11316
+ // processing this location change
11317
+ if ($location.absUrl() !== newUrl) return;
11318
+
11319
+ if (defaultPrevented) {
11207
11320
  $location.$$parse(oldUrl);
11208
11321
  $location.$$state = oldState;
11209
11322
  } else {
11210
11323
  if (urlOrStateChanged) {
11211
- setBrowserUrlWithFallback($location.absUrl(), currentReplace,
11324
+ setBrowserUrlWithFallback(newUrl, currentReplace,
11212
11325
  oldState === $location.$$state ? null : $location.$$state);
11213
11326
  }
11214
11327
  afterLocationChange(oldUrl, oldState);
@@ -11398,7 +11511,7 @@ var $parseMinErr = minErr('$parse');
11398
11511
  // Sandboxing Angular Expressions
11399
11512
  // ------------------------------
11400
11513
  // Angular expressions are generally considered safe because these expressions only have direct
11401
- // access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
11514
+ // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
11402
11515
  // obtaining a reference to native JS functions such as the Function constructor.
11403
11516
  //
11404
11517
  // As an example, consider the following Angular expression:
@@ -11407,7 +11520,7 @@ var $parseMinErr = minErr('$parse');
11407
11520
  //
11408
11521
  // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
11409
11522
  // against the expression language, but not to prevent exploits that were enabled by exposing
11410
- // sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
11523
+ // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
11411
11524
  // practice and therefore we are not even trying to protect against interaction with an object
11412
11525
  // explicitly exposed in this way.
11413
11526
  //
@@ -11415,6 +11528,8 @@ var $parseMinErr = minErr('$parse');
11415
11528
  // window or some DOM object that has a reference to window is published onto a Scope.
11416
11529
  // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
11417
11530
  // native objects.
11531
+ //
11532
+ // See https://docs.angularjs.org/guide/security
11418
11533
 
11419
11534
 
11420
11535
  function ensureSafeMemberName(name, fullExpression) {
@@ -11423,7 +11538,7 @@ function ensureSafeMemberName(name, fullExpression) {
11423
11538
  || name === "__proto__") {
11424
11539
  throw $parseMinErr('isecfld',
11425
11540
  'Attempting to access a disallowed field in Angular expressions! '
11426
- +'Expression: {0}', fullExpression);
11541
+ + 'Expression: {0}', fullExpression);
11427
11542
  }
11428
11543
  return name;
11429
11544
  }
@@ -11500,24 +11615,24 @@ var OPERATORS = extend(createMap(), {
11500
11615
  }
11501
11616
  return a;
11502
11617
  }
11503
- return isDefined(b)?b:undefined;},
11618
+ return isDefined(b) ? b : undefined;},
11504
11619
  '-':function(self, locals, a, b) {
11505
11620
  a=a(self, locals); b=b(self, locals);
11506
- return (isDefined(a)?a:0)-(isDefined(b)?b:0);
11621
+ return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
11507
11622
  },
11508
- '*':function(self, locals, a, b) {return a(self, locals)*b(self, locals);},
11509
- '/':function(self, locals, a, b) {return a(self, locals)/b(self, locals);},
11510
- '%':function(self, locals, a, b) {return a(self, locals)%b(self, locals);},
11511
- '===':function(self, locals, a, b) {return a(self, locals)===b(self, locals);},
11512
- '!==':function(self, locals, a, b) {return a(self, locals)!==b(self, locals);},
11513
- '==':function(self, locals, a, b) {return a(self, locals)==b(self, locals);},
11514
- '!=':function(self, locals, a, b) {return a(self, locals)!=b(self, locals);},
11515
- '<':function(self, locals, a, b) {return a(self, locals)<b(self, locals);},
11516
- '>':function(self, locals, a, b) {return a(self, locals)>b(self, locals);},
11517
- '<=':function(self, locals, a, b) {return a(self, locals)<=b(self, locals);},
11518
- '>=':function(self, locals, a, b) {return a(self, locals)>=b(self, locals);},
11519
- '&&':function(self, locals, a, b) {return a(self, locals)&&b(self, locals);},
11520
- '||':function(self, locals, a, b) {return a(self, locals)||b(self, locals);},
11623
+ '*':function(self, locals, a, b) {return a(self, locals) * b(self, locals);},
11624
+ '/':function(self, locals, a, b) {return a(self, locals) / b(self, locals);},
11625
+ '%':function(self, locals, a, b) {return a(self, locals) % b(self, locals);},
11626
+ '===':function(self, locals, a, b) {return a(self, locals) === b(self, locals);},
11627
+ '!==':function(self, locals, a, b) {return a(self, locals) !== b(self, locals);},
11628
+ '==':function(self, locals, a, b) {return a(self, locals) == b(self, locals);},
11629
+ '!=':function(self, locals, a, b) {return a(self, locals) != b(self, locals);},
11630
+ '<':function(self, locals, a, b) {return a(self, locals) < b(self, locals);},
11631
+ '>':function(self, locals, a, b) {return a(self, locals) > b(self, locals);},
11632
+ '<=':function(self, locals, a, b) {return a(self, locals) <= b(self, locals);},
11633
+ '>=':function(self, locals, a, b) {return a(self, locals) >= b(self, locals);},
11634
+ '&&':function(self, locals, a, b) {return a(self, locals) && b(self, locals);},
11635
+ '||':function(self, locals, a, b) {return a(self, locals) || b(self, locals);},
11521
11636
  '!':function(self, locals, a) {return !a(self, locals);},
11522
11637
 
11523
11638
  //Tokenized as operators but parsed as assignment/filters
@@ -11543,44 +11658,31 @@ Lexer.prototype = {
11543
11658
  lex: function(text) {
11544
11659
  this.text = text;
11545
11660
  this.index = 0;
11546
- this.ch = undefined;
11547
11661
  this.tokens = [];
11548
11662
 
11549
11663
  while (this.index < this.text.length) {
11550
- this.ch = this.text.charAt(this.index);
11551
- if (this.is('"\'')) {
11552
- this.readString(this.ch);
11553
- } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
11664
+ var ch = this.text.charAt(this.index);
11665
+ if (ch === '"' || ch === "'") {
11666
+ this.readString(ch);
11667
+ } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
11554
11668
  this.readNumber();
11555
- } else if (this.isIdent(this.ch)) {
11669
+ } else if (this.isIdent(ch)) {
11556
11670
  this.readIdent();
11557
- } else if (this.is('(){}[].,;:?')) {
11558
- this.tokens.push({
11559
- index: this.index,
11560
- text: this.ch
11561
- });
11671
+ } else if (this.is(ch, '(){}[].,;:?')) {
11672
+ this.tokens.push({index: this.index, text: ch});
11562
11673
  this.index++;
11563
- } else if (this.isWhitespace(this.ch)) {
11674
+ } else if (this.isWhitespace(ch)) {
11564
11675
  this.index++;
11565
11676
  } else {
11566
- var ch2 = this.ch + this.peek();
11677
+ var ch2 = ch + this.peek();
11567
11678
  var ch3 = ch2 + this.peek(2);
11568
- var fn = OPERATORS[this.ch];
11569
- var fn2 = OPERATORS[ch2];
11570
- var fn3 = OPERATORS[ch3];
11571
- if (fn3) {
11572
- this.tokens.push({index: this.index, text: ch3, fn: fn3});
11573
- this.index += 3;
11574
- } else if (fn2) {
11575
- this.tokens.push({index: this.index, text: ch2, fn: fn2});
11576
- this.index += 2;
11577
- } else if (fn) {
11578
- this.tokens.push({
11579
- index: this.index,
11580
- text: this.ch,
11581
- fn: fn
11582
- });
11583
- this.index += 1;
11679
+ var op1 = OPERATORS[ch];
11680
+ var op2 = OPERATORS[ch2];
11681
+ var op3 = OPERATORS[ch3];
11682
+ if (op1 || op2 || op3) {
11683
+ var token = op3 ? ch3 : (op2 ? ch2 : ch);
11684
+ this.tokens.push({index: this.index, text: token, operator: true});
11685
+ this.index += token.length;
11584
11686
  } else {
11585
11687
  this.throwError('Unexpected next character ', this.index, this.index + 1);
11586
11688
  }
@@ -11589,8 +11691,8 @@ Lexer.prototype = {
11589
11691
  return this.tokens;
11590
11692
  },
11591
11693
 
11592
- is: function(chars) {
11593
- return chars.indexOf(this.ch) !== -1;
11694
+ is: function(ch, chars) {
11695
+ return chars.indexOf(ch) !== -1;
11594
11696
  },
11595
11697
 
11596
11698
  peek: function(i) {
@@ -11599,7 +11701,7 @@ Lexer.prototype = {
11599
11701
  },
11600
11702
 
11601
11703
  isNumber: function(ch) {
11602
- return ('0' <= ch && ch <= '9');
11704
+ return ('0' <= ch && ch <= '9') && typeof ch === "string";
11603
11705
  },
11604
11706
 
11605
11707
  isWhitespace: function(ch) {
@@ -11652,79 +11754,28 @@ Lexer.prototype = {
11652
11754
  }
11653
11755
  this.index++;
11654
11756
  }
11655
- number = 1 * number;
11656
11757
  this.tokens.push({
11657
11758
  index: start,
11658
11759
  text: number,
11659
11760
  constant: true,
11660
- fn: function() { return number; }
11761
+ value: Number(number)
11661
11762
  });
11662
11763
  },
11663
11764
 
11664
11765
  readIdent: function() {
11665
- var expression = this.text;
11666
-
11667
- var ident = '';
11668
11766
  var start = this.index;
11669
-
11670
- var lastDot, peekIndex, methodName, ch;
11671
-
11672
11767
  while (this.index < this.text.length) {
11673
- ch = this.text.charAt(this.index);
11674
- if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
11675
- if (ch === '.') lastDot = this.index;
11676
- ident += ch;
11677
- } else {
11768
+ var ch = this.text.charAt(this.index);
11769
+ if (!(this.isIdent(ch) || this.isNumber(ch))) {
11678
11770
  break;
11679
11771
  }
11680
11772
  this.index++;
11681
11773
  }
11682
-
11683
- //check if the identifier ends with . and if so move back one char
11684
- if (lastDot && ident[ident.length - 1] === '.') {
11685
- this.index--;
11686
- ident = ident.slice(0, -1);
11687
- lastDot = ident.lastIndexOf('.');
11688
- if (lastDot === -1) {
11689
- lastDot = undefined;
11690
- }
11691
- }
11692
-
11693
- //check if this is not a method invocation and if it is back out to last dot
11694
- if (lastDot) {
11695
- peekIndex = this.index;
11696
- while (peekIndex < this.text.length) {
11697
- ch = this.text.charAt(peekIndex);
11698
- if (ch === '(') {
11699
- methodName = ident.substr(lastDot - start + 1);
11700
- ident = ident.substr(0, lastDot - start);
11701
- this.index = peekIndex;
11702
- break;
11703
- }
11704
- if (this.isWhitespace(ch)) {
11705
- peekIndex++;
11706
- } else {
11707
- break;
11708
- }
11709
- }
11710
- }
11711
-
11712
11774
  this.tokens.push({
11713
11775
  index: start,
11714
- text: ident,
11715
- fn: CONSTANTS[ident] || getterFn(ident, this.options, expression)
11776
+ text: this.text.slice(start, this.index),
11777
+ identifier: true
11716
11778
  });
11717
-
11718
- if (methodName) {
11719
- this.tokens.push({
11720
- index: lastDot,
11721
- text: '.'
11722
- });
11723
- this.tokens.push({
11724
- index: lastDot + 1,
11725
- text: methodName
11726
- });
11727
- }
11728
11779
  },
11729
11780
 
11730
11781
  readString: function(quote) {
@@ -11755,9 +11806,8 @@ Lexer.prototype = {
11755
11806
  this.tokens.push({
11756
11807
  index: start,
11757
11808
  text: rawString,
11758
- string: string,
11759
11809
  constant: true,
11760
- fn: function() { return string; }
11810
+ value: string
11761
11811
  });
11762
11812
  return;
11763
11813
  } else {
@@ -11818,16 +11868,12 @@ Parser.prototype = {
11818
11868
  primary = this.arrayDeclaration();
11819
11869
  } else if (this.expect('{')) {
11820
11870
  primary = this.object();
11871
+ } else if (this.peek().identifier) {
11872
+ primary = this.identifier();
11873
+ } else if (this.peek().constant) {
11874
+ primary = this.constant();
11821
11875
  } else {
11822
- var token = this.expect();
11823
- primary = token.fn;
11824
- if (!primary) {
11825
- this.throwError('not a primary expression', token);
11826
- }
11827
- if (token.constant) {
11828
- primary.constant = true;
11829
- primary.literal = true;
11830
- }
11876
+ this.throwError('not a primary expression', this.peek());
11831
11877
  }
11832
11878
 
11833
11879
  var next, context;
@@ -11861,8 +11907,11 @@ Parser.prototype = {
11861
11907
  },
11862
11908
 
11863
11909
  peek: function(e1, e2, e3, e4) {
11864
- if (this.tokens.length > 0) {
11865
- var token = this.tokens[0];
11910
+ return this.peekAhead(0, e1, e2, e3, e4);
11911
+ },
11912
+ peekAhead: function(i, e1, e2, e3, e4) {
11913
+ if (this.tokens.length > i) {
11914
+ var token = this.tokens[i];
11866
11915
  var t = token.text;
11867
11916
  if (t === e1 || t === e2 || t === e3 || t === e4 ||
11868
11917
  (!e1 && !e2 && !e3 && !e4)) {
@@ -11882,12 +11931,19 @@ Parser.prototype = {
11882
11931
  },
11883
11932
 
11884
11933
  consume: function(e1) {
11885
- if (!this.expect(e1)) {
11934
+ if (this.tokens.length === 0) {
11935
+ throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
11936
+ }
11937
+
11938
+ var token = this.expect(e1);
11939
+ if (!token) {
11886
11940
  this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
11887
11941
  }
11942
+ return token;
11888
11943
  },
11889
11944
 
11890
- unaryFn: function(fn, right) {
11945
+ unaryFn: function(op, right) {
11946
+ var fn = OPERATORS[op];
11891
11947
  return extend(function $parseUnaryFn(self, locals) {
11892
11948
  return fn(self, locals, right);
11893
11949
  }, {
@@ -11896,7 +11952,8 @@ Parser.prototype = {
11896
11952
  });
11897
11953
  },
11898
11954
 
11899
- binaryFn: function(left, fn, right, isBranching) {
11955
+ binaryFn: function(left, op, right, isBranching) {
11956
+ var fn = OPERATORS[op];
11900
11957
  return extend(function $parseBinaryFn(self, locals) {
11901
11958
  return fn(self, locals, left, right);
11902
11959
  }, {
@@ -11905,6 +11962,28 @@ Parser.prototype = {
11905
11962
  });
11906
11963
  },
11907
11964
 
11965
+ identifier: function() {
11966
+ var id = this.consume().text;
11967
+
11968
+ //Continue reading each `.identifier` unless it is a method invocation
11969
+ while (this.peek('.') && this.peekAhead(1).identifier && !this.peekAhead(2, '(')) {
11970
+ id += this.consume().text + this.consume().text;
11971
+ }
11972
+
11973
+ return CONSTANTS[id] || getterFn(id, this.options, this.text);
11974
+ },
11975
+
11976
+ constant: function() {
11977
+ var value = this.consume().value;
11978
+
11979
+ return extend(function $parseConstant() {
11980
+ return value;
11981
+ }, {
11982
+ constant: true,
11983
+ literal: true
11984
+ });
11985
+ },
11986
+
11908
11987
  statements: function() {
11909
11988
  var statements = [];
11910
11989
  while (true) {
@@ -11936,8 +12015,7 @@ Parser.prototype = {
11936
12015
  },
11937
12016
 
11938
12017
  filter: function(inputFn) {
11939
- var token = this.expect();
11940
- var fn = this.$filter(token.text);
12018
+ var fn = this.$filter(this.consume().text);
11941
12019
  var argsFn;
11942
12020
  var args;
11943
12021
 
@@ -12000,7 +12078,7 @@ Parser.prototype = {
12000
12078
  var token;
12001
12079
  if ((token = this.expect('?'))) {
12002
12080
  middle = this.assignment();
12003
- if ((token = this.expect(':'))) {
12081
+ if (this.consume(':')) {
12004
12082
  var right = this.assignment();
12005
12083
 
12006
12084
  return extend(function $parseTernary(self, locals) {
@@ -12008,9 +12086,6 @@ Parser.prototype = {
12008
12086
  }, {
12009
12087
  constant: left.constant && middle.constant && right.constant
12010
12088
  });
12011
-
12012
- } else {
12013
- this.throwError('expected :', token);
12014
12089
  }
12015
12090
  }
12016
12091
 
@@ -12021,7 +12096,7 @@ Parser.prototype = {
12021
12096
  var left = this.logicalAND();
12022
12097
  var token;
12023
12098
  while ((token = this.expect('||'))) {
12024
- left = this.binaryFn(left, token.fn, this.logicalAND(), true);
12099
+ left = this.binaryFn(left, token.text, this.logicalAND(), true);
12025
12100
  }
12026
12101
  return left;
12027
12102
  },
@@ -12030,7 +12105,7 @@ Parser.prototype = {
12030
12105
  var left = this.equality();
12031
12106
  var token;
12032
12107
  if ((token = this.expect('&&'))) {
12033
- left = this.binaryFn(left, token.fn, this.logicalAND(), true);
12108
+ left = this.binaryFn(left, token.text, this.logicalAND(), true);
12034
12109
  }
12035
12110
  return left;
12036
12111
  },
@@ -12039,7 +12114,7 @@ Parser.prototype = {
12039
12114
  var left = this.relational();
12040
12115
  var token;
12041
12116
  if ((token = this.expect('==','!=','===','!=='))) {
12042
- left = this.binaryFn(left, token.fn, this.equality());
12117
+ left = this.binaryFn(left, token.text, this.equality());
12043
12118
  }
12044
12119
  return left;
12045
12120
  },
@@ -12048,7 +12123,7 @@ Parser.prototype = {
12048
12123
  var left = this.additive();
12049
12124
  var token;
12050
12125
  if ((token = this.expect('<', '>', '<=', '>='))) {
12051
- left = this.binaryFn(left, token.fn, this.relational());
12126
+ left = this.binaryFn(left, token.text, this.relational());
12052
12127
  }
12053
12128
  return left;
12054
12129
  },
@@ -12057,7 +12132,7 @@ Parser.prototype = {
12057
12132
  var left = this.multiplicative();
12058
12133
  var token;
12059
12134
  while ((token = this.expect('+','-'))) {
12060
- left = this.binaryFn(left, token.fn, this.multiplicative());
12135
+ left = this.binaryFn(left, token.text, this.multiplicative());
12061
12136
  }
12062
12137
  return left;
12063
12138
  },
@@ -12066,7 +12141,7 @@ Parser.prototype = {
12066
12141
  var left = this.unary();
12067
12142
  var token;
12068
12143
  while ((token = this.expect('*','/','%'))) {
12069
- left = this.binaryFn(left, token.fn, this.unary());
12144
+ left = this.binaryFn(left, token.text, this.unary());
12070
12145
  }
12071
12146
  return left;
12072
12147
  },
@@ -12076,9 +12151,9 @@ Parser.prototype = {
12076
12151
  if (this.expect('+')) {
12077
12152
  return this.primary();
12078
12153
  } else if ((token = this.expect('-'))) {
12079
- return this.binaryFn(Parser.ZERO, token.fn, this.unary());
12154
+ return this.binaryFn(Parser.ZERO, token.text, this.unary());
12080
12155
  } else if ((token = this.expect('!'))) {
12081
- return this.unaryFn(token.fn, this.unary());
12156
+ return this.unaryFn(token.text, this.unary());
12082
12157
  } else {
12083
12158
  return this.primary();
12084
12159
  }
@@ -12086,7 +12161,7 @@ Parser.prototype = {
12086
12161
 
12087
12162
  fieldAccess: function(object) {
12088
12163
  var expression = this.text;
12089
- var field = this.expect().text;
12164
+ var field = this.consume().text;
12090
12165
  var getter = getterFn(field, this.options, expression);
12091
12166
 
12092
12167
  return extend(function $parseFieldAccess(scope, locals, self) {
@@ -12171,8 +12246,7 @@ Parser.prototype = {
12171
12246
  // Support trailing commas per ES5.1.
12172
12247
  break;
12173
12248
  }
12174
- var elementFn = this.expression();
12175
- elementFns.push(elementFn);
12249
+ elementFns.push(this.expression());
12176
12250
  } while (this.expect(','));
12177
12251
  }
12178
12252
  this.consume(']');
@@ -12198,11 +12272,16 @@ Parser.prototype = {
12198
12272
  // Support trailing commas per ES5.1.
12199
12273
  break;
12200
12274
  }
12201
- var token = this.expect();
12202
- keys.push(token.string || token.text);
12275
+ var token = this.consume();
12276
+ if (token.constant) {
12277
+ keys.push(token.value);
12278
+ } else if (token.identifier) {
12279
+ keys.push(token.text);
12280
+ } else {
12281
+ this.throwError("invalid key", token);
12282
+ }
12203
12283
  this.consume(':');
12204
- var value = this.expression();
12205
- valueFns.push(value);
12284
+ valueFns.push(this.expression());
12206
12285
  } while (this.expect(','));
12207
12286
  }
12208
12287
  this.consume('}');
@@ -12644,13 +12723,21 @@ function $ParseProvider() {
12644
12723
 
12645
12724
  function addInterceptor(parsedExpression, interceptorFn) {
12646
12725
  if (!interceptorFn) return parsedExpression;
12726
+ var watchDelegate = parsedExpression.$$watchDelegate;
12647
12727
 
12648
- var fn = function interceptedExpression(scope, locals) {
12728
+ var regularWatch =
12729
+ watchDelegate !== oneTimeLiteralWatchDelegate &&
12730
+ watchDelegate !== oneTimeWatchDelegate;
12731
+
12732
+ var fn = regularWatch ? function regularInterceptedExpression(scope, locals) {
12733
+ var value = parsedExpression(scope, locals);
12734
+ return interceptorFn(value, scope, locals);
12735
+ } : function oneTimeInterceptedExpression(scope, locals) {
12649
12736
  var value = parsedExpression(scope, locals);
12650
12737
  var result = interceptorFn(value, scope, locals);
12651
12738
  // we only return the interceptor's result if the
12652
12739
  // initial value is defined (for bind-once)
12653
- return isDefined(value) || interceptorFn.$stateful ? result : value;
12740
+ return isDefined(value) ? result : value;
12654
12741
  };
12655
12742
 
12656
12743
  // Propagate $$watchDelegates other then inputsWatchDelegate
@@ -12675,7 +12762,11 @@ function $ParseProvider() {
12675
12762
  * @requires $rootScope
12676
12763
  *
12677
12764
  * @description
12678
- * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
12765
+ * A service that helps you run functions asynchronously, and use their return values (or exceptions)
12766
+ * when they are done processing.
12767
+ *
12768
+ * This is an implementation of promises/deferred objects inspired by
12769
+ * [Kris Kowal's Q](https://github.com/kriskowal/q).
12679
12770
  *
12680
12771
  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
12681
12772
  * implementations, and the other which resembles ES6 promises to some degree.
@@ -12811,16 +12902,12 @@ function $ParseProvider() {
12811
12902
  *
12812
12903
  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
12813
12904
  *
12814
- * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
12905
+ * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
12815
12906
  * but to do so without modifying the final value. This is useful to release resources or do some
12816
12907
  * clean-up that needs to be done whether the promise was rejected or resolved. See the [full
12817
12908
  * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
12818
12909
  * more information.
12819
12910
  *
12820
- * Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
12821
- * property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
12822
- * make your code IE8 and Android 2.x compatible.
12823
- *
12824
12911
  * # Chaining promises
12825
12912
  *
12826
12913
  * Because calling the `then` method of a promise returns a new derived promise, it is easily
@@ -14043,11 +14130,11 @@ function $RootScopeProvider() {
14043
14130
  if (ttl < 5) {
14044
14131
  logIdx = 4 - ttl;
14045
14132
  if (!watchLog[logIdx]) watchLog[logIdx] = [];
14046
- logMsg = (isFunction(watch.exp))
14047
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
14048
- : watch.exp;
14049
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
14050
- watchLog[logIdx].push(logMsg);
14133
+ watchLog[logIdx].push({
14134
+ msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
14135
+ newVal: value,
14136
+ oldVal: last
14137
+ });
14051
14138
  }
14052
14139
  } else if (watch === lastDirtyWatch) {
14053
14140
  // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
@@ -14080,7 +14167,7 @@ function $RootScopeProvider() {
14080
14167
  throw $rootScopeMinErr('infdig',
14081
14168
  '{0} $digest() iterations reached. Aborting!\n' +
14082
14169
  'Watchers fired in the last 5 iterations: {1}',
14083
- TTL, toJson(watchLog));
14170
+ TTL, watchLog);
14084
14171
  }
14085
14172
 
14086
14173
  } while (dirty || asyncQueue.length);
@@ -14431,7 +14518,7 @@ function $RootScopeProvider() {
14431
14518
  do {
14432
14519
  namedListeners = scope.$$listeners[name] || empty;
14433
14520
  event.currentScope = scope;
14434
- for (i=0, length=namedListeners.length; i<length; i++) {
14521
+ for (i = 0, length = namedListeners.length; i < length; i++) {
14435
14522
 
14436
14523
  // if listeners were deregistered, defragment the array
14437
14524
  if (!namedListeners[i]) {
@@ -14505,7 +14592,7 @@ function $RootScopeProvider() {
14505
14592
  while ((current = next)) {
14506
14593
  event.currentScope = current;
14507
14594
  listeners = current.$$listeners[name] || [];
14508
- for (i=0, length = listeners.length; i<length; i++) {
14595
+ for (i = 0, length = listeners.length; i < length; i++) {
14509
14596
  // if listeners were deregistered, defragment the array
14510
14597
  if (!listeners[i]) {
14511
14598
  listeners.splice(i, 1);
@@ -14661,7 +14748,7 @@ function $$SanitizeUriProvider() {
14661
14748
  var normalizedVal;
14662
14749
  normalizedVal = urlResolve(uri).href;
14663
14750
  if (normalizedVal !== '' && !normalizedVal.match(regex)) {
14664
- return 'unsafe:'+normalizedVal;
14751
+ return 'unsafe:' + normalizedVal;
14665
14752
  }
14666
14753
  return uri;
14667
14754
  };
@@ -15760,7 +15847,7 @@ function $SnifferProvider() {
15760
15847
  transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
15761
15848
  animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
15762
15849
 
15763
- if (android && (!transitions||!animations)) {
15850
+ if (android && (!transitions || !animations)) {
15764
15851
  transitions = isString(document.body.style.webkitTransition);
15765
15852
  animations = isString(document.body.style.webkitAnimation);
15766
15853
  }
@@ -15831,7 +15918,7 @@ function $TemplateRequestProvider() {
15831
15918
  if (isArray(transformResponse)) {
15832
15919
  var original = transformResponse;
15833
15920
  transformResponse = [];
15834
- for (var i=0; i<original.length; ++i) {
15921
+ for (var i = 0; i < original.length; ++i) {
15835
15922
  var transformer = original[i];
15836
15923
  if (transformer !== defaultHttpResponseTransform) {
15837
15924
  transformResponse.push(transformer);
@@ -16075,7 +16162,7 @@ function $TimeoutProvider() {
16075
16162
  // exactly the behavior needed here. There is little value is mocking these out for this
16076
16163
  // service.
16077
16164
  var urlParsingNode = document.createElement("a");
16078
- var originUrl = urlResolve(window.location.href, true);
16165
+ var originUrl = urlResolve(window.location.href);
16079
16166
 
16080
16167
 
16081
16168
  /**
@@ -16130,7 +16217,7 @@ var originUrl = urlResolve(window.location.href, true);
16130
16217
  * | pathname | The pathname, beginning with "/"
16131
16218
  *
16132
16219
  */
16133
- function urlResolve(url, base) {
16220
+ function urlResolve(url) {
16134
16221
  var href = url;
16135
16222
 
16136
16223
  if (msie) {
@@ -16510,8 +16597,8 @@ function filterFilter() {
16510
16597
  }
16511
16598
  return false;
16512
16599
  }
16513
- text = (''+text).toLowerCase();
16514
- return (''+obj).toLowerCase().indexOf(text) > -1;
16600
+ text = ('' + text).toLowerCase();
16601
+ return ('' + obj).toLowerCase().indexOf(text) > -1;
16515
16602
  };
16516
16603
  }
16517
16604
  }
@@ -16595,7 +16682,7 @@ function filterFilter() {
16595
16682
  *
16596
16683
  * @param {number} amount Input to filter.
16597
16684
  * @param {string=} symbol Currency symbol or identifier to be displayed.
16598
- * @param {number=} fractionSize Number of decimal places to round the amount to.
16685
+ * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
16599
16686
  * @returns {string} Formatted number.
16600
16687
  *
16601
16688
  *
@@ -16645,8 +16732,7 @@ function currencyFilter($locale) {
16645
16732
  }
16646
16733
 
16647
16734
  if (isUndefined(fractionSize)) {
16648
- // TODO: read the default value from the locale file
16649
- fractionSize = 2;
16735
+ fractionSize = formats.PATTERNS[1].maxFrac;
16650
16736
  }
16651
16737
 
16652
16738
  // if null or undefined pass it through
@@ -16771,7 +16857,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16771
16857
  if (whole.length >= (lgroup + group)) {
16772
16858
  pos = whole.length - lgroup;
16773
16859
  for (i = 0; i < pos; i++) {
16774
- if ((pos - i)%group === 0 && i !== 0) {
16860
+ if ((pos - i) % group === 0 && i !== 0) {
16775
16861
  formatedText += groupSep;
16776
16862
  }
16777
16863
  formatedText += whole.charAt(i);
@@ -16779,7 +16865,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16779
16865
  }
16780
16866
 
16781
16867
  for (i = pos; i < whole.length; i++) {
16782
- if ((whole.length - i)%lgroup === 0 && i !== 0) {
16868
+ if ((whole.length - i) % lgroup === 0 && i !== 0) {
16783
16869
  formatedText += groupSep;
16784
16870
  }
16785
16871
  formatedText += whole.charAt(i);
@@ -16798,9 +16884,9 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16798
16884
  }
16799
16885
  }
16800
16886
 
16801
- parts.push(isNegative ? pattern.negPre : pattern.posPre);
16802
- parts.push(formatedText);
16803
- parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
16887
+ parts.push(isNegative ? pattern.negPre : pattern.posPre,
16888
+ formatedText,
16889
+ isNegative ? pattern.negSuf : pattern.posSuf);
16804
16890
  return parts.join('');
16805
16891
  }
16806
16892
 
@@ -17019,10 +17105,10 @@ function dateFilter($locale) {
17019
17105
  tzMin = int(match[9] + match[11]);
17020
17106
  }
17021
17107
  dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
17022
- var h = int(match[4]||0) - tzHour;
17023
- var m = int(match[5]||0) - tzMin;
17024
- var s = int(match[6]||0);
17025
- var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
17108
+ var h = int(match[4] || 0) - tzHour;
17109
+ var m = int(match[5] || 0) - tzMin;
17110
+ var s = int(match[6] || 0);
17111
+ var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
17026
17112
  timeSetter.call(date, h, m, s, ms);
17027
17113
  return date;
17028
17114
  }
@@ -17254,7 +17340,7 @@ function limitToFilter() {
17254
17340
  n = input.length;
17255
17341
  }
17256
17342
 
17257
- for (; i<n; i++) {
17343
+ for (; i < n; i++) {
17258
17344
  out.push(input[i]);
17259
17345
  }
17260
17346
 
@@ -17381,7 +17467,7 @@ orderByFilter.$inject = ['$parse'];
17381
17467
  function orderByFilter($parse) {
17382
17468
  return function(array, sortPredicate, reverseOrder) {
17383
17469
  if (!(isArrayLike(array))) return array;
17384
- sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
17470
+ sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
17385
17471
  if (sortPredicate.length === 0) { sortPredicate = ['+']; }
17386
17472
  sortPredicate = sortPredicate.map(function(predicate) {
17387
17473
  var descending = false, get = predicate || identity;
@@ -17408,9 +17494,7 @@ function orderByFilter($parse) {
17408
17494
  return compare(get(a),get(b));
17409
17495
  }, descending);
17410
17496
  });
17411
- var arrayCopy = [];
17412
- for (var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
17413
- return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
17497
+ return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
17414
17498
 
17415
17499
  function comparator(o1, o2) {
17416
17500
  for (var i = 0; i < sortPredicate.length; i++) {
@@ -18382,9 +18466,7 @@ var formDirectiveFactory = function(isNgForm) {
18382
18466
  controller.$setSubmitted();
18383
18467
  });
18384
18468
 
18385
- event.preventDefault
18386
- ? event.preventDefault()
18387
- : event.returnValue = false; // IE
18469
+ event.preventDefault();
18388
18470
  };
18389
18471
 
18390
18472
  addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
@@ -18471,10 +18553,16 @@ var inputType = {
18471
18553
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
18472
18554
  * minlength.
18473
18555
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
18474
- * maxlength.
18475
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
18476
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
18477
- * patterns defined as scope expressions.
18556
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
18557
+ * any length.
18558
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
18559
+ * that contains the regular expression body that will be converted to a regular expression
18560
+ * as in the ngPattern directive.
18561
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
18562
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
18563
+ * If the expression evaluates to a RegExp object then this is used directly.
18564
+ * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
18565
+ * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
18478
18566
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
18479
18567
  * interaction with the input element.
18480
18568
  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
@@ -19014,10 +19102,16 @@ var inputType = {
19014
19102
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19015
19103
  * minlength.
19016
19104
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19017
- * maxlength.
19018
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19019
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19020
- * patterns defined as scope expressions.
19105
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19106
+ * any length.
19107
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19108
+ * that contains the regular expression body that will be converted to a regular expression
19109
+ * as in the ngPattern directive.
19110
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19111
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
19112
+ * If the expression evaluates to a RegExp object then this is used directly.
19113
+ * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19114
+ * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19021
19115
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
19022
19116
  * interaction with the input element.
19023
19117
  *
@@ -19096,10 +19190,16 @@ var inputType = {
19096
19190
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19097
19191
  * minlength.
19098
19192
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19099
- * maxlength.
19100
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19101
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19102
- * patterns defined as scope expressions.
19193
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19194
+ * any length.
19195
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19196
+ * that contains the regular expression body that will be converted to a regular expression
19197
+ * as in the ngPattern directive.
19198
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19199
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
19200
+ * If the expression evaluates to a RegExp object then this is used directly.
19201
+ * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19202
+ * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19103
19203
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
19104
19204
  * interaction with the input element.
19105
19205
  *
@@ -19179,10 +19279,16 @@ var inputType = {
19179
19279
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19180
19280
  * minlength.
19181
19281
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19182
- * maxlength.
19183
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19184
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19185
- * patterns defined as scope expressions.
19282
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19283
+ * any length.
19284
+ * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19285
+ * that contains the regular expression body that will be converted to a regular expression
19286
+ * as in the ngPattern directive.
19287
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
19288
+ * a RegExp found by evaluating the Angular expression given in the attribute value.
19289
+ * If the expression evaluates to a RegExp object then this is used directly.
19290
+ * If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
19291
+ * characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
19186
19292
  * @param {string=} ngChange Angular expression to be executed when input changes due to user
19187
19293
  * interaction with the input element.
19188
19294
  *
@@ -19445,7 +19551,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19445
19551
  element.on('change', listener);
19446
19552
 
19447
19553
  ctrl.$render = function() {
19448
- element.val(ctrl.$isEmpty(ctrl.$modelValue) ? '' : ctrl.$viewValue);
19554
+ element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
19449
19555
  };
19450
19556
  }
19451
19557
 
@@ -19493,8 +19599,8 @@ function createDateParser(regexp, mapping) {
19493
19599
  // When a date is JSON'ified to wraps itself inside of an extra
19494
19600
  // set of double quotes. This makes the date parsing code unable
19495
19601
  // to match the date string and parse it as a date.
19496
- if (iso.charAt(0) == '"' && iso.charAt(iso.length-1) == '"') {
19497
- iso = iso.substring(1, iso.length-1);
19602
+ if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
19603
+ iso = iso.substring(1, iso.length - 1);
19498
19604
  }
19499
19605
  if (ISO_DATE_REGEXP.test(iso)) {
19500
19606
  return new Date(iso);
@@ -19555,10 +19661,10 @@ function createDateInputType(type, regexp, parseDate, format) {
19555
19661
  });
19556
19662
 
19557
19663
  ctrl.$formatters.push(function(value) {
19558
- if (!ctrl.$isEmpty(value)) {
19559
- if (!isDate(value)) {
19560
- throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
19561
- }
19664
+ if (value && !isDate(value)) {
19665
+ throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
19666
+ }
19667
+ if (isValidDate(value)) {
19562
19668
  previousDate = value;
19563
19669
  if (previousDate && timezone === 'UTC') {
19564
19670
  var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
@@ -19567,14 +19673,14 @@ function createDateInputType(type, regexp, parseDate, format) {
19567
19673
  return $filter('date')(value, format, timezone);
19568
19674
  } else {
19569
19675
  previousDate = null;
19676
+ return '';
19570
19677
  }
19571
- return '';
19572
19678
  });
19573
19679
 
19574
19680
  if (isDefined(attr.min) || attr.ngMin) {
19575
19681
  var minVal;
19576
19682
  ctrl.$validators.min = function(value) {
19577
- return ctrl.$isEmpty(value) || isUndefined(minVal) || parseDate(value) >= minVal;
19683
+ return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
19578
19684
  };
19579
19685
  attr.$observe('min', function(val) {
19580
19686
  minVal = parseObservedDateValue(val);
@@ -19585,18 +19691,18 @@ function createDateInputType(type, regexp, parseDate, format) {
19585
19691
  if (isDefined(attr.max) || attr.ngMax) {
19586
19692
  var maxVal;
19587
19693
  ctrl.$validators.max = function(value) {
19588
- return ctrl.$isEmpty(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
19694
+ return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
19589
19695
  };
19590
19696
  attr.$observe('max', function(val) {
19591
19697
  maxVal = parseObservedDateValue(val);
19592
19698
  ctrl.$validate();
19593
19699
  });
19594
19700
  }
19595
- // Override the standard $isEmpty to detect invalid dates as well
19596
- ctrl.$isEmpty = function(value) {
19701
+
19702
+ function isValidDate(value) {
19597
19703
  // Invalid Date: getTime() returns NaN
19598
- return !value || (value.getTime && value.getTime() !== value.getTime());
19599
- };
19704
+ return value && !(value.getTime && value.getTime() !== value.getTime());
19705
+ }
19600
19706
 
19601
19707
  function parseObservedDateValue(val) {
19602
19708
  return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
@@ -19680,7 +19786,8 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19680
19786
  stringBasedInputType(ctrl);
19681
19787
 
19682
19788
  ctrl.$$parserName = 'url';
19683
- ctrl.$validators.url = function(value) {
19789
+ ctrl.$validators.url = function(modelValue, viewValue) {
19790
+ var value = modelValue || viewValue;
19684
19791
  return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
19685
19792
  };
19686
19793
  }
@@ -19692,7 +19799,8 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19692
19799
  stringBasedInputType(ctrl);
19693
19800
 
19694
19801
  ctrl.$$parserName = 'email';
19695
- ctrl.$validators.email = function(value) {
19802
+ ctrl.$validators.email = function(modelValue, viewValue) {
19803
+ var value = modelValue || viewValue;
19696
19804
  return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
19697
19805
  };
19698
19806
  }
@@ -19746,9 +19854,11 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
19746
19854
  element[0].checked = ctrl.$viewValue;
19747
19855
  };
19748
19856
 
19749
- // Override the standard `$isEmpty` because an empty checkbox is never equal to the trueValue
19857
+ // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
19858
+ // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
19859
+ // it to a boolean.
19750
19860
  ctrl.$isEmpty = function(value) {
19751
- return value !== trueValue;
19861
+ return value === false;
19752
19862
  };
19753
19863
 
19754
19864
  ctrl.$formatters.push(function(value) {
@@ -19780,7 +19890,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
19780
19890
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19781
19891
  * minlength.
19782
19892
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19783
- * maxlength.
19893
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
19894
+ * length.
19784
19895
  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19785
19896
  * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19786
19897
  * patterns defined as scope expressions.
@@ -19812,7 +19923,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
19812
19923
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19813
19924
  * minlength.
19814
19925
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19815
- * maxlength.
19926
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
19927
+ * length.
19816
19928
  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19817
19929
  * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19818
19930
  * patterns defined as scope expressions.
@@ -19941,12 +20053,17 @@ var VALID_CLASS = 'ng-valid',
19941
20053
  * @property {string} $viewValue Actual string value in the view.
19942
20054
  * @property {*} $modelValue The value in the model that the control is bound to.
19943
20055
  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
19944
- the control reads value from the DOM. The functions are called in array order, each passing the value
19945
- through to the next. The last return value is forwarded to the $validators collection.
19946
- Used to sanitize / convert the value.
19947
- Returning undefined from a parser means a parse error occurred. No $validators will
19948
- run and the 'ngModel' will not be updated until the parse error is resolved. The parse error is stored
19949
- in 'ngModel.$error.parse'.
20056
+ the control reads value from the DOM. The functions are called in array order, each passing
20057
+ its return value through to the next. The last return value is forwarded to the
20058
+ {@link ngModel.NgModelController#$validators `$validators`} collection.
20059
+
20060
+ Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
20061
+ `$viewValue`}.
20062
+
20063
+ Returning `undefined` from a parser means a parse error occurred. In that case,
20064
+ no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
20065
+ will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
20066
+ is set to `true`. The parse error is stored in `ngModel.$error.parse`.
19950
20067
 
19951
20068
  *
19952
20069
  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
@@ -20023,13 +20140,18 @@ var VALID_CLASS = 'ng-valid',
20023
20140
  *
20024
20141
  * @description
20025
20142
  *
20026
- * `NgModelController` provides API for the `ng-model` directive. The controller contains
20027
- * services for data-binding, validation, CSS updates, and value formatting and parsing. It
20028
- * purposefully does not contain any logic which deals with DOM rendering or listening to
20029
- * DOM events. Such DOM related logic should be provided by other directives which make use of
20030
- * `NgModelController` for data-binding.
20143
+ * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
20144
+ * The controller contains services for data-binding, validation, CSS updates, and value formatting
20145
+ * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
20146
+ * listening to DOM events.
20147
+ * Such DOM related logic should be provided by other directives which make use of
20148
+ * `NgModelController` for data-binding to control elements.
20149
+ * Angular provides this DOM logic for most {@link input `input`} elements.
20150
+ * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
20151
+ * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
20031
20152
  *
20032
- * ## Custom Control Example
20153
+ * @example
20154
+ * ### Custom Control Example
20033
20155
  * This example shows how to use `NgModelController` with a custom control to achieve
20034
20156
  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
20035
20157
  * collaborate together to achieve the desired result.
@@ -20071,7 +20193,7 @@ var VALID_CLASS = 'ng-valid',
20071
20193
 
20072
20194
  // Listen for change events to enable binding
20073
20195
  element.on('blur keyup change', function() {
20074
- scope.$apply(read);
20196
+ scope.$evalAsync(read);
20075
20197
  });
20076
20198
  read(); // initialize
20077
20199
 
@@ -20126,6 +20248,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20126
20248
  function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
20127
20249
  this.$viewValue = Number.NaN;
20128
20250
  this.$modelValue = Number.NaN;
20251
+ this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
20129
20252
  this.$validators = {};
20130
20253
  this.$asyncValidators = {};
20131
20254
  this.$parsers = [];
@@ -20144,32 +20267,33 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20144
20267
 
20145
20268
 
20146
20269
  var parsedNgModel = $parse($attr.ngModel),
20270
+ parsedNgModelAssign = parsedNgModel.assign,
20271
+ ngModelGet = parsedNgModel,
20272
+ ngModelSet = parsedNgModelAssign,
20147
20273
  pendingDebounce = null,
20148
20274
  ctrl = this;
20149
20275
 
20150
- var ngModelGet = function ngModelGet() {
20151
- var modelValue = parsedNgModel($scope);
20152
- if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) {
20153
- modelValue = modelValue();
20154
- }
20155
- return modelValue;
20156
- };
20157
-
20158
- var ngModelSet = function ngModelSet(newValue) {
20159
- var getterSetter;
20160
- if (ctrl.$options && ctrl.$options.getterSetter &&
20161
- isFunction(getterSetter = parsedNgModel($scope))) {
20162
-
20163
- getterSetter(ctrl.$modelValue);
20164
- } else {
20165
- parsedNgModel.assign($scope, ctrl.$modelValue);
20166
- }
20167
- };
20168
-
20169
20276
  this.$$setOptions = function(options) {
20170
20277
  ctrl.$options = options;
20171
-
20172
- if (!parsedNgModel.assign && (!options || !options.getterSetter)) {
20278
+ if (options && options.getterSetter) {
20279
+ var invokeModelGetter = $parse($attr.ngModel + '()'),
20280
+ invokeModelSetter = $parse($attr.ngModel + '($$$p)');
20281
+
20282
+ ngModelGet = function($scope) {
20283
+ var modelValue = parsedNgModel($scope);
20284
+ if (isFunction(modelValue)) {
20285
+ modelValue = invokeModelGetter($scope);
20286
+ }
20287
+ return modelValue;
20288
+ };
20289
+ ngModelSet = function($scope, newValue) {
20290
+ if (isFunction(parsedNgModel($scope))) {
20291
+ invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
20292
+ } else {
20293
+ parsedNgModelAssign($scope, ctrl.$modelValue);
20294
+ }
20295
+ };
20296
+ } else if (!parsedNgModel.assign) {
20173
20297
  throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
20174
20298
  $attr.ngModel, startingTag($element));
20175
20299
  }
@@ -20202,17 +20326,18 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20202
20326
  * @name ngModel.NgModelController#$isEmpty
20203
20327
  *
20204
20328
  * @description
20205
- * This is called when we need to determine if the value of the input is empty.
20329
+ * This is called when we need to determine if the value of an input is empty.
20206
20330
  *
20207
20331
  * For instance, the required directive does this to work out if the input has data or not.
20332
+ *
20208
20333
  * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
20209
20334
  *
20210
20335
  * You can override this for input directives whose concept of being empty is different to the
20211
20336
  * default. The `checkboxInputType` directive does this because in its case a value of `false`
20212
20337
  * implies empty.
20213
20338
  *
20214
- * @param {*} value Model value to check.
20215
- * @returns {boolean} True if `value` is empty.
20339
+ * @param {*} value The value of the input to check for emptiness.
20340
+ * @returns {boolean} True if `value` is "empty".
20216
20341
  */
20217
20342
  this.$isEmpty = function(value) {
20218
20343
  return isUndefined(value) || value === '' || value === null || value !== value;
@@ -20263,9 +20388,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20263
20388
  * @description
20264
20389
  * Sets the control to its pristine state.
20265
20390
  *
20266
- * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
20267
- * state (ng-pristine class). A model is considered to be pristine when the model has not been changed
20268
- * from when first compiled within then form.
20391
+ * This method can be called to remove the `ng-dirty` class and set the control to its pristine
20392
+ * state (`ng-pristine` class). A model is considered to be pristine when the control
20393
+ * has not been changed from when first compiled.
20269
20394
  */
20270
20395
  this.$setPristine = function() {
20271
20396
  ctrl.$dirty = false;
@@ -20274,6 +20399,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20274
20399
  $animate.addClass($element, PRISTINE_CLASS);
20275
20400
  };
20276
20401
 
20402
+ /**
20403
+ * @ngdoc method
20404
+ * @name ngModel.NgModelController#$setDirty
20405
+ *
20406
+ * @description
20407
+ * Sets the control to its dirty state.
20408
+ *
20409
+ * This method can be called to remove the `ng-pristine` class and set the control to its dirty
20410
+ * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
20411
+ * from when first compiled.
20412
+ */
20413
+ this.$setDirty = function() {
20414
+ ctrl.$dirty = true;
20415
+ ctrl.$pristine = false;
20416
+ $animate.removeClass($element, PRISTINE_CLASS);
20417
+ $animate.addClass($element, DIRTY_CLASS);
20418
+ parentForm.$setDirty();
20419
+ };
20420
+
20277
20421
  /**
20278
20422
  * @ngdoc method
20279
20423
  * @name ngModel.NgModelController#$setUntouched
@@ -20281,8 +20425,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20281
20425
  * @description
20282
20426
  * Sets the control to its untouched state.
20283
20427
  *
20284
- * This method can be called to remove the 'ng-touched' class and set the control to its
20285
- * untouched state (ng-untouched class). Upon compilation, a model is set as untouched
20428
+ * This method can be called to remove the `ng-touched` class and set the control to its
20429
+ * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
20286
20430
  * by default, however this function can be used to restore that state if the model has
20287
20431
  * already been touched by the user.
20288
20432
  */
@@ -20299,10 +20443,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20299
20443
  * @description
20300
20444
  * Sets the control to its touched state.
20301
20445
  *
20302
- * This method can be called to remove the 'ng-untouched' class and set the control to its
20303
- * touched state (ng-touched class). A model is considered to be touched when the user has
20304
- * first interacted (focussed) on the model input element and then shifted focus away (blurred)
20305
- * from the input element.
20446
+ * This method can be called to remove the `ng-untouched` class and set the control to its
20447
+ * touched state (`ng-touched` class). A model is considered to be touched when the user has
20448
+ * first focused the control element and then shifted focus away from the control (blur event).
20306
20449
  */
20307
20450
  this.$setTouched = function() {
20308
20451
  ctrl.$touched = true;
@@ -20380,14 +20523,51 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20380
20523
  * @name ngModel.NgModelController#$validate
20381
20524
  *
20382
20525
  * @description
20383
- * Runs each of the registered validators (first synchronous validators and then asynchronous validators).
20526
+ * Runs each of the registered validators (first synchronous validators and then
20527
+ * asynchronous validators).
20528
+ * If the validity changes to invalid, the model will be set to `undefined`,
20529
+ * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
20530
+ * If the validity changes to valid, it will set the model to the last available valid
20531
+ * modelValue, i.e. either the last parsed value or the last value set from the scope.
20384
20532
  */
20385
20533
  this.$validate = function() {
20386
20534
  // ignore $validate before model is initialized
20387
20535
  if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
20388
20536
  return;
20389
20537
  }
20390
- this.$$parseAndValidate();
20538
+
20539
+ var viewValue = ctrl.$$lastCommittedViewValue;
20540
+ // Note: we use the $$rawModelValue as $modelValue might have been
20541
+ // set to undefined during a view -> model update that found validation
20542
+ // errors. We can't parse the view here, since that could change
20543
+ // the model although neither viewValue nor the model on the scope changed
20544
+ var modelValue = ctrl.$$rawModelValue;
20545
+
20546
+ // Check if the there's a parse error, so we don't unset it accidentially
20547
+ var parserName = ctrl.$$parserName || 'parse';
20548
+ var parserValid = ctrl.$error[parserName] ? false : undefined;
20549
+
20550
+ var prevValid = ctrl.$valid;
20551
+ var prevModelValue = ctrl.$modelValue;
20552
+
20553
+ var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
20554
+
20555
+ ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
20556
+ // If there was no change in validity, don't update the model
20557
+ // This prevents changing an invalid modelValue to undefined
20558
+ if (!allowInvalid && prevValid !== allValid) {
20559
+ // Note: Don't check ctrl.$valid here, as we could have
20560
+ // external validators (e.g. calculated on the server),
20561
+ // that just call $setValidity and need the model value
20562
+ // to calculate their validity.
20563
+ ctrl.$modelValue = allValid ? modelValue : undefined;
20564
+
20565
+ if (ctrl.$modelValue !== prevModelValue) {
20566
+ ctrl.$$writeModelToScope();
20567
+ }
20568
+ }
20569
+ });
20570
+
20391
20571
  };
20392
20572
 
20393
20573
  this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
@@ -20506,11 +20686,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20506
20686
 
20507
20687
  // change to dirty
20508
20688
  if (ctrl.$pristine) {
20509
- ctrl.$dirty = true;
20510
- ctrl.$pristine = false;
20511
- $animate.removeClass($element, PRISTINE_CLASS);
20512
- $animate.addClass($element, DIRTY_CLASS);
20513
- parentForm.$setDirty();
20689
+ this.$setDirty();
20514
20690
  }
20515
20691
  this.$$parseAndValidate();
20516
20692
  };
@@ -20531,10 +20707,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20531
20707
  }
20532
20708
  if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
20533
20709
  // ctrl.$modelValue has not been touched yet...
20534
- ctrl.$modelValue = ngModelGet();
20710
+ ctrl.$modelValue = ngModelGet($scope);
20535
20711
  }
20536
20712
  var prevModelValue = ctrl.$modelValue;
20537
20713
  var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
20714
+ ctrl.$$rawModelValue = modelValue;
20538
20715
  if (allowInvalid) {
20539
20716
  ctrl.$modelValue = modelValue;
20540
20717
  writeToModelIfNeeded();
@@ -20558,7 +20735,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20558
20735
  };
20559
20736
 
20560
20737
  this.$$writeModelToScope = function() {
20561
- ngModelSet(ctrl.$modelValue);
20738
+ ngModelSet($scope, ctrl.$modelValue);
20562
20739
  forEach(ctrl.$viewChangeListeners, function(listener) {
20563
20740
  try {
20564
20741
  listener();
@@ -20654,12 +20831,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20654
20831
  // ng-change executes in apply phase
20655
20832
  // 4. view should be changed back to 'a'
20656
20833
  $scope.$watch(function ngModelWatch() {
20657
- var modelValue = ngModelGet();
20834
+ var modelValue = ngModelGet($scope);
20658
20835
 
20659
20836
  // if scope model value and ngModel value are out of sync
20660
20837
  // TODO(perf): why not move this to the action fn?
20661
20838
  if (modelValue !== ctrl.$modelValue) {
20662
- ctrl.$modelValue = modelValue;
20839
+ ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
20663
20840
 
20664
20841
  var formatters = ctrl.$formatters,
20665
20842
  idx = formatters.length;
@@ -20844,7 +21021,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20844
21021
  </file>
20845
21022
  * </example>
20846
21023
  */
20847
- var ngModelDirective = function() {
21024
+ var ngModelDirective = ['$rootScope', function($rootScope) {
20848
21025
  return {
20849
21026
  restrict: 'A',
20850
21027
  require: ['ngModel', '^?form', '^?ngModelOptions'],
@@ -20888,15 +21065,17 @@ var ngModelDirective = function() {
20888
21065
  element.on('blur', function(ev) {
20889
21066
  if (modelCtrl.$touched) return;
20890
21067
 
20891
- scope.$apply(function() {
20892
- modelCtrl.$setTouched();
20893
- });
21068
+ if ($rootScope.$$phase) {
21069
+ scope.$evalAsync(modelCtrl.$setTouched);
21070
+ } else {
21071
+ scope.$apply(modelCtrl.$setTouched);
21072
+ }
20894
21073
  });
20895
21074
  }
20896
21075
  };
20897
21076
  }
20898
21077
  };
20899
- };
21078
+ }];
20900
21079
 
20901
21080
 
20902
21081
  /**
@@ -20985,8 +21164,8 @@ var requiredDirective = function() {
20985
21164
  if (!ctrl) return;
20986
21165
  attr.required = true; // force truthy in case we are on non input element
20987
21166
 
20988
- ctrl.$validators.required = function(value) {
20989
- return !attr.required || !ctrl.$isEmpty(value);
21167
+ ctrl.$validators.required = function(modelValue, viewValue) {
21168
+ return !attr.required || !ctrl.$isEmpty(viewValue);
20990
21169
  };
20991
21170
 
20992
21171
  attr.$observe('required', function() {
@@ -21007,7 +21186,7 @@ var patternDirective = function() {
21007
21186
  var regexp, patternExp = attr.ngPattern || attr.pattern;
21008
21187
  attr.$observe('pattern', function(regex) {
21009
21188
  if (isString(regex) && regex.length > 0) {
21010
- regex = new RegExp(regex);
21189
+ regex = new RegExp('^' + regex + '$');
21011
21190
  }
21012
21191
 
21013
21192
  if (regex && !regex.test) {
@@ -21035,13 +21214,14 @@ var maxlengthDirective = function() {
21035
21214
  link: function(scope, elm, attr, ctrl) {
21036
21215
  if (!ctrl) return;
21037
21216
 
21038
- var maxlength = 0;
21217
+ var maxlength = -1;
21039
21218
  attr.$observe('maxlength', function(value) {
21040
- maxlength = int(value) || 0;
21219
+ var intVal = int(value);
21220
+ maxlength = isNaN(intVal) ? -1 : intVal;
21041
21221
  ctrl.$validate();
21042
21222
  });
21043
21223
  ctrl.$validators.maxlength = function(modelValue, viewValue) {
21044
- return ctrl.$isEmpty(modelValue) || viewValue.length <= maxlength;
21224
+ return (maxlength < 0) || ctrl.$isEmpty(modelValue) || (viewValue.length <= maxlength);
21045
21225
  };
21046
21226
  }
21047
21227
  };
@@ -21060,7 +21240,7 @@ var minlengthDirective = function() {
21060
21240
  ctrl.$validate();
21061
21241
  });
21062
21242
  ctrl.$validators.minlength = function(modelValue, viewValue) {
21063
- return ctrl.$isEmpty(modelValue) || viewValue.length >= minlength;
21243
+ return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
21064
21244
  };
21065
21245
  }
21066
21246
  };
@@ -21298,7 +21478,7 @@ var ngValueDirective = function() {
21298
21478
  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
21299
21479
  *
21300
21480
  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
21301
- * - `updateOn`: string specifying which event should be the input bound to. You can set several
21481
+ * - `updateOn`: string specifying which event should the input be bound to. You can set several
21302
21482
  * events using an space delimited list. There is a special event called `default` that
21303
21483
  * matches the default events belonging of the control.
21304
21484
  * - `debounce`: integer value which contains the debounce model update value in milliseconds. A
@@ -21688,12 +21868,11 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
21688
21868
  * @name ngBindHtml
21689
21869
  *
21690
21870
  * @description
21691
- * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
21692
- * element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
21693
- * ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
21694
- * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
21695
- * core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
21696
- * include "angular-sanitize.js" in your application.
21871
+ * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
21872
+ * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
21873
+ * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
21874
+ * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
21875
+ * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
21697
21876
  *
21698
21877
  * You may also bypass sanitization for values you know are safe. To do so, bind to
21699
21878
  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
@@ -23757,7 +23936,9 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
23757
23936
  </example>
23758
23937
  */
23759
23938
  var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
23760
- var BRACE = /{}/g;
23939
+ var BRACE = /{}/g,
23940
+ IS_WHEN = /^when(Minus)?(.+)$/;
23941
+
23761
23942
  return {
23762
23943
  restrict: 'EA',
23763
23944
  link: function(scope, element, attr) {
@@ -23768,34 +23949,44 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
23768
23949
  whensExpFns = {},
23769
23950
  startSymbol = $interpolate.startSymbol(),
23770
23951
  endSymbol = $interpolate.endSymbol(),
23771
- isWhen = /^when(Minus)?(.+)$/;
23952
+ braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
23953
+ watchRemover = angular.noop,
23954
+ lastCount;
23772
23955
 
23773
23956
  forEach(attr, function(expression, attributeName) {
23774
- if (isWhen.test(attributeName)) {
23775
- whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
23776
- element.attr(attr.$attr[attributeName]);
23957
+ var tmpMatch = IS_WHEN.exec(attributeName);
23958
+ if (tmpMatch) {
23959
+ var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
23960
+ whens[whenKey] = element.attr(attr.$attr[attributeName]);
23777
23961
  }
23778
23962
  });
23779
23963
  forEach(whens, function(expression, key) {
23780
- whensExpFns[key] =
23781
- $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
23782
- offset + endSymbol));
23964
+ whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
23965
+
23783
23966
  });
23784
23967
 
23785
- scope.$watch(function ngPluralizeWatch() {
23786
- var value = parseFloat(scope.$eval(numberExp));
23968
+ scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
23969
+ var count = parseFloat(newVal);
23970
+ var countIsNaN = isNaN(count);
23787
23971
 
23788
- if (!isNaN(value)) {
23789
- //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
23790
- //check it against pluralization rules in $locale service
23791
- if (!(value in whens)) value = $locale.pluralCat(value - offset);
23792
- return whensExpFns[value](scope);
23793
- } else {
23794
- return '';
23972
+ if (!countIsNaN && !(count in whens)) {
23973
+ // If an explicit number rule such as 1, 2, 3... is defined, just use it.
23974
+ // Otherwise, check it against pluralization rules in $locale service.
23975
+ count = $locale.pluralCat(count - offset);
23976
+ }
23977
+
23978
+ // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
23979
+ // In JS `NaN !== NaN`, so we have to exlicitly check.
23980
+ if ((count !== lastCount) && !(countIsNaN && isNaN(lastCount))) {
23981
+ watchRemover();
23982
+ watchRemover = scope.$watch(whensExpFns[count], updateElementText);
23983
+ lastCount = count;
23795
23984
  }
23796
- }, function ngPluralizeWatchAction(newVal) {
23797
- element.text(newVal);
23798
23985
  });
23986
+
23987
+ function updateElementText(newText) {
23988
+ element.text(newText || '');
23989
+ }
23799
23990
  }
23800
23991
  };
23801
23992
  }];
@@ -24166,7 +24357,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
24166
24357
  });
24167
24358
  throw ngRepeatMinErr('dupes',
24168
24359
  "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
24169
- expression, trackById, toJson(value));
24360
+ expression, trackById, value);
24170
24361
  } else {
24171
24362
  // new never before seen block
24172
24363
  nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
@@ -24277,17 +24468,17 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24277
24468
  *
24278
24469
  * ### Overriding `.ng-hide`
24279
24470
  *
24280
- * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
24471
+ * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24281
24472
  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24282
24473
  * class in CSS:
24283
24474
  *
24284
24475
  * ```css
24285
24476
  * .ng-hide {
24286
24477
  * /&#42; this is just another form of hiding an element &#42;/
24287
- * display:block!important;
24288
- * position:absolute;
24289
- * top:-9999px;
24290
- * left:-9999px;
24478
+ * display: block!important;
24479
+ * position: absolute;
24480
+ * top: -9999px;
24481
+ * left: -9999px;
24291
24482
  * }
24292
24483
  * ```
24293
24484
  *
@@ -24307,13 +24498,13 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24307
24498
  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24308
24499
  * /&#42; this is required as of 1.3x to properly
24309
24500
  * apply all styling in a show/hide animation &#42;/
24310
- * transition:0s linear all;
24501
+ * transition: 0s linear all;
24311
24502
  * }
24312
24503
  *
24313
24504
  * .my-element.ng-hide-add-active,
24314
24505
  * .my-element.ng-hide-remove-active {
24315
24506
  * /&#42; the transition is defined in the active class &#42;/
24316
- * transition:1s linear all;
24507
+ * transition: 1s linear all;
24317
24508
  * }
24318
24509
  *
24319
24510
  * .my-element.ng-hide-add { ... }
@@ -24355,29 +24546,29 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24355
24546
  </file>
24356
24547
  <file name="animations.css">
24357
24548
  .animate-show {
24358
- line-height:20px;
24359
- opacity:1;
24360
- padding:10px;
24361
- border:1px solid black;
24362
- background:white;
24549
+ line-height: 20px;
24550
+ opacity: 1;
24551
+ padding: 10px;
24552
+ border: 1px solid black;
24553
+ background: white;
24363
24554
  }
24364
24555
 
24365
24556
  .animate-show.ng-hide-add.ng-hide-add-active,
24366
24557
  .animate-show.ng-hide-remove.ng-hide-remove-active {
24367
- -webkit-transition:all linear 0.5s;
24368
- transition:all linear 0.5s;
24558
+ -webkit-transition: all linear 0.5s;
24559
+ transition: all linear 0.5s;
24369
24560
  }
24370
24561
 
24371
24562
  .animate-show.ng-hide {
24372
- line-height:0;
24373
- opacity:0;
24374
- padding:0 10px;
24563
+ line-height: 0;
24564
+ opacity: 0;
24565
+ padding: 0 10px;
24375
24566
  }
24376
24567
 
24377
24568
  .check-element {
24378
- padding:10px;
24379
- border:1px solid black;
24380
- background:white;
24569
+ padding: 10px;
24570
+ border: 1px solid black;
24571
+ background: white;
24381
24572
  }
24382
24573
  </file>
24383
24574
  <file name="protractor.js" type="protractor">
@@ -24451,17 +24642,17 @@ var ngShowDirective = ['$animate', function($animate) {
24451
24642
  *
24452
24643
  * ### Overriding `.ng-hide`
24453
24644
  *
24454
- * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
24645
+ * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
24455
24646
  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24456
24647
  * class in CSS:
24457
24648
  *
24458
24649
  * ```css
24459
24650
  * .ng-hide {
24460
24651
  * /&#42; this is just another form of hiding an element &#42;/
24461
- * display:block!important;
24462
- * position:absolute;
24463
- * top:-9999px;
24464
- * left:-9999px;
24652
+ * display: block!important;
24653
+ * position: absolute;
24654
+ * top: -9999px;
24655
+ * left: -9999px;
24465
24656
  * }
24466
24657
  * ```
24467
24658
  *
@@ -24478,7 +24669,7 @@ var ngShowDirective = ['$animate', function($animate) {
24478
24669
  * //a working example can be found at the bottom of this page
24479
24670
  * //
24480
24671
  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24481
- * transition:0.5s linear all;
24672
+ * transition: 0.5s linear all;
24482
24673
  * }
24483
24674
  *
24484
24675
  * .my-element.ng-hide-add { ... }
@@ -24520,25 +24711,25 @@ var ngShowDirective = ['$animate', function($animate) {
24520
24711
  </file>
24521
24712
  <file name="animations.css">
24522
24713
  .animate-hide {
24523
- -webkit-transition:all linear 0.5s;
24524
- transition:all linear 0.5s;
24525
- line-height:20px;
24526
- opacity:1;
24527
- padding:10px;
24528
- border:1px solid black;
24529
- background:white;
24714
+ -webkit-transition: all linear 0.5s;
24715
+ transition: all linear 0.5s;
24716
+ line-height: 20px;
24717
+ opacity: 1;
24718
+ padding: 10px;
24719
+ border: 1px solid black;
24720
+ background: white;
24530
24721
  }
24531
24722
 
24532
24723
  .animate-hide.ng-hide {
24533
- line-height:0;
24534
- opacity:0;
24535
- padding:0 10px;
24724
+ line-height: 0;
24725
+ opacity: 0;
24726
+ padding: 0 10px;
24536
24727
  }
24537
24728
 
24538
24729
  .check-element {
24539
- padding:10px;
24540
- border:1px solid black;
24541
- background:white;
24730
+ padding: 10px;
24731
+ border: 1px solid black;
24732
+ background: white;
24542
24733
  }
24543
24734
  </file>
24544
24735
  <file name="protractor.js" type="protractor">
@@ -24972,7 +25163,7 @@ var ngOptionsMinErr = minErr('ngOptions');
24972
25163
  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
24973
25164
  * similar result. However, the `ngOptions` provides some benefits such as reducing memory and
24974
25165
  * increasing speed by not creating a new scope for each repeated instance, as well as providing
24975
- * more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions should be
25166
+ * more flexibility in how the `select`'s model is assigned via `select as`. `ngOptions` should be
24976
25167
  * used when the `select` model needs to be bound to a non-string value. This is because an option
24977
25168
  * element can only be bound to string values at present.
24978
25169
  *
@@ -25570,13 +25761,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25570
25761
  lastElement = null; // start at the beginning
25571
25762
  for (index = 0, length = optionGroup.length; index < length; index++) {
25572
25763
  option = optionGroup[index];
25573
- if ((existingOption = existingOptions[index+1])) {
25764
+ if ((existingOption = existingOptions[index + 1])) {
25574
25765
  // reuse elements
25575
25766
  lastElement = existingOption.element;
25576
25767
  if (existingOption.label !== option.label) {
25577
25768
  updateLabelMap(labelMap, existingOption.label, false);
25578
25769
  updateLabelMap(labelMap, option.label, true);
25579
25770
  lastElement.text(existingOption.label = option.label);
25771
+ lastElement.prop('label', existingOption.label);
25580
25772
  }
25581
25773
  if (existingOption.id !== option.id) {
25582
25774
  lastElement.val(existingOption.id = option.id);
@@ -25606,6 +25798,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
25606
25798
  .val(option.id)
25607
25799
  .prop('selected', option.selected)
25608
25800
  .attr('selected', option.selected)
25801
+ .prop('label', option.label)
25609
25802
  .text(option.label);
25610
25803
  }
25611
25804