diff --git a/README.md b/README.md index ed40ccf..36d0815 100755 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Please [★ on GitHub](https://github.com/pushtell/react-bootstrap-date-picker)! ## Installation -`react-bootstrap-date-picker` is compatible with React 0.14.x. +`react-bootstrap-date-picker` is compatible with React 0.14.x and 0.15.x. ```bash npm install react-bootstrap-date-picker @@ -71,6 +71,10 @@ DatePicker component. Renders as a [react-bootstrap input element](https://react [Input element](https://react-bootstrap.github.io/components.html#forms) properties are passed through to the input element. * **Properties:** + * `dateFormat` - Date format. `"MM/DD/YYYY"` or `"DD/MM/YYYY"` or `"YYYY/MM/DD"` + * **Optional** + * **Type:** `string` + * **Example:** `"MM/DD/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 1e2fe33..284a77d 100755 --- a/example/app.jsx +++ b/example/app.jsx @@ -7,14 +7,12 @@ import NavBar from "react-bootstrap/lib/NavBar"; import Nav from "react-bootstrap/lib/Nav"; import NavItem from "react-bootstrap/lib/NavItem"; import DatePicker from "../src/index.jsx"; -import LinkedStateMixin from 'react-addons-linked-state-mixin'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; const spanishDayLabels = ['Dom', 'Lu', 'Ma', 'Mx', 'Ju', 'Vi', 'Sab']; const spanishMonthLabels = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']; const App = React.createClass({ - mixins: [LinkedStateMixin], getInitialState() { return { date: new Date().toISOString(), @@ -59,47 +57,57 @@ const App = React.createClass({ -

LinkState

+

Blur and Focus Events

- + {console.log("Focus")}} onBlur={() => {console.log("Blur")}}/>
-

Blur and Focus Events

+

Styles

- +
- {console.log("Focus")}} onBlur={() => {console.log("Blur")}}/> + + + + +
+ + + + +
+
-

Styles

+

Date Format

- +
- +
- +
diff --git a/lib/index.js b/lib/index.js index 1bfeab5..b9acca9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,11 +1,11 @@ 'use strict'; -var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // See http://jszen.blogspot.com/2007/03/how-to-build-simple-calendar-with.html for calendar logic. - Object.defineProperty(exports, "__esModule", { value: true }); +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // See http://jszen.blogspot.com/2007/03/how-to-build-simple-calendar-with.html for calendar logic. + var _react = require('react'); var _react2 = _interopRequireDefault(_react); @@ -28,19 +28,12 @@ var _OverlayTrigger2 = _interopRequireDefault(_OverlayTrigger); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var makeInputValueString = function makeInputValueString(date) { - var month = date.getMonth() + 1; - var day = date.getDate(); - return (month > 9 ? month : "0" + month) + "/" + (day > 9 ? day : "0" + day) + "/" + date.getFullYear(); -}; - var CalendarHeader = _react2.default.createClass({ displayName: "DatePickerHeader", propTypes: { displayDate: _react2.default.PropTypes.object.isRequired, onChange: _react2.default.PropTypes.func.isRequired, monthLabels: _react2.default.PropTypes.array.isRequired, - onDateClick: _react2.default.PropTypes.func.isRequired, previousButtonElement: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]).isRequired, nextButtonElement: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]).isRequired }, @@ -65,7 +58,7 @@ var CalendarHeader = _react2.default.createClass({ ), _react2.default.createElement( 'span', - { onClick: this.props.onDateClick }, + null, this.props.monthLabels[this.props.displayDate.getMonth()], ' ', this.props.displayDate.getFullYear() @@ -182,35 +175,40 @@ exports.default = _react2.default.createClass({ propTypes: { value: _react2.default.PropTypes.string, cellPadding: _react2.default.PropTypes.string, + placeholder: _react2.default.PropTypes.string, dayLabels: _react2.default.PropTypes.array, monthLabels: _react2.default.PropTypes.array, onChange: _react2.default.PropTypes.func, clearButtonElement: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]), previousButtonElement: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]), nextButtonElement: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.object]), - calendarPlacement: _react2.default.PropTypes.string + calendarPlacement: _react2.default.PropTypes.string, + dateFormat: _react2.default.PropTypes.oneOf(['MM/DD/YYYY', 'DD/MM/YYYY', 'YYYY/MM/DD']) }, getDefaultProps: function getDefaultProps() { + var language = (window.navigator.userLanguage || window.navigator.language || '').toLowerCase(); + var dateFormat = !language || language === "en-us" ? 'MM/DD/YYYY' : 'DD/MM/YYYY'; return { cellPadding: "5px", dayLabels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], monthLabels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - placeholder: "MM/DD/YYYY", clearButtonElement: "×", previousButtonElement: "<", nextButtonElement: ">", - calendarPlacement: "bottom" + calendarPlacement: "bottom", + dateFormat: dateFormat }; }, getInitialState: function getInitialState() { - var state = this.makeDateValues(this.props.value ? this.props.value : this.props.valueLink ? this.props.valueLink.value : null); + var state = this.makeDateValues(this.props.value); state.focused = false; + state.placeholder = this.props.placeholder || this.props.dateFormat; return state; }, makeDateValues: function makeDateValues(isoString) { - var displayDate = undefined; + var displayDate = void 0; var selectedDate = isoString ? new Date(isoString) : null; - var inputValue = isoString ? makeInputValueString(selectedDate) : null; + var inputValue = isoString ? this.makeInputValueString(selectedDate) : null; if (selectedDate) { displayDate = new Date(selectedDate); } else { @@ -232,9 +230,6 @@ exports.default = _react2.default.createClass({ if (this.props.onChange) { this.props.onChange(null); } - if (this.props.valueLink && this.props.valueLink.requestChange) { - this.props.valueLink.requestChange(null); - } }, handleHide: function handleHide(e) { if (document.activeElement === this.refs.input.getInputDOMNode()) { @@ -269,24 +264,52 @@ exports.default = _react2.default.createClass({ this.props.onBlur(e); } }, - handleHeaderDateClick: function handleHeaderDateClick(e) {}, getValue: function getValue() { return this.state.selectedDate ? this.state.selectedDate.toISOString() : null; }, + makeInputValueString: function makeInputValueString(date) { + var month = date.getMonth() + 1; + var day = date.getDate(); + if (this.props.dateFormat === "MM/DD/YYYY") { + return (month > 9 ? month : "0" + month) + "/" + (day > 9 ? day : "0" + day) + "/" + date.getFullYear(); + } else if (this.props.dateFormat === "DD/MM/YYYY") { + return (day > 9 ? day : "0" + day) + "/" + (month > 9 ? month : "0" + month) + "/" + date.getFullYear(); + } else { + return date.getFullYear() + "/" + (month > 9 ? month : "0" + month) + "/" + (day > 9 ? day : "0" + day); + } + }, handleInputChange: function handleInputChange(e) { var inputValue = this.refs.input.getValue(); inputValue = inputValue.replace(/(-|\/\/)/g, '/'); - var month = inputValue.slice(0, 2).replace(/[^0-9]/g, ''); - var day = inputValue.slice(3, 5).replace(/[^0-9]/g, ''); - var year = inputValue.slice(6, 10).replace(/[^0-9]/g, ''); + var month = void 0, + day = void 0, + year = void 0; + if (this.props.dateFormat === "MM/DD/YYYY") { + 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 === "DD/MM/YYYY") { + 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 { + 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 (!isNaN(monthInteger) && !isNaN(dayInteger) && !isNaN(yearInteger) && monthInteger <= 12 && dayInteger <= 31 && yearInteger > 999) { var selectedDate = new Date(); - selectedDate.setDate(dayInteger); - selectedDate.setMonth(monthInteger - 1); + selectedDate.setHours(12); + selectedDate.setMinutes(0); + selectedDate.setSeconds(0); + selectedDate.setMilliseconds(0); selectedDate.setYear(yearInteger); + selectedDate.setMonth(monthInteger - 1); + selectedDate.setDate(dayInteger); this.setState({ selectedDate: selectedDate, displayDate: selectedDate, @@ -295,19 +318,34 @@ exports.default = _react2.default.createClass({ if (this.props.onChange) { this.props.onChange(selectedDate.toISOString()); } - if (this.props.valueLink && this.props.valueLink.requestChange) { - this.props.valueLink.requestChange(selectedDate.toISOString()); - } } - inputValue = month + inputValue.slice(2, 3).replace(/[^\/]/g, '') + day + inputValue.slice(5, 6).replace(/[^\/]/g, '') + year; - if (this.state.inputValue && inputValue.length > this.state.inputValue.length) { - if (inputValue.length == 2) { - inputValue += "/"; + if (this.props.dateFormat === "MM/DD/YYYY") { + inputValue = month + inputValue.slice(2, 3).replace(/[^\/]/g, '') + day + inputValue.slice(5, 6).replace(/[^\/]/g, '') + year; + } else if (this.props.dateFormat === "DD/MM/YYYY") { + inputValue = day + inputValue.slice(2, 3).replace(/[^\/]/g, '') + month + inputValue.slice(5, 6).replace(/[^\/]/g, '') + year; + } else { + inputValue = year + inputValue.slice(4, 5).replace(/[^\/]/g, '') + month + inputValue.slice(7, 8).replace(/[^\/]/g, ''); + } + if (this.props.dateFormat === "YYYY/MM/DD") { + if (this.state.inputValue && inputValue.length > this.state.inputValue.length) { + if (inputValue.length == 4) { + inputValue += "/"; + } + if (inputValue.length == 7) { + inputValue += "/"; + } + inputValue = inputValue.slice(0, 10); } - if (inputValue.length == 5) { - inputValue += "/"; + } else { + if (this.state.inputValue && inputValue.length > this.state.inputValue.length) { + if (inputValue.length == 2) { + inputValue += "/"; + } + if (inputValue.length == 5) { + inputValue += "/"; + } + inputValue = inputValue.slice(0, 10); } - inputValue = inputValue.slice(0, 10); } this.setState({ inputValue: inputValue @@ -320,7 +358,7 @@ exports.default = _react2.default.createClass({ }, onChangeDate: function onChangeDate(newSelectedDate) { this.setState({ - inputValue: makeInputValueString(newSelectedDate), + inputValue: this.makeInputValueString(newSelectedDate), selectedDate: newSelectedDate, displayDate: newSelectedDate, value: newSelectedDate.toISOString() @@ -329,12 +367,9 @@ exports.default = _react2.default.createClass({ if (this.props.onChange) { this.props.onChange(newSelectedDate.toISOString()); } - if (this.props.valueLink && this.props.valueLink.requestChange) { - this.props.valueLink.requestChange(newSelectedDate.toISOString()); - } }, componentWillReceiveProps: function componentWillReceiveProps(newProps) { - var value = newProps.value ? newProps.value : newProps.valueLink ? newProps.valueLink.value : null; + var value = newProps.value; if (this.getValue() !== value) { this.setState(this.makeDateValues(value)); } @@ -344,9 +379,9 @@ exports.default = _react2.default.createClass({ previousButtonElement: this.props.previousButtonElement, nextButtonElement: this.props.nextButtonElement, displayDate: this.state.displayDate, - onDateClick: this.handleHeaderDateClick, onChange: this.onChangeMonth, - monthLabels: this.props.monthLabels }); + monthLabels: this.props.monthLabels, + dateFormat: this.props.dateFormat }); var popOver = _react2.default.createElement( _Popover2.default, { id: 'calendar', title: calendarHeader }, @@ -360,16 +395,15 @@ exports.default = _react2.default.createClass({ ); return _react2.default.createElement( 'div', - null, + { id: this.props.id ? this.props.id + "_container" : null }, _react2.default.createElement( _OverlayTrigger2.default, { ref: 'overlay', trigger: 'click', rootClose: true, placement: this.props.calendarPlacement, overlay: popOver, delayHide: 100 }, _react2.default.createElement(_Input2.default, _extends({}, this.props, { - value: this.state.inputValue, + value: this.state.inputValue || '', ref: 'input', type: 'text', - valueLink: null, - placeholder: this.state.focused ? "MM/DD/YYYY" : this.props.placeholder, + placeholder: this.state.focused ? this.props.dateFormat : this.state.placeholder, onFocus: this.handleFocus, onBlur: this.handleBlur, onChange: this.handleInputChange, @@ -378,7 +412,7 @@ exports.default = _react2.default.createClass({ id: null })) ), - _react2.default.createElement('input', { type: 'hidden', id: this.props.id, name: this.props.name, value: this.state.value }) + _react2.default.createElement('input', { type: 'hidden', id: this.props.id, name: this.props.name, value: this.state.value || '' }) ); } }); \ No newline at end of file diff --git a/package.json b/package.json old mode 100755 new mode 100644 index 6b0c001..21b238d --- a/package.json +++ b/package.json @@ -1,8 +1,17 @@ { "name": "react-bootstrap-date-picker", - "keywords": ["react", "react-component", "react-bootstrap", "bootstrap", "date picker", "calendar", "date", "picker"], + "keywords": [ + "react", + "react-component", + "react-bootstrap", + "bootstrap", + "date picker", + "calendar", + "date", + "picker" + ], "main": "lib/index.js", - "version": "1.1.0", + "version": "2.0.0", "description": "React-Bootstrap based date picker.", "directories": { "test": "test" @@ -12,39 +21,38 @@ "react-bootstrap": "^0.28.1" }, "devDependencies": { - "react": ">=0.14.0", - "react-bootstrap": "^0.28.1", - "react-dom": "^0.14.0", "assert": "*", - "co": "*", - "regenerator": "*", - "regenerator-loader": "*", - "babel":"^6.1.18", - "babel-cli":"6.2.0", + "babel": "^6.1.18", + "babel-cli": "^6.7.5", + "babel-loader": "^6.2.0", "babel-preset-es2015": "*", - "babel-preset-stage-1": "*", "babel-preset-react": "*", - "babel-loader": "^6.2.0", - "isparta-loader": "*", - "expose-loader": "*", - "transform-loader": "*", + "babel-preset-stage-1": "*", + "co": "*", "envify": "*", + "es6-promise": "*", + "expose-loader": "*", + "isparta-loader": "*", "karma": "*", + "karma-browserstack-launcher": "*", "karma-chrome-launcher": "*", + "karma-coverage": "*", + "karma-coveralls": "*", "karma-firefox-launcher": "*", "karma-mocha": "*", "karma-sourcemap-loader": "*", "karma-webpack": "*", - "karma-browserstack-launcher": "*", - "es6-promise": "*", - "node-uuid": "*", - "karma-coveralls": "*", - "karma-coverage": "*", + "mocha": "*", "mocha-babel": "*", + "node-uuid": "*", + "react": "^15.0.1", + "react-bootstrap": "^0.28.1", + "react-dom": "^15.0.1", + "regenerator": "*", + "regenerator-loader": "*", + "transform-loader": "*", "webpack": "*", - "mocha": "*", - "webpack-dev-server": "*", - "react-addons-linked-state-mixin": "*" + "webpack-dev-server": "*" }, "scripts": { "example": "./node_modules/webpack-dev-server/bin/webpack-dev-server.js --content-base example/ --config ./example/webpack.example.config.js", diff --git a/src/index.jsx b/src/index.jsx index 46b7c8e..a32a01e 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -6,19 +6,12 @@ import Popover from 'react-bootstrap/lib/Popover'; import Button from 'react-bootstrap/lib/Button'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; -const makeInputValueString = function(date) { - const month = date.getMonth() + 1; - const day = date.getDate(); - return (month > 9 ? month : "0" + month) + "/" + (day > 9 ? day : "0" + day) + "/" + date.getFullYear() -}; - const CalendarHeader = React.createClass({ displayName: "DatePickerHeader", propTypes: { displayDate: React.PropTypes.object.isRequired, onChange: React.PropTypes.func.isRequired, monthLabels: React.PropTypes.array.isRequired, - onDateClick: React.PropTypes.func.isRequired, previousButtonElement: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.object @@ -26,7 +19,7 @@ const CalendarHeader = React.createClass({ nextButtonElement: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.object - ]).isRequired, + ]).isRequired }, handleClickPrevious(){ const newDisplayDate = new Date(this.props.displayDate); @@ -41,7 +34,7 @@ const CalendarHeader = React.createClass({ render() { return
{this.props.previousButtonElement}
- {this.props.monthLabels[this.props.displayDate.getMonth()]} {this.props.displayDate.getFullYear()} + {this.props.monthLabels[this.props.displayDate.getMonth()]} {this.props.displayDate.getFullYear()}
{this.props.nextButtonElement}
; } @@ -126,6 +119,7 @@ export default React.createClass({ propTypes: { value: React.PropTypes.string, cellPadding: React.PropTypes.string, + placeholder: React.PropTypes.string, dayLabels: React.PropTypes.array, monthLabels: React.PropTypes.array, onChange: React.PropTypes.func, @@ -141,31 +135,35 @@ export default React.createClass({ React.PropTypes.string, React.PropTypes.object ]), - calendarPlacement: React.PropTypes.string + calendarPlacement: React.PropTypes.string, + dateFormat: React.PropTypes.oneOf(['MM/DD/YYYY', 'DD/MM/YYYY', 'YYYY/MM/DD']) }, getDefaultProps() { + const language = (window.navigator.userLanguage || window.navigator.language || '').toLowerCase(); + const dateFormat = !language || language === "en-us" ? 'MM/DD/YYYY' : 'DD/MM/YYYY'; return { cellPadding: "5px", dayLabels: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], monthLabels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - placeholder: "MM/DD/YYYY", clearButtonElement: "×", previousButtonElement: "<", nextButtonElement: ">", - calendarPlacement: "bottom" + calendarPlacement: "bottom", + dateFormat: dateFormat } }, getInitialState() { - var state = this.makeDateValues(this.props.value ? this.props.value : this.props.valueLink ? this.props.valueLink.value : null); + var state = this.makeDateValues(this.props.value); state.focused = false; + state.placeholder = this.props.placeholder || this.props.dateFormat; return state; }, makeDateValues(isoString) { let displayDate; const selectedDate = isoString ? new Date(isoString) : null; - const inputValue = isoString ? makeInputValueString(selectedDate) : null; + const inputValue = isoString ? this.makeInputValueString(selectedDate) : null; if(selectedDate) { displayDate = new Date(selectedDate); } else { @@ -187,9 +185,6 @@ export default React.createClass({ if(this.props.onChange) { this.props.onChange(null); } - if(this.props.valueLink && this.props.valueLink.requestChange) { - this.props.valueLink.requestChange(null); - } }, handleHide(e){ if(document.activeElement === this.refs.input.getInputDOMNode()) { @@ -223,27 +218,51 @@ export default React.createClass({ if(this.props.onBlur) { this.props.onBlur(e); } - }, - handleHeaderDateClick(e) { - }, getValue(){ return this.state.selectedDate ? this.state.selectedDate.toISOString() : null; }, + makeInputValueString(date) { + const month = date.getMonth() + 1; + const day = date.getDate(); + if(this.props.dateFormat === "MM/DD/YYYY") { + return (month > 9 ? month : "0" + month) + "/" + (day > 9 ? day : "0" + day) + "/" + date.getFullYear(); + } else if(this.props.dateFormat === "DD/MM/YYYY") { + return (day > 9 ? day : "0" + day) + "/" + (month > 9 ? month : "0" + month) + "/" + date.getFullYear(); + } else { + return date.getFullYear() + "/" + (month > 9 ? month : "0" + month) + "/" + (day > 9 ? day : "0" + day); + } + }, handleInputChange(e){ let inputValue = this.refs.input.getValue(); inputValue = inputValue.replace(/(-|\/\/)/g, '/'); - const month = inputValue.slice(0,2).replace(/[^0-9]/g, ''); - const day = inputValue.slice(3,5).replace(/[^0-9]/g, ''); - const year = inputValue.slice(6,10).replace(/[^0-9]/g, ''); + let month, day, year; + if(this.props.dateFormat === "MM/DD/YYYY") { + 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 === "DD/MM/YYYY") { + 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 { + 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(!isNaN(monthInteger) && !isNaN(dayInteger) && !isNaN(yearInteger) && monthInteger <= 12 && dayInteger <= 31 && yearInteger > 999) { const selectedDate = new Date(); - selectedDate.setDate(dayInteger); - selectedDate.setMonth(monthInteger - 1); + selectedDate.setHours(12); + selectedDate.setMinutes(0); + selectedDate.setSeconds(0); + selectedDate.setMilliseconds(0); selectedDate.setYear(yearInteger); + selectedDate.setMonth(monthInteger - 1); + selectedDate.setDate(dayInteger); this.setState({ selectedDate: selectedDate, displayDate: selectedDate, @@ -252,19 +271,34 @@ export default React.createClass({ if(this.props.onChange) { this.props.onChange(selectedDate.toISOString()); } - if(this.props.valueLink && this.props.valueLink.requestChange) { - this.props.valueLink.requestChange(selectedDate.toISOString()); - } } - inputValue = month + inputValue.slice(2,3).replace(/[^\/]/g, '') + day + inputValue.slice(5,6).replace(/[^\/]/g, '') + year; - if(this.state.inputValue && inputValue.length > this.state.inputValue.length) { - if(inputValue.length == 2) { - inputValue += "/"; + if(this.props.dateFormat === "MM/DD/YYYY") { + inputValue = month + inputValue.slice(2,3).replace(/[^\/]/g, '') + day + inputValue.slice(5,6).replace(/[^\/]/g, '') + year; + } else if(this.props.dateFormat === "DD/MM/YYYY") { + inputValue = day + inputValue.slice(2,3).replace(/[^\/]/g, '') + month + inputValue.slice(5,6).replace(/[^\/]/g, '') + year; + } else { + inputValue = year + inputValue.slice(4,5).replace(/[^\/]/g, '') + month + inputValue.slice(7,8).replace(/[^\/]/g, ''); + } + if(this.props.dateFormat === "YYYY/MM/DD") { + if(this.state.inputValue && inputValue.length > this.state.inputValue.length) { + if(inputValue.length == 4) { + inputValue += "/"; + } + if(inputValue.length == 7) { + inputValue += "/"; + } + inputValue = inputValue.slice(0, 10); } - if(inputValue.length == 5) { - inputValue += "/"; + } else { + if(this.state.inputValue && inputValue.length > this.state.inputValue.length) { + if(inputValue.length == 2) { + inputValue += "/"; + } + if(inputValue.length == 5) { + inputValue += "/"; + } + inputValue = inputValue.slice(0, 10); } - inputValue = inputValue.slice(0, 10); } this.setState({ inputValue: inputValue @@ -277,7 +311,7 @@ export default React.createClass({ }, onChangeDate(newSelectedDate) { this.setState({ - inputValue: makeInputValueString(newSelectedDate), + inputValue: this.makeInputValueString(newSelectedDate), selectedDate: newSelectedDate, displayDate: newSelectedDate, value: newSelectedDate.toISOString() @@ -286,12 +320,9 @@ export default React.createClass({ if(this.props.onChange) { this.props.onChange(newSelectedDate.toISOString()); } - if(this.props.valueLink && this.props.valueLink.requestChange) { - this.props.valueLink.requestChange(newSelectedDate.toISOString()); - } }, componentWillReceiveProps(newProps) { - const value = newProps.value ? newProps.value : newProps.valueLink ? newProps.valueLink.value : null; + const value = newProps.value; if(this.getValue() !== value) { this.setState(this.makeDateValues(value)); } @@ -301,23 +332,22 @@ export default React.createClass({ previousButtonElement={this.props.previousButtonElement} nextButtonElement={this.props.nextButtonElement} displayDate={this.state.displayDate} - onDateClick={this.handleHeaderDateClick} onChange={this.onChangeMonth} - monthLabels={this.props.monthLabels} />; + monthLabels={this.props.monthLabels} + dateFormat={this.props.dateFormat} />; const popOver = ; const buttonStyle = this.props.bsStyle === "error" ? "danger" : this.props.bsStyle; const clearButton = ; - return
+ return
- +
; } }); - diff --git a/test/core.test.jsx b/test/core.test.jsx index fae9c9a..5e1175e 100755 --- a/test/core.test.jsx +++ b/test/core.test.jsx @@ -6,7 +6,6 @@ import co from "co"; import ES6Promise from 'es6-promise'; import UUID from "node-uuid"; import TestUtils from 'react/lib/ReactTestUtils'; -import LinkedStateMixin from 'react-addons-linked-state-mixin'; ES6Promise.polyfill(); @@ -102,35 +101,24 @@ describe("Date Picker", function() { assert(typeof value === "string"); ReactDOM.unmountComponentAtNode(container); })); - it("should open the calendar, select a date, and update a linked value.", co.wrap(function *(){ + it("should open the calendar and render 29 days on a leap year.", co.wrap(function *(){ const id = UUID.v4(); + let value = "2016-02-15T00:00:00.000Z"; const App = React.createClass({ - mixins: [LinkedStateMixin], - getValue: function(){ - return this.state.value - }, - getInitialState: function(){ - return { - value: null - } - }, render: function(){ return
-
{this.state.value}
- +
; } }); yield new Promise(function(resolve, reject){ ReactDOM.render(, container, resolve); }); - const linkedValue = document.getElementById("linkedValue"); const inputElement = document.querySelector("input.form-control"); TestUtils.Simulate.click(inputElement); - const dayElement = document.querySelector("table tbody tr:nth-child(2) td"); - assert.equal(linkedValue.innerHTML, ''); + const dayElement = document.querySelector("table tbody tr:nth-child(5) td:nth-of-type(2)"); + assert.equal(dayElement.innerHTML, '29'); TestUtils.Simulate.click(dayElement); - assert.notEqual(linkedValue.innerHTML, ''); ReactDOM.unmountComponentAtNode(container); })); it("should update via a change handler when the input is changed.", co.wrap(function *(){ @@ -153,38 +141,7 @@ describe("Date Picker", function() { inputElement.value = "05/31/1980"; TestUtils.Simulate.change(inputElement); const date = new Date(value); - assert.equal(date.getMonth(), 4); - assert.equal(date.getDate(), 31); - assert.equal(date.getFullYear(), 1980); - ReactDOM.unmountComponentAtNode(container); - })); - it("should update a linked value when the input is changed.", co.wrap(function *(){ - const id = UUID.v4(); - const App = React.createClass({ - mixins: [LinkedStateMixin], - getValue: function(){ - return this.state.value - }, - getInitialState: function(){ - return { - value: null - } - }, - render: function(){ - return
-
{this.state.value}
- -
; - } - }); - yield new Promise(function(resolve, reject){ - ReactDOM.render(, container, resolve); - }); - const linkedValue = document.getElementById("linkedValue"); - const inputElement = document.querySelector("input.form-control"); - inputElement.value = "05/31/1980"; - TestUtils.Simulate.change(inputElement); - const date = new Date(linkedValue.innerHTML); + console.log(window.navigator.userLanguage); assert.equal(date.getMonth(), 4); assert.equal(date.getDate(), 31); assert.equal(date.getFullYear(), 1980); @@ -272,39 +229,6 @@ describe("Date Picker", function() { } ReactDOM.unmountComponentAtNode(container); })); - it("should updated a linked value when cleared.", co.wrap(function *(){ - const id = UUID.v4(); - const App = React.createClass({ - mixins: [LinkedStateMixin], - getValue: function(){ - return this.state.value - }, - getInitialState: function(){ - return { - value: null - } - }, - render: function(){ - return
-
{this.state.value}
- -
; - } - }); - yield new Promise(function(resolve, reject){ - ReactDOM.render(, container, resolve); - }); - const linkedValue = document.getElementById("linkedValue"); - const inputElement = document.querySelector("input.form-control"); - TestUtils.Simulate.click(inputElement); - const clearButtonElement = document.querySelector(".form-group button"); - const dayElement = document.querySelector("table tbody tr:nth-child(2) td"); - TestUtils.Simulate.click(dayElement); - assert.notEqual(linkedValue.innerHTML, ""); - TestUtils.Simulate.click(clearButtonElement); - assert.equal(linkedValue.innerHTML, ""); - ReactDOM.unmountComponentAtNode(container); - })); it("should updated a change handler when cleared.", co.wrap(function *(){ const id = UUID.v4(); let value = null; @@ -389,14 +313,81 @@ describe("Date Picker", function() { }); const inputElement = document.querySelector("input.form-control"); inputElement.value = "0"; - TestUtils.Simulate.change(inputElement) + TestUtils.Simulate.change(inputElement); inputElement.value = "05"; - TestUtils.Simulate.change(inputElement) + TestUtils.Simulate.change(inputElement); assert.equal(inputElement.value, "05/"); inputElement.value = "05/31"; TestUtils.Simulate.change(inputElement) assert.equal(inputElement.value, "05/31/"); ReactDOM.unmountComponentAtNode(container); })); + it("should automatically insert in YYYY/MM/DD format.", co.wrap(function *(){ + const id = UUID.v4(); + const App = React.createClass({ + render: function(){ + return
+ +
; + } + }); + yield new Promise(function(resolve, reject){ + ReactDOM.render(, container, resolve); + }); + const inputElement = document.querySelector("input.form-control"); + inputElement.value = "0"; + TestUtils.Simulate.change(inputElement); + inputElement.value = "1980"; + TestUtils.Simulate.change(inputElement); + assert.equal(inputElement.value, "1980/"); + inputElement.value = "1980/05"; + TestUtils.Simulate.change(inputElement) + assert.equal(inputElement.value, "1980/05/"); + ReactDOM.unmountComponentAtNode(container); + })); + it("should render dates in different formats.", co.wrap(function *(){ + const mm_dd_yyyy_id = "_" + UUID.v4(); + const dd_mm_yyyy_id = "_" + UUID.v4(); + const yyyy_mm_dd_id = "_" + UUID.v4(); + const App = React.createClass({ + getInitialState: function(){ + return { + value: null + } + }, + handleChange(value){ + this.setState({value:value}); + }, + render: function(){ + return
+ + + +
; + } + }); + yield new Promise(function(resolve, reject){ + ReactDOM.render(, container, resolve); + }); + const mm_dd_yyyy_inputElement = document.querySelector("#" + mm_dd_yyyy_id + "_container input.form-control"); + const dd_mm_yyyy_inputElement = document.querySelector("#" + dd_mm_yyyy_id + "_container input.form-control"); + const yyyy_mm_dd_inputElement = document.querySelector("#" + yyyy_mm_dd_id + "_container input.form-control"); + mm_dd_yyyy_inputElement.value = "05/31/1980"; + TestUtils.Simulate.change(mm_dd_yyyy_inputElement); + assert.equal(mm_dd_yyyy_inputElement.value, "05/31/1980"); + assert.equal(dd_mm_yyyy_inputElement.value, "31/05/1980"); + assert.equal(yyyy_mm_dd_inputElement.value, "1980/05/31"); + dd_mm_yyyy_inputElement.value = "15/04/2015"; + TestUtils.Simulate.change(dd_mm_yyyy_inputElement); + assert.equal(mm_dd_yyyy_inputElement.value, "04/15/2015"); + assert.equal(dd_mm_yyyy_inputElement.value, "15/04/2015"); + assert.equal(yyyy_mm_dd_inputElement.value, "2015/04/15"); + yyyy_mm_dd_inputElement.value = "1999/12/31"; + TestUtils.Simulate.change(yyyy_mm_dd_inputElement); + assert.equal(mm_dd_yyyy_inputElement.value, "12/31/1999"); + assert.equal(dd_mm_yyyy_inputElement.value, "31/12/1999"); + assert.equal(yyyy_mm_dd_inputElement.value, "1999/12/31"); + ReactDOM.unmountComponentAtNode(container); + })); });