Commit 06b2a84839493c6d82610b8c9fcf5e88faed87d1

Authored by Aresn
Committed by GitHub
2 parents 2ffa16c4 fe5108cd

Merge pull request #1580 from SergioCrisostomo/2.0

Time-Picker new feature: allow steps in lists
src/components/date-picker/base/time-spinner.vue
1 <template> 1 <template>
2 <div :class="classes"> 2 <div :class="classes">
3 <div :class="[prefixCls+ '-list']" ref="hours"> 3 <div :class="[prefixCls+ '-list']" ref="hours">
4 - <ul :class="[prefixCls + '-ul']" @click="handleClickHours">  
5 - <li :class="getCellCls(item)" v-for="(item, index) in hoursList" v-show="!item.hide" :index="index">{{ formatTime(item.text) }}</li> 4 + <ul :class="[prefixCls + '-ul']">
  5 + <li :class="getCellCls(item)" v-for="item in hoursList" v-show="!item.hide" @click="handleClick('hours', item)">{{ formatTime(item.text) }}</li>
6 </ul> 6 </ul>
7 </div> 7 </div>
8 <div :class="[prefixCls+ '-list']" ref="minutes"> 8 <div :class="[prefixCls+ '-list']" ref="minutes">
9 - <ul :class="[prefixCls + '-ul']" @click="handleClickMinutes">  
10 - <li :class="getCellCls(item)" v-for="(item, index) in minutesList" v-show="!item.hide" :index="index">{{ formatTime(item.text) }}</li> 9 + <ul :class="[prefixCls + '-ul']">
  10 + <li :class="getCellCls(item)" v-for="item in minutesList" v-show="!item.hide" @click="handleClick('minutes', item)">{{ formatTime(item.text) }}</li>
11 </ul> 11 </ul>
12 </div> 12 </div>
13 <div :class="[prefixCls+ '-list']" v-show="showSeconds" ref="seconds"> 13 <div :class="[prefixCls+ '-list']" v-show="showSeconds" ref="seconds">
14 - <ul :class="[prefixCls + '-ul']" @click="handleClickSeconds">  
15 - <li :class="getCellCls(item)" v-for="(item, index) in secondsList" v-show="!item.hide" :index="index">{{ formatTime(item.text) }}</li> 14 + <ul :class="[prefixCls + '-ul']">
  15 + <li :class="getCellCls(item)" v-for="item in secondsList" v-show="!item.hide" @click="handleClick('seconds', item)">{{ formatTime(item.text) }}</li>
