keystone
Version:
Web Application Framework and Admin GUI / Content Management System built on Express.js and Mongoose
158 lines (139 loc) • 4.41 kB
JavaScript
import DateInput from '../../components/DateInput';
import Field from '../Field';
import moment from 'moment';
import React from 'react';
import {
Button,
FormField,
FormInput,
FormNote,
InlineGroup as Group,
InlineGroupSection as Section,
} from '../../../admin/client/App/elemental';
module.exports = Field.create({
displayName: 'DatetimeField',
statics: {
type: 'Datetime',
},
focusTargetRef: 'dateInput',
// default input formats
dateInputFormat: 'YYYY-MM-DD',
timeInputFormat: 'h:mm:ss a',
tzOffsetInputFormat: 'Z',
// 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 () {
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),
tzOffsetValue: this.props.value ? this.moment(this.props.value).format(this.tzOffsetInputFormat) : this.moment().format(this.tzOffsetInputFormat),
};
},
getDefaultProps () {
return {
formatString: 'Do MMM YYYY, h:mm:ss a',
};
},
moment () {
if (this.props.isUTC) return moment.utc.apply(moment, arguments);
else return moment.apply(undefined, arguments);
},
// TODO: Move isValid() so we can share with server-side code
isValid (value) {
return this.moment(value, this.parseFormats).isValid();
},
// TODO: Move format() so we can share with server-side code
format (value, format) {
format = format || this.dateInputFormat + ' ' + this.timeInputFormat;
return value ? this.moment(value).format(format) : '';
},
handleChange (dateValue, timeValue, tzOffsetValue) {
var value = dateValue + ' ' + timeValue;
var datetimeFormat = this.dateInputFormat + ' ' + this.timeInputFormat;
// if the change included a timezone offset, include that in the calculation (so NOW works correctly during DST changes)
if (typeof tzOffsetValue !== 'undefined') {
value += ' ' + tzOffsetValue;
datetimeFormat += ' ' + this.tzOffsetInputFormat;
}
// if not, calculate the timezone offset based on the date (respect different DST values)
else {
this.setState({ tzOffsetValue: this.moment(value, datetimeFormat).format(this.tzOffsetInputFormat) });
}
this.props.onChange({
path: this.props.path,
value: this.isValid(value) ? this.moment(value, datetimeFormat).toISOString() : null,
});
},
dateChanged ({ value }) {
this.setState({ dateValue: value });
this.handleChange(value, this.state.timeValue);
},
timeChanged (evt) {
this.setState({ timeValue: evt.target.value });
this.handleChange(this.state.dateValue, evt.target.value);
},
setNow () {
var dateValue = this.moment().format(this.dateInputFormat);
var timeValue = this.moment().format(this.timeInputFormat);
var tzOffsetValue = this.moment().format(this.tzOffsetInputFormat);
this.setState({
dateValue: dateValue,
timeValue: timeValue,
tzOffsetValue: tzOffsetValue,
});
this.handleChange(dateValue, timeValue, tzOffsetValue);
},
renderNote () {
if (!this.props.note) return null;
return <FormNote note={this.props.note} />;
},
renderUI () {
var input;
if (this.shouldRenderField()) {
input = (
<div>
<Group>
<Section grow>
<DateInput
format={this.dateInputFormat}
name={this.getInputName(this.props.paths.date)}
onChange={this.dateChanged}
ref="dateInput"
value={this.state.dateValue}
/>
</Section>
<Section grow>
<FormInput
autoComplete="off"
name={this.getInputName(this.props.paths.time)}
onChange={this.timeChanged}
placeholder="HH:MM:SS am/pm"
value={this.state.timeValue}
/>
</Section>
<Section>
<Button onClick={this.setNow}>Now</Button>
</Section>
</Group>
<input
name={this.getInputName(this.props.paths.tzOffset)}
type="hidden"
value={this.state.tzOffsetValue}
/>
</div>
);
} else {
input = (
<FormInput noedit>
{this.format(this.props.value, this.props.formatString)}
</FormInput>
);
}
return (
<FormField label={this.props.label} className="field-type-datetime" htmlFor={this.getInputName(this.props.path)}>
{input}
{this.renderNote()}
</FormField>
);
},
});