diff --git a/README.md b/README.md index b78a8bd..c9d20b8 100755 --- a/README.md +++ b/README.md @@ -126,10 +126,10 @@ DatePicker component. Renders as a [React-Bootstrap InputGroup](https://react-bo * **Callback Arguments:** * `event` - Blur event. * **Type:** `Event` - * `dateFormat` - Date format. Any combination of DD, MM, YYYY and separator. + * `dateFormat` - Date format. Any combination of D/DD, M/MM, YYYY and separator. * **Optional** * **Type:** `string` - * **Examples:** `"MM/DD/YYYY"`, `"YYYY/MM/DD"`, `"MM-DD-YYYY"`, or `"DD MM YYYY"` + * **Examples:** `"MM/DD/YYYY"`, `"YYYY/M/D"`, `"MM-DD-YYYY"`, or `"DD MM YYYY"` * `clearButtonElement` - Character or component to use for the clear button. * **Optional** * **Type:** `string` or `ReactClass` diff --git a/example/app.jsx b/example/app.jsx index 36e0d9e..3e322c5 100755 --- a/example/app.jsx +++ b/example/app.jsx @@ -147,8 +147,8 @@ const App = React.createClass({ - YYYY/MM/DD - + YYYY/M/D + Help diff --git a/lib/index.js b/lib/index.js index 04f36fc..4f32802 100644 --- a/lib/index.js +++ b/lib/index.js @@ -14,9 +14,15 @@ var _reactDom2 = _interopRequireDefault(_reactDom); var _reactBootstrap = require('react-bootstrap'); +var _moment = require('moment'); + +var _moment2 = _interopRequireDefault(_moment); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var instanceCount = 0; // See http://jszen.blogspot.com/2007/03/how-to-build-simple-calendar-with.html for calendar logic. +// See http://jszen.blogspot.com/2007/03/how-to-build-simple-calendar-with.html for calendar logic. + +var instanceCount = 0; var CalendarHeader = _react2.default.createClass({ displayName: 'DatePickerHeader', @@ -30,14 +36,12 @@ var CalendarHeader = _react2.default.createClass({ }, handleClickPrevious: function handleClickPrevious() { - var newDisplayDate = new Date(this.props.displayDate); - newDisplayDate.setMonth(newDisplayDate.getMonth() - 1); - this.props.onChange(newDisplayDate); + var date = this.props.displayDate; + this.props.onChange(date.month(date.month() - 1)); }, handleClickNext: function handleClickNext() { - var newDisplayDate = new Date(this.props.displayDate); - newDisplayDate.setMonth(newDisplayDate.getMonth() + 1); - this.props.onChange(newDisplayDate); + var date = this.props.displayDate; + this.props.onChange(date.month(date.month() + 1)); }, render: function render() { return _react2.default.createElement( @@ -51,9 +55,9 @@ var CalendarHeader = _react2.default.createClass({ _react2.default.createElement( 'span', null, - this.props.monthLabels[this.props.displayDate.getMonth()], + this.props.monthLabels[this.props.displayDate.month()], ' ', - this.props.displayDate.getFullYear() + this.props.displayDate.year() ), _react2.default.createElement( 'div', @@ -81,36 +85,27 @@ var Calendar = _react2.default.createClass({ }, handleClick: function handleClick(day) { - var newSelectedDate = new Date(this.props.displayDate); - newSelectedDate.setHours(12); - newSelectedDate.setMinutes(0); - newSelectedDate.setSeconds(0); - newSelectedDate.setMilliseconds(0); - newSelectedDate.setDate(day); + var newSelectedDate = (0, _moment2.default)(this.props.displayDate).date(day); this.props.onChange(newSelectedDate); }, handleClickToday: function handleClickToday() { - var newSelectedDate = new Date(); - newSelectedDate.setHours(12); - newSelectedDate.setMinutes(0); - newSelectedDate.setSeconds(0); - newSelectedDate.setMilliseconds(0); + var newSelectedDate = (0, _moment2.default)().startOf('day').hour(12); this.props.onChange(newSelectedDate); }, render: function render() { var _this = this; - var currentDate = new Date(); - var currentDay = currentDate.getDate(); - var currentMonth = currentDate.getMonth(); - var currentYear = currentDate.getFullYear(); - var selectedDay = this.props.selectedDate ? this.props.selectedDate.getDate() : null; - var selectedMonth = this.props.selectedDate ? this.props.selectedDate.getMonth() : null; - var selectedYear = this.props.selectedDate ? this.props.selectedDate.getFullYear() : null; - var year = this.props.displayDate.getFullYear(); - var month = this.props.displayDate.getMonth(); - var firstDay = new Date(year, month, 1); - var startingDay = this.props.weekStartsOnMonday ? firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1 : firstDay.getDay(); + var currentDate = (0, _moment2.default)(); + var currentDay = currentDate.date(); + var currentMonth = currentDate.month(); + var currentYear = currentDate.year(); + var selectedDay = this.props.selectedDate ? this.props.selectedDate.date() : null; + var selectedMonth = this.props.selectedDate ? this.props.selectedDate.month() : null; + var selectedYear = this.props.selectedDate ? this.props.selectedDate.year() : null; + var year = this.props.displayDate.year(); + var month = this.props.displayDate.month(); + var firstDay = (0, _moment2.default)([year, month, 1]); + var startingDay = this.props.weekStartsOnMonday ? firstDay.day() === 0 ? 6 : firstDay.day() - 1 : firstDay.day(); var monthLength = daysInMonth[month]; if (month == 1) { @@ -282,17 +277,12 @@ exports.default = _react2.default.createClass({ return state; }, makeDateValues: function makeDateValues(isoString) { - var displayDate = void 0; - var selectedDate = isoString ? new Date(isoString.slice(0, 10) + 'T12:00:00.000Z') : null; + var selectedDate = isoString ? (0, _moment2.default)(isoString.slice(0, 10) + 'T12:00:00.000Z') : null; var inputValue = isoString ? this.makeInputValueString(selectedDate) : null; - if (selectedDate) { - displayDate = new Date(selectedDate); - } else { - displayDate = new Date(new Date().toISOString().slice(0, 10) + 'T12:00:00.000Z'); - } + var displayDate = selectedDate || (0, _moment2.default)(); return { - value: selectedDate ? selectedDate.toISOString() : null, + value: selectedDate ? selectedDate.format() : null, displayDate: displayDate, selectedDate: selectedDate, inputValue: inputValue @@ -372,22 +362,11 @@ exports.default = _react2.default.createClass({ return this.state.displayDate ? this.state.inputValue : null; }, makeInputValueString: function makeInputValueString(date) { - var month = date.getMonth() + 1; - var day = date.getDate(); - - //this method is executed during intialState setup... handle a missing state properly - var separator = this.state ? this.state.separator : this.props.dateFormat.match(/[^A-Z]/)[0]; - if (this.props.dateFormat.match(/MM.DD.YYYY/)) { - return (month > 9 ? month : '0' + month) + separator + (day > 9 ? day : '0' + day) + separator + date.getFullYear(); - } else if (this.props.dateFormat.match(/DD.MM.YYYY/)) { - return (day > 9 ? day : '0' + day) + separator + (month > 9 ? month : '0' + month) + separator + date.getFullYear(); - } else { - return date.getFullYear() + separator + (month > 9 ? month : '0' + month) + separator + (day > 9 ? day : '0' + day); - } + return date.format(this.props.dateFormat); }, handleBadInput: function handleBadInput(originalValue) { var parts = originalValue.replace(new RegExp('[^0-9' + this.state.separator + ']'), '').split(this.state.separator); - if (this.props.dateFormat.match(/MM.DD.YYYY/) || this.props.dateFormat.match(/DD.MM.YYYY/)) { + if (this.props.dateFormat.match(/MM?.DD?.YYYY/) || this.props.dateFormat.match(/DD?.MM?.YYYY/)) { if (parts[0] && parts[0].length > 2) { parts[1] = parts[0].slice(2) + (parts[1] || ''); parts[0] = parts[0].slice(0, 2); @@ -421,58 +400,19 @@ exports.default = _react2.default.createClass({ var originalValue = _reactDom2.default.findDOMNode(this.refs.input).value; var inputValue = originalValue.replace(/(-|\/\/)/g, this.state.separator).slice(0, 10); - var month = void 0, - day = void 0, - year = void 0; - if (this.props.dateFormat.match(/MM.DD.YYYY/)) { - if (!inputValue.match(/[0-1][0-9].[0-3][0-9].[1-2][0-9][0-9][0-9]/)) { - return this.handleBadInput(originalValue); - } - - month = inputValue.slice(0, 2).replace(/[^0-9]/g, ''); - day = inputValue.slice(3, 5).replace(/[^0-9]/g, ''); - year = inputValue.slice(6, 10).replace(/[^0-9]/g, ''); - } else if (this.props.dateFormat.match(/DD.MM.YYYY/)) { - if (!inputValue.match(/[0-3][0-9].[0-1][0-9].[1-2][0-9][0-9][0-9]/)) { - return this.handleBadInput(originalValue); - } - - day = inputValue.slice(0, 2).replace(/[^0-9]/g, ''); - month = inputValue.slice(3, 5).replace(/[^0-9]/g, ''); - year = inputValue.slice(6, 10).replace(/[^0-9]/g, ''); - } else { - if (!inputValue.match(/[1-2][0-9][0-9][0-9].[0-1][0-9].[0-3][0-9]/)) { - return this.handleBadInput(originalValue); - } - - year = inputValue.slice(0, 4).replace(/[^0-9]/g, ''); - month = inputValue.slice(5, 7).replace(/[^0-9]/g, ''); - day = inputValue.slice(8, 10).replace(/[^0-9]/g, ''); - } - - var monthInteger = parseInt(month, 10); - var dayInteger = parseInt(day, 10); - var yearInteger = parseInt(year, 10); - if (monthInteger > 12 || dayInteger > 31) { + var selectedDate = (0, _moment2.default)(inputValue, this.props.dateFormat, true); + if (!selectedDate.isValid()) { return this.handleBadInput(originalValue); } - - if (!isNaN(monthInteger) && !isNaN(dayInteger) && !isNaN(yearInteger) && monthInteger <= 12 && dayInteger <= 31 && yearInteger > 999) { - var selectedDate = new Date(yearInteger, monthInteger - 1, dayInteger, 12, 0, 0, 0); - this.setState({ - selectedDate: selectedDate, - displayDate: selectedDate, - value: selectedDate.toISOString() - }); - - if (this.props.onChange) { - this.props.onChange(selectedDate.toISOString(), inputValue); - } - } - this.setState({ - inputValue: inputValue + displayDate: selectedDate, + inputValue: inputValue, + selectedDate: selectedDate, + value: selectedDate.format() }); + if (this.props.onChange) { + this.props.onChange(selectedDate.format(), inputValue); + } }, onChangeMonth: function onChangeMonth(newDisplayDate) { this.setState({ diff --git a/package.json b/package.json index 0637665..83c7cf5 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ "directories": { "test": "test" }, + "dependencies": { + "moment": "^2.17.0" + }, "peerDependencies": { "react": ">=0.14.0", "react-bootstrap": "^0.30.2" diff --git a/src/index.jsx b/src/index.jsx index 540f1a8..408fe31 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -9,6 +9,7 @@ import { Overlay, Popover, } from 'react-bootstrap'; +import moment from 'moment'; let instanceCount = 0; @@ -30,21 +31,19 @@ const CalendarHeader = React.createClass({ }, handleClickPrevious() { - const newDisplayDate = new Date(this.props.displayDate); - newDisplayDate.setMonth(newDisplayDate.getMonth() - 1); - this.props.onChange(newDisplayDate); + const date = this.props.displayDate; + this.props.onChange(date.month(date.month() - 1)); }, handleClickNext() { - const newDisplayDate = new Date(this.props.displayDate); - newDisplayDate.setMonth(newDisplayDate.getMonth() + 1); - this.props.onChange(newDisplayDate); + const date = this.props.displayDate; + this.props.onChange(date.month(date.month() + 1)); }, render() { return
{this.props.previousButtonElement}
- {this.props.monthLabels[this.props.displayDate.getMonth()]} {this.props.displayDate.getFullYear()} + {this.props.monthLabels[this.props.displayDate.month()]} {this.props.displayDate.year()}
{this.props.nextButtonElement}
; } @@ -67,36 +66,27 @@ const Calendar = React.createClass({ }, handleClick(day) { - const newSelectedDate = new Date(this.props.displayDate); - newSelectedDate.setHours(12); - newSelectedDate.setMinutes(0); - newSelectedDate.setSeconds(0); - newSelectedDate.setMilliseconds(0); - newSelectedDate.setDate(day); + const newSelectedDate = moment(this.props.displayDate).date(day); this.props.onChange(newSelectedDate); }, handleClickToday() { - const newSelectedDate = new Date(); - newSelectedDate.setHours(12); - newSelectedDate.setMinutes(0); - newSelectedDate.setSeconds(0); - newSelectedDate.setMilliseconds(0); + const newSelectedDate = moment().startOf('day').hour(12); this.props.onChange(newSelectedDate); }, render() { - const currentDate = new Date(); - const currentDay = currentDate.getDate(); - const currentMonth = currentDate.getMonth(); - const currentYear = currentDate.getFullYear(); - const selectedDay = this.props.selectedDate ? this.props.selectedDate.getDate() : null; - const selectedMonth = this.props.selectedDate ? this.props.selectedDate.getMonth() : null; - const selectedYear = this.props.selectedDate ? this.props.selectedDate.getFullYear() : null; - const year = this.props.displayDate.getFullYear(); - const month = this.props.displayDate.getMonth(); - const firstDay = new Date(year, month, 1); - const startingDay = this.props.weekStartsOnMonday ? (firstDay.getDay() === 0 ? 6 : firstDay.getDay() - 1) : firstDay.getDay(); + const currentDate = moment(); + const currentDay = currentDate.date(); + const currentMonth = currentDate.month(); + const currentYear = currentDate.year(); + const selectedDay = this.props.selectedDate ? this.props.selectedDate.date() : null; + const selectedMonth = this.props.selectedDate ? this.props.selectedDate.month() : null; + const selectedYear = this.props.selectedDate ? this.props.selectedDate.year() : null; + const year = this.props.displayDate.year(); + const month = this.props.displayDate.month(); + const firstDay = moment([year, month, 1]); + const startingDay = this.props.weekStartsOnMonday ? (firstDay.day() === 0 ? 6 : firstDay.day() - 1) : firstDay.day(); let monthLength = daysInMonth[month]; if (month == 1) { @@ -253,17 +243,12 @@ export default React.createClass({ }, makeDateValues(isoString) { - let displayDate; - const selectedDate = isoString ? new Date(`${isoString.slice(0,10)}T12:00:00.000Z`) : null; + const selectedDate = isoString ? moment(`${isoString.slice(0,10)}T12:00:00.000Z`) : null; const inputValue = isoString ? this.makeInputValueString(selectedDate) : null; - if (selectedDate) { - displayDate = new Date(selectedDate); - } else { - displayDate = new Date(`${(new Date().toISOString().slice(0,10))}T12:00:00.000Z`); - } + const displayDate = selectedDate || moment(); return { - value: selectedDate ? selectedDate.toISOString() : null, + value: selectedDate ? selectedDate.format() : null, displayDate: displayDate, selectedDate: selectedDate, inputValue: inputValue @@ -350,25 +335,12 @@ export default React.createClass({ }, makeInputValueString(date) { - const month = date.getMonth() + 1; - const day = date.getDate(); - - //this method is executed during intialState setup... handle a missing state properly - const separator = (this.state ? this.state.separator : this.props.dateFormat.match(/[^A-Z]/)[0]); - if (this.props.dateFormat.match(/MM.DD.YYYY/)) { - return (month > 9 ? month : `0${month}`) + separator + (day > 9 ? day : `0${day}`) + separator + date.getFullYear(); - } - else if (this.props.dateFormat.match(/DD.MM.YYYY/)) { - return (day > 9 ? day : `0${day}`) + separator + (month > 9 ? month : `0${month}`) + separator + date.getFullYear(); - } - else { - return date.getFullYear() + separator + (month > 9 ? month : `0${month}`) + separator + (day > 9 ? day : `0${day}`); - } + return date.format(this.props.dateFormat) }, handleBadInput(originalValue) { const parts = originalValue.replace(new RegExp(`[^0-9${this.state.separator}]`), '').split(this.state.separator); - if (this.props.dateFormat.match(/MM.DD.YYYY/) || this.props.dateFormat.match(/DD.MM.YYYY/)) { + if (this.props.dateFormat.match(/MM?.DD?.YYYY/) || this.props.dateFormat.match(/DD?.MM?.YYYY/)) { if (parts[0] && parts[0].length > 2) { parts[1] = parts[0].slice(2) + (parts[1] || ''); parts[0] = parts[0].slice(0, 2); @@ -403,56 +375,19 @@ export default React.createClass({ const originalValue = ReactDOM.findDOMNode(this.refs.input).value; const inputValue = originalValue.replace(/(-|\/\/)/g, this.state.separator).slice(0,10); - let month, day, year; - if (this.props.dateFormat.match(/MM.DD.YYYY/)) { - if (!inputValue.match(/[0-1][0-9].[0-3][0-9].[1-2][0-9][0-9][0-9]/)) { - return this.handleBadInput(originalValue); - } - - month = inputValue.slice(0,2).replace(/[^0-9]/g, ''); - day = inputValue.slice(3,5).replace(/[^0-9]/g, ''); - year = inputValue.slice(6,10).replace(/[^0-9]/g, ''); - } else if (this.props.dateFormat.match(/DD.MM.YYYY/)) { - if (!inputValue.match(/[0-3][0-9].[0-1][0-9].[1-2][0-9][0-9][0-9]/)) { - return this.handleBadInput(originalValue); - } - - day = inputValue.slice(0,2).replace(/[^0-9]/g, ''); - month = inputValue.slice(3,5).replace(/[^0-9]/g, ''); - year = inputValue.slice(6,10).replace(/[^0-9]/g, ''); - } else { - if (!inputValue.match(/[1-2][0-9][0-9][0-9].[0-1][0-9].[0-3][0-9]/)) { - return this.handleBadInput(originalValue); - } - - year = inputValue.slice(0,4).replace(/[^0-9]/g, ''); - month = inputValue.slice(5,7).replace(/[^0-9]/g, ''); - day = inputValue.slice(8,10).replace(/[^0-9]/g, ''); - } - - const monthInteger = parseInt(month, 10); - const dayInteger = parseInt(day, 10); - const yearInteger = parseInt(year, 10); - if (monthInteger > 12 || dayInteger > 31) { + const selectedDate = moment(inputValue, this.props.dateFormat, true); + if (!selectedDate.isValid()) { return this.handleBadInput(originalValue); } - - if (!isNaN(monthInteger) && !isNaN(dayInteger) && !isNaN(yearInteger) && monthInteger <= 12 && dayInteger <= 31 && yearInteger > 999) { - const selectedDate = new Date(yearInteger, monthInteger - 1, dayInteger, 12, 0, 0, 0); - this.setState({ - selectedDate: selectedDate, - displayDate: selectedDate, - value: selectedDate.toISOString() - }); - - if (this.props.onChange) { - this.props.onChange(selectedDate.toISOString(), inputValue); - } - } - this.setState({ - inputValue: inputValue + displayDate: selectedDate, + inputValue: inputValue, + selectedDate: selectedDate, + value: selectedDate.format() }); + if (this.props.onChange) { + this.props.onChange(selectedDate.format(), inputValue); + } }, onChangeMonth(newDisplayDate) {