diff options
author | afc163 <afc163@gmail.com> | 2016-11-11 12:10:26 +0800 |
---|---|---|
committer | afc163 <afc163@gmail.com> | 2016-11-11 12:10:26 +0800 |
commit | 614f6c90232d890984d0f4f2f13ff41fdb144b27 (patch) | |
tree | ce1a9be06b3264fd9fc09b3c2b028646db03a322 /src | |
parent | cb5a445c75c7117c7c705d615099086274c2b254 (diff) | |
parent | f429b4a79df25c9eadc3901e2483716835cc7de7 (diff) | |
download | time-picker-614f6c90232d890984d0f4f2f13ff41fdb144b27.tar.gz time-picker-614f6c90232d890984d0f4f2f13ff41fdb144b27.tar.zst time-picker-614f6c90232d890984d0f4f2f13ff41fdb144b27.zip |
Merge branch 'master' of github.com:react-component/time-picker
Diffstat (limited to 'src')
-rw-r--r-- | src/Combobox.jsx (renamed from src/module/Combobox.jsx) | 54 | ||||
-rw-r--r-- | src/Header.jsx | 177 | ||||
-rw-r--r-- | src/Panel.jsx (renamed from src/module/Panel.jsx) | 57 | ||||
-rw-r--r-- | src/Select.jsx (renamed from src/module/Select.jsx) | 18 | ||||
-rw-r--r-- | src/TimePicker.jsx | 69 | ||||
-rw-r--r-- | src/locale/en_US.js | 8 | ||||
-rw-r--r-- | src/locale/ru_RU.js | 8 | ||||
-rw-r--r-- | src/locale/zh_CN.js | 8 | ||||
-rw-r--r-- | src/mixin/CommonMixin.js | 16 | ||||
-rw-r--r-- | src/module/Header.jsx | 204 | ||||
-rw-r--r-- | src/placements.js (renamed from src/util/placements.js) | 0 | ||||
-rw-r--r-- | src/util/index.js | 8 | ||||
-rw-r--r-- | src/util/selection.js | 17 |
13 files changed, 278 insertions, 366 deletions
diff --git a/src/module/Combobox.jsx b/src/Combobox.jsx index f1e7c5b..9d9da16 100644 --- a/src/module/Combobox.jsx +++ b/src/Combobox.jsx | |||
@@ -1,6 +1,5 @@ | |||
1 | import React, {PropTypes} from 'react'; | 1 | import React, { PropTypes } from 'react'; |
2 | import Select from './Select'; | 2 | import Select from './Select'; |
3 | import GregorianCalendar from 'gregorian-calendar'; | ||
4 | 3 | ||
5 | const formatOption = (option, disabledOptions) => { | 4 | const formatOption = (option, disabledOptions) => { |
6 | let value = `${option}`; | 5 | let value = `${option}`; |
@@ -21,12 +20,12 @@ const formatOption = (option, disabledOptions) => { | |||
21 | 20 | ||
22 | const Combobox = React.createClass({ | 21 | const Combobox = React.createClass({ |
23 | propTypes: { | 22 | propTypes: { |
24 | formatter: PropTypes.object, | 23 | format: PropTypes.string, |
24 | defaultOpenValue: PropTypes.object, | ||
25 | prefixCls: PropTypes.string, | 25 | prefixCls: PropTypes.string, |
26 | value: PropTypes.object, | 26 | value: PropTypes.object, |
27 | onChange: PropTypes.func, | 27 | onChange: PropTypes.func, |
28 | showHour: PropTypes.bool, | 28 | showHour: PropTypes.bool, |
29 | gregorianCalendarLocale: PropTypes.object, | ||
30 | showSecond: PropTypes.bool, | 29 | showSecond: PropTypes.bool, |
31 | hourOptions: PropTypes.array, | 30 | hourOptions: PropTypes.array, |
32 | minuteOptions: PropTypes.array, | 31 | minuteOptions: PropTypes.array, |
@@ -38,19 +37,14 @@ const Combobox = React.createClass({ | |||
38 | }, | 37 | }, |
39 | 38 | ||
40 | onItemChange(type, itemValue) { | 39 | onItemChange(type, itemValue) { |
41 | const { onChange } = this.props; | 40 | const { onChange, defaultOpenValue } = this.props; |
42 | let value = this.props.value; | 41 | const value = (this.props.value || defaultOpenValue).clone(); |
43 | if (value) { | ||
44 | value = value.clone(); | ||
45 | } else { | ||
46 | value = this.getNow().clone(); | ||
47 | } | ||
48 | if (type === 'hour') { | 42 | if (type === 'hour') { |
49 | value.setHourOfDay(itemValue); | 43 | value.hour(itemValue); |
50 | } else if (type === 'minute') { | 44 | } else if (type === 'minute') { |
51 | value.setMinutes(itemValue); | 45 | value.minute(itemValue); |
52 | } else { | 46 | } else { |
53 | value.setSeconds(itemValue); | 47 | value.second(itemValue); |
54 | } | 48 | } |
55 | onChange(value); | 49 | onChange(value); |
56 | }, | 50 | }, |
@@ -79,9 +73,9 @@ const Combobox = React.createClass({ | |||
79 | }, | 73 | }, |
80 | 74 | ||
81 | getMinuteSelect(minute) { | 75 | getMinuteSelect(minute) { |
82 | const { prefixCls, minuteOptions, disabledMinutes } = this.props; | 76 | const { prefixCls, minuteOptions, disabledMinutes, defaultOpenValue } = this.props; |
83 | const value = this.props.value || this.getNow(); | 77 | const value = this.props.value || defaultOpenValue; |
84 | const disabledOptions = disabledMinutes(value.getHourOfDay()); | 78 | const disabledOptions = disabledMinutes(value.hour()); |
85 | 79 | ||
86 | return ( | 80 | return ( |
87 | <Select | 81 | <Select |
@@ -96,12 +90,12 @@ const Combobox = React.createClass({ | |||
96 | }, | 90 | }, |
97 | 91 | ||
98 | getSecondSelect(second) { | 92 | getSecondSelect(second) { |
99 | const { prefixCls, secondOptions, disabledSeconds, showSecond } = this.props; | 93 | const { prefixCls, secondOptions, disabledSeconds, showSecond, defaultOpenValue } = this.props; |
100 | if (!showSecond) { | 94 | if (!showSecond) { |
101 | return null; | 95 | return null; |
102 | } | 96 | } |
103 | const value = this.props.value || this.getNow(); | 97 | const value = this.props.value || defaultOpenValue; |
104 | const disabledOptions = disabledSeconds(value.getHourOfDay(), value.getMinutes()); | 98 | const disabledOptions = disabledSeconds(value.hour(), value.minute()); |
105 | 99 | ||
106 | return ( | 100 | return ( |
107 | <Select | 101 | <Select |
@@ -115,24 +109,14 @@ const Combobox = React.createClass({ | |||
115 | ); | 109 | ); |
116 | }, | 110 | }, |
117 | 111 | ||
118 | getNow() { | ||
119 | if (this.showNow) { | ||
120 | return this.showNow; | ||
121 | } | ||
122 | const value = new GregorianCalendar(this.props.gregorianCalendarLocale); | ||
123 | value.setTime(Date.now()); | ||
124 | this.showNow = value; | ||
125 | return value; | ||
126 | }, | ||
127 | |||
128 | render() { | 112 | render() { |
129 | const { prefixCls } = this.props; | 113 | const { prefixCls, defaultOpenValue } = this.props; |
130 | const value = this.props.value || this.getNow(); | 114 | const value = this.props.value || defaultOpenValue; |
131 | return ( | 115 | return ( |
132 | <div className={`${prefixCls}-combobox`}> | 116 | <div className={`${prefixCls}-combobox`}> |
133 | {this.getHourSelect(value.getHourOfDay())} | 117 | {this.getHourSelect(value.hour())} |
134 | {this.getMinuteSelect(value.getMinutes())} | 118 | {this.getMinuteSelect(value.minute())} |
135 | {this.getSecondSelect(value.getSeconds())} | 119 | {this.getSecondSelect(value.second())} |
136 | </div> | 120 | </div> |
137 | ); | 121 | ); |
138 | }, | 122 | }, |
diff --git a/src/Header.jsx b/src/Header.jsx new file mode 100644 index 0000000..2ef9827 --- /dev/null +++ b/src/Header.jsx | |||
@@ -0,0 +1,177 @@ | |||
1 | import React, { PropTypes } from 'react'; | ||
2 | import moment from 'moment'; | ||
3 | |||
4 | const Header = React.createClass({ | ||
5 | propTypes: { | ||
6 | format: PropTypes.string, | ||
7 | prefixCls: PropTypes.string, | ||
8 | disabledDate: PropTypes.func, | ||
9 | placeholder: PropTypes.string, | ||
10 | clearText: PropTypes.string, | ||
11 | value: PropTypes.object, | ||
12 | hourOptions: PropTypes.array, | ||
13 | minuteOptions: PropTypes.array, | ||
14 | secondOptions: PropTypes.array, | ||
15 | disabledHours: PropTypes.func, | ||
16 | disabledMinutes: PropTypes.func, | ||
17 | disabledSeconds: PropTypes.func, | ||
18 | onChange: PropTypes.func, | ||
19 | onClear: PropTypes.func, | ||
20 | onEsc: PropTypes.func, | ||
21 | allowEmpty: PropTypes.bool, | ||
22 | defaultOpenValue: PropTypes.object, | ||
23 | currentSelectPanel: PropTypes.string, | ||
24 | }, | ||
25 | |||
26 | getInitialState() { | ||
27 | const { value, format } = this.props; | ||
28 | return { | ||
29 | str: value && value.format(format) || '', | ||
30 | invalid: false, | ||
31 | }; | ||
32 | }, | ||
33 | |||
34 | componentWillReceiveProps(nextProps) { | ||
35 | const { value, format } = nextProps; | ||
36 | this.setState({ | ||
37 | str: value && value.format(format) || '', | ||
38 | invalid: false, | ||
39 | }); | ||
40 | }, | ||
41 | |||
42 | onInputChange(event) { | ||
43 | const str = event.target.value; | ||
44 | this.setState({ | ||
45 | str, | ||
46 | }); | ||
47 | const { | ||
48 | format, hourOptions, minuteOptions, secondOptions, | ||
49 | disabledHours, disabledMinutes, | ||
50 | disabledSeconds, onChange, allowEmpty, | ||
51 | } = this.props; | ||
52 | |||
53 | if (str) { | ||
54 | const originalValue = this.props.value; | ||
55 | const value = this.getProtoValue().clone(); | ||
56 | const parsed = moment(str, format, true); | ||
57 | if (!parsed.isValid()) { | ||
58 | this.setState({ | ||
59 | invalid: true, | ||
60 | }); | ||
61 | return; | ||
62 | } | ||
63 | value.hour(parsed.hour()).minute(parsed.minute()).second(parsed.second()); | ||
64 | |||
65 | // if time value not allowed, response warning. | ||
66 | if ( | ||
67 | hourOptions.indexOf(value.hour()) < 0 || | ||
68 | minuteOptions.indexOf(value.minute()) < 0 || | ||
69 | secondOptions.indexOf(value.second()) < 0 | ||
70 | ) { | ||
71 | this.setState({ | ||
72 | invalid: true, | ||
73 | }); | ||
74 | return; | ||
75 | } | ||
76 | |||
77 | // if time value is disabled, response warning. | ||
78 | const disabledHourOptions = disabledHours(); | ||
79 | const disabledMinuteOptions = disabledMinutes(value.hour()); | ||
80 | const disabledSecondOptions = disabledSeconds(value.hour(), value.minute()); | ||
81 | if ( | ||
82 | (disabledHourOptions && disabledHourOptions.indexOf(value.hour()) >= 0) || | ||
83 | (disabledMinuteOptions && disabledMinuteOptions.indexOf(value.minute()) >= 0) || | ||
84 | (disabledSecondOptions && disabledSecondOptions.indexOf(value.second()) >= 0) | ||
85 | ) { | ||
86 | this.setState({ | ||
87 | invalid: true, | ||
88 | }); | ||
89 | return; | ||
90 | } | ||
91 | |||
92 | if (originalValue) { | ||
93 | if ( | ||
94 | originalValue.hour() !== value.hour() || | ||
95 | originalValue.minute() !== value.minute() || | ||
96 | originalValue.second() !== value.second() | ||
97 | ) { | ||
98 | // keep other fields for rc-calendar | ||
99 | const changedValue = originalValue.clone(); | ||
100 | changedValue.hour(value.hour()); | ||
101 | changedValue.minute(value.minute()); | ||
102 | changedValue.second(value.second()); | ||
103 | onChange(changedValue); | ||
104 | } | ||
105 | } else if (originalValue !== value) { | ||
106 | onChange(value); | ||
107 | } | ||
108 | } else if (allowEmpty) { | ||
109 | onChange(null); | ||
110 | } else { | ||
111 | this.setState({ | ||
112 | invalid: true, | ||
113 | }); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | this.setState({ | ||
118 | invalid: false, | ||
119 | }); | ||
120 | }, | ||
121 | |||
122 | onKeyDown(e) { | ||
123 | if (e.keyCode === 27) { | ||
124 | this.props.onEsc(); | ||
125 | } | ||
126 | }, | ||
127 | |||
128 | onClear() { | ||
129 | this.setState({ str: '' }); | ||
130 | this.props.onClear(); | ||
131 | }, | ||
132 | |||
133 | getClearButton() { | ||
134 | const { prefixCls, allowEmpty } = this.props; | ||
135 | if (!allowEmpty) { | ||
136 | return null; | ||
137 | } | ||
138 | return (<a | ||
139 | className={`${prefixCls}-clear-btn`} | ||
140 | role="button" | ||
141 | title={this.props.clearText} | ||
142 | onMouseDown={this.onClear} | ||
143 | />); | ||
144 | }, | ||
145 | |||
146 | getProtoValue() { | ||
147 | return this.props.value || this.props.defaultOpenValue; | ||
148 | }, | ||
149 | |||
150 | getInput() { | ||
151 | const { prefixCls, placeholder } = this.props; | ||
152 | const { invalid, str } = this.state; | ||
153 | const invalidClass = invalid ? `${prefixCls}-input-invalid` : ''; | ||
154 | return ( | ||
155 | <input | ||
156 | className={`${prefixCls}-input ${invalidClass}`} | ||
157 | ref="input" | ||
158 | onKeyDown={this.onKeyDown} | ||
159 | value={str} | ||
160 | placeholder={placeholder} | ||
161 | onChange={this.onInputChange} | ||
162 | /> | ||
163 | ); | ||
164 | }, | ||
165 | |||
166 | render() { | ||
167 | const { prefixCls } = this.props; | ||
168 | return ( | ||
169 | <div className={`${prefixCls}-input-wrap`}> | ||
170 | {this.getInput()} | ||
171 | {this.getClearButton()} | ||
172 | </div> | ||
173 | ); | ||
174 | }, | ||
175 | }); | ||
176 | |||
177 | export default Header; | ||
diff --git a/src/module/Panel.jsx b/src/Panel.jsx index 4c3d071..0ed60e9 100644 --- a/src/module/Panel.jsx +++ b/src/Panel.jsx | |||
@@ -1,7 +1,8 @@ | |||
1 | import React, {PropTypes} from 'react'; | 1 | import React, { PropTypes } from 'react'; |
2 | import CommonMixin from '../mixin/CommonMixin'; | ||
3 | import Header from './Header'; | 2 | import Header from './Header'; |
4 | import Combobox from './Combobox'; | 3 | import Combobox from './Combobox'; |
4 | import moment from 'moment'; | ||
5 | import classNames from 'classnames'; | ||
5 | 6 | ||
6 | function noop() { | 7 | function noop() { |
7 | } | 8 | } |
@@ -18,12 +19,13 @@ function generateOptions(length, disabledOptions, hideDisabledOptions) { | |||
18 | 19 | ||
19 | const Panel = React.createClass({ | 20 | const Panel = React.createClass({ |
20 | propTypes: { | 21 | propTypes: { |
22 | clearText: PropTypes.string, | ||
21 | prefixCls: PropTypes.string, | 23 | prefixCls: PropTypes.string, |
24 | className: PropTypes.string, | ||
25 | defaultOpenValue: PropTypes.object, | ||
22 | value: PropTypes.object, | 26 | value: PropTypes.object, |
23 | locale: PropTypes.object, | ||
24 | placeholder: PropTypes.string, | 27 | placeholder: PropTypes.string, |
25 | gregorianCalendarLocale: PropTypes.object, | 28 | format: PropTypes.string, |
26 | formatter: PropTypes.object, | ||
27 | disabledHours: PropTypes.func, | 29 | disabledHours: PropTypes.func, |
28 | disabledMinutes: PropTypes.func, | 30 | disabledMinutes: PropTypes.func, |
29 | disabledSeconds: PropTypes.func, | 31 | disabledSeconds: PropTypes.func, |
@@ -34,14 +36,19 @@ const Panel = React.createClass({ | |||
34 | showHour: PropTypes.bool, | 36 | showHour: PropTypes.bool, |
35 | showSecond: PropTypes.bool, | 37 | showSecond: PropTypes.bool, |
36 | onClear: PropTypes.func, | 38 | onClear: PropTypes.func, |
39 | addon: PropTypes.func, | ||
37 | }, | 40 | }, |
38 | 41 | ||
39 | mixins: [CommonMixin], | ||
40 | |||
41 | getDefaultProps() { | 42 | getDefaultProps() { |
42 | return { | 43 | return { |
44 | prefixCls: 'rc-time-picker-panel', | ||
43 | onChange: noop, | 45 | onChange: noop, |
44 | onClear: noop, | 46 | onClear: noop, |
47 | disabledHours: noop, | ||
48 | disabledMinutes: noop, | ||
49 | disabledSeconds: noop, | ||
50 | defaultOpenValue: moment(), | ||
51 | addon: noop, | ||
45 | }; | 52 | }; |
46 | }, | 53 | }, |
47 | 54 | ||
@@ -74,26 +81,37 @@ const Panel = React.createClass({ | |||
74 | this.setState({ currentSelectPanel }); | 81 | this.setState({ currentSelectPanel }); |
75 | }, | 82 | }, |
76 | 83 | ||
84 | close() { | ||
85 | this.props.onEsc(); | ||
86 | }, | ||
87 | |||
77 | render() { | 88 | render() { |
78 | const { locale, prefixCls, placeholder, disabledHours, disabledMinutes, disabledSeconds, hideDisabledOptions, allowEmpty, showHour, showSecond, formatter, gregorianCalendarLocale } = this.props; | 89 | const { |
79 | const value = this.state.value; | 90 | prefixCls, className, placeholder, disabledHours, disabledMinutes, |
91 | disabledSeconds, hideDisabledOptions, allowEmpty, showHour, showSecond, | ||
92 | format, defaultOpenValue, clearText, onEsc, addon, | ||
93 | } = this.props; | ||
94 | const { | ||
95 | value, currentSelectPanel, | ||
96 | } = this.state; | ||
80 | const disabledHourOptions = disabledHours(); | 97 | const disabledHourOptions = disabledHours(); |
81 | const disabledMinuteOptions = disabledMinutes(value ? value.getHourOfDay() : null); | 98 | const disabledMinuteOptions = disabledMinutes(value ? value.hour() : null); |
82 | const disabledSecondOptions = disabledSeconds(value ? value.getHourOfDay() : null, value ? value.getMinutes() : null); | 99 | const disabledSecondOptions = disabledSeconds(value ? value.hour() : null, |
100 | value ? value.minute() : null); | ||
83 | const hourOptions = generateOptions(24, disabledHourOptions, hideDisabledOptions); | 101 | const hourOptions = generateOptions(24, disabledHourOptions, hideDisabledOptions); |
84 | const minuteOptions = generateOptions(60, disabledMinuteOptions, hideDisabledOptions); | 102 | const minuteOptions = generateOptions(60, disabledMinuteOptions, hideDisabledOptions); |
85 | const secondOptions = generateOptions(60, disabledSecondOptions, hideDisabledOptions); | 103 | const secondOptions = generateOptions(60, disabledSecondOptions, hideDisabledOptions); |
86 | 104 | ||
87 | return ( | 105 | return ( |
88 | <div className={`${prefixCls}-inner`}> | 106 | <div className={classNames({ [`${prefixCls}-inner`]: true, [className]: !!className })}> |
89 | <Header | 107 | <Header |
108 | clearText={clearText} | ||
90 | prefixCls={prefixCls} | 109 | prefixCls={prefixCls} |
91 | gregorianCalendarLocale={gregorianCalendarLocale} | 110 | defaultOpenValue={defaultOpenValue} |
92 | locale={locale} | ||
93 | value={value} | 111 | value={value} |
94 | currentSelectPanel={this.state.currentSelectPanel} | 112 | currentSelectPanel={currentSelectPanel} |
95 | onEsc={this.props.onEsc} | 113 | onEsc={onEsc} |
96 | formatter={formatter} | 114 | format={format} |
97 | placeholder={placeholder} | 115 | placeholder={placeholder} |
98 | hourOptions={hourOptions} | 116 | hourOptions={hourOptions} |
99 | minuteOptions={minuteOptions} | 117 | minuteOptions={minuteOptions} |
@@ -108,8 +126,8 @@ const Panel = React.createClass({ | |||
108 | <Combobox | 126 | <Combobox |
109 | prefixCls={prefixCls} | 127 | prefixCls={prefixCls} |
110 | value={value} | 128 | value={value} |
111 | gregorianCalendarLocale={gregorianCalendarLocale} | 129 | defaultOpenValue={defaultOpenValue} |
112 | formatter={formatter} | 130 | format={format} |
113 | onChange={this.onChange} | 131 | onChange={this.onChange} |
114 | showHour={showHour} | 132 | showHour={showHour} |
115 | showSecond={showSecond} | 133 | showSecond={showSecond} |
@@ -121,6 +139,7 @@ const Panel = React.createClass({ | |||
121 | disabledSeconds={disabledSeconds} | 139 | disabledSeconds={disabledSeconds} |
122 | onCurrentSelectPanelChange={this.onCurrentSelectPanelChange} | 140 | onCurrentSelectPanelChange={this.onCurrentSelectPanelChange} |
123 | /> | 141 | /> |
142 | {addon(this)} | ||
124 | </div> | 143 | </div> |
125 | ); | 144 | ); |
126 | }, | 145 | }, |
diff --git a/src/module/Select.jsx b/src/Select.jsx index fa4e5c4..238a776 100644 --- a/src/module/Select.jsx +++ b/src/Select.jsx | |||
@@ -1,4 +1,4 @@ | |||
1 | import React, {PropTypes} from 'react'; | 1 | import React, { PropTypes } from 'react'; |
2 | import ReactDom from 'react-dom'; | 2 | import ReactDom from 'react-dom'; |
3 | import classnames from 'classnames'; | 3 | import classnames from 'classnames'; |
4 | 4 | ||
@@ -26,7 +26,6 @@ const Select = React.createClass({ | |||
26 | propTypes: { | 26 | propTypes: { |
27 | prefixCls: PropTypes.string, | 27 | prefixCls: PropTypes.string, |
28 | options: PropTypes.array, | 28 | options: PropTypes.array, |
29 | gregorianCalendarLocale: PropTypes.object, | ||
30 | selectedIndex: PropTypes.number, | 29 | selectedIndex: PropTypes.number, |
31 | type: PropTypes.string, | 30 | type: PropTypes.string, |
32 | onSelect: PropTypes.func, | 31 | onSelect: PropTypes.func, |
@@ -61,7 +60,14 @@ const Select = React.createClass({ | |||
61 | if (!item.disabled) { | 60 | if (!item.disabled) { |
62 | onclick = this.onSelect.bind(this, +item.value); | 61 | onclick = this.onSelect.bind(this, +item.value); |
63 | } | 62 | } |
64 | return <li className={cls} key={index} onClick={onclick} disabled={item.disabled}>{item.value}</li>; | 63 | return (<li |
64 | className={cls} | ||
65 | key={index} | ||
66 | onClick={onclick} | ||
67 | disabled={item.disabled} | ||
68 | > | ||
69 | {item.value} | ||
70 | </li>); | ||
65 | }); | 71 | }); |
66 | }, | 72 | }, |
67 | 73 | ||
@@ -89,8 +95,10 @@ const Select = React.createClass({ | |||
89 | const { prefixCls } = this.props; | 95 | const { prefixCls } = this.props; |
90 | 96 | ||
91 | return ( | 97 | return ( |
92 | <div className={`${prefixCls}-select`} | 98 | <div |
93 | onMouseEnter={this.props.onMouseEnter}> | 99 | className={`${prefixCls}-select`} |
100 | onMouseEnter={this.props.onMouseEnter} | ||
101 | > | ||
94 | <ul ref="list">{this.getOptions()}</ul> | 102 | <ul ref="list">{this.getOptions()}</ul> |
95 | </div> | 103 | </div> |
96 | ); | 104 | ); |
diff --git a/src/TimePicker.jsx b/src/TimePicker.jsx index 350eeb2..358b596 100644 --- a/src/TimePicker.jsx +++ b/src/TimePicker.jsx | |||
@@ -1,9 +1,8 @@ | |||
1 | import React, { PropTypes } from 'react'; | 1 | import React, { PropTypes } from 'react'; |
2 | import Trigger from 'rc-trigger'; | 2 | import Trigger from 'rc-trigger'; |
3 | import Panel from './module/Panel'; | 3 | import Panel from './Panel'; |
4 | import placements from './util/placements'; | 4 | import placements from './placements'; |
5 | import CommonMixin from './mixin/CommonMixin'; | 5 | import moment from 'moment'; |
6 | import { getFormatter } from './util/index'; | ||
7 | 6 | ||
8 | function noop() { | 7 | function noop() { |
9 | } | 8 | } |
@@ -15,8 +14,9 @@ function refFn(field, component) { | |||
15 | const Picker = React.createClass({ | 14 | const Picker = React.createClass({ |
16 | propTypes: { | 15 | propTypes: { |
17 | prefixCls: PropTypes.string, | 16 | prefixCls: PropTypes.string, |
18 | locale: PropTypes.object, | 17 | clearText: PropTypes.string, |
19 | value: PropTypes.object, | 18 | value: PropTypes.object, |
19 | defaultOpenValue: PropTypes.object, | ||
20 | disabled: PropTypes.bool, | 20 | disabled: PropTypes.bool, |
21 | allowEmpty: PropTypes.bool, | 21 | allowEmpty: PropTypes.bool, |
22 | defaultValue: PropTypes.object, | 22 | defaultValue: PropTypes.object, |
@@ -27,7 +27,7 @@ const Picker = React.createClass({ | |||
27 | transitionName: PropTypes.string, | 27 | transitionName: PropTypes.string, |
28 | getPopupContainer: PropTypes.func, | 28 | getPopupContainer: PropTypes.func, |
29 | placeholder: PropTypes.string, | 29 | placeholder: PropTypes.string, |
30 | formatter: PropTypes.any, | 30 | format: PropTypes.string, |
31 | showHour: PropTypes.bool, | 31 | showHour: PropTypes.bool, |
32 | style: PropTypes.object, | 32 | style: PropTypes.object, |
33 | className: PropTypes.string, | 33 | className: PropTypes.string, |
@@ -39,16 +39,18 @@ const Picker = React.createClass({ | |||
39 | onChange: PropTypes.func, | 39 | onChange: PropTypes.func, |
40 | onOpen: PropTypes.func, | 40 | onOpen: PropTypes.func, |
41 | onClose: PropTypes.func, | 41 | onClose: PropTypes.func, |
42 | addon: PropTypes.func, | ||
42 | }, | 43 | }, |
43 | 44 | ||
44 | mixins: [CommonMixin], | ||
45 | |||
46 | getDefaultProps() { | 45 | getDefaultProps() { |
47 | return { | 46 | return { |
47 | clearText: 'clear', | ||
48 | prefixCls: 'rc-time-picker', | ||
48 | defaultOpen: false, | 49 | defaultOpen: false, |
49 | style: {}, | 50 | style: {}, |
50 | className: '', | 51 | className: '', |
51 | align: {}, | 52 | align: {}, |
53 | defaultOpenValue: moment(), | ||
52 | allowEmpty: true, | 54 | allowEmpty: true, |
53 | showHour: true, | 55 | showHour: true, |
54 | showSecond: true, | 56 | showSecond: true, |
@@ -60,6 +62,7 @@ const Picker = React.createClass({ | |||
60 | onChange: noop, | 62 | onChange: noop, |
61 | onOpen: noop, | 63 | onOpen: noop, |
62 | onClose: noop, | 64 | onClose: noop, |
65 | addon: noop, | ||
63 | }; | 66 | }; |
64 | }, | 67 | }, |
65 | 68 | ||
@@ -117,61 +120,47 @@ const Picker = React.createClass({ | |||
117 | this.props.onChange(value); | 120 | this.props.onChange(value); |
118 | }, | 121 | }, |
119 | 122 | ||
120 | getFormatter() { | 123 | getFormat() { |
121 | const formatter = this.props.formatter; | 124 | const format = this.props.format; |
122 | const locale = this.props.locale; | 125 | if (format) { |
123 | if (formatter) { | 126 | return format; |
124 | if (formatter === this.lastFormatter) { | ||
125 | return this.normalFormatter; | ||
126 | } | ||
127 | this.normalFormatter = getFormatter(formatter, locale); | ||
128 | this.lastFormatter = formatter; | ||
129 | return this.normalFormatter; | ||
130 | } | 127 | } |
131 | if (!this.props.showSecond) { | 128 | if (!this.props.showSecond) { |
132 | if (!this.notShowSecondFormatter) { | 129 | return 'HH:mm'; |
133 | this.notShowSecondFormatter = getFormatter('HH:mm', locale); | ||
134 | } | ||
135 | return this.notShowSecondFormatter; | ||
136 | } | 130 | } |
137 | if (!this.props.showHour) { | 131 | if (!this.props.showHour) { |
138 | if (!this.notShowHourFormatter) { | 132 | return 'mm:ss'; |
139 | this.notShowHourFormatter = getFormatter('mm:ss', locale); | ||
140 | } | ||
141 | return this.notShowHourFormatter; | ||
142 | } | 133 | } |
143 | if (!this.normalFormatter) { | 134 | return 'HH:mm:ss'; |
144 | this.normalFormatter = getFormatter('HH:mm:ss', locale); | ||
145 | } | ||
146 | return this.normalFormatter; | ||
147 | }, | 135 | }, |
148 | 136 | ||
149 | getPanelElement() { | 137 | getPanelElement() { |
150 | const { | 138 | const { |
151 | prefixCls, defaultValue, locale, placeholder, disabledHours, | 139 | prefixCls, placeholder, disabledHours, |
152 | disabledMinutes, disabledSeconds, hideDisabledOptions, | 140 | disabledMinutes, disabledSeconds, hideDisabledOptions, |
153 | allowEmpty, showHour, showSecond, | 141 | allowEmpty, showHour, showSecond, defaultOpenValue, clearText, |
142 | addon, | ||
154 | } = this.props; | 143 | } = this.props; |
155 | return ( | 144 | return ( |
156 | <Panel | 145 | <Panel |
146 | clearText={clearText} | ||
157 | prefixCls={`${prefixCls}-panel`} | 147 | prefixCls={`${prefixCls}-panel`} |
158 | ref={this.savePanelRef} | 148 | ref={this.savePanelRef} |
159 | value={this.state.value} | 149 | value={this.state.value} |
160 | onChange={this.onPanelChange} | 150 | onChange={this.onPanelChange} |
161 | gregorianCalendarLocale={locale.calendar} | ||
162 | onClear={this.onPanelClear} | 151 | onClear={this.onPanelClear} |
163 | defaultValue={defaultValue} | 152 | defaultOpenValue={defaultOpenValue} |
164 | showHour={showHour} | 153 | showHour={showHour} |
165 | onEsc={this.onEsc} | 154 | onEsc={this.onEsc} |
166 | showSecond={showSecond} | 155 | showSecond={showSecond} |
167 | locale={locale} | ||
168 | allowEmpty={allowEmpty} | 156 | allowEmpty={allowEmpty} |
169 | formatter={this.getFormatter()} | 157 | format={this.getFormat()} |
170 | placeholder={placeholder} | 158 | placeholder={placeholder} |
171 | disabledHours={disabledHours} | 159 | disabledHours={disabledHours} |
172 | disabledMinutes={disabledMinutes} | 160 | disabledMinutes={disabledMinutes} |
173 | disabledSeconds={disabledSeconds} | 161 | disabledSeconds={disabledSeconds} |
174 | hideDisabledOptions={hideDisabledOptions} | 162 | hideDisabledOptions={hideDisabledOptions} |
163 | addon={addon} | ||
175 | /> | 164 | /> |
176 | ); | 165 | ); |
177 | }, | 166 | }, |
@@ -194,7 +183,11 @@ const Picker = React.createClass({ | |||
194 | }, | 183 | }, |
195 | 184 | ||
196 | render() { | 185 | render() { |
197 | const { prefixCls, placeholder, placement, align, disabled, transitionName, style, className, showHour, showSecond, getPopupContainer } = this.props; | 186 | const { |
187 | prefixCls, placeholder, placement, align, | ||
188 | disabled, transitionName, style, className, showHour, | ||
189 | showSecond, getPopupContainer, | ||
190 | } = this.props; | ||
198 | const { open, value } = this.state; | 191 | const { open, value } = this.state; |
199 | let popupClassName; | 192 | let popupClassName; |
200 | if (!showHour || !showSecond) { | 193 | if (!showHour || !showSecond) { |
@@ -221,7 +214,7 @@ const Picker = React.createClass({ | |||
221 | ref="picker" type="text" placeholder={placeholder} | 214 | ref="picker" type="text" placeholder={placeholder} |
222 | readOnly | 215 | readOnly |
223 | onKeyDown={this.onKeyDown} | 216 | onKeyDown={this.onKeyDown} |
224 | disabled={disabled} value={value && this.getFormatter().format(value) || ''} | 217 | disabled={disabled} value={value && value.format(this.getFormat()) || ''} |
225 | /> | 218 | /> |
226 | <span className={`${prefixCls}-icon`}/> | 219 | <span className={`${prefixCls}-icon`}/> |
227 | </span> | 220 | </span> |
diff --git a/src/locale/en_US.js b/src/locale/en_US.js deleted file mode 100644 index 506f4c9..0000000 --- a/src/locale/en_US.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | import enUs from 'gregorian-calendar-format/lib/locale/en_US'; | ||
2 | import enUsCalendar from 'gregorian-calendar/lib/locale/en_US'; | ||
3 | |||
4 | export default { | ||
5 | clear: 'Clear', | ||
6 | format: enUs, | ||
7 | calendar: enUsCalendar, | ||
8 | }; | ||
diff --git a/src/locale/ru_RU.js b/src/locale/ru_RU.js deleted file mode 100644 index 86746ea..0000000 --- a/src/locale/ru_RU.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | import ruRu from 'gregorian-calendar-format/lib/locale/ru_RU'; | ||
2 | import ruRuCalendar from 'gregorian-calendar/lib/locale/ru_RU'; | ||
3 | |||
4 | export default { | ||
5 | clear: 'Очистить', | ||
6 | format: ruRu, | ||
7 | calendar: ruRuCalendar, | ||
8 | }; | ||
diff --git a/src/locale/zh_CN.js b/src/locale/zh_CN.js deleted file mode 100644 index 1e977be..0000000 --- a/src/locale/zh_CN.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | import zhCn from 'gregorian-calendar-format/lib/locale/zh_CN'; | ||
2 | import zhCnCalendar from 'gregorian-calendar/lib/locale/zh_CN'; | ||
3 | |||
4 | export default { | ||
5 | clear: '清除', | ||
6 | format: zhCn, | ||
7 | calendar: zhCnCalendar, | ||
8 | }; | ||
diff --git a/src/mixin/CommonMixin.js b/src/mixin/CommonMixin.js deleted file mode 100644 index a6893b8..0000000 --- a/src/mixin/CommonMixin.js +++ /dev/null | |||
@@ -1,16 +0,0 @@ | |||
1 | import {PropTypes} from 'react'; | ||
2 | import enUs from '../locale/en_US'; | ||
3 | |||
4 | export default { | ||
5 | propTypes: { | ||
6 | prefixCls: PropTypes.string, | ||
7 | locale: PropTypes.object, | ||
8 | }, | ||
9 | |||
10 | getDefaultProps() { | ||
11 | return { | ||
12 | prefixCls: 'rc-time-picker', | ||
13 | locale: enUs, | ||
14 | }; | ||
15 | }, | ||
16 | }; | ||
diff --git a/src/module/Header.jsx b/src/module/Header.jsx deleted file mode 100644 index a926e98..0000000 --- a/src/module/Header.jsx +++ /dev/null | |||
@@ -1,204 +0,0 @@ | |||
1 | import React, { PropTypes } from 'react'; | ||
2 | import createSelection from '../util/selection'; | ||
3 | |||
4 | const Header = React.createClass({ | ||
5 | propTypes: { | ||
6 | formatter: PropTypes.object, | ||
7 | prefixCls: PropTypes.string, | ||
8 | gregorianCalendarLocale: PropTypes.object, | ||
9 | locale: PropTypes.object, | ||
10 | disabledDate: PropTypes.func, | ||
11 | placeholder: 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 | currentSelectPanel: PropTypes.string, | ||
24 | }, | ||
25 | |||
26 | getInitialState() { | ||
27 | const value = this.props.value; | ||
28 | return { | ||
29 | str: value && this.props.formatter.format(value) || '', | ||
30 | invalid: false, | ||
31 | }; | ||
32 | }, | ||
33 | |||
34 | componentDidMount() { | ||
35 | this.timer = setTimeout(this.selectRange, 0); | ||
36 | }, | ||
37 | |||
38 | componentWillReceiveProps(nextProps) { | ||
39 | const value = nextProps.value; | ||
40 | this.setState({ | ||
41 | str: value && nextProps.formatter.format(value) || '', | ||
42 | invalid: false, | ||
43 | }); | ||
44 | }, | ||
45 | |||
46 | componentDidUpdate() { | ||
47 | this.timer = setTimeout(this.selectRange, 0); | ||
48 | }, | ||
49 | |||
50 | componentWillUnmount() { | ||
51 | clearTimeout(this.timer); | ||
52 | }, | ||
53 | |||
54 | onInputChange(event) { | ||
55 | const str = event.target.value; | ||
56 | this.setState({ | ||
57 | str, | ||
58 | }); | ||
59 | let value = null; | ||
60 | const { formatter, gregorianCalendarLocale, hourOptions, minuteOptions, secondOptions, disabledHours, disabledMinutes, disabledSeconds, onChange, allowEmpty } = this.props; | ||
61 | |||
62 | if (str) { | ||
63 | const originalValue = this.props.value; | ||
64 | try { | ||
65 | value = formatter.parse(str, { | ||
66 | locale: gregorianCalendarLocale, | ||
67 | obeyCount: true, | ||
68 | }); | ||
69 | } catch (ex) { | ||
70 | this.setState({ | ||
71 | invalid: true, | ||
72 | }); | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | if (value) { | ||
77 | // if time value not allowed, response warning. | ||
78 | if ( | ||
79 | hourOptions.indexOf(value.getHourOfDay()) < 0 || | ||
80 | minuteOptions.indexOf(value.getMinutes()) < 0 || | ||
81 | secondOptions.indexOf(value.getSeconds()) < 0 | ||
82 | ) { | ||
83 | this.setState({ | ||
84 | invalid: true, | ||
85 | }); | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | // if time value is disabled, response warning. | ||
90 | const disabledHourOptions = disabledHours(); | ||
91 | const disabledMinuteOptions = disabledMinutes(value.getHourOfDay()); | ||
92 | const disabledSecondOptions = disabledSeconds(value.getHourOfDay(), value.getMinutes()); | ||
93 | if ( | ||
94 | (disabledHourOptions && disabledHourOptions.indexOf(value.getHourOfDay()) >= 0) || | ||
95 | (disabledMinuteOptions && disabledMinuteOptions.indexOf(value.getMinutes()) >= 0) || | ||
96 | (disabledSecondOptions && disabledSecondOptions.indexOf(value.getSeconds()) >= 0) | ||
97 | ) { | ||
98 | this.setState({ | ||
99 | invalid: true, | ||
100 | }); | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | if (originalValue && value) { | ||
105 | if ( | ||
106 | originalValue.getHourOfDay() !== value.getHourOfDay() || | ||
107 | originalValue.getMinutes() !== value.getMinutes() || | ||
108 | originalValue.getSeconds() !== value.getSeconds() | ||
109 | ) { | ||
110 | // keep other fields for rc-calendar | ||
111 | const changedValue = originalValue.clone(); | ||
112 | changedValue.setHourOfDay(value.getHourOfDay()); | ||
113 | changedValue.setMinutes(value.getMinutes()); | ||
114 | changedValue.setSeconds(value.getSeconds()); | ||
115 | onChange(changedValue); | ||
116 | } | ||
117 | } else if (originalValue !== value) { | ||
118 | onChange(value); | ||
119 | } | ||
120 | } else { | ||
121 | this.setState({ | ||
122 | invalid: true, | ||
123 | }); | ||
124 | return; | ||
125 | } | ||
126 | } else if (allowEmpty) { | ||
127 | onChange(null); | ||
128 | } else { | ||
129 | this.setState({ | ||
130 | invalid: true, | ||
131 | }); | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | this.setState({ | ||
136 | invalid: false, | ||
137 | }); | ||
138 | }, | ||
139 | |||
140 | onKeyDown(e) { | ||
141 | if (e.keyCode === 27) { | ||
142 | this.props.onEsc(); | ||
143 | } | ||
144 | }, | ||
145 | |||
146 | onClear() { | ||
147 | this.setState({ str: '' }); | ||
148 | this.props.onClear(); | ||
149 | }, | ||
150 | |||
151 | getClearButton() { | ||
152 | const { locale, prefixCls, allowEmpty } = this.props; | ||
153 | if (!allowEmpty) { | ||
154 | return null; | ||
155 | } | ||
156 | return <a className={`${prefixCls}-clear-btn`} role="button" title={locale.clear} onMouseDown={this.onClear}/>; | ||
157 | }, | ||
158 | |||
159 | getInput() { | ||
160 | const { prefixCls, placeholder } = this.props; | ||
161 | const { invalid, str } = this.state; | ||
162 | const invalidClass = invalid ? `${prefixCls}-input-invalid` : ''; | ||
163 | return (<input | ||
164 | className={`${prefixCls}-input ${invalidClass}`} | ||
165 | ref="input" | ||
166 | onKeyDown={this.onKeyDown} | ||
167 | value={str} | ||
168 | placeholder={placeholder} onChange={this.onInputChange} | ||
169 | />); | ||
170 | }, | ||
171 | |||
172 | selectRange() { | ||
173 | this.refs.input.select(); | ||
174 | if (this.props.currentSelectPanel && this.refs.input.value) { | ||
175 | let selectionRangeStart = 0; | ||
176 | let selectionRangeEnd = 0; | ||
177 | if (this.props.currentSelectPanel === 'hour') { | ||
178 | selectionRangeStart = 0; | ||
179 | selectionRangeEnd = this.refs.input.value.indexOf(':'); | ||
180 | } else if (this.props.currentSelectPanel === 'minute') { | ||
181 | selectionRangeStart = this.refs.input.value.indexOf(':') + 1; | ||
182 | selectionRangeEnd = this.refs.input.value.lastIndexOf(':'); | ||
183 | } else if (this.props.currentSelectPanel === 'second') { | ||
184 | selectionRangeStart = this.refs.input.value.lastIndexOf(':') + 1; | ||
185 | selectionRangeEnd = this.refs.input.value.length; | ||
186 | } | ||
187 | if (selectionRangeEnd - selectionRangeStart === 2) { | ||
188 | createSelection(this.refs.input, selectionRangeStart, selectionRangeEnd); | ||
189 | } | ||
190 | } | ||
191 | }, | ||
192 | |||
193 | render() { | ||
194 | const { prefixCls } = this.props; | ||
195 | return ( | ||
196 | <div className={`${prefixCls}-input-wrap`}> | ||
197 | {this.getInput()} | ||
198 | {this.getClearButton()} | ||
199 | </div> | ||
200 | ); | ||
201 | }, | ||
202 | }); | ||
203 | |||
204 | export default Header; | ||
diff --git a/src/util/placements.js b/src/placements.js index 6760286..6760286 100644 --- a/src/util/placements.js +++ b/src/placements.js | |||
diff --git a/src/util/index.js b/src/util/index.js deleted file mode 100644 index 5bc0a78..0000000 --- a/src/util/index.js +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | import DateTimeFormat from 'gregorian-calendar-format'; | ||
2 | |||
3 | export function getFormatter(format, locale) { | ||
4 | if (typeof format === 'string') { | ||
5 | return new DateTimeFormat(format, locale.format); | ||
6 | } | ||
7 | return format; | ||
8 | } | ||
diff --git a/src/util/selection.js b/src/util/selection.js deleted file mode 100644 index 395901e..0000000 --- a/src/util/selection.js +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | export default function createSelection(field, start, end) { | ||
2 | if (field.createTextRange) { | ||
3 | const selRange = field.createTextRange(); | ||
4 | selRange.collapse(true); | ||
5 | selRange.moveStart('character', start); | ||
6 | selRange.moveEnd('character', end); | ||
7 | selRange.select(); | ||
8 | field.focus(); | ||
9 | } else if (field.setSelectionRange) { | ||
10 | field.focus(); | ||
11 | field.setSelectionRange(start, end); | ||
12 | } else if (typeof field.selectionStart !== 'undefined') { | ||
13 | field.selectionStart = start; | ||
14 | field.selectionEnd = end; | ||
15 | field.focus(); | ||
16 | } | ||
17 | } | ||