2
0
mirror of https://github.com/frappe/books.git synced 2024-11-10 07:40:55 +00:00

feat: DatePicker

This commit is contained in:
Faris Ansari 2019-12-11 14:34:27 +05:30
parent 24a768f6ad
commit df6ace3b8d
2 changed files with 235 additions and 0 deletions

View File

@ -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>

View 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>