Commit b27858ddb52b2f6238294eea561e129c6194b1ab
1 parent
3d50db5b
add date panel label format logic
Showing
4 changed files
with
143 additions
and
78 deletions
Show diff stats
src/components/date-picker/panel/date-panel-label.vue
0 → 100644
1 | +<template> | |
2 | + <span> | |
3 | + <span | |
4 | + v-if="datePanelLabel" | |
5 | + v-show="datePanelLabel.labels[0].type === 'year' || currentView === 'date'" | |
6 | + :class="[datePrefixCls + '-header-label']" | |
7 | + @click="datePanelLabel.labels[0].handler">{{ datePanelLabel.labels[0].label }}</span> | |
8 | + <template v-if="datePanelLabel && currentView === 'date'">{{ datePanelLabel.separator }}</template> | |
9 | + <span | |
10 | + v-if="datePanelLabel" | |
11 | + v-show="datePanelLabel.labels[1].type === 'year' || currentView === 'date'" | |
12 | + :class="[datePrefixCls + '-header-label']" | |
13 | + @click="datePanelLabel.labels[1].handler">{{ datePanelLabel.labels[1].label }}</span> | |
14 | + </span> | |
15 | +</template> | |
16 | + | |
17 | +<script> | |
18 | +export default { | |
19 | + props: { | |
20 | + datePanelLabel: Object, | |
21 | + currentView: String, | |
22 | + datePrefixCls: String | |
23 | + } | |
24 | +}; | |
25 | +</script> | ... | ... |
src/components/date-picker/panel/date-range.vue
... | ... | @@ -16,13 +16,10 @@ |
16 | 16 | :class="iconBtnCls('prev')" |
17 | 17 | @click="prevMonth" |
18 | 18 | v-show="leftCurrentView === 'date'"><Icon type="ios-arrow-left"></Icon></span> |
19 | - <span | |
20 | - :class="[datePrefixCls + '-header-label']" | |
21 | - @click="showYearPicker('left')">{{ leftYearLabel }}</span> | |
22 | - <span | |
23 | - :class="[datePrefixCls + '-header-label']" | |
24 | - @click="showMonthPicker('left')" | |
25 | - v-show="leftCurrentView === 'date'">{{ leftMonthLabel }}</span> | |
19 | + <date-panel-label | |
20 | + :date-panel-label="leftDatePanelLabel" | |
21 | + :current-view="leftCurrentView" | |
22 | + :date-prefix-cls="datePrefixCls"/> | |
26 | 23 | <span |
27 | 24 | :class="iconBtnCls('next', '-double')" |
28 | 25 | @click="nextYear('left')" |
... | ... | @@ -66,13 +63,10 @@ |
66 | 63 | :class="iconBtnCls('prev', '-double')" |
67 | 64 | @click="prevYear('right')" |
68 | 65 | v-show="rightCurrentView === 'year' || rightCurrentView === 'month'"><Icon type="ios-arrow-left"></Icon></span> |
69 | - <span | |
70 | - :class="[datePrefixCls + '-header-label']" | |
71 | - @click="showYearPicker('right')">{{ rightYearLabel }}</span> | |
72 | - <span | |
73 | - :class="[datePrefixCls + '-header-label']" | |
74 | - @click="showMonthPicker('right')" | |
75 | - v-show="rightCurrentView === 'date'">{{ rightMonthLabel }}</span> | |
66 | + <date-panel-label | |
67 | + :date-panel-label="rightDatePanelLabel" | |
68 | + :current-view="rightCurrentView" | |
69 | + :date-prefix-cls="datePrefixCls"/> | |
76 | 70 | <span |
77 | 71 | :class="iconBtnCls('next', '-double')" |
78 | 72 | @click="nextYear('right')"><Icon type="ios-arrow-right"></Icon></span> |
... | ... | @@ -138,7 +132,8 @@ |
138 | 132 | import MonthTable from '../base/month-table.vue'; |
139 | 133 | import TimePicker from './time-range.vue'; |
140 | 134 | import Confirm from '../base/confirm.vue'; |
141 | - import { toDate, prevMonth, nextMonth, initTimeDate } from '../util'; | |
135 | + import { toDate, prevMonth, nextMonth, initTimeDate, formatDateLabels } from '../util'; | |
136 | + import datePanelLabel from './date-panel-label.vue'; | |
142 | 137 | |
143 | 138 | import Mixin from './mixin'; |
144 | 139 | import Locale from '../../../mixins/locale'; |
... | ... | @@ -149,7 +144,7 @@ |
149 | 144 | export default { |
150 | 145 | name: 'DatePicker', |
151 | 146 | mixins: [ Mixin, Locale ], |
152 | - components: { Icon, DateTable, YearTable, MonthTable, TimePicker, Confirm }, | |
147 | + components: { Icon, DateTable, YearTable, MonthTable, TimePicker, Confirm, datePanelLabel }, | |
153 | 148 | data () { |
154 | 149 | return { |
155 | 150 | prefixCls: prefixCls, |
... | ... | @@ -195,26 +190,9 @@ |
195 | 190 | return this.date; |
196 | 191 | } |
197 | 192 | }, |
198 | - leftYearLabel () { | |
199 | - const tYear = this.t('i.datepicker.year'); | |
200 | - if (this.leftCurrentView === 'year') { | |
201 | - const year = this.leftTableYear; | |
202 | - if (!year) return ''; | |
203 | - const startYear = Math.floor(year / 10) * 10; | |
204 | - return `${startYear}${tYear} - ${startYear + 9}${tYear}`; | |
205 | - } else { | |
206 | - const year = this.leftCurrentView === 'month' ? this.leftTableYear : this.leftYear; | |
207 | - if (!year) return ''; | |
208 | - return `${year}${tYear}`; | |
209 | - } | |
210 | - }, | |
211 | 193 | leftMonth () { |
212 | 194 | return this.date.getMonth(); |
213 | 195 | }, |
214 | - leftMonthLabel () { | |
215 | - const month = this.leftMonth + 1; | |
216 | - return this.t(`i.datepicker.month${month}`); | |
217 | - }, | |
218 | 196 | rightYear () { |
219 | 197 | return this.rightDate.getFullYear(); |
220 | 198 | }, |
... | ... | @@ -225,26 +203,9 @@ |
225 | 203 | return this.date; |
226 | 204 | } |
227 | 205 | }, |
228 | - rightYearLabel () { | |
229 | - const tYear = this.t('i.datepicker.year'); | |
230 | - if (this.rightCurrentView === 'year') { | |
231 | - const year = this.rightTableYear; | |
232 | - if (!year) return ''; | |
233 | - const startYear = Math.floor(year / 10) * 10; | |
234 | - return `${startYear}${tYear} - ${startYear + 9}${tYear}`; | |
235 | - } else { | |
236 | - const year = this.rightCurrentView === 'month' ? this.rightTableYear : this.rightYear; | |
237 | - if (!year) return ''; | |
238 | - return `${year}${tYear}`; | |
239 | - } | |
240 | - }, | |
241 | 206 | rightMonth () { |
242 | 207 | return this.rightDate.getMonth(); |
243 | 208 | }, |
244 | - rightMonthLabel () { | |
245 | - const month = this.rightMonth + 1; | |
246 | - return this.t(`i.datepicker.month${month}`); | |
247 | - }, | |
248 | 209 | rightDate () { |
249 | 210 | const newDate = new Date(this.date); |
250 | 211 | const month = newDate.getMonth(); |
... | ... | @@ -258,6 +219,14 @@ |
258 | 219 | } |
259 | 220 | return newDate; |
260 | 221 | }, |
222 | + leftDatePanelLabel () { | |
223 | + if (!this.leftYear) return null; // not ready yet | |
224 | + return this.panelLabelConfig('left'); | |
225 | + }, | |
226 | + rightDatePanelLabel () { | |
227 | + if (!this.leftYear) return null; // not ready yet | |
228 | + return this.panelLabelConfig('right'); | |
229 | + }, | |
261 | 230 | timeDisabled () { |
262 | 231 | return !(this.minDate && this.maxDate); |
263 | 232 | } |
... | ... | @@ -288,6 +257,22 @@ |
288 | 257 | } |
289 | 258 | }, |
290 | 259 | methods: { |
260 | + panelLabelConfig (direction) { | |
261 | + const locale = this.t('i.locale'); | |
262 | + const datePanelLabel = this.t('i.datepicker.datePanelLabel'); | |
263 | + const handler = type => { | |
264 | + const fn = type == 'month' ? this.showMonthPicker : this.showYearPicker; | |
265 | + return () => fn(direction); | |
266 | + }; | |
267 | + | |
268 | + const date = new Date(this[`${direction}Year`], this[`${direction}Month`]); | |
269 | + const { labels, separator } = formatDateLabels(locale, datePanelLabel, date); | |
270 | + | |
271 | + return { | |
272 | + separator: separator, | |
273 | + labels: labels.map(obj => ((obj.handler = handler(obj.type)), obj)) | |
274 | + }; | |
275 | + }, | |
291 | 276 | resetDate () { |
292 | 277 | this.date = new Date(this.date); |
293 | 278 | this.leftTableYear = this.date.getFullYear(); | ... | ... |
src/components/date-picker/panel/date.vue
... | ... | @@ -15,13 +15,10 @@ |
15 | 15 | :class="iconBtnCls('prev')" |
16 | 16 | @click="changeMonth(-1)" |
17 | 17 | v-show="currentView === 'date'"><Icon type="ios-arrow-left"></Icon></span> |
18 | - <span | |
19 | - :class="[datePrefixCls + '-header-label']" | |
20 | - @click="showYearPicker">{{ yearLabel }}</span> | |
21 | - <span | |
22 | - :class="[datePrefixCls + '-header-label']" | |
23 | - @click="showMonthPicker" | |
24 | - v-show="currentView === 'date'">{{ monthLabel }}</span> | |
18 | + <date-panel-label | |
19 | + :date-panel-label="datePanelLabel" | |
20 | + :current-view="currentView" | |
21 | + :date-prefix-cls="datePrefixCls"/> | |
25 | 22 | <span |
26 | 23 | :class="iconBtnCls('next', '-double')" |
27 | 24 | @click="changeYear(+1)"><Icon type="ios-arrow-right"></Icon></span> |
... | ... | @@ -83,11 +80,12 @@ |
83 | 80 | import MonthTable from '../base/month-table.vue'; |
84 | 81 | import TimePicker from './time.vue'; |
85 | 82 | import Confirm from '../base/confirm.vue'; |
83 | + import datePanelLabel from './date-panel-label.vue'; | |
86 | 84 | |
87 | 85 | import Mixin from './mixin'; |
88 | 86 | import Locale from '../../../mixins/locale'; |
89 | 87 | |
90 | - import { initTimeDate, siblingMonth } from '../util'; | |
88 | + import { initTimeDate, siblingMonth, formatDateLabels } from '../util'; | |
91 | 89 | |
92 | 90 | const prefixCls = 'ivu-picker-panel'; |
93 | 91 | const datePrefixCls = 'ivu-date-picker'; |
... | ... | @@ -95,7 +93,7 @@ |
95 | 93 | export default { |
96 | 94 | name: 'DatePicker', |
97 | 95 | mixins: [ Mixin, Locale ], |
98 | - components: { Icon, DateTable, YearTable, MonthTable, TimePicker, Confirm }, | |
96 | + components: { Icon, DateTable, YearTable, MonthTable, TimePicker, Confirm, datePanelLabel }, | |
99 | 97 | data () { |
100 | 98 | return { |
101 | 99 | prefixCls: prefixCls, |
... | ... | @@ -123,19 +121,21 @@ |
123 | 121 | } |
124 | 122 | ]; |
125 | 123 | }, |
126 | - yearLabel () { | |
127 | - const tYear = this.t('i.datepicker.year'); | |
128 | - const year = this.year; | |
129 | - if (!year) return ''; | |
130 | - if (this.currentView === 'year') { | |
131 | - const startYear = Math.floor(year / 10) * 10; | |
132 | - return `${startYear}${tYear} - ${startYear + 9}${tYear}`; | |
133 | - } | |
134 | - return `${year}${tYear}`; | |
135 | - }, | |
136 | - monthLabel () { | |
137 | - const month = this.month + 1; | |
138 | - return this.t(`i.datepicker.month${month}`); | |
124 | + datePanelLabel () { | |
125 | + if (!this.year) return null; // not ready yet | |
126 | + const locale = this.t('i.locale'); | |
127 | + const datePanelLabel = this.t('i.datepicker.datePanelLabel'); | |
128 | + const date = new Date(this.year, this.month); | |
129 | + const { labels, separator } = formatDateLabels(locale, datePanelLabel, date); | |
130 | + | |
131 | + const handler = type => { | |
132 | + return () => (this.currentView = type); | |
133 | + }; | |
134 | + | |
135 | + return { | |
136 | + separator: separator, | |
137 | + labels: labels.map(obj => ((obj.handler = handler(obj.type)), obj)) | |
138 | + }; | |
139 | 139 | } |
140 | 140 | }, |
141 | 141 | watch: { |
... | ... | @@ -196,12 +196,6 @@ |
196 | 196 | this.date = siblingMonth(this.date, dir); |
197 | 197 | this.setMonthYear(this.date); |
198 | 198 | }, |
199 | - showYearPicker () { | |
200 | - this.currentView = 'year'; | |
201 | - }, | |
202 | - showMonthPicker () { | |
203 | - this.currentView = 'month'; | |
204 | - }, | |
205 | 199 | handleToggleTime () { |
206 | 200 | if (this.currentView === 'date') { |
207 | 201 | this.currentView = 'time'; | ... | ... |
src/components/date-picker/util.js
... | ... | @@ -61,3 +61,64 @@ export const initTimeDate = function() { |
61 | 61 | date.setSeconds(0); |
62 | 62 | return date; |
63 | 63 | }; |
64 | + | |
65 | +export const formatDateLabels = (function() { | |
66 | + /* | |
67 | + Formats: | |
68 | + yyyy - 4 digit year | |
69 | + m - month, numeric, 1 - 12 | |
70 | + m - month, numeric, 01 - 12 | |
71 | + mmm - month, 3 letters, as in `toLocaleDateString` | |
72 | + Mmm - month, 3 letters, capitalize the return from `toLocaleDateString` | |
73 | + mmmm - month, full name, as in `toLocaleDateString` | |
74 | + Mmmm - month, full name, capitalize the return from `toLocaleDateString` | |
75 | + */ | |
76 | + | |
77 | + const formats = { | |
78 | + yyyy: date => date.getFullYear(), | |
79 | + m: date => date.getMonth(), | |
80 | + mm: date => ('0' + date.getMonth()).slice(-2), | |
81 | + mmm: (date, locale) => { | |
82 | + const monthName = date.toLocaleDateString(locale, { | |
83 | + month: 'long' | |
84 | + }); | |
85 | + return monthName.slice(0, 3); | |
86 | + }, | |
87 | + Mmm: (date, locale) => { | |
88 | + const monthName = date.toLocaleDateString(locale, { | |
89 | + month: 'long' | |
90 | + }); | |
91 | + return (monthName[0].toUpperCase() + monthName.slice(1).toLowerCase()).slice(0, 3); | |
92 | + }, | |
93 | + mmmm: (date, locale) => | |
94 | + date.toLocaleDateString(locale, { | |
95 | + month: 'long' | |
96 | + }), | |
97 | + Mmmm: (date, locale) => { | |
98 | + const monthName = date.toLocaleDateString(locale, { | |
99 | + month: 'long' | |
100 | + }); | |
101 | + return monthName[0].toUpperCase() + monthName.slice(1).toLowerCase(); | |
102 | + } | |
103 | + }; | |
104 | + const formatRegex = new RegExp(['yyyy', 'Mmmm', 'mmmm', 'Mmm', 'mmm', 'mm', 'm'].join('|'), 'g'); | |
105 | + | |
106 | + return function(locale, format, date) { | |
107 | + const componetsRegex = /(\[[^\]]+\])([^\[\]]+)(\[[^\]]+\])/; | |
108 | + const components = format.match(componetsRegex).slice(1); | |
109 | + const separator = components[1]; | |
110 | + const labels = [components[0], components[2]].map(component => { | |
111 | + const label = component.replace(/\[[^\]]+\]/, str => { | |
112 | + return str.slice(1, -1).replace(formatRegex, match => formats[match](date, locale)); | |
113 | + }); | |
114 | + return { | |
115 | + label: label, | |
116 | + type: component.includes('yy') ? 'year' : 'month' | |
117 | + }; | |
118 | + }); | |
119 | + return { | |
120 | + separator: separator, | |
121 | + labels: labels | |
122 | + }; | |
123 | + }; | |
124 | +})(); | ... | ... |