|
|
@@ -1,12 +1,14 @@
|
|
|
<template>
|
|
|
- <div class="formcontrol date-input-control">
|
|
|
+ <div class="formcontrol date-input-control" :class="{ 'formcontrol--error': !isValid }">
|
|
|
<div class="formcontrol-label">{{ label }}</div>
|
|
|
<div class="input-wrapper" @click="openPicker">
|
|
|
<input
|
|
|
class="date-input"
|
|
|
+ :class="{ 'date-input--invalid': !isValid }"
|
|
|
type="text"
|
|
|
- placeholder="yyyy/mm/dd"
|
|
|
+ :placeholder="placeholder"
|
|
|
v-model="textValue"
|
|
|
+ @change="parseNewText"
|
|
|
@focus="openPicker"
|
|
|
/>
|
|
|
</div>
|
|
|
@@ -165,8 +167,9 @@ export default defineComponent({
|
|
|
},
|
|
|
},
|
|
|
data: function () {
|
|
|
- const now = dayjs().startOf("day");
|
|
|
+ const now = dayjs();
|
|
|
return {
|
|
|
+ isValid: true,
|
|
|
today: now,
|
|
|
currentMonth: now.startOf("month"),
|
|
|
zoom: "month" as "day" | "month" | "year" | "decade",
|
|
|
@@ -177,6 +180,9 @@ export default defineComponent({
|
|
|
};
|
|
|
},
|
|
|
computed: {
|
|
|
+ placeholder(): string {
|
|
|
+ return "yyyy/mm/dd" + (this.target == "hour" ? " HH:mm" : "");
|
|
|
+ },
|
|
|
currentZoomParameter(): ZoomParameter {
|
|
|
return datepickerParameter[this.zoom];
|
|
|
},
|
|
|
@@ -210,39 +216,23 @@ export default defineComponent({
|
|
|
watch: {
|
|
|
modelValue: function (val) {
|
|
|
if (["object", "string", "number"].includes(typeof val)) {
|
|
|
- this.valueObject = dayjs(val);
|
|
|
- }
|
|
|
- },
|
|
|
- textValue: function (val, oldVal) {
|
|
|
- const l = val.length;
|
|
|
- if (l > 10 || !/^[0-9/]*$/.test(val)) {
|
|
|
- this.textValue = val === "Invalid Date" ? "" : val.slice(0, 10);
|
|
|
- }
|
|
|
- if (l < oldVal.length) {
|
|
|
- this.textValue = oldVal.charAt(oldVal.length - 1) === "/" ? val.slice(0, -1) : val;
|
|
|
- } else if ([4, 7].includes(l)) {
|
|
|
- this.textValue = val + "/";
|
|
|
- }
|
|
|
- if (/^\d{4}/.test(val)) {
|
|
|
- this.currentMonth = this.currentMonth.year(parseInt(val.slice(0, 4)));
|
|
|
- }
|
|
|
- const re = /\/(0?[0-9]|(?:1[0-2]))\//.exec(val);
|
|
|
- if (re) {
|
|
|
- this.currentMonth = this.currentMonth.month(parseInt(re[1]) - 1);
|
|
|
- }
|
|
|
- if (this.textRegex.test(val)) {
|
|
|
- this.valueObject = dayjs(val, "YYYY/M/D");
|
|
|
+ const d = dayjs(val);
|
|
|
+ if (!this.valueObject?.isSame(d)) {
|
|
|
+ this.valueObject = dayjs(val);
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
- valueObject: function (v) {
|
|
|
- if (v) {
|
|
|
- this.textValue = v.format("YYYY/MM/DD");
|
|
|
- this.$emit("update:modelValue", this.textValue);
|
|
|
+ valueObject(v: Dayjs) {
|
|
|
+ if (v.isValid()) {
|
|
|
+ this.currentMonth = v;
|
|
|
if (this.target == "day") {
|
|
|
+ this.textValue = v.format("YYYY/MM/DD");
|
|
|
this.zoom = "month";
|
|
|
} else {
|
|
|
+ this.textValue = v.format("YYYY/MM/DD HH:mm");
|
|
|
this.zoom = "day";
|
|
|
}
|
|
|
+ this.$emit("update:modelValue", v);
|
|
|
} else {
|
|
|
this.textValue = "";
|
|
|
}
|
|
|
@@ -262,6 +252,26 @@ export default defineComponent({
|
|
|
isOut(d: Dayjs): boolean {
|
|
|
return this.currentZoomParameter.outOfCurrentZoom(this.currentMonth, d);
|
|
|
},
|
|
|
+ inputEventLintener(event: InputEvent) {
|
|
|
+ this.parseNewText((event.target as HTMLInputElement).value);
|
|
|
+ },
|
|
|
+ parseNewText(newValue: string) {
|
|
|
+ let candidate: Dayjs | null = null;
|
|
|
+ if (this.target == "day") {
|
|
|
+ candidate = dayjs(newValue, "YYYY/M/D");
|
|
|
+ } else {
|
|
|
+ candidate = dayjs(newValue, "YYYY/M/D HH:mm");
|
|
|
+ }
|
|
|
+ if (candidate && candidate.isValid() && !this.valueObject?.isSame(candidate)) {
|
|
|
+ this.valueObject = candidate;
|
|
|
+ this.isValid = true;
|
|
|
+ }
|
|
|
+ if (candidate && !candidate.isValid()) {
|
|
|
+ this.isValid = false;
|
|
|
+ } else {
|
|
|
+ this.isValid = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
selectItem: function (i: number): void {
|
|
|
const d = this.pickerContent[i];
|
|
|
if (
|
|
|
@@ -302,13 +312,7 @@ export default defineComponent({
|
|
|
window.removeEventListener("focusin", this.loseFocusListener);
|
|
|
window.removeEventListener("click", this.loseFocusListener);
|
|
|
this.isPickerOpen = false;
|
|
|
- const d = dayjs(this.textValue, "YYYY/MM/DD");
|
|
|
- if (d.isValid()) {
|
|
|
- this.valueObject = d;
|
|
|
- this.textValue = d.format("YYYY/MM/DD");
|
|
|
- } else {
|
|
|
- this.$emit("update:modelValue", "");
|
|
|
- }
|
|
|
+ this.parseNewText(this.textValue);
|
|
|
}
|
|
|
},
|
|
|
},
|
|
|
@@ -318,6 +322,7 @@ export default defineComponent({
|
|
|
this.valueObject = dayjs(this.modelValue);
|
|
|
}
|
|
|
}
|
|
|
+ this.zoom = "month";
|
|
|
},
|
|
|
});
|
|
|
</script>
|
|
|
@@ -379,6 +384,13 @@ export default defineComponent({
|
|
|
.date-input[type="text"]:hover + .datepicker-container {
|
|
|
display: block;
|
|
|
}
|
|
|
+.date-input--invalid {
|
|
|
+ box-shadow: 0 -1px 0 0 #e93255 inset !important;
|
|
|
+}
|
|
|
+[type="text"].date-input--invalid:focus {
|
|
|
+ box-shadow: 0 0 0 2px #e93255 !important;
|
|
|
+ border-bottom: 0;
|
|
|
+}
|
|
|
.datepicker-container {
|
|
|
position: absolute;
|
|
|
width: 315px;
|