Commit 06b2a84839493c6d82610b8c9fcf5e88faed87d1
Committed by
GitHub
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 | 1 | <template> |
2 | 2 | <div :class="classes"> |
3 | 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 | 6 | </ul> |
7 | 7 | </div> |
8 | 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 | 11 | </ul> |
12 | 12 | </div> |
13 | 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 | 16 | </ul> |
17 | 17 | </div> |
18 | 18 | </div> |
... | ... | @@ -41,10 +41,15 @@ |
41 | 41 | showSeconds: { |
42 | 42 | type: Boolean, |
43 | 43 | default: true |
44 | + }, | |
45 | + steps: { | |
46 | + type: Array, | |
47 | + default: () => [] | |
44 | 48 | } |
45 | 49 | }, |
46 | 50 | data () { |
47 | 51 | return { |
52 | + spinerSteps: [1, 1, 1].map((one, i) => Math.abs(this.steps[i]) || one), | |
48 | 53 | prefixCls: prefixCls, |
49 | 54 | compiled: false |
50 | 55 | }; |
... | ... | @@ -60,6 +65,7 @@ |
60 | 65 | }, |
61 | 66 | hoursList () { |
62 | 67 | let hours = []; |
68 | + const step = this.spinerSteps[0]; | |
63 | 69 | const hour_tmpl = { |
64 | 70 | text: 0, |
65 | 71 | selected: false, |
... | ... | @@ -67,7 +73,7 @@ |
67 | 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 | 77 | const hour = deepCopy(hour_tmpl); |
72 | 78 | hour.text = i; |
73 | 79 | |
... | ... | @@ -83,6 +89,7 @@ |
83 | 89 | }, |
84 | 90 | minutesList () { |
85 | 91 | let minutes = []; |
92 | + const step = this.spinerSteps[1]; | |
86 | 93 | const minute_tmpl = { |
87 | 94 | text: 0, |
88 | 95 | selected: false, |
... | ... | @@ -90,7 +97,7 @@ |
90 | 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 | 101 | const minute = deepCopy(minute_tmpl); |
95 | 102 | minute.text = i; |
96 | 103 | |
... | ... | @@ -101,11 +108,11 @@ |
101 | 108 | if (this.minutes === i) minute.selected = true; |
102 | 109 | minutes.push(minute); |
103 | 110 | } |
104 | - | |
105 | 111 | return minutes; |
106 | 112 | }, |
107 | 113 | secondsList () { |
108 | 114 | let seconds = []; |
115 | + const step = this.spinerSteps[2]; | |
109 | 116 | const second_tmpl = { |
110 | 117 | text: 0, |
111 | 118 | selected: false, |
... | ... | @@ -113,7 +120,7 @@ |
113 | 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 | 124 | const second = deepCopy(second_tmpl); |
118 | 125 | second.text = i; |
119 | 126 | |
... | ... | @@ -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 | 153 | this.$emit('on-pick-click'); |
160 | 154 | }, |
161 | 155 | scroll (type, index) { |
... | ... | @@ -183,20 +177,24 @@ |
183 | 177 | }, |
184 | 178 | formatTime (text) { |
185 | 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 | 186 | watch: { |
189 | 187 | hours (val) { |
190 | 188 | if (!this.compiled) return; |
191 | - this.scroll('hours', val); | |
189 | + this.scroll('hours', this.getItemIndex('hours', val)); | |
192 | 190 | }, |
193 | 191 | minutes (val) { |
194 | 192 | if (!this.compiled) return; |
195 | - this.scroll('minutes', val); | |
193 | + this.scroll('minutes', this.getItemIndex('minutes', val)); | |
196 | 194 | }, |
197 | 195 | seconds (val) { |
198 | 196 | if (!this.compiled) return; |
199 | - this.scroll('seconds', val); | |
197 | + this.scroll('seconds', this.getItemIndex('seconds', val)); | |
200 | 198 | } |
201 | 199 | }, |
202 | 200 | mounted () { |
... | ... | @@ -204,4 +202,4 @@ |
204 | 202 | this.$nextTick(() => this.compiled = true); |
205 | 203 | } |
206 | 204 | }; |
207 | -</script> | |
208 | 205 | \ No newline at end of file |
206 | +</script> | ... | ... |
src/components/date-picker/panel/time.vue
... | ... | @@ -6,6 +6,7 @@ |
6 | 6 | <time-spinner |
7 | 7 | ref="timeSpinner" |
8 | 8 | :show-seconds="showSeconds" |
9 | + :steps="steps" | |
9 | 10 | :hours="hours" |
10 | 11 | :minutes="minutes" |
11 | 12 | :seconds="seconds" |
... | ... | @@ -39,6 +40,12 @@ |
39 | 40 | name: 'TimePicker', |
40 | 41 | mixins: [ Mixin, Locale ], |
41 | 42 | components: { TimeSpinner, Confirm }, |
43 | + props: { | |
44 | + steps: { | |
45 | + type: Array, | |
46 | + default: () => [] | |
47 | + } | |
48 | + }, | |
42 | 49 | data () { |
43 | 50 | return { |
44 | 51 | prefixCls: prefixCls, |
... | ... | @@ -113,4 +120,4 @@ |
113 | 120 | if (this.$parent && this.$parent.$options.name === 'DatePicker') this.showDate = true; |
114 | 121 | } |
115 | 122 | }; |
116 | -</script> | |
117 | 123 | \ No newline at end of file |
124 | +</script> | ... | ... |
src/components/date-picker/picker.vue
... | ... | @@ -32,7 +32,6 @@ |
32 | 32 | </div> |
33 | 33 | </template> |
34 | 34 | <script> |
35 | - import Vue from 'vue'; | |
36 | 35 | import iInput from '../../components/input/input.vue'; |
37 | 36 | import Drop from '../../components/select/dropdown.vue'; |
38 | 37 | import clickoutside from '../../directives/clickoutside'; |
... | ... | @@ -397,7 +396,7 @@ |
397 | 396 | let isConfirm = this.confirm; |
398 | 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 | 400 | if (type === 'datetime' || type === 'datetimerange') { |
402 | 401 | isConfirm = true; |
403 | 402 | this.picker.showTime = true; | ... | ... |
src/components/date-picker/picker/date-picker.js
1 | +import Vue from 'vue'; | |
1 | 2 | import Picker from '../picker.vue'; |
2 | 3 | import DatePanel from '../panel/date.vue'; |
3 | 4 | import DateRangePanel from '../panel/date-range.vue'; |
... | ... | @@ -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 | 2 | import Picker from '../picker.vue'; |
2 | 3 | import TimePanel from '../panel/time.vue'; |
3 | 4 | import TimeRangePanel from '../panel/time-range.vue'; |
... | ... | @@ -21,6 +22,10 @@ export default { |
21 | 22 | }, |
22 | 23 | default: 'time' |
23 | 24 | }, |
25 | + steps: { | |
26 | + type: Array, | |
27 | + default: () => [] | |
28 | + }, | |
24 | 29 | value: {} |
25 | 30 | }, |
26 | 31 | created () { |
... | ... | @@ -31,6 +36,11 @@ export default { |
31 | 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 | 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 | +}); | ... | ... |