|
2 | 2 | <div class="md-datepicker">
|
3 | 3 | <md-icon @click.native="openPicker">event</md-icon>
|
4 | 4 |
|
| 5 | + <md-input |
| 6 | + type="date" |
| 7 | + v-model="modelDate" |
| 8 | + :id="id" |
| 9 | + :name="name" |
| 10 | + :required="required" |
| 11 | + :placeholder="placeholder" |
| 12 | + :disabled="disabled" |
| 13 | + @focus.native="openOnFocus" |
| 14 | + ref="pickerInput" /> |
| 15 | + |
5 | 16 | <div class="md-datepicker-popup" :class="[themeClass, classes]" :style="styles" ref="pickerElement">
|
6 | 17 | <div class="md-datepicker-header">
|
7 |
| - <span class="md-datepicker-year-select" @click="currentView = 'year'">{{ currentDate.getFullYear() }}</span> |
8 |
| - <div class="md-datepicker-date-select" @click="currentView = 'date'"> |
9 |
| - <strong class="md-datepicker-dayname">{{ locale.shortDays[currentDate.getDay()] }},</strong> |
10 |
| - <strong class="md-datepicker-monthname">{{ locale.shortMonths[currentDate.getMonth()] }}</strong> |
11 |
| - <strong class="md-datepicker-day">{{ currentDate.getDate() }}</strong> |
| 18 | + <span class="md-datepicker-year-select" @click="showYearPicker">{{ selectedDate.getFullYear() }}</span> |
| 19 | + <div class="md-datepicker-date-select" @click="showDatePicker"> |
| 20 | + <strong class="md-datepicker-dayname">{{ locale.shortDays[selectedDate.getDay()] }},</strong> |
| 21 | + <strong class="md-datepicker-monthname">{{ locale.shortMonths[selectedDate.getMonth()] }}</strong> |
| 22 | + <strong class="md-datepicker-day">{{ selectedDate.getDate() }}</strong> |
12 | 23 | </div>
|
13 | 24 | </div>
|
14 | 25 |
|
|
19 | 30 | <md-icon>keyboard_arrow_left</md-icon>
|
20 | 31 | </md-button>
|
21 | 32 |
|
22 |
| - <span class="md-current-date">{{ locale.months[currentDate.getMonth()] }} {{ currentDate.getFullYear() }}</span> |
23 |
| - |
24 | 33 | <md-button class="md-icon-button">
|
25 | 34 | <md-icon>keyboard_arrow_right</md-icon>
|
26 | 35 | </md-button>
|
27 | 36 | </div>
|
28 | 37 |
|
29 |
| - <div class="md-datepicker-week-days"> |
30 |
| - <span v-for="day in locale.shorterDays">{{ day }}</span> |
31 |
| - </div> |
| 38 | + <div class="md-calendar-container"> |
| 39 | + <div class="md-datepicker-month" v-for="month in createdMonths"> |
| 40 | + <span class="md-current-date">{{ locale.months[month.getMonth()] }} {{ month.getFullYear() }}</span> |
| 41 | + |
| 42 | + <div class="md-datepicker-week-days"> |
| 43 | + <span v-for="day in locale.shorterDays">{{ day }}</span> |
| 44 | + </div> |
32 | 45 |
|
33 |
| - <div class="md-datepicker-days"> |
34 |
| - <md-button class="md-icon-button md-empty" v-for="day in startOfMonth(currentDate).getDay()" disabled></md-button> |
35 |
| - <md-button class="md-icon-button" :class="{ 'md-today': isToday(day, currentDate) }" v-for="day in getDaysInMonth(currentDate)">{{ day }}</md-button> |
| 46 | + <div class="md-datepicker-days"> |
| 47 | + <span class="md-empty" v-for="day in startOfMonth(month).getDay()"></span> |
| 48 | + |
| 49 | + <md-button |
| 50 | + class="md-icon-button" |
| 51 | + v-for="day in getDaysInMonth(month)" |
| 52 | + :key="day" |
| 53 | + :class="{ |
| 54 | + 'md-today': isToday(day), |
| 55 | + 'md-selected': isSelectedDay(day) |
| 56 | + }" |
| 57 | + @click.native="selectDate(day)"> |
| 58 | + {{ day }} |
| 59 | + </md-button> |
| 60 | + </div> |
| 61 | + </div> |
36 | 62 | </div>
|
37 | 63 | </div>
|
38 | 64 |
|
39 | 65 | <div class="md-datepicker-years" v-show="currentView === 'year'">
|
40 |
| - <md-button class="md-dense md-datepicker-year" :class="{ 'md-primary': isThisYear(year, currentDate) }" v-for="year in visibleYears()" @click="setYear(year)">{{ year }}</md-button> |
| 66 | + <md-button |
| 67 | + class="md-dense md-datepicker-year" |
| 68 | + v-for="year in visibleYears()" |
| 69 | + :key="year" |
| 70 | + :class="[ |
| 71 | + { |
| 72 | + 'md-primary': isThisYear(year), |
| 73 | + 'md-primary md-raised': isSelectedYear(year), |
| 74 | + }, |
| 75 | + 'data-' + year |
| 76 | + ]" |
| 77 | + @click.native="setYear(year)"> |
| 78 | + {{ year }} |
| 79 | + </md-button> |
41 | 80 | </div>
|
42 | 81 |
|
43 | 82 | <div class="md-datepicker-actions md-dialog-actions">
|
|
48 | 87 | </div>
|
49 | 88 |
|
50 | 89 | <md-backdrop class="md-datepicker-backdrop" :class="classes" @close="closePicker" ref="pickerBackdrop" />
|
51 |
| - |
52 |
| - <md-input |
53 |
| - type="date" |
54 |
| - v-model="value" |
55 |
| - :id="id" |
56 |
| - :name="name" |
57 |
| - :required="required" |
58 |
| - :placeholder="placeholder" |
59 |
| - :disabled="disabled" |
60 |
| - @focus.native="mdOpenOnFocus || openPicker" |
61 |
| - ref="pickerInput" /> |
62 | 90 | </div>
|
63 | 91 | </template>
|
64 | 92 |
|
|
69 | 97 | import getClosestVueParent from '../../core/utils/getClosestVueParent';
|
70 | 98 | import getInViewPosition from '../../core/utils/getInViewPosition';
|
71 | 99 | import transitionEndEventName from '../../core/utils/transitionEndEventName';
|
72 |
| - import startOfMonth from 'date-fns/start_of_month'; |
73 | 100 | import formatDate from 'date-fns/format';
|
| 101 | + import startOfMonth from 'date-fns/start_of_month'; |
| 102 | + import addMonths from 'date-fns/add_months'; |
74 | 103 | import getDaysInMonth from 'date-fns/get_days_in_month';
|
75 | 104 | import setDate from 'date-fns/set_date';
|
76 | 105 | import setYear from 'date-fns/set_year';
|
77 | 106 | import isToday from 'date-fns/is_today';
|
| 107 | + import isSameDay from 'date-fns/is_same_day'; |
78 | 108 | import isThisYear from 'date-fns/is_this_year';
|
79 | 109 |
|
80 | 110 | export default {
|
|
108 | 138 |
|
109 | 139 | return years;
|
110 | 140 | },
|
111 |
| - currentView: 'date', |
112 |
| - currentDate: new Date(this.value) |
| 141 | + currentDate: new Date(this.value), |
| 142 | + selectedDate: new Date(this.value), |
| 143 | + createdMonths: [ |
| 144 | + addMonths(this.value, -1), |
| 145 | + this.value, |
| 146 | + addMonths(this.value, 1) |
| 147 | + ], |
| 148 | + currentView: 'date' |
113 | 149 | };
|
114 | 150 | },
|
115 | 151 | computed: {
|
|
126 | 162 | left: this.pickerPosition.left
|
127 | 163 | };
|
128 | 164 | },
|
| 165 | + modelDate() { |
| 166 | + return formatDate(this.selectedDate, this.locale.dateFormat); |
| 167 | + }, |
129 | 168 | locale() {
|
130 | 169 | return this.$material.locale;
|
131 | 170 | }
|
132 | 171 | },
|
133 | 172 | methods: {
|
134 |
| - startOfMonth, |
135 |
| - getDaysInMonth, |
136 |
| - isToday(day, fullDate) { |
137 |
| - return isToday(setDate(fullDate, day)); |
| 173 | + startOfMonth(month) { |
| 174 | + return startOfMonth(month); |
| 175 | + }, |
| 176 | + getDaysInMonth(month) { |
| 177 | + return getDaysInMonth(month); |
| 178 | + }, |
| 179 | + isToday(day) { |
| 180 | + return isToday(setDate(new Date(), day)); |
138 | 181 | },
|
139 |
| - isThisYear(year, fullDate) { |
140 |
| - return isThisYear(setYear(fullDate, year)); |
| 182 | + isThisYear(year) { |
| 183 | + return isThisYear(setYear(new Date(), year)); |
| 184 | + }, |
| 185 | + isSelectedDay(day) { |
| 186 | + return isSameDay(this.selectedDate, setDate(this.selectedDate, day)); |
| 187 | + }, |
| 188 | + isSelectedYear(year) { |
| 189 | + return isSameDay(this.selectedDate, setYear(this.selectedDate, year)); |
141 | 190 | },
|
142 | 191 | setYear(year) {
|
143 |
| - this.setModelValue(setYear(this.currentDate, year)); |
| 192 | + this.setModelValue(setYear(this.selectedDate, year)); |
144 | 193 | },
|
145 | 194 | setModelValue(date) {
|
146 |
| - this.currentDate = date; |
147 |
| - this.$emit('input', formatDate(date, this.locale.dateFormat)); |
| 195 | + this.selectedDate = date; |
| 196 | + this.$emit('input', this.modelDate); |
| 197 | + }, |
| 198 | + openOnFocus() { |
| 199 | + if (this.mdOpenOnFocus) { |
| 200 | + this.openPicker(); |
| 201 | + } |
148 | 202 | },
|
149 | 203 | calculatePopupPosition() {
|
150 | 204 | window.requestAnimationFrame(() => {
|
|
179 | 233 | window.removeEventListener('resize', this.calculatePopupPosition);
|
180 | 234 | this.pickerElement.removeEventListener(transitionEndEventName, cleanUp);
|
181 | 235 | this.pickerElement.addEventListener(transitionEndEventName, cleanUp);
|
| 236 | + this.showDatePicker(); |
182 | 237 | this.active = false;
|
| 238 | + }, |
| 239 | + showDatePicker() { |
183 | 240 | this.currentView = 'date';
|
| 241 | + }, |
| 242 | + showYearPicker() { |
| 243 | + this.currentView = 'year'; |
| 244 | +
|
| 245 | + this.$nextTick(() => { |
| 246 | + this.pickerElement.querySelector(`.data-${this.selectedDate.getFullYear()}`).scrollIntoViewIfNeeded(true); |
| 247 | + }); |
| 248 | + }, |
| 249 | + selectDate(day) { |
| 250 | + this.selectedDate = setDate(this.selectedDate, day); |
184 | 251 | }
|
185 | 252 | },
|
186 | 253 | mounted() {
|
|
0 commit comments