react-datetime
Version:
A lightweight but complete datetime picker React.js component.
205 lines (188 loc) • 5.94 kB
JavaScript
'use strict';
var React = require('react'),
assign = require('object-assign');
var DOM = React.DOM;
var DateTimePickerTime = React.createClass({
getInitialState: function(){
return this.calculateState( this.props );
},
calculateState: function( props ){
var date = props.selectedDate || props.viewDate,
format = props.timeFormat,
counters = []
;
if ( format.indexOf('H') !== -1 || format.indexOf('h') !== -1 ){
counters.push('hours');
if ( format.indexOf('m') !== -1 ){
counters.push('minutes');
if ( format.indexOf('s') !== -1 ){
counters.push('seconds');
}
}
}
var daypart = false;
if ( this.props.timeFormat.indexOf(' A') !== -1 && this.state !== null ){
daypart = ( this.state.hours >= 12 ) ? 'PM' : 'AM';
}
return {
hours: date.format('H'),
minutes: date.format('mm'),
seconds: date.format('ss'),
milliseconds: date.format('SSS'),
daypart: daypart,
counters: counters
};
},
renderCounter: function( type ){
if (type !== 'daypart') {
var value = this.state[ type ];
if (type === 'hours' && this.props.timeFormat.indexOf(' A') !== -1) {
value = (value - 1) % 12 + 1;
if (value === 0) {
value = 12;
}
}
return DOM.div({ key: type, className: 'rdtCounter'}, [
DOM.span({ key:'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'increase', type ) }, '▲' ),
DOM.div({ key:'c', className: 'rdtCount' }, value ),
DOM.span({ key:'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'decrease', type ) }, '▼' )
]);
}
return '';
},
renderDayPart: function() {
return DOM.div({ className: 'rdtCounter', key: 'dayPart'}, [
DOM.span({ key:'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▲' ),
DOM.div({ key: this.state.daypart, className: 'rdtCount'}, this.state.daypart ),
DOM.span({ key:'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▼' )
]);
},
render: function() {
var me = this,
counters = []
;
this.state.counters.forEach( function(c){
if ( counters.length )
counters.push( DOM.div( {key: 'sep' + counters.length, className: 'rdtCounterSeparator' }, ':' ));
counters.push( me.renderCounter( c ) );
});
if (this.state.daypart !== false) {
counters.push( me.renderDayPart() );
}
if ( this.state.counters.length === 3 && this.props.timeFormat.indexOf('S') !== -1 ){
counters.push( DOM.div( {className: 'rdtCounterSeparator', key: 'sep5' }, ':' ));
counters.push(
DOM.div( {className: 'rdtCounter rdtMilli', key:'m'},
DOM.input({ value: this.state.milliseconds, type: 'text', onChange: this.updateMilli })
)
);
}
return DOM.div( {className: 'rdtTime'},
DOM.table( {}, [
this.renderHeader(),
DOM.tbody({key: 'b'}, DOM.tr({}, DOM.td({},
DOM.div({ className: 'rdtCounters' }, counters )
)))
])
);
},
componentWillMount: function() {
var me = this;
me.timeConstraints = {
hours: {
min: 0,
max: 23,
step: 1
},
minutes: {
min: 0,
max: 59,
step: 1
},
seconds: {
min: 0,
max: 59,
step: 1,
},
milliseconds: {
min: 0,
max: 999,
step: 1
}
};
['hours', 'minutes', 'seconds', 'milliseconds'].forEach(function(type) {
assign(me.timeConstraints[type], me.props.timeConstraints[type]);
});
this.setState( this.calculateState( this.props ) );
},
componentWillReceiveProps: function( nextProps ){
this.setState( this.calculateState( nextProps ) );
},
updateMilli: function( e ){
var milli = parseInt( e.target.value, 10 );
if ( milli === e.target.value && milli >= 0 && milli < 1000 ){
this.props.setTime( 'milliseconds', milli );
this.setState({ milliseconds: milli });
}
},
renderHeader: function(){
if ( !this.props.dateFormat )
return null;
var date = this.props.selectedDate || this.props.viewDate;
return DOM.thead({ key: 'h'}, DOM.tr({},
DOM.th( {className: 'rdtSwitch', colSpan: 4, onClick: this.props.showView('days')}, date.format( this.props.dateFormat ) )
));
},
onStartClicking: function( action, type ){
var me = this;
return function(){
var update = {};
update[ type ] = me[ action ]( type );
me.setState( update );
me.timer = setTimeout( function(){
me.increaseTimer = setInterval( function(){
update[ type ] = me[ action ]( type );
me.setState( update );
}, 70);
}, 500);
me.mouseUpListener = function(){
clearTimeout( me.timer );
clearInterval( me.increaseTimer );
me.props.setTime( type, me.state[ type ] );
document.body.removeEventListener('mouseup', me.mouseUpListener);
};
document.body.addEventListener('mouseup', me.mouseUpListener);
};
},
padValues: {
hours: 1,
minutes: 2,
seconds: 2,
milliseconds: 3
},
toggleDayPart: function( type ){ // type is always 'hours'
var value = parseInt(this.state[ type ], 10) + 12;
if ( value > this.timeConstraints[ type ].max )
value = this.timeConstraints[ type ].min + (value - (this.timeConstraints[ type ].max + 1));
return this.pad( type, value );
},
increase: function( type ){
var value = parseInt(this.state[ type ], 10) + this.timeConstraints[ type ].step;
if ( value > this.timeConstraints[ type ].max )
value = this.timeConstraints[ type ].min + ( value - ( this.timeConstraints[ type ].max + 1) );
return this.pad( type, value );
},
decrease: function( type ){
var value = parseInt(this.state[ type ], 10) - this.timeConstraints[ type ].step;
if ( value < this.timeConstraints[ type ].min )
value = this.timeConstraints[ type ].max + 1 - ( this.timeConstraints[ type ].min - value );
return this.pad( type, value );
},
pad: function( type, value ){
var str = value + '';
while ( str.length < this.padValues[ type ] )
str = '0' + str;
return str;
}
});
module.exports = DateTimePickerTime;