Josh Beckman
2017-04-12 84755ceb54dd6f5fe7682912336b243e4b7dc59b
commit | author | age
d76f7b 1 'use strict';
M 2
bc8e0f 3 var React = require('react'),
84755c 4     createClass = require('create-react-class'),
11612b 5     assign = require('object-assign'),
JM 6   onClickOutside = require('react-onclickoutside')
f0ec5a 7 ;
d76f7b 8
M 9 var DOM = React.DOM;
84755c 10 var DateTimePickerTime = onClickOutside( createClass({
cf1e72 11     getInitialState: function() {
c658ad 12         return this.calculateState( this.props );
M 13     },
f0ec5a 14
cf1e72 15     calculateState: function( props ) {
62fd2f 16         var date = props.selectedDate || props.viewDate,
c658ad 17             format = props.timeFormat,
d76f7b 18             counters = []
M 19         ;
20
cf1e72 21         if ( format.toLowerCase().indexOf('h') !== -1 ) {
d76f7b 22             counters.push('hours');
cf1e72 23             if ( format.indexOf('m') !== -1 ) {
d76f7b 24                 counters.push('minutes');
cf1e72 25                 if ( format.indexOf('s') !== -1 ) {
d76f7b 26                     counters.push('seconds');
M 27                 }
28             }
29         }
30
fa70cd 31         var daypart = false;
f0ec5a 32         if ( this.state !== null && this.props.timeFormat.toLowerCase().indexOf( ' a' ) !== -1 ) {
SE 33             if ( this.props.timeFormat.indexOf( ' A' ) !== -1 ) {
cf1e72 34                 daypart = ( this.state.hours >= 12 ) ? 'PM' : 'AM';
SE 35             } else {
36                 daypart = ( this.state.hours >= 12 ) ? 'pm' : 'am';
37             }
a17593 38         }
MK 39
d76f7b 40         return {
f0ec5a 41             hours: date.format( 'H' ),
SE 42             minutes: date.format( 'mm' ),
43             seconds: date.format( 'ss' ),
44             milliseconds: date.format( 'SSS' ),
a17593 45             daypart: daypart,
d76f7b 46             counters: counters
M 47         };
48     },
1a0429 49
f0ec5a 50     renderCounter: function( type ) {
SE 51         if ( type !== 'daypart' ) {
52             var value = this.state[ type ];
53             if ( type === 'hours' && this.props.timeFormat.toLowerCase().indexOf( ' a' ) !== -1 ) {
54                 value = ( value - 1 ) % 12 + 1;
55
56                 if ( value === 0 ) {
7c7053 57                     value = 12;
ER 58                 }
a17593 59             }
f0ec5a 60             return DOM.div({ key: type, className: 'rdtCounter' }, [
SE 61                 DOM.span({ key: 'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'increase', type ) }, '▲' ),
62                 DOM.div({ key: 'c', className: 'rdtCount' }, value ),
63                 DOM.span({ key: 'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'decrease', type ) }, '▼' )
a17593 64             ]);
MK 65         }
66         return '';
d76f7b 67     },
f0ec5a 68
3bf154 69     renderDayPart: function() {
f0ec5a 70         return DOM.div({ key: 'dayPart', className: 'rdtCounter' }, [
SE 71             DOM.span({ key: 'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▲' ),
72             DOM.div({ key: this.state.daypart, className: 'rdtCount' }, this.state.daypart ),
73             DOM.span({ key: 'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours') }, '▼' )
3bf154 74         ]);
DF 75     },
f0ec5a 76
d76f7b 77     render: function() {
M 78         var me = this,
79             counters = []
80         ;
81
f0ec5a 82         this.state.counters.forEach( function( c ) {
462115 83             if ( counters.length )
f0ec5a 84                 counters.push( DOM.div({ key: 'sep' + counters.length, className: 'rdtCounterSeparator' }, ':' ) );
d76f7b 85             counters.push( me.renderCounter( c ) );
M 86         });
a17593 87
f0ec5a 88         if ( this.state.daypart !== false ) {
3bf154 89             counters.push( me.renderDayPart() );
a17593 90         }
MK 91
f0ec5a 92         if ( this.state.counters.length === 3 && this.props.timeFormat.indexOf( 'S' ) !== -1 ) {
SE 93             counters.push( DOM.div({ className: 'rdtCounterSeparator', key: 'sep5' }, ':' ) );
d76f7b 94             counters.push(
f0ec5a 95                 DOM.div({ className: 'rdtCounter rdtMilli', key: 'm' },
SE 96                     DOM.input({ value: this.state.milliseconds, type: 'text', onChange: this.updateMilli } )
d76f7b 97                     )
M 98                 );
99         }
100
f0ec5a 101         return DOM.div({ className: 'rdtTime' },
SE 102             DOM.table({}, [
a3a33b 103                 this.renderHeader(),
f0ec5a 104                 DOM.tbody({ key: 'b'}, DOM.tr({}, DOM.td({},
SE 105                     DOM.div({ className: 'rdtCounters' }, counters )
a3a33b 106                 )))
M 107             ])
d76f7b 108         );
c658ad 109     },
f0ec5a 110
bc8e0f 111     componentWillMount: function() {
LG 112         var me = this;
9c55be 113         me.timeConstraints = {
AG 114             hours: {
115                 min: 0,
116                 max: 23,
117                 step: 1
118             },
119             minutes: {
120                 min: 0,
121                 max: 59,
122                 step: 1
123             },
124             seconds: {
125                 min: 0,
126                 max: 59,
cf1e72 127                 step: 1
9c55be 128             },
AG 129             milliseconds: {
130                 min: 0,
131                 max: 999,
132                 step: 1
133             }
134         };
f0ec5a 135         ['hours', 'minutes', 'seconds', 'milliseconds'].forEach( function( type ) {
cf1e72 136             assign(me.timeConstraints[ type ], me.props.timeConstraints[ type ]);
bc8e0f 137         });
79e319 138         this.setState( this.calculateState( this.props ) );
bc8e0f 139     },
f0ec5a 140
cf1e72 141     componentWillReceiveProps: function( nextProps ) {
c658ad 142         this.setState( this.calculateState( nextProps ) );
d76f7b 143     },
f0ec5a 144
cf1e72 145     updateMilli: function( e ) {
462115 146         var milli = parseInt( e.target.value, 10 );
cf1e72 147         if ( milli === e.target.value && milli >= 0 && milli < 1000 ) {
d76f7b 148             this.props.setTime( 'milliseconds', milli );
cf1e72 149             this.setState( { milliseconds: milli } );
d76f7b 150         }
M 151     },
f0ec5a 152
cf1e72 153     renderHeader: function() {
462115 154         if ( !this.props.dateFormat )
49a27b 155             return null;
d76f7b 156
62fd2f 157         var date = this.props.selectedDate || this.props.viewDate;
f0ec5a 158         return DOM.thead({ key: 'h' }, DOM.tr({},
SE 159             DOM.th({ className: 'rdtSwitch', colSpan: 4, onClick: this.props.showView( 'days' ) }, date.format( this.props.dateFormat ) )
d76f7b 160         ));
M 161     },
f0ec5a 162
cf1e72 163     onStartClicking: function( action, type ) {
462115 164         var me = this;
59314a 165
cf1e72 166         return function() {
d76f7b 167             var update = {};
M 168             update[ type ] = me[ action ]( type );
169             me.setState( update );
170
cf1e72 171             me.timer = setTimeout( function() {
SE 172                 me.increaseTimer = setInterval( function() {
d76f7b 173                     update[ type ] = me[ action ]( type );
M 174                     me.setState( update );
462115 175                 }, 70);
d76f7b 176             }, 500);
M 177
cf1e72 178             me.mouseUpListener = function() {
d76f7b 179                 clearTimeout( me.timer );
M 180                 clearInterval( me.increaseTimer );
181                 me.props.setTime( type, me.state[ type ] );
f0ec5a 182                 document.body.removeEventListener( 'mouseup', me.mouseUpListener );
4e9d38 183             };
M 184
f0ec5a 185             document.body.addEventListener( 'mouseup', me.mouseUpListener );
d76f7b 186         };
0b3475 187     },
f0ec5a 188
0b3475 189     padValues: {
LG 190         hours: 1,
191         minutes: 2,
192         seconds: 2,
193         milliseconds: 3
d76f7b 194     },
f0ec5a 195
cf1e72 196     toggleDayPart: function( type ) { // type is always 'hours'
f0ec5a 197         var value = parseInt( this.state[ type ], 10) + 12;
0b3475 198         if ( value > this.timeConstraints[ type ].max )
cf1e72 199             value = this.timeConstraints[ type ].min + ( value - ( this.timeConstraints[ type ].max + 1 ) );
d76f7b 200         return this.pad( type, value );
M 201     },
f0ec5a 202
SE 203     increase: function( type ) {
204         var value = parseInt( this.state[ type ], 10) + this.timeConstraints[ type ].step;
205         if ( value > this.timeConstraints[ type ].max )
206             value = this.timeConstraints[ type ].min + ( value - ( this.timeConstraints[ type ].max + 1 ) );
207         return this.pad( type, value );
208     },
209
cf1e72 210     decrease: function( type ) {
f0ec5a 211         var value = parseInt( this.state[ type ], 10) - this.timeConstraints[ type ].step;
0b3475 212         if ( value < this.timeConstraints[ type ].min )
4ed404 213             value = this.timeConstraints[ type ].max + 1 - ( this.timeConstraints[ type ].min - value );
d76f7b 214         return this.pad( type, value );
M 215     },
f0ec5a 216
cf1e72 217     pad: function( type, value ) {
d76f7b 218         var str = value + '';
462115 219         while ( str.length < this.padValues[ type ] )
d76f7b 220             str = '0' + str;
M 221         return str;
11612b 222     },
JM 223
224   handleClickOutside: function() {
225     this.props.handleClickOutside();
226   }
227 }));
d76f7b 228
M 229 module.exports = DateTimePickerTime;