angularjs-rails 1.2.18 → 1.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.13
2
+ * @license AngularJS v1.3.0-beta.14
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.0-beta.13
2
+ * @license AngularJS v1.3.0-beta.14
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -68,7 +68,7 @@ function minErr(module) {
68
68
  return match;
69
69
  });
70
70
 
71
- message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.13/' +
71
+ message = message + '\nhttp://errors.angularjs.org/1.3.0-beta.14/' +
72
72
  (module ? module + '/' : '') + code;
73
73
  for (i = 2; i < arguments.length; i++) {
74
74
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -93,6 +93,7 @@ function minErr(module) {
93
93
  -nodeName_,
94
94
  -uid,
95
95
  -REGEX_STRING_REGEXP,
96
+ -VALIDITY_STATE_PROPERTY,
96
97
 
97
98
  -lowercase,
98
99
  -uppercase,
@@ -145,7 +146,6 @@ function minErr(module) {
145
146
  -toJsonReplacer,
146
147
  -toJson,
147
148
  -fromJson,
148
- -toBoolean,
149
149
  -startingTag,
150
150
  -tryDecodeURIComponent,
151
151
  -parseKeyValue,
@@ -184,6 +184,10 @@ function minErr(module) {
184
184
 
185
185
  var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
186
186
 
187
+ // The name of a form control's ValidityState property.
188
+ // This is used so that it's possible for internal tests to create mock ValidityStates.
189
+ var VALIDITY_STATE_PROPERTY = 'validity';
190
+
187
191
  /**
188
192
  * @ngdoc function
189
193
  * @name angular.lowercase
@@ -320,12 +324,12 @@ function forEach(obj, iterator, context) {
320
324
  iterator.call(context, obj[key], key);
321
325
  }
322
326
  }
323
- } else if (obj.forEach && obj.forEach !== forEach) {
324
- obj.forEach(iterator, context);
325
- } else if (isArrayLike(obj)) {
327
+ } else if (isArray(obj) || isArrayLike(obj)) {
326
328
  for (key = 0, length = obj.length; key < length; key++) {
327
329
  iterator.call(context, obj[key], key);
328
330
  }
331
+ } else if (obj.forEach && obj.forEach !== forEach) {
332
+ obj.forEach(iterator, context);
329
333
  } else {
330
334
  for (key in obj) {
331
335
  if (obj.hasOwnProperty(key)) {
@@ -694,12 +698,14 @@ function makeMap(str) {
694
698
  if (msie < 9) {
695
699
  nodeName_ = function(element) {
696
700
  element = element.nodeName ? element : element[0];
697
- return (element.scopeName && element.scopeName != 'HTML')
698
- ? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
701
+ return lowercase(
702
+ (element.scopeName && element.scopeName != 'HTML')
703
+ ? element.scopeName + ':' + element.nodeName : element.nodeName
704
+ );
699
705
  };
700
706
  } else {
701
707
  nodeName_ = function(element) {
702
- return element.nodeName ? element.nodeName : element[0].nodeName;
708
+ return lowercase(element.nodeName ? element.nodeName : element[0].nodeName);
703
709
  };
704
710
  }
705
711
 
@@ -762,10 +768,10 @@ function arrayRemove(array, value) {
762
768
 
763
769
  function isLeafNode (node) {
764
770
  if (node) {
765
- switch (node.nodeName) {
766
- case "OPTION":
767
- case "PRE":
768
- case "TITLE":
771
+ switch (nodeName_(node)) {
772
+ case "option":
773
+ case "pre":
774
+ case "title":
769
775
  return true;
770
776
  }
771
777
  }
@@ -845,7 +851,8 @@ function copy(source, destination, stackSource, stackDest) {
845
851
  } else if (isRegExp(source)) {
846
852
  destination = new RegExp(source.source);
847
853
  } else if (isObject(source)) {
848
- destination = copy(source, {}, stackSource, stackDest);
854
+ var emptyObject = Object.create(Object.getPrototypeOf(source));
855
+ destination = copy(source, emptyObject, stackSource, stackDest);
849
856
  }
850
857
  }
851
858
  } else {
@@ -880,12 +887,14 @@ function copy(source, destination, stackSource, stackDest) {
880
887
  delete destination[key];
881
888
  });
882
889
  for ( var key in source) {
883
- result = copy(source[key], null, stackSource, stackDest);
884
- if (isObject(source[key])) {
885
- stackSource.push(source[key]);
886
- stackDest.push(result);
890
+ if(source.hasOwnProperty(key)) {
891
+ result = copy(source[key], null, stackSource, stackDest);
892
+ if (isObject(source[key])) {
893
+ stackSource.push(source[key]);
894
+ stackDest.push(result);
895
+ }
896
+ destination[key] = result;
887
897
  }
888
- destination[key] = result;
889
898
  }
890
899
  setHashKey(destination,h);
891
900
  }
@@ -1105,18 +1114,6 @@ function fromJson(json) {
1105
1114
  }
1106
1115
 
1107
1116
 
1108
- function toBoolean(value) {
1109
- if (typeof value === 'function') {
1110
- value = true;
1111
- } else if (value && value.length !== 0) {
1112
- var v = lowercase("" + value);
1113
- value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
1114
- } else {
1115
- value = false;
1116
- }
1117
- return value;
1118
- }
1119
-
1120
1117
  /**
1121
1118
  * @returns {string} Returns the string representation of the element.
1122
1119
  */
@@ -1446,7 +1443,7 @@ function angularInit(element, bootstrap) {
1446
1443
  *
1447
1444
  * Angular will detect if it has been loaded into the browser more than once and only allow the
1448
1445
  * first loaded script to be bootstrapped and will report a warning to the browser console for
1449
- * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1446
+ * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1450
1447
  * multiple instances of Angular try to work on the DOM.
1451
1448
  *
1452
1449
  * ```html
@@ -1589,7 +1586,7 @@ function assertArgFn(arg, name, acceptArrayAnnotation) {
1589
1586
  }
1590
1587
 
1591
1588
  assertArg(isFunction(arg), name, 'not a function, got ' +
1592
- (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
1589
+ (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1593
1590
  return arg;
1594
1591
  }
1595
1592
 
@@ -2044,6 +2041,7 @@ function setupModuleLoader(window) {
2044
2041
  $ParseProvider,
2045
2042
  $RootScopeProvider,
2046
2043
  $QProvider,
2044
+ $$QProvider,
2047
2045
  $$SanitizeUriProvider,
2048
2046
  $SceProvider,
2049
2047
  $SceDelegateProvider,
@@ -2071,11 +2069,11 @@ function setupModuleLoader(window) {
2071
2069
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2072
2070
  */
2073
2071
  var version = {
2074
- full: '1.3.0-beta.13', // all of these placeholder strings will be replaced by grunt's
2072
+ full: '1.3.0-beta.14', // all of these placeholder strings will be replaced by grunt's
2075
2073
  major: 1, // package task
2076
2074
  minor: 3,
2077
2075
  dot: 0,
2078
- codeName: 'idiosyncratic-numerification'
2076
+ codeName: 'harmonious-cacophonies'
2079
2077
  };
2080
2078
 
2081
2079
 
@@ -2193,6 +2191,7 @@ function publishExternalAPI(angular){
2193
2191
  $parse: $ParseProvider,
2194
2192
  $rootScope: $RootScopeProvider,
2195
2193
  $q: $QProvider,
2194
+ $$q: $$QProvider,
2196
2195
  $sce: $SceProvider,
2197
2196
  $sceDelegate: $SceDelegateProvider,
2198
2197
  $sniffer: $SnifferProvider,
@@ -2367,6 +2366,12 @@ function jqLiteIsTextNode(html) {
2367
2366
  return !HTML_REGEXP.test(html);
2368
2367
  }
2369
2368
 
2369
+ function jqLiteAcceptsData(node) {
2370
+ // The window object can accept data but has no nodeType
2371
+ // Otherwise we are only interested in elements (1) and documents (9)
2372
+ return !node.nodeType || node.nodeType === 1 || node.nodeType === 9;
2373
+ }
2374
+
2370
2375
  function jqLiteBuildFragment(html, context) {
2371
2376
  var elem, tmp, tag, wrap,
2372
2377
  fragment = context.createDocumentFragment(),
@@ -2514,30 +2519,29 @@ function jqLiteExpandoStore(element, key, value) {
2514
2519
  }
2515
2520
 
2516
2521
  function jqLiteData(element, key, value) {
2517
- var data = jqLiteExpandoStore(element, 'data'),
2518
- isSetter = isDefined(value),
2519
- keyDefined = !isSetter && isDefined(key),
2520
- isSimpleGetter = keyDefined && !isObject(key);
2521
-
2522
- if (!data && !isSimpleGetter) {
2523
- jqLiteExpandoStore(element, 'data', data = {});
2524
- }
2522
+ if (jqLiteAcceptsData(element)) {
2523
+ var data = jqLiteExpandoStore(element, 'data'),
2524
+ isSetter = isDefined(value),
2525
+ keyDefined = !isSetter && isDefined(key),
2526
+ isSimpleGetter = keyDefined && !isObject(key);
2527
+
2528
+ if (!data && !isSimpleGetter) {
2529
+ jqLiteExpandoStore(element, 'data', data = {});
2530
+ }
2525
2531
 
2526
- if (isSetter) {
2527
- // set data only on Elements and Documents
2528
- if (element.nodeType === 1 || element.nodeType === 9) {
2532
+ if (isSetter) {
2529
2533
  data[key] = value;
2530
- }
2531
- } else {
2532
- if (keyDefined) {
2533
- if (isSimpleGetter) {
2534
- // don't create data in this case.
2535
- return data && data[key];
2534
+ } else {
2535
+ if (keyDefined) {
2536
+ if (isSimpleGetter) {
2537
+ // don't create data in this case.
2538
+ return data && data[key];
2539
+ } else {
2540
+ extend(data, key);
2541
+ }
2536
2542
  } else {
2537
- extend(data, key);
2543
+ return data;
2538
2544
  }
2539
- } else {
2540
- return data;
2541
2545
  }
2542
2546
  }
2543
2547
  }
@@ -2591,6 +2595,10 @@ function jqLiteAddNodes(root, elements) {
2591
2595
  // if an Array or NodeList and not a Window
2592
2596
  if (typeof length === 'number' && elements.window !== elements) {
2593
2597
  if (length) {
2598
+ if (elements.item) {
2599
+ // convert NodeList to an Array to make PhantomJS 1.x happy
2600
+ elements = slice.call(elements);
2601
+ }
2594
2602
  push.apply(root, elements);
2595
2603
  }
2596
2604
  } else {
@@ -2688,7 +2696,7 @@ forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','),
2688
2696
  });
2689
2697
  var BOOLEAN_ELEMENTS = {};
2690
2698
  forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
2691
- BOOLEAN_ELEMENTS[uppercase(value)] = true;
2699
+ BOOLEAN_ELEMENTS[value] = true;
2692
2700
  });
2693
2701
  var ALIASED_ATTR = {
2694
2702
  'ngMinlength' : 'minlength',
@@ -2701,7 +2709,7 @@ function getBooleanAttrName(element, name) {
2701
2709
  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
2702
2710
 
2703
2711
  // booleanAttr is here twice to minimize DOM access
2704
- return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
2712
+ return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
2705
2713
  }
2706
2714
 
2707
2715
  function getAliasedAttrName(element, name) {
@@ -2811,7 +2819,7 @@ forEach({
2811
2819
 
2812
2820
  val: function(element, value) {
2813
2821
  if (isUndefined(value)) {
2814
- if (nodeName_(element) === 'SELECT' && element.multiple) {
2822
+ if (element.multiple && nodeName_(element) === 'select') {
2815
2823
  var result = [];
2816
2824
  forEach(element.options, function (option) {
2817
2825
  if (option.selected) {
@@ -2956,6 +2964,11 @@ forEach({
2956
2964
  on: function onFn(element, type, fn, unsupported){
2957
2965
  if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
2958
2966
 
2967
+ // Do not add event handlers to non-elements because they will not be cleaned up.
2968
+ if (!jqLiteAcceptsData(element)) {
2969
+ return;
2970
+ }
2971
+
2959
2972
  var events = jqLiteExpandoStore(element, 'events'),
2960
2973
  handle = jqLiteExpandoStore(element, 'handle');
2961
2974
 
@@ -3145,7 +3158,12 @@ forEach({
3145
3158
  eventData = eventData || [];
3146
3159
 
3147
3160
  var event = [{
3148
- preventDefault: noop,
3161
+ preventDefault: function() {
3162
+ this.defaultPrevented = true;
3163
+ },
3164
+ isDefaultPrevented: function() {
3165
+ return this.defaultPrevented === true;
3166
+ },
3149
3167
  stopPropagation: noop
3150
3168
  }];
3151
3169
 
@@ -3190,16 +3208,16 @@ forEach({
3190
3208
  * @returns {string} hash string such that the same input will have the same hash string.
3191
3209
  * The resulting string key is in 'type:hashKey' format.
3192
3210
  */
3193
- function hashKey(obj) {
3211
+ function hashKey(obj, nextUidFn) {
3194
3212
  var objType = typeof obj,
3195
3213
  key;
3196
3214
 
3197
- if (objType == 'object' && obj !== null) {
3215
+ if (objType == 'function' || (objType == 'object' && obj !== null)) {
3198
3216
  if (typeof (key = obj.$$hashKey) == 'function') {
3199
3217
  // must invoke on object to keep the right this
3200
3218
  key = obj.$$hashKey();
3201
3219
  } else if (key === undefined) {
3202
- key = obj.$$hashKey = nextUid();
3220
+ key = obj.$$hashKey = (nextUidFn || nextUid)();
3203
3221
  }
3204
3222
  } else {
3205
3223
  key = obj;
@@ -3211,7 +3229,13 @@ function hashKey(obj) {
3211
3229
  /**
3212
3230
  * HashMap which can use objects as keys
3213
3231
  */
3214
- function HashMap(array){
3232
+ function HashMap(array, isolatedUid) {
3233
+ if (isolatedUid) {
3234
+ var uid = 0;
3235
+ this.nextUid = function() {
3236
+ return ++uid;
3237
+ };
3238
+ }
3215
3239
  forEach(array, this.put, this);
3216
3240
  }
3217
3241
  HashMap.prototype = {
@@ -3221,7 +3245,7 @@ HashMap.prototype = {
3221
3245
  * @param value value to store can be any type
3222
3246
  */
3223
3247
  put: function(key, value) {
3224
- this[hashKey(key)] = value;
3248
+ this[hashKey(key, this.nextUid)] = value;
3225
3249
  },
3226
3250
 
3227
3251
  /**
@@ -3229,7 +3253,7 @@ HashMap.prototype = {
3229
3253
  * @returns {Object} the value for the key
3230
3254
  */
3231
3255
  get: function(key) {
3232
- return this[hashKey(key)];
3256
+ return this[hashKey(key, this.nextUid)];
3233
3257
  },
3234
3258
 
3235
3259
  /**
@@ -3237,7 +3261,7 @@ HashMap.prototype = {
3237
3261
  * @param key
3238
3262
  */
3239
3263
  remove: function(key) {
3240
- var value = this[key = hashKey(key)];
3264
+ var value = this[key = hashKey(key, this.nextUid)];
3241
3265
  delete this[key];
3242
3266
  return value;
3243
3267
  }
@@ -3327,7 +3351,7 @@ function annotate(fn, strictDi, name) {
3327
3351
  argDecl,
3328
3352
  last;
3329
3353
 
3330
- if (typeof fn == 'function') {
3354
+ if (typeof fn === 'function') {
3331
3355
  if (!($inject = fn.$inject)) {
3332
3356
  $inject = [];
3333
3357
  if (fn.length) {
@@ -3547,7 +3571,7 @@ function annotate(fn, strictDi, name) {
3547
3571
 
3548
3572
 
3549
3573
  /**
3550
- * @ngdoc object
3574
+ * @ngdoc service
3551
3575
  * @name $provide
3552
3576
  *
3553
3577
  * @description
@@ -3854,7 +3878,7 @@ function createInjector(modulesToLoad, strictDi) {
3854
3878
  var INSTANTIATING = {},
3855
3879
  providerSuffix = 'Provider',
3856
3880
  path = [],
3857
- loadedModules = new HashMap(),
3881
+ loadedModules = new HashMap([], true),
3858
3882
  providerCache = {
3859
3883
  $provide: {
3860
3884
  provider: supportObject(provider),
@@ -4035,8 +4059,7 @@ function createInjector(modulesToLoad, strictDi) {
4035
4059
  : getService(key)
4036
4060
  );
4037
4061
  }
4038
- if (!fn.$inject) {
4039
- // this means that we must be an array.
4062
+ if (isArray(fn)) {
4040
4063
  fn = fn[length];
4041
4064
  }
4042
4065
 
@@ -4139,7 +4162,7 @@ function $AnchorScrollProvider() {
4139
4162
  function getFirstAnchor(list) {
4140
4163
  var result = null;
4141
4164
  forEach(list, function(element) {
4142
- if (!result && lowercase(element.nodeName) === 'a') result = element;
4165
+ if (!result && nodeName_(element) === 'a') result = element;
4143
4166
  });
4144
4167
  return result;
4145
4168
  }
@@ -5964,8 +5987,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
5964
5987
  nodeName = nodeName_(this.$$element);
5965
5988
 
5966
5989
  // sanitize a[href] and img[src] values
5967
- if ((nodeName === 'A' && key === 'href') ||
5968
- (nodeName === 'IMG' && key === 'src')) {
5990
+ if ((nodeName === 'a' && key === 'href') ||
5991
+ (nodeName === 'img' && key === 'src')) {
5969
5992
  this[key] = value = $$sanitizeUri(value, key === 'src');
5970
5993
  }
5971
5994
 
@@ -6235,10 +6258,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6235
6258
  case 1: /* Element */
6236
6259
  // use the node name: <directive>
6237
6260
  addDirective(directives,
6238
- directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
6261
+ directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
6239
6262
 
6240
6263
  // iterate over the attributes
6241
- for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
6264
+ for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
6242
6265
  j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
6243
6266
  var attrStartName = false;
6244
6267
  var attrEndName = false;
@@ -6246,9 +6269,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6246
6269
  attr = nAttrs[j];
6247
6270
  if (!msie || msie >= 8 || attr.specified) {
6248
6271
  name = attr.name;
6272
+ value = trim(attr.value);
6273
+
6249
6274
  // support ngAttr attribute binding
6250
6275
  ngAttrName = directiveNormalize(name);
6251
- if (NG_ATTR_BINDING.test(ngAttrName)) {
6276
+ if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
6252
6277
  name = snake_case(ngAttrName.substr(6), '-');
6253
6278
  }
6254
6279
 
@@ -6261,9 +6286,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
6261
6286
 
6262
6287
  nName = directiveNormalize(name.toLowerCase());
6263
6288
  attrsMap[nName] = name;
6264
- attrs[nName] = value = trim(attr.value);
6265
- if (getBooleanAttrName(node, nName)) {
6266
- attrs[nName] = true; // presence means true
6289
+ if (isNgAttr || !attrs.hasOwnProperty(nName)) {
6290
+ attrs[nName] = value;
6291
+ if (getBooleanAttrName(node, nName)) {
6292
+ attrs[nName] = true; // presence means true
6293
+ }
6267
6294
  }
6268
6295
  addAttrInterpolateDirective(node, directives, value, nName);
6269
6296
  addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
@@ -7098,8 +7125,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7098
7125
  var tag = nodeName_(node);
7099
7126
  // maction[xlink:href] can source SVG. It's not limited to <maction>.
7100
7127
  if (attrNormalizedName == "xlinkHref" ||
7101
- (tag == "FORM" && attrNormalizedName == "action") ||
7102
- (tag != "IMG" && (attrNormalizedName == "src" ||
7128
+ (tag == "form" && attrNormalizedName == "action") ||
7129
+ (tag != "img" && (attrNormalizedName == "src" ||
7103
7130
  attrNormalizedName == "ngSrc"))) {
7104
7131
  return $sce.RESOURCE_URL;
7105
7132
  }
@@ -7113,7 +7140,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7113
7140
  if (!interpolateFn) return;
7114
7141
 
7115
7142
 
7116
- if (name === "multiple" && nodeName_(node) === "SELECT") {
7143
+ if (name === "multiple" && nodeName_(node) === "select") {
7117
7144
  throw $compileMinErr("selmulti",
7118
7145
  "Binding to the 'multiple' attribute is not supported. Element: {0}",
7119
7146
  startingTag(node));
@@ -7391,7 +7418,7 @@ function $ControllerProvider() {
7391
7418
  instance = $injector.instantiate(expression, locals, constructor);
7392
7419
 
7393
7420
  if (identifier) {
7394
- if (!(locals && typeof locals.$scope == 'object')) {
7421
+ if (!(locals && typeof locals.$scope === 'object')) {
7395
7422
  throw minErr('$controller')('noscp',
7396
7423
  "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
7397
7424
  constructor || expression.name, identifier);
@@ -8265,7 +8292,21 @@ function $HttpProvider() {
8265
8292
  * @param {Object=} config Optional configuration object
8266
8293
  * @returns {HttpPromise} Future object
8267
8294
  */
8268
- createShortMethodsWithData('post', 'put');
8295
+
8296
+ /**
8297
+ * @ngdoc method
8298
+ * @name ng.$http#patch
8299
+ * @methodOf ng.$http
8300
+ *
8301
+ * @description
8302
+ * Shortcut method to perform `PATCH` request.
8303
+ *
8304
+ * @param {string} url Relative or absolute URL specifying the destination of the request
8305
+ * @param {*} data Request content
8306
+ * @param {Object=} config Optional configuration object
8307
+ * @returns {HttpPromise} Future object
8308
+ */
8309
+ createShortMethodsWithData('post', 'put', 'patch');
8269
8310
 
8270
8311
  /**
8271
8312
  * @ngdoc property
@@ -8521,7 +8562,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
8521
8562
  // Safari respectively.
8522
8563
  if (xhr && xhr.readyState == 4) {
8523
8564
  var responseHeaders = null,
8524
- response = null;
8565
+ response = null,
8566
+ statusText = '';
8525
8567
 
8526
8568
  if(status !== ABORTED) {
8527
8569
  responseHeaders = xhr.getAllResponseHeaders();
@@ -8531,11 +8573,17 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
8531
8573
  response = ('response' in xhr) ? xhr.response : xhr.responseText;
8532
8574
  }
8533
8575
 
8576
+ // Accessing statusText on an aborted xhr object will
8577
+ // throw an 'c00c023f error' in IE9 and lower, don't touch it.
8578
+ if (!(status === ABORTED && msie < 10)) {
8579
+ statusText = xhr.statusText;
8580
+ }
8581
+
8534
8582
  completeRequest(callback,
8535
8583
  status || xhr.status,
8536
8584
  response,
8537
8585
  responseHeaders,
8538
- xhr.statusText || '');
8586
+ statusText);
8539
8587
  }
8540
8588
  };
8541
8589
 
@@ -9015,8 +9063,8 @@ function $InterpolateProvider() {
9015
9063
  }
9016
9064
 
9017
9065
  function $IntervalProvider() {
9018
- this.$get = ['$rootScope', '$window', '$q',
9019
- function($rootScope, $window, $q) {
9066
+ this.$get = ['$rootScope', '$window', '$q', '$$q',
9067
+ function($rootScope, $window, $q, $$q) {
9020
9068
  var intervals = {};
9021
9069
 
9022
9070
 
@@ -9146,10 +9194,10 @@ function $IntervalProvider() {
9146
9194
  function interval(fn, delay, count, invokeApply) {
9147
9195
  var setInterval = $window.setInterval,
9148
9196
  clearInterval = $window.clearInterval,
9149
- deferred = $q.defer(),
9150
- promise = deferred.promise,
9151
9197
  iteration = 0,
9152
- skipApply = (isDefined(invokeApply) && !invokeApply);
9198
+ skipApply = (isDefined(invokeApply) && !invokeApply),
9199
+ deferred = (skipApply ? $$q : $q).defer(),
9200
+ promise = deferred.promise;
9153
9201
 
9154
9202
  count = isDefined(count) ? count : 0;
9155
9203
 
@@ -9187,7 +9235,7 @@ function $IntervalProvider() {
9187
9235
  interval.cancel = function(promise) {
9188
9236
  if (promise && promise.$$intervalId in intervals) {
9189
9237
  intervals[promise.$$intervalId].reject('canceled');
9190
- clearInterval(promise.$$intervalId);
9238
+ $window.clearInterval(promise.$$intervalId);
9191
9239
  delete intervals[promise.$$intervalId];
9192
9240
  return true;
9193
9241
  }
@@ -9821,7 +9869,7 @@ function $LocationProvider(){
9821
9869
  html5Mode = false;
9822
9870
 
9823
9871
  /**
9824
- * @ngdoc property
9872
+ * @ngdoc method
9825
9873
  * @name $locationProvider#hashPrefix
9826
9874
  * @description
9827
9875
  * @param {string=} prefix Prefix for hash part (containing path and search)
@@ -9837,7 +9885,7 @@ function $LocationProvider(){
9837
9885
  };
9838
9886
 
9839
9887
  /**
9840
- * @ngdoc property
9888
+ * @ngdoc method
9841
9889
  * @name $locationProvider#html5Mode
9842
9890
  * @description
9843
9891
  * @param {boolean=} mode Use HTML5 strategy if available.
@@ -9906,7 +9954,7 @@ function $LocationProvider(){
9906
9954
  var elm = jqLite(event.target);
9907
9955
 
9908
9956
  // traverse the DOM up to find first A tag
9909
- while (lowercase(elm[0].nodeName) !== 'a') {
9957
+ while (nodeName_(elm[0]) !== 'a') {
9910
9958
  // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
9911
9959
  if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
9912
9960
  }
@@ -10193,14 +10241,7 @@ var $parseMinErr = minErr('$parse');
10193
10241
  //
10194
10242
  // As an example, consider the following Angular expression:
10195
10243
  //
10196
- // {}.toString.constructor(alert("evil JS code"))
10197
- //
10198
- // We want to prevent this type of access. For the sake of performance, during the lexing phase we
10199
- // disallow any "dotted" access to any member named "constructor".
10200
- //
10201
- // For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
10202
- // while evaluating the expression, which is a stronger but more expensive test. Since reflective
10203
- // calls are expensive anyway, this is not such a big deal compared to static dereferencing.
10244
+ // {}.toString.constructor('alert("evil JS code")')
10204
10245
  //
10205
10246
  // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
10206
10247
  // against the expression language, but not to prevent exploits that were enabled by exposing
@@ -10208,17 +10249,19 @@ var $parseMinErr = minErr('$parse');
10208
10249
  // practice and therefore we are not even trying to protect against interaction with an object
10209
10250
  // explicitly exposed in this way.
10210
10251
  //
10211
- // A developer could foil the name check by aliasing the Function constructor under a different
10212
- // name on the scope.
10213
- //
10214
10252
  // In general, it is not possible to access a Window object from an angular expression unless a
10215
10253
  // window or some DOM object that has a reference to window is published onto a Scope.
10254
+ // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
10255
+ // native objects.
10256
+
10216
10257
 
10217
10258
  function ensureSafeMemberName(name, fullExpression) {
10218
- if (name === "constructor") {
10259
+ if (name === "__defineGetter__" || name === "__defineSetter__"
10260
+ || name === "__lookupGetter__" || name === "__lookupSetter__"
10261
+ || name === "__proto__") {
10219
10262
  throw $parseMinErr('isecfld',
10220
- 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
10221
- fullExpression);
10263
+ 'Attempting to access a disallowed field in Angular expressions! '
10264
+ +'Expression: {0}', fullExpression);
10222
10265
  }
10223
10266
  return name;
10224
10267
  }
@@ -10231,7 +10274,7 @@ function ensureSafeObject(obj, fullExpression) {
10231
10274
  'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10232
10275
  fullExpression);
10233
10276
  } else if (// isWindow(obj)
10234
- obj.document && obj.location && obj.alert && obj.setInterval) {
10277
+ obj.window === obj) {
10235
10278
  throw $parseMinErr('isecwindow',
10236
10279
  'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
10237
10280
  fullExpression);
@@ -10240,11 +10283,34 @@ function ensureSafeObject(obj, fullExpression) {
10240
10283
  throw $parseMinErr('isecdom',
10241
10284
  'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
10242
10285
  fullExpression);
10286
+ } else if (// block Object so that we can't get hold of dangerous Object.* methods
10287
+ obj === Object) {
10288
+ throw $parseMinErr('isecobj',
10289
+ 'Referencing Object in Angular expressions is disallowed! Expression: {0}',
10290
+ fullExpression);
10243
10291
  }
10244
10292
  }
10245
10293
  return obj;
10246
10294
  }
10247
10295
 
10296
+ var CALL = Function.prototype.call;
10297
+ var APPLY = Function.prototype.apply;
10298
+ var BIND = Function.prototype.bind;
10299
+
10300
+ function ensureSafeFunction(obj, fullExpression) {
10301
+ if (obj) {
10302
+ if (obj.constructor === obj) {
10303
+ throw $parseMinErr('isecfn',
10304
+ 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
10305
+ fullExpression);
10306
+ } else if (obj === CALL || obj === APPLY || obj === BIND) {
10307
+ throw $parseMinErr('isecff',
10308
+ 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
10309
+ fullExpression);
10310
+ }
10311
+ }
10312
+ }
10313
+
10248
10314
  var OPERATORS = {
10249
10315
  /* jshint bitwise : false */
10250
10316
  'null':function(){return null;},
@@ -10864,6 +10930,7 @@ Parser.prototype = {
10864
10930
  i = indexFn(self, locals),
10865
10931
  v;
10866
10932
 
10933
+ ensureSafeMemberName(i, parser.text);
10867
10934
  if (!o) return undefined;
10868
10935
  v = ensureSafeObject(o[i], parser.text);
10869
10936
  return v;
@@ -10898,7 +10965,7 @@ Parser.prototype = {
10898
10965
  var fnPtr = fn(scope, locals, context) || noop;
10899
10966
 
10900
10967
  ensureSafeObject(context, parser.text);
10901
- ensureSafeObject(fnPtr, parser.text);
10968
+ ensureSafeFunction(fnPtr, parser.text);
10902
10969
 
10903
10970
  // IE stupidity! (IE doesn't have apply for some native functions)
10904
10971
  var v = fnPtr.apply
@@ -10993,6 +11060,8 @@ function setter(obj, path, setValue, fullExp) {
10993
11060
  obj = propertyObj;
10994
11061
  }
10995
11062
  key = ensureSafeMemberName(element.shift(), fullExp);
11063
+ ensureSafeObject(obj, fullExp);
11064
+ ensureSafeObject(obj[key], fullExp);
10996
11065
  obj[key] = setValue;
10997
11066
  return setValue;
10998
11067
  }
@@ -11210,11 +11279,7 @@ function $ParseProvider() {
11210
11279
  cache[exp] = parsedExpression;
11211
11280
  }
11212
11281
 
11213
- if (parsedExpression.constant) {
11214
- parsedExpression.$$unwatch = true;
11215
- }
11216
-
11217
- return oneTime ? oneTimeWrapper(parsedExpression) : parsedExpression;
11282
+ return oneTime || parsedExpression.constant ? oneTimeWrapper(parsedExpression) : parsedExpression;
11218
11283
 
11219
11284
  case 'function':
11220
11285
  return exp;
@@ -11233,7 +11298,7 @@ function $ParseProvider() {
11233
11298
 
11234
11299
  function oneTimeParseFn(self, locals) {
11235
11300
  if (!stable) {
11236
- lastValue = expression(self, locals);
11301
+ lastValue = expression.constant && lastValue ? lastValue : expression(self, locals);
11237
11302
  oneTimeParseFn.$$unwatch = isDefined(lastValue);
11238
11303
  if (oneTimeParseFn.$$unwatch && self && self.$$postDigestQueue) {
11239
11304
  self.$$postDigestQueue.push(function () {
@@ -11275,17 +11340,13 @@ function $ParseProvider() {
11275
11340
  * var deferred = $q.defer();
11276
11341
  *
11277
11342
  * setTimeout(function() {
11278
- * // since this fn executes async in a future turn of the event loop, we need to wrap
11279
- * // our code into an $apply call so that the model changes are properly observed.
11280
- * scope.$apply(function() {
11281
- * deferred.notify('About to greet ' + name + '.');
11282
- *
11283
- * if (okToGreet(name)) {
11284
- * deferred.resolve('Hello, ' + name + '!');
11285
- * } else {
11286
- * deferred.reject('Greeting ' + name + ' is not allowed.');
11287
- * }
11288
- * });
11343
+ * deferred.notify('About to greet ' + name + '.');
11344
+ *
11345
+ * if (okToGreet(name)) {
11346
+ * deferred.resolve('Hello, ' + name + '!');
11347
+ * } else {
11348
+ * deferred.reject('Greeting ' + name + ' is not allowed.');
11349
+ * }
11289
11350
  * }, 1000);
11290
11351
  *
11291
11352
  * return deferred.promise;
@@ -11429,6 +11490,13 @@ function $QProvider() {
11429
11490
  }];
11430
11491
  }
11431
11492
 
11493
+ function $$QProvider() {
11494
+ this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
11495
+ return qFactory(function(callback) {
11496
+ $browser.defer(callback);
11497
+ }, $exceptionHandler);
11498
+ }];
11499
+ }
11432
11500
 
11433
11501
  /**
11434
11502
  * Constructs a promise manager.
@@ -12176,7 +12244,7 @@ function $RootScopeProvider(){
12176
12244
  * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
12177
12245
  * If any one expression in the collection changes the `listener` is executed.
12178
12246
  *
12179
- * - The items in the `watchCollection` array are observed via standard $watch operation and are examined on every
12247
+ * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
12180
12248
  * call to $digest() to see if any items changes.
12181
12249
  * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
12182
12250
  *
@@ -12506,7 +12574,7 @@ function $RootScopeProvider(){
12506
12574
  if ((value = watch.get(current)) !== (last = watch.last) &&
12507
12575
  !(watch.eq
12508
12576
  ? equals(value, last)
12509
- : (typeof value == 'number' && typeof last == 'number'
12577
+ : (typeof value === 'number' && typeof last === 'number'
12510
12578
  && isNaN(value) && isNaN(last)))) {
12511
12579
  dirty = true;
12512
12580
  lastDirtyWatch = watch;
@@ -13866,7 +13934,7 @@ function $SceProvider() {
13866
13934
 
13867
13935
  /**
13868
13936
  * @ngdoc method
13869
- * @name $sce#parse
13937
+ * @name $sce#parseAs
13870
13938
  *
13871
13939
  * @description
13872
13940
  * Converts Angular {@link guide/expression expression} into a function. This is like {@link
@@ -14253,8 +14321,8 @@ function $SnifferProvider() {
14253
14321
  }
14254
14322
 
14255
14323
  function $TimeoutProvider() {
14256
- this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
14257
- function($rootScope, $browser, $q, $exceptionHandler) {
14324
+ this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
14325
+ function($rootScope, $browser, $q, $$q, $exceptionHandler) {
14258
14326
  var deferreds = {};
14259
14327
 
14260
14328
 
@@ -14284,9 +14352,9 @@ function $TimeoutProvider() {
14284
14352
  *
14285
14353
  */
14286
14354
  function timeout(fn, delay, invokeApply) {
14287
- var deferred = $q.defer(),
14355
+ var skipApply = (isDefined(invokeApply) && !invokeApply),
14356
+ deferred = (skipApply ? $$q : $q).defer(),
14288
14357
  promise = deferred.promise,
14289
- skipApply = (isDefined(invokeApply) && !invokeApply),
14290
14358
  timeoutId;
14291
14359
 
14292
14360
  timeoutId = $browser.defer(function() {
@@ -14824,7 +14892,7 @@ function filterFilter() {
14824
14892
  // jshint +W086
14825
14893
  for (var key in expression) {
14826
14894
  (function(path) {
14827
- if (typeof expression[path] == 'undefined') return;
14895
+ if (typeof expression[path] === 'undefined') return;
14828
14896
  predicates.push(function(value) {
14829
14897
  return search(path == '$' ? value : (value && value[path]), expression[path]);
14830
14898
  });
@@ -14979,6 +15047,7 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14979
15047
  var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
14980
15048
  if (match && match[2] == '-' && match[3] > fractionSize + 1) {
14981
15049
  numStr = '0';
15050
+ number = 0;
14982
15051
  } else {
14983
15052
  formatedText = numStr;
14984
15053
  hasExponent = true;
@@ -14993,8 +15062,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
14993
15062
  fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
14994
15063
  }
14995
15064
 
14996
- var pow = Math.pow(10, fractionSize + 1);
14997
- number = Math.floor(number * pow + 5) / pow;
15065
+ // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
15066
+ // inspired by:
15067
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
15068
+ number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
15069
+
14998
15070
  var fraction = ('' + number).split(DECIMAL_SEP);
14999
15071
  var whole = fraction[0];
15000
15072
  fraction = fraction[1] || '';
@@ -15617,7 +15689,7 @@ function orderByFilter($parse){
15617
15689
  return 0;
15618
15690
  }
15619
15691
  function reverseComparator(comp, descending) {
15620
- return toBoolean(descending)
15692
+ return descending
15621
15693
  ? function(a,b){return comp(b,a);}
15622
15694
  : comp;
15623
15695
  }
@@ -16576,7 +16648,7 @@ var ngFormDirective = formDirectiveFactory(true);
16576
16648
  */
16577
16649
 
16578
16650
  var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
16579
- var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
16651
+ var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
16580
16652
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
16581
16653
  var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
16582
16654
  var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/;
@@ -16742,7 +16814,7 @@ var inputType = {
16742
16814
  expect(valid.getText()).toContain('myForm.input.$valid = false');
16743
16815
  });
16744
16816
  </file>
16745
- </example>f
16817
+ </example>
16746
16818
  */
16747
16819
  'date': createDateInputType('date', DATE_REGEXP,
16748
16820
  createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
@@ -17427,15 +17499,29 @@ function validate(ctrl, validatorName, validity, value){
17427
17499
  return validity ? value : undefined;
17428
17500
  }
17429
17501
 
17502
+ function testFlags(validity, flags) {
17503
+ var i, flag;
17504
+ if (flags) {
17505
+ for (i=0; i<flags.length; ++i) {
17506
+ flag = flags[i];
17507
+ if (validity[flag]) {
17508
+ return true;
17509
+ }
17510
+ }
17511
+ }
17512
+ return false;
17513
+ }
17430
17514
 
17431
- function addNativeHtml5Validators(ctrl, validatorName, element) {
17432
- var validity = element.prop('validity');
17515
+ // Pass validity so that behaviour can be mocked easier.
17516
+ function addNativeHtml5Validators(ctrl, validatorName, badFlags, ignoreFlags, validity) {
17433
17517
  if (isObject(validity)) {
17518
+ ctrl.$$hasNativeValidators = true;
17434
17519
  var validator = function(value) {
17435
17520
  // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
17436
17521
  // perform the required validation)
17437
- if (!ctrl.$error[validatorName] && (validity.badInput || validity.customError ||
17438
- validity.typeMismatch) && !validity.valueMissing) {
17522
+ if (!ctrl.$error[validatorName] &&
17523
+ !testFlags(validity, ignoreFlags) &&
17524
+ testFlags(validity, badFlags)) {
17439
17525
  ctrl.$setValidity(validatorName, false);
17440
17526
  return;
17441
17527
  }
@@ -17446,8 +17532,9 @@ function addNativeHtml5Validators(ctrl, validatorName, element) {
17446
17532
  }
17447
17533
 
17448
17534
  function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17449
- var validity = element.prop('validity');
17535
+ var validity = element.prop(VALIDITY_STATE_PROPERTY);
17450
17536
  var placeholder = element[0].placeholder, noevent = {};
17537
+ ctrl.$$validityState = validity;
17451
17538
 
17452
17539
  // In composition mode, users are still inputing intermediate text buffer,
17453
17540
  // hold the listener until composition is done.
@@ -17482,20 +17569,20 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17482
17569
  // By default we will trim the value
17483
17570
  // If the attribute ng-trim exists we will avoid trimming
17484
17571
  // e.g. <input ng-model="foo" ng-trim="false">
17485
- if (toBoolean(attr.ngTrim || 'T')) {
17572
+ if (!attr.ngTrim || attr.ngTrim !== 'false') {
17486
17573
  value = trim(value);
17487
17574
  }
17488
17575
 
17489
- if (ctrl.$viewValue !== value ||
17490
- // If the value is still empty/falsy, and there is no `required` error, run validators
17491
- // again. This enables HTML5 constraint validation errors to affect Angular validation
17492
- // even when the first character entered causes an error.
17493
- (validity && value === '' && !validity.valueMissing)) {
17576
+ // If a control is suffering from bad input, browsers discard its value, so it may be
17577
+ // necessary to revalidate even if the control's value is the same empty value twice in
17578
+ // a row.
17579
+ var revalidate = validity && ctrl.$$hasNativeValidators;
17580
+ if (ctrl.$viewValue !== value || (value === '' && revalidate)) {
17494
17581
  if (scope.$$phase) {
17495
- ctrl.$setViewValue(value, event);
17582
+ ctrl.$setViewValue(value, event, revalidate);
17496
17583
  } else {
17497
17584
  scope.$apply(function() {
17498
- ctrl.$setViewValue(value, event);
17585
+ ctrl.$setViewValue(value, event, revalidate);
17499
17586
  });
17500
17587
  }
17501
17588
  }
@@ -17644,6 +17731,8 @@ function createDateInputType(type, regexp, parseDate, format) {
17644
17731
  };
17645
17732
  }
17646
17733
 
17734
+ var numberBadFlags = ['badInput'];
17735
+
17647
17736
  function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17648
17737
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17649
17738
 
@@ -17658,7 +17747,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17658
17747
  }
17659
17748
  });
17660
17749
 
17661
- addNativeHtml5Validators(ctrl, 'number', element);
17750
+ addNativeHtml5Validators(ctrl, 'number', numberBadFlags, null, ctrl.$$validityState);
17662
17751
 
17663
17752
  ctrl.$formatters.push(function(value) {
17664
17753
  return ctrl.$isEmpty(value) ? '' : '' + value;
@@ -17692,23 +17781,19 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17692
17781
  function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17693
17782
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17694
17783
 
17695
- var urlValidator = function(value) {
17696
- return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
17784
+ ctrl.$validators.url = function(modelValue, viewValue) {
17785
+ var value = modelValue || viewValue;
17786
+ return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
17697
17787
  };
17698
-
17699
- ctrl.$formatters.push(urlValidator);
17700
- ctrl.$parsers.push(urlValidator);
17701
17788
  }
17702
17789
 
17703
17790
  function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
17704
17791
  textInputType(scope, element, attr, ctrl, $sniffer, $browser);
17705
17792
 
17706
- var emailValidator = function(value) {
17707
- return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
17793
+ ctrl.$validators.email = function(modelValue, viewValue) {
17794
+ var value = modelValue || viewValue;
17795
+ return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
17708
17796
  };
17709
-
17710
- ctrl.$formatters.push(emailValidator);
17711
- ctrl.$parsers.push(emailValidator);
17712
17797
  }
17713
17798
 
17714
17799
  function radioInputType(scope, element, attr, ctrl) {
@@ -18163,7 +18248,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18163
18248
  * `ngModel.$validators` pipeline which is designed to handle validations with true/false values.
18164
18249
  *
18165
18250
  * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
18166
- * to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
18251
+ * to `$error[validationErrorKey]=!isValid` so that it is available for data-binding.
18167
18252
  * The `validationErrorKey` should be in camelCase and will get converted into dash-case
18168
18253
  * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
18169
18254
  * class and can be bound to as `{{someForm.someControl.$error.myError}}` .
@@ -18342,11 +18427,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18342
18427
  * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
18343
18428
  * usually handles calling this in response to input events.
18344
18429
  */
18345
- this.$commitViewValue = function() {
18430
+ this.$commitViewValue = function(revalidate) {
18346
18431
  var viewValue = ctrl.$viewValue;
18347
18432
 
18348
18433
  $timeout.cancel(pendingDebounce);
18349
- if (ctrl.$$lastCommittedViewValue === viewValue) {
18434
+ if (!revalidate && ctrl.$$lastCommittedViewValue === viewValue) {
18350
18435
  return;
18351
18436
  }
18352
18437
  ctrl.$$lastCommittedViewValue = viewValue;
@@ -18411,14 +18496,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18411
18496
  * @param {string} value Value from the view.
18412
18497
  * @param {string} trigger Event that triggered the update.
18413
18498
  */
18414
- this.$setViewValue = function(value, trigger) {
18499
+ this.$setViewValue = function(value, trigger, revalidate) {
18415
18500
  ctrl.$viewValue = value;
18416
18501
  if (!ctrl.$options || ctrl.$options.updateOnDefault) {
18417
- ctrl.$$debounceViewValueCommit(trigger);
18502
+ ctrl.$$debounceViewValueCommit(trigger, revalidate);
18418
18503
  }
18419
18504
  };
18420
18505
 
18421
- this.$$debounceViewValueCommit = function(trigger) {
18506
+ this.$$debounceViewValueCommit = function(trigger, revalidate) {
18422
18507
  var debounceDelay = 0,
18423
18508
  options = ctrl.$options,
18424
18509
  debounce;
@@ -18437,10 +18522,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18437
18522
  $timeout.cancel(pendingDebounce);
18438
18523
  if (debounceDelay) {
18439
18524
  pendingDebounce = $timeout(function() {
18440
- ctrl.$commitViewValue();
18525
+ ctrl.$commitViewValue(revalidate);
18441
18526
  }, debounceDelay);
18442
18527
  } else {
18443
- ctrl.$commitViewValue();
18528
+ ctrl.$commitViewValue(revalidate);
18444
18529
  }
18445
18530
  };
18446
18531
 
@@ -20484,7 +20569,7 @@ var ngIfDirective = ['$animate', function($animate) {
20484
20569
  var block, childScope, previousElements;
20485
20570
  $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
20486
20571
 
20487
- if (toBoolean(value)) {
20572
+ if (value) {
20488
20573
  if (!childScope) {
20489
20574
  $transclude(function (clone, newScope) {
20490
20575
  childScope = newScope;
@@ -20967,7 +21052,7 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
20967
21052
  * When one person, perhaps John, views the document, "John is viewing" will be shown.
20968
21053
  * When three people view the document, no explicit number rule is found, so
20969
21054
  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
20970
- * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
21055
+ * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
20971
21056
  * is shown.
20972
21057
  *
20973
21058
  * Note that when you specify offsets, you must provide explicit number rules for
@@ -21516,15 +21601,10 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
21516
21601
  * <div ng-show="myValue" class="ng-hide"></div>
21517
21602
  * ```
21518
21603
  *
21519
- * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
21520
- * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
21604
+ * When the ngShow expression evaluates to a falsy value then the ng-hide CSS class is added to the class
21605
+ * attribute on the element causing it to become hidden. When truthy, the ng-hide CSS class is removed
21521
21606
  * from the element causing the element not to appear hidden.
21522
21607
  *
21523
- * <div class="alert alert-warning">
21524
- * **Note:** Here is a list of values that ngShow will consider as a falsy value (case insensitive):<br />
21525
- * "f" / "0" / "false" / "no" / "n" / "[]"
21526
- * </div>
21527
- *
21528
21608
  * ## Why is !important used?
21529
21609
  *
21530
21610
  * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
@@ -21660,7 +21740,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
21660
21740
  var ngShowDirective = ['$animate', function($animate) {
21661
21741
  return function(scope, element, attr) {
21662
21742
  scope.$watch(attr.ngShow, function ngShowWatchAction(value){
21663
- $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
21743
+ $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide');
21664
21744
  });
21665
21745
  };
21666
21746
  }];
@@ -21685,15 +21765,10 @@ var ngShowDirective = ['$animate', function($animate) {
21685
21765
  * <div ng-hide="myValue"></div>
21686
21766
  * ```
21687
21767
  *
21688
- * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
21689
- * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
21768
+ * When the ngHide expression evaluates to a truthy value then the .ng-hide CSS class is added to the class
21769
+ * attribute on the element causing it to become hidden. When falsy, the ng-hide CSS class is removed
21690
21770
  * from the element causing the element not to appear hidden.
21691
21771
  *
21692
- * <div class="alert alert-warning">
21693
- * **Note:** Here is a list of values that ngHide will consider as a falsy value (case insensitive):<br />
21694
- * "f" / "0" / "false" / "no" / "n" / "[]"
21695
- * </div>
21696
- *
21697
21772
  * ## Why is !important used?
21698
21773
  *
21699
21774
  * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
@@ -21816,7 +21891,7 @@ var ngShowDirective = ['$animate', function($animate) {
21816
21891
  var ngHideDirective = ['$animate', function($animate) {
21817
21892
  return function(scope, element, attr) {
21818
21893
  scope.$watch(attr.ngHide, function ngHideWatchAction(value){
21819
- $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
21894
+ $animate[value ? 'addClass' : 'removeClass'](element, 'ng-hide');
21820
21895
  });
21821
21896
  };
21822
21897
  }];