Nicolas Sandron
2018-03-26 26446a92e043d107681f1bf9194621fe30731a04
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
'use strict';
 
var React = require('react'),
    createClass = require('create-react-class'),
    assign = require('object-assign'),
    onClickOutside = require('react-onclickoutside').default
    ;
 
var DateTimePickerTime = onClickOutside( createClass({
    getInitialState: function() {
        return this.calculateState( this.props );
    },
 
    calculateState: function( props ) {
        var date = props.selectedDate || props.viewDate,
            format = props.timeFormat,
            counters = []
            ;
 
        if ( format.toLowerCase().indexOf('h') !== -1 ) {
            counters.push('hours');
            if ( format.indexOf('m') !== -1 ) {
                counters.push('minutes');
                if ( format.indexOf('s') !== -1 ) {
                    counters.push('seconds');
                }
            }
        }
 
        var hours = date.format( 'H' );
        
        var daypart = false;
        if ( this.state !== null && this.props.timeFormat.toLowerCase().indexOf( ' a' ) !== -1 ) {
            if ( this.props.timeFormat.indexOf( ' A' ) !== -1 ) {
                daypart = ( hours >= 12 ) ? 'PM' : 'AM';
            } else {
                daypart = ( hours >= 12 ) ? 'pm' : 'am';
            }
        }
 
        return {
            hours: hours,
            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.toLowerCase().indexOf( ' a' ) !== -1 ) {
                value = ( value - 1 ) % 12 + 1;
 
                if ( value === 0 ) {
                    value = 12;
                }
            }
            return React.createElement('div', { key: type, className: 'rdtCounter' }, [
                React.createElement('span', { key: 'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'increase', type ), onContextMenu: this.disableContextMenu }, '▲' ),
                React.createElement('div', { key: 'c', className: 'rdtCount' }, value ),
                React.createElement('span', { key: 'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'decrease', type ), onContextMenu: this.disableContextMenu }, '▼' )
            ]);
        }
        return '';
    },
 
    renderDayPart: function() {
        return React.createElement('div', { key: 'dayPart', className: 'rdtCounter' }, [
            React.createElement('span', { key: 'up', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours'), onContextMenu: this.disableContextMenu }, '▲' ),
            React.createElement('div', { key: this.state.daypart, className: 'rdtCount' }, this.state.daypart ),
            React.createElement('span', { key: 'do', className: 'rdtBtn', onMouseDown: this.onStartClicking( 'toggleDayPart', 'hours'), onContextMenu: this.disableContextMenu }, '▼' )
        ]);
    },
 
    render: function() {
        var me = this,
            counters = []
        ;
 
        this.state.counters.forEach( function( c ) {
            if ( counters.length )
                counters.push( React.createElement('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( React.createElement('div', { className: 'rdtCounterSeparator', key: 'sep5' }, ':' ) );
            counters.push(
                React.createElement('div', { className: 'rdtCounter rdtMilli', key: 'm' },
                    React.createElement('input', { value: this.state.milliseconds, type: 'text', onChange: this.updateMilli } )
                    )
                );
        }
 
        return React.createElement('div', { className: 'rdtTime' },
            React.createElement('table', {}, [
                this.renderHeader(),
                React.createElement('tbody', { key: 'b'}, React.createElement('tr', {}, React.createElement('td', {},
                    React.createElement('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 React.createElement('thead', { key: 'h' }, React.createElement('tr', {},
            React.createElement('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.removeEventListener( 'touchend', me.mouseUpListener );
            };
 
            document.body.addEventListener( 'mouseup', me.mouseUpListener );
            document.body.addEventListener( 'touchend', me.mouseUpListener );
        };
    },
 
    disableContextMenu: function( event ) {
        event.preventDefault();
        return false;
    },
 
    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;
    },
 
    handleClickOutside: function() {
        this.props.handleClickOutside();
    }
}));
 
module.exports = DateTimePickerTime;