16 </ul> 16 </ul>
17 </div> 17 </div>
18 </div> 18 </div>
@@ -41,10 +41,15 @@ @@ -41,10 +41,15 @@
41 showSeconds: { 41 showSeconds: {
42 type: Boolean, 42 type: Boolean,
43 default: true 43 default: true
  44 + },
  45 + steps: {
  46 + type: Array,
  47 + default: () => []
44 } 48 }
45 }, 49 },
46 data () { 50 data () {
47 return { 51 return {
  52 + spinerSteps: [1, 1, 1].map((one, i) => Math.abs(this.steps[i]) || one),
48 prefixCls: prefixCls, 53 prefixCls: prefixCls,
49 compiled: false 54 compiled: false
50 }; 55 };
@@ -60,6 +65,7 @@ @@ -60,6 +65,7 @@
60 }, 65 },
61 hoursList () { 66 hoursList () {
62 let hours = []; 67 let hours = [];
  68 + const step = this.spinerSteps[0];
63 const hour_tmpl = { 69 const hour_tmpl = {
64 text: 0, 70 text: 0,
65 selected: false, 71 selected: false,
@@ -67,7 +73,7 @@ @@ -67,7 +73,7 @@
67 hide: false 73 hide: false
68 }; 74 };
69 75
70 - for (let i = 0; i < 24; i++) { 76 + for (let i = 0; i < 24; i += step) {
71 const hour = deepCopy(hour_tmpl); 77 const hour = deepCopy(hour_tmpl);
72 hour.text = i; 78 hour.text = i;
73 79
@@ -83,6 +89,7 @@ @@ -83,6 +89,7 @@
83 }, 89 },
84 minutesList () { 90 minutesList () {
85 let minutes = []; 91 let minutes = [];
  92 + const step = this.spinerSteps[1];
86 const minute_tmpl = { 93 const minute_tmpl = {
87 text: 0, 94 text: 0,
88 selected: false, 95 selected: false,
@@ -90,7 +97,7 @@ @@ -90,7 +97,7 @@
90 hide: false 97 hide: false
91 }; 98 };
92 99
93 - for (let i = 0; i < 60; i++) { 100 + for (let i = 0; i < 60; i += step) {
94 const minute = deepCopy(minute_tmpl); 101 const minute = deepCopy(minute_tmpl);
95 minute.text = i; 102 minute.text = i;
96 103
@@ -101,11 +108,11 @@ @@ -101,11 +108,11 @@
101 if (this.minutes === i) minute.selected = true; 108 if (this.minutes === i) minute.selected = true;
102 minutes.push(minute); 109 minutes.push(minute);
103 } 110 }
104 -  
105 return minutes; 111 return minutes;
106 }, 112 },
107 secondsList () { 113 secondsList () {
108 let seconds = []; 114 let seconds = [];
  115 + const step = this.spinerSteps[2];
109 const second_tmpl = { 116 const second_tmpl = {
110 text: 0, 117 text: 0,
111 selected: false, 118 selected: false,
@@ -113,7 +120,7 @@ @@ -113,7 +120,7 @@
113 hide: false 120 hide: false
114 }; 121 };
115 122
116 - for (let i = 0; i < 60; i++) { 123 + for (let i = 0; i < 60; i += step) {
117 const second = deepCopy(second_tmpl); 124 const second = deepCopy(second_tmpl);
118 second.text = i; 125 second.text = i;
119 126
@@ -138,24 +145,11 @@ @@ -138,24 +145,11 @@
138 } 145 }
139 ]; 146 ];
140 }, 147 },
141 - handleClickHours (event) {  
142 - this.handleClick('hours', event);  
143 - },  
144 - handleClickMinutes (event) {  
145 - this.handleClick('minutes', event);  
146 - },  
147 - handleClickSeconds (event) {  
148 - this.handleClick('seconds', event);  
149 - },  
150 - handleClick (type, event) {  
151 - const target = event.target;  
152 - if (target.tagName === 'LI') {  
153 - const cell = this[`${type}List`][parseInt(event.target.getAttribute('index'))];  
154 - if (cell.disabled) return;  
155 - const data = {};  
156 - data[type] = cell.text;  
157 - this.$emit('on-change', data);  
158 - } 148 + handleClick (type, cell) {
  149 + if (cell.disabled) return;
  150 + const data = {};
  151 + data[type] = cell.text;
  152 + this.$emit('on-change', data);
159 this.$emit('on-pick-click'); 153 this.$emit('on-pick-click');
160 }, 154 },
161 scroll (type, index) { 155 scroll (type, index) {
@@ -183,20 +177,24 @@ @@ -183,20 +177,24 @@
183 }, 177 },
184 formatTime (text) { 178 formatTime (text) {
185 return text < 10 ? '0' + text : text; 179 return text < 10 ? '0' + text : text;
  180 + },
  181 + getItemIndex(type, val){
  182 + const item = this[`${type}List`].find(obj => obj.text == val);
  183 + return this[`${type}List`].indexOf(item);
186 } 184 }
187 }, 185 },
188 watch: { 186 watch: {
189 hours (val) { 187 hours (val) {
190 if (!this.compiled) return; 188 if (!this.compiled) return;
191 - this.scroll('hours', val); 189 + this.scroll('hours', this.getItemIndex('hours', val));
192 }, 190 },
193 minutes (val) { 191 minutes (val) {
194 if (!this.compiled) return; 192 if (!this.compiled) return;
195 - this.scroll('minutes', val); 193 + this.scroll('minutes', this.getItemIndex('minutes', val));
196 }, 194 },
197 seconds (val) { 195 seconds (val) {
198 if (!this.compiled) return; 196 if (!this.compiled) return;
199 - this.scroll('seconds', val); 197 + this.scroll('seconds', this.getItemIndex('seconds', val));
200 } 198 }
201 }, 199 },
202 mounted () { 200 mounted () {
@@ -204,4 +202,4 @@ @@ -204,4 +202,4 @@
204 this.$nextTick(() => this.compiled = true); 202 this.$nextTick(() => this.compiled = true);
205 } 203 }
206 }; 204 };
207 -</script>  
208 \ No newline at end of file 205 \ No newline at end of file
  206 +</script>
