Skip to content

Commit

Permalink
[TimePicker] Added value prop.
Browse files Browse the repository at this point in the history
- TimePicker#getValue is now deprecated.
- TimePicker#setValue is now deprecated.
- Added value prop.
- defaultTime is only used if value is not defined on props.
- Added tests for TimePicker initialization behavior.
- Adding  utils/DateTime#formatTime

Fixes #3094

Signed-off-by: rscnt <[email protected]>
  • Loading branch information
raul-ascencio-applaudo authored and rscnt committed Feb 14, 2016
1 parent d4472ee commit 2117dca
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@ import TimePicker from 'material-ui/lib/time-picker/time-picker';

export default class TimePickerExampleComplex extends React.Component {

constructor(props) {
super(props);
this.state = {value24: null, value12: null};
}

handleChangeTimePicker12 = (err, time) => {
this.refs.picker12hr.setTime(time);
handleChangeTimePicker24 = (e, date) => {
this.setState({value24: date});
};

handleChangeTimePicker24 = (err, time) => {
this.refs.picker24hr.setTime(time);
handleChangeTimePicker12 = (e, date) => {
this.setState({value12: date});
};

render() {
return (
<div>
<TimePicker
ref="picker12hr"
format="ampm"
hintText="12hr Format"
onChange={this.handleChangeTimePicker24}
/>
<TimePicker
ref="picker24hr"
format="24hr"
hintText="24hr Format"
<TimePicker format="ampm" hintText="12hr Format"
value={this.state.value12}
onChange={this.handleChangeTimePicker12}
/>
<TimePicker format="24hr" hintText="24hr Format"
value={this.state.value24}
onChange={this.handleChangeTimePicker24}
/>
</div>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/time-picker/clock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ const Clock = React.createClass({
getInitialState() {
return {
muiTheme: this.context.muiTheme || getMuiTheme(),
selectedTime: this.props.initialTime,
selectedTime: this.props.initialTime || new Date(),
mode: 'hour',
};
},

componentWillReceiveProps(nextProps, nextContext) {
this.setState({
muiTheme: nextContext.muiTheme || this.state.muiTheme,
selectedTime: nextProps.initialTime,
selectedTime: nextProps.initialTime || new Date(),
});
},

Expand Down
79 changes: 47 additions & 32 deletions src/time-picker/time-picker.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from 'react';
import warning from 'warning';
import DateTime from '../utils/date-time.js';
import TimePickerDialog from './time-picker-dialog';
import TextField from '../text-field';
import getMuiTheme from '../styles/getMuiTheme';
Expand Down Expand Up @@ -76,6 +78,11 @@ const TimePicker = React.createClass({
* Override the inline-styles of TimePicker's TextField element.
*/
textFieldStyle: React.PropTypes.object,

/**
* Sets the time for the Time Picker programmatically.
*/
value: React.PropTypes.object,
},

contextTypes: {
Expand All @@ -94,47 +101,41 @@ const TimePicker = React.createClass({

getInitialState() {
return {
time: this.props.defaultTime || emptyTime,
time: this._isControlled() ? this._getControlledTime() : this.props.defaultTime,
dialogTime: new Date(),
muiTheme: this.context.muiTheme || getMuiTheme(),
};
},

formatTime(date) {
let hours = date.getHours();
let mins = date.getMinutes().toString();

if (this.props.format === 'ampm') {
const isAM = hours < 12;
hours = hours % 12;
const additional = isAM ? ' am' : ' pm';
hours = (hours || 12).toString();

if (mins.length < 2 ) mins = `0${mins}`;

if (this.props.pedantic) {
// Treat midday/midnight specially http://www.nist.gov/pml/div688/times.cfm
if (hours === '12' && mins === '00') {
return additional === ' pm' ? '12 noon' : '12 midnight';
}
}

return hours + (mins === '00' ? '' : `:${mins}`) + additional;
componentWillReceiveProps(nextProps, nextContext) {
const newState = this.state;
if (nextContext.muiTheme) {
newState.muiTheme = nextContext.muiTheme;
}

hours = hours.toString();

if (hours.length < 2) hours = `0${hours}`;
if (mins.length < 2) mins = `0${mins}`;

return `${hours}:${mins}`;
newState.time = this._getControlledTime(nextProps);
this.setState(newState);
},


/**
* Deprecated.
* returns timepicker value.
**/
getTime() {
warning(false, `getTime() method is deprecated. Use the defaultTime property
instead. Or use the TimePicker as a controlled component with the value
property.`);
return this.state.time;
},

/**
* Deprecated
* sets timepicker value.
**/
setTime(time) {
warning(false, `setTime() method is deprecated. Use the defaultTime property
instead. Or use the TimePicker as a controlled component with the value
property.`);
this.setState({time: time ? time : emptyTime});
},

Expand All @@ -147,14 +148,15 @@ const TimePicker = React.createClass({

openDialog() {
this.setState({
dialogTime: this.getTime(),
dialogTime: this.state.time,
});

this.refs.dialogWindow.show();
},

_handleDialogAccept(t) {
this.setTime(t);
this.setState({
time: t,
});
if (this.props.onChange) this.props.onChange(null, t);
},

Expand All @@ -171,6 +173,18 @@ const TimePicker = React.createClass({
if (this.props.onTouchTap) this.props.onTouchTap(e);
},

_isControlled() {
return this.props.value !== null;
},

_getControlledTime(props = this.props) {
let result = null;
if (DateTime.isDateObject(props.value)) {
result = props.value;
}
return result;
},

render() {
const {
autoOk,
Expand All @@ -181,6 +195,7 @@ const TimePicker = React.createClass({
onDismiss,
style,
textFieldStyle,
pedantic,
...other,
} = this.props;

Expand All @@ -197,7 +212,7 @@ const TimePicker = React.createClass({
{...other}
style={textFieldStyle}
ref="input"
value={time === emptyTime ? null : this.formatTime(time)}
value={time === emptyTime ? null : DateTime.formatTime(time, format, pedantic)}
onFocus={this._handleInputFocus}
onTouchTap={this._handleInputTouchTap}
/>
Expand Down
58 changes: 58 additions & 0 deletions src/utils/date-time.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,24 @@ export default {
return newDate;
},

addHours(d, hours) {
const newDate = this.clone(d);
newDate.setHours(d.getHours() + hours);
return newDate;
},

addMinutes(d, minutes) {
const newDate = this.clone(d);
newDate.setMinutes(d.getMinutes() + minutes);
return newDate;
},

addSeconds(d, seconds) {
const newDate = this.clone(d);
newDate.setSeconds(d.getMinutes() + seconds);
return newDate;
},

clone(d) {
return new Date(d.getTime());
},
Expand Down Expand Up @@ -123,6 +141,46 @@ export default {
return `${m}/${d}/${y}`;
},

/**
* formatTime, extracted from date-picker/date-picker.
*
* @param date [Date] A Date object.
* @param format [String] One of 'ampm', '24hr', defaults to 'ampm'.
* @param pedantic [Boolean] Check time-picker/time-picker.jsx file.
*
* @return String A string representing the formatted time.
*/
formatTime(date, format = 'ampm', pedantic = false) {
if (!date) return '';
let hours = date.getHours();
let mins = date.getMinutes().toString();

if (format === 'ampm') {
let isAM = hours < 12;
hours = hours % 12;
let additional = isAM ? ' am' : ' pm';
hours = (hours || 12).toString();

if (mins.length < 2 ) mins = `0${mins}`;

if (pedantic) {
// Treat midday/midnight specially http://www.nist.gov/pml/div688/times.cfm
if (hours === '12' && mins === '00') {
return additional === ' pm' ? '12 noon' : '12 midnight';
}
}

return hours + (mins === '00' ? '' : `:${mins}`) + additional;
}

hours = hours.toString();

if (hours.length < 2) hours = `0${hours}`;
if (mins.length < 2) mins = `0${mins}`;

return `${hours}:${mins}`;
},

isEqualDate(d1, d2) {
return d1 && d2 &&
(d1.getFullYear() === d2.getFullYear()) &&
Expand Down
53 changes: 53 additions & 0 deletions test/time-picker/time-picker-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';
import TextField from 'text-field';
import TimePicker from 'time-picker/time-picker';
import DateTime from 'utils/date-time';
import TestUtils from 'react-addons-test-utils';

describe('TimePicker', () => {

it('has to give value prop precedence over defaultTime', () => {
let initialTime = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GMT
let valueTime = DateTime.addHours(initialTime, 2);

let render = TestUtils.renderIntoDocument(
<TimePicker value={valueTime} format="ampm" locale="en-US"
initialTime={initialTime}
/>
);

let timeTextField = TestUtils.findRenderedComponentWithType(render, TextField);

expect(timeTextField.props.value, DateTime.formatTime(valueTime));
});

it('takes defaulTime prop to set first value when value prop is missing', () => {
let initialTime = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GMT

let render = TestUtils.renderIntoDocument(
<TimePicker format="ampm" locale="en-US"
defaultTime={initialTime}
/>
);

let timeTextField = TestUtils.findRenderedComponentWithType(render, TextField);

expect(timeTextField.props.value, DateTime.formatTime(initialTime));
});

it('shows value prop if defaultTime is missing', () => {
let initialTime = null;
let valueTime = new Date(1448967059892); // Tue, 01 Dec 2015 10:50:59 GM

let render = TestUtils.renderIntoDocument(
<TimePicker value={valueTime} format="ampm" locale="en-US"
defaultTime={initialTime}
/>
);

let timeTextField = TestUtils.findRenderedComponentWithType(render, TextField);

expect(timeTextField.props.value, DateTime.formatTime(valueTime));
});

});

0 comments on commit 2117dca

Please sign in to comment.