]> git.immae.eu Git - github/fretlink/time-picker.git/blob - src/Header.jsx
9e80a9ccd18e738161a44838767e166c35717352
[github/fretlink/time-picker.git] / src / Header.jsx
1 import React, { Component } from 'react';
2 import PropTypes from 'prop-types';
3 import moment from 'moment';
4
5 class Header extends Component {
6 static propTypes = {
7 format: PropTypes.string,
8 prefixCls: PropTypes.string,
9 disabledDate: PropTypes.func,
10 placeholder: PropTypes.string,
11 clearText: PropTypes.string,
12 value: PropTypes.object,
13 hourOptions: PropTypes.array,
14 minuteOptions: PropTypes.array,
15 secondOptions: PropTypes.array,
16 disabledHours: PropTypes.func,
17 disabledMinutes: PropTypes.func,
18 disabledSeconds: PropTypes.func,
19 onChange: PropTypes.func,
20 onClear: PropTypes.func,
21 onEsc: PropTypes.func,
22 allowEmpty: PropTypes.bool,
23 defaultOpenValue: PropTypes.object,
24 currentSelectPanel: PropTypes.string,
25 focusOnOpen: PropTypes.bool,
26 };
27
28 constructor(props) {
29 super(props);
30 const { value, format } = props;
31 this.state = {
32 str: value && value.format(format) || '',
33 invalid: false,
34 };
35 }
36
37 componentDidMount() {
38 if (this.props.focusOnOpen) {
39 // Wait one frame for the panel to be positioned before focusing
40 const requestAnimationFrame = (window.requestAnimationFrame || window.setTimeout);
41 requestAnimationFrame(() => this.refs.input.focus());
42 }
43 }
44
45 componentWillReceiveProps(nextProps) {
46 const { value, format } = nextProps;
47 this.setState({
48 str: value && value.format(format) || '',
49 invalid: false,
50 });
51 }
52
53 onInputChange = (event) => {
54 const str = event.target.value;
55 this.setState({
56 str,
57 });
58 const {
59 format, hourOptions, minuteOptions, secondOptions,
60 disabledHours, disabledMinutes,
61 disabledSeconds, onChange, allowEmpty,
62 } = this.props;
63
64 if (str) {
65 const originalValue = this.props.value;
66 const value = this.getProtoValue().clone();
67 const parsed = moment(str, format, true);
68 if (!parsed.isValid()) {
69 this.setState({
70 invalid: true,
71 });
72 return;
73 }
74 value.hour(parsed.hour()).minute(parsed.minute()).second(parsed.second());
75
76 // if time value not allowed, response warning.
77 if (
78 hourOptions.indexOf(value.hour()) < 0 ||
79 minuteOptions.indexOf(value.minute()) < 0 ||
80 secondOptions.indexOf(value.second()) < 0
81 ) {
82 this.setState({
83 invalid: true,
84 });
85 return;
86 }
87
88 // if time value is disabled, response warning.
89 const disabledHourOptions = disabledHours();
90 const disabledMinuteOptions = disabledMinutes(value.hour());
91 const disabledSecondOptions = disabledSeconds(value.hour(), value.minute());
92 if (
93 (disabledHourOptions && disabledHourOptions.indexOf(value.hour()) >= 0) ||
94 (disabledMinuteOptions && disabledMinuteOptions.indexOf(value.minute()) >= 0) ||
95 (disabledSecondOptions && disabledSecondOptions.indexOf(value.second()) >= 0)
96 ) {
97 this.setState({
98 invalid: true,
99 });
100 return;
101 }
102
103 if (originalValue) {
104 if (
105 originalValue.hour() !== value.hour() ||
106 originalValue.minute() !== value.minute() ||
107 originalValue.second() !== value.second()
108 ) {
109 // keep other fields for rc-calendar
110 const changedValue = originalValue.clone();
111 changedValue.hour(value.hour());
112 changedValue.minute(value.minute());
113 changedValue.second(value.second());
114 onChange(changedValue);
115 }
116 } else if (originalValue !== value) {
117 onChange(value);
118 }
119 } else if (allowEmpty) {
120 onChange(null);
121 } else {
122 this.setState({
123 invalid: true,
124 });
125 return;
126 }
127
128 this.setState({
129 invalid: false,
130 });
131 }
132
133 onKeyDown = (e) => {
134 if (e.keyCode === 27) {
135 this.props.onEsc();
136 }
137 }
138
139 onClear = () => {
140 this.setState({ str: '' });
141 this.props.onClear();
142 }
143
144 getClearButton() {
145 const { prefixCls, allowEmpty } = this.props;
146 if (!allowEmpty) {
147 return null;
148 }
149 return (<a
150 className={`${prefixCls}-clear-btn`}
151 role="button"
152 title={this.props.clearText}
153 onMouseDown={this.onClear}
154 />);
155 }
156
157 getProtoValue() {
158 return this.props.value || this.props.defaultOpenValue;
159 }
160
161 getInput() {
162 const { prefixCls, placeholder } = this.props;
163 const { invalid, str } = this.state;
164 const invalidClass = invalid ? `${prefixCls}-input-invalid` : '';
165 return (
166 <input
167 className={`${prefixCls}-input ${invalidClass}`}
168 ref="input"
169 onKeyDown={this.onKeyDown}
170 value={str}
171 placeholder={placeholder}
172 onChange={this.onInputChange}
173 />
174 );
175 }
176
177 render() {
178 const { prefixCls } = this.props;
179 return (
180 <div className={`${prefixCls}-input-wrap`}>
181 {this.getInput()}
182 {this.getClearButton()}
183 </div>
184 );
185 }
186 }
187
188 export default Header;