src/components/date-picker/panel/time.vue
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 <time-spinner 6 <time-spinner
7 ref="timeSpinner" 7 ref="timeSpinner"
8 :show-seconds="showSeconds" 8 :show-seconds="showSeconds"
  9 + :steps="steps"
9 :hours="hours" 10 :hours="hours"
10 :minutes="minutes" 11 :minutes="minutes"
11 :seconds="seconds" 12 :seconds="seconds"
@@ -39,6 +40,12 @@ @@ -39,6 +40,12 @@
39 name: 'TimePicker', 40 name: 'TimePicker',
40 mixins: [ Mixin, Locale ], 41 mixins: [ Mixin, Locale ],
41 components: { TimeSpinner, Confirm }, 42 components: { TimeSpinner, Confirm },
  43 + props: {
  44 + steps: {
  45 + type: Array,
  46 + default: () => []
  47 + }
  48 + },
42 data () { 49 data () {
43 return { 50 return {
44 prefixCls: prefixCls, 51 prefixCls: prefixCls,
@@ -113,4 +120,4 @@ @@ -113,4 +120,4 @@
113 if (this.$parent && this.$parent.$options.name === 'DatePicker') this.showDate = true; 120 if (this.$parent && this.$parent.$options.name === 'DatePicker') this.showDate = true;
114 } 121 }
115 }; 122 };
116 -</script>  
117 \ No newline at end of file 123 \ No newline at end of file
  124 +</script>
src/components/date-picker/picker.vue
@@ -32,7 +32,6 @@ @@ -32,7 +32,6 @@
32 </div> 32 </div>
33 </template> 33 </template>
34 <script> 34 <script>
35 - import Vue from 'vue';  
36 import iInput from '../../components/input/input.vue'; 35 import iInput from '../../components/input/input.vue';
37 import Drop from '../../components/select/dropdown.vue'; 36 import Drop from '../../components/select/dropdown.vue';
38 import clickoutside from '../../directives/clickoutside'; 37 import clickoutside from '../../directives/clickoutside';
@@ -397,7 +396,7 @@ @@ -397,7 +396,7 @@
397 let isConfirm = this.confirm; 396 let isConfirm = this.confirm;
398 const type = this.type; 397 const type = this.type;
399 398
400 - this.picker = new Vue(this.panel).$mount(this.$refs.picker); 399 + this.picker = this.Panel.$mount(this.$refs.picker);
401 if (type === 'datetime' || type === 'datetimerange') { 400 if (type === 'datetime' || type === 'datetimerange') {
402 isConfirm = true; 401 isConfirm = true;
403 this.picker.showTime = true; 402 this.picker.showTime = true;
src/components/date-picker/picker/date-picker.js
  1 +import Vue from 'vue';
1 import Picker from '../picker.vue'; 2 import Picker from '../picker.vue';
2 import DatePanel from '../panel/date.vue'; 3 import DatePanel from '../panel/date.vue';
3 import DateRangePanel from '../panel/date-range.vue'; 4 import DateRangePanel from '../panel/date-range.vue';
@@ -31,6 +32,7 @@ export default { @@ -31,6 +32,7 @@ export default {
31 } 32 }
32 } 33 }
33 34
34 - this.panel = getPanel(this.type); 35 + const panel = getPanel(this.type);
  36 + this.Panel = new Vue(panel);
