]> git.immae.eu Git - github/fretlink/time-picker.git/commitdiff
Merge branch 'shaleynikov-master'
authorafc163 <afc163@gmail.com>
Wed, 8 Mar 2017 07:00:31 +0000 (15:00 +0800)
committerafc163 <afc163@gmail.com>
Wed, 8 Mar 2017 07:00:31 +0000 (15:00 +0800)
README.md
examples/12hours.html [new file with mode: 0644]
examples/12hours.js [new file with mode: 0644]
src/Combobox.jsx
src/Panel.jsx
src/Select.jsx
src/TimePicker.jsx
tests/Select.spec.jsx

index 9ecbc945d99959c93bb1d0e65acb90bd9f80d174..d8a35b9c3a004440b4dbbe3c9192e51efad6e67b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -60,12 +60,13 @@ API
 | value                   | moment                            | null                                          | current value                                                                              |
 | placeholder             | String                            | ''                                            | time input's placeholder                                                                   |
 | showHour                | Boolean                           | whether show hour                             |                                                                                            |
-| showMinute                | Boolean                         | whether show minute                             |                                                                                            |
+| showMinute              | Boolean                           | whether show minute                             |                                                                                            |
 | showSecond              | Boolean                           | whether show second                           |                                                                                            |
 | format                  | String                            |                                               |                                                                                            |
 | disabledHours           | Function                          | disabled hour options                         |                                                                                            |
 | disabledMinutes         | Function                          | disabled minute options                       |                                                                                            |
 | disabledSeconds         | Function                          | disabled second options                       |                                                                                            |
+| use12Hours              | Boolean                           | 12 hours display mode                         |                                                                                            |
 | hideDisabledOptions     | Boolean                           | whether hide disabled options                 |                                                                                            |
 | onChange                | Function                          | null                                          | called when select a different value                                                       |
 | addon                   | Function                          | nothing                                       | called from timepicker panel to render some addon to its bottom, like an OK button. Receives panel instance as parameter, to be able to close it like `panel.close()`.|
