Simon Egersand
2018-02-07 de3fe15c59e7692eda6058a0dc8d0271acbcf3a3
src/TimeView.js
@@ -1,235 +1,354 @@
'use strict';
var React = require('react'),
   createClass = require('create-react-class'),
   assign = require('object-assign'),
   onClickOutside = require('react-onclickoutside').default
   ;
  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 );
   },
var DateTimePickerTime = onClickOutside(
  createClass({
    getInitialState: function() {
      return this.calculateState(this.props);
    },
   calculateState: function( props ) {
      var date = props.selectedDate || props.viewDate,
         format = props.timeFormat,
         counters = []
         ;
    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');
            }
         }
      }
      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';
         }
      }
      var hours = date.format('H');
      return {
         hours: hours,
         minutes: date.format( 'mm' ),
         seconds: date.format( 'ss' ),
         milliseconds: date.format( 'SSS' ),
         daypart: daypart,
         counters: counters
      };
   },
      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';
        }
      }
   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;
      return {
        hours: hours,
        minutes: date.format('mm'),
        seconds: date.format('ss'),
        milliseconds: date.format('SSS'),
        daypart: daypart,
        counters: counters
      };
    },
            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 '';
   },
    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;
   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 }, '▼' )
      ]);
   },
          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 '';
    },
   render: function() {
      var me = this,
         counters = []
      ;
    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
            },
            '▼'
          )
        ]
      );
    },
      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 ) );
      });
    render: function() {
      var me = this,
        counters = [];
      if ( this.state.daypart !== false ) {
         counters.push( me.renderDayPart() );
      }
      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.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 } )
               )
            );
      }
      if (this.state.daypart !== false) {
        counters.push(me.renderDayPart());
      }
      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 )
            )))
         ])
      );
   },
      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
            })
          )
        );
      }
   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 ) );
   },
      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
                )
              )
            )
          )
        ])
      );
    },
   componentWillReceiveProps: function( nextProps ) {
      this.setState( this.calculateState( nextProps ) );
   },
    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));
    },
   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 } );
      }
   },
    componentWillReceiveProps: function(nextProps) {
      this.setState(this.calculateState(nextProps));
    },
   renderHeader: function() {
      if ( !this.props.dateFormat )
         return null;
    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 });
      }
    },
      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 ) )
      ));
   },
    renderHeader: function() {
      if (!this.props.dateFormat) return null;
   onStartClicking: function( action, type ) {
      var me = this;
      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)
          )
        )
      );
    },
      return function() {
         var update = {};
         update[ type ] = me[ action ]( type );
         me.setState( update );
    onStartClicking: function(action, type) {
      var me = this;
         me.timer = setTimeout( function() {
            me.increaseTimer = setInterval( function() {
               update[ type ] = me[ action ]( type );
               me.setState( update );
            }, 70);
         }, 500);
      return function() {
        var update = {};
        update[type] = me[action](type);
        me.setState(update);
         me.mouseUpListener = function() {
            clearTimeout( me.timer );
            clearInterval( me.increaseTimer );
            me.props.setTime( type, me.state[ type ] );
            document.body.removeEventListener( 'mouseup', me.mouseUpListener );
         };
        me.timer = setTimeout(function() {
          me.increaseTimer = setInterval(function() {
            update[type] = me[action](type);
            me.setState(update);
          }, 70);
        }, 500);
         document.body.addEventListener( 'mouseup', me.mouseUpListener );
      };
   },
        me.mouseUpListener = function() {
          clearTimeout(me.timer);
          clearInterval(me.increaseTimer);
          me.props.setTime(type, me.state[type]);
          document.body.removeEventListener('mouseup', me.mouseUpListener);
        };
   disableContextMenu: function( event ) {
      event.preventDefault();
      return false;
   },
        document.body.addEventListener('mouseup', me.mouseUpListener);
      };
    },
   padValues: {
      hours: 1,
      minutes: 2,
      seconds: 2,
      milliseconds: 3
   },
    disableContextMenu: function(event) {
      event.preventDefault();
      return false;
    },
   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 );
   },
    padValues: {
      hours: 1,
      minutes: 2,
      seconds: 2,
      milliseconds: 3
    },
   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 );
   },
    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);
    },
   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 );
   },
    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);
    },
   pad: function( type, value ) {
      var str = value + '';
      while ( str.length < this.padValues[ type ] )
         str = '0' + str;
      return str;
   },
    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);
    },
   handleClickOutside: function() {
      this.props.handleClickOutside();
   }
}));
    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;