2
0
mirror of https://github.com/tenrok/vue2-datepicker.git synced 2026-06-24 16:00:41 +03:00

refactor: remove date-fns && optimize code

This commit is contained in:
mengxiong10
2020-11-16 11:30:42 +08:00
parent a9b7900f39
commit a5a41096dc
37 changed files with 1908 additions and 1963 deletions
@@ -1,245 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CalendarPanel prop: type=date 1`] = `
<div
class="mx-calendar mx-calendar-panel-date"
>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-left"
type="button"
>
<i
class="mx-icon-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-right"
type="button"
>
<i
class="mx-icon-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<button
class="mx-btn mx-btn-text mx-btn-current-month"
type="button"
>
Oct
</button>
<button
class="mx-btn mx-btn-text mx-btn-current-year"
type="button"
>
2019
</button>
</span>
</div>
<div
class="mx-calendar-content"
>
<table-year-stub
decade="2010"
getcellclasses="function () { [native code] }"
style="display: none;"
/>
<table-month-stub
getcellclasses="function () { [native code] }"
style="display: none;"
/>
<table-date-stub
calendarmonth="9"
calendaryear="2019"
getcellclasses="function () { [native code] }"
getrowclasses="function () { [native code] }"
titleformat="YYYY-MM-DD"
/>
</div>
</div>
`;
exports[`CalendarPanel prop: type=month 1`] = `
<div
class="mx-calendar mx-calendar-panel-month"
>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-left"
style="display: none;"
type="button"
>
<i
class="mx-icon-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-right"
style="display: none;"
type="button"
>
<i
class="mx-icon-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<button
class="mx-btn mx-btn-text"
type="button"
>
2019
</button>
</span>
</div>
<div
class="mx-calendar-content"
>
<table-year-stub
decade="2010"
getcellclasses="function () { [native code] }"
style="display: none;"
/>
<table-month-stub
getcellclasses="function () { [native code] }"
/>
<!---->
</div>
</div>
`;
exports[`CalendarPanel prop: type=year 1`] = `
<div
class="mx-calendar mx-calendar-panel-year"
>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-left"
style="display: none;"
type="button"
>
<i
class="mx-icon-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-right"
style="display: none;"
type="button"
>
<i
class="mx-icon-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<span>
2010
</span>
<span
class="mx-calendar-decade-separator"
/>
<span>
2019
</span>
</span>
</div>
<div
class="mx-calendar-content"
>
<table-year-stub
decade="2010"
getcellclasses="function () { [native code] }"
/>
<!---->
<!---->
</div>
</div>
`;
+58 -87
View File
@@ -14,33 +14,23 @@ exports[`DatePicker prop: attrs of input 1`] = `
placeholder="test placeholder"
type="number"
/>
<!---->
<i
class="mx-icon-calendar"
>
<icon-calendar-stub />
<anonymous-stub />
</i>
</div>
<popup-stub
appendtobody="true"
>
<!---->
<div
class="mx-datepicker-content"
>
<!---->
<div
class="mx-datepicker-body"
>
<div />
</div>
<!---->
</div>
</popup-stub>
</div>
@@ -60,33 +50,23 @@ exports[`DatePicker prop: clearable 1`] = `
placeholder=""
type="text"
/>
<!---->
<i
class="mx-icon-calendar"
>
<icon-calendar-stub />
<anonymous-stub />
</i>
</div>
<popup-stub
appendtobody="true"
>
<!---->
<div
class="mx-datepicker-content"
>
<!---->
<div
class="mx-datepicker-body"
>
<div />
</div>
<!---->
</div>
</popup-stub>
</div>
@@ -107,37 +87,28 @@ exports[`DatePicker prop: editable 1`] = `
readonly="readonly"
type="text"
/>
<i
class="mx-icon-clear"
>
<icon-close-stub />
<anonymous-stub />
</i>
<i
class="mx-icon-calendar"
>
<icon-calendar-stub />
<anonymous-stub />
</i>
</div>
<popup-stub
appendtobody="true"
>
<!---->
<div
class="mx-datepicker-content"
>
<!---->
<div
class="mx-datepicker-body"
>
<div />
</div>
<!---->
</div>
</popup-stub>
</div>
@@ -185,13 +156,13 @@ exports[`DatePicker prop: formatter 1`] = `
class="mx-week-number"
>
29
29
</td>
<td
class="cell not-current-month"
data-day="-1"
data-date="1569686400000"
title="2019-09-29"
>
<div>
@@ -200,7 +171,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="0"
data-date="1569772800000"
title="2019-09-30"
>
<div>
@@ -209,7 +180,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="1"
data-date="1569859200000"
title="2019-10-01"
>
<div>
@@ -218,7 +189,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="2"
data-date="1569945600000"
title="2019-10-02"
>
<div>
@@ -227,7 +198,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="3"
data-date="1570032000000"
title="2019-10-03"
>
<div>
@@ -236,7 +207,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="4"
data-date="1570118400000"
title="2019-10-04"
>
<div>
@@ -245,7 +216,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="5"
data-date="1570204800000"
title="2019-10-05"
>
<div>
@@ -260,13 +231,13 @@ exports[`DatePicker prop: formatter 1`] = `
class="mx-week-number"
>
6
6
</td>
<td
class="cell"
data-day="6"
data-date="1570291200000"
title="2019-10-06"
>
<div>
@@ -275,7 +246,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="7"
data-date="1570377600000"
title="2019-10-07"
>
<div>
@@ -284,7 +255,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="8"
data-date="1570464000000"
title="2019-10-08"
>
<div>
@@ -293,7 +264,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="9"
data-date="1570550400000"
title="2019-10-09"
>
<div>
@@ -302,7 +273,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="10"
data-date="1570636800000"
title="2019-10-10"
>
<div>
@@ -311,7 +282,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="11"
data-date="1570723200000"
title="2019-10-11"
>
<div>
@@ -320,7 +291,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="12"
data-date="1570809600000"
title="2019-10-12"
>
<div>
@@ -335,13 +306,13 @@ exports[`DatePicker prop: formatter 1`] = `
class="mx-week-number"
>
13
13
</td>
<td
class="cell active"
data-day="13"
data-date="1570896000000"
title="2019-10-13"
>
<div>
@@ -350,7 +321,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="14"
data-date="1570982400000"
title="2019-10-14"
>
<div>
@@ -359,7 +330,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="15"
data-date="1571068800000"
title="2019-10-15"
>
<div>
@@ -368,7 +339,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="16"
data-date="1571155200000"
title="2019-10-16"
>
<div>
@@ -377,7 +348,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="17"
data-date="1571241600000"
title="2019-10-17"
>
<div>
@@ -386,7 +357,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="18"
data-date="1571328000000"
title="2019-10-18"
>
<div>
@@ -395,7 +366,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="19"
data-date="1571414400000"
title="2019-10-19"
>
<div>
@@ -410,13 +381,13 @@ exports[`DatePicker prop: formatter 1`] = `
class="mx-week-number"
>
20
20
</td>
<td
class="cell"
data-day="20"
data-date="1571500800000"
title="2019-10-20"
>
<div>
@@ -425,7 +396,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="21"
data-date="1571587200000"
title="2019-10-21"
>
<div>
@@ -434,7 +405,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="22"
data-date="1571673600000"
title="2019-10-22"
>
<div>
@@ -443,7 +414,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="23"
data-date="1571760000000"
title="2019-10-23"
>
<div>
@@ -452,7 +423,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="24"
data-date="1571846400000"
title="2019-10-24"
>
<div>
@@ -461,7 +432,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="25"
data-date="1571932800000"
title="2019-10-25"
>
<div>
@@ -470,7 +441,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="26"
data-date="1572019200000"
title="2019-10-26"
>
<div>
@@ -485,13 +456,13 @@ exports[`DatePicker prop: formatter 1`] = `
class="mx-week-number"
>
27
27
</td>
<td
class="cell"
data-day="27"
data-date="1572105600000"
title="2019-10-27"
>
<div>
@@ -500,7 +471,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="28"
data-date="1572192000000"
title="2019-10-28"
>
<div>
@@ -509,7 +480,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="29"
data-date="1572278400000"
title="2019-10-29"
>
<div>
@@ -518,7 +489,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="30"
data-date="1572364800000"
title="2019-10-30"
>
<div>
@@ -527,7 +498,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell"
data-day="31"
data-date="1572451200000"
title="2019-10-31"
>
<div>
@@ -536,7 +507,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="32"
data-date="1572537600000"
title="2019-11-01"
>
<div>
@@ -545,7 +516,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="33"
data-date="1572624000000"
title="2019-11-02"
>
<div>
@@ -560,13 +531,13 @@ exports[`DatePicker prop: formatter 1`] = `
class="mx-week-number"
>
3
3
</td>
<td
class="cell not-current-month"
data-day="34"
data-date="1572710400000"
title="2019-11-03"
>
<div>
@@ -575,7 +546,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="35"
data-date="1572796800000"
title="2019-11-04"
>
<div>
@@ -584,7 +555,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="36"
data-date="1572883200000"
title="2019-11-05"
>
<div>
@@ -593,7 +564,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="37"
data-date="1572969600000"
title="2019-11-06"
>
<div>
@@ -602,7 +573,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="38"
data-date="1573056000000"
title="2019-11-07"
>
<div>
@@ -611,7 +582,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="39"
data-date="1573142400000"
title="2019-11-08"
>
<div>
@@ -620,7 +591,7 @@ exports[`DatePicker prop: formatter 1`] = `
</td>
<td
class="cell not-current-month"
data-day="40"
data-date="1573228800000"
title="2019-11-09"
>
<div>
+513 -445
View File
@@ -1,453 +1,521 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TableDate corrent render 1`] = `
<table
class="mx-table mx-table-date"
firstdayofweek="1"
<div
class="mx-calendar mx-calendar-panel-date"
>
<thead>
<tr>
<!---->
<th>
Su
</th>
<th>
Mo
</th>
<th>
Tu
</th>
<th>
We
</th>
<th>
Th
</th>
<th>
Fr
</th>
<th>
Sa
</th>
</tr>
</thead>
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-left"
type="button"
>
<i
class="mx-icon-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-right"
type="button"
>
<i
class="mx-icon-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<button
class="mx-btn mx-btn-text mx-btn-current-month"
type="button"
>
Oct
</button>
<button
class="mx-btn mx-btn-text mx-btn-current-year"
type="button"
>
2019
</button>
</span>
</div>
<tbody>
<tr
class="mx-date-row"
<div
class="mx-calendar-content"
>
<table
class="mx-table mx-table-date"
>
<!---->
<thead>
<tr>
<!---->
<th>
Su
</th>
<th>
Mo
</th>
<th>
Tu
</th>
<th>
We
</th>
<th>
Th
</th>
<th>
Fr
</th>
<th>
Sa
</th>
</tr>
</thead>
<td
class="cell"
data-day="-1"
title="29/09/2019"
>
<div>
29
</div>
</td>
<td
class="cell"
data-day="0"
title="30/09/2019"
>
<div>
30
</div>
</td>
<td
class="cell"
data-day="1"
title="01/10/2019"
>
<div>
1
</div>
</td>
<td
class="cell"
data-day="2"
title="02/10/2019"
>
<div>
2
</div>
</td>
<td
class="cell"
data-day="3"
title="03/10/2019"
>
<div>
3
</div>
</td>
<td
class="cell"
data-day="4"
title="04/10/2019"
>
<div>
4
</div>
</td>
<td
class="cell"
data-day="5"
title="05/10/2019"
>
<div>
5
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-day="6"
title="06/10/2019"
>
<div>
6
</div>
</td>
<td
class="cell"
data-day="7"
title="07/10/2019"
>
<div>
7
</div>
</td>
<td
class="cell"
data-day="8"
title="08/10/2019"
>
<div>
8
</div>
</td>
<td
class="cell"
data-day="9"
title="09/10/2019"
>
<div>
9
</div>
</td>
<td
class="cell"
data-day="10"
title="10/10/2019"
>
<div>
10
</div>
</td>
<td
class="cell"
data-day="11"
title="11/10/2019"
>
<div>
11
</div>
</td>
<td
class="cell"
data-day="12"
title="12/10/2019"
>
<div>
12
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-day="13"
title="13/10/2019"
>
<div>
13
</div>
</td>
<td
class="cell"
data-day="14"
title="14/10/2019"
>
<div>
14
</div>
</td>
<td
class="cell"
data-day="15"
title="15/10/2019"
>
<div>
15
</div>
</td>
<td
class="cell"
data-day="16"
title="16/10/2019"
>
<div>
16
</div>
</td>
<td
class="cell"
data-day="17"
title="17/10/2019"
>
<div>
17
</div>
</td>
<td
class="cell"
data-day="18"
title="18/10/2019"
>
<div>
18
</div>
</td>
<td
class="cell"
data-day="19"
title="19/10/2019"
>
<div>
19
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-day="20"
title="20/10/2019"
>
<div>
20
</div>
</td>
<td
class="cell"
data-day="21"
title="21/10/2019"
>
<div>
21
</div>
</td>
<td
class="cell"
data-day="22"
title="22/10/2019"
>
<div>
22
</div>
</td>
<td
class="cell"
data-day="23"
title="23/10/2019"
>
<div>
23
</div>
</td>
<td
class="cell"
data-day="24"
title="24/10/2019"
>
<div>
24
</div>
</td>
<td
class="cell"
data-day="25"
title="25/10/2019"
>
<div>
25
</div>
</td>
<td
class="cell"
data-day="26"
title="26/10/2019"
>
<div>
26
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-day="27"
title="27/10/2019"
>
<div>
27
</div>
</td>
<td
class="cell"
data-day="28"
title="28/10/2019"
>
<div>
28
</div>
</td>
<td
class="cell"
data-day="29"
title="29/10/2019"
>
<div>
29
</div>
</td>
<td
class="cell"
data-day="30"
title="30/10/2019"
>
<div>
30
</div>
</td>
<td
class="cell"
data-day="31"
title="31/10/2019"
>
<div>
31
</div>
</td>
<td
class="cell"
data-day="32"
title="01/11/2019"
>
<div>
1
</div>
</td>
<td
class="cell"
data-day="33"
title="02/11/2019"
>
<div>
2
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-day="34"
title="03/11/2019"
>
<div>
3
</div>
</td>
<td
class="cell"
data-day="35"
title="04/11/2019"
>
<div>
4
</div>
</td>
<td
class="cell"
data-day="36"
title="05/11/2019"
>
<div>
5
</div>
</td>
<td
class="cell"
data-day="37"
title="06/11/2019"
>
<div>
6
</div>
</td>
<td
class="cell"
data-day="38"
title="07/11/2019"
>
<div>
7
</div>
</td>
<td
class="cell"
data-day="39"
title="08/11/2019"
>
<div>
8
</div>
</td>
<td
class="cell"
data-day="40"
title="09/11/2019"
>
<div>
9
</div>
</td>
</tr>
</tbody>
</table>
<tbody>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-date="1569686400000"
title="29/09/2019"
>
<div>
29
</div>
</td>
<td
class="cell"
data-date="1569772800000"
title="30/09/2019"
>
<div>
30
</div>
</td>
<td
class="cell"
data-date="1569859200000"
title="01/10/2019"
>
<div>
1
</div>
</td>
<td
class="cell"
data-date="1569945600000"
title="02/10/2019"
>
<div>
2
</div>
</td>
<td
class="cell"
data-date="1570032000000"
title="03/10/2019"
>
<div>
3
</div>
</td>
<td
class="cell"
data-date="1570118400000"
title="04/10/2019"
>
<div>
4
</div>
</td>
<td
class="cell"
data-date="1570204800000"
title="05/10/2019"
>
<div>
5
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-date="1570291200000"
title="06/10/2019"
>
<div>
6
</div>
</td>
<td
class="cell"
data-date="1570377600000"
title="07/10/2019"
>
<div>
7
</div>
</td>
<td
class="cell"
data-date="1570464000000"
title="08/10/2019"
>
<div>
8
</div>
</td>
<td
class="cell"
data-date="1570550400000"
title="09/10/2019"
>
<div>
9
</div>
</td>
<td
class="cell"
data-date="1570636800000"
title="10/10/2019"
>
<div>
10
</div>
</td>
<td
class="cell"
data-date="1570723200000"
title="11/10/2019"
>
<div>
11
</div>
</td>
<td
class="cell"
data-date="1570809600000"
title="12/10/2019"
>
<div>
12
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-date="1570896000000"
title="13/10/2019"
>
<div>
13
</div>
</td>
<td
class="cell"
data-date="1570982400000"
title="14/10/2019"
>
<div>
14
</div>
</td>
<td
class="cell"
data-date="1571068800000"
title="15/10/2019"
>
<div>
15
</div>
</td>
<td
class="cell"
data-date="1571155200000"
title="16/10/2019"
>
<div>
16
</div>
</td>
<td
class="cell"
data-date="1571241600000"
title="17/10/2019"
>
<div>
17
</div>
</td>
<td
class="cell"
data-date="1571328000000"
title="18/10/2019"
>
<div>
18
</div>
</td>
<td
class="cell"
data-date="1571414400000"
title="19/10/2019"
>
<div>
19
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-date="1571500800000"
title="20/10/2019"
>
<div>
20
</div>
</td>
<td
class="cell"
data-date="1571587200000"
title="21/10/2019"
>
<div>
21
</div>
</td>
<td
class="cell"
data-date="1571673600000"
title="22/10/2019"
>
<div>
22
</div>
</td>
<td
class="cell"
data-date="1571760000000"
title="23/10/2019"
>
<div>
23
</div>
</td>
<td
class="cell"
data-date="1571846400000"
title="24/10/2019"
>
<div>
24
</div>
</td>
<td
class="cell"
data-date="1571932800000"
title="25/10/2019"
>
<div>
25
</div>
</td>
<td
class="cell"
data-date="1572019200000"
title="26/10/2019"
>
<div>
26
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-date="1572105600000"
title="27/10/2019"
>
<div>
27
</div>
</td>
<td
class="cell"
data-date="1572192000000"
title="28/10/2019"
>
<div>
28
</div>
</td>
<td
class="cell"
data-date="1572278400000"
title="29/10/2019"
>
<div>
29
</div>
</td>
<td
class="cell"
data-date="1572364800000"
title="30/10/2019"
>
<div>
30
</div>
</td>
<td
class="cell"
data-date="1572451200000"
title="31/10/2019"
>
<div>
31
</div>
</td>
<td
class="cell"
data-date="1572537600000"
title="01/11/2019"
>
<div>
1
</div>
</td>
<td
class="cell"
data-date="1572624000000"
title="02/11/2019"
>
<div>
2
</div>
</td>
</tr>
<tr
class="mx-date-row"
>
<!---->
<td
class="cell"
data-date="1572710400000"
title="03/11/2019"
>
<div>
3
</div>
</td>
<td
class="cell"
data-date="1572796800000"
title="04/11/2019"
>
<div>
4
</div>
</td>
<td
class="cell"
data-date="1572883200000"
title="05/11/2019"
>
<div>
5
</div>
</td>
<td
class="cell"
data-date="1572969600000"
title="06/11/2019"
>
<div>
6
</div>
</td>
<td
class="cell"
data-date="1573056000000"
title="07/11/2019"
>
<div>
7
</div>
</td>
<td
class="cell"
data-date="1573142400000"
title="08/11/2019"
>
<div>
8
</div>
</td>
<td
class="cell"
data-date="1573228800000"
title="09/11/2019"
>
<div>
9
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
`;
+146 -110
View File
@@ -1,119 +1,155 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TableMonth correct render 1`] = `
<table
class="mx-table mx-table-month"
getclasses="month => {
if (month === 9) {
return 'active';
}
return '';
}"
<div
class="mx-calendar mx-calendar-panel-month"
>
<tr>
<td
class="cell"
data-month="0"
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<div>
Jan
</div>
</td>
<td
class="cell"
data-month="1"
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<div>
Feb
</div>
</td>
<td
class="cell"
data-month="2"
<i
class="mx-icon-double-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<div>
Mar
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="3"
<button
class="mx-btn mx-btn-text"
type="button"
>
2019
</button>
</span>
</div>
<div
class="mx-calendar-content"
>
<table
class="mx-table mx-table-month"
>
<div>
Apr
</div>
</td>
<td
class="cell"
data-month="4"
>
<div>
May
</div>
</td>
<td
class="cell"
data-month="5"
>
<div>
Jun
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="6"
>
<div>
Jul
</div>
</td>
<td
class="cell"
data-month="7"
>
<div>
Aug
</div>
</td>
<td
class="cell"
data-month="8"
>
<div>
Sep
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="9"
>
<div>
Oct
</div>
</td>
<td
class="cell"
data-month="10"
>
<div>
Nov
</div>
</td>
<td
class="cell"
data-month="11"
>
<div>
Dec
</div>
</td>
</tr>
</table>
<tr>
<td
class="cell"
data-month="0"
>
<div>
Jan
</div>
</td>
<td
class="cell"
data-month="1"
>
<div>
Feb
</div>
</td>
<td
class="cell"
data-month="2"
>
<div>
Mar
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="3"
>
<div>
Apr
</div>
</td>
<td
class="cell"
data-month="4"
>
<div>
May
</div>
</td>
<td
class="cell"
data-month="5"
>
<div>
Jun
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-month="6"
>
<div>
Jul
</div>
</td>
<td
class="cell"
data-month="7"
>
<div>
Aug
</div>
</td>
<td
class="cell"
data-month="8"
>
<div>
Sep
</div>
</td>
</tr>
<tr>
<td
class="cell active"
data-month="9"
>
<div>
Oct
</div>
</td>
<td
class="cell"
data-month="10"
>
<div>
Nov
</div>
</td>
<td
class="cell"
data-month="11"
>
<div>
Dec
</div>
</td>
</tr>
</table>
</div>
</div>
`;
+136 -90
View File
@@ -1,98 +1,144 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TableYear decade=2010 1`] = `
<table
class="mx-table mx-table-year"
<div
class="mx-calendar mx-calendar-panel-year"
>
<tr>
<td
class="cell"
data-year="2010"
<div
class="mx-calendar-header"
>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-left"
type="button"
>
<div>
<i
class="mx-icon-double-left"
/>
</button>
<button
class="mx-btn mx-btn-text mx-btn-icon-double-right"
type="button"
>
<i
class="mx-icon-double-right"
/>
</button>
<span
class="mx-calendar-header-label"
>
<span>
2010
</div>
</td>
<td
class="cell"
data-year="2011"
>
<div>
2011
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2012"
>
<div>
2012
</div>
</td>
<td
class="cell"
data-year="2013"
>
<div>
2013
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2014"
>
<div>
2014
</div>
</td>
<td
class="cell"
data-year="2015"
>
<div>
2015
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2016"
>
<div>
2016
</div>
</td>
<td
class="cell"
data-year="2017"
>
<div>
2017
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2018"
>
<div>
2018
</div>
</td>
<td
class="cell"
data-year="2019"
>
<div>
</span>
<span
class="mx-calendar-decade-separator"
/>
<span>
2019
</div>
</td>
</tr>
</table>
</span>
</span>
</div>
<div
class="mx-calendar-content"
>
<table
class="mx-table mx-table-year"
>
<tr>
<td
class="cell"
data-year="2010"
>
<div>
2010
</div>
</td>
<td
class="cell"
data-year="2011"
>
<div>
2011
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2012"
>
<div>
2012
</div>
</td>
<td
class="cell"
data-year="2013"
>
<div>
2013
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2014"
>
<div>
2014
</div>
</td>
<td
class="cell"
data-year="2015"
>
<div>
2015
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2016"
>
<div>
2016
</div>
</td>
<td
class="cell"
data-year="2017"
>
<div>
2017
</div>
</td>
</tr>
<tr>
<td
class="cell"
data-year="2018"
>
<div>
2018
</div>
</td>
<td
class="cell"
data-year="2019"
>
<div>
2019
</div>
</td>
</tr>
</table>
</div>
</div>
`;
+75 -39
View File
@@ -1,3 +1,4 @@
/* eslint-disable no-await-in-loop */
import { mount, shallowMount } from '@vue/test-utils';
import CalendarPanel from '../src/calendar/calendar-panel';
@@ -14,8 +15,8 @@ describe('CalendarPanel', () => {
value: new Date(2019, 9, 4),
},
});
const tds = wrapper.findAll('.mx-table-date td');
tds.at(0).trigger('click');
const td = wrapper.find('.mx-table-date td');
td.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(new Date(2019, 8, 29));
});
@@ -26,8 +27,8 @@ describe('CalendarPanel', () => {
defaultValue: new Date(2019, 9, 1),
},
});
const tds = wrapper.findAll('.mx-table-month td > div');
tds.at(0).trigger('click');
const td = wrapper.find('.mx-table-month td > div');
td.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(new Date(2019, 0, 1));
});
@@ -38,8 +39,8 @@ describe('CalendarPanel', () => {
defaultValue: new Date(2019, 9, 1),
},
});
const tds = wrapper.findAll('.mx-table-year td > div');
tds.at(0).trigger('click');
const td = wrapper.find('.mx-table-year td > div');
td.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(new Date(2010, 0));
});
@@ -50,22 +51,37 @@ describe('CalendarPanel', () => {
defaultValue: new Date().setFullYear(11),
},
});
const tds = wrapper.findAll('.mx-table-year td > div');
tds.at(0).trigger('click');
const td = wrapper.find('.mx-table-year td > div');
td.trigger('click');
const expectedDate = new Date(10, 0).setFullYear(10);
expect(wrapper.emitted().select[0][0].getTime()).toBe(expectedDate);
});
it('feat: active class', () => {
it('feat: active class', async () => {
wrapper = mount(CalendarPanel);
const td = wrapper.find('.mx-table-date td:nth-child(6)');
expect(td.classes()).not.toContain('active');
wrapper.setProps({ value: new Date(2019, 9, 4) });
await wrapper.setProps({ value: new Date(2019, 9, 4) });
expect(td.classes()).toContain('active');
});
it('feat: click prev/next month', () => {
wrapper = shallowMount(CalendarPanel);
it('feat: panel change', async () => {
wrapper = mount(CalendarPanel);
const { vm } = wrapper;
await wrapper.find('.mx-btn-current-year').trigger('click');
expect(vm.panel).toBe('year');
await wrapper.find('.mx-table-year td > div').trigger('click');
expect(vm.panel).toBe('month');
await wrapper.find('.mx-table-month td > div').trigger('click');
expect(vm.panel).toBe('date');
await wrapper.find('.mx-btn-current-month').trigger('click');
expect(vm.panel).toBe('month');
await wrapper.find('.mx-calendar-header-label > button').trigger('click');
expect(vm.panel).toBe('year');
});
it('feat: click prev/next month', async () => {
wrapper = mount(CalendarPanel);
const nextBtn = wrapper.find('.mx-btn-icon-right');
const lastBtn = wrapper.find('.mx-btn-icon-left');
@@ -74,7 +90,7 @@ describe('CalendarPanel', () => {
while (count--) {
const oldYear = vm.calendarYear;
const oldMonth = vm.calendarMonth;
nextBtn.trigger('click');
await nextBtn.trigger('click');
const newYear = vm.calendarYear;
const newMonth = vm.calendarMonth;
if (oldMonth === 11) {
@@ -89,7 +105,7 @@ describe('CalendarPanel', () => {
while (count--) {
const oldYear = vm.calendarYear;
const oldMonth = vm.calendarMonth;
lastBtn.trigger('click');
await lastBtn.trigger('click');
const newYear = vm.calendarYear;
const newMonth = vm.calendarMonth;
if (oldMonth === 0) {
@@ -102,33 +118,42 @@ describe('CalendarPanel', () => {
}
});
it('feat: click prev/next year', () => {
wrapper = shallowMount(CalendarPanel, {
['date', 'month'].forEach(type => {
it(`feat: click prev/next year in ${type} panel`, async () => {
wrapper = mount(CalendarPanel, {
propsData: {
value: new Date(2018, 4, 5),
defaultPanel: type,
},
});
const nextBtn = wrapper.find('.mx-btn-icon-double-right');
const lastBtn = wrapper.find('.mx-btn-icon-double-left');
const { vm } = wrapper;
const oldYear = vm.calendarYear;
expect(oldYear).toBe(2018);
await nextBtn.trigger('click');
let newYear = vm.calendarYear;
expect(newYear).toBe(2019);
await lastBtn.trigger('click');
newYear = vm.calendarYear;
expect(newYear).toBe(oldYear);
});
});
it('feat: click prev/next decade', () => {
wrapper = mount(CalendarPanel, {
propsData: {
value: new Date(2018, 4, 5),
defaultPanel: 'year',
},
});
const nextBtn = wrapper.find('.mx-btn-icon-double-right');
const lastBtn = wrapper.find('.mx-btn-icon-double-left');
const yearBtn = wrapper.find('.mx-btn-current-year');
const { vm } = wrapper;
const oldYear = vm.calendarYear;
expect(oldYear).toBe(2018);
nextBtn.trigger('click');
let newYear = vm.calendarYear;
expect(newYear).toBe(2019);
lastBtn.trigger('click');
newYear = vm.calendarYear;
expect(newYear).toBe(oldYear);
// 年视图测试
yearBtn.trigger('click');
expect(vm.panel).toBe('year');
expect(vm.calendarDecade).toBe(2010);
nextBtn.trigger('click');
expect(vm.calendarDecade).toBe(2020);
expect(wrapper.vm.calendarYear).toBe(2028);
lastBtn.trigger('click');
lastBtn.trigger('click');
expect(vm.calendarDecade).toBe(2000);
expect(wrapper.vm.calendarYear).toBe(2008);
});
const renderType = type => {
@@ -139,11 +164,24 @@ describe('CalendarPanel', () => {
value: new Date(2019, 9, 1, 10),
},
});
expect(wrapper.element).toMatchSnapshot();
expect(wrapper.vm.panel).toBe(type);
});
};
['date', 'month', 'year'].forEach(renderType);
it('feat: select year to change the calendar', async () => {
wrapper = mount(CalendarPanel, {
propsData: {
value: new Date(2018, 4, 5),
defaultPanel: 'year',
},
});
await wrapper.find('.mx-table-year td > div').trigger('click');
expect(wrapper.vm.calendarYear).toBe(2010);
await wrapper.find('.mx-table-month td > div').trigger('click');
expect(wrapper.vm.calendarMonth).toBe(0);
});
it('prop: disabledDate', () => {
const disabledDate = date => {
return date < new Date(2019, 9, 1) || date > new Date(2019, 9, 20);
@@ -168,11 +206,12 @@ describe('CalendarPanel', () => {
expect(wrapper.emitted().select).toBeUndefined();
});
it('prop: partialUpdate', () => {
it('prop: partialUpdate', async () => {
wrapper = mount(CalendarPanel, {
propsData: {
value: new Date(2019, 9, 4),
partialUpdate: true,
defaultPanel: 'year',
},
});
wrapper
@@ -180,11 +219,8 @@ describe('CalendarPanel', () => {
.at(0)
.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(new Date(2010, 9, 4));
wrapper.setProps({ value: new Date(2010, 9, 4) });
wrapper
.findAll('.mx-table-month td > div')
.at(0)
.trigger('click');
await wrapper.setProps({ value: new Date(2010, 9, 4) });
wrapper.find('.mx-table-month td > div').trigger('click');
expect(wrapper.emitted().select[1][0]).toEqual(new Date(2010, 0, 4));
});
+8 -17
View File
@@ -1,5 +1,4 @@
import { mount } from '@vue/test-utils';
import flushPromises from 'flush-promises';
import CalendarRange from '../src/calendar/calendar-range';
import CalendarPanel from '../src/calendar/calendar-panel';
@@ -12,7 +11,6 @@ afterEach(() => {
describe('CalendarRange', () => {
it('feat: correct classes', () => {
wrapper = mount(CalendarRange, {
sync: false,
propsData: {
value: [new Date(2019, 9, 30), new Date(2019, 10, 2)],
},
@@ -29,38 +27,31 @@ describe('CalendarRange', () => {
it('feat: click range', async () => {
wrapper = mount(CalendarRange, {
sync: false,
propsData: {
defaultValue: new Date(2019, 9, 1),
},
});
expect(wrapper.vm.calendars).toEqual([new Date(2019, 9, 1), new Date(2019, 10, 1)]);
const tds = wrapper.findAll('.mx-table-date td');
tds.at(2).trigger('click');
await flushPromises();
await tds.at(2).trigger('click');
expect(wrapper.emitted().select).toBeUndefined();
tds.at(8).trigger('click');
await flushPromises();
await tds.at(8).trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual([new Date(2019, 9, 1), new Date(2019, 9, 7)]);
});
it('feat: calendars min gap', async () => {
wrapper = mount(CalendarRange, {
sync: false,
propsData: {
defaultValue: new Date(2019, 6, 1),
},
});
const panels = wrapper.findAll(CalendarPanel);
const startPanel = panels.at(0);
const endPanel = panels.at(1);
const firstRightIcon = wrapper.find('.mx-calendar-panel-date .mx-btn-icon-right');
const secondLeftIcon = wrapper.find('.mx-calendar-panel-date:nth-child(2) .mx-btn-icon-left');
startPanel.find('.mx-btn-icon-right').trigger('click');
await flushPromises();
await firstRightIcon.trigger('click');
expect(wrapper.vm.calendars).toEqual([new Date(2019, 7, 1), new Date(2019, 8, 1)]);
endPanel.find('.mx-btn-icon-left').trigger('click');
await flushPromises();
await secondLeftIcon.trigger('click');
expect(wrapper.vm.calendars).toEqual([new Date(2019, 6, 1), new Date(2019, 7, 1)]);
});
@@ -70,7 +61,7 @@ describe('CalendarRange', () => {
partialUpdate: true,
},
});
const panels = wrapper.findAll(CalendarPanel);
const panels = wrapper.findAllComponents(CalendarPanel);
const startPanel = panels.at(0);
const endPanel = panels.at(1);
expect(startPanel.vm.partialUpdate).toBe(false);
@@ -83,7 +74,7 @@ describe('CalendarRange', () => {
defaultValue: [new Date(2019, 9, 1), new Date(2019, 11, 1)],
},
});
const panels = wrapper.findAll(CalendarPanel);
const panels = wrapper.findAllComponents(CalendarPanel);
const startPanel = panels.at(0);
const endPanel = panels.at(1);
expect(startPanel.vm.calendarMonth).toBe(9);
+36 -35
View File
@@ -1,6 +1,7 @@
import { shallowMount, createWrapper, mount } from '@vue/test-utils';
import { format, parse } from 'date-fns';
import DatePicker from '../src/date-picker.vue';
import Popup from '../src/popup';
import DatePicker from '../src/date-picker';
let wrapper;
@@ -9,28 +10,28 @@ afterEach(() => {
});
describe('DatePicker', () => {
it('feat: open and close the popup', () => {
it('feat: open and close the popup', async () => {
wrapper = mount(DatePicker, {
attachToDocument: true,
attachTo: document.body,
});
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(false);
// expect click input should show the popup
const input = wrapper.find('input');
input.trigger('mousedown');
await input.trigger('mousedown');
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(true);
// expect click out side should hide the popup
const bodyWrapper = createWrapper(document.body);
bodyWrapper.trigger('mousedown');
await bodyWrapper.trigger('mousedown');
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(false);
// expect focus input should show the popop
input.trigger('focus');
await input.trigger('focus');
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(true);
// expoce keydown tab should hide the popup
input.trigger('keydown.tab');
await input.trigger('keydown.tab');
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(false);
});
it('feat: should init panel and calendar when reopen', () => {
it('feat: should init panel and calendar when reopen', async () => {
wrapper = mount(DatePicker, {
propsData: {
defaultValue: new Date(2019, 9, 1),
@@ -38,15 +39,15 @@ describe('DatePicker', () => {
},
});
const yearBtn = wrapper.find('.mx-btn-current-year');
yearBtn.trigger('click');
await yearBtn.trigger('click');
// change to year panel
expect(wrapper.find('.mx-calendar-panel-year').exists()).toBe(true);
wrapper.setProps({ open: false });
wrapper.setProps({ open: true });
await wrapper.setProps({ open: false });
await wrapper.setProps({ open: true });
expect(wrapper.find('.mx-calendar-panel-year').exists()).toBe(false);
});
it('prop: open', () => {
it('prop: open', async () => {
wrapper = mount(DatePicker, {
propsData: {
open: false,
@@ -55,7 +56,7 @@ describe('DatePicker', () => {
const { vm } = wrapper;
vm.openPopup();
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(false);
wrapper.setProps({ open: true });
await wrapper.setProps({ open: true });
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(true);
vm.closePopup();
expect(wrapper.find('.mx-datepicker-popup').exists()).toBe(true);
@@ -161,7 +162,7 @@ describe('DatePicker', () => {
expect(tableDate.element).toMatchSnapshot();
});
it('prop: valueType', () => {
it('prop: valueType', async () => {
const value = new Date(2019, 9, 20);
const emitValue = new Date(2019, 9, 22);
wrapper = shallowMount(DatePicker, {
@@ -173,13 +174,13 @@ describe('DatePicker', () => {
const { vm } = wrapper;
expect(vm.text).toBe('2019/10/20');
vm.emitValue(emitValue);
wrapper.setProps({ valueType: 'format', value: '2019/10/20' });
await wrapper.setProps({ valueType: 'format', value: '2019/10/20' });
expect(vm.text).toBe('2019/10/20');
vm.emitValue(emitValue);
wrapper.setProps({ valueType: 'timestamp', value: value.getTime() });
await wrapper.setProps({ valueType: 'timestamp', value: value.getTime() });
expect(vm.text).toBe('2019/10/20');
vm.emitValue(emitValue);
wrapper.setProps({ valueType: 'DD/MM/YYYY', value: '20/10/2019' });
await wrapper.setProps({ valueType: 'DD/MM/YYYY', value: '20/10/2019' });
expect(vm.text).toBe('2019/10/20');
vm.emitValue(emitValue);
const emitted = wrapper.emitted();
@@ -191,12 +192,13 @@ describe('DatePicker', () => {
]);
});
it('prop: shortcut', () => {
it('prop: shortcut', async () => {
const date = new Date(2019, 4, 10);
wrapper = shallowMount(DatePicker, {
propsData: {
open: true,
valueType: 'YYYY/MM/DD',
range: false,
shortcuts: [
{
text: 'Today',
@@ -207,12 +209,11 @@ describe('DatePicker', () => {
],
},
});
const btn = wrapper.find('.mx-btn-shortcut');
btn.trigger('click');
await btn.trigger('click');
const emitted = wrapper.emitted();
expect(emitted.input).toEqual([['2019/05/10']]);
wrapper.setProps({
await wrapper.setProps({
range: true,
shortcuts: [
{
@@ -234,7 +235,7 @@ describe('DatePicker', () => {
popupClass: 'test',
},
});
const popup = wrapper.find('.mx-datepicker-popup');
const popup = wrapper.findComponent(Popup);
expect(popup.classes()).toContain('test');
});
@@ -247,25 +248,25 @@ describe('DatePicker', () => {
},
},
});
const popup = wrapper.find('.mx-datepicker-popup');
const popup = wrapper.findComponent(Popup);
expect(popup.element.style.color).toBe('red');
});
it('prop: confirm', () => {
it('prop: confirm', async () => {
wrapper = shallowMount(DatePicker, {
propsData: {
confirm: true,
},
});
const { vm } = wrapper;
vm.openPopup();
await wrapper.find('input').trigger('focus');
const btn = wrapper.find('.mx-datepicker-btn-confirm');
expect(btn.exists()).toBe(true);
// click the date expect popup don't close
vm.handleSelectDate(new Date(2018, 5, 5));
expect(wrapper.emitted().input).toBeUndefined();
expect(vm.popupVisible).toBe(true);
btn.trigger('click');
await btn.trigger('click');
expect(wrapper.emitted().input[0][0]).toEqual(new Date(2018, 5, 5));
expect(vm.popupVisible).toBe(false);
});
@@ -291,7 +292,7 @@ describe('DatePicker', () => {
},
});
const popup = wrapper.find('.mx-datepicker-popup');
const popup = wrapper.findComponent(Popup);
expect(popup.element.parentNode).toBe(document.body);
});
@@ -366,7 +367,7 @@ describe('DatePicker', () => {
expect(wrapper.emitted().pick[0][0]).toEqual(new Date(2019, 8, 29));
});
it('Ignore whitespace around separator on manual range input', () => {
it('Ignore whitespace around separator on manual range input', async () => {
const rangeSeparator = ' ~ ';
const text = '2020-02-12';
wrapper = mount(DatePicker, {
@@ -378,13 +379,13 @@ describe('DatePicker', () => {
});
const input = wrapper.find('input');
input.setValue(`${text} ${rangeSeparator} ${text}`);
input.trigger('change');
input.setValue(`${text}${rangeSeparator.trim()}${text}`);
input.trigger('change');
wrapper.setProps({ rangeSeparator: ' - ' });
input.setValue(`${text} - ${text}`);
input.trigger('change');
await input.setValue(`${text} ${rangeSeparator} ${text}`);
await input.trigger('change');
await input.setValue(`${text}${rangeSeparator.trim()}${text}`);
await input.trigger('change');
await wrapper.setProps({ rangeSeparator: ' - ' });
await input.setValue(`${text} - ${text}`);
await input.trigger('change');
expect(wrapper.emitted().input).toEqual([[[text, text]], [[text, text]], [[text, text]]]);
});
+7 -7
View File
@@ -8,7 +8,7 @@ afterEach(() => {
});
describe('DatetimePanel', () => {
it('feat: click date', () => {
it('feat: click date', async () => {
wrapper = mount(DatetimePanel, {
propsData: {
type: 'datetime',
@@ -16,16 +16,16 @@ describe('DatetimePanel', () => {
},
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
td.trigger('click');
await td.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(new Date(2019, 9, 2, 12));
let timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(true);
timeTitle.trigger('click');
await timeTitle.trigger('click');
timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(false);
});
it('feat: disabled time', () => {
it('feat: disabled time', async () => {
const disabledDate = date => date < new Date(2019, 9, 2);
const disabledTime = date => date < new Date(2019, 9, 2, 12);
wrapper = mount(DatetimePanel, {
@@ -36,14 +36,14 @@ describe('DatetimePanel', () => {
},
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
td.trigger('click');
await td.trigger('click');
expect(wrapper.emitted().select).toBeUndefined();
const timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.text()).toBe('2019-10-02');
// set the defaultValue is not disabled
const defaultValue = new Date(2019, 9, 2, 12);
wrapper.setProps({ defaultValue });
td.trigger('click');
await wrapper.setProps({ defaultValue });
await td.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(defaultValue);
});
});
+7 -14
View File
@@ -1,5 +1,4 @@
import { mount } from '@vue/test-utils';
import flushPromises from 'flush-promises';
import DatetimeRange from '../src/datetime/datetime-range';
let wrapper;
@@ -11,7 +10,6 @@ afterEach(() => {
describe('DatetimeRange', () => {
it('feat: click dates', async () => {
wrapper = mount(DatetimeRange, {
sync: false,
propsData: {
type: 'datetime',
value: [new Date(2019, 9, 4, 18), new Date(2019, 9, 6, 12)],
@@ -20,21 +18,18 @@ describe('DatetimeRange', () => {
const td = wrapper.find('.mx-table-date td:nth-child(4)');
const td2 = wrapper.find('.mx-table-date td:nth-child(5)');
td.trigger('click');
td2.trigger('click');
await flushPromises();
await td2.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual([
new Date(2019, 9, 2, 18),
new Date(2019, 9, 3, 12),
]);
let timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(true);
timeTitle.trigger('click');
await flushPromises();
await timeTitle.trigger('click');
timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.exists()).toBe(false);
td.trigger('click');
td.trigger('click');
await flushPromises();
await td.trigger('click');
expect(wrapper.emitted().select[1][0]).toEqual([
new Date(2019, 9, 2, 18),
new Date(2019, 9, 2, 18),
@@ -54,16 +49,14 @@ describe('DatetimeRange', () => {
});
const td = wrapper.find('.mx-table-date td:nth-child(4)');
td.trigger('click');
td.trigger('click');
await flushPromises();
await td.trigger('click');
expect(wrapper.emitted().select).toBeUndefined();
const timeTitle = wrapper.find('.mx-time-header-title');
expect(timeTitle.text()).toBe('2019-10-02');
const defaultValue = [new Date(2019, 9, 2, 12), new Date(2019, 9, 2, 12)];
wrapper.setProps({ defaultValue });
td.trigger('click');
td.trigger('click');
await flushPromises();
await wrapper.setProps({ defaultValue });
await td.trigger('click');
await td.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(defaultValue);
});
});
+11 -6
View File
@@ -1,5 +1,6 @@
import { mount } from '@vue/test-utils';
import DatePicker from '../src/date-picker.vue';
import DatePicker from '../src/date-picker';
import Calendar from '../src/calendar/calendar-panel';
import '../src/locale/zh-cn';
let wrapper;
@@ -20,7 +21,7 @@ describe('Locale', () => {
expect(wrapper.find('.mx-table-date td').element.title).toBe('2019-09-30');
});
it('prop: lang - string', () => {
it('prop: lang - string', async () => {
wrapper = mount(DatePicker, {
propsData: {
value: new Date(2019, 9, 10),
@@ -30,14 +31,18 @@ describe('Locale', () => {
},
});
expect(wrapper.find('.mx-table-date th').text()).toBe('Su');
expect(wrapper.find('.mx-table-month td').text()).toBe('Jan');
expect(wrapper.find('.mx-btn-current-month').text()).toBe('Oct');
expect(wrapper.find('.mx-table-date .active').element.title).toBe('Oct 10, 2019');
expect(wrapper.find('.mx-btn-current-month').text()).toBe('Oct');
await wrapper.findComponent(Calendar).setData({ panel: 'month' });
// expect(wrapper.vm.panel).toBe('month');
expect(wrapper.find('.mx-table-month td').text()).toBe('Jan');
wrapper.setProps({ lang: 'zh-cn' });
await wrapper.findComponent(Calendar).setData({ panel: 'date' });
expect(wrapper.find('.mx-table-date th').text()).toBe('一');
expect(wrapper.find('.mx-table-month td').text()).toBe('1月');
expect(wrapper.find('.mx-btn-current-month').text()).toBe('10月');
expect(wrapper.find('.mx-table-date .active').element.title).toBe('10月 10, 2019');
expect(wrapper.find('.mx-btn-current-month').text()).toBe('10月');
await wrapper.findComponent(Calendar).setData({ panel: 'month' });
expect(wrapper.find('.mx-table-month td').text()).toBe('1月');
});
it('prop: lang - object', () => {
+1 -3
View File
@@ -11,9 +11,7 @@ describe('TableDate', () => {
it('corrent render', () => {
wrapper = mount(TableDate, {
propsData: {
calendarYear: 2019,
calendarMonth: 9,
firstDayOfWeek: 1,
calendar: new Date(2019, 9, 1, 0, 0, 0),
titleFormat: 'DD/MM/YYYY',
},
});
+2 -1
View File
@@ -11,7 +11,8 @@ describe('TableMonth', () => {
it('correct render', () => {
wrapper = mount(TableMonth, {
propsData: {
getClasses: month => {
calendar: new Date(2019, 9, 1, 0, 0, 0),
getCellClasses: month => {
if (month === 9) {
return 'active';
}
+1 -1
View File
@@ -11,7 +11,7 @@ describe('TableYear', () => {
it('decade=2010', () => {
wrapper = mount(TableYear, {
propsData: {
decade: 2010,
calendar: new Date(2019, 9, 1, 0, 0, 0),
},
});
expect(wrapper.element).toMatchSnapshot();
+5 -5
View File
@@ -62,7 +62,7 @@ describe('TimePanel', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('feat: emit select event when click', () => {
it('feat: emit select event when click', async () => {
wrapper = mount(TimePanel, {
propsData: {
format: 'hh:mm:ss a',
@@ -72,15 +72,15 @@ describe('TimePanel', () => {
const hour = wrapper.find('[data-type=hour] li:nth-child(2)');
hour.trigger('click');
expect(wrapper.emitted().select[0][0]).toEqual(new Date(2019, 9, 10, 1));
wrapper.setProps({ value: new Date(2019, 9, 10, 1) });
await wrapper.setProps({ value: new Date(2019, 9, 10, 1) });
const minute = wrapper.find('[data-type=minute] li:nth-child(2)');
minute.trigger('click');
expect(wrapper.emitted().select[1][0]).toEqual(new Date(2019, 9, 10, 1, 1));
wrapper.setProps({ value: new Date(2019, 9, 10, 1, 1) });
await wrapper.setProps({ value: new Date(2019, 9, 10, 1, 1) });
const second = wrapper.find('[data-type=second] li:nth-child(2)');
second.trigger('click');
expect(wrapper.emitted().select[2][0]).toEqual(new Date(2019, 9, 10, 1, 1, 1));
wrapper.setProps({ value: new Date(2019, 9, 10, 1, 1, 1) });
await wrapper.setProps({ value: new Date(2019, 9, 10, 1, 1, 1) });
const pm = wrapper.find('[data-type=ampm] li:nth-child(2)');
pm.trigger('click');
expect(wrapper.emitted().select[3][0]).toEqual(new Date(2019, 9, 10, 13, 1, 1));
@@ -105,7 +105,7 @@ describe('TimePanel', () => {
format: {},
},
});
const cols = wrapper.find(ListColumns);
const cols = wrapper.findComponent(ListColumns);
expect(cols.props('showHour')).toBe(true);
expect(cols.props('showMinute')).toBe(true);
expect(cols.props('showSecond')).toBe(true);
+87 -56
View File
@@ -1800,7 +1800,8 @@
"version": "7.0.7",
"resolved": "https://registry.npm.taobao.org/@types/babel-types/download/@types/babel-types-7.0.7.tgz",
"integrity": "sha1-Zn6xZA6AOUNgKAVXN9K5mG7jNuM=",
"dev": true
"dev": true,
"optional": true
},
"@types/babel__core": {
"version": "7.1.3",
@@ -1848,6 +1849,7 @@
"resolved": "https://registry.npm.taobao.org/@types/babylon/download/@types/babylon-6.16.5.tgz",
"integrity": "sha1-HFZB22nrjN83jt0ltL53VL7rSLQ=",
"dev": true,
"optional": true,
"requires": {
"@types/babel-types": "*"
}
@@ -2116,13 +2118,14 @@
}
},
"@vue/test-utils": {
"version": "1.0.0-beta.29",
"resolved": "https://registry.npm.taobao.org/@vue/test-utils/download/@vue/test-utils-1.0.0-beta.29.tgz",
"integrity": "sha1-yULPJeiRzwgbagMzK0rh70MHJvA=",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-1.1.1.tgz",
"integrity": "sha512-/32538ilZ9qSiu1gui7zfBn+IFy+zoTaQTZ1qiLfQXzZtaeAD23kJMrnqaoe2w8JzJoXuqHUl2ruuStG8rwFYQ==",
"dev": true,
"requires": {
"dom-event-types": "^1.0.0",
"lodash": "^4.17.4"
"lodash": "^4.17.15",
"pretty": "^2.0.0"
}
},
"JSONStream": {
@@ -2221,9 +2224,10 @@
},
"align-text": {
"version": "0.1.4",
"resolved": "http://registry.npm.taobao.org/align-text/download/align-text-0.1.4.tgz",
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2",
"longest": "^1.0.1",
@@ -2235,6 +2239,7 @@
"resolved": "https://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
@@ -2927,7 +2932,7 @@
},
"big.js": {
"version": "3.2.0",
"resolved": "http://registry.npm.taobao.org/big.js/download/big.js-3.2.0.tgz",
"resolved": "https://registry.npm.taobao.org/big.js/download/big.js-3.2.0.tgz",
"integrity": "sha1-pfwpi4G54Nyi5FiCR4S2XFK6WI4=",
"dev": true
},
@@ -3305,7 +3310,7 @@
},
"center-align": {
"version": "0.1.3",
"resolved": "http://registry.npm.taobao.org/center-align/download/center-align-0.1.3.tgz",
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
"dev": true,
"optional": true,
@@ -3758,6 +3763,7 @@
"resolved": "https://registry.npm.taobao.org/constantinople/download/constantinople-3.1.2.tgz",
"integrity": "sha1-1F7XJPV9PRBQABen06iJwTga5kc=",
"dev": true,
"optional": true,
"requires": {
"@types/babel-types": "^7.0.0",
"@types/babylon": "^6.16.2",
@@ -4729,9 +4735,10 @@
}
},
"date-fns": {
"version": "2.7.0",
"resolved": "https://registry.npm.taobao.org/date-fns/download/date-fns-2.7.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdate-fns%2Fdownload%2Fdate-fns-2.7.0.tgz",
"integrity": "sha1-gnHZQ8xGNqHydpjxuNap8c63QCY="
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz",
"integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==",
"dev": true
},
"date-format-parse": {
"version": "0.2.5",
@@ -4994,8 +5001,8 @@
},
"dom-event-types": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/dom-event-types/download/dom-event-types-1.0.0.tgz",
"integrity": "sha1-WDCgop4b+Df+UKcM2ApZcjKBPK4=",
"resolved": "https://registry.npmjs.org/dom-event-types/-/dom-event-types-1.0.0.tgz",
"integrity": "sha512-2G2Vwi2zXTHBGqXHsJ4+ak/iP0N8Ar+G8a7LiD2oup5o4sQWytwqqrZu/O6hIMV0KMID2PL69OhpshLO0n7UJQ==",
"dev": true
},
"dom-serializer": {
@@ -5155,7 +5162,7 @@
},
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npm.taobao.org/emojis-list/download/emojis-list-2.1.0.tgz",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true
},
@@ -5188,7 +5195,7 @@
},
"errno": {
"version": "0.1.7",
"resolved": "http://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz",
"resolved": "https://registry.npm.taobao.org/errno/download/errno-0.1.7.tgz",
"integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=",
"dev": true,
"optional": true,
@@ -6145,7 +6152,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@@ -6166,12 +6174,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -6186,17 +6196,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -6313,7 +6326,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@@ -6325,6 +6339,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -6339,6 +6354,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -6346,12 +6362,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -6370,6 +6388,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -6450,7 +6469,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -6462,6 +6482,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -6547,7 +6568,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -6583,6 +6605,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -6602,6 +6625,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -6645,12 +6669,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@@ -7304,7 +7330,7 @@
},
"html-tags": {
"version": "2.0.0",
"resolved": "https://registry.npm.taobao.org/html-tags/download/html-tags-2.0.0.tgz",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz",
"integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=",
"dev": true
},
@@ -7554,7 +7580,7 @@
},
"image-size": {
"version": "0.5.5",
"resolved": "https://registry.npm.taobao.org/image-size/download/image-size-0.5.5.tgz",
"resolved": "https://registry.npm.taobao.org/image-size/download/image-size-0.5.5.tgz?cache=0&sync_timestamp=1569841767280&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fimage-size%2Fdownload%2Fimage-size-0.5.5.tgz",
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
"dev": true,
"optional": true
@@ -7883,7 +7909,7 @@
"dependencies": {
"acorn": {
"version": "4.0.13",
"resolved": "https://registry.npm.taobao.org/acorn/download/acorn-4.0.13.tgz?cache=0&sync_timestamp=1583824513691&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-4.0.13.tgz",
"resolved": "https://registry.npm.taobao.org/acorn/download/acorn-4.0.13.tgz",
"integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
"dev": true,
"optional": true
@@ -8724,7 +8750,8 @@
"version": "1.0.2",
"resolved": "https://registry.npm.taobao.org/js-stringify/download/js-stringify-1.0.2.tgz",
"integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=",
"dev": true
"dev": true,
"optional": true
},
"js-tokens": {
"version": "4.0.0",
@@ -8895,7 +8922,7 @@
},
"lazy-cache": {
"version": "1.0.4",
"resolved": "http://registry.npm.taobao.org/lazy-cache/download/lazy-cache-1.0.4.tgz",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
"dev": true,
"optional": true
@@ -9317,7 +9344,7 @@
},
"loader-utils": {
"version": "0.2.17",
"resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-0.2.17.tgz?cache=0&sync_timestamp=1584445611428&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Floader-utils%2Fdownload%2Floader-utils-0.2.17.tgz",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
"integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
"dev": true,
"requires": {
@@ -9371,7 +9398,7 @@
},
"lodash.kebabcase": {
"version": "4.1.1",
"resolved": "https://registry.npm.taobao.org/lodash.kebabcase/download/lodash.kebabcase-4.1.1.tgz",
"resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz",
"integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=",
"dev": true
},
@@ -9523,9 +9550,10 @@
},
"longest": {
"version": "1.0.1",
"resolved": "http://registry.npm.taobao.org/longest/download/longest-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
"dev": true
"dev": true,
"optional": true
},
"loose-envify": {
"version": "1.4.0",
@@ -11444,7 +11472,7 @@
},
"postcss": {
"version": "5.2.18",
"resolved": "https://registry.npm.taobao.org/postcss/download/postcss-5.2.18.tgz?cache=0&sync_timestamp=1581994853208&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpostcss%2Fdownload%2Fpostcss-5.2.18.tgz",
"resolved": "https://registry.npm.taobao.org/postcss/download/postcss-5.2.18.tgz",
"integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=",
"dev": true,
"requires": {
@@ -11456,7 +11484,7 @@
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz",
"resolved": "https://registry.npm.taobao.org/strip-ansi/download/strip-ansi-3.0.1.tgz?cache=0&sync_timestamp=1573280518303&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstrip-ansi%2Fdownload%2Fstrip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
@@ -11803,7 +11831,7 @@
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fpromise%2Fdownload%2Fpromise-7.3.1.tgz",
"resolved": "https://registry.npm.taobao.org/promise/download/promise-7.3.1.tgz",
"integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=",
"dev": true,
"optional": true,
@@ -11829,7 +11857,7 @@
},
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npm.taobao.org/prr/download/prr-1.0.1.tgz",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
"dev": true,
"optional": true
@@ -11910,7 +11938,8 @@
"version": "1.3.3",
"resolved": "https://registry.npm.taobao.org/pug-error/download/pug-error-1.3.3.tgz",
"integrity": "sha1-80L7AIdS1YA0wYXeA2At2f/hX6Y=",
"dev": true
"dev": true,
"optional": true
},
"pug-filters": {
"version": "3.1.1",
@@ -11930,7 +11959,7 @@
"dependencies": {
"camelcase": {
"version": "1.2.1",
"resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-1.2.1.tgz?cache=0&sync_timestamp=1586229901005&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcamelcase%2Fdownload%2Fcamelcase-1.2.1.tgz",
"resolved": "https://registry.npm.taobao.org/camelcase/download/camelcase-1.2.1.tgz",
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
"dev": true,
"optional": true
@@ -11949,7 +11978,7 @@
},
"uglify-js": {
"version": "2.8.29",
"resolved": "https://registry.npm.taobao.org/uglify-js/download/uglify-js-2.8.29.tgz",
"resolved": "https://registry.npm.taobao.org/uglify-js/download/uglify-js-2.8.29.tgz?cache=0&sync_timestamp=1573031889241&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fuglify-js%2Fdownload%2Fuglify-js-2.8.29.tgz",
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
"dev": true,
"optional": true,
@@ -11961,14 +11990,14 @@
},
"wordwrap": {
"version": "0.0.2",
"resolved": "http://registry.npm.taobao.org/wordwrap/download/wordwrap-0.0.2.tgz",
"resolved": "https://registry.npm.taobao.org/wordwrap/download/wordwrap-0.0.2.tgz",
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
"dev": true,
"optional": true
},
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npm.taobao.org/yargs/download/yargs-3.10.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fyargs%2Fdownload%2Fyargs-3.10.0.tgz",
"resolved": "https://registry.npm.taobao.org/yargs/download/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
"dev": true,
"optional": true,
@@ -12030,7 +12059,8 @@
"version": "2.0.5",
"resolved": "https://registry.npm.taobao.org/pug-runtime/download/pug-runtime-2.0.5.tgz",
"integrity": "sha1-baeXbDa/IvaOczw1kkDYrnoylTo=",
"dev": true
"dev": true,
"optional": true
},
"pug-strip-comments": {
"version": "1.0.4",
@@ -12046,7 +12076,8 @@
"version": "1.1.8",
"resolved": "https://registry.npm.taobao.org/pug-walk/download/pug-walk-1.1.8.tgz",
"integrity": "sha1-tAj2fyeRL4wh2i9FtyMMS9Kl6no=",
"dev": true
"dev": true,
"optional": true
},
"pump": {
"version": "3.0.0",
@@ -12622,7 +12653,7 @@
},
"right-align": {
"version": "0.1.3",
"resolved": "http://registry.npm.taobao.org/right-align/download/right-align-0.1.3.tgz",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
"dev": true,
"optional": true,
@@ -13685,7 +13716,7 @@
},
"stylus": {
"version": "0.54.7",
"resolved": "https://registry.npm.taobao.org/stylus/download/stylus-0.54.7.tgz",
"resolved": "https://registry.npm.taobao.org/stylus/download/stylus-0.54.7.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstylus%2Fdownload%2Fstylus-0.54.7.tgz",
"integrity": "sha1-xs5Hk5Ze5Ti86+UPMVN7/ATYjNI=",
"dev": true,
"optional": true,
@@ -13702,7 +13733,7 @@
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
"resolved": "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"dev": true,
"optional": true,
@@ -13726,7 +13757,7 @@
},
"source-map": {
"version": "0.7.3",
"resolved": "http://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz",
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.7.3.tgz",
"integrity": "sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=",
"dev": true,
"optional": true
@@ -13744,7 +13775,7 @@
},
"svg-tags": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/svg-tags/download/svg-tags-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz",
"integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=",
"dev": true
},
@@ -14178,7 +14209,7 @@
},
"uglify-to-browserify": {
"version": "1.0.2",
"resolved": "http://registry.npm.taobao.org/uglify-to-browserify/download/uglify-to-browserify-1.0.2.tgz",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
"dev": true,
"optional": true
@@ -14723,7 +14754,7 @@
},
"window-size": {
"version": "0.1.0",
"resolved": "http://registry.npm.taobao.org/window-size/download/window-size-0.1.0.tgz",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
"dev": true,
"optional": true
@@ -14741,14 +14772,14 @@
"dependencies": {
"acorn": {
"version": "3.3.0",
"resolved": "https://registry.npm.taobao.org/acorn/download/acorn-3.3.0.tgz?cache=0&sync_timestamp=1583824513691&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-3.3.0.tgz",
"resolved": "https://registry.npm.taobao.org/acorn/download/acorn-3.3.0.tgz",
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
"dev": true,
"optional": true
},
"acorn-globals": {
"version": "3.1.0",
"resolved": "https://registry.npm.taobao.org/acorn-globals/download/acorn-globals-3.1.0.tgz?cache=0&sync_timestamp=1583643398087&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-globals%2Fdownload%2Facorn-globals-3.1.0.tgz",
"resolved": "https://registry.npm.taobao.org/acorn-globals/download/acorn-globals-3.1.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn-globals%2Fdownload%2Facorn-globals-3.1.0.tgz",
"integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=",
"dev": true,
"optional": true,
@@ -14758,7 +14789,7 @@
"dependencies": {
"acorn": {
"version": "4.0.13",
"resolved": "https://registry.npm.taobao.org/acorn/download/acorn-4.0.13.tgz?cache=0&sync_timestamp=1583824513691&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Facorn%2Fdownload%2Facorn-4.0.13.tgz",
"resolved": "https://registry.npm.taobao.org/acorn/download/acorn-4.0.13.tgz",
"integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
"dev": true,
"optional": true
+2 -2
View File
@@ -48,7 +48,6 @@
"vue": "^2.5.0"
},
"dependencies": {
"date-fns": "^2.0.1",
"date-format-parse": "^0.2.5"
},
"devDependencies": {
@@ -62,7 +61,7 @@
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
"@vue/babel-preset-jsx": "^1.1.2",
"@vue/component-compiler-utils": "^3.0.0",
"@vue/test-utils": "^1.0.0-beta.29",
"@vue/test-utils": "^1.1.1",
"acorn": "^7.0.0",
"autoprefixer": "^9.7.1",
"babel-core": "^7.0.0-bridge.0",
@@ -72,6 +71,7 @@
"core-js": "^3.3.5",
"coveralls": "^3.0.7",
"cross-env": "^6.0.3",
"date-fns": "^2.16.1",
"eslint": "^6.2.2",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-config-prettier": "^6.1.0",
+1 -1
View File
@@ -5,7 +5,7 @@ import vue from 'rollup-plugin-vue';
import { terser } from 'rollup-plugin-terser';
import pkg from './package.json';
const external = id => /date-fns/.test(id);
const external = Object.keys(pkg.dependencies);
const input = 'src/index.js';
+259
View File
@@ -0,0 +1,259 @@
import {
getValidDate,
isValidDate,
createDate,
setMonth,
startOfYear,
startOfMonth,
startOfDay,
} from '../util/date';
import TableDate from './table-date';
import TableMonth from './table-month';
import TableYear from './table-year';
export default {
name: 'CalendarPanel',
inject: {
prefixClass: {
default: 'mx',
},
dispatchDatePicker: {
default: () => () => {},
},
},
props: {
value: {},
defaultValue: {
default() {
const date = new Date();
date.setHours(0, 0, 0, 0);
return date;
},
},
defaultPanel: {
type: String,
},
disabledDate: {
type: Function,
default: () => false,
},
type: {
type: String,
default: 'date',
},
getClasses: {
type: Function,
default: () => [],
},
showWeekNumber: {
type: Boolean,
default: undefined,
},
titleFormat: {
type: String,
default: 'YYYY-MM-DD',
},
calendar: Date,
// update date when select year or month
partialUpdate: {
type: Boolean,
default: false,
},
},
data() {
const panels = ['date', 'month', 'year'];
const index = Math.max(panels.indexOf(this.type), panels.indexOf(this.defaultPanel));
const panel = index !== -1 ? panels[index] : 'date';
return {
panel,
innerCalendar: new Date(),
};
},
computed: {
innerValue() {
const value = Array.isArray(this.value) ? this.value : [this.value];
const map = {
year: startOfYear,
month: startOfMonth,
date: startOfDay,
};
const start = map[this.type] || map.date;
return value.filter(isValidDate).map(v => start(v));
},
calendarYear() {
return this.innerCalendar.getFullYear();
},
calendarMonth() {
return this.innerCalendar.getMonth();
},
},
watch: {
value: {
immediate: true,
handler: 'initCalendar',
},
calendar: {
handler: 'initCalendar',
},
defaultValue: {
handler: 'initCalendar',
},
},
methods: {
initCalendar() {
let calendarDate = this.calendar;
if (!isValidDate(calendarDate)) {
const { length } = this.innerValue;
calendarDate = getValidDate(length > 0 ? this.innerValue[length - 1] : this.defaultValue);
}
this.innerCalendar = startOfMonth(calendarDate);
},
isDisabled(date) {
return this.disabledDate(new Date(date), this.innerValue);
},
emitDate(date, type) {
if (!this.isDisabled(date)) {
this.$emit('select', date, type, this.innerValue);
// someone need get the first selected date to set range value. (#429)
this.dispatchDatePicker('pick', date, type);
}
},
handleCalendarChange(calendar, type) {
const oldCalendar = new Date(this.innerCalendar);
this.innerCalendar = calendar;
this.$emit('update:calendar', calendar);
this.dispatchDatePicker('calendar-change', calendar, oldCalendar, type);
},
handelPanelChange(panel) {
this.panel = panel;
},
handleSelectYear(year) {
if (this.type === 'year') {
const date = this.getYearCellDate(year);
this.emitDate(date, 'year');
} else {
this.handleCalendarChange(createDate(year, this.calendarMonth), 'year');
this.handelPanelChange('month');
if (this.partialUpdate && this.innerValue.length === 1) {
const date = new Date(this.innerValue[0]);
date.setFullYear(year);
this.emitDate(date, 'year');
}
}
},
handleSelectMonth(month) {
if (this.type === 'month') {
const date = this.getMonthCellDate(month);
this.emitDate(date, 'month');
} else {
this.handleCalendarChange(createDate(this.calendarYear, month), 'month');
this.handelPanelChange('date');
if (this.partialUpdate && this.innerValue.length === 1) {
const date = new Date(this.innerValue[0]);
date.setFullYear(this.calendarYear);
this.emitDate(setMonth(date, month), 'month');
}
}
},
handleSelectDate(date) {
this.emitDate(date, this.type === 'week' ? 'week' : 'date');
},
getMonthCellDate(month) {
return createDate(this.calendarYear, month);
},
getYearCellDate(year) {
return createDate(year, 0);
},
getDateClasses(cellDate) {
const notCurrentMonth = cellDate.getMonth() !== this.calendarMonth;
const classes = [];
if (cellDate.getTime() === new Date().setHours(0, 0, 0, 0)) {
classes.push('today');
}
if (notCurrentMonth) {
classes.push('not-current-month');
}
const state = this.getStateClass(cellDate);
if (!(state === 'active' && notCurrentMonth)) {
classes.push(state);
}
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getMonthClasses(month) {
if (this.type !== 'month') {
return this.calendarMonth === month ? 'active' : '';
}
const classes = [];
const cellDate = this.getMonthCellDate(month);
classes.push(this.getStateClass(cellDate));
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getYearClasses(year) {
if (this.type !== 'year') {
return this.calendarYear === year ? 'active' : '';
}
const classes = [];
const cellDate = this.getYearCellDate(year);
classes.push(this.getStateClass(cellDate));
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getStateClass(cellDate) {
if (this.isDisabled(cellDate)) {
return 'disabled';
}
if (this.innerValue.some(v => v.getTime() === cellDate.getTime())) {
return 'active';
}
return '';
},
getWeekState(row) {
if (this.type !== 'week') return '';
const start = row[0].getTime();
const end = row[6].getTime();
const active = this.innerValue.some(v => {
const time = v.getTime();
return time >= start && time <= end;
});
return active ? `${this.prefixClass}-active-week` : '';
},
},
render() {
const { panel, innerCalendar } = this;
if (panel === 'year') {
return (
<TableYear
calendar={innerCalendar}
getCellClasses={this.getYearClasses}
onSelect={this.handleSelectYear}
onChangecalendar={this.handleCalendarChange}
/>
);
}
if (panel === 'month') {
return (
<TableMonth
calendar={innerCalendar}
getCellClasses={this.getMonthClasses}
onSelect={this.handleSelectMonth}
onChangepanel={this.handelPanelChange}
onChangecalendar={this.handleCalendarChange}
/>
);
}
return (
<TableDate
class={{ [`${this.prefixClass}-calendar-week-mode`]: this.type === 'week' }}
calendar={innerCalendar}
getCellClasses={this.getDateClasses}
getRowClasses={this.getWeekState}
titleFormat={this.titleFormat}
showWeekNumber={
typeof showWeekNumber === 'boolean' ? this.showWeekNumber : this.type === 'week'
}
onSelect={this.handleSelectDate}
onChangepanel={this.handelPanelChange}
onChangecalendar={this.handleCalendarChange}
/>
);
},
};
-379
View File
@@ -1,379 +0,0 @@
<template>
<div
:class="[
`${prefixClass}-calendar`,
`${prefixClass}-calendar-panel-${panel}`,
{ [`${prefixClass}-calendar-week-mode`]: type === 'week' },
]"
>
<div :class="`${prefixClass}-calendar-header`">
<button
v-show="showIconDoubleArrow"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-double-left`"
@click="handleIconDoubleLeftClick"
>
<i :class="`${prefixClass}-icon-double-left`"></i>
</button>
<button
v-show="showIconArrow"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-left`"
@click="handleIconLeftClick"
>
<i :class="`${prefixClass}-icon-left`"></i>
</button>
<button
v-show="showIconDoubleArrow"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-double-right`"
@click="handleIconDoubleRightClick"
>
<i :class="`${prefixClass}-icon-double-right`"></i>
</button>
<button
v-show="showIconArrow"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-right`"
@click="handleIconRightClick"
>
<i :class="`${prefixClass}-icon-right`"></i>
</button>
<span :class="`${prefixClass}-calendar-header-label`">
<template v-if="panel === 'year'">
<span>{{ calendarDecade }}</span>
<span :class="`${prefixClass}-calendar-decade-separator`"></span>
<span>{{ calendarDecade + 9 }}</span>
</template>
<button
v-else-if="panel === 'month'"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text`"
@click="handelPanelChange('year')"
>
{{ calendarYear }}
</button>
<template v-else-if="panel === 'date'">
<button
v-for="item in dateHeader"
:key="item.panel"
type="button"
:class="
`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-current-${item.panel}`
"
@click="handelPanelChange(item.panel)"
>
{{ item.label }}
</button>
</template>
</span>
</div>
<div :class="`${prefixClass}-calendar-content`">
<table-year
v-show="panel === 'year'"
:decade="calendarDecade"
:get-cell-classes="getYearClasses"
@select="handleSelectYear"
></table-year>
<table-month
v-if="type !== 'year'"
v-show="panel === 'month'"
:get-cell-classes="getMonthClasses"
@select="handleSelectMonth"
></table-month>
<table-date
v-if="type !== 'year' && type !== 'month'"
v-show="panel === 'date'"
:calendar-year="calendarYear"
:calendar-month="calendarMonth"
:title-format="titleFormat"
:show-week-number="typeof showWeekNumber === 'boolean' ? showWeekNumber : type === 'week'"
:get-cell-classes="getDateClasses"
:get-row-classes="getWeekState"
@select="handleSelectDate"
></table-date>
</div>
</div>
</template>
<script>
import {
subMonths,
addMonths,
subYears,
addYears,
setMonth,
setYear,
startOfYear,
startOfMonth,
startOfDay,
} from 'date-fns';
import { format } from 'date-format-parse';
import { getValidDate, isValidDate, createDate } from '../util/date';
import TableDate from './table-date';
import TableMonth from './table-month';
import TableYear from './table-year';
import { getLocaleFieldValue } from '../locale';
import emitter from '../mixin/emitter';
export default {
name: 'CalendarPanel',
components: {
TableDate,
TableMonth,
TableYear,
},
mixins: [emitter],
inject: {
translateFn: {
default: () => getLocaleFieldValue,
},
prefixClass: {
default: 'mx',
},
},
props: {
value: {},
defaultValue: {
default() {
const date = new Date();
date.setHours(0, 0, 0, 0);
return date;
},
},
defaultPanel: {
type: String,
},
disabledDate: {
type: Function,
default: () => false,
},
type: {
type: String,
default: 'date',
},
getClasses: {
type: Function,
default: () => [],
},
showWeekNumber: {
type: Boolean,
default: undefined,
},
titleFormat: {
type: String,
default: 'YYYY-MM-DD',
},
calendar: Date,
// update date when select year or month
partialUpdate: {
type: Boolean,
default: false,
},
},
data() {
const panels = ['date', 'month', 'year'];
const index = Math.max(panels.indexOf(this.type), panels.indexOf(this.defaultPanel));
const panel = index !== -1 ? panels[index] : 'date';
return {
panel,
innerCalendar: null,
};
},
computed: {
innerValue() {
const value = Array.isArray(this.value) ? this.value : [this.value];
const map = {
year: startOfYear,
month: startOfMonth,
date: startOfDay,
};
const start = map[this.type] || map.date;
return value.filter(isValidDate).map(v => start(v));
},
calendarYear() {
return this.innerCalendar.getFullYear();
},
calendarMonth() {
return this.innerCalendar.getMonth();
},
calendarDecade() {
return Math.floor(this.calendarYear / 10) * 10;
},
showIconDoubleArrow() {
return this.panel === 'date' || this.panel === 'month' || this.panel === 'year';
},
showIconArrow() {
return this.panel === 'date';
},
dateHeader() {
const monthBeforeYear = this.translateFn('monthBeforeYear');
const yearFormat = this.translateFn('yearFormat');
const monthFormat = this.translateFn('monthFormat') || 'MMM';
const yearLabel = {
panel: 'year',
label: this.formatDate(this.innerCalendar, yearFormat),
};
const monthLabel = {
panel: 'month',
label: this.formatDate(this.innerCalendar, monthFormat),
};
return monthBeforeYear ? [monthLabel, yearLabel] : [yearLabel, monthLabel];
},
},
watch: {
value: {
immediate: true,
handler: 'initCalendar',
},
calendar: {
handler: 'initCalendar',
},
defaultValue: {
handler: 'initCalendar',
},
},
methods: {
formatDate(date, fmt) {
return format(date, fmt, { locale: this.translateFn('formatLocale') });
},
initCalendar() {
let calendarDate = this.calendar;
if (!isValidDate(calendarDate)) {
const { length } = this.innerValue;
calendarDate = getValidDate(length > 0 ? this.innerValue[length - 1] : this.defaultValue);
}
this.innerCalendar = calendarDate;
},
isDisabled(date) {
return this.disabledDate(new Date(date), this.innerValue);
},
emitDate(date, type) {
if (!this.isDisabled(date)) {
this.$emit('select', date, type, this.innerValue);
// someone need get the first selected date to set range value. (#429)
this.dispatch('DatePicker', 'pick', date, type);
}
},
updateCalendar(date, type) {
const oldValue = new Date(this.innerCalendar);
this.innerCalendar = date;
this.$emit('update:calendar', date);
this.dispatch('DatePicker', 'calendar-change', date, oldValue, type);
},
handelPanelChange(panel) {
this.panel = panel;
},
handleIconLeftClick() {
const nextCalendar = subMonths(this.innerCalendar, 1);
this.updateCalendar(nextCalendar, 'last-month');
},
handleIconRightClick() {
const nextCalendar = addMonths(this.innerCalendar, 1);
this.updateCalendar(nextCalendar, 'next-month');
},
handleIconDoubleLeftClick() {
const nextCalendar = subYears(this.innerCalendar, this.panel === 'year' ? 10 : 1);
this.updateCalendar(nextCalendar, this.panel === 'year' ? 'last-decade' : 'last-year');
},
handleIconDoubleRightClick() {
const nextCalendar = addYears(this.innerCalendar, this.panel === 'year' ? 10 : 1);
this.updateCalendar(nextCalendar, this.panel === 'year' ? 'next-decade' : 'next-year');
},
handleSelectYear(year) {
if (this.type === 'year') {
const date = this.getCellDate(year, 'year');
this.emitDate(date, 'year');
} else {
const nextCalendar = setYear(this.innerCalendar, year);
this.updateCalendar(nextCalendar, 'year');
this.handelPanelChange('month');
if (this.partialUpdate && this.innerValue.length === 1) {
const date = setYear(this.innerValue[0], year);
this.emitDate(date, 'year');
}
}
},
handleSelectMonth(month) {
if (this.type === 'month') {
const date = this.getCellDate(month, 'month');
this.emitDate(date, 'month');
} else {
const nextCalendar = setMonth(this.innerCalendar, month);
this.updateCalendar(nextCalendar, 'month');
this.handelPanelChange('date');
if (this.partialUpdate && this.innerValue.length === 1) {
const date = setMonth(setYear(this.innerValue[0], this.calendarYear), month);
this.emitDate(date, 'month');
}
}
},
handleSelectDate(day) {
const date = this.getCellDate(day, 'date');
this.emitDate(date, this.type === 'week' ? 'week' : 'date');
},
getCellDate(value, type) {
if (type === 'year') {
return createDate(value, 0);
}
if (type === 'month') {
return createDate(this.calendarYear, value);
}
return createDate(this.calendarYear, this.calendarMonth, value);
},
getDateClasses(day) {
const cellDate = this.getCellDate(day, 'date');
const notCurrentMonth = cellDate.getMonth() !== this.calendarMonth;
const classes = [];
if (cellDate.getTime() === new Date().setHours(0, 0, 0, 0)) {
classes.push('today');
}
if (notCurrentMonth) {
classes.push('not-current-month');
}
const state = this.getStateClass(cellDate);
if (!(state === 'active' && notCurrentMonth)) {
classes.push(state);
}
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getMonthClasses(month) {
if (this.type !== 'month') {
return this.calendarMonth === month ? 'active' : '';
}
const classes = [];
const cellDate = this.getCellDate(month, 'month');
classes.push(this.getStateClass(cellDate));
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getYearClasses(year) {
if (this.type !== 'year') {
return this.calendarYear === year ? 'active' : '';
}
const classes = [];
const cellDate = this.getCellDate(year, 'year');
classes.push(this.getStateClass(cellDate));
return classes.concat(this.getClasses(cellDate, this.innerValue, classes.join(' ')));
},
getStateClass(cellDate) {
if (this.isDisabled(cellDate)) {
return 'disabled';
}
if (this.innerValue.some(v => v.getTime() === cellDate.getTime())) {
return 'active';
}
return '';
},
getWeekState(row) {
if (this.type !== 'week') return '';
const start = this.getCellDate(row[0].day, 'date').getTime();
const end = this.getCellDate(row[6].day, 'date').getTime();
const active = this.innerValue.some(v => {
const time = v.getTime();
return time >= start && time <= end;
});
return active ? `${this.prefixClass}-active-week` : '';
},
},
};
</script>
+18 -19
View File
@@ -1,6 +1,5 @@
import { addMonths, subMonths, differenceInCalendarMonths } from 'date-fns';
import CalendarPanel from './calendar-panel';
import { getValidDate, isValidDate, isValidRangeDate } from '../util/date';
import { getValidDate, isValidDate, isValidRangeDate, startOfMonth } from '../util/date';
export default {
name: 'CalendarRange',
@@ -45,8 +44,10 @@ export default {
this.innerValue = isValidRangeDate(this.value)
? this.value
: [new Date(NaN), new Date(NaN)];
this.calendars = this.innerValue.map((v, i) => getValidDate(v, this.defaultValues[i]));
this.validateCalendars(1);
const calendars = this.innerValue.map((v, i) =>
startOfMonth(getValidDate(v, this.defaultValues[i]))
);
this.updateCalendars(calendars);
},
},
},
@@ -68,27 +69,25 @@ export default {
this.$emit('select', dates, type);
},
updateStartCalendar(value) {
this.calendars.splice(0, 1, value);
this.validateCalendars(1);
this.updateCalendars([value, this.calendars[1]], 1);
},
updateEndCalendar(value) {
this.calendars.splice(1, 1, value);
this.validateCalendars(0);
this.updateCalendars([this.calendars[0], value], 0);
},
validateCalendars(index) {
const gap = this.getCalendarGap();
updateCalendars(calendars, adjustIndex = 1) {
const gap = this.getCalendarGap(calendars);
if (gap) {
let calendar = this.calendars[index];
if (index === 0) {
calendar = subMonths(calendar, gap);
} else {
calendar = addMonths(calendar, gap);
}
this.calendars.splice(index, 1, calendar);
const calendar = new Date(calendars[adjustIndex]);
calendar.setMonth(calendar.getMonth() + (adjustIndex === 0 ? -gap : gap));
calendars[adjustIndex] = calendar;
}
this.calendars = calendars;
},
getCalendarGap() {
const diff = differenceInCalendarMonths(this.calendars[1], this.calendars[0]);
getCalendarGap(calendars) {
const [calendarLeft, calendarRight] = calendars;
const yearDiff = calendarRight.getFullYear() - calendarLeft.getFullYear();
const monthDiff = calendarRight.getMonth() - calendarLeft.getMonth();
const diff = yearDiff * 12 + monthDiff;
const min = this.calendarMinDiff;
const max = this.calendarMaxDiff;
if (diff < min) {
+22
View File
@@ -0,0 +1,22 @@
<template>
<button
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-icon-${type}`"
v-on="$listeners"
>
<i :class="`${prefixClass}-icon-${type}`"></i>
</button>
</template>
<script>
export default {
props: {
type: String,
},
inject: {
prefixClass: {
default: 'mx',
},
},
};
</script>
+112 -93
View File
@@ -1,46 +1,71 @@
<template>
<table :class="`${prefixClass}-table ${prefixClass}-table-date`">
<thead>
<tr>
<th v-if="showWeekNumber" :class="`${prefixClass}-week-number-header`"></th>
<th v-for="day in days" :key="day">{{ day }}</th>
</tr>
</thead>
<tbody @click="handleCellClick">
<tr
v-for="(row, i) in dates"
:key="i"
:class="[`${prefixClass}-date-row`, getRowClasses(row)]"
>
<td v-if="showWeekNumber" :class="`${prefixClass}-week-number`">
{{ getWeekNumber(row[0].day) }}
</td>
<td
v-for="(cell, j) in row"
:key="j"
:data-day="cell.day"
class="cell"
:class="getCellClasses(cell.day)"
:title="getCellTitle(cell.day)"
<div :class="`${prefixClass}-calendar ${prefixClass}-calendar-panel-date`">
<div :class="`${prefixClass}-calendar-header`">
<icon-button type="double-left" @click="handleIconDoubleLeftClick"></icon-button>
<icon-button type="left" @click="handleIconLeftClick"></icon-button>
<icon-button type="double-right" @click="handleIconDoubleRightClick"></icon-button>
<icon-button type="right" @click="handleIconRightClick"></icon-button>
<span :class="`${prefixClass}-calendar-header-label`">
<button
v-for="item in yearMonth"
:key="item.panel"
type="button"
:class="
`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-current-${item.panel}`
"
@click="handlePanelChange(item.panel)"
>
<div>{{ cell.text }}</div>
</td>
</tr>
</tbody>
</table>
{{ item.label }}
</button>
</span>
</div>
<div :class="`${prefixClass}-calendar-content`">
<table :class="`${prefixClass}-table ${prefixClass}-table-date`">
<thead>
<tr>
<th v-if="showWeekNumber" :class="`${prefixClass}-week-number-header`"></th>
<th v-for="day in days" :key="day">{{ day }}</th>
</tr>
</thead>
<tbody @click="handleCellClick">
<tr
v-for="(row, i) in dates"
:key="i"
:class="[`${prefixClass}-date-row`, getRowClasses(row)]"
>
<td v-if="showWeekNumber" :class="`${prefixClass}-week-number`">
{{ getWeekNumber(row[0]) }}
</td>
<td
v-for="(cell, j) in row"
:key="j"
:data-date="cell.getTime()"
class="cell"
:class="getCellClasses(cell)"
:title="getCellTitle(cell)"
>
<div>{{ cell.getDate() }}</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import { getWeek, format } from 'date-format-parse';
import IconButton from './icon-button';
import { chunk } from '../util/base';
import { createDate } from '../util/date';
import { getLocaleFieldValue } from '../locale';
import { createDate, getCalendar } from '../util/date';
import { getLocale } from '../locale';
export default {
name: 'TableDate',
components: { IconButton },
inject: {
translateFn: {
default: () => getLocaleFieldValue,
getLocale: {
default: () => getLocale,
},
getWeek: {
default: () => getWeek,
@@ -50,17 +75,9 @@ export default {
},
},
props: {
calendarYear: {
type: Number,
default() {
return new Date().getFullYear();
},
},
calendarMonth: {
type: Number,
default() {
return new Date().getMonth();
},
calendar: {
type: Date,
default: () => new Date(),
},
showWeekNumber: {
type: Boolean,
@@ -72,83 +89,85 @@ export default {
},
getRowClasses: {
type: Function,
default() {
return [];
},
default: () => [],
},
getCellClasses: {
type: Function,
default() {
return [];
},
default: () => [],
},
},
computed: {
firstDayOfWeek() {
return this.translateFn('formatLocale.firstDayOfWeek') || 0;
return this.getLocale().formatLocale.firstDayOfWeek || 0;
},
yearMonth() {
const { yearFormat, monthBeforeYear, monthFormat = 'MMM' } = this.getLocale();
const yearLabel = {
panel: 'year',
label: this.formatDate(this.calendar, yearFormat),
};
const monthLabel = {
panel: 'month',
label: this.formatDate(this.calendar, monthFormat),
};
return monthBeforeYear ? [monthLabel, yearLabel] : [yearLabel, monthLabel];
},
days() {
const days = this.translateFn('days') || this.translateFn('formatLocale.weekdaysMin');
const locale = this.getLocale();
const days = locale.days || locale.formatLocale.weekdaysMin;
return days.concat(days).slice(this.firstDayOfWeek, this.firstDayOfWeek + 7);
},
dates() {
const arr = [];
const { firstDayOfWeek } = this;
const year = this.calendarYear;
const month = this.calendarMonth;
// change to the last day of the last month
const calendar = createDate(year, month, 0);
const lastDayInLastMonth = calendar.getDate();
// getDay() 0 is Sunday, 1 is Monday
const firstDayInLastMonth =
lastDayInLastMonth - ((calendar.getDay() + 7 - firstDayOfWeek) % 7);
for (let i = firstDayInLastMonth; i <= lastDayInLastMonth; i++) {
const day = i - lastDayInLastMonth;
arr.push({ day, text: i });
}
// change to the last day of the current month
calendar.setMonth(month + 1, 0);
const lastDayInCurrentMonth = calendar.getDate();
for (let i = 1; i <= lastDayInCurrentMonth; i++) {
arr.push({ day: i, text: i });
}
const lastMonthLength = lastDayInLastMonth - firstDayInLastMonth + 1;
const nextMonthLength = 6 * 7 - lastMonthLength - lastDayInCurrentMonth;
for (let i = 1; i <= nextMonthLength; i++) {
arr.push({ day: lastDayInCurrentMonth + i, text: i });
}
const year = this.calendar.getFullYear();
const month = this.calendar.getMonth();
const arr = getCalendar({
firstDayOfWeek: this.firstDayOfWeek,
year,
month,
});
return chunk(arr, 7);
},
},
methods: {
formatDate(date, fmt) {
return format(date, fmt, { locale: this.translateFn('formatLocale') });
getNextCalendar(diffMonth) {
const year = this.calendar.getFullYear();
const month = this.calendar.getMonth();
return createDate(year, month + diffMonth);
},
handleIconLeftClick() {
this.$emit('changecalendar', this.getNextCalendar(-1), 'last-month');
},
handleIconRightClick() {
this.$emit('changecalendar', this.getNextCalendar(1), 'next-month');
},
handleIconDoubleLeftClick() {
this.$emit('changecalendar', this.getNextCalendar(-12), 'last-year');
},
handleIconDoubleRightClick() {
this.$emit('changecalendar', this.getNextCalendar(12), 'next-year');
},
handlePanelChange(panel) {
this.$emit('changepanel', panel);
},
handleCellClick(evt) {
let { target } = evt;
if (target.tagName === 'DIV') {
target = target.parentNode;
}
const day = target.getAttribute('data-day');
if (day) {
this.$emit('select', parseInt(day, 10));
const date = target.getAttribute('data-date');
if (date) {
this.$emit('select', new Date(parseInt(date, 10)));
}
},
getCellTitle(day) {
const year = this.calendarYear;
const month = this.calendarMonth;
formatDate(date, fmt) {
return format(date, fmt, { locale: this.getLocale().formatLocale });
},
getCellTitle(date) {
const fmt = this.titleFormat;
const date = createDate(year, month, day);
return this.formatDate(date, fmt);
},
getWeekNumber(day) {
const year = this.calendarYear;
const month = this.calendarMonth;
const date = createDate(year, month, day);
return this.getWeek(date, this.translateFn('formatLocale'));
getWeekNumber(date) {
return this.getWeek(date, this.getLocale().formatLocale);
},
},
};
+60 -21
View File
@@ -1,45 +1,70 @@
<template>
<table :class="`${prefixClass}-table ${prefixClass}-table-month`" @click="handleClick">
<tr v-for="(row, i) in months" :key="i">
<td
v-for="(cell, j) in row"
:key="j"
:data-month="cell.month"
class="cell"
:class="getCellClasses(cell.month)"
>
<div>{{ cell.text }}</div>
</td>
</tr>
</table>
<div :class="`${prefixClass}-calendar ${prefixClass}-calendar-panel-month`">
<div :class="`${prefixClass}-calendar-header`">
<icon-button type="double-left" @click="handleIconDoubleLeftClick"></icon-button>
<icon-button type="double-right" @click="handleIconDoubleRightClick"></icon-button>
<span :class="`${prefixClass}-calendar-header-label`">
<button
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text`"
@click="handlePanelChange"
>
{{ calendarYear }}
</button>
</span>
</div>
<div :class="`${prefixClass}-calendar-content`">
<table :class="`${prefixClass}-table ${prefixClass}-table-month`" @click="handleClick">
<tr v-for="(row, i) in months" :key="i">
<td
v-for="(cell, j) in row"
:key="j"
:data-month="cell.month"
class="cell"
:class="getCellClasses(cell.month)"
>
<div>{{ cell.text }}</div>
</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import { chunk } from '../util/base';
import { getLocaleFieldValue } from '../locale';
import IconButton from './icon-button';
import { getLocale } from '../locale';
import { createDate } from '../util/date';
export default {
name: 'TableMonth',
components: { IconButton },
inject: {
translateFn: {
default: () => getLocaleFieldValue,
getLocale: {
default: () => getLocale,
},
prefixClass: {
default: 'mx',
},
},
props: {
calendar: {
type: Date,
default: () => new Date(),
},
getCellClasses: {
type: Function,
default: () => {
return [];
},
default: () => [],
},
},
computed: {
calendarYear() {
return this.calendar.getFullYear();
},
months() {
const monthsLocale =
this.translateFn('months') || this.translateFn('formatLocale.monthsShort');
const locale = this.getLocale();
const monthsLocale = locale.months || locale.formatLocale.monthsShort;
const months = monthsLocale.map((text, month) => {
return { text, month };
});
@@ -47,6 +72,20 @@ export default {
},
},
methods: {
getNextCalendar(diffYear) {
const year = this.calendar.getFullYear();
const month = this.calendar.getMonth();
return createDate(year + diffYear, month);
},
handleIconDoubleLeftClick() {
this.$emit('changecalendar', this.getNextCalendar(-1), 'last-year');
},
handleIconDoubleRightClick() {
this.$emit('changecalendar', this.getNextCalendar(1), 'next-year');
},
handlePanelChange() {
this.$emit('changepanel', 'year');
},
handleClick(evt) {
let { target } = evt;
if (target.tagName === 'DIV') {
+53 -18
View File
@@ -1,49 +1,84 @@
<template>
<table :class="`${prefixClass}-table ${prefixClass}-table-year`" @click="handleClick">
<tr v-for="(row, i) in years" :key="i">
<td
v-for="(cell, j) in row"
:key="j"
:data-year="cell"
class="cell"
:class="getCellClasses(cell)"
>
<div>{{ cell }}</div>
</td>
</tr>
</table>
<div :class="`${prefixClass}-calendar ${prefixClass}-calendar-panel-year`">
<div :class="`${prefixClass}-calendar-header`">
<icon-button type="double-left" @click="handleIconDoubleLeftClick"></icon-button>
<icon-button type="double-right" @click="handleIconDoubleRightClick"></icon-button>
<span :class="`${prefixClass}-calendar-header-label`">
<span>{{ firstYear }}</span>
<span :class="`${prefixClass}-calendar-decade-separator`"></span>
<span>{{ lastYear }}</span>
</span>
</div>
<div :class="`${prefixClass}-calendar-content`">
<table :class="`${prefixClass}-table ${prefixClass}-table-year`" @click="handleClick">
<tr v-for="(row, i) in years" :key="i">
<td
v-for="(cell, j) in row"
:key="j"
:data-year="cell"
class="cell"
:class="getCellClasses(cell)"
>
<div>{{ cell }}</div>
</td>
</tr>
</table>
</div>
</div>
</template>
<script>
import IconButton from './icon-button';
import { chunk } from '../util/base';
import { createDate } from '../util/date';
export default {
name: 'TableYear',
components: { IconButton },
inject: {
prefixClass: {
default: 'mx',
},
},
props: {
decade: Number,
calendar: {
type: Date,
default: () => new Date(),
},
getCellClasses: {
type: Function,
default: () => {
return [];
},
default: () => [],
},
},
computed: {
years() {
const firstYear = this.decade;
const firstYear = Math.floor(this.calendar.getFullYear() / 10) * 10;
const years = [];
for (let i = 0; i < 10; i++) {
years.push(firstYear + i);
}
return chunk(years, 2);
},
firstYear() {
return this.years[0][0];
},
lastYear() {
const last = arr => arr[arr.length - 1];
return last(last(this.years));
},
},
methods: {
getNextCalendar(diffYear) {
const year = this.calendar.getFullYear();
const month = this.calendar.getMonth();
return createDate(year + diffYear, month);
},
handleIconDoubleLeftClick() {
this.$emit('changecalendar', this.getNextCalendar(-10), 'last-decade');
},
handleIconDoubleRightClick() {
this.$emit('changecalendar', this.getNextCalendar(10), 'next-decade');
},
handleClick(evt) {
let { target } = evt;
if (target.tagName === 'DIV') {
+199 -178
View File
@@ -1,126 +1,7 @@
<template>
<div
:class="{
[`${prefixClass}-datepicker`]: true,
[`${prefixClass}-datepicker-range`]: range,
[`${prefixClass}-datepicker-inline`]: inline,
disabled: disabled,
}"
>
<div v-if="!inline" :class="`${prefixClass}-input-wrapper`" @mousedown="openPopup">
<slot
name="input"
:props="{
name: 'date',
type: 'text',
autocomplete: 'off',
value: text,
class: inputClass,
readonly: !editable,
disabled,
placeholder,
...inputAttr,
}"
:events="{
keydown: handleInputKeydown,
focus: handleInputFocus,
blur: handleInputBlur,
input: handleInputInput,
change: handleInputChange,
}"
>
<input
ref="input"
v-bind="{
name: 'date',
type: 'text',
autocomplete: 'off',
value: text,
class: inputClass,
readonly: !editable,
disabled,
placeholder,
...inputAttr,
}"
v-on="{
keydown: handleInputKeydown,
focus: handleInputFocus,
blur: handleInputBlur,
input: handleInputInput,
change: handleInputChange,
}"
/>
</slot>
<i v-if="showClearIcon" :class="`${prefixClass}-icon-clear`" @mousedown.stop="handleClear">
<slot name="icon-clear">
<icon-close></icon-close>
</slot>
</i>
<i :class="`${prefixClass}-icon-calendar`">
<slot name="icon-calendar">
<icon-calendar></icon-calendar>
</slot>
</i>
</div>
<Popup
ref="popup"
:class="popupClass"
:style="popupStyle"
:inline="inline"
:visible="popupVisible"
:append-to-body="appendToBody"
@clickoutside="handleClickOutSide"
>
<div
v-if="hasSlot('sidebar') || shortcuts.length"
:class="`${prefixClass}-datepicker-sidebar`"
>
<slot name="sidebar" :value="currentValue" :emit="emitValue"></slot>
<button
v-for="(v, i) in shortcuts"
:key="i"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-shortcut`"
@click="handleSelectShortcut(v)"
>
{{ v.text }}
</button>
</div>
<div :class="`${prefixClass}-datepicker-content`">
<div v-if="hasSlot('header')" :class="`${prefixClass}-datepicker-header`">
<slot name="header" :value="currentValue" :emit="emitValue"></slot>
</div>
<div :class="`${prefixClass}-datepicker-body`">
<slot name="content" :value="currentValue" :emit="emitValue">
<component
:is="currentComponent"
ref="picker"
v-bind="currentComponentProps"
@select="handleSelectDate"
></component>
</slot>
</div>
<div v-if="hasSlot('footer') || confirm" :class="`${prefixClass}-datepicker-footer`">
<slot name="footer" :value="currentValue" :emit="emitValue"></slot>
<button
v-if="confirm"
type="button"
:class="`${prefixClass}-btn ${prefixClass}-datepicker-btn-confirm`"
@click="handleConfirmDate"
>
{{ confirmText }}
</button>
</div>
</div>
</Popup>
</div>
</template>
<script>
import { parse, format, getWeek } from 'date-format-parse';
import { isValidDate, isValidRangeDate, isValidDates } from './util/date';
import { pick, isObject, mergeDeep } from './util/base';
import { getLocale, getLocaleFieldValue } from './locale';
import { getLocale } from './locale';
import Popup from './popup';
import IconCalendar from './icon/icon-calendar';
import IconClose from './icon/icon-close';
@@ -144,16 +25,13 @@ const componentRangeMap = {
export default {
name: 'DatePicker',
components: {
IconCalendar,
IconClose,
Popup,
},
provide() {
return {
translateFn: this.getLocaleFieldValue,
// make locale reactive
getLocale: () => this.locale,
getWeek: this.getWeek,
prefixClass: this.prefixClass,
dispatchDatePicker: this.$emit.bind(this),
};
},
props: {
@@ -169,17 +47,6 @@ export default {
},
format: {
type: String,
default() {
const map = {
date: 'YYYY-MM-DD',
datetime: 'YYYY-MM-DD HH:mm:ss',
year: 'YYYY',
month: 'YYYY-MM',
time: 'HH:mm:ss',
week: 'w',
};
return map[this.type] || map.date;
},
},
formatter: {
type: Object,
@@ -194,9 +61,6 @@ export default {
},
rangeSeparator: {
type: String,
default() {
return this.multiple ? ',' : ' ~ ';
},
},
lang: {
type: [String, Object],
@@ -221,16 +85,10 @@ export default {
type: String,
default: 'mx',
},
inputClass: {
default() {
return `${this.prefixClass}-input`;
},
},
inputClass: {},
inputAttr: {
type: Object,
default() {
return {};
},
default: () => ({}),
},
appendToBody: {
type: Boolean,
@@ -243,9 +101,7 @@ export default {
popupClass: {},
popupStyle: {
type: Object,
default: () => {
return {};
},
default: () => ({}),
},
inline: {
type: Boolean,
@@ -286,20 +142,23 @@ export default {
};
},
computed: {
currentComponent() {
const map = this.range ? componentRangeMap : componentMap;
return map[this.type] || map.default;
},
currentComponentProps() {
const props = {
...pick(this, Object.keys(this.currentComponent.props)),
value: this.currentValue,
};
return props;
},
popupVisible() {
return !this.disabled && (typeof this.open === 'boolean' ? this.open : this.defaultOpen);
},
innerRangeSeparator() {
return this.rangeSeparator || (this.multiple ? ',' : ' ~ ');
},
innerFormat() {
const map = {
date: 'YYYY-MM-DD',
datetime: 'YYYY-MM-DD HH:mm:ss',
year: 'YYYY',
month: 'YYYY-MM',
time: 'HH:mm:ss',
week: 'w',
};
return this.format || map[this.type] || map.date;
},
innerValue() {
let { value } = this;
if (this.validMultipleType) {
@@ -310,7 +169,7 @@ export default {
value = Array.isArray(value) ? value.slice(0, 2) : [null, null];
return value.map(this.value2date);
}
return this.value2date(this.value);
return this.value2date(value);
},
text() {
if (this.userInput !== null) {
@@ -322,11 +181,10 @@ export default {
if (!this.isValidValue(this.innerValue)) {
return '';
}
const fmt = this.format;
if (Array.isArray(this.innerValue)) {
return this.innerValue.map(v => this.formatDate(v, fmt)).join(this.rangeSeparator);
return this.innerValue.map(v => this.formatDate(v)).join(this.innerRangeSeparator);
}
return this.formatDate(this.innerValue, fmt);
return this.formatDate(this.innerValue);
},
showClearIcon() {
return !this.disabled && this.clearable && this.text;
@@ -377,6 +235,7 @@ export default {
return getWeek(date, options);
},
parseDate(value, fmt) {
fmt = fmt || this.innerFormat;
if (typeof this.getFormatter('parse') === 'function') {
return this.getFormatter('parse')(value, fmt);
}
@@ -384,6 +243,7 @@ export default {
return parse(value, fmt, { locale: this.locale.formatLocale, backupDate });
},
formatDate(date, fmt) {
fmt = fmt || this.innerFormat;
if (typeof this.getFormatter('stringify') === 'function') {
return this.getFormatter('stringify')(date, fmt);
}
@@ -397,7 +257,7 @@ export default {
case 'timestamp':
return typeof value === 'number' ? new Date(value) : new Date(NaN);
case 'format':
return typeof value === 'string' ? this.parseDate(value, this.format) : new Date(NaN);
return typeof value === 'string' ? this.parseDate(value) : new Date(NaN);
default:
return typeof value === 'string' ? this.parseDate(value, this.valueType) : new Date(NaN);
}
@@ -411,7 +271,7 @@ export default {
case 'timestamp':
return date.getTime();
case 'format':
return this.formatDate(date, this.format);
return this.formatDate(date);
default:
return this.formatDate(date, this.valueType);
}
@@ -471,7 +331,8 @@ export default {
this.emitValue(val, this.validMultipleType ? `multiple-${type}` : type);
}
},
handleClear() {
handleClear(evt) {
evt.stopPropagation();
this.emitValue(this.range ? [null, null] : null);
this.$emit('clear');
},
@@ -479,7 +340,9 @@ export default {
const value = this.emitValue(this.currentValue);
this.$emit('confirm', value);
},
handleSelectShortcut(item) {
handleSelectShortcut(evt) {
const index = evt.currentTarget.getAttribute('data-index');
const item = this.shortcuts[parseInt(index, 10)];
if (isObject(item) && typeof item.onClick === 'function') {
const date = item.onClick(this);
if (date) {
@@ -520,17 +383,17 @@ export default {
}
let date;
if (this.validMultipleType) {
date = text.split(this.rangeSeparator).map(v => this.parseDate(v.trim(), this.format));
date = text.split(this.innerRangeSeparator).map(v => this.parseDate(v.trim()));
} else if (this.range) {
let arr = text.split(this.rangeSeparator);
let arr = text.split(this.innerRangeSeparator);
if (arr.length !== 2) {
// Maybe the separator during the day is the same as the separator for the date
// eg: 2019-10-09-2020-01-02
arr = text.split(this.rangeSeparator.trim());
arr = text.split(this.innerRangeSeparator.trim());
}
date = arr.map(v => this.parseDate(v.trim(), this.format));
date = arr.map(v => this.parseDate(v.trim()));
} else {
date = this.parseDate(text, this.format);
date = this.parseDate(text);
}
if (this.isValidValueAndNotDisabled(date)) {
this.emitValue(date);
@@ -562,9 +425,167 @@ export default {
hasSlot(name) {
return !!(this.$slots[name] || this.$scopedSlots[name]);
},
getLocaleFieldValue(path) {
return getLocaleFieldValue(path, this.locale);
renderSlot(name, fallback, props) {
const slotFn = this.$scopedSlots[name];
if (slotFn) {
return slotFn(props) || fallback;
}
return this.$slots[name] || fallback;
},
renderInput() {
const { prefixClass } = this;
const props = {
name: 'date',
type: 'text',
autocomplete: 'off',
value: this.text,
class: this.inputClass || `${this.prefixClass}-input`,
readonly: !this.editable,
disabled: this.disabled,
placeholder: this.placeholder,
...this.inputAttr,
};
const { value, ...attrs } = props;
const events = {
keydown: this.handleInputKeydown,
focus: this.handleInputFocus,
blur: this.handleInputBlur,
input: this.handleInputInput,
change: this.handleInputChange,
};
const input = this.renderSlot(
'input',
<input value={value} {...{ attrs, on: events }} ref="input" />,
{
props,
events,
}
);
return (
<div class={`${prefixClass}-input-wrapper`} onMousedown={this.openPopup}>
{input}
{this.showClearIcon ? (
<i class={`${prefixClass}-icon-clear`} onMousedown={this.handleClear}>
{this.renderSlot('icon-clear', <IconClose />)}
</i>
) : null}
<i class={`${prefixClass}-icon-calendar`}>
{this.renderSlot('icon-calendar', <IconCalendar />)}
</i>
</div>
);
},
renderContent() {
const map = this.range ? componentRangeMap : componentMap;
const Component = map[this.type] || map.default;
const props = {
...pick(this.$props, Object.keys(Component.props)),
value: this.currentValue,
};
const content = (
<Component {...{ props, on: { select: this.handleSelectDate }, ref: 'picker' }} />
);
return (
<div class={`${this.prefixClass}-datepicker-body`}>
{this.renderSlot('content', content, {
value: this.currentValue,
emit: this.handleSelectDate,
})}
</div>
);
},
renderSidebar() {
const { prefixClass } = this;
return (
<div class={`${prefixClass}-datepicker-sidebar`}>
{this.renderSlot('sidebar', null, {
value: this.currentValue,
emit: this.handleSelectDate,
})}
{this.shortcuts.map((v, i) => (
<button
key={i}
data-index={i}
type="button"
class={`${prefixClass}-btn ${prefixClass}-btn-text ${prefixClass}-btn-shortcut`}
onClick={this.handleSelectShortcut}
>
{v.text}
</button>
))}
</div>
);
},
renderHeader() {
return (
<div class={`${this.prefixClass}-datepicker-header`}>
{this.renderSlot('header', null, {
value: this.currentValue,
emit: this.handleSelectDate,
})}
</div>
);
},
renderFooter() {
const { prefixClass } = this;
return (
<div class={`${prefixClass}-datepicker-footer`}>
{this.renderSlot('footer', null, {
value: this.currentValue,
emit: this.handleSelectDate,
})}
{this.confirm ? (
<button
type="button"
class={`${prefixClass}-btn ${prefixClass}-datepicker-btn-confirm`}
onClick={this.handleConfirmDate}
>
{this.confirmText}
</button>
) : null}
</div>
);
},
},
render() {
const { prefixClass, inline, disabled } = this;
const sidedar = this.hasSlot('sidebar') || this.shortcuts.length ? this.renderSidebar() : null;
const content = (
<div class={`${prefixClass}-datepicker-content`}>
{this.hasSlot('header') ? this.renderHeader() : null}
{this.renderContent()}
{this.hasSlot('footer') || this.confirm ? this.renderFooter() : null}
</div>
);
return (
<div
class={{
[`${prefixClass}-datepicker`]: true,
[`${prefixClass}-datepicker-range`]: this.range,
[`${prefixClass}-datepicker-inline`]: inline,
disabled,
}}
>
{!inline ? this.renderInput() : null}
{!inline ? (
<Popup
ref="popup"
class={this.popupClass}
style={this.popupStyle}
visible={this.popupVisible}
appendToBody={this.appendToBody}
onClickoutside={this.handleClickOutSide}
>
{sidedar}
{content}
</Popup>
) : (
<div class={`${prefixClass}-datepicker-main`}>
{sidedar}
{content}
</div>
)}
</div>
);
},
};
</script>
+4 -4
View File
@@ -1,5 +1,5 @@
import CalendarPanel from '../calendar/calendar-panel';
import TimePanel from '../time/time-panel.vue';
import TimePanel from '../time/time-panel';
import { assignTime, getValidDate } from '../util/date';
import { pick } from '../util/base';
@@ -64,7 +64,7 @@ export default {
render() {
const calendarProps = {
props: {
...pick(this, Object.keys(CalendarPanel.props)),
...pick(this.$props, Object.keys(CalendarPanel.props)),
type: 'date',
value: this.currentValue,
},
@@ -74,13 +74,13 @@ export default {
};
const timeProps = {
props: {
...pick(this, Object.keys(TimePanel.props)),
...pick(this.$props, Object.keys(TimePanel.props)),
showTimeHeader: true,
value: this.currentValue,
},
on: {
select: this.emitDate,
'title-click': this.closeTimePanel,
clicktitle: this.closeTimePanel,
},
};
+3 -3
View File
@@ -71,7 +71,7 @@ export default {
render() {
const calendarProps = {
props: {
...pick(this, Object.keys(CalendarRange.props)),
...pick(this.$props, Object.keys(CalendarRange.props)),
type: 'date',
value: this.currentValue,
},
@@ -81,13 +81,13 @@ export default {
};
const timeProps = {
props: {
...pick(this, Object.keys(TimeRange.props)),
...pick(this.$props, Object.keys(TimeRange.props)),
value: this.currentValue,
showTimeHeader: true,
},
on: {
select: this.emitDate,
'title-click': this.closeTimePanel,
clicktitle: this.closeTimePanel,
},
};
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">
<path
d="M940.218182 107.054545h-209.454546V46.545455h-65.163636v60.50909H363.054545V46.545455H297.890909v60.50909H83.781818c-18.618182 0-32.581818 13.963636-32.581818 32.581819v805.236363c0 18.618182 13.963636 32.581818 32.581818 32.581818h861.090909c18.618182 0 32.581818-13.963636 32.581818-32.581818V139.636364c-4.654545-18.618182-18.618182-32.581818-37.236363-32.581819zM297.890909 172.218182V232.727273h65.163636V172.218182h307.2V232.727273h65.163637V172.218182h176.872727v204.8H116.363636V172.218182h181.527273zM116.363636 912.290909V442.181818h795.927273v470.109091H116.363636z"
></path>
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1em" height="1em">
<path
d="M810.005333 274.005333l-237.994667 237.994667 237.994667 237.994667-60.010667 60.010667-237.994667-237.994667-237.994667 237.994667-60.010667-60.010667 237.994667-237.994667-237.994667-237.994667 60.010667-60.010667 237.994667 237.994667 237.994667-237.994667z"
></path>
+1 -1
View File
@@ -1,5 +1,5 @@
/* istanbul ignore file */
import DatePicker from './date-picker.vue';
import DatePicker from './date-picker';
import CalendarPanel from './calendar/calendar-panel';
import CalendarRange from './calendar/calendar-range';
import TimePanel from './time/time-panel';
-23
View File
@@ -27,26 +27,3 @@ export function locale(name, object, isLocal) {
export function getLocale(name) {
return locale(name, null, true);
}
/**
* get locale field value
* @param {string} field field eg: 'formatLocale.shortMonth'
* @param {object} lang locale object
*/
export function getLocaleFieldValue(field, lang) {
const arr = (field || '').split('.');
let current = lang || getLocale();
let value;
for (let i = 0, len = arr.length; i < len; i++) {
const prop = arr[i];
value = current[prop];
if (i === len - 1) {
return value;
}
if (!value) {
return null;
}
current = value;
}
return null;
}
-19
View File
@@ -1,19 +0,0 @@
export default {
methods: {
dispatch(componentName, ...params) {
let parent = this.$parent || this.$root;
let { name } = parent.$options;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
if (parent) {
parent.$emit(...params);
}
},
},
};
+15 -30
View File
@@ -1,3 +1,16 @@
<template>
<transition :name="`${prefixClass}-zoom-in-down`">
<div
v-if="visible"
:class="`${prefixClass}-datepicker-main ${prefixClass}-datepicker-popup`"
:style="{ top, left, position: 'absolute' }"
>
<slot></slot>
</div>
</transition>
</template>
<script>
import { rafThrottle } from './util/throttle';
import { getPopupElementSize, getRelativePosition, getScrollParent } from './util/dom';
@@ -17,10 +30,6 @@ export default {
type: Boolean,
default: true,
},
inline: {
type: Boolean,
default: false,
},
},
data() {
return {
@@ -41,9 +50,6 @@ export default {
},
},
mounted() {
if (this.inline) {
return;
}
if (this.appendToBody) {
document.body.appendChild(this.$el);
}
@@ -59,9 +65,6 @@ export default {
window.addEventListener('resize', this._displayPopup);
},
beforeDestroy() {
if (this.inline) {
return;
}
if (this.appendToBody && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el);
}
@@ -81,7 +84,7 @@ export default {
}
},
displayPopup() {
if (this.inline || !this.visible) return;
if (!this.visible) return;
const popup = this.$el;
const relativeElement = this.$parent.$el;
const { appendToBody } = this;
@@ -94,23 +97,5 @@ export default {
this.top = top;
},
},
render() {
const { prefixClass } = this;
if (this.inline) {
return <div class={`${prefixClass}-datepicker-main`}>{this.$slots.default}</div>;
}
return (
<transition name={`${prefixClass}-zoom-in-down`}>
{this.visible && (
<div
class={`${prefixClass}-datepicker-main ${prefixClass}-datepicker-popup`}
style={{ top: this.top, left: this.left, position: 'absolute' }}
>
{this.$slots.default}
</div>
)}
</transition>
);
},
};
</script>
+4 -4
View File
@@ -15,7 +15,7 @@
import { format } from 'date-format-parse';
import ScrollbarVertical from '../scrollbar/scrollbar-vertical';
import { getScrollParent } from '../util/dom';
import { getLocaleFieldValue } from '../locale';
import { getLocale } from '../locale';
function parseOption(time = '') {
const values = time.split(':');
@@ -40,8 +40,8 @@ export default {
name: 'ListOptions',
components: { ScrollbarVertical },
inject: {
translateFn: {
default: () => getLocaleFieldValue,
getLocale: {
default: () => getLocale,
},
prefixClass: {
default: 'mx',
@@ -99,7 +99,7 @@ export default {
},
methods: {
formatDate(date, fmt) {
return format(date, fmt, { locale: this.translateFn('formatLocale') });
return format(date, fmt, { locale: this.getLocale().formatLocale });
},
scrollToSelected() {
const element = this.$el.querySelector('.active');
+5 -5
View File
@@ -41,14 +41,14 @@ import { format } from 'date-format-parse';
import { getValidDate } from '../util/date';
import ListColumns from './list-columns';
import ListOptions from './list-options';
import { getLocaleFieldValue } from '../locale';
import { getLocale } from '../locale';
export default {
name: 'TimePanel',
components: { ListColumns, ListOptions },
inject: {
translateFn: {
default: () => getLocaleFieldValue,
getLocale: {
default: () => getLocale,
},
prefixClass: {
default: 'mx',
@@ -149,7 +149,7 @@ export default {
},
methods: {
formatDate(date, fmt) {
return format(date, fmt, { locale: this.translateFn('formatLocale') });
return format(date, fmt, { locale: this.getLocale().formatLocale });
},
isDisabled(date) {
return this.disabledTime(new Date(date));
@@ -161,7 +161,7 @@ export default {
}
},
handleClickTitle() {
this.$emit('title-click');
this.$emit('clicktitle');
},
getClasses(value) {
const cellDate = new Date(value);
+55
View File
@@ -30,6 +30,61 @@ export function getValidDate(value, ...backup) {
return new Date();
}
export function startOfYear(value) {
const date = new Date(value);
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
return date;
}
export function startOfMonth(value) {
const date = new Date(value);
date.setDate(1);
date.setHours(0, 0, 0, 0);
return date;
}
export function startOfDay(value) {
const date = new Date(value);
date.setHours(0, 0, 0, 0);
return date;
}
export function getCalendar({ firstDayOfWeek, year, month }) {
const arr = [];
// change to the last day of the last month
const calendar = createDate(year, month, 0);
const lastDayInLastMonth = calendar.getDate();
// getDay() 0 is Sunday, 1 is Monday
const firstDayInLastMonth = lastDayInLastMonth - ((calendar.getDay() + 7 - firstDayOfWeek) % 7);
for (let i = firstDayInLastMonth; i <= lastDayInLastMonth; i++) {
arr.push(createDate(year, month, i - lastDayInLastMonth));
}
// change to the last day of the current month
calendar.setMonth(month + 1, 0);
const lastDayInCurrentMonth = calendar.getDate();
for (let i = 1; i <= lastDayInCurrentMonth; i++) {
arr.push(createDate(year, month, i));
}
const lastMonthLength = lastDayInLastMonth - firstDayInLastMonth + 1;
const nextMonthLength = 6 * 7 - lastMonthLength - lastDayInCurrentMonth;
for (let i = 1; i <= nextMonthLength; i++) {
arr.push(createDate(year, month, lastDayInCurrentMonth + i));
}
return arr;
}
export function setMonth(dirtyDate, dirtyMonth) {
const date = new Date(dirtyDate);
const month = Number(dirtyMonth);
const year = date.getFullYear();
const daysInMonth = createDate(year, month + 1, 0).getDate();
const day = date.getDate();
date.setMonth(month, Math.min(day, daysInMonth));
return date;
}
export function assignTime(target, source) {
const date = new Date(target);
const time = new Date(source);