Simon Egersand
2018-02-07 de3fe15c59e7692eda6058a0dc8d0271acbcf3a3
commit | author | age
d76f7b 1 'use strict';
M 2
bc8e0f 3 var React = require('react'),
de3fe1 4   createClass = require('create-react-class'),
SE 5   assign = require('object-assign'),
6   onClickOutside = require('react-onclickoutside').default;
d76f7b 7
de3fe1 8 var DateTimePickerTime = onClickOutside(
SE 9   createClass({
10     getInitialState: function() {
11       return this.calculateState(this.props);
12     },
f0ec5a 13
de3fe1 14     calculateState: function(props) {
SE 15       var date = props.selectedDate || props.viewDate,
16         format = props.timeFormat,
17         counters = [];
d76f7b 18
de3fe1 19       if (format.toLowerCase().indexOf('h') !== -1) {
SE 20         counters.push('hours');
21         if (format.indexOf('m') !== -1) {
22           counters.push('minutes');
23           if (format.indexOf('s') !== -1) {
24             counters.push('seconds');
25           }
26         }
27       }
d76f7b 28
de3fe1 29       var hours = date.format('H');
a17593 30
de3fe1 31       var daypart = false;
SE 32       if (
33         this.state !== null &&
34         this.props.timeFormat.toLowerCase().indexOf(' a') !== -1
35       ) {
36         if (this.props.timeFormat.indexOf(' A') !== -1) {
37           daypart = hours >= 12 ? 'PM' : 'AM';
38         } else {
39           daypart = hours >= 12 ? 'pm' : 'am';
40         }
41       }
1a0429 42
de3fe1 43       return {
SE 44         hours: hours,
45         minutes: date.format('mm'),
46         seconds: date.format('ss'),
47         milliseconds: date.format('SSS'),
48         daypart: daypart,
49         counters: counters
50       };
51     },
f0ec5a 52
de3fe1 53     renderCounter: function(type) {
SE 54       if (type !== 'daypart') {
55         var value = this.state[type];
56         if (
57           type === 'hours' &&
58           this.props.timeFormat.toLowerCase().indexOf(' a') !== -1
59         ) {
60           value = (value - 1) % 12 + 1;
f0ec5a 61
de3fe1 62           if (value === 0) {
SE 63             value = 12;
64           }
65         }
66         return React.createElement(
67           'div',
68           { key: type, className: 'rdtCounter' },
69           [
70             React.createElement(
71               'span',
72               {
73                 key: 'up',
74                 className: 'rdtBtn',
75                 onMouseDown: this.onStartClicking('increase', type),
76                 onContextMenu: this.disableContextMenu
77               },
78               '▲'
79             ),
80             React.createElement(
81               'div',
82               { key: 'c', className: 'rdtCount' },
83               value
84             ),
85             React.createElement(
86               'span',
87               {
88                 key: 'do',
89                 className: 'rdtBtn',
90                 onMouseDown: this.onStartClicking('decrease', type),
91                 onContextMenu: this.disableContextMenu
92               },
93               '▼'
94             )
95           ]
96         );
97       }
98       return '';
99     },
f0ec5a 100
de3fe1 101     renderDayPart: function() {
SE 102       return React.createElement(
103         'div',
104         { key: 'dayPart', className: 'rdtCounter' },
105         [
106           React.createElement(
107             'span',
108             {
109               key: 'up',
110               className: 'rdtBtn',
111               onMouseDown: this.onStartClicking('toggleDayPart', 'hours'),
112               onContextMenu: this.disableContextMenu
113             },
114             '▲'
115           ),
116           React.createElement(
117             'div',
118             { key: this.state.daypart, className: 'rdtCount' },
119             this.state.daypart
120           ),
121           React.createElement(
122             'span',
123             {
124               key: 'do',
125               className: 'rdtBtn',
126               onMouseDown: this.onStartClicking('toggleDayPart', 'hours'),
127               onContextMenu: this.disableContextMenu
128             },
129             '▼'
130           )
131         ]
132       );
133     },
d76f7b 134
de3fe1 135     render: function() {
SE 136       var me = this,
137         counters = [];
a17593 138
de3fe1 139       this.state.counters.forEach(function(c) {
SE 140         if (counters.length)
141           counters.push(
142             React.createElement(
143               'div',
144               {
145                 key: 'sep' + counters.length,
146                 className: 'rdtCounterSeparator'
147               },
148               ':'
149             )
150           );
151         counters.push(me.renderCounter(c));
152       });
a17593 153
de3fe1 154       if (this.state.daypart !== false) {
SE 155         counters.push(me.renderDayPart());
156       }
d76f7b 157
de3fe1 158       if (
SE 159         this.state.counters.length === 3 &&
160         this.props.timeFormat.indexOf('S') !== -1
161       ) {
162         counters.push(
163           React.createElement(
164             'div',
165             { className: 'rdtCounterSeparator', key: 'sep5' },
166             ':'
167           )
168         );
169         counters.push(
170           React.createElement(
171             'div',
172             { className: 'rdtCounter rdtMilli', key: 'm' },
173             React.createElement('input', {
174               value: this.state.milliseconds,
175               type: 'text',
176               onChange: this.updateMilli
177             })
178           )
179         );
180       }
f0ec5a 181
de3fe1 182       return React.createElement(
SE 183         'div',
184         { className: 'rdtTime' },
185         React.createElement('table', {}, [
186           this.renderHeader(),
187           React.createElement(
188             'tbody',
189             { key: 'b' },
190             React.createElement(
191               'tr',
192               {},
193               React.createElement(
194                 'td',
195                 {},
196                 React.createElement(
197                   'div',
198                   { className: 'rdtCounters' },
199                   counters
200                 )
201               )
202             )
203           )
204         ])
205       );
206     },
f0ec5a 207
de3fe1 208     componentWillMount: function() {
SE 209       var me = this;
210       me.timeConstraints = {
211         hours: {
212           min: 0,
213           max: 23,
214           step: 1
215         },
216         minutes: {
217           min: 0,
218           max: 59,
219           step: 1
220         },
221         seconds: {
222           min: 0,
223           max: 59,
224           step: 1
225         },
226         milliseconds: {
227           min: 0,
228           max: 999,
229           step: 1
230         }
231       };
232       ['hours', 'minutes', 'seconds', 'milliseconds'].forEach(function(type) {
233         assign(me.timeConstraints[type], me.props.timeConstraints[type]);
234       });
235       this.setState(this.calculateState(this.props));
236     },
f0ec5a 237
de3fe1 238     componentWillReceiveProps: function(nextProps) {
SE 239       this.setState(this.calculateState(nextProps));
240     },
f0ec5a 241
de3fe1 242     updateMilli: function(e) {
SE 243       var milli = parseInt(e.target.value, 10);
244       if (milli === e.target.value && milli >= 0 && milli < 1000) {
245         this.props.setTime('milliseconds', milli);
246         this.setState({ milliseconds: milli });
247       }
248     },
d76f7b 249
de3fe1 250     renderHeader: function() {
SE 251       if (!this.props.dateFormat) return null;
f0ec5a 252
de3fe1 253       var date = this.props.selectedDate || this.props.viewDate;
SE 254       return React.createElement(
255         'thead',
256         { key: 'h' },
257         React.createElement(
258           'tr',
259           {},
260           React.createElement(
261             'th',
262             {
263               className: 'rdtSwitch',
264               colSpan: 4,
265               onClick: this.props.showView('days')
266             },
267             date.format(this.props.dateFormat)
268           )
269         )
270       );
271     },
59314a 272
de3fe1 273     onStartClicking: function(action, type) {
SE 274       var me = this;
d76f7b 275
de3fe1 276       return function() {
SE 277         var update = {};
278         update[type] = me[action](type);
279         me.setState(update);
d76f7b 280
de3fe1 281         me.timer = setTimeout(function() {
SE 282           me.increaseTimer = setInterval(function() {
283             update[type] = me[action](type);
284             me.setState(update);
285           }, 70);
286         }, 500);
4e9d38 287
de3fe1 288         me.mouseUpListener = function() {
SE 289           clearTimeout(me.timer);
290           clearInterval(me.increaseTimer);
291           me.props.setTime(type, me.state[type]);
292           document.body.removeEventListener('mouseup', me.mouseUpListener);
293         };
f0ec5a 294
de3fe1 295         document.body.addEventListener('mouseup', me.mouseUpListener);
SE 296       };
297     },
a8de69 298
de3fe1 299     disableContextMenu: function(event) {
SE 300       event.preventDefault();
301       return false;
302     },
f0ec5a 303
de3fe1 304     padValues: {
SE 305       hours: 1,
306       minutes: 2,
307       seconds: 2,
308       milliseconds: 3
309     },
f0ec5a 310
de3fe1 311     toggleDayPart: function(type) {
SE 312       // type is always 'hours'
313       var value = parseInt(this.state[type], 10) + 12;
314       if (value > this.timeConstraints[type].max)
315         value =
316           this.timeConstraints[type].min +
317           (value - (this.timeConstraints[type].max + 1));
318       return this.pad(type, value);
319     },
f0ec5a 320
de3fe1 321     increase: function(type) {
SE 322       var value =
323         parseInt(this.state[type], 10) + this.timeConstraints[type].step;
324       if (value > this.timeConstraints[type].max)
325         value =
326           this.timeConstraints[type].min +
327           (value - (this.timeConstraints[type].max + 1));
328       return this.pad(type, value);
329     },
f0ec5a 330
de3fe1 331     decrease: function(type) {
SE 332       var value =
333         parseInt(this.state[type], 10) - this.timeConstraints[type].step;
334       if (value < this.timeConstraints[type].min)
335         value =
336           this.timeConstraints[type].max +
337           1 -
338           (this.timeConstraints[type].min - value);
339       return this.pad(type, value);
340     },
11612b 341
de3fe1 342     pad: function(type, value) {
SE 343       var str = value + '';
344       while (str.length < this.padValues[type]) str = '0' + str;
345       return str;
346     },
347
348     handleClickOutside: function() {
349       this.props.handleClickOutside();
350     }
351   })
352 );
d76f7b 353
M 354 module.exports = DateTimePickerTime;