diff options
| author | Ben Lesh | 2013-12-03 23:27:01 -0500 | 
|---|---|---|
| committer | Tobias Bosch | 2014-03-06 12:21:15 -0800 | 
| commit | 46bd6dc88de252886d75426efc2ce8107a5134e9 (patch) | |
| tree | a864ee270bb2ebfdd0692ab473bf8a90875e2a6f | |
| parent | 0609453e1f9ae074f8d786df903096a6eadb6aa0 (diff) | |
| download | angular.js-46bd6dc88de252886d75426efc2ce8107a5134e9.tar.bz2 | |
feat(input): support types date, time, datetime-local, month, week
On older browser that don't support the new HTML5 inputs
and display a text input instead, the user is required to enter
the data in the corresponding ISO format. The value in `ng-model`
will always be a date.
E2e tests contain a workaround to a bug in webdriver,
see https://github.com/angular/protractor/issues/562.
Also adds weeks as format to the `dateFilter`.
Related to #757.
Closes #5864.
| -rw-r--r-- | src/.jshintrc | 3 | ||||
| -rw-r--r-- | src/ng/directive/input.js | 535 | ||||
| -rw-r--r-- | src/ng/filter/filters.js | 34 | ||||
| -rw-r--r-- | test/ng/directive/inputSpec.js | 713 | ||||
| -rw-r--r-- | test/ng/filter/filtersSpec.js | 8 | 
5 files changed, 1287 insertions, 6 deletions
| diff --git a/src/.jshintrc b/src/.jshintrc index f32caa45..4e19601d 100644 --- a/src/.jshintrc +++ b/src/.jshintrc @@ -101,6 +101,9 @@      "getter": false,      "getBlockElements": false, +    /* filters.js */ +    "getFirstThursdayOfYear": false, +      /* AngularPublic.js */      "version": false,      "publishExternalAPI": false, diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index c31bb400..cb432c52 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -11,6 +11,11 @@  var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;  var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/; +var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/; +var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/; +var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/; +var MONTH_REGEXP = /^(\d{4})-(\d\d)$/; +var TIME_REGEXP = /^(\d\d):(\d\d)$/;  var inputType = { @@ -91,6 +96,425 @@ var inputType = {     */    'text': textInputType, +    /** +     * @ngdoc input +     * @name input[date] +     * +     * @description +     * Input with date validation and transformation. In browsers that do not yet support +     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601 +     * date format (yyyy-MM-dd), for example: `2009-01-06`. The model must always be a Date object. +     * +     * @param {string} ngModel Assignable angular expression to data-bind to. +     * @param {string=} name Property name of the form under which the control is published. +     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a +     * valid ISO date string (yyyy-MM-dd). +     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be +     * a valid ISO date string (yyyy-MM-dd). +     * @param {string=} required Sets `required` validation error key if the value is not entered. +     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to +     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of +     *    `required` when you want to data-bind to the `required` attribute. +     * @param {string=} ngChange Angular expression to be executed when input changes due to user +     *    interaction with the input element. +     * +     * @example +     <example name="date-input-directive"> +     <file name="index.html"> +       <script> +          function Ctrl($scope) { +            $scope.value = new Date(2013, 9, 22); +          } +       </script> +       <form name="myForm" ng-controller="Ctrl as dateCtrl"> +          Pick a date between in 2013: +          <input type="date" id="exampleInput" name="input" ng-model="value" +              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required /> +          <span class="error" ng-show="myForm.input.$error.required"> +              Required!</span> +          <span class="error" ng-show="myForm.input.$error.date"> +              Not a valid date!</span> +           <tt>value = {{value | date: "yyyy-MM-dd"}}</tt><br/> +           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/> +           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/> +           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/> +           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/> +       </form> +     </file> +     <file name="protractor.js" type="protractor"> +        var value = element(by.binding('value | date: "yyyy-MM-dd"')); +        var valid = element(by.binding('myForm.input.$valid')); +        var input = element(by.model('value')); + +        // currently protractor/webdriver does not support +        // sending keys to all known HTML5 input controls +        // for various browsers (see https://github.com/angular/protractor/issues/562). +        function setInput(val) { +          // set the value of the element and force validation. +          var scr = "var ipt = document.getElementById('exampleInput'); " + +          "ipt.value = '" + val + "';" + +          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; +          browser.executeScript(scr); +        } + +        it('should initialize to model', function() { +          expect(value.getText()).toContain('2013-10-22'); +          expect(valid.getText()).toContain('myForm.input.$valid = true'); +        }); + +        it('should be invalid if empty', function() { +          setInput(''); +          expect(value.getText()).toEqual('value ='); +          expect(valid.getText()).toContain('myForm.input.$valid = false'); +        }); + +        it('should be invalid if over max', function() { +          setInput('2015-01-01'); +          expect(value.getText()).toContain(''); +          expect(valid.getText()).toContain('myForm.input.$valid = false'); +        }); +     </file> +     </example>f +     */ +  'date': createDateInputType('date', DATE_REGEXP, +         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']), +         'yyyy-MM-dd'), + +   /** +    * @ngdoc input +    * @name input[dateTimeLocal] +    * +    * @description +    * Input with datetime validation and transformation. In browsers that do not yet support +    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 +    * local datetime format (yyyy-MM-ddTHH:mm), for example: `2010-12-28T14:57`. The model must be a Date object. +    * +    * @param {string} ngModel Assignable angular expression to data-bind to. +    * @param {string=} name Property name of the form under which the control is published. +    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a +    * valid ISO datetime format (yyyy-MM-ddTHH:mm). +    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be +    * a valid ISO datetime format (yyyy-MM-ddTHH:mm). +    * @param {string=} required Sets `required` validation error key if the value is not entered. +    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to +    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of +    *    `required` when you want to data-bind to the `required` attribute. +    * @param {string=} ngChange Angular expression to be executed when input changes due to user +    *    interaction with the input element. +    * +    * @example +    <example name="datetimelocal-input-directive"> +    <file name="index.html"> +      <script> +        function Ctrl($scope) { +          $scope.value = new Date(2010, 11, 28, 14, 57); +        } +      </script> +      <form name="myForm" ng-controller="Ctrl as dateCtrl"> +        Pick a date between in 2013: +        <input type="datetime-local" id="exampleInput" name="input" ng-model="value" +            placeholder="yyyy-MM-ddTHH:mm" min="2001-01-01T00:00" max="2013-12-31T00:00" required /> +        <span class="error" ng-show="myForm.input.$error.required"> +            Required!</span> +        <span class="error" ng-show="myForm.input.$error.datetimelocal"> +            Not a valid date!</span> +        <tt>value = {{value | date: "yyyy-MM-ddTHH:mm"}}</tt><br/> +        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/> +        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/> +        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/> +        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/> +      </form> +    </file> +    <file name="protractor.js" type="protractor"> +      var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm"')); +      var valid = element(by.binding('myForm.input.$valid')); +      var input = element(by.model('value')); + +      // currently protractor/webdriver does not support +      // sending keys to all known HTML5 input controls +      // for various browsers (https://github.com/angular/protractor/issues/562). +      function setInput(val) { +        // set the value of the element and force validation. +        var scr = "var ipt = document.getElementById('exampleInput'); " + +        "ipt.value = '" + val + "';" + +        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; +        browser.executeScript(scr); +      } + +      it('should initialize to model', function() { +        expect(value.getText()).toContain('2010-12-28T14:57'); +        expect(valid.getText()).toContain('myForm.input.$valid = true'); +      }); + +      it('should be invalid if empty', function() { +        setInput(''); +        expect(value.getText()).toEqual('value ='); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); + +      it('should be invalid if over max', function() { +        setInput('2015-01-01T23:59'); +        expect(value.getText()).toContain(''); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); +    </file> +    </example> +    */ +  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP, +      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm']), +      'yyyy-MM-ddTHH:mm'), + +  /** +   * @ngdoc input +   * @name input[time] +   * +   * @description +   * Input with time validation and transformation. In browsers that do not yet support +   * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 +   * local time format (HH:mm), for example: `14:57`. Model must be a Date object. This binding will always output a +   * Date object to the model of January 1, 1900, or local date `new Date(0, 0, 1, HH, mm)`. +   * +   * @param {string} ngModel Assignable angular expression to data-bind to. +   * @param {string=} name Property name of the form under which the control is published. +   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a +   * valid ISO time format (HH:mm). +   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a +   * valid ISO time format (HH:mm). +   * @param {string=} required Sets `required` validation error key if the value is not entered. +   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to +   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of +   *    `required` when you want to data-bind to the `required` attribute. +   * @param {string=} ngChange Angular expression to be executed when input changes due to user +   *    interaction with the input element. +   * +   * @example +   <example name="time-input-directive"> +   <file name="index.html"> +     <script> +      function Ctrl($scope) { +        $scope.value = new Date(0, 0, 1, 14, 57); +      } +     </script> +     <form name="myForm" ng-controller="Ctrl as dateCtrl"> +        Pick a between 8am and 5pm: +        <input type="time" id="exampleInput" name="input" ng-model="value" +            placeholder="HH:mm" min="08:00" max="17:00" required /> +        <span class="error" ng-show="myForm.input.$error.required"> +            Required!</span> +        <span class="error" ng-show="myForm.input.$error.time"> +            Not a valid date!</span> +        <tt>value = {{value | date: "HH:mm"}}</tt><br/> +        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/> +        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/> +        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/> +        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/> +     </form> +   </file> +   <file name="protractor.js" type="protractor"> +      var value = element(by.binding('value | date: "HH:mm"')); +      var valid = element(by.binding('myForm.input.$valid')); +      var input = element(by.model('value')); + +      // currently protractor/webdriver does not support +      // sending keys to all known HTML5 input controls +      // for various browsers (https://github.com/angular/protractor/issues/562). +      function setInput(val) { +        // set the value of the element and force validation. +        var scr = "var ipt = document.getElementById('exampleInput'); " + +        "ipt.value = '" + val + "';" + +        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; +        browser.executeScript(scr); +      } + +      it('should initialize to model', function() { +        expect(value.getText()).toContain('14:57'); +        expect(valid.getText()).toContain('myForm.input.$valid = true'); +      }); + +      it('should be invalid if empty', function() { +        setInput(''); +        expect(value.getText()).toEqual('value ='); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); + +      it('should be invalid if over max', function() { +        setInput('23:59'); +        expect(value.getText()).toContain(''); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); +   </file> +   </example> +   */ +  'time': createDateInputType('time', TIME_REGEXP, +      createDateParser(TIME_REGEXP, ['HH', 'mm']), +     'HH:mm'), + +   /** +    * @ngdoc input +    * @name input[week] +    * +    * @description +    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support +    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 +    * week format (yyyy-W##), for example: `2013-W02`. The model must always be a Date object. +    * +    * @param {string} ngModel Assignable angular expression to data-bind to. +    * @param {string=} name Property name of the form under which the control is published. +    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a +    * valid ISO week format (yyyy-W##). +    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be +    * a valid ISO week format (yyyy-W##). +    * @param {string=} required Sets `required` validation error key if the value is not entered. +    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to +    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of +    *    `required` when you want to data-bind to the `required` attribute. +    * @param {string=} ngChange Angular expression to be executed when input changes due to user +    *    interaction with the input element. +    * +    * @example +    <example name="week-input-directive"> +    <file name="index.html"> +      <script> +      function Ctrl($scope) { +        $scope.value = new Date(2013, 0, 3); +      } +      </script> +      <form name="myForm" ng-controller="Ctrl as dateCtrl"> +        Pick a date between in 2013: +        <input id="exampleInput" type="week" name="input" ng-model="value" +            placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required /> +        <span class="error" ng-show="myForm.input.$error.required"> +            Required!</span> +        <span class="error" ng-show="myForm.input.$error.week"> +            Not a valid date!</span> +        <tt>value = {{value | date: "yyyy-Www"}}</tt><br/> +        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/> +        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/> +        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/> +        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/> +      </form> +    </file> +    <file name="protractor.js" type="protractor"> +      var value = element(by.binding('value | date: "yyyy-Www"')); +      var valid = element(by.binding('myForm.input.$valid')); +      var input = element(by.model('value')); + +      // currently protractor/webdriver does not support +      // sending keys to all known HTML5 input controls +      // for various browsers (https://github.com/angular/protractor/issues/562). +      function setInput(val) { +        // set the value of the element and force validation. +        var scr = "var ipt = document.getElementById('exampleInput'); " + +        "ipt.value = '" + val + "';" + +        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; +        browser.executeScript(scr); +      } + +      it('should initialize to model', function() { +        expect(value.getText()).toContain('2013-W01'); +        expect(valid.getText()).toContain('myForm.input.$valid = true'); +      }); + +      it('should be invalid if empty', function() { +        setInput(''); +        expect(value.getText()).toEqual('value ='); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); + +      it('should be invalid if over max', function() { +        setInput('2015-W01'); +        expect(value.getText()).toContain(''); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); +    </file> +    </example> +    */ +  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'), + +  /** +   * @ngdoc input +   * @name input[month] +   * +   * @description +   * Input with month validation and transformation. In browsers that do not yet support +   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601 +   * month format (yyyy-MM), for example: `2009-01`. The model must always be a Date object. In the event the model is +   * not set to the first of the month, the first of that model's month is assumed. +   * +   * @param {string} ngModel Assignable angular expression to data-bind to. +   * @param {string=} name Property name of the form under which the control is published. +   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be +   * a valid ISO month format (yyyy-MM). +   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must +   * be a valid ISO month format (yyyy-MM). +   * @param {string=} required Sets `required` validation error key if the value is not entered. +   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to +   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of +   *    `required` when you want to data-bind to the `required` attribute. +   * @param {string=} ngChange Angular expression to be executed when input changes due to user +   *    interaction with the input element. +   * +   * @example +   <example name="month-input-directive"> +   <file name="index.html"> +     <script> +      function Ctrl($scope) { +        $scope.value = new Date(2013, 9, 1); +      } +     </script> +     <form name="myForm" ng-controller="Ctrl as dateCtrl"> +       Pick a month int 2013: +       <input id="exampleInput" type="month" name="input" ng-model="value" +          placeholder="yyyy-MM" min="2013-01" max="2013-12" required /> +       <span class="error" ng-show="myForm.input.$error.required"> +          Required!</span> +       <span class="error" ng-show="myForm.input.$error.month"> +          Not a valid month!</span> +       <tt>value = {{value | date: "yyyy-MM"}}</tt><br/> +       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/> +       <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/> +       <tt>myForm.$valid = {{myForm.$valid}}</tt><br/> +       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/> +     </form> +   </file> +   <file name="protractor.js" type="protractor"> +      var value = element(by.binding('value | date: "yyyy-MM"')); +      var valid = element(by.binding('myForm.input.$valid')); +      var input = element(by.model('value')); + +      // currently protractor/webdriver does not support +      // sending keys to all known HTML5 input controls +      // for various browsers (https://github.com/angular/protractor/issues/562). +      function setInput(val) { +        // set the value of the element and force validation. +        var scr = "var ipt = document.getElementById('exampleInput'); " + +        "ipt.value = '" + val + "';" + +        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });"; +        browser.executeScript(scr); +      } + +      it('should initialize to model', function() { +        expect(value.getText()).toContain('2013-10'); +        expect(valid.getText()).toContain('myForm.input.$valid = true'); +      }); + +      it('should be invalid if empty', function() { +        setInput(''); +        expect(value.getText()).toEqual('value ='); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); + +      it('should be invalid if over max', function() { +        setInput('2015-01'); +        expect(value.getText()).toContain(''); +        expect(valid.getText()).toContain('myForm.input.$valid = false'); +      }); +   </file> +   </example> +   */ +  'month': createDateInputType('month', MONTH_REGEXP, +     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']), +     'yyyy-MM'),    /**     * @ngdoc input @@ -593,6 +1017,108 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {    }  } +function weekParser(isoWeek) { +   if(isDate(isoWeek)) { +      return isoWeek; +   } + +   if(isString(isoWeek)) { +      WEEK_REGEXP.lastIndex = 0; +      var parts = WEEK_REGEXP.exec(isoWeek); +      if(parts) { +         var year = +parts[1], +            week = +parts[2], +            firstThurs = getFirstThursdayOfYear(year), +            addDays = (week - 1) * 7; +         return new Date(year, 0, firstThurs.getDate() + addDays); +      } +   } + +   return NaN; +} + +function createDateParser(regexp, mapping) { +   return function(iso) { +      var parts, map; + +      if(isDate(iso)) { +         return iso; +      } + +      if(isString(iso)) { +         regexp.lastIndex = 0; +         parts = regexp.exec(iso); + +         if(parts) { +            parts.shift(); +            map = { yyyy: 0, MM: 1, dd: 1, HH: 0, mm: 0 }; + +            forEach(parts, function(part, index) { +               if(index < mapping.length) { +                  map[mapping[index]] = +part; +               } +            }); + +            return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm); +         } +      } + +      return NaN; +   }; +} + +function createDateInputType(type, regexp, parseDate, format) { +   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) { +      textInputType(scope, element, attr, ctrl, $sniffer, $browser); + +      ctrl.$parsers.push(function(value) { +         if(ctrl.$isEmpty(value)) { +            ctrl.$setValidity(type, true); +            return null; +         } + +         if(regexp.test(value)) { +            ctrl.$setValidity(type, true); +            return parseDate(value); +         } + +         ctrl.$setValidity(type, false); +         return undefined; +      }); + +      ctrl.$formatters.push(function(value) { +         if(isDate(value)) { +            return $filter('date')(value, format); +         } +         return ''; +      }); + +      if(attr.min) { +         var minValidator = function(value) { +            var valid = ctrl.$isEmpty(value) || +               (parseDate(value) >= parseDate(attr.min)); +            ctrl.$setValidity('min', valid); +            return valid ? value : undefined; +         }; + +         ctrl.$parsers.push(minValidator); +         ctrl.$formatters.push(minValidator); +      } + +      if(attr.max) { +         var maxValidator = function(value) { +            var valid = ctrl.$isEmpty(value) || +               (parseDate(value) <= parseDate(attr.max)); +            ctrl.$setValidity('max', valid); +            return valid ? value : undefined; +         }; + +         ctrl.$parsers.push(maxValidator); +         ctrl.$formatters.push(maxValidator); +      } +   }; +} +  function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {    textInputType(scope, element, attr, ctrl, $sniffer, $browser); @@ -852,14 +1378,14 @@ function checkboxInputType(scope, element, attr, ctrl) {        </file>      </example>   */ -var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) { +var inputDirective = ['$browser', '$sniffer', '$filter', function($browser, $sniffer, $filter) {    return {      restrict: 'E',      require: '?ngModel',      link: function(scope, element, attr, ctrl) {        if (ctrl) {          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer, -                                                            $browser); +                                                            $browser, $filter);        }      }    }; @@ -1247,6 +1773,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$   *    - {@link input[number] number}   *    - {@link input[email] email}   *    - {@link input[url] url} + *    - {@link input[date] date} + *    - {@link input[dateTimeLocal] dateTimeLocal} + *    - {@link input[time] time} + *    - {@link input[month] month} + *    - {@link input[week] week}   *  - {@link ng.directive:select select}   *  - {@link ng.directive:textarea textarea}   * diff --git a/src/ng/filter/filters.js b/src/ng/filter/filters.js index b81838c6..7c805660 100644 --- a/src/ng/filter/filters.js +++ b/src/ng/filter/filters.js @@ -235,6 +235,32 @@ function timeZoneGetter(date) {    return paddedZone;  } +function getFirstThursdayOfYear(year) { +    // 0 = index of January +    var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay(); +    // 4 = index of Thursday (+1 to account for 1st = 5) +    // 11 = index of *next* Thursday (+1 account for 1st = 12) +    return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst); +} + +function getThursdayThisWeek(datetime) { +    return new Date(datetime.getFullYear(), datetime.getMonth(), +      // 4 = index of Thursday +      datetime.getDate() + (4 - datetime.getDay())); +} + +function weekGetter(size) { +   return function(date) { +      var firstThurs = getFirstThursdayOfYear(date.getFullYear()), +         thisThurs = getThursdayThisWeek(date); + +      var diff = +thisThurs - +firstThurs, +         result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week + +      return padNumber(result, size); +   }; +} +  function ampmGetter(date, formats) {    return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];  } @@ -263,10 +289,12 @@ var DATE_FORMATS = {    EEEE: dateStrGetter('Day'),     EEE: dateStrGetter('Day', true),       a: ampmGetter, -     Z: timeZoneGetter +     Z: timeZoneGetter, +    ww: weekGetter(2), +     w: weekGetter(1)  }; -var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/, +var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,      NUMBER_STRING = /^\-?\d+$/;  /** @@ -301,6 +329,8 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+   *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)   *   * `'a'`: am/pm marker   *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200) + *   * `'ww'`: ISO-8601 week of year (00-53) + *   * `'w'`: ISO-8601 week of year (0-53)   *   *   `format` string can also be one of the following predefined   *   {@link guide/i18n localizable formats}: diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index e3e50e02..eba3028e 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -762,6 +762,718 @@ describe('input', function() {    // INPUT TYPES +  describe('month', function (){ +      it('should render blank if model is not a Date object', function() { +          compileInput('<input type="month" ng-model="january"/>'); + +          scope.$apply(function(){ +              scope.january = '2013-01'; +          }); + +          expect(inputElm.val()).toBe(''); +      }); + +      it('should set the view if the model is a valid Date object', function (){ +          compileInput('<input type="month" ng-model="march"/>'); + +          scope.$apply(function(){ +              scope.march = new Date(2013, 2, 1); +          }); + +          expect(inputElm.val()).toBe('2013-03'); +      }); + +      it('should set the model undefined if the input is an invalid month string', function () { +          compileInput('<input type="month" ng-model="value"/>'); + +          scope.$apply(function(){ +              scope.value = new Date(2013, 0, 1); +          }); + + +          expect(inputElm.val()).toBe('2013-01'); + +          try { +              //set to text for browsers with datetime-local validation. +              inputElm[0].setAttribute('type', 'text'); +          } catch(e) { +              //for IE8 +          } + +          changeInputValueTo('stuff'); +          expect(inputElm.val()).toBe('stuff'); +          expect(scope.value).toBeUndefined(); +          expect(inputElm).toBeInvalid(); +      }); + +      it('should render as blank if null', function() { +          compileInput('<input type="month" ng-model="test" />'); + +          scope.$apply(function() { +              scope.test = null; +          }); + +          expect(scope.test).toBeNull(); +          expect(inputElm.val()).toEqual(''); +      }); + +      it('should come up blank when no value specified', function() { +          compileInput('<input type="month" ng-model="test" />'); + +          scope.$digest(); +          expect(inputElm.val()).toBe(''); + +          scope.$apply(function() { +              scope.test = null; +          }); + +          expect(scope.test).toBeNull(); +          expect(inputElm.val()).toBe(''); +      }); + + +      it('should parse empty string to null', function() { +          compileInput('<input type="month" ng-model="test" />'); + +          scope.$apply(function() { +              scope.test = new Date(2011, 0, 1); +          }); + +          changeInputValueTo(''); +          expect(scope.test).toBeNull(); +          expect(inputElm).toBeValid(); +      }); + + +      describe('min', function (){ +          beforeEach(function (){ +              compileInput('<input type="month" ng-model="value" name="alias" min="2013-01" />'); +              scope.$digest(); +          }); + +          it('should invalidate', function (){ +              changeInputValueTo('2012-12'); +              expect(inputElm).toBeInvalid(); +              expect(scope.value).toBeFalsy(); +              expect(scope.form.alias.$error.min).toBeTruthy(); +          }); + +          it('should validate', function (){ +              changeInputValueTo('2013-07'); +              expect(inputElm).toBeValid(); +              expect(+scope.value).toBe(+new Date(2013, 6, 1)); +              expect(scope.form.alias.$error.min).toBeFalsy(); +          }); +      }); + +      describe('max', function(){ +          beforeEach(function (){ +              compileInput('<input type="month" ng-model="value" name="alias" max="2013-01" />'); +              scope.$digest(); +          }); + +          it('should validate', function (){ +              changeInputValueTo('2012-03'); +              expect(inputElm).toBeValid(); +              expect(+scope.value).toBe(+new Date(2012, 2, 1)); +              expect(scope.form.alias.$error.max).toBeFalsy(); +          }); + +          it('should invalidate', function (){ +              changeInputValueTo('2013-05'); +              expect(inputElm).toBeInvalid(); +              expect(scope.value).toBeUndefined(); +              expect(scope.form.alias.$error.max).toBeTruthy(); +          }); +      }); +  }); + +   describe('week', function (){ +      it('should set render blank if model is not a Date object', function() { +         compileInput('<input type="week" ng-model="secondWeek"/>'); + +         scope.$apply(function(){ +            scope.secondWeek = '2013-W02'; +         }); + +         expect(inputElm.val()).toBe(''); +      }); + +      it('should set the view if the model is a valid Date object', function (){ +         compileInput('<input type="week" ng-model="secondWeek"/>'); + +         scope.$apply(function(){ +            scope.secondWeek = new Date(2013, 0, 11); +         }); + +         expect(inputElm.val()).toBe('2013-W02'); +      }); + +      it('should set the model undefined if the input is an invalid week string', function () { +         compileInput('<input type="week" ng-model="value"/>'); + +         scope.$apply(function(){ +            scope.value = new Date(2013, 0, 11); +         }); + + +         expect(inputElm.val()).toBe('2013-W02'); + +         try { +            //set to text for browsers with datetime-local validation. +            inputElm[0].setAttribute('type', 'text'); +         } catch(e) { +            //for IE8 +         } + +         changeInputValueTo('stuff'); +         expect(inputElm.val()).toBe('stuff'); +         expect(scope.value).toBeUndefined(); +         expect(inputElm).toBeInvalid(); +      }); + +       it('should render as blank if null', function() { +           compileInput('<input type="week" ng-model="test" />'); + +           scope.$apply(function() { +               scope.test = null; +           }); + +           expect(scope.test).toBeNull(); +           expect(inputElm.val()).toEqual(''); +       }); + +       it('should come up blank when no value specified', function() { +           compileInput('<input type="week" ng-model="test" />'); + +           scope.$digest(); +           expect(inputElm.val()).toBe(''); + +           scope.$apply(function() { +               scope.test = null; +           }); + +           expect(scope.test).toBeNull(); +           expect(inputElm.val()).toBe(''); +       }); + + +       it('should parse empty string to null', function() { +           compileInput('<input type="week" ng-model="test" />'); + +           scope.$apply(function() { +               scope.test = new Date(2011, 0, 1); +           }); + +           changeInputValueTo(''); +           expect(scope.test).toBeNull(); +           expect(inputElm).toBeValid(); +       }); + +      describe('min', function (){ +         beforeEach(function (){ +            compileInput('<input type="week" ng-model="value" name="alias" min="2013-W01" />'); +            scope.$digest(); +         }); + +         it('should invalidate', function (){ +            changeInputValueTo('2012-W12'); +            expect(inputElm).toBeInvalid(); +            expect(scope.value).toBeFalsy(); +            expect(scope.form.alias.$error.min).toBeTruthy(); +         }); + +         it('should validate', function (){ +            changeInputValueTo('2013-W03'); +            expect(inputElm).toBeValid(); +            expect(+scope.value).toBe(+new Date(2013, 0, 17)); +            expect(scope.form.alias.$error.min).toBeFalsy(); +         }); +      }); + +      describe('max', function(){ +         beforeEach(function (){ +            compileInput('<input type="week" ng-model="value" name="alias" max="2013-W01" />'); +            scope.$digest(); +         }); + +         it('should validate', function (){ +            changeInputValueTo('2012-W01'); +            expect(inputElm).toBeValid(); +            expect(+scope.value).toBe(+new Date(2012, 0, 5)); +            expect(scope.form.alias.$error.max).toBeFalsy(); +         }); + +         it('should invalidate', function (){ +            changeInputValueTo('2013-W03'); +            expect(inputElm).toBeInvalid(); +            expect(scope.value).toBeUndefined(); +            expect(scope.form.alias.$error.max).toBeTruthy(); +         }); +      }); +   }); + +   describe('datetime-local', function () { +      it('should render blank if model is not a Date object', function() { +         compileInput('<input type="datetime-local" ng-model="lunchtime"/>'); + +         scope.$apply(function(){ +            scope.lunchtime = '2013-12-16T11:30'; +         }); + +         expect(inputElm.val()).toBe(''); +      }); + +      it('should set the view if the model if a valid Date object.', function(){ +         compileInput('<input type="datetime-local" ng-model="tenSecondsToNextYear"/>'); + +         scope.$apply(function (){ +            scope.tenSecondsToNextYear = new Date(2013, 11, 31, 23, 59); +         }); + +         expect(inputElm.val()).toBe('2013-12-31T23:59'); +      }); + +      it('should set the model undefined if the view is invalid', function (){ +         compileInput('<input type="datetime-local" ng-model="breakMe"/>'); + +         scope.$apply(function (){ +            scope.breakMe = new Date(2009, 0, 6, 16, 25); +         }); + +         expect(inputElm.val()).toBe('2009-01-06T16:25'); + +         try { +            //set to text for browsers with datetime-local validation. +            inputElm[0].setAttribute('type', 'text'); +         } catch(e) { +            //for IE8 +         } + +         changeInputValueTo('stuff'); +         expect(inputElm.val()).toBe('stuff'); +         expect(scope.breakMe).toBeUndefined(); +         expect(inputElm).toBeInvalid(); +      }); + +       it('should render as blank if null', function() { +           compileInput('<input type="datetime-local" ng-model="test" />'); + +           scope.$apply(function() { +               scope.test = null; +           }); + +           expect(scope.test).toBeNull(); +           expect(inputElm.val()).toEqual(''); +       }); + +       it('should come up blank when no value specified', function() { +           compileInput('<input type="datetime-local" ng-model="test" />'); + +           scope.$digest(); +           expect(inputElm.val()).toBe(''); + +           scope.$apply(function() { +               scope.test = null; +           }); + +           expect(scope.test).toBeNull(); +           expect(inputElm.val()).toBe(''); +       }); + + +       it('should parse empty string to null', function() { +           compileInput('<input type="datetime-local" ng-model="test" />'); + +           scope.$apply(function() { +               scope.test = new Date(2011, 0, 1); +           }); + +           changeInputValueTo(''); +           expect(scope.test).toBeNull(); +           expect(inputElm).toBeValid(); +       }); + +      describe('min', function (){ +         beforeEach(function (){ +            compileInput('<input type="datetime-local" ng-model="value" name="alias" min="2000-01-01T12:30" />'); +            scope.$digest(); +         }); + +         it('should invalidate', function (){ +            changeInputValueTo('1999-12-31T01:02'); +            expect(inputElm).toBeInvalid(); +            expect(scope.value).toBeFalsy(); +            expect(scope.form.alias.$error.min).toBeTruthy(); +         }); + +         it('should validate', function (){ +            changeInputValueTo('2000-01-01T23:02'); +            expect(inputElm).toBeValid(); +            expect(+scope.value).toBe(+new Date(2000, 0, 1, 23, 2)); +            expect(scope.form.alias.$error.min).toBeFalsy(); +         }); +      }); + +      describe('max', function (){ +         beforeEach(function (){ +            compileInput('<input type="datetime-local" ng-model="value" name="alias" max="2019-01-01T01:02" />'); +            scope.$digest(); +         }); + +         it('should invalidate', function (){ +            changeInputValueTo('2019-12-31T01:02'); +            expect(inputElm).toBeInvalid(); +            expect(scope.value).toBeFalsy(); +            expect(scope.form.alias.$error.max).toBeTruthy(); +         }); + +         it('should validate', function() { +            changeInputValueTo('2000-01-01T01:02'); +            expect(inputElm).toBeValid(); +            expect(+scope.value).toBe(+new Date(2000, 0, 1, 1, 2)); +            expect(scope.form.alias.$error.max).toBeFalsy(); +         }); +      }); + +      it('should validate even if max value changes on-the-fly', function(done) { +         scope.max = '2013-01-01T01:02'; +         compileInput('<input type="datetime-local" ng-model="value" name="alias" max="{{max}}" />'); +         scope.$digest(); + +         changeInputValueTo('2014-01-01T12:34'); +         expect(inputElm).toBeInvalid(); + +         scope.max = '2001-01-01T01:02'; +         scope.$digest(function () { +            expect(inputElm).toBeValid(); +            done(); +         }); +      }); + +      it('should validate even if min value changes on-the-fly', function(done) { +         scope.min = '2013-01-01T01:02'; +         compileInput('<input type="datetime-local" ng-model="value" name="alias" min="{{min}}" />'); +         scope.$digest(); + +         changeInputValueTo('2010-01-01T12:34'); +         expect(inputElm).toBeInvalid(); + +         scope.min = '2014-01-01T01:02'; +         scope.$digest(function () { +            expect(inputElm).toBeValid(); +            done(); +         }); +      }); +   }); + +  describe('time', function () { +    it('should render blank if model is not a Date object', function() { +      compileInput('<input type="time" ng-model="lunchtime"/>'); + +      scope.$apply(function(){ +        scope.lunchtime = '11:30'; +      }); + +      expect(inputElm.val()).toBe(''); +    }); + +    it('should set the view if the model if a valid Date object.', function(){ +      compileInput('<input type="time" ng-model="threeFortyOnePm"/>'); + +      scope.$apply(function (){ +        scope.threeFortyOnePm = new Date(0, 0, 1, 15, 41); +      }); + +      expect(inputElm.val()).toBe('15:41'); +    }); + +    it('should set the model undefined if the view is invalid', function (){ +      compileInput('<input type="time" ng-model="breakMe"/>'); + +      scope.$apply(function (){ +        scope.breakMe = new Date(0, 0, 1, 16, 25); +      }); + +      expect(inputElm.val()).toBe('16:25'); + +      try { +        //set to text for browsers with time validation. +        inputElm[0].setAttribute('type', 'text'); +      } catch(e) { +        //for IE8 +      } + +      changeInputValueTo('stuff'); +      expect(inputElm.val()).toBe('stuff'); +      expect(scope.breakMe).toBeUndefined(); +      expect(inputElm).toBeInvalid(); +    }); + +      it('should render as blank if null', function() { +          compileInput('<input type="time" ng-model="test" />'); + +          scope.$apply(function() { +              scope.test = null; +          }); + +          expect(scope.test).toBeNull(); +          expect(inputElm.val()).toEqual(''); +      }); + +      it('should come up blank when no value specified', function() { +          compileInput('<input type="time" ng-model="test" />'); + +          scope.$digest(); +          expect(inputElm.val()).toBe(''); + +          scope.$apply(function() { +              scope.test = null; +          }); + +          expect(scope.test).toBeNull(); +          expect(inputElm.val()).toBe(''); +      }); + + +      it('should parse empty string to null', function() { +          compileInput('<input type="time" ng-model="test" />'); + +          scope.$apply(function() { +              scope.test = new Date(2011, 0, 1); +          }); + +          changeInputValueTo(''); +          expect(scope.test).toBeNull(); +          expect(inputElm).toBeValid(); +      }); + +    describe('min', function (){ +      beforeEach(function (){ +        compileInput('<input type="time" ng-model="value" name="alias" min="09:30" />'); +        scope.$digest(); +      }); + +      it('should invalidate', function (){ +        changeInputValueTo('01:02'); +        expect(inputElm).toBeInvalid(); +        expect(scope.value).toBeFalsy(); +        expect(scope.form.alias.$error.min).toBeTruthy(); +      }); + +      it('should validate', function (){ +        changeInputValueTo('23:02'); +        expect(inputElm).toBeValid(); +        expect(+scope.value).toBe(+new Date(0, 0, 1, 23, 2)); +        expect(scope.form.alias.$error.min).toBeFalsy(); +      }); +    }); + +    describe('max', function (){ +      beforeEach(function (){ +        compileInput('<input type="time" ng-model="value" name="alias" max="22:30" />'); +        scope.$digest(); +      }); + +      it('should invalidate', function (){ +        changeInputValueTo('23:00'); +        expect(inputElm).toBeInvalid(); +        expect(scope.value).toBeFalsy(); +        expect(scope.form.alias.$error.max).toBeTruthy(); +      }); + +      it('should validate', function() { +        changeInputValueTo('05:30'); +        expect(inputElm).toBeValid(); +        expect(+scope.value).toBe(+new Date(0, 0, 1, 5, 30)); +        expect(scope.form.alias.$error.max).toBeFalsy(); +      }); +    }); + +    it('should validate even if max value changes on-the-fly', function(done) { +      scope.max = '21:02'; +      compileInput('<input type="time" ng-model="value" name="alias" max="{{max}}" />'); +      scope.$digest(); + +      changeInputValueTo('22:34'); +      expect(inputElm).toBeInvalid(); + +      scope.max = '12:34'; +      scope.$digest(function () { +        expect(inputElm).toBeValid(); +        done(); +      }); +    }); + +    it('should validate even if min value changes on-the-fly', function(done) { +      scope.min = '08:45'; +      compileInput('<input type="time" ng-model="value" name="alias" min="{{min}}" />'); +      scope.$digest(); + +      changeInputValueTo('06:15'); +      expect(inputElm).toBeInvalid(); + +      scope.min = '13:50'; +      scope.$digest(function () { +        expect(inputElm).toBeValid(); +        done(); +      }); +    }); +  }); + +  describe('date', function () { +    it('should render blank if model is not a Date object.', function() { +        compileInput('<input type="date" ng-model="birthday"/>'); + +        scope.$apply(function(){ +            scope.birthday = '1977-10-22'; +        }); + +        expect(inputElm.val()).toBe(''); +    }); + +    it('should set the view if the model if a valid Date object.', function(){ +        compileInput('<input type="date" ng-model="christmas"/>'); + +        scope.$apply(function (){ +            scope.christmas = new Date(2013, 11, 25); +        }); + +        expect(inputElm.val()).toBe('2013-12-25'); +    }); + +    it('should set the model undefined if the view is invalid', function (){ +        compileInput('<input type="date" ng-model="arrMatey"/>'); + +        scope.$apply(function (){ +            scope.arrMatey = new Date(2014, 8, 14); +        }); + +        expect(inputElm.val()).toBe('2014-09-14'); + +        try { +            //set to text for browsers with date validation. +            inputElm[0].setAttribute('type', 'text'); +        } catch(e) { +            //for IE8 +        } + +        changeInputValueTo('1-2-3'); +        expect(inputElm.val()).toBe('1-2-3'); +        expect(scope.arrMatey).toBeUndefined(); +        expect(inputElm).toBeInvalid(); +    }); + +      it('should render as blank if null', function() { +          compileInput('<input type="date" ng-model="test" />'); + +          scope.$apply(function() { +              scope.test = null; +          }); + +          expect(scope.test).toBeNull(); +          expect(inputElm.val()).toEqual(''); +      }); + +      it('should come up blank when no value specified', function() { +          compileInput('<input type="date" ng-model="test" />'); + +          scope.$digest(); +          expect(inputElm.val()).toBe(''); + +          scope.$apply(function() { +              scope.test = null; +          }); + +          expect(scope.test).toBeNull(); +          expect(inputElm.val()).toBe(''); +      }); + + +      it('should parse empty string to null', function() { +          compileInput('<input type="date" ng-model="test" />'); + +          scope.$apply(function() { +              scope.test = new Date(2011, 0, 1); +          }); + +          changeInputValueTo(''); +          expect(scope.test).toBeNull(); +          expect(inputElm).toBeValid(); +      }); + +    describe('min', function (){ +        beforeEach(function (){ +           compileInput('<input type="date" ng-model="value" name="alias" min="2000-01-01" />'); +           scope.$digest(); +        }); + +        it('should invalidate', function (){ +           changeInputValueTo('1999-12-31'); +           expect(inputElm).toBeInvalid(); +           expect(scope.value).toBeFalsy(); +           expect(scope.form.alias.$error.min).toBeTruthy(); +        }); + +        it('should validate', function (){ +            changeInputValueTo('2000-01-01'); +            expect(inputElm).toBeValid(); +            expect(+scope.value).toBe(+new Date(2000, 0, 1)); +            expect(scope.form.alias.$error.min).toBeFalsy(); +        }); +    }); + +    describe('max', function (){ +        beforeEach(function (){ +           compileInput('<input type="date" ng-model="value" name="alias" max="2019-01-01" />'); +           scope.$digest(); +        }); + +        it('should invalidate', function (){ +            changeInputValueTo('2019-12-31'); +            expect(inputElm).toBeInvalid(); +            expect(scope.value).toBeFalsy(); +            expect(scope.form.alias.$error.max).toBeTruthy(); +        }); + +        it('should validate', function() { +            changeInputValueTo('2000-01-01'); +            expect(inputElm).toBeValid(); +            expect(+scope.value).toBe(+new Date(2000, 0, 1)); +            expect(scope.form.alias.$error.max).toBeFalsy(); +        }); +    }); + +    it('should validate even if max value changes on-the-fly', function(done) { +      scope.max = '2013-01-01'; +      compileInput('<input type="date" ng-model="value" name="alias" max="{{max}}" />'); +      scope.$digest(); + +      changeInputValueTo('2014-01-01'); +      expect(inputElm).toBeInvalid(); + +      scope.max = '2001-01-01'; +      scope.$digest(function () { +         expect(inputElm).toBeValid(); +         done(); +      }); +    }); + +    it('should validate even if min value changes on-the-fly', function(done) { +       scope.min = '2013-01-01'; +       compileInput('<input type="date" ng-model="value" name="alias" min="{{min}}" />'); +       scope.$digest(); + +       changeInputValueTo('2010-01-01'); +       expect(inputElm).toBeInvalid(); + +       scope.min = '2014-01-01'; +       scope.$digest(function () { +          expect(inputElm).toBeValid(); +          done(); +       }); +    }); +  });    describe('number', function() { @@ -798,7 +1510,6 @@ describe('input', function() {        expect(inputElm.val()).toEqual('');      }); -      it('should come up blank when no value specified', function() {        compileInput('<input type="number" ng-model="age" />'); diff --git a/test/ng/filter/filtersSpec.js b/test/ng/filter/filtersSpec.js index 8e6ec1f1..efe12e05 100644 --- a/test/ng/filter/filtersSpec.js +++ b/test/ng/filter/filtersSpec.js @@ -197,7 +197,7 @@ describe('filters', function() {      var noon =     new angular.mock.TzDate(+5, '2010-09-03T17:05:08.012Z'); //12pm      var midnight = new angular.mock.TzDate(+5, '2010-09-03T05:05:08.123Z'); //12am      var earlyDate = new angular.mock.TzDate(+5, '0001-09-03T05:05:08.000Z'); - +    var secondWeek = new angular.mock.TzDate(+5, '2013-01-11T12:00:00.000Z'); //Friday Jan 11, 2012      var date;      beforeEach(inject(function($filter) { @@ -220,6 +220,12 @@ describe('filters', function() {      });      it('should accept various format strings', function() { +      expect(date(secondWeek, 'yyyy-Ww')). +                      toEqual('2013-W2'); + +      expect(date(secondWeek, 'yyyy-Www')). +                      toEqual('2013-W02'); +        expect(date(morning, "yy-MM-dd HH:mm:ss")).                        toEqual('10-09-03 07:05:08'); | 