diff --git a/examples/12hours.html b/examples/12hours.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/examples/12hours.js b/examples/12hours.js
new file mode 100644 (file)
index 0000000..72d6950
--- /dev/null
@@ -0,0 +1,30 @@
+/* eslint no-console:0 */
+
+import 'rc-time-picker/assets/index.less';
+
+import React from 'react';
+import ReactDom from 'react-dom';
+
+import moment from 'moment';
+
+import TimePicker from 'rc-time-picker';
+
+const format = 'h:mm a';
+
+const now = moment().hour(0).minute(0);
+
+function onChange(value) {
+  console.log(value && value.format(format));
+}
+
+ReactDom.render(
+  <TimePicker
+    showSecond={false}
+    defaultValue={now}
+    className="xxx"
+    onChange={onChange}
+    format={format}
+    use12Hours
+  />,
+  document.getElementById('__react-content')
+);
index 013617cbe75af9fb3c12432030f5057f2f9bbd10..36b61cca13712b78fe33f1977823daa8d5d5c815 100644 (file)
@@ -35,17 +35,40 @@ const Combobox = React.createClass({
     disabledMinutes: PropTypes.func,
     disabledSeconds: PropTypes.func,
     onCurrentSelectPanelChange: PropTypes.func,
+    use12Hours: PropTypes.bool,
   },
 
   onItemChange(type, itemValue) {
-    const { onChange, defaultOpenValue } = this.props;
+    const { onChange, defaultOpenValue, use12Hours } = this.props;
     const value = (this.props.value || defaultOpenValue).clone();
+
     if (type === 'hour') {
-      value.hour(itemValue);
+      if (use12Hours) {
+        if (this.isAM()) {
+          value.hour(+itemValue % 12);
+        } else {
+          value.hour((+itemValue % 12) + 12);
+        }
+      } else {
+        value.hour(+itemValue);
+      }
     } else if (type === 'minute') {
-      value.minute(itemValue);
+      value.minute(+itemValue);
+    } else if (type === 'ampm') {
+      const ampm = itemValue.toUpperCase();
+      if (use12Hours) {
+        if (ampm === 'PM' && value.hour() < 12) {
+          value.hour((value.hour() % 12) + 12);
+        }
+
+        if (ampm === 'AM') {
+          if (value.hour() >= 12) {
+            value.hour(value.hour() - 12);
+          }
+        }
+      }
     } else {
-      value.second(itemValue);
+      value.second(+itemValue);
     }
     onChange(value);
   },
@@ -55,17 +78,26 @@ const Combobox = React.createClass({
   },
 
   getHourSelect(hour) {
-    const { prefixCls, hourOptions, disabledHours, showHour } = this.props;
+    const { prefixCls, hourOptions, disabledHours, showHour, use12Hours } = this.props;
     if (!showHour) {
       return null;
     }
     const disabledOptions = disabledHours();
+    let hourOptionsAdj;
+    let hourAdj;
+    if (use12Hours) {
+      hourOptionsAdj = [12].concat(hourOptions.filter(h => h < 12 && h > 0));
+      hourAdj = (hour % 12) || 12;
+    } else {
+      hourOptionsAdj = hourOptions;
+      hourAdj = hour;
+    }
 
     return (
       <Select
         prefixCls={prefixCls}
-        options={hourOptions.map(option => formatOption(option, disabledOptions))}
-        selectedIndex={hourOptions.indexOf(hour)}
+        options={hourOptionsAdj.map(option => formatOption(option, disabledOptions))}
+        selectedIndex={hourOptionsAdj.indexOf(hourAdj)}
         type="hour"
         onSelect={this.onItemChange}
         onMouseEnter={this.onEnterSelectPanel.bind(this, 'hour')}
@@ -113,6 +145,35 @@ const Combobox = React.createClass({
     );
   },
 
+  getAMPMSelect() {
+    const { prefixCls, use12Hours, format } = this.props;
+    if (!use12Hours) {
+      return null;
+    }
+
+    const AMPMOptions = ['am', 'pm'] // If format has A char, then we should uppercase AM/PM
+                          .map(c => format.match(/\sA/) ? c.toUpperCase() : c)
+                          .map(c => ({ value: c }));
+
+    const selected = this.isAM() ? 0 : 1;
+
+    return (
+      <Select
+        prefixCls={prefixCls}
+        options={AMPMOptions}
+        selectedIndex={selected}
+        type="ampm"
+        onSelect={this.onItemChange}
+        onMouseEnter={this.onEnterSelectPanel.bind(this, 'ampm')}
+      />
+    );
+  },
+
+  isAM() {
+    const { value } = this.props;
+    return value.hour() >= 0 && value.hour() < 12;
+  },
+
   render() {
     const { prefixCls, defaultOpenValue } = this.props;
     const value = this.props.value || defaultOpenValue;
@@ -121,6 +182,7 @@ const Combobox = React.createClass({
         {this.getHourSelect(value.hour())}
         {this.getMinuteSelect(value.minute())}
         {this.getSecondSelect(value.second())}
+        {this.getAMPMSelect(value.hour())}
       </div>
     );
   },
index fddea1c09ddbc8fa591bd0847c7db1e7f23450a0..df128ff67d75741216952588899a005c570bb30f 100644 (file)
@@ -37,6 +37,7 @@ const Panel = React.createClass({
     showMinute: PropTypes.bool,
     showSecond: PropTypes.bool,
     onClear: PropTypes.func,
+    use12Hours: PropTypes.bool,
     addon: PropTypes.func,
   },
 
@@ -49,6 +50,7 @@ const Panel = React.createClass({
       disabledMinutes: noop,
       disabledSeconds: noop,
       defaultOpenValue: moment(),
+      use12Hours: false,
       addon: noop,
     };
   },
@@ -90,7 +92,7 @@ const Panel = React.createClass({
     const {
       prefixCls, className, placeholder, disabledHours, disabledMinutes,
       disabledSeconds, hideDisabledOptions, allowEmpty, showHour, showMinute, showSecond,
-      format, defaultOpenValue, clearText, onEsc, addon,
+      format, defaultOpenValue, clearText, onEsc, addon, use12Hours,
     } = this.props;
     const {
       value, currentSelectPanel,
@@ -140,6 +142,7 @@ const Panel = React.createClass({
           disabledMinutes={disabledMinutes}
           disabledSeconds={disabledSeconds}
           onCurrentSelectPanelChange={this.onCurrentSelectPanelChange}
+          use12Hours={use12Hours}
         />
         {addon(this)}
       </div>
index 238a776811cc913eb21feb389c17b40b91f3d6a5..5733b1a235b9348f94c5f7fac1b3f9c4109fba71 100644 (file)
@@ -58,7 +58,7 @@ const Select = React.createClass({
       });
       let onclick = null;
       if (!item.disabled) {
-        onclick = this.onSelect.bind(this, +item.value);
+        onclick = this.onSelect.bind(this, item.value);
       }
       return (<li
         className={cls}
index e9d6d15330a11fa26d6d8ca17bba0892648fae66..70653331185a61a7738d3383157806a45a4128e9 100644 (file)
@@ -43,6 +43,7 @@ const Picker = React.createClass({
     addon: PropTypes.func,
     name: PropTypes.string,
     autoComplete: PropTypes.string,
+    use12Hours: PropTypes.bool,
   },
 
   getDefaultProps() {
@@ -67,6 +68,7 @@ const Picker = React.createClass({
       onOpen: noop,
       onClose: noop,
       addon: noop,
+      use12Hours: false,
     };
   },
 
@@ -126,10 +128,21 @@ const Picker = React.createClass({
   },
 
   getFormat() {
-    const { format, showHour, showMinute, showSecond } = this.props;
+    const { format, showHour, showMinute, showSecond, use12Hours } = this.props;
     if (format) {
       return format;
     }
+
+    if (use12Hours) {
+      const fmtString = ([
+        showHour ? 'h' : '',
+        showMinute ? 'mm' : '',
+        showSecond ? 'ss' : '',
+      ].filter(item => !!item).join(':'));
+
+      return fmtString.concat(' a');
+    }
+
     return [
       showHour ? 'HH' : '',
       showMinute ? 'mm' : '',
@@ -142,7 +155,7 @@ const Picker = React.createClass({
       prefixCls, placeholder, disabledHours,
       disabledMinutes, disabledSeconds, hideDisabledOptions,
       allowEmpty, showHour, showMinute, showSecond, defaultOpenValue, clearText,
-      addon,
+      addon, use12Hours,
     } = this.props;
     return (
       <Panel
@@ -164,6 +177,7 @@ const Picker = React.createClass({
         disabledMinutes={disabledMinutes}
         disabledSeconds={disabledSeconds}
         hideDisabledOptions={hideDisabledOptions}
+        use12Hours={use12Hours}
         addon={addon}
       />
     );
index e6d32ddfd9d879c38395e7f69411567779152cb5..fd2ec326800dfb80d65058e99b8b571ee03d6529 100644 (file)
@@ -315,4 +315,180 @@ describe('Select', () => {
       });
     });
   });
+
+
+  describe('select in 12 hours mode', () => {
+    it('renders correctly', (done) => {
+      const picker = renderPicker({
+        use12Hours: true,
+        defaultValue: moment().hour(14).minute(0).second(0),
+        showSecond: false,
+        format: undefined,
+      });
+      expect(picker.state.open).not.to.be.ok();
+      const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+        'rc-time-picker-input')[0];
+      let selector;
+      async.series([(next) => {
+        expect(picker.state.open).to.be(false);
+
+        Simulate.click(input);
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(picker.state.open).to.be(true);
+        selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+          'rc-time-picker-panel-select');
+        expect((input).value).to.be('2:00 pm');
+
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(selector.length).to.be(3);
+
+        next();
+      }], () => {
+        done();
+      });
+    });
+
+
+    it('renders 12am correctly', (done) => {
+      const picker = renderPicker({
+        use12Hours: true,
+        defaultValue: moment().hour(0).minute(0).second(0),
+        showSecond: false,
+        format: undefined,
+      });
+      expect(picker.state.open).not.to.be.ok();
+      const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+        'rc-time-picker-input')[0];
+      let selector;
+      async.series([(next) => {
+        expect(picker.state.open).to.be(false);
+
+        Simulate.click(input);
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(picker.state.open).to.be(true);
+        selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+          'rc-time-picker-panel-select');
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(selector.length).to.be(3);
+
+        next();
+      }], () => {
+        done();
+      });
+    });
+
+
+    it('renders 5am correctly', (done) => {
+      const picker = renderPicker({
+        use12Hours: true,
+        defaultValue: moment().hour(0).minute(0).second(0),
+        showSecond: false,
+        format: undefined,
+      });
+      expect(picker.state.open).not.to.be.ok();
+      const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+        'rc-time-picker-input')[0];
+      let selector;
+      async.series([(next) => {
+        expect(picker.state.open).to.be(false);
+
+        Simulate.click(input);
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(picker.state.open).to.be(true);
+        selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+          'rc-time-picker-panel-select')[0];
+        expect((input).value).to.be('12:00 am');
+        const option = selector.getElementsByTagName('li')[3];
+        Simulate.click(option);
+        setTimeout(next, 100);
+      }, (next) => {
+        expect((input).value).to.be('3:00 am');
+        next();
+      }], () => {
+        done();
+      });
+    });
+
+
+    it('renders 12am/pm correctly', (done) => {
+      const picker = renderPicker({
+        use12Hours: true,
+        defaultValue: moment().hour(0).minute(0).second(0),
+        showSecond: false,
+        format: undefined,
+      });
+      expect(picker.state.open).not.to.be.ok();
+      const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+        'rc-time-picker-input')[0];
+      let selector;
+      async.series([(next) => {
+        expect(picker.state.open).to.be(false);
+
+        Simulate.click(input);
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(picker.state.open).to.be(true);
+        selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+          'rc-time-picker-panel-select')[2];
+        expect((input).value).to.be('12:00 am');
+        const option = selector.getElementsByTagName('li')[1];
+        Simulate.click(option);
+        setTimeout(next, 200);
+      }, (next) => {
+        expect((input).value).to.be('12:00 pm');
+        next();
+      }, (next) => {
+        Simulate.click(selector.getElementsByTagName('li')[0]);
+        setTimeout(next, 200);
+      }, (next) => {
+        expect((input).value).to.be('12:00 am');
+        next();
+      }], () => {
+        done();
+      });
+    });
+
+    it('renders uppercase AM correctly', (done) => {
+      const picker = renderPicker({
+        use12Hours: true,
+        defaultValue: moment().hour(0).minute(0).second(0),
+        showSecond: false,
+        format: 'h:mm A',
+      });
+      expect(picker.state.open).not.to.be.ok();
+      const input = TestUtils.scryRenderedDOMComponentsWithClass(picker,
+        'rc-time-picker-input')[0];
+      let selector;
+      async.series([(next) => {
+        expect(picker.state.open).to.be(false);
+
+        Simulate.click(input);
+        setTimeout(next, 100);
+      }, (next) => {
+        expect(picker.state.open).to.be(true);
+        selector = TestUtils.scryRenderedDOMComponentsWithClass(picker.panelInstance,
+          'rc-time-picker-panel-select')[2];
+        expect((input).value).to.be('12:00 AM');
+        const option = selector.getElementsByTagName('li')[1];
+        Simulate.click(option);
+        setTimeout(next, 200);
+      }, (next) => {
+        expect((input).value).to.be('12:00 PM');
+        next();
+      }, (next) => {
+        Simulate.click(selector.getElementsByTagName('li')[0]);
+        setTimeout(next, 200);
+      }, (next) => {
+        expect((input).value).to.be('12:00 AM');
+        next();
+      }], () => {
+        done();
+      });
+    });
+  });
 });