angularjs-rails 1.3.3 → 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/angularjs-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/angular-animate.js +14 -14
  4. data/vendor/assets/javascripts/angular-aria.js +1 -1
  5. data/vendor/assets/javascripts/angular-cookies.js +1 -1
  6. data/vendor/assets/javascripts/angular-loader.js +2 -2
  7. data/vendor/assets/javascripts/angular-messages.js +1 -1
  8. data/vendor/assets/javascripts/angular-mocks.js +1 -1
  9. data/vendor/assets/javascripts/angular-resource.js +1 -1
  10. data/vendor/assets/javascripts/angular-route.js +3 -3
  11. data/vendor/assets/javascripts/angular-sanitize.js +7 -7
  12. data/vendor/assets/javascripts/angular-scenario.js +354 -190
  13. data/vendor/assets/javascripts/angular-touch.js +1 -1
  14. data/vendor/assets/javascripts/angular.js +354 -190
  15. data/vendor/assets/javascripts/unstable/angular-animate.js +14 -14
  16. data/vendor/assets/javascripts/unstable/angular-aria.js +1 -1
  17. data/vendor/assets/javascripts/unstable/angular-cookies.js +1 -1
  18. data/vendor/assets/javascripts/unstable/angular-loader.js +2 -2
  19. data/vendor/assets/javascripts/unstable/angular-messages.js +1 -1
  20. data/vendor/assets/javascripts/unstable/angular-mocks.js +1 -1
  21. data/vendor/assets/javascripts/unstable/angular-resource.js +1 -1
  22. data/vendor/assets/javascripts/unstable/angular-route.js +3 -3
  23. data/vendor/assets/javascripts/unstable/angular-sanitize.js +7 -7
  24. data/vendor/assets/javascripts/unstable/angular-scenario.js +354 -190
  25. data/vendor/assets/javascripts/unstable/angular-touch.js +1 -1
  26. data/vendor/assets/javascripts/unstable/angular.js +354 -190
  27. metadata +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.3
2
+ * @license AngularJS v1.3.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.3.3
2
+ * @license AngularJS v1.3.4
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -54,7 +54,7 @@ function minErr(module, ErrorConstructor) {
54
54
  return match;
55
55
  });
56
56
 
57
- message = message + '\nhttp://errors.angularjs.org/1.3.3/' +
57
+ message = message + '\nhttp://errors.angularjs.org/1.3.4/' +
58
58
  (module ? module + '/' : '') + code;
59
59
  for (i = 2; i < arguments.length; i++) {
60
60
  message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
@@ -426,7 +426,7 @@ function int(str) {
426
426
 
427
427
 
428
428
  function inherit(parent, extra) {
429
- return extend(new (extend(function() {}, {prototype:parent}))(), extra);
429
+ return extend(Object.create(parent), extra);
430
430
  }
431
431
 
432
432
  /**
@@ -689,7 +689,7 @@ function makeMap(str) {
689
689
 
690
690
 
691
691
  function nodeName_(element) {
692
- return lowercase(element.nodeName || element[0].nodeName);
692
+ return lowercase(element.nodeName || (element[0] && element[0].nodeName));
693
693
  }
694
694
 
695
695
  function includes(array, obj) {
@@ -1395,8 +1395,8 @@ function angularInit(element, bootstrap) {
1395
1395
  * @param {Object=} config an object for defining configuration options for the application. The
1396
1396
  * following keys are supported:
1397
1397
  *
1398
- * - `strictDi`: disable automatic function annotation for the application. This is meant to
1399
- * 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`.
1400
1400
  *
1401
1401
  * @returns {auto.$injector} Returns the newly created injector for this app.
1402
1402
  */
@@ -2100,11 +2100,11 @@ function toDebugString(obj) {
2100
2100
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2101
2101
  */
2102
2102
  var version = {
2103
- full: '1.3.3', // 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
2104
2104
  major: 1, // package task
2105
2105
  minor: 3,
2106
- dot: 3,
2107
- codeName: 'undersea-arithmetic'
2106
+ dot: 4,
2107
+ codeName: 'highfalutin-petroglyph'
2108
2108
  };
2109
2109
 
2110
2110
 
@@ -2327,10 +2327,12 @@ function publishExternalAPI(angular) {
2327
2327
  * `'ngModel'`).
2328
2328
  * - `injector()` - retrieves the injector of the current element or its parent.
2329
2329
  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2330
- * element or its parent.
2330
+ * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2331
+ * be enabled.
2331
2332
  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2332
2333
  * current element. This getter should be used only on elements that contain a directive which starts a new isolate
2333
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.
2334
2336
  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2335
2337
  * parent element is reached.
2336
2338
  *
@@ -3325,9 +3327,10 @@ HashMap.prototype = {
3325
3327
  * Creates an injector object that can be used for retrieving services as well as for
3326
3328
  * dependency injection (see {@link guide/di dependency injection}).
3327
3329
  *
3328
-
3329
3330
  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3330
- * {@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.
3331
3334
  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3332
3335
  *
3333
3336
  * @example
@@ -3473,8 +3476,10 @@ function annotate(fn, strictDi, name) {
3473
3476
  * ## Inference
3474
3477
  *
3475
3478
  * In JavaScript calling `toString()` on a function returns the function definition. The definition
3476
- * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
3477
- * 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.
3478
3483
  *
3479
3484
  * ## `$inject` Annotation
3480
3485
  * By adding an `$inject` property onto a function the injection parameters can be specified.
@@ -3559,6 +3564,8 @@ function annotate(fn, strictDi, name) {
3559
3564
  * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
3560
3565
  * ```
3561
3566
  *
3567
+ * You can disallow this method by using strict injection mode.
3568
+ *
3562
3569
  * This method does not work with code minification / obfuscation. For this reason the following
3563
3570
  * annotation strategies are supported.
3564
3571
  *
@@ -3611,6 +3618,8 @@ function annotate(fn, strictDi, name) {
3611
3618
  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
3612
3619
  * be retrieved as described above.
3613
3620
  *
3621
+ * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
3622
+ *
3614
3623
  * @returns {Array.<string>} The names of the services which the function requires.
3615
3624
  */
3616
3625
 
@@ -4130,14 +4139,11 @@ function createInjector(modulesToLoad, strictDi) {
4130
4139
  }
4131
4140
 
4132
4141
  function instantiate(Type, locals, serviceName) {
4133
- var Constructor = function() {},
4134
- instance, returnedValue;
4135
-
4136
4142
  // Check if Type is annotated and use just the given function at n-1 as parameter
4137
4143
  // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4138
- Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
4139
- instance = new Constructor();
4140
- 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);
4141
4147
 
4142
4148
  return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
4143
4149
  }
@@ -4973,7 +4979,7 @@ function Browser(window, document, $log, $sniffer) {
4973
4979
  // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
4974
4980
  // See https://github.com/angular/angular.js/commit/ffb2701
4975
4981
  if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
4976
- return;
4982
+ return self;
4977
4983
  }
4978
4984
  var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
4979
4985
  lastBrowserUrl = url;
@@ -7885,10 +7891,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7885
7891
  var childBoundTranscludeFn = boundTranscludeFn;
7886
7892
  if (scope.$$destroyed) return;
7887
7893
  if (linkQueue) {
7888
- linkQueue.push(scope);
7889
- linkQueue.push(node);
7890
- linkQueue.push(rootElement);
7891
- linkQueue.push(childBoundTranscludeFn);
7894
+ linkQueue.push(scope,
7895
+ node,
7896
+ rootElement,
7897
+ childBoundTranscludeFn);
7892
7898
  } else {
7893
7899
  if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
7894
7900
  childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
@@ -8357,10 +8363,10 @@ function $ControllerProvider() {
8357
8363
  //
8358
8364
  // This feature is not intended for use by applications, and is thus not documented
8359
8365
  // publicly.
8360
- var Constructor = function() {};
8361
- Constructor.prototype = (isArray(expression) ?
8366
+ // Object creation: http://jsperf.com/create-constructor/2
8367
+ var controllerPrototype = (isArray(expression) ?
8362
8368
  expression[expression.length - 1] : expression).prototype;
8363
- instance = new Constructor();
8369
+ instance = Object.create(controllerPrototype);
8364
8370
 
8365
8371
  if (identifier) {
8366
8372
  addIdentifier(locals, identifier, instance, constructor || expression.name);
@@ -8501,7 +8507,7 @@ function defaultHttpResponseTransform(data, headers) {
8501
8507
  * @returns {Object} Parsed headers as key value object
8502
8508
  */
8503
8509
  function parseHeaders(headers) {
8504
- var parsed = {}, key, val, i;
8510
+ var parsed = createMap(), key, val, i;
8505
8511
 
8506
8512
  if (!headers) return parsed;
8507
8513
 
@@ -8538,7 +8544,11 @@ function headersGetter(headers) {
8538
8544
  if (!headersObj) headersObj = parseHeaders(headers);
8539
8545
 
8540
8546
  if (name) {
8541
- return headersObj[lowercase(name)] || null;
8547
+ var value = headersObj[lowercase(name)];
8548
+ if (value === void 0) {
8549
+ value = null;
8550
+ }
8551
+ return value;
8542
8552
  }
8543
8553
 
8544
8554
  return headersObj;
@@ -8587,6 +8597,11 @@ function $HttpProvider() {
8587
8597
  *
8588
8598
  * Object containing default values for all {@link ng.$http $http} requests.
8589
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
+ *
8590
8605
  * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
8591
8606
  * Defaults value is `'XSRF-TOKEN'`.
8592
8607
  *
@@ -8600,6 +8615,7 @@ function $HttpProvider() {
8600
8615
  * - **`defaults.headers.post`**
8601
8616
  * - **`defaults.headers.put`**
8602
8617
  * - **`defaults.headers.patch`**
8618
+ *
8603
8619
  **/
8604
8620
  var defaults = this.defaults = {
8605
8621
  // transform incoming response data
@@ -8814,6 +8830,21 @@ function $HttpProvider() {
8814
8830
  * In addition, you can supply a `headers` property in the config object passed when
8815
8831
  * calling `$http(config)`, which overrides the defaults without changing them globally.
8816
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
+ * ```
8817
8848
  *
8818
8849
  * ## Transforming Requests and Responses
8819
8850
  *
@@ -9193,6 +9224,10 @@ function $HttpProvider() {
9193
9224
  };
9194
9225
  var headers = mergeHeaders(requestConfig);
9195
9226
 
9227
+ if (!angular.isObject(requestConfig)) {
9228
+ throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
9229
+ }
9230
+
9196
9231
  extend(config, requestConfig);
9197
9232
  config.headers = headers;
9198
9233
  config.method = uppercase(config.method);
@@ -10687,6 +10722,13 @@ var locationPrototype = {
10687
10722
  * Return full url representation with all segments encoded according to rules specified in
10688
10723
  * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
10689
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
+ *
10690
10732
  * @return {string} full url
10691
10733
  */
10692
10734
  absUrl: locationGetter('$$absUrl'),
@@ -10702,6 +10744,13 @@ var locationPrototype = {
10702
10744
  *
10703
10745
  * Change path, search and hash, when called with parameter and return `$location`.
10704
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
+ *
10705
10754
  * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
10706
10755
  * @return {string} url
10707
10756
  */
@@ -10710,8 +10759,8 @@ var locationPrototype = {
10710
10759
  return this.$$url;
10711
10760
 
10712
10761
  var match = PATH_MATCH.exec(url);
10713
- if (match[1]) this.path(decodeURIComponent(match[1]));
10714
- 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] || '');
10715
10764
  this.hash(match[5] || '');
10716
10765
 
10717
10766
  return this;
@@ -10726,6 +10775,13 @@ var locationPrototype = {
10726
10775
  *
10727
10776
  * Return protocol of current url.
10728
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
+ *
10729
10785
  * @return {string} protocol of current url
10730
10786
  */
10731
10787
  protocol: locationGetter('$$protocol'),
@@ -10739,6 +10795,13 @@ var locationPrototype = {
10739
10795
  *
10740
10796
  * Return host of current url.
10741
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
+ *
10742
10805
  * @return {string} host of current url.
10743
10806
  */
10744
10807
  host: locationGetter('$$host'),
@@ -10752,6 +10815,13 @@ var locationPrototype = {
10752
10815
  *
10753
10816
  * Return port of current url.
10754
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
+ *
10755
10825
  * @return {Number} port
10756
10826
  */
10757
10827
  port: locationGetter('$$port'),
@@ -10770,6 +10840,13 @@ var locationPrototype = {
10770
10840
  * Note: Path should always begin with forward slash (/), this method will add the forward slash
10771
10841
  * if it is missing.
10772
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
+ *
10773
10850
  * @param {(string|number)=} path New path
10774
10851
  * @return {string} path
10775
10852
  */
@@ -10795,10 +10872,9 @@ var locationPrototype = {
10795
10872
  * var searchObject = $location.search();
10796
10873
  * // => {foo: 'bar', baz: 'xoxo'}
10797
10874
  *
10798
- *
10799
10875
  * // set foo to 'yipee'
10800
10876
  * $location.search('foo', 'yipee');
10801
- * // => $location
10877
+ * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
10802
10878
  * ```
10803
10879
  *
10804
10880
  * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
@@ -10868,6 +10944,13 @@ var locationPrototype = {
10868
10944
  *
10869
10945
  * Change hash fragment when called with parameter and return `$location`.
10870
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
+ *
10871
10954
  * @param {(string|number)=} hash New hash fragment
10872
10955
  * @return {string} hash
10873
10956
  */
@@ -16599,7 +16682,7 @@ function filterFilter() {
16599
16682
  *
16600
16683
  * @param {number} amount Input to filter.
16601
16684
  * @param {string=} symbol Currency symbol or identifier to be displayed.
16602
- * @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
16603
16686
  * @returns {string} Formatted number.
16604
16687
  *
16605
16688
  *
@@ -16649,8 +16732,7 @@ function currencyFilter($locale) {
16649
16732
  }
16650
16733
 
16651
16734
  if (isUndefined(fractionSize)) {
16652
- // TODO: read the default value from the locale file
16653
- fractionSize = 2;
16735
+ fractionSize = formats.PATTERNS[1].maxFrac;
16654
16736
  }
16655
16737
 
16656
16738
  // if null or undefined pass it through
@@ -16802,9 +16884,9 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
16802
16884
  }
16803
16885
  }
16804
16886
 
16805
- parts.push(isNegative ? pattern.negPre : pattern.posPre);
16806
- parts.push(formatedText);
16807
- parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
16887
+ parts.push(isNegative ? pattern.negPre : pattern.posPre,
16888
+ formatedText,
16889
+ isNegative ? pattern.negSuf : pattern.posSuf);
16808
16890
  return parts.join('');
16809
16891
  }
16810
16892
 
@@ -18384,9 +18466,7 @@ var formDirectiveFactory = function(isNgForm) {
18384
18466
  controller.$setSubmitted();
18385
18467
  });
18386
18468
 
18387
- event.preventDefault
18388
- ? event.preventDefault()
18389
- : event.returnValue = false; // IE
18469
+ event.preventDefault();
18390
18470
  };
18391
18471
 
18392
18472
  addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
@@ -18473,7 +18553,8 @@ var inputType = {
18473
18553
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
18474
18554
  * minlength.
18475
18555
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
18476
- * maxlength.
18556
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
18557
+ * any length.
18477
18558
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
18478
18559
  * that contains the regular expression body that will be converted to a regular expression
18479
18560
  * as in the ngPattern directive.
@@ -19021,7 +19102,8 @@ var inputType = {
19021
19102
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19022
19103
  * minlength.
19023
19104
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19024
- * maxlength.
19105
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19106
+ * any length.
19025
19107
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19026
19108
  * that contains the regular expression body that will be converted to a regular expression
19027
19109
  * as in the ngPattern directive.
@@ -19108,7 +19190,8 @@ var inputType = {
19108
19190
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19109
19191
  * minlength.
19110
19192
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19111
- * maxlength.
19193
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19194
+ * any length.
19112
19195
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19113
19196
  * that contains the regular expression body that will be converted to a regular expression
19114
19197
  * as in the ngPattern directive.
@@ -19196,7 +19279,8 @@ var inputType = {
19196
19279
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19197
19280
  * minlength.
19198
19281
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19199
- * maxlength.
19282
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
19283
+ * any length.
19200
19284
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
19201
19285
  * that contains the regular expression body that will be converted to a regular expression
19202
19286
  * as in the ngPattern directive.
@@ -19467,7 +19551,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19467
19551
  element.on('change', listener);
19468
19552
 
19469
19553
  ctrl.$render = function() {
19470
- element.val(ctrl.$isEmpty(ctrl.$modelValue) ? '' : ctrl.$viewValue);
19554
+ element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
19471
19555
  };
19472
19556
  }
19473
19557
 
@@ -19577,10 +19661,10 @@ function createDateInputType(type, regexp, parseDate, format) {
19577
19661
  });
19578
19662
 
19579
19663
  ctrl.$formatters.push(function(value) {
19580
- if (!ctrl.$isEmpty(value)) {
19581
- if (!isDate(value)) {
19582
- throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
19583
- }
19664
+ if (value && !isDate(value)) {
19665
+ throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
19666
+ }
19667
+ if (isValidDate(value)) {
19584
19668
  previousDate = value;
19585
19669
  if (previousDate && timezone === 'UTC') {
19586
19670
  var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
@@ -19589,14 +19673,14 @@ function createDateInputType(type, regexp, parseDate, format) {
19589
19673
  return $filter('date')(value, format, timezone);
19590
19674
  } else {
19591
19675
  previousDate = null;
19676
+ return '';
19592
19677
  }
19593
- return '';
19594
19678
  });
19595
19679
 
19596
19680
  if (isDefined(attr.min) || attr.ngMin) {
19597
19681
  var minVal;
19598
19682
  ctrl.$validators.min = function(value) {
19599
- return ctrl.$isEmpty(value) || isUndefined(minVal) || parseDate(value) >= minVal;
19683
+ return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
19600
19684
  };
19601
19685
  attr.$observe('min', function(val) {
19602
19686
  minVal = parseObservedDateValue(val);
@@ -19607,18 +19691,18 @@ function createDateInputType(type, regexp, parseDate, format) {
19607
19691
  if (isDefined(attr.max) || attr.ngMax) {
19608
19692
  var maxVal;
19609
19693
  ctrl.$validators.max = function(value) {
19610
- return ctrl.$isEmpty(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
19694
+ return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
19611
19695
  };
19612
19696
  attr.$observe('max', function(val) {
19613
19697
  maxVal = parseObservedDateValue(val);
19614
19698
  ctrl.$validate();
19615
19699
  });
19616
19700
  }
19617
- // Override the standard $isEmpty to detect invalid dates as well
19618
- ctrl.$isEmpty = function(value) {
19701
+
19702
+ function isValidDate(value) {
19619
19703
  // Invalid Date: getTime() returns NaN
19620
- return !value || (value.getTime && value.getTime() !== value.getTime());
19621
- };
19704
+ return value && !(value.getTime && value.getTime() !== value.getTime());
19705
+ }
19622
19706
 
19623
19707
  function parseObservedDateValue(val) {
19624
19708
  return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
@@ -19702,7 +19786,8 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19702
19786
  stringBasedInputType(ctrl);
19703
19787
 
19704
19788
  ctrl.$$parserName = 'url';
19705
- ctrl.$validators.url = function(value) {
19789
+ ctrl.$validators.url = function(modelValue, viewValue) {
19790
+ var value = modelValue || viewValue;
19706
19791
  return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
19707
19792
  };
19708
19793
  }
@@ -19714,7 +19799,8 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
19714
19799
  stringBasedInputType(ctrl);
19715
19800
 
19716
19801
  ctrl.$$parserName = 'email';
19717
- ctrl.$validators.email = function(value) {
19802
+ ctrl.$validators.email = function(modelValue, viewValue) {
19803
+ var value = modelValue || viewValue;
19718
19804
  return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
19719
19805
  };
19720
19806
  }
@@ -19768,9 +19854,11 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
19768
19854
  element[0].checked = ctrl.$viewValue;
19769
19855
  };
19770
19856
 
19771
- // 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.
19772
19860
  ctrl.$isEmpty = function(value) {
19773
- return value !== trueValue;
19861
+ return value === false;
19774
19862
  };
19775
19863
 
19776
19864
  ctrl.$formatters.push(function(value) {
@@ -19802,7 +19890,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
19802
19890
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19803
19891
  * minlength.
19804
19892
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19805
- * maxlength.
19893
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
19894
+ * length.
19806
19895
  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19807
19896
  * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19808
19897
  * patterns defined as scope expressions.
@@ -19834,7 +19923,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
19834
19923
  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
19835
19924
  * minlength.
19836
19925
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
19837
- * maxlength.
19926
+ * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
19927
+ * length.
19838
19928
  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
19839
19929
  * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
19840
19930
  * patterns defined as scope expressions.
@@ -20050,13 +20140,18 @@ is set to `true`. The parse error is stored in `ngModel.$error.parse`.
20050
20140
  *
20051
20141
  * @description
20052
20142
  *
20053
- * `NgModelController` provides API for the `ng-model` directive. The controller contains
20054
- * services for data-binding, validation, CSS updates, and value formatting and parsing. It
20055
- * purposefully does not contain any logic which deals with DOM rendering or listening to
20056
- * DOM events. Such DOM related logic should be provided by other directives which make use of
20057
- * `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.
20058
20152
  *
20059
- * ## Custom Control Example
20153
+ * @example
20154
+ * ### Custom Control Example
20060
20155
  * This example shows how to use `NgModelController` with a custom control to achieve
20061
20156
  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
20062
20157
  * collaborate together to achieve the desired result.
@@ -20153,6 +20248,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20153
20248
  function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
20154
20249
  this.$viewValue = Number.NaN;
20155
20250
  this.$modelValue = Number.NaN;
20251
+ this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
20156
20252
  this.$validators = {};
20157
20253
  this.$asyncValidators = {};
20158
20254
  this.$parsers = [];
@@ -20171,32 +20267,33 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20171
20267
 
20172
20268
 
20173
20269
  var parsedNgModel = $parse($attr.ngModel),
20270
+ parsedNgModelAssign = parsedNgModel.assign,
20271
+ ngModelGet = parsedNgModel,
20272
+ ngModelSet = parsedNgModelAssign,
20174
20273
  pendingDebounce = null,
20175
20274
  ctrl = this;
20176
20275
 
20177
- var ngModelGet = function ngModelGet() {
20178
- var modelValue = parsedNgModel($scope);
20179
- if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) {
20180
- modelValue = modelValue();
20181
- }
20182
- return modelValue;
20183
- };
20184
-
20185
- var ngModelSet = function ngModelSet(newValue) {
20186
- var getterSetter;
20187
- if (ctrl.$options && ctrl.$options.getterSetter &&
20188
- isFunction(getterSetter = parsedNgModel($scope))) {
20189
-
20190
- getterSetter(ctrl.$modelValue);
20191
- } else {
20192
- parsedNgModel.assign($scope, ctrl.$modelValue);
20193
- }
20194
- };
20195
-
20196
20276
  this.$$setOptions = function(options) {
20197
20277
  ctrl.$options = options;
20198
-
20199
- 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) {
20200
20297
  throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
20201
20298
  $attr.ngModel, startingTag($element));
20202
20299
  }
@@ -20229,17 +20326,18 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20229
20326
  * @name ngModel.NgModelController#$isEmpty
20230
20327
  *
20231
20328
  * @description
20232
- * 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.
20233
20330
  *
20234
20331
  * For instance, the required directive does this to work out if the input has data or not.
20332
+ *
20235
20333
  * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
20236
20334
  *
20237
20335
  * You can override this for input directives whose concept of being empty is different to the
20238
20336
  * default. The `checkboxInputType` directive does this because in its case a value of `false`
20239
20337
  * implies empty.
20240
20338
  *
20241
- * @param {*} value Model value to check.
20242
- * @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".
20243
20341
  */
20244
20342
  this.$isEmpty = function(value) {
20245
20343
  return isUndefined(value) || value === '' || value === null || value !== value;
@@ -20290,9 +20388,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20290
20388
  * @description
20291
20389
  * Sets the control to its pristine state.
20292
20390
  *
20293
- * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
20294
- * state (ng-pristine class). A model is considered to be pristine when the model has not been changed
20295
- * 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.
20296
20394
  */
20297
20395
  this.$setPristine = function() {
20298
20396
  ctrl.$dirty = false;
@@ -20301,6 +20399,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20301
20399
  $animate.addClass($element, PRISTINE_CLASS);
20302
20400
  };
20303
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
+
20304
20421
  /**
20305
20422
  * @ngdoc method
20306
20423
  * @name ngModel.NgModelController#$setUntouched
@@ -20308,8 +20425,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20308
20425
  * @description
20309
20426
  * Sets the control to its untouched state.
20310
20427
  *
20311
- * This method can be called to remove the 'ng-touched' class and set the control to its
20312
- * 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
20313
20430
  * by default, however this function can be used to restore that state if the model has
20314
20431
  * already been touched by the user.
20315
20432
  */
@@ -20326,10 +20443,9 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20326
20443
  * @description
20327
20444
  * Sets the control to its touched state.
20328
20445
  *
20329
- * This method can be called to remove the 'ng-untouched' class and set the control to its
20330
- * touched state (ng-touched class). A model is considered to be touched when the user has
20331
- * first interacted (focussed) on the model input element and then shifted focus away (blurred)
20332
- * 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).
20333
20449
  */
20334
20450
  this.$setTouched = function() {
20335
20451
  ctrl.$touched = true;
@@ -20407,14 +20523,51 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20407
20523
  * @name ngModel.NgModelController#$validate
20408
20524
  *
20409
20525
  * @description
20410
- * 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.
20411
20532
  */
20412
20533
  this.$validate = function() {
20413
20534
  // ignore $validate before model is initialized
20414
20535
  if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
20415
20536
  return;
20416
20537
  }
20417
- 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
+
20418
20571
  };
20419
20572
 
20420
20573
  this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
@@ -20533,11 +20686,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20533
20686
 
20534
20687
  // change to dirty
20535
20688
  if (ctrl.$pristine) {
20536
- ctrl.$dirty = true;
20537
- ctrl.$pristine = false;
20538
- $animate.removeClass($element, PRISTINE_CLASS);
20539
- $animate.addClass($element, DIRTY_CLASS);
20540
- parentForm.$setDirty();
20689
+ this.$setDirty();
20541
20690
  }
20542
20691
  this.$$parseAndValidate();
20543
20692
  };
@@ -20558,10 +20707,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20558
20707
  }
20559
20708
  if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
20560
20709
  // ctrl.$modelValue has not been touched yet...
20561
- ctrl.$modelValue = ngModelGet();
20710
+ ctrl.$modelValue = ngModelGet($scope);
20562
20711
  }
20563
20712
  var prevModelValue = ctrl.$modelValue;
20564
20713
  var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
20714
+ ctrl.$$rawModelValue = modelValue;
20565
20715
  if (allowInvalid) {
20566
20716
  ctrl.$modelValue = modelValue;
20567
20717
  writeToModelIfNeeded();
@@ -20585,7 +20735,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20585
20735
  };
20586
20736
 
20587
20737
  this.$$writeModelToScope = function() {
20588
- ngModelSet(ctrl.$modelValue);
20738
+ ngModelSet($scope, ctrl.$modelValue);
20589
20739
  forEach(ctrl.$viewChangeListeners, function(listener) {
20590
20740
  try {
20591
20741
  listener();
@@ -20681,12 +20831,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20681
20831
  // ng-change executes in apply phase
20682
20832
  // 4. view should be changed back to 'a'
20683
20833
  $scope.$watch(function ngModelWatch() {
20684
- var modelValue = ngModelGet();
20834
+ var modelValue = ngModelGet($scope);
20685
20835
 
20686
20836
  // if scope model value and ngModel value are out of sync
20687
20837
  // TODO(perf): why not move this to the action fn?
20688
20838
  if (modelValue !== ctrl.$modelValue) {
20689
- ctrl.$modelValue = modelValue;
20839
+ ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
20690
20840
 
20691
20841
  var formatters = ctrl.$formatters,
20692
20842
  idx = formatters.length;
@@ -20871,7 +21021,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20871
21021
  </file>
20872
21022
  * </example>
20873
21023
  */
20874
- var ngModelDirective = function() {
21024
+ var ngModelDirective = ['$rootScope', function($rootScope) {
20875
21025
  return {
20876
21026
  restrict: 'A',
20877
21027
  require: ['ngModel', '^?form', '^?ngModelOptions'],
@@ -20915,15 +21065,17 @@ var ngModelDirective = function() {
20915
21065
  element.on('blur', function(ev) {
20916
21066
  if (modelCtrl.$touched) return;
20917
21067
 
20918
- scope.$apply(function() {
20919
- modelCtrl.$setTouched();
20920
- });
21068
+ if ($rootScope.$$phase) {
21069
+ scope.$evalAsync(modelCtrl.$setTouched);
21070
+ } else {
21071
+ scope.$apply(modelCtrl.$setTouched);
21072
+ }
20921
21073
  });
20922
21074
  }
20923
21075
  };
20924
21076
  }
20925
21077
  };
20926
- };
21078
+ }];
20927
21079
 
20928
21080
 
20929
21081
  /**
@@ -21012,8 +21164,8 @@ var requiredDirective = function() {
21012
21164
  if (!ctrl) return;
21013
21165
  attr.required = true; // force truthy in case we are on non input element
21014
21166
 
21015
- ctrl.$validators.required = function(value) {
21016
- return !attr.required || !ctrl.$isEmpty(value);
21167
+ ctrl.$validators.required = function(modelValue, viewValue) {
21168
+ return !attr.required || !ctrl.$isEmpty(viewValue);
21017
21169
  };
21018
21170
 
21019
21171
  attr.$observe('required', function() {
@@ -21062,13 +21214,14 @@ var maxlengthDirective = function() {
21062
21214
  link: function(scope, elm, attr, ctrl) {
21063
21215
  if (!ctrl) return;
21064
21216
 
21065
- var maxlength = 0;
21217
+ var maxlength = -1;
21066
21218
  attr.$observe('maxlength', function(value) {
21067
- maxlength = int(value) || 0;
21219
+ var intVal = int(value);
21220
+ maxlength = isNaN(intVal) ? -1 : intVal;
21068
21221
  ctrl.$validate();
21069
21222
  });
21070
21223
  ctrl.$validators.maxlength = function(modelValue, viewValue) {
21071
- return ctrl.$isEmpty(modelValue) || viewValue.length <= maxlength;
21224
+ return (maxlength < 0) || ctrl.$isEmpty(modelValue) || (viewValue.length <= maxlength);
21072
21225
  };
21073
21226
  }
21074
21227
  };
@@ -21087,7 +21240,7 @@ var minlengthDirective = function() {
21087
21240
  ctrl.$validate();
21088
21241
  });
21089
21242
  ctrl.$validators.minlength = function(modelValue, viewValue) {
21090
- return ctrl.$isEmpty(modelValue) || viewValue.length >= minlength;
21243
+ return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
21091
21244
  };
21092
21245
  }
21093
21246
  };
@@ -21715,12 +21868,11 @@ var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate
21715
21868
  * @name ngBindHtml
21716
21869
  *
21717
21870
  * @description
21718
- * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
21719
- * element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
21720
- * ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
21721
- * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
21722
- * core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
21723
- * 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.
21724
21876
  *
21725
21877
  * You may also bypass sanitization for values you know are safe. To do so, bind to
21726
21878
  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
@@ -23784,7 +23936,9 @@ var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
23784
23936
  </example>
23785
23937
  */
23786
23938
  var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
23787
- var BRACE = /{}/g;
23939
+ var BRACE = /{}/g,
23940
+ IS_WHEN = /^when(Minus)?(.+)$/;
23941
+
23788
23942
  return {
23789
23943
  restrict: 'EA',
23790
23944
  link: function(scope, element, attr) {
@@ -23795,34 +23949,44 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
23795
23949
  whensExpFns = {},
23796
23950
  startSymbol = $interpolate.startSymbol(),
23797
23951
  endSymbol = $interpolate.endSymbol(),
23798
- isWhen = /^when(Minus)?(.+)$/;
23952
+ braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
23953
+ watchRemover = angular.noop,
23954
+ lastCount;
23799
23955
 
23800
23956
  forEach(attr, function(expression, attributeName) {
23801
- if (isWhen.test(attributeName)) {
23802
- whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
23803
- 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]);
23804
23961
  }
23805
23962
  });
23806
23963
  forEach(whens, function(expression, key) {
23807
- whensExpFns[key] =
23808
- $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
23809
- offset + endSymbol));
23964
+ whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
23965
+
23810
23966
  });
23811
23967
 
23812
- scope.$watch(function ngPluralizeWatch() {
23813
- var value = parseFloat(scope.$eval(numberExp));
23968
+ scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
23969
+ var count = parseFloat(newVal);
23970
+ var countIsNaN = isNaN(count);
23814
23971
 
23815
- if (!isNaN(value)) {
23816
- //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
23817
- //check it against pluralization rules in $locale service
23818
- if (!(value in whens)) value = $locale.pluralCat(value - offset);
23819
- return whensExpFns[value](scope);
23820
- } else {
23821
- 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;
23822
23984
  }
23823
- }, function ngPluralizeWatchAction(newVal) {
23824
- element.text(newVal);
23825
23985
  });
23986
+
23987
+ function updateElementText(newText) {
23988
+ element.text(newText || '');
23989
+ }
23826
23990
  }
23827
23991
  };
23828
23992
  }];
@@ -24304,17 +24468,17 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24304
24468
  *
24305
24469
  * ### Overriding `.ng-hide`
24306
24470
  *
24307
- * 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
24308
24472
  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24309
24473
  * class in CSS:
24310
24474
  *
24311
24475
  * ```css
24312
24476
  * .ng-hide {
24313
24477
  * /&#42; this is just another form of hiding an element &#42;/
24314
- * display:block!important;
24315
- * position:absolute;
24316
- * top:-9999px;
24317
- * left:-9999px;
24478
+ * display: block!important;
24479
+ * position: absolute;
24480
+ * top: -9999px;
24481
+ * left: -9999px;
24318
24482
  * }
24319
24483
  * ```
24320
24484
  *
@@ -24334,13 +24498,13 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24334
24498
  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24335
24499
  * /&#42; this is required as of 1.3x to properly
24336
24500
  * apply all styling in a show/hide animation &#42;/
24337
- * transition:0s linear all;
24501
+ * transition: 0s linear all;
24338
24502
  * }
24339
24503
  *
24340
24504
  * .my-element.ng-hide-add-active,
24341
24505
  * .my-element.ng-hide-remove-active {
24342
24506
  * /&#42; the transition is defined in the active class &#42;/
24343
- * transition:1s linear all;
24507
+ * transition: 1s linear all;
24344
24508
  * }
24345
24509
  *
24346
24510
  * .my-element.ng-hide-add { ... }
@@ -24382,29 +24546,29 @@ var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
24382
24546
  </file>
24383
24547
  <file name="animations.css">
24384
24548
  .animate-show {
24385
- line-height:20px;
24386
- opacity:1;
24387
- padding:10px;
24388
- border:1px solid black;
24389
- background:white;
24549
+ line-height: 20px;
24550
+ opacity: 1;
24551
+ padding: 10px;
24552
+ border: 1px solid black;
24553
+ background: white;
24390
24554
  }
24391
24555
 
24392
24556
  .animate-show.ng-hide-add.ng-hide-add-active,
24393
24557
  .animate-show.ng-hide-remove.ng-hide-remove-active {
24394
- -webkit-transition:all linear 0.5s;
24395
- transition:all linear 0.5s;
24558
+ -webkit-transition: all linear 0.5s;
24559
+ transition: all linear 0.5s;
24396
24560
  }
24397
24561
 
24398
24562
  .animate-show.ng-hide {
24399
- line-height:0;
24400
- opacity:0;
24401
- padding:0 10px;
24563
+ line-height: 0;
24564
+ opacity: 0;
24565
+ padding: 0 10px;
24402
24566
  }
24403
24567
 
24404
24568
  .check-element {
24405
- padding:10px;
24406
- border:1px solid black;
24407
- background:white;
24569
+ padding: 10px;
24570
+ border: 1px solid black;
24571
+ background: white;
24408
24572
  }
24409
24573
  </file>
24410
24574
  <file name="protractor.js" type="protractor">
@@ -24478,17 +24642,17 @@ var ngShowDirective = ['$animate', function($animate) {
24478
24642
  *
24479
24643
  * ### Overriding `.ng-hide`
24480
24644
  *
24481
- * 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
24482
24646
  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
24483
24647
  * class in CSS:
24484
24648
  *
24485
24649
  * ```css
24486
24650
  * .ng-hide {
24487
24651
  * /&#42; this is just another form of hiding an element &#42;/
24488
- * display:block!important;
24489
- * position:absolute;
24490
- * top:-9999px;
24491
- * left:-9999px;
24652
+ * display: block!important;
24653
+ * position: absolute;
24654
+ * top: -9999px;
24655
+ * left: -9999px;
24492
24656
  * }
24493
24657
  * ```
24494
24658
  *
@@ -24505,7 +24669,7 @@ var ngShowDirective = ['$animate', function($animate) {
24505
24669
  * //a working example can be found at the bottom of this page
24506
24670
  * //
24507
24671
  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
24508
- * transition:0.5s linear all;
24672
+ * transition: 0.5s linear all;
24509
24673
  * }
24510
24674
  *
24511
24675
  * .my-element.ng-hide-add { ... }
@@ -24547,25 +24711,25 @@ var ngShowDirective = ['$animate', function($animate) {
24547
24711
  </file>
24548
24712
  <file name="animations.css">
24549
24713
  .animate-hide {
24550
- -webkit-transition:all linear 0.5s;
24551
- transition:all linear 0.5s;
24552
- line-height:20px;
24553
- opacity:1;
24554
- padding:10px;
24555
- border:1px solid black;
24556
- 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;
24557
24721
  }
24558
24722
 
24559
24723
  .animate-hide.ng-hide {
24560
- line-height:0;
24561
- opacity:0;
24562
- padding:0 10px;
24724
+ line-height: 0;
24725
+ opacity: 0;
24726
+ padding: 0 10px;
24563
24727
  }
24564
24728
 
24565
24729
  .check-element {
24566
- padding:10px;
24567
- border:1px solid black;
24568
- background:white;
24730
+ padding: 10px;
24731
+ border: 1px solid black;
24732
+ background: white;
24569
24733
  }
24570
24734
  </file>
24571
24735
  <file name="protractor.js" type="protractor">