mirror of
https://github.com/frappe/books.git
synced 2024-11-10 07:40:55 +00:00
feat: DatePicker
This commit is contained in:
parent
24a768f6ad
commit
df6ace3b8d
@ -1,13 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="text-gray-600 text-sm mb-1" v-if="showLabel">
|
||||
{{ df.label }}
|
||||
</div>
|
||||
<DatePicker
|
||||
ref="input"
|
||||
:class="[inputClasses, 'cursor-text']"
|
||||
:value="value"
|
||||
:placeholder="inputPlaceholder"
|
||||
:readonly="isReadOnly"
|
||||
:format-value="formatValue"
|
||||
@change="value => triggerChange(value)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import frappe from 'frappejs';
|
||||
import Base from './Base';
|
||||
import DatePicker from '../DatePicker/DatePicker';
|
||||
|
||||
export default {
|
||||
name: 'Date',
|
||||
extends: Base,
|
||||
components: {
|
||||
DatePicker
|
||||
},
|
||||
computed: {
|
||||
inputType() {
|
||||
return 'date';
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatValue(value) {
|
||||
return frappe.format(value, this.df);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
208
src/components/DatePicker/DatePicker.vue
Normal file
208
src/components/DatePicker/DatePicker.vue
Normal file
@ -0,0 +1,208 @@
|
||||
<template>
|
||||
<Popover @open="selectCurrentMonthYear">
|
||||
<template v-slot:target="{ toggleDropdown }">
|
||||
<div @click="!readonly ? toggleDropdown() : null">
|
||||
<span v-if="value">
|
||||
{{ formatValue ? formatValue(value) : value }}
|
||||
</span>
|
||||
<span class="text-gray-600" v-else>
|
||||
{{ placeholder }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:content="{ toggleDropdown }">
|
||||
<div class="text-left p-3 select-none">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-medium text-blue-500 text-base">
|
||||
{{ formatMonth }}
|
||||
</span>
|
||||
<span class="flex">
|
||||
<div
|
||||
class="w-5 h-5 hover:bg-gray-100 rounded flex-center cursor-pointer"
|
||||
>
|
||||
<feather-icon
|
||||
@click="prevMonth"
|
||||
name="chevron-left"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ml-2 w-5 h-5 hover:bg-gray-100 rounded flex-center cursor-pointer"
|
||||
>
|
||||
<feather-icon
|
||||
@click="nextMonth"
|
||||
name="chevron-right"
|
||||
class="w-4 h-4"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 text-sm">
|
||||
<div class="flex w-full text-gray-600">
|
||||
<div
|
||||
class="w-6 h-6 mr-1 last:mr-0 flex items-center justify-center text-center"
|
||||
v-for="d in ['S', 'M', 'T', 'W', 'T', 'F', 'S']"
|
||||
>
|
||||
{{ d }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(week, i) in datesAsWeeks" :key="i" class="mt-1">
|
||||
<div class="flex w-full">
|
||||
<div
|
||||
v-for="date in week"
|
||||
:key="toValue(date)"
|
||||
class="w-6 h-6 mr-1 last:mr-0 flex items-center justify-center cursor-pointer rounded-md hover:bg-blue-100 hover:text-blue-500"
|
||||
:class="{
|
||||
'text-gray-600': date.getMonth() !== currentMonth - 1,
|
||||
'bg-blue-100 font-semibold text-blue-500':
|
||||
toValue(date) === value
|
||||
}"
|
||||
@click="
|
||||
selectDate(date);
|
||||
toggleDropdown();
|
||||
"
|
||||
>
|
||||
{{ date.getDate() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Popover from '../Popover';
|
||||
import Row from '../Row';
|
||||
|
||||
export default {
|
||||
name: 'DatePicker',
|
||||
props: ['value', 'placeholder', 'readonly', 'formatValue'],
|
||||
components: {
|
||||
Popover,
|
||||
Row
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentYear: null,
|
||||
currentMonth: null
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.selectCurrentMonthYear();
|
||||
},
|
||||
computed: {
|
||||
datesAsWeeks() {
|
||||
let datesAsWeeks = [];
|
||||
let dates = this.dates.slice();
|
||||
while (dates.length) {
|
||||
let week = dates.splice(0, 7);
|
||||
datesAsWeeks.push(week);
|
||||
}
|
||||
return datesAsWeeks;
|
||||
},
|
||||
dates() {
|
||||
if (!(this.currentYear && this.currentMonth)) {
|
||||
return [];
|
||||
}
|
||||
let monthIndex = this.currentMonth - 1;
|
||||
let year = this.currentYear;
|
||||
|
||||
let firstDayOfMonth = this.getDate(year, monthIndex, 1);
|
||||
let lastDayOfMonth = this.getDate(year, monthIndex + 1, 0);
|
||||
let leftPaddingCount = firstDayOfMonth.getDay();
|
||||
let rightPaddingCount = 6 - lastDayOfMonth.getDay();
|
||||
|
||||
let leftPadding = this.getDatesAfter(firstDayOfMonth, -leftPaddingCount);
|
||||
let rightPadding = this.getDatesAfter(lastDayOfMonth, rightPaddingCount);
|
||||
let daysInMonth = this.getDaysInMonth(monthIndex, year);
|
||||
let datesInMonth = this.getDatesAfter(firstDayOfMonth, daysInMonth - 1);
|
||||
|
||||
return [
|
||||
...leftPadding,
|
||||
firstDayOfMonth,
|
||||
...datesInMonth,
|
||||
...rightPadding
|
||||
];
|
||||
},
|
||||
formatMonth() {
|
||||
let date = this.getDate(this.currentYear, this.currentMonth - 1, 1);
|
||||
return date.toLocaleString('en-US', { month: 'short', year: 'numeric' });
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectDate(date) {
|
||||
this.$emit('change', this.toValue(date));
|
||||
},
|
||||
selectCurrentMonthYear() {
|
||||
let date = this.value ? this.getDate(this.value) : this.getDate();
|
||||
this.currentYear = date.getFullYear();
|
||||
this.currentMonth = date.getMonth() + 1;
|
||||
},
|
||||
prevMonth() {
|
||||
this.changeMonth(-1);
|
||||
},
|
||||
nextMonth() {
|
||||
this.changeMonth(1);
|
||||
},
|
||||
changeMonth(adder) {
|
||||
this.currentMonth = this.currentMonth + adder;
|
||||
if (this.currentMonth < 1) {
|
||||
this.currentMonth = 12;
|
||||
this.currentYear = this.currentYear - 1;
|
||||
}
|
||||
if (this.currentMonth > 12) {
|
||||
this.currentMonth = 1;
|
||||
this.currentYear = this.currentYear + 1;
|
||||
}
|
||||
},
|
||||
getDatesAfter(date, count) {
|
||||
let incrementer = 1;
|
||||
if (count < 0) {
|
||||
incrementer = -1;
|
||||
count = Math.abs(count);
|
||||
}
|
||||
let dates = [];
|
||||
while (count) {
|
||||
date = this.getDate(
|
||||
date.getFullYear(),
|
||||
date.getMonth(),
|
||||
date.getDate() + incrementer
|
||||
);
|
||||
dates.push(date);
|
||||
count--;
|
||||
}
|
||||
if (incrementer === -1) {
|
||||
return dates.reverse();
|
||||
}
|
||||
return dates;
|
||||
},
|
||||
|
||||
getDaysInMonth(monthIndex, year) {
|
||||
let daysInMonthMap = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
let daysInMonth = daysInMonthMap[monthIndex];
|
||||
if (monthIndex === 1 && this.isLeapYear(year)) {
|
||||
return 29;
|
||||
}
|
||||
return daysInMonth;
|
||||
},
|
||||
|
||||
isLeapYear(year) {
|
||||
if (year % 400 === 0) return true;
|
||||
if (year % 100 === 0) return false;
|
||||
if (year % 4 === 0) return true;
|
||||
return false;
|
||||
},
|
||||
|
||||
toValue(date) {
|
||||
return date.toISOString().slice(0, 10);
|
||||
},
|
||||
|
||||
getDate(...args) {
|
||||
let d = new Date(...args);
|
||||
return new Date(d.getTime() - d.getTimezoneOffset() * 60000);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user