Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 5f90340

Browse files
committed
fix(input): allow to use seconds in input[time] and input[datetime-local]
The HTML5 spec allows to use seconds for `input[time]` and `input[datetime-local]`, even though they are not displayed by all browsers. Related to #8447.
1 parent cc6fc19 commit 5f90340

File tree

2 files changed

+109
-72
lines changed

2 files changed

+109
-72
lines changed

src/ng/directive/input.js

+26-27
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\
1212
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
1313
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
1414
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
15-
var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/;
15+
var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d))?$/;
1616
var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
1717
var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
18-
var TIME_REGEXP = /^(\d\d):(\d\d)$/;
18+
var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d))?$/;
1919
var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
2020

2121
var inputType = {
@@ -199,17 +199,17 @@ var inputType = {
199199
* @description
200200
* Input with datetime validation and transformation. In browsers that do not yet support
201201
* the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
202-
* local datetime format (yyyy-MM-ddTHH:mm), for example: `2010-12-28T14:57`. The model must be a Date object.
202+
* local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. The model must be a Date object.
203203
*
204204
* The timezone to be used to read/write the `Date` instance in the model can be defined using
205205
* {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
206206
*
207207
* @param {string} ngModel Assignable angular expression to data-bind to.
208208
* @param {string=} name Property name of the form under which the control is published.
209209
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
210-
* valid ISO datetime format (yyyy-MM-ddTHH:mm).
210+
* valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
211211
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
212-
* a valid ISO datetime format (yyyy-MM-ddTHH:mm).
212+
* a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
213213
* @param {string=} required Sets `required` validation error key if the value is not entered.
214214
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
215215
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -229,20 +229,20 @@ var inputType = {
229229
<form name="myForm" ng-controller="DateController as dateCtrl">
230230
Pick a date between in 2013:
231231
<input type="datetime-local" id="exampleInput" name="input" ng-model="value"
232-
placeholder="yyyy-MM-ddTHH:mm" min="2001-01-01T00:00" max="2013-12-31T00:00" required />
232+
placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
233233
<span class="error" ng-show="myForm.input.$error.required">
234234
Required!</span>
235235
<span class="error" ng-show="myForm.input.$error.datetimelocal">
236236
Not a valid date!</span>
237-
<tt>value = {{value | date: "yyyy-MM-ddTHH:mm"}}</tt><br/>
237+
<tt>value = {{value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
238238
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
239239
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
240240
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
241241
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
242242
</form>
243243
</file>
244244
<file name="protractor.js" type="protractor">
245-
var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm"'));
245+
var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm:ss"'));
246246
var valid = element(by.binding('myForm.input.$valid'));
247247
var input = element(by.model('value'));
248248
@@ -258,7 +258,7 @@ var inputType = {
258258
}
259259
260260
it('should initialize to model', function() {
261-
expect(value.getText()).toContain('2010-12-28T14:57');
261+
expect(value.getText()).toContain('2010-12-28T14:57:00');
262262
expect(valid.getText()).toContain('myForm.input.$valid = true');
263263
});
264264
@@ -269,16 +269,16 @@ var inputType = {
269269
});
270270
271271
it('should be invalid if over max', function() {
272-
setInput('2015-01-01T23:59');
272+
setInput('2015-01-01T23:59:00');
273273
expect(value.getText()).toContain('');
274274
expect(valid.getText()).toContain('myForm.input.$valid = false');
275275
});
276276
</file>
277277
</example>
278278
*/
279279
'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
280-
createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm']),
281-
'yyyy-MM-ddTHH:mm'),
280+
createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss']),
281+
'yyyy-MM-ddTHH:mm:ss'),
282282

283283
/**
284284
* @ngdoc input
@@ -287,18 +287,18 @@ var inputType = {
287287
* @description
288288
* Input with time validation and transformation. In browsers that do not yet support
289289
* the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
290-
* local time format (HH:mm), for example: `14:57`. Model must be a Date object. This binding will always output a
291-
* Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm)`.
290+
* local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
291+
* Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
292292
*
293293
* The timezone to be used to read/write the `Date` instance in the model can be defined using
294294
* {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
295295
*
296296
* @param {string} ngModel Assignable angular expression to data-bind to.
297297
* @param {string=} name Property name of the form under which the control is published.
298298
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
299-
* valid ISO time format (HH:mm).
299+
* valid ISO time format (HH:mm:ss).
300300
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
301-
* valid ISO time format (HH:mm).
301+
* valid ISO time format (HH:mm:ss).
302302
* @param {string=} required Sets `required` validation error key if the value is not entered.
303303
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
304304
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -312,26 +312,26 @@ var inputType = {
312312
<script>
313313
angular.module('timeExample', [])
314314
.controller('DateController', ['$scope', function($scope) {
315-
$scope.value = new Date(1970, 0, 1, 14, 57);
315+
$scope.value = new Date(1970, 0, 1, 14, 57, 0);
316316
}]);
317317
</script>
318318
<form name="myForm" ng-controller="DateController as dateCtrl">
319319
Pick a between 8am and 5pm:
320320
<input type="time" id="exampleInput" name="input" ng-model="value"
321-
placeholder="HH:mm" min="08:00" max="17:00" required />
321+
placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
322322
<span class="error" ng-show="myForm.input.$error.required">
323323
Required!</span>
324324
<span class="error" ng-show="myForm.input.$error.time">
325325
Not a valid date!</span>
326-
<tt>value = {{value | date: "HH:mm"}}</tt><br/>
326+
<tt>value = {{value | date: "HH:mm:ss"}}</tt><br/>
327327
<tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
328328
<tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
329329
<tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
330330
<tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
331331
</form>
332332
</file>
333333
<file name="protractor.js" type="protractor">
334-
var value = element(by.binding('value | date: "HH:mm"'));
334+
var value = element(by.binding('value | date: "HH:mm:ss"'));
335335
var valid = element(by.binding('myForm.input.$valid'));
336336
var input = element(by.model('value'));
337337
@@ -347,7 +347,7 @@ var inputType = {
347347
}
348348
349349
it('should initialize to model', function() {
350-
expect(value.getText()).toContain('14:57');
350+
expect(value.getText()).toContain('14:57:00');
351351
expect(valid.getText()).toContain('myForm.input.$valid = true');
352352
});
353353
@@ -358,16 +358,16 @@ var inputType = {
358358
});
359359
360360
it('should be invalid if over max', function() {
361-
setInput('23:59');
361+
setInput('23:59:00');
362362
expect(value.getText()).toContain('');
363363
expect(valid.getText()).toContain('myForm.input.$valid = false');
364364
});
365365
</file>
366366
</example>
367367
*/
368368
'time': createDateInputType('time', TIME_REGEXP,
369-
createDateParser(TIME_REGEXP, ['HH', 'mm']),
370-
'HH:mm'),
369+
createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss']),
370+
'HH:mm:ss'),
371371

372372
/**
373373
* @ngdoc input
@@ -1057,15 +1057,14 @@ function createDateParser(regexp, mapping) {
10571057

10581058
if(parts) {
10591059
parts.shift();
1060-
map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0 };
1060+
map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0 };
10611061

10621062
forEach(parts, function(part, index) {
10631063
if(index < mapping.length) {
10641064
map[mapping[index]] = +part;
10651065
}
10661066
});
1067-
1068-
return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm);
1067+
return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0);
10691068
}
10701069
}
10711070

0 commit comments

Comments
 (0)