diff options
Diffstat (limited to 'src/ng/directive/ngPluralize.js')
| -rw-r--r-- | src/ng/directive/ngPluralize.js | 204 | 
1 files changed, 204 insertions, 0 deletions
| diff --git a/src/ng/directive/ngPluralize.js b/src/ng/directive/ngPluralize.js new file mode 100644 index 00000000..a8cc40a6 --- /dev/null +++ b/src/ng/directive/ngPluralize.js @@ -0,0 +1,204 @@ +'use strict'; + +/** + * @ngdoc directive + * @name angular.module.ng.$compileProvider.directive.ng-pluralize + * @restrict EA + * + * @description + * # Overview + * ng-pluralize is a directive that displays messages according to en-US localization rules. + * These rules are bundled with angular.js and the rules can be overridden + * (see {@link guide/dev_guide.i18n Angular i18n} dev guide). You configure ng-pluralize by + * specifying the mappings between + * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html + * plural categories} and the strings to be displayed. + * + * # Plural categories and explicit number rules + * There are two + * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html + * plural categories} in Angular's default en-US locale: "one" and "other". + * + * While a pural category may match many numbers (for example, in en-US locale, "other" can match + * any number that is not 1), an explicit number rule can only match one number. For example, the + * explicit number rule for "3" matches the number 3. You will see the use of plural categories + * and explicit number rules throughout later parts of this documentation. + * + * # Configuring ng-pluralize + * You configure ng-pluralize by providing 2 attributes: `count` and `when`. + * You can also provide an optional attribute, `offset`. + * + * The value of the `count` attribute can be either a string or an {@link guide/dev_guide.expressions + * Angular expression}; these are evaluated on the current scope for its binded value. + * + * The `when` attribute specifies the mappings between plural categories and the actual + * string to be displayed. The value of the attribute should be a JSON object so that Angular + * can interpret it correctly. + * + * The following example shows how to configure ng-pluralize: + * + * <pre> + * <ng-pluralize count="personCount" +                 when="{'0': 'Nobody is viewing.', + *                      'one': '1 person is viewing.', + *                      'other': '{} people are viewing.'}"> + * </ng-pluralize> + *</pre> + * + * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not + * specify this rule, 0 would be matched to the "other" category and "0 people are viewing" + * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for + * other numbers, for example 12, so that instead of showing "12 people are viewing", you can + * show "a dozen people are viewing". + * + * You can use a set of closed braces(`{}`) as a placeholder for the number that you want substituted + * into pluralized strings. In the previous example, Angular will replace `{}` with + * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder + * for <span ng-non-bindable>{{numberExpression}}</span>. + * + * # Configuring ng-pluralize with offset + * The `offset` attribute allows further customization of pluralized text, which can result in + * a better user experience. For example, instead of the message "4 people are viewing this document", + * you might display "John, Kate and 2 others are viewing this document". + * The offset attribute allows you to offset a number by any desired value. + * Let's take a look at an example: + * + * <pre> + * <ng-pluralize count="personCount" offset=2 + *               when="{'0': 'Nobody is viewing.', + *                      '1': '{{person1}} is viewing.', + *                      '2': '{{person1}} and {{person2}} are viewing.', + *                      'one': '{{person1}}, {{person2}} and one other person are viewing.', + *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}"> + * </ng-pluralize> + * </pre> + * + * Notice that we are still using two plural categories(one, other), but we added + * three explicit number rules 0, 1 and 2. + * When one person, perhaps John, views the document, "John is viewing" will be shown. + * When three people view the document, no explicit number rule is found, so + * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category. + * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing" + * is shown. + * + * Note that when you specify offsets, you must provide explicit number rules for + * numbers from 0 up to and including the offset. If you use an offset of 3, for example, + * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for + * plural categories "one" and "other". + * + * @param {string|expression} count The variable to be bounded to. + * @param {string} when The mapping between plural category to its correspoding strings. + * @param {number=} offset Offset to deduct from the total number. + * + * @example +    <doc:example> +      <doc:source> +        <script> +          function Ctrl($scope) { +            $scope.person1 = 'Igor'; +            $scope.person2 = 'Misko'; +            $scope.personCount = 1; +          } +        </script> +        <div ng-controller="Ctrl"> +          Person 1:<input type="text" ng-model="person1" value="Igor" /><br/> +          Person 2:<input type="text" ng-model="person2" value="Misko" /><br/> +          Number of People:<input type="text" ng-model="personCount" value="1" /><br/> + +          <!--- Example with simple pluralization rules for en locale ---> +          Without Offset: +          <ng-pluralize count="personCount" +                        when="{'0': 'Nobody is viewing.', +                               'one': '1 person is viewing.', +                               'other': '{} people are viewing.'}"> +          </ng-pluralize><br> + +          <!--- Example with offset ---> +          With Offset(2): +          <ng-pluralize count="personCount" offset=2 +                        when="{'0': 'Nobody is viewing.', +                               '1': '{{person1}} is viewing.', +                               '2': '{{person1}} and {{person2}} are viewing.', +                               'one': '{{person1}}, {{person2}} and one other person are viewing.', +                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}"> +          </ng-pluralize> +        </div> +      </doc:source> +      <doc:scenario> +        it('should show correct pluralized string', function() { +          expect(element('.doc-example-live ng-pluralize:first').text()). +                                             toBe('1 person is viewing.'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +                                                toBe('Igor is viewing.'); + +          using('.doc-example-live').input('personCount').enter('0'); +          expect(element('.doc-example-live ng-pluralize:first').text()). +                                               toBe('Nobody is viewing.'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +                                              toBe('Nobody is viewing.'); + +          using('.doc-example-live').input('personCount').enter('2'); +          expect(element('.doc-example-live ng-pluralize:first').text()). +                                            toBe('2 people are viewing.'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +                              toBe('Igor and Misko are viewing.'); + +          using('.doc-example-live').input('personCount').enter('3'); +          expect(element('.doc-example-live ng-pluralize:first').text()). +                                            toBe('3 people are viewing.'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +                              toBe('Igor, Misko and one other person are viewing.'); + +          using('.doc-example-live').input('personCount').enter('4'); +          expect(element('.doc-example-live ng-pluralize:first').text()). +                                            toBe('4 people are viewing.'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +                              toBe('Igor, Misko and 2 other people are viewing.'); +        }); + +        it('should show data-binded names', function() { +          using('.doc-example-live').input('personCount').enter('4'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +              toBe('Igor, Misko and 2 other people are viewing.'); + +          using('.doc-example-live').input('person1').enter('Di'); +          using('.doc-example-live').input('person2').enter('Vojta'); +          expect(element('.doc-example-live ng-pluralize:last').text()). +              toBe('Di, Vojta and 2 other people are viewing.'); +        }); +      </doc:scenario> +    </doc:example> + */ +var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) { +  var BRACE = /{}/g; +  return { +    restrict: 'EA', +    link: function(scope, element, attr) { +      var numberExp = attr.count, +          whenExp = element.attr(attr.$attr.when), // this is because we have {{}} in attrs +          offset = attr.offset || 0, +          whens = scope.$eval(whenExp), +          whensExpFns = {}; + +      forEach(whens, function(expression, key) { +        whensExpFns[key] = +          $interpolate(expression.replace(BRACE, '{{' + numberExp + '-' + offset + '}}')); +      }); + +      scope.$watch(function() { +        var value = parseFloat(scope.$eval(numberExp)); + +        if (!isNaN(value)) { +          //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise, +          //check it against pluralization rules in $locale service +          if (!whens[value]) value = $locale.pluralCat(value - offset); +           return whensExpFns[value](scope, element, true); +        } else { +          return ''; +        } +      }, function(newVal) { +        element.text(newVal); +      }); +    } +  }; +}]; | 
