From 93587eb59c1f7ca8fe719dbddc5307700ad407f8 Mon Sep 17 00:00:00 2001 From: Jared Collier Date: Sat, 11 Jun 2016 23:28:37 -0400 Subject: [PATCH 1/2] #3030 | Fix Datetime format option bug - Update the Datetime field, type definition, and DateInput component to display the selected format for any date selected. - Update the placeholder for Datetime fields to display 'e.g.' before a formatted version of today's date. - Update the Datetime field to not show placeholder text when format is set to false. - Update the Date field, type definition, and DateInput component to display the selected format for any date selected. - Update the placeholder for Date fields to display 'e.g.' before a formatted version of today's date. - Update the Date field to not show placeholder text when format is set to false. - Update variable names to bring the implementations of Date and Datetime in line. --- fields/types/date/DateField.js | 14 +++++------ fields/types/date/DateType.js | 18 ++++++------- fields/types/datetime/DatetimeField.js | 31 +++++++++-------------- fields/types/datetime/DatetimeType.js | 35 +++++++++++++++++++++++--- 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/fields/types/date/DateField.js b/fields/types/date/DateField.js index adf6d6decd..e839cb09a8 100644 --- a/fields/types/date/DateField.js +++ b/fields/types/date/DateField.js @@ -12,13 +12,13 @@ module.exports = Field.create({ getInitialState: function() { return { - value: this.props.value ? this.moment(this.props.value).format(this.props.formatString) : '' + value: this.props.value ? this.moment(this.props.value).format(this.props.dateFormat) : '' }; }, getDefaultProps: function() { return { - formatString: 'YYYY-MM-DD' + dateFormat: 'YYYY-MM-DD' }; }, @@ -30,12 +30,12 @@ module.exports = Field.create({ // TODO: Move isValid() so we can share with server-side code isValid: function(value) { - return moment(value, this.inputFormat).isValid(); + return moment(value, this.props.dateFormat).isValid(); }, // TODO: Move format() so we can share with server-side code format: function(dateValue, format) { - format = format || this.inputFormat; + format = format || this.props.dateFormat; return dateValue ? this.moment(this.props.dateValue).format(format) : ''; }, @@ -48,7 +48,7 @@ module.exports = Field.create({ }, setToday: function() { - this.setDate(moment().format(this.props.formatString)); + this.setDate(moment().format(this.props.dateFormat)); }, valueChanged: function(value) { @@ -63,14 +63,14 @@ module.exports = Field.create({ if (this.shouldRenderField()) { input = (
- +
); } else { input = (
-
{this.format(this.props.value, this.props.formatString)}
+
{this.format(this.props.value, this.props.dateFormat)}
); } diff --git a/fields/types/date/DateType.js b/fields/types/date/DateType.js index 6a8f3b4d18..8515f6c6b3 100644 --- a/fields/types/date/DateType.js +++ b/fields/types/date/DateType.js @@ -12,13 +12,13 @@ function date(list, path, options) { this._nativeType = Date; this._underscoreMethods = ['format', 'moment', 'parse']; this._fixedSize = 'large'; - this._properties = ['formatString', 'placeholder', 'yearRange', 'isUTC']; - this.parseFormatString = options.parseFormat || 'YYYY-MM-DD'; - this.formatString = (options.format === false) ? false : (options.format || 'YYYY-MM-DD'); - this.placeholder = this.formatString ? 'e.g. ' + moment().format(this.parseFormatString) : ''; + this._properties = ['dateFormat', 'datePlaceholder', 'yearRange', 'isUTC']; + this.parseDateFormat = options.parseFormat || 'YYYY-MM-DD'; + this.dateFormat = (options.format === false) ? false : (options.format || 'YYYY-MM-DD'); + this.datePlaceholder = this.dateFormat ? 'e.g. ' + moment().format(this.parseDateFormat) : ''; this.yearRange = options.yearRange; this.isUTC = options.utc || false; - if (this.formatString && 'string' !== typeof this.formatString) { + if (this.dateFormat && 'string' !== typeof this.dateFormat) { throw new Error('FieldType.Date: options.format must be a string.'); } date.super_.call(this, list, path, options); @@ -62,8 +62,8 @@ date.prototype.addFilterToQuery = function(filter, query) { * Formats the field value */ date.prototype.format = function(item, format) { - if (format || this.formatString) { - return item.get(this.path) ? this.moment(item).format(format || this.formatString) : ''; + if (format || this.dateFormat) { + return item.get(this.path) ? this.moment(item).format(format || this.dateFormat) : ''; } else { return item.get(this.path) || ''; } @@ -94,7 +94,7 @@ date.prototype.parse = function(item) { */ date.prototype.validateInput = function(data, required, item) { if (!(this.path in data) && item && item.get(this.path)) return true; - var newValue = moment(data[this.path], this.parseFormatString); + var newValue = moment(data[this.path], this.parseDateFormat); if (required && (!newValue.isValid())) { return false; } else if (data[this.path] && newValue && !newValue.isValid()) { @@ -112,7 +112,7 @@ date.prototype.updateItem = function(item, data) { return; } var m = this.isUTC ? moment.utc : moment; - var newValue = m(data[this.path], this.parseFormatString); + var newValue = m(data[this.path], this.parseDateFormat); if (newValue.isValid()) { if (!item.get(this.path) || !newValue.isSame(item.get(this.path))) { item.set(this.path, newValue.toDate()); diff --git a/fields/types/datetime/DatetimeField.js b/fields/types/datetime/DatetimeField.js index 29acda9800..e3acf9f7fe 100644 --- a/fields/types/datetime/DatetimeField.js +++ b/fields/types/datetime/DatetimeField.js @@ -5,28 +5,21 @@ var DateInput = require('../../components/DateInput'); var moment = require('moment'); module.exports = Field.create({ - + displayName: 'DatetimeField', focusTargetRef: 'dateInput', - // default input formats - dateInputFormat: 'YYYY-MM-DD', - timeInputFormat: 'h:mm:ss a', - - // parse formats (duplicated from lib/fieldTypes/datetime.js) - parseFormats: ['YYYY-MM-DD', 'YYYY-MM-DD h:m:s a', 'YYYY-MM-DD h:m a', 'YYYY-MM-DD H:m:s', 'YYYY-MM-DD H:m'], - getInitialState: function() { return { - dateValue: this.props.value ? this.moment(this.props.value).format(this.dateInputFormat) : '', - timeValue: this.props.value ? this.moment(this.props.value).format(this.timeInputFormat) : '' + dateValue: this.props.value ? this.moment(this.props.value).format(this.props.dateFormat) : '', + timeValue: this.props.value ? this.moment(this.props.value).format(this.props.timeFormat) : '' }; }, getDefaultProps: function() { - return { - formatString: 'Do MMM YYYY, h:mm:ss a' + return { + formatString: 'YYYY-MM-DD, h:mm a' }; }, @@ -38,18 +31,18 @@ module.exports = Field.create({ // TODO: Move isValid() so we can share with server-side code isValid: function(value) { - return moment(value, this.parseFormats).isValid(); + return moment(value, this.props.formatString).isValid(); }, // TODO: Move format() so we can share with server-side code format: function(value, format) { - format = format || this.dateInputFormat + ' ' + this.timeInputFormat; + format = format || this.props.dateFormat + ' ' + this.props.timeFormat; return value ? this.moment(value).format(format) : ''; }, handleChange: function(dateValue, timeValue) { var value = dateValue + ' ' + timeValue; - var datetimeFormat = this.dateInputFormat + ' ' + this.timeInputFormat; + var datetimeFormat = this.props.dateFormat + ' ' + this.props.timeFormat; this.props.onChange({ path: this.props.path, value: this.isValid(value) ? moment(value, datetimeFormat).toISOString() : null @@ -67,8 +60,8 @@ module.exports = Field.create({ }, setNow: function() { - var dateValue = moment().format(this.dateInputFormat); - var timeValue = moment().format(this.timeInputFormat); + var dateValue = moment().format(this.props.dateFormat); + var timeValue = moment().format(this.props.timeFormat); this.setState({ dateValue: dateValue, timeValue: timeValue @@ -82,8 +75,8 @@ module.exports = Field.create({ if (this.shouldRenderField()) { input = (
- - + +
); diff --git a/fields/types/datetime/DatetimeType.js b/fields/types/datetime/DatetimeType.js index 374307b7f5..5f057182f2 100644 --- a/fields/types/datetime/DatetimeType.js +++ b/fields/types/datetime/DatetimeType.js @@ -2,6 +2,7 @@ var moment = require('moment'); var DateType = require('../date/DateType'); var FieldType = require('../Type'); var util = require('util'); +var _ = require('underscore'); var parseFormats = ['YYYY-MM-DD', 'YYYY-MM-DD h:m:s a', 'YYYY-MM-DD h:m a', 'YYYY-MM-DD H:m:s', 'YYYY-MM-DD H:m']; @@ -14,10 +15,38 @@ function datetime(list, path, options) { this._nativeType = Date; this._underscoreMethods = ['format', 'moment', 'parse']; this._fixedSize = 'large'; - this._properties = ['formatString', 'isUTC']; + this._properties = ['formatString', 'dateFormat', 'timeFormat', 'datePlaceholder', 'timePlaceholder', 'isUTC']; this.typeDescription = 'date and time'; this.parseFormatString = options.parseFormat || parseFormats; - this.formatString = (options.format === false) ? false : (options.format || 'YYYY-MM-DD h:m:s a'); + this.formatString = (options.format === false) ? false : (options.format || 'YYYY-MM-DD h:mm a'); + // Create an array of moment time format characters to help find where the time portion of the format string beings + var timeOptions = ['h', 'H', 'm', 's', 'S']; + var timeIndex = -1; + + var that = this; + + if(this.formatString) { + // Loop through each moment time format character to determine which begins the time portion of format to segregate date from time + _.each(timeOptions, function(timeChar) { + var charIndex = that.formatString.indexOf(timeChar); + + if((charIndex !== -1 && charIndex < timeIndex) || (charIndex !== -1 && timeIndex === -1)) { + timeIndex = charIndex; + } + }); + + this.dateFormat = this.formatString.slice(0, timeIndex).trim(); + this.timeFormat = this.formatString.slice(timeIndex).trim(); + this.datePlaceholder = 'e.g. ' + moment().format(this.dateFormat); + this.timePlaceholder = 'e.g. ' + moment().format(this.timeFormat); + + } else { + this.dateFormat = ''; + this.timeFormat = ''; + this.datePlaceholder = ''; + this.timePlaceholder = ''; + } + this.isUTC = options.utc || false; if (this.formatString && 'string' !== typeof this.formatString) { throw new Error('FieldType.DateTime: options.format must be a string.'); @@ -71,7 +100,7 @@ datetime.prototype.updateItem = function(item, data) { return; } var m = this.isUTC ? moment.utc : moment; - var newValue = m(this.getInputFromData(data), parseFormats); + var newValue = m(this.getInputFromData(data), this.formatString); if (newValue.isValid()) { if (!item.get(this.path) || !newValue.isSame(item.get(this.path))) { item.set(this.path, newValue.toDate()); From 610cedd46ce24dd7f7607d5469477504c625cce1 Mon Sep 17 00:00:00 2001 From: Jared Collier Date: Sat, 11 Jun 2016 23:39:42 -0400 Subject: [PATCH 2/2] #3030 | fix Date unit tests - Update date unit test to match the new format in Date and Datetime. --- fields/types/date/test/server.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fields/types/date/test/server.js b/fields/types/date/test/server.js index 6069249ae1..fef16e93e6 100644 --- a/fields/types/date/test/server.js +++ b/fields/types/date/test/server.js @@ -13,13 +13,13 @@ exports.testFieldType = function(List) { it('should parse without error via underscore date', function() { testItem._.date.parse('20131204', 'YYYYMMDD'); }); - + it('should be the date we expect', function() { testItem.date = new Date(2013, 11, 4); - demand(testItem._.date.format()).to.equal('4th Dec 2013'); + demand(testItem._.date.format()).to.equal('2013-12-04'); demand(testItem._.date.format('YYYYMMDD')).to.equal('20131204'); }); - + it('should be a moment object', function() { testItem.date = new Date(2013, 11, 4); demand(testItem._.date.moment()._isAMomentObject);