Commit 06b2a84839493c6d82610b8c9fcf5e88faed87d1
Committed by
GitHub
![](/assets/no_avatar-fd406ccede8cb1881f20921c8bfa169b.png)
Merge pull request #1580 from SergioCrisostomo/2.0
Time-Picker new feature: allow steps in lists
Showing
6 changed files
with
114 additions
and
38 deletions
Show diff stats
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 | +}; |
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 | +}); |