From 918374e89110d613a92c5177126a37a1bc615989 Mon Sep 17 00:00:00 2001 From: Joe Taylor III Date: Tue, 3 Nov 2015 09:45:10 -0800 Subject: [PATCH] a fix to selecting expiry date with 1|2/1|2 and typing --- public/javascript/field-kit.js | 46 +++++++++++++++++---- src/expiry_date_formatter.js | 36 ++++++++++++---- test/selenium/expiry_date_formatter_test.js | 30 ++++++++++++++ test/unit/expiry_date_formatter_test.js | 46 +++++++++++++++++++++ 4 files changed, 141 insertions(+), 17 deletions(-) diff --git a/public/javascript/field-kit.js b/public/javascript/field-kit.js index e95b69b..fe02e93 100644 --- a/public/javascript/field-kit.js +++ b/public/javascript/field-kit.js @@ -3048,6 +3048,8 @@ Object.defineProperty(exports, '__esModule', { value: true }); +var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })(); + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; @@ -3122,13 +3124,37 @@ var ExpiryDateFormatter = (function (_DelimitedTextFormatter) { if (!value) { return ''; } + if (typeof value === 'string') { + var _value$split = value.split(this.delimiter); + + var _value$split2 = _slicedToArray(_value$split, 2); + + var _value$split2$0 = _value$split2[0]; + var month = _value$split2$0 === undefined ? '' : _value$split2$0; + var _value$split2$1 = _value$split2[1]; + var year = _value$split2$1 === undefined ? '' : _value$split2$1; + + if (month.length > 2) { + year = typeof year === 'undefined' ? month.slice(2) : month.slice(2) + year; + month = month.slice(0, 2); + } + + // If it looks like a valid 4 digit year + if (year.length === 4 && /^(19|20)\d{2}$/.test(year)) { + year = year.slice(2); + } else if (year.length > 2) { + year = year.slice(0, 2); + } - var month = value.month; - var year = value.year; + return _get(Object.getPrototypeOf(ExpiryDateFormatter.prototype), 'format', this).call(this, (0, _utils.zpad2)(month) + year); + } else { + var month = value.month; + var year = value.year; - year = year % 100; + year = year % 100; - return _get(Object.getPrototypeOf(ExpiryDateFormatter.prototype), 'format', this).call(this, (0, _utils.zpad2)(month) + (0, _utils.zpad2)(year)); + return _get(Object.getPrototypeOf(ExpiryDateFormatter.prototype), 'format', this).call(this, (0, _utils.zpad2)(month) + (0, _utils.zpad2)(year)); + } } /** @@ -3187,10 +3213,6 @@ var ExpiryDateFormatter = (function (_DelimitedTextFormatter) { if (newText === '0') { newText = ''; } - if (change.inserted.text.length > 0 && !/^\d$/.test(change.inserted.text)) { - error('expiry-date-formatter.only-digits-allowed'); - return false; - } } // 4| -> 04| @@ -3199,7 +3221,7 @@ var ExpiryDateFormatter = (function (_DelimitedTextFormatter) { } // 15| -> 1| - if (/^1[3-9]$/.test(newText)) { + if (/^1[3-9].*$/.test(newText)) { error('expiry-date-formatter.invalid-month'); return false; } @@ -3215,6 +3237,12 @@ var ExpiryDateFormatter = (function (_DelimitedTextFormatter) { newText += this.delimiter; } + // 103 -> 10/3 + if (newText.length > 2 && !new RegExp('^\\d\\d' + this.delimiter + '(\\d)*').test(newText)) { + newText = newText.replace(this.delimiter, ''); + newText = this.format(newText); + } + var match = newText.match(/^(\d\d)(.)(\d\d?).*$/); if (match && match[2] === this.delimiter) { newText = match[1] + this.delimiter + match[3]; diff --git a/src/expiry_date_formatter.js b/src/expiry_date_formatter.js index b19cb83..0a9c33a 100644 --- a/src/expiry_date_formatter.js +++ b/src/expiry_date_formatter.js @@ -47,11 +47,29 @@ class ExpiryDateFormatter extends DelimitedTextFormatter { */ format(value) { if (!value) { return ''; } + if (typeof value === 'string') { + let [month = '', year = ''] = value.split(this.delimiter); - let {month, year} = value; - year = year % 100; + if (month.length > 2) { + year = typeof year === 'undefined' ? month.slice(2) : + month.slice(2) + year; + month = month.slice(0,2); + } + + // If it looks like a valid 4 digit year + if (year.length === 4 && /^(19|20)\d{2}$/.test(year)) { + year = year.slice(2); + } else if (year.length > 2) { + year = year.slice(0,2); + } + + return super.format(zpad2(month) + year); + } else { + let {month, year} = value; + year = year % 100; - return super.format(zpad2(month) + zpad2(year)); + return super.format(zpad2(month) + zpad2(year)); + } } /** @@ -104,10 +122,6 @@ class ExpiryDateFormatter extends DelimitedTextFormatter { if (newText === '0') { newText = ''; } - if (change.inserted.text.length > 0 && !/^\d$/.test(change.inserted.text)) { - error('expiry-date-formatter.only-digits-allowed'); - return false; - } } // 4| -> 04| @@ -116,7 +130,7 @@ class ExpiryDateFormatter extends DelimitedTextFormatter { } // 15| -> 1| - if (/^1[3-9]$/.test(newText)) { + if (/^1[3-9].*$/.test(newText)) { error('expiry-date-formatter.invalid-month'); return false; } @@ -132,6 +146,12 @@ class ExpiryDateFormatter extends DelimitedTextFormatter { newText += this.delimiter; } + // 103 -> 10/3 + if (newText.length > 2 && !new RegExp('^\\d\\d' + this.delimiter + '(\\d)*').test(newText)) { + newText = newText.replace(this.delimiter, ''); + newText = this.format(newText); + } + const match = newText.match(/^(\d\d)(.)(\d\d?).*$/); if (match && match[2] === this.delimiter) { newText = match[1] + this.delimiter + match[3]; diff --git a/test/selenium/expiry_date_formatter_test.js b/test/selenium/expiry_date_formatter_test.js index 5126e5d..b1dc216 100644 --- a/test/selenium/expiry_date_formatter_test.js +++ b/test/selenium/expiry_date_formatter_test.js @@ -185,6 +185,36 @@ module.exports = function(ua) { }); }); }); + + test.it('part selecting and typing a nonvalid month', function() { + helpers.setInput('12/12', input); + var element = 'window.testField.element'; + + return driver.executeScript(element + '.selectionStart = 1; ' + element + '.selectionEnd = 4;') + .then(function() { + input.sendKeys('444'); + + return helpers.getFieldKitValues() + .then(function(values) { + expect(values.raw).to.equal('12/12'); + }); + }); + }); + + test.it('part selecting and typing a valid month', function() { + helpers.setInput('12/12', input); + var element = 'window.testField.element'; + + return driver.executeScript(element + '.selectionStart = 1; ' + element + '.selectionEnd = 4;') + .then(function() { + input.sendKeys('0'); + + return helpers.getFieldKitValues() + .then(function(values) { + expect(values.raw).to.equal('10/2'); + }); + }); + }); } }); }; diff --git a/test/unit/expiry_date_formatter_test.js b/test/unit/expiry_date_formatter_test.js index 50b2def..6bafb45 100644 --- a/test/unit/expiry_date_formatter_test.js +++ b/test/unit/expiry_date_formatter_test.js @@ -71,6 +71,52 @@ testsWithAllKeyboards('FieldKit.ExpiryDateFormatter', function() { expect(textFieldDidFailToParseString.firstCall.args).to.eql([field, 'abc', 'expiry-date-formatter.invalid-date']); }); + describe('#format', function() { + describe('formats object into string date', function() { + it('with one digit month', function() { + expect(formatter.format({month: 9, year: 1999})).to.eql('09/99'); + }); + + it('with two digit month', function() { + expect(formatter.format({month: 11, year: 1999})).to.eql('11/99'); + }); + + it('with two digit year', function() { + expect(formatter.format({month: 9, year: 99})).to.eql('09/99'); + }); + + it('with one digit year', function() { + expect(formatter.format({month: 9, year: 9})).to.eql('09/09'); + }); + }); + + describe('formats string into string date', function() { + it('with one digit month', function() { + expect(formatter.format('9/99')).to.eql('09/99'); + }); + + it('with two digit month', function() { + expect(formatter.format('11/99')).to.eql('11/99'); + }); + + it('with three digit month', function() { + expect(formatter.format('119/9')).to.eql('11/99'); + }); + + it('with no delimiter', function() { + expect(formatter.format('1199')).to.eql('11/99'); + }); + + it('with no year', function() { + expect(formatter.format('11')).to.eql('11/'); + }); + + it('with four digit year', function() { + expect(formatter.format('11/2018')).to.eql('11/18'); + }); + }); + }); + describe('#parse', function() { var clock;