Home Reference Source Repository

src/components/picker/InlineTimePicker.js

/**
 * @author haw
 */

import React, {
  PropTypes,
  Component
} from 'react';
import Options from './Options';
import {
  classNames,
  generateOptions,
  indexOfOptions
} from '../util';

const prefix = 'picker-body';

/**
 * 內联时间选择器
 */
export default class InlineTimePicker extends Component {

  /**
   * 构造函数
   * @param {Object} props 组件所使用的属性
   * @param {string} [props.selectedTime] 当前选中的日期
   * @param {string} [props.minDate='00:00:00'] 最小可选择的日期
   * @param {string} [props.maxDate='23:59:59'] 最大可选择的日期
   * @param {string} [props.hourUnit=''] 小时的单位文案
   * @param {string} [props.minuteUnit=''] 分钟的单位文案
   * @param {string} [props.secondUnit=''] 秒的单位文案
   * @param {function} props.onChange 选中某一个项时触发的函数回调
   * @param {Object} context
   */
  constructor(props, context) {
    super(props, context);
  }

  _setHours = (hourOptions, selectedIndex) => {
    const value = hourOptions[selectedIndex].value;

    this.onChange(value, 'hours');
  };

  _setMinutes = (minuteOptions, selectedIndex) => {
    const value = minuteOptions[selectedIndex].value;

    this.onChange(value, 'minutes');
  };

  _setSeconds = (secondOptions, selectedIndex) => {
    const value = secondOptions[selectedIndex].value;

    this.onChange(value, 'seconds');
  };

  onChange(value, key) {
    const {
      onChange,
      selectedTime
    } = this.props;
    let time = parseTime(selectedTime);
    time[key] = value;
    const newTime = formatTime(time);

    onChange && onChange(newTime);
  }

  render() {
    let {
      selectedTime,
      maxTime,
      minTime,
      hourUnit,
      minuteUnit,
      secondUnit,
      className,
      ...rest
    } = this.props;
    const clazz = classNames(prefix, {
      [className]: className
    });
    const selectedTimeObj = parseTime(selectedTime);
    const maxTimeObj = parseTime(maxTime);
    const minTimeObj = parseTime(minTime);
    const hourOptions = createHourOptions(maxTimeObj, minTimeObj, hourUnit);
    const minuteOptions = createMinuteOptions(maxTimeObj, minTimeObj,
      selectedTimeObj, minuteUnit);
    const secondOptions = createSecondOptions(maxTimeObj, minTimeObj,
      selectedTimeObj, secondUnit);
    const hoursIndex = indexOfOptions(selectedTimeObj.hours, hourOptions);
    const minutesIndex = indexOfOptions(selectedTimeObj.minutes, minuteOptions);
    const secondsIndex = indexOfOptions(selectedTimeObj.seconds, secondOptions);

    return (
      <div className={clazz} {...rest}>
        <Options
          selectedIndex={hoursIndex}
          options={hourOptions}
          key={'hours'}
          onChange={this._setHours.bind(this, hourOptions)}
        />
        <Options
          selectedIndex={minutesIndex}
          options={minuteOptions}
          key={'minutes'}
          onChange={this._setMinutes.bind(this, minuteOptions)}
        />
        <Options
          selectedIndex={secondsIndex}
          options={secondOptions}
          key={'seconds'}
          onChange={this._setSeconds.bind(this, secondOptions)}
        />
      </div>
    );
  }
}

function formatTime(timeObj) {
  let hours = add0(timeObj.hours);
  let minutes = add0(timeObj.minutes);
  let seconds = add0(timeObj.seconds);

  return `${hours}:${minutes}:${seconds}`;
}

function add0(value) {
  return value < 10 ? `0${value}` : value;
}

function createHourOptions(maxTimeObj, minTimeObj, hourUnit) {
  return generateOptions(maxTimeObj.hours, minTimeObj.hours, hourUnit);
}

function createMinuteOptions(maxTimeObj, minTimeObj, selectedTimeObj, minuteUnit) {
  const max = isEqualHour(maxTimeObj, selectedTimeObj) ? maxTimeObj.minutes : 59;
  const min = isEqualHour(minTimeObj, selectedTimeObj) ? minTimeObj.minutes : 0;

  return generateOptions(max, min, minuteUnit);
}

function createSecondOptions(maxTimeObj, minTimeObj, selectedTimeObj, secondUnit) {
  const max = isEqualHourMinute(maxTimeObj, selectedTimeObj) ? maxTimeObj.minutes : 59;
  const min = isEqualHourMinute(minTimeObj, selectedTimeObj) ? minTimeObj.minutes : 0;

  return generateOptions(max, min, secondUnit);
}

function isEqualHour(t1, t2) {
  return t1.hours === t2.hours;
}

function isEqualHourMinute(t1, t2) {
  return isEqualHour(t1, t2) && t1.minutes === t2.minutes;
}

function parseTime(time) {
  const times = time.split(':');

  return {
    hours: parseInt(times[0]),
    minutes: parseInt(times[1]),
    seconds: parseInt(times[2])
  };
}

InlineTimePicker.propTypes = {
  selectedTime: PropTypes.string.isRequired,
  minTime: PropTypes.string,
  maxTime: PropTypes.string,
  hourUnit: PropTypes.string,
  minuteUnit: PropTypes.string,
  secondUnit: PropTypes.string,
  onChange: PropTypes.func,
  className: PropTypes.string
};

InlineTimePicker.defaultProps = {
  minTime: '00:00:00',
  maxTime: '23:59:59',
  hourUnit: '',
  minuteUnit: '',
  secondUnit: ''
};