vuetify-umalqura
Version:
a vuetify date picker for umalqura calendar
419 lines (365 loc) • 16.7 kB
JavaScript
import { VDatePickerHeader, VDatePickerMonthTable, VDatePickerDateTable, VDatePicker } from 'vuetify/lib';
import umalqura from '@umalqura/core';
import { pad, createItemTypeListeners } from 'vuetify/lib/components/VDatePicker/util';
import isDateAllowed from 'vuetify/lib/components/VDatePicker/util/isDateAllowed';
import { wrapInArray } from 'vuetify/lib/util/helpers';
function createFormatter(type, locale) {
return dateString => {
const [year, month, date] = dateString.trim().split(' ')[0].split('-');
if (type === 'day') {
return umalqura(year, month, date).format('d', locale)
}
if (type === 'year') {
return year
}
if (type === 'month') {
return umalqura(year, month, 1).format('MMMM', locale)
}
if (type === 'date') {
return umalqura(year, month, date).format(locale === 'ar' ? 'dddd, d MMM' : 'ddd, MMM d', locale)
}
if (type === 'monthYear') {
return umalqura(year, month, 1).format('MMMM yyyy', locale)
}
}
}
function daysInMonth(year, month){
return umalqura(year, month, 1).daysInMonth
}
function firstDayOfTheMonth(year, month) {
return umalqura(year, month, 1).dayOfWeek
}
function weekOfYear(year, month, date) {
return umalqura(year, month, date).weekOfYear
}
var VHijriDatePickerHeader = {
extends: VDatePickerHeader,
computed: {
formatter() {
return this.format || createFormatter(String(this.value).split('-')[1] ? 'monthYear' : 'year', this.currentLocale);
}
},
};
var VHijriDatePickerMonthTable = {
extends: VDatePickerMonthTable,
computed: {
formatter() {
return this.format || createFormatter('month', this.currentLocale);
}
},
methods: {
genTBody() {
const children = [];
const cols = Array(3).fill(null);
const rows = 12 / cols.length;
for (let row = 0; row < rows; row++) {
const tds = cols.map((_, col) => {
const month = row * cols.length + col;
const date = `${this.displayedYear}-${pad(month + 1)}`;
return this.$createElement('td', { key: month }, [this.genButton(date, false, 'month', this.formatter)]);
});
children.push(this.$createElement('tr', { key: row }, tds));
}
return this.$createElement('tbody', children);
},
genButton(value, isFloating, mouseEventType, formatter) {
const isAllowed = isDateAllowed(value, this.min, this.max, this.allowedDates);
const isSelected = this.isSelected(value) && isAllowed;
const isCurrent = value === this.current;
const setColor = isSelected ? this.setBackgroundColor : this.setTextColor;
const color = (isSelected || isCurrent) && (this.color || 'accent');
return this.$createElement('button', setColor(color, {
staticClass: 'v-btn',
class: this.genButtonClasses(isAllowed, isFloating, isSelected, isCurrent),
attrs: {
type: 'button'
},
domProps: {
disabled: this.disabled || !isAllowed
},
on: this.genButtonEvents(value, isAllowed, mouseEventType)
}), [this.$createElement('div', {
staticClass: 'v-btn__content'
}, [formatter(value)]), this.genEvents(value)]);
},
}
};
var VHijriDatePickerDateTable = {
extends: VDatePickerDateTable,
computed: {
formatter() {
return this.format || createFormatter('day', this.currentLocale);
},
},
methods: {
weekDaysBeforeFirstDayOfTheMonth() {
const weekDay = firstDayOfTheMonth(this.displayedYear, this.displayedMonth);
return (weekDay - parseInt(this.firstDayOfWeek) + 7) % 7;
},
getWeekNumber(dayInMonth) {
return weekOfYear(this.displayedYear, this.displayedMonth, dayInMonth)
},
genTBody() {
const children = [];
const daysInCurrentMonth = daysInMonth(this.displayedYear, this.displayedMonth);
let rows = [];
let day = this.weekDaysBeforeFirstDayOfTheMonth();
if (this.showWeek) {
rows.push(this.genWeekNumber(this.getWeekNumber(1)));
}
const prevMonthYear = this.displayedMonth === 1 ? this.displayedYear - 1 : this.displayedYear;
const prevMonth = this.displayedMonth === 1 ? 12 : this.displayedMonth - 1;
const firstDayFromPreviousMonth = daysInMonth(prevMonthYear, prevMonth);
const cellsInRow = this.showWeek ? 8 : 7;
while (day--) {
const date = `${prevMonthYear}-${pad(prevMonth)}-${pad(firstDayFromPreviousMonth - day)}`;
rows.push(this.$createElement('td', this.showAdjacentMonths ? [this.genButton(date, true, 'date', this.formatter, true)] : []));
}
for (day = 1; day <= daysInCurrentMonth; day++) {
const date = `${this.displayedYear}-${pad(this.displayedMonth)}-${pad(day)}`;
rows.push(this.$createElement('td', [this.genButton(date, true, 'date', this.formatter)]));
if (rows.length % cellsInRow === 0) {
children.push(this.genTR(rows));
rows = [];
if (this.showWeek && (day < daysInCurrentMonth || this.showAdjacentMonths)) {
rows.push(this.genWeekNumber(this.getWeekNumber((day + 7) > daysInCurrentMonth ? daysInCurrentMonth : (day + 7))));
}
}
}
const nextMonthYear = this.displayedMonth === 12 ? this.displayedYear + 1 : this.displayedYear;
const nextMonth = this.displayedMonth === 12 ? 1 : this.displayedMonth + 1;
let nextMonthDay = 1;
while (rows.length < cellsInRow) {
const date = `${nextMonthYear}-${pad(nextMonth)}-${pad(nextMonthDay++)}`;
rows.push(this.$createElement('td', this.showAdjacentMonths ? [this.genButton(date, true, 'date', this.formatter, true)] : []));
}
if (rows.length) {
children.push(this.genTR(rows));
}
return this.$createElement('tbody', children);
},
}
};
function sanitizeDateString(dateString, type) {
const [year, month = 1, date = 1] = dateString.split("-");
return `${year}-${pad(month)}-${pad(date)}`.substr(
0,
{
date: 10,
month: 7,
year: 4
}[type]
);
}
var VHijriDatePicker = {
extends: VDatePicker,
name: "VHijriDatePicker",
props: {
max: {
type: String,
validator: dateString => {
return Number(sanitizeDateString(dateString, 'year')) <= umalqura.max.hy
}
},
min: {
type: String,
validator: dateString => {
return Number(sanitizeDateString(dateString, 'year')) >= umalqura.min.hy
}
},
},
data() {
const now = umalqura();
return {
internalActivePicker: this.type.toUpperCase(),
inputDay: null,
inputMonth: null,
inputYear: null,
isReversing: false,
now,
tableDate: (() => {
if (this.pickerDate) {
return this.pickerDate;
}
const multipleValue = wrapInArray(this.value);
const date = multipleValue[multipleValue.length - 1] || (typeof this.showCurrent === 'string' ? this.showCurrent : `${now.hy}-${now.hm}`);
return sanitizeDateString(date, this.type === 'date' ? 'month' : 'year');
})(),
};
},
computed: {
current() {
if (this.showCurrent === true) {
return sanitizeDateString(`${this.now.hy}-${this.now.hm}-${this.now.hd}`, this.type);
}
return this.showCurrent || null;
},
inputDate() {
return this.type === 'date' ? `${this.inputYear}-${pad(this.inputMonth)}-${pad(this.inputDay)}` : `${this.inputYear}-${pad(this.inputMonth)}`;
},
tableMonth() {
return Number((this.pickerDate || this.tableDate).split('-')[1]);
},
minMonth() {
return this.min ? sanitizeDateString(this.min, 'month') : umalqura.min.format('yyyy-MM');
},
maxMonth() {
return this.max ? sanitizeDateString(this.max, 'month') : umalqura.max.subtract(1,'year').format('yyyy-MM');
},
minYear() {
return this.min ? sanitizeDateString(this.min, 'year') : umalqura.min.format('yyyy');
},
maxYear() {
return this.max ? sanitizeDateString(this.max, 'year') : umalqura.max.subtract(1,'year').format('yyyy')
},
formatters() {
return {
year: createFormatter('year', this.currentLocale),
titleDate: this.titleDateFormat || (this.isMultiple ? this.defaultTitleMultipleDateFormatter : this.defaultTitleDateFormatter)
};
},
defaultTitleDateFormatter() {
const titleDateFormatter = createFormatter(this.type, this.currentLocale);
const landscapeFormatter = date => titleDateFormatter(date).replace(/([^\d\s])([\d])/g, (match, nonDigit, digit) => `${nonDigit} ${digit}`).replace(', ', ',<br>');
return this.landscape ? landscapeFormatter : titleDateFormatter;
}
},
methods: {
yearClick(value) {
this.inputYear = value;
if (this.type === 'month') {
this.tableDate = `${value}`;
} else {
this.tableDate = `${value}-${pad(this.tableMonth || 1)}`;
}
this.internalActivePicker = 'MONTH';
if (this.reactive && !this.readonly && !this.isMultiple && this.isDateAllowed(this.inputDate)) {
this.$emit('input', this.inputDate);
}
},
monthClick(value) {
this.inputYear = parseInt(value.split('-')[0], 10);
this.inputMonth = parseInt(value.split('-')[1], 10);
if (this.type === 'date') {
if (this.inputDay) {
this.inputDay = Math.min(this.inputDay, daysInMonth(this.inputYear, this.inputMonth));
}
this.tableDate = value;
this.internalActivePicker = 'DATE';
if (this.reactive && !this.readonly && !this.isMultiple && this.isDateAllowed(this.inputDate)) {
this.$emit('input', this.inputDate);
}
} else {
this.emitInput(this.inputDate);
}
},
dateClick(value) {
this.inputYear = parseInt(value.split('-')[0], 10);
this.inputMonth = parseInt(value.split('-')[1], 10);
this.inputDay = parseInt(value.split('-')[2], 10);
this.emitInput(this.inputDate);
},
genTableHeader() {
return this.$createElement(VHijriDatePickerHeader, {
props: {
nextIcon: this.nextIcon,
color: this.color,
dark: this.dark,
disabled: this.disabled,
format: this.headerDateFormat,
light: this.light,
locale: this.locale,
min: this.internalActivePicker === 'DATE' ? this.minMonth : this.minYear,
max: this.internalActivePicker === 'DATE' ? this.maxMonth : this.maxYear,
nextAriaLabel: this.internalActivePicker === 'DATE' ? this.nextMonthAriaLabel : this.nextYearAriaLabel,
prevAriaLabel: this.internalActivePicker === 'DATE' ? this.prevMonthAriaLabel : this.prevYearAriaLabel,
prevIcon: this.prevIcon,
readonly: this.readonly,
value: this.internalActivePicker === 'DATE' ? `${pad(this.tableYear, 4)}-${pad(this.tableMonth)}` : `${pad(this.tableYear, 4)}`
},
on: {
toggle: () => this.internalActivePicker = this.internalActivePicker === 'DATE' ? 'MONTH' : 'YEAR',
input: value => this.tableDate = value
}
});
},
genDateTable() {
return this.$createElement(VHijriDatePickerDateTable, {
props: {
allowedDates: this.allowedDates,
color: this.color,
current: this.current,
dark: this.dark,
disabled: this.disabled,
events: this.events,
eventColor: this.eventColor,
firstDayOfWeek: this.firstDayOfWeek,
format: this.dayFormat,
light: this.light,
locale: this.locale,
localeFirstDayOfYear: this.localeFirstDayOfYear,
min: this.min,
max: this.max,
range: this.range,
readonly: this.readonly,
scrollable: this.scrollable,
showAdjacentMonths: this.showAdjacentMonths,
showWeek: this.showWeek,
tableDate: `${pad(this.tableYear, 4)}-${pad(this.tableMonth + 1)}`,
value: this.value,
weekdayFormat: this.weekdayFormat
},
ref: 'table',
on: {
input: this.dateClick,
'update:table-date': value => this.tableDate = value,
...createItemTypeListeners(this, ':date')
}
});
},
genMonthTable() {
return this.$createElement(VHijriDatePickerMonthTable, {
props: {
allowedDates: this.type === 'month' ? this.allowedDates : null,
color: this.color,
current: this.current ? sanitizeDateString(this.current, 'month') : null,
dark: this.dark,
disabled: this.disabled,
events: this.type === 'month' ? this.events : null,
eventColor: this.type === 'month' ? this.eventColor : null,
format: this.monthFormat,
light: this.light,
locale: this.locale,
min: this.minMonth,
max: this.maxMonth,
range: this.range,
readonly: this.readonly && this.type === 'month',
scrollable: this.scrollable,
value: this.selectedMonths,
tableDate: `${pad(this.tableYear, 4)}`
},
ref: 'table',
on: {
input: this.monthClick,
'update:table-date': value => this.tableDate = value,
...createItemTypeListeners(this, ':month')
}
});
},
setInputDate() {
if (this.lastValue) {
const array = this.lastValue.split('-');
this.inputYear = parseInt(array[0], 10);
this.inputMonth = parseInt(array[1], 10);
if (this.type === 'date') {
this.inputDay = parseInt(array[2], 10);
}
} else {
this.inputYear = this.inputYear || this.now.hy;
this.inputMonth = this.inputMonth == null ? this.inputMonth : this.now.hm;
this.inputDay = this.inputDay || this.now.hd;
}
},
}
};
export default VHijriDatePicker;