angularjs-rails 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. checksums.yaml +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">