From d846e2d788020c8d4c270ae7d90066bb092f1a16 Mon Sep 17 00:00:00 2001 From: Wesley Cho Date: Sun, 26 Jun 2016 23:14:14 -0700 Subject: [PATCH] fix(dateparser): correctly format with literals - Fix formatting of dates with literal usage Closes #6055 Fixes #5620 Fixes #5802 --- src/dateparser/dateparser.js | 91 ++++++++++++++++++++------ src/dateparser/test/dateparser.spec.js | 42 ++++++------ 2 files changed, 91 insertions(+), 42 deletions(-) diff --git a/src/dateparser/dateparser.js b/src/dateparser/dateparser.js index 3dae13b051..732ed4e01b 100644 --- a/src/dateparser/dateparser.js +++ b/src/dateparser/dateparser.js @@ -234,7 +234,7 @@ angular.module('ui.bootstrap.dateparser', []) this.init(); - function createParser(format, func) { + function createParser(format) { var map = [], regex = format.split(''); // check for literal values @@ -283,7 +283,7 @@ angular.module('ui.bootstrap.dateparser', []) map.push({ index: index, key: data.key, - apply: data[func], + apply: data.apply, matcher: data.regex }); } @@ -295,6 +295,70 @@ angular.module('ui.bootstrap.dateparser', []) }; } + function createFormatter(format) { + var formatters = []; + var i = 0; + var formatter, literalIdx; + while (i < format.length) { + if (angular.isNumber(literalIdx)) { + if (format.charAt(i) === '\'') { + if (i + 1 >= format.length || format.charAt(i + 1) !== '\'') { + formatters.push(constructLiteralFormatter(format, literalIdx, i)); + literalIdx = null; + } + } else if (i === format.length) { + while (literalIdx < format.length) { + formatter = constructFormatterFromIdx(format, literalIdx); + formatters.push(formatter); + literalIdx = formatter.endIdx; + } + } + + i++; + continue; + } + + if (format.charAt(i) === '\'') { + literalIdx = i; + i++; + continue; + } + + formatter = constructFormatterFromIdx(format, i); + + formatters.push(formatter.parser); + i = formatter.endIdx; + } + + return formatters; + } + + function constructLiteralFormatter(format, literalIdx, endIdx) { + return function() { + return format.substr(literalIdx + 1, endIdx - literalIdx - 1); + }; + } + + function constructFormatterFromIdx(format, i) { + var currentPosStr = format.substr(i); + for (var j = 0; j < formatCodeToRegex.length; j++) { + if (new RegExp('^' + formatCodeToRegex[j].key).test(currentPosStr)) { + var data = formatCodeToRegex[j]; + return { + endIdx: i + data.key.length, + parser: data.formatter + }; + } + } + + return { + endIdx: i + 1, + parser: function() { + return currentPosStr.charAt(0); + } + }; + } + this.filter = function(date, format) { if (!angular.isDate(date) || isNaN(date) || !format) { return ''; @@ -307,28 +371,13 @@ angular.module('ui.bootstrap.dateparser', []) } if (!this.formatters[format]) { - this.formatters[format] = createParser(format, 'formatter'); + this.formatters[format] = createFormatter(format); } - var parser = this.formatters[format], - map = parser.map; - - var _format = format; - - return map.reduce(function(str, mapper, i) { - var match = _format.match(new RegExp('(.*)' + mapper.key)); - if (match && angular.isString(match[1])) { - str += match[1]; - _format = _format.replace(match[1] + mapper.key, ''); - } - - var endStr = i === map.length - 1 ? _format : ''; - - if (mapper.apply) { - return str + mapper.apply.call(null, date) + endStr; - } + var formatters = this.formatters[format]; - return str + endStr; + return formatters.reduce(function(str, formatter) { + return str + formatter(date); }, ''); }; diff --git a/src/dateparser/test/dateparser.spec.js b/src/dateparser/test/dateparser.spec.js index 8b96a7c77a..419a705bf5 100644 --- a/src/dateparser/test/dateparser.spec.js +++ b/src/dateparser/test/dateparser.spec.js @@ -565,27 +565,27 @@ describe('date parser', function() { }); describe('with value literals', function() { - // describe('filter', function() { - // it('should work with multiple literals', function() { - // expect(dateParser.filter(new Date(2013, 0, 29), 'd \'de\' MMMM \'de\' y')).toEqual('29 de January de 2013'); - // }); - // - // it('should work with escaped single quote', function() { - // expect(dateParser.filter(new Date(2015, 2, 22, 12), 'd.MMMM.yy h \'o\'\'clock\'')).toEqual('22.March.15 12 o\'clock'); - // }); - // - // it('should work with only a single quote', function() { - // expect(dateParser.filter(new Date(2015, 2, 22), 'd.MMMM.yy \'\'\'')).toEqual('22.March.15 \''); - // }); - // - // it('should work with trailing literal', function() { - // expect(dateParser.filter(new Date(2013, 0, 1), '\'year\' y')).toEqual('year 2013'); - // }); - // - // it('should work without whitespace', function() { - // expect(dateParser.filter(new Date(2013, 0, 1), '\'year:\'y')).toEqual('year:2013'); - // }); - // }); + describe('filter', function() { + it('should work with multiple literals', function() { + expect(dateParser.filter(new Date(2013, 0, 29), 'd \'de\' MMMM \'de\' y')).toEqual('29 de January de 2013'); + }); + + it('should work with escaped single quote', function() { + expect(dateParser.filter(new Date(2015, 2, 22, 12), 'd.MMMM.yy h \'o\'\'clock\'')).toEqual('22.March.15 12 o\'clock'); + }); + + it('should work with only a single quote', function() { + expect(dateParser.filter(new Date(2015, 2, 22), 'd.MMMM.yy \'\'\'')).toEqual('22.March.15 \''); + }); + + it('should work with trailing literal', function() { + expect(dateParser.filter(new Date(2013, 0, 1), '\'year\' y')).toEqual('year 2013'); + }); + + it('should work without whitespace', function() { + expect(dateParser.filter(new Date(2013, 0, 1), '\'year:\'y')).toEqual('year:2013'); + }); + }); describe('parse', function() { it('should work with multiple literals', function() {