35 } 37 }
36 }; 38 };
src/components/date-picker/picker/time-picker.js
  1 +import Vue from 'vue';
1 import Picker from '../picker.vue'; 2 import Picker from '../picker.vue';
2 import TimePanel from '../panel/time.vue'; 3 import TimePanel from '../panel/time.vue';
3 import TimeRangePanel from '../panel/time-range.vue'; 4 import TimeRangePanel from '../panel/time-range.vue';
@@ -21,6 +22,10 @@ export default { @@ -21,6 +22,10 @@ export default {
21 }, 22 },
22 default: 'time' 23 default: 'time'
23 }, 24 },
  25 + steps: {
  26 + type: Array,
  27 + default: () => []
  28 + },
24 value: {} 29 value: {}
25 }, 30 },
26 created () { 31 created () {
@@ -31,6 +36,11 @@ export default { @@ -31,6 +36,11 @@ export default {
31 this.currentValue = ''; 36 this.currentValue = '';
32 } 37 }
33 } 38 }
34 - this.panel = getPanel(this.type); 39 + const Panel = Vue.extend(getPanel(this.type));
  40 + this.Panel = new Panel({
  41 + propsData: {
  42 + steps: this.steps
  43 + }
  44 + });
35 } 45 }
36 -};  
37 \ No newline at end of file 46 \ No newline at end of file
  47 +};
test/unit/specs/time-spinner.spec.js 0 → 100644
  1 +import { createVue, destroyVM } from '../util';
  2 +
  3 +describe('TimePicker.vue', () => {
  4 + let vm;
  5 + afterEach(() => {
  6 + destroyVM(vm);
  7 + });
  8 +
  9 + it('should create a TimePicker component with hours, minutes and seconds', done => {
  10 + vm = createVue(`
  11 + <Time-Picker></Time-Picker>
  12 + `);
  13 + const picker = vm.$children[0];
  14 + picker.handleIconClick(); // open the picker panels
  15 +
  16 + vm.$nextTick(() => {
  17 + const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
  18 + expect(spiners.length).to.equal(3); // hh:mm:ss
  19 + expect(spiners[0].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(24);
  20 + expect(spiners[1].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
  21 + expect(spiners[2].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
  22 + done();
  23 + });
  24 + });
  25 +
  26 + it('should create a TimePicker component with only hours and minutes', done => {
  27 + vm = createVue(`
  28 + <Time-Picker format="HH:mm"></Time-Picker>
  29 + `);
  30 + const picker = vm.$children[0];
  31 + picker.handleIconClick(); // open the picker panels
  32 +
  33 + vm.$nextTick(() => {
  34 + const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
  35 + expect([...spiners].filter(el => el.style.display != 'none').length).to.equal(2); // hh:mm
  36 + expect(spiners[0].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(24);
  37 + expect(spiners[1].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
  38 + done();
  39 + });
  40 + });
  41 +
  42 + it('should create a TimePicker component with steps of 15 minutes', done => {
  43 + vm = createVue(`
  44 + <Time-Picker :steps="[1, 15]"></Time-Picker>
  45 + `);
  46 + const picker = vm.$children[0];
  47 + picker.handleIconClick(); // open the picker panels
  48 +
  49 + vm.$nextTick(() => {
  50 + const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
  51 + const minutesList = [...spiners[1].querySelectorAll('.ivu-time-picker-cells-cell')];
  52 +
  53 + expect(spiners[0].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(24);
  54 + expect(minutesList.map(el => el.textContent).join(',')).to.equal('00,15,30,45');
  55 + expect(spiners[1].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(4);
  56 + expect(spiners[2].querySelectorAll('.ivu-time-picker-cells-cell').length).to.equal(60);
  57 + done();
  58 + });
  59 + });
  60 +});