diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index 35f3d31cea1c..1692061a0146 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -1004,7 +1004,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { }; } -function weekParser(isoWeek) { +function weekParser(isoWeek, existingDate) { if (isDate(isoWeek)) { return isoWeek; } @@ -1015,9 +1015,21 @@ function weekParser(isoWeek) { if (parts) { var year = +parts[1], week = +parts[2], + hours = 0, + minutes = 0, + seconds = 0, + milliseconds = 0, firstThurs = getFirstThursdayOfYear(year), addDays = (week - 1) * 7; - return new Date(year, 0, firstThurs.getDate() + addDays); + + if (existingDate) { + hours = existingDate.getHours(); + minutes = existingDate.getMinutes(); + seconds = existingDate.getSeconds(); + milliseconds = existingDate.getMilliseconds(); + } + + return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds); } } @@ -1025,7 +1037,7 @@ function weekParser(isoWeek) { } function createDateParser(regexp, mapping) { - return function(iso) { + return function(iso, date) { var parts, map; if (isDate(iso)) { @@ -1047,14 +1059,26 @@ function createDateParser(regexp, mapping) { if (parts) { parts.shift(); - map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0 }; + if (date) { + map = { + yyyy: date.getFullYear(), + MM: date.getMonth() + 1, + dd: date.getDate(), + HH: date.getHours(), + mm: date.getMinutes(), + ss: date.getSeconds(), + sss: date.getMilliseconds() + }; + } else { + map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 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, map.ss || 0); + return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss || 0); } } @@ -1072,7 +1096,12 @@ function createDateInputType(type, regexp, parseDate, format) { ctrl.$parsers.push(function(value) { if (ctrl.$isEmpty(value)) return null; if (regexp.test(value)) { - var parsedDate = parseDate(value); + var previousDate = ctrl.$modelValue; + if (previousDate && timezone === 'UTC') { + var timezoneOffset = 60000 * previousDate.getTimezoneOffset(); + previousDate = new Date(previousDate.getTime() + timezoneOffset); + } + var parsedDate = parseDate(value, previousDate); if (timezone === 'UTC') { parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset()); } diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index 1fde81335ce4..a50c1640cfc5 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -2314,6 +2314,17 @@ describe('input', function() { expect(scope.form.alias.$error.month).toBeTruthy(); }); + it('should only change the month of a bound date', function() { + compileInput(''); + + scope.$apply(function() { + scope.value = new Date(Date.UTC(2013, 7, 1, 1, 0, 0, 0)); + }); + changeInputValueTo('2013-12'); + expect(+scope.value).toBe(Date.UTC(2013, 11, 1, 1, 0, 0, 0)); + expect(inputElm.val()).toBe('2013-12'); + }); + describe('min', function (){ var scope; beforeEach(inject(function ($rootScope){ @@ -2406,6 +2417,18 @@ describe('input', function() { expect(inputElm.val()).toBe('2013-W02'); }); + it('should not affect the hours or minutes of a bound date', function (){ + compileInput(''); + + scope.$apply(function(){ + scope.secondWeek = new Date(2013, 0, 11, 1, 0, 0, 0); + }); + + changeInputValueTo('2013-W03'); + + expect(+scope.secondWeek).toBe(+new Date(2013, 0, 17, 1, 0, 0, 0)); + }); + it('should set the model undefined if the input is an invalid week string', function () { compileInput(''); @@ -2934,6 +2957,17 @@ describe('input', function() { expect(scope.form.alias.$error.time).toBeTruthy(); }); + it('should only change hours and minute of a bound date', function() { + compileInput(''); + + scope.$apply(function(){ + scope.value = new Date(2013, 2, 3, 1, 0, 0); + }); + + changeInputValueTo('01:02'); + expect(+scope.value).toBe(+new Date(2013, 2, 3, 1, 2, 0)); + }); + describe('min', function (){ var scope; beforeEach(inject(function ($rootScope){ @@ -3141,6 +3175,50 @@ describe('input', function() { expect(scope.form.alias.$error.date).toBeTruthy(); }); + it('should work with multiple date types bound to the same model', function() { + formElm = jqLite('
'); + + var timeElm = jqLite(''), + monthElm = jqLite(''), + weekElm = jqLite(''); + + formElm.append(timeElm); + formElm.append(monthElm); + formElm.append(weekElm); + + $compile(formElm)(scope); + + scope.$apply(function() { + scope.val = new Date(2013, 1, 2, 3, 4, 5, 6); + }); + + expect(timeElm.val()).toBe('03:04:05'); + expect(monthElm.val()).toBe('2013-02'); + expect(weekElm.val()).toBe('2013-W05'); + + changeGivenInputTo(monthElm, '2012-02'); + expect(monthElm.val()).toBe('2012-02'); + expect(timeElm.val()).toBe('03:04:05'); + expect(weekElm.val()).toBe('2012-W05'); + + changeGivenInputTo(timeElm, '04:05:06'); + expect(monthElm.val()).toBe('2012-02'); + expect(timeElm.val()).toBe('04:05:06'); + expect(weekElm.val()).toBe('2012-W05'); + + changeGivenInputTo(weekElm, '2014-W01'); + expect(monthElm.val()).toBe('2014-01'); + expect(timeElm.val()).toBe('04:05:06'); + expect(weekElm.val()).toBe('2014-W01'); + + expect(+scope.val).toBe(+new Date(2014, 0, 2, 4, 5, 6, 6)); + + function changeGivenInputTo(inputElm, value) { + inputElm.val(value); + browserTrigger(inputElm, $sniffer.hasEvent('input') ? 'input' : 'change'); + } + }); + describe('min', function (){ beforeEach(function (){ compileInput('');