Skip to content

Commit

Permalink
MM/DD/YYYY, DD/MM/YYYY, and YYYY/MM/DD formats. Closes #3. React 15 c…
Browse files Browse the repository at this point in the history
…ompatibility. Remove valueLink as it's been depreciated.

Test of pre and post-commit hooks.

Test of pre and post-commit hooks.

Document date format property.
  • Loading branch information
wehriam committed Apr 9, 2016
1 parent 2eb2aba commit a9b5cf7
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 214 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -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
Expand Down Expand Up @@ -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`
Expand Down
30 changes: 19 additions & 11 deletions example/app.jsx
Expand Up @@ -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(),
Expand Down Expand Up @@ -59,47 +57,57 @@ const App = React.createClass({
</Row>
<Row>
<Col xs={12}>
<h2>LinkState</h2>
<h2>Blur and Focus Events</h2>
</Col>
</Row>
<Row>
<Col sm={6}>
<form>
<DatePicker placeholder="Placeholder" valueLink={this.linkState('date')} />
<DatePicker placeholder="Placeholder" help="Open console to see focus/blur logging." value={this.state.date} onFocus={() => {console.log("Focus")}} onBlur={() => {console.log("Blur")}}/>
</form>
</Col>
</Row>
<Row>
<Col xs={12}>
<h2>Blur and Focus Events</h2>
<h2>Styles</h2>
</Col>
</Row>
<Row>
<Col sm={6}>
<Col sm={4}>
<form>
<DatePicker placeholder="Placeholder" help="Open console to see focus/blur logging." value={this.state.date} onFocus={() => {console.log("Focus")}} onBlur={() => {console.log("Blur")}}/>
<DatePicker bsStyle="success" label="Success" placeholder="Placeholder" help="Help" />
</form>
</Col>
<Col sm={4}>
<form>
<DatePicker bsStyle="warning" label="Warning" placeholder="Placeholder" value={this.state.date} help="Help" />
</form>
</Col>
<Col sm={4}>
<form>
<DatePicker bsStyle="error" label="Error" placeholder="Placeholder" value={this.state.date} help="Help" />
</form>
</Col>
</Row>
<Row>
<Col xs={12}>
<h2>Styles</h2>
<h2>Date Format</h2>
</Col>
</Row>
<Row>
<Col sm={4}>
<form>
<DatePicker bsStyle="success" label="Success" placeholder="Placeholder" help="Help" />
<DatePicker label="MM/DD/YYYY" dateFormat="MM/DD/YYYY" onChange={this.handleChange} value={this.state.date} help="Help" />
</form>
</Col>
<Col sm={4}>
<form>
<DatePicker bsStyle="warning" label="Warning" placeholder="Placeholder" value={this.state.date} help="Help" />
<DatePicker label="DD/MM/YYYY" dateFormat="DD/MM/YYYY" onChange={this.handleChange} value={this.state.date} help="Help" />
</form>
</Col>
<Col sm={4}>
<form>
<DatePicker bsStyle="error" label="Error" placeholder="Placeholder" value={this.state.date} help="Help" />
<DatePicker label="YYYY/MM/DD" dateFormat="YYYY/MM/DD" onChange={this.handleChange} value={this.state.date} help="Help" />
</form>
</Col>
</Row>
Expand Down
128 changes: 81 additions & 47 deletions 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);
Expand All @@ -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
},
Expand All @@ -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()
Expand Down Expand Up @@ -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 {
Expand All @@ -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()) {
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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()
Expand All @@ -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));
}
Expand All @@ -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 },
Expand All @@ -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,
Expand All @@ -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 || '' })
);
}
});

0 comments on commit a9b5cf7

Please sign in to comment.