Initiated Calendar component
parent
bf9c810f71
commit
4ead1093a4
|
@ -2,7 +2,8 @@
|
||||||
<span :class="containerClass">
|
<span :class="containerClass">
|
||||||
<CalendarInputText v-if="!inline" type="text" v-bind="$attrs" v-on="listeners" :value="inputFieldValue" />
|
<CalendarInputText v-if="!inline" type="text" v-bind="$attrs" v-on="listeners" :value="inputFieldValue" />
|
||||||
<CalendarButton v-if="showIcon" :icon="icon" tabindex="-1" class="p-datepicker-trigger p-calendar-button" :disabled="$attrs.disabled" />
|
<CalendarButton v-if="showIcon" :icon="icon" tabindex="-1" class="p-datepicker-trigger p-calendar-button" :disabled="$attrs.disabled" />
|
||||||
<div :class="panelStyleClass">
|
<transition name="p-input-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave">
|
||||||
|
<div ref="overlay" :class="panelStyleClass" v-if="inline ? true : overlayVisible">
|
||||||
<div class="p-datepicker-group" v-for="(month,i) of months" :key="month.month + month.year">
|
<div class="p-datepicker-group" v-for="(month,i) of months" :key="month.month + month.year">
|
||||||
<div class="p-datepicker-header">
|
<div class="p-datepicker-header">
|
||||||
<button class="p-datepicker-prev p-link" v-if="i === 0">
|
<button class="p-datepicker-prev p-link" v-if="i === 0">
|
||||||
|
@ -16,11 +17,11 @@
|
||||||
<span class="p-datepicker-year" v-if="!yearNavigator">{{view === 'month' ? currentYear : month.year}}</span>
|
<span class="p-datepicker-year" v-if="!yearNavigator">{{view === 'month' ? currentYear : month.year}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-datepicker-calendar-container" *ngIf="view ==='date'">
|
<div class="p-datepicker-calendar-container" v-if="view ==='date'">
|
||||||
<table class="p-datepicker-calendar">
|
<table class="p-datepicker-calendar">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col" *ngFor="let weekDay of weekDays;let begin = first; let end = last">
|
<th scope="col" v-for="weekDay of weekDays" :key="weekDay">
|
||||||
<span>{{weekDay}}</span>
|
<span>{{weekDay}}</span>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="week of month.dates" :key="week[0].day + week[0].month">
|
<tr v-for="week of month.dates" :key="week[0].day + week[0].month">
|
||||||
<td v-for="date of week" :key="date.day" :class="{'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today}">
|
<td v-for="date of week" :key="date.day" :class="{'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today}">
|
||||||
|
<span :class="{'p-highlight': isSelected(date), 'p-disabled': !date.selectable}">{{date.day}}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -36,17 +37,23 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</transition>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import InputText from '../inputtext/InputText';
|
import InputText from '../inputtext/InputText';
|
||||||
import Button from '../button/Button';
|
import Button from '../button/Button';
|
||||||
|
import DomHandler from '../utils/DomHandler';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
value: null,
|
value: null,
|
||||||
|
defaultDate: {
|
||||||
|
type: Date,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
timeOnly: {
|
timeOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
@ -85,9 +92,26 @@ export default {
|
||||||
},
|
},
|
||||||
panelClass: String,
|
panelClass: String,
|
||||||
panelStyle: null,
|
panelStyle: null,
|
||||||
|
minDate: {
|
||||||
|
type: Date,
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
maxDate: {
|
||||||
|
type: Date,
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
disabledDates: {
|
||||||
|
type: Array,
|
||||||
|
value: null
|
||||||
|
},
|
||||||
|
disabledDays: {
|
||||||
|
type: Array,
|
||||||
|
value: null
|
||||||
|
},
|
||||||
locale: {
|
locale: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: {
|
default: () => {
|
||||||
|
return {
|
||||||
firstDayOfWeek: 0,
|
firstDayOfWeek: 0,
|
||||||
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
||||||
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||||
|
@ -100,12 +124,234 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
appendTo: null,
|
||||||
|
showOnFocus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
autoZIndex: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
baseZIndex: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
let viewDate = null;
|
||||||
|
if (this.defaultDate) {
|
||||||
|
viewDate = this.defaultDate;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let propValue = this.value;
|
||||||
|
if (Array.isArray(propValue)) {
|
||||||
|
propValue = propValue[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
viewDate = propValue || new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentMonth = viewDate.getMonth();
|
||||||
|
this.currentYear = viewDate.getFullYear();
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentMonth: null,
|
||||||
|
currentYear: null,
|
||||||
|
overlayVisible: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
outsideClickListener: null,
|
||||||
|
methods: {
|
||||||
|
isSelected(dateMeta) {
|
||||||
|
if(this.value) {
|
||||||
|
if(this.isSingleSelection()) {
|
||||||
|
return this.isDateEquals(this.props.value, dateMeta);
|
||||||
|
}
|
||||||
|
else if(this.isMultipleSelection()) {
|
||||||
|
let selected = false;
|
||||||
|
for(let date of this.props.value) {
|
||||||
|
selected = this.isDateEquals(date, dateMeta);
|
||||||
|
if(selected) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected;
|
||||||
|
}
|
||||||
|
else if(this.isRangeSelection()) {
|
||||||
|
if(this.props.value[1])
|
||||||
|
return this.isDateEquals(this.props.value[0], dateMeta) || this.isDateEquals(this.props.value[1], dateMeta) || this.isDateBetween(this.props.value[0], this.props.value[1], dateMeta);
|
||||||
|
else {
|
||||||
|
return this.isDateEquals(this.props.value[0], dateMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getFirstDayOfMonthIndex(month, year) {
|
||||||
|
let day = new Date();
|
||||||
|
day.setDate(1);
|
||||||
|
day.setMonth(month);
|
||||||
|
day.setFullYear(year);
|
||||||
|
|
||||||
|
let dayIndex = day.getDay() + this.sundayIndex;
|
||||||
|
return dayIndex >= 7 ? dayIndex - 7 : dayIndex;
|
||||||
|
},
|
||||||
|
getDaysCountInMonth(month, year) {
|
||||||
|
return 32 - this.daylightSavingAdjust(new Date(year, month, 32)).getDate();
|
||||||
|
},
|
||||||
|
getDaysCountInPrevMonth(month, year) {
|
||||||
|
let prev = this.getPreviousMonthAndYear(month, year);
|
||||||
|
return this.getDaysCountInMonth(prev.month, prev.year);
|
||||||
|
},
|
||||||
|
getPreviousMonthAndYear(month, year) {
|
||||||
|
let m, y;
|
||||||
|
|
||||||
|
if (month === 0) {
|
||||||
|
m = 11;
|
||||||
|
y = year - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m = month - 1;
|
||||||
|
y = year;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {'month':m, 'year': y};
|
||||||
|
},
|
||||||
|
getNextMonthAndYear(month, year) {
|
||||||
|
let m, y;
|
||||||
|
|
||||||
|
if (month === 11) {
|
||||||
|
m = 0;
|
||||||
|
y = year + 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m = month + 1;
|
||||||
|
y = year;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {'month':m,'year':y};
|
||||||
|
},
|
||||||
|
daylightSavingAdjust(date) {
|
||||||
|
if (!date) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
|
||||||
|
|
||||||
|
return date;
|
||||||
|
},
|
||||||
|
isToday(today, day, month, year) {
|
||||||
|
return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
|
||||||
|
},
|
||||||
|
isSelectable(day, month, year, otherMonth) {
|
||||||
|
let validMin = true;
|
||||||
|
let validMax = true;
|
||||||
|
let validDate = true;
|
||||||
|
let validDay = true;
|
||||||
|
|
||||||
|
if (otherMonth && !this.selectOtherMonths) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.minDate) {
|
||||||
|
if (this.minDate.getFullYear() > year) {
|
||||||
|
validMin = false;
|
||||||
|
}
|
||||||
|
else if (this.minDate.getFullYear() === year) {
|
||||||
|
if (this.minDate.getMonth() > month) {
|
||||||
|
validMin = false;
|
||||||
|
}
|
||||||
|
else if (this.minDate.getMonth() === month) {
|
||||||
|
if (this.minDate.getDate() > day) {
|
||||||
|
validMin = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.maxDate) {
|
||||||
|
if (this.maxDate.getFullYear() < year) {
|
||||||
|
validMax = false;
|
||||||
|
}
|
||||||
|
else if (this.maxDate.getFullYear() === year) {
|
||||||
|
if (this.maxDate.getMonth() < month) {
|
||||||
|
validMax = false;
|
||||||
|
}
|
||||||
|
else if (this.maxDate.getMonth() === month) {
|
||||||
|
if (this.maxDate.getDate() < day) {
|
||||||
|
validMax = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.disabledDates) {
|
||||||
|
validDate = !this.isDateDisabled(day,month,year);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.disabledDays) {
|
||||||
|
validDay = !this.isDayDisabled(day,month,year)
|
||||||
|
}
|
||||||
|
|
||||||
|
return validMin && validMax && validDate && validDay;
|
||||||
|
},
|
||||||
|
onOverlayEnter() {
|
||||||
|
if (this.autoZIndex) {
|
||||||
|
this.$refs.overlay.style.zIndex = String(this.baseZIndex + DomHandler.generateZIndex());
|
||||||
|
}
|
||||||
|
this.alignOverlay();
|
||||||
|
this.bindOutsideClickListener();
|
||||||
|
},
|
||||||
|
onOverlayLeave() {
|
||||||
|
this.unbindOutsideClickListener();
|
||||||
|
},
|
||||||
|
bindOutsideClickListener() {
|
||||||
|
if (!this.outsideClickListener) {
|
||||||
|
this.outsideClickListener = (event) => {
|
||||||
|
if (this.overlayVisible && this.$refs.overlay && !this.$el.contains(event.target)) {
|
||||||
|
this.overlayVisible = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.addEventListener('click', this.outsideClickListener);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unbindOutsideClickListener() {
|
||||||
|
if (this.outsideClickListener) {
|
||||||
|
document.removeEventListener('click', this.outsideClickListener);
|
||||||
|
this.outsideClickListener = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
alignOverlay() {
|
||||||
|
if (this.$refs.overlay) {
|
||||||
|
if (this.appendTo)
|
||||||
|
DomHandler.absolutePosition(this.$refs.overlay, this.$el);
|
||||||
|
else
|
||||||
|
DomHandler.relativePosition(this.$refs.overlay, this.$el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
listeners() {
|
listeners() {
|
||||||
return {
|
return {
|
||||||
...this.$listeners,
|
...this.$listeners,
|
||||||
input: event => {
|
input: event => {
|
||||||
this.$emit('input', event)
|
this.$emit('input', event)
|
||||||
|
},
|
||||||
|
focus: event => {
|
||||||
|
this.focus = true;
|
||||||
|
if (this.showOnFocus) {
|
||||||
|
this.overlayVisible = true;
|
||||||
|
}
|
||||||
|
this.$emit('focus', event)
|
||||||
|
},
|
||||||
|
blur: event => {
|
||||||
|
this.$emit('blur', event);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -124,7 +370,6 @@ export default {
|
||||||
'p-datepicker p-component',
|
'p-datepicker p-component',
|
||||||
{
|
{
|
||||||
'p-datepicker-inline': this.inline,
|
'p-datepicker-inline': this.inline,
|
||||||
'p-input-overlay': !this.inline,
|
|
||||||
'p-shadow': !this.inline,
|
'p-shadow': !this.inline,
|
||||||
'p-disabled': this.$attrs.disabled,
|
'p-disabled': this.$attrs.disabled,
|
||||||
'p-datepicker-timeonly': this.timeOnly,
|
'p-datepicker-timeonly': this.timeOnly,
|
||||||
|
@ -136,6 +381,85 @@ export default {
|
||||||
},
|
},
|
||||||
inputFieldValue() {
|
inputFieldValue() {
|
||||||
return '';
|
return '';
|
||||||
|
},
|
||||||
|
months() {
|
||||||
|
let months = [];
|
||||||
|
for (let i = 0 ; i < this.numberOfMonths; i++) {
|
||||||
|
let month = this.currentMonth + i;
|
||||||
|
let year = this.currentYear;
|
||||||
|
if (month > 11) {
|
||||||
|
month = month % 11 - 1;
|
||||||
|
year = year + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dates = [];
|
||||||
|
let firstDay = this.getFirstDayOfMonthIndex(month, year);
|
||||||
|
let daysLength = this.getDaysCountInMonth(month, year);
|
||||||
|
let prevMonthDaysLength = this.getDaysCountInPrevMonth(month, year);
|
||||||
|
let dayNo = 1;
|
||||||
|
let today = new Date();
|
||||||
|
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
let week = [];
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
for (let j = (prevMonthDaysLength - firstDay + 1); j <= prevMonthDaysLength; j++) {
|
||||||
|
let prev = this.getPreviousMonthAndYear(month, year);
|
||||||
|
week.push({day: j, month: prev.month, year: prev.year, otherMonth: true,
|
||||||
|
today: this.isToday(today, j, prev.month, prev.year), selectable: this.isSelectable(j, prev.month, prev.year, true)});
|
||||||
|
}
|
||||||
|
|
||||||
|
let remainingDaysLength = 7 - week.length;
|
||||||
|
for (let j = 0; j < remainingDaysLength; j++) {
|
||||||
|
week.push({day: dayNo, month: month, year: year, today: this.isToday(today, dayNo, month, year),
|
||||||
|
selectable: this.isSelectable(dayNo, month, year, false)});
|
||||||
|
dayNo++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let j = 0; j < 7; j++) {
|
||||||
|
if (dayNo > daysLength) {
|
||||||
|
let next = this.getNextMonthAndYear(month, year);
|
||||||
|
week.push({day: dayNo - daysLength, month: next.month, year: next.year, otherMonth: true,
|
||||||
|
today: this.isToday(today, dayNo - daysLength, next.month, next.year),
|
||||||
|
selectable: this.isSelectable((dayNo - daysLength), next.month, next.year, true)});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
week.push({day: dayNo, month: month, year: year, today: this.isToday(today, dayNo, month, year),
|
||||||
|
selectable: this.isSelectable(dayNo, month, year, false)});
|
||||||
|
}
|
||||||
|
|
||||||
|
dayNo++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dates.push(week);
|
||||||
|
}
|
||||||
|
|
||||||
|
months.push({
|
||||||
|
month: month,
|
||||||
|
year: year,
|
||||||
|
dates: dates
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return months;
|
||||||
|
},
|
||||||
|
weekDays() {
|
||||||
|
let weekDays = [];
|
||||||
|
let dayIndex = this.locale.firstDayOfWeek;
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
weekDays.push(this.locale.dayNamesMin[dayIndex]);
|
||||||
|
dayIndex = (dayIndex == 6) ? 0 : ++dayIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return weekDays;
|
||||||
|
},
|
||||||
|
ticksTo1970() {
|
||||||
|
return (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000);
|
||||||
|
},
|
||||||
|
sundayIndex() {
|
||||||
|
return this.locale.firstDayOfWeek > 0 ? 7 - this.locale.firstDayOfWeek : 0;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -190,7 +514,6 @@ export default {
|
||||||
.p-datepicker {
|
.p-datepicker {
|
||||||
width: auto;
|
width: auto;
|
||||||
padding: .2em;
|
padding: .2em;
|
||||||
display: none;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue