@febe95/vue-functional-calendar
Version:
Lightweight, high-performance calendar component based on Vue.js
1 lines • 167 kB
Source Map (JSON)
{"version":3,"file":"FunctionalCalendar.umd.cjs","sources":["../src/assets/js/helpCalendar.js","../src/mixins/propsAndData.js","../src/components/TimePicker.vue","../src/components/CalendarArrows.vue","../src/components/WeekNumbers.vue","../src/components/CalendarDay.vue","../src/components/MonthYearPicker.vue","../src/components/PickerInputs.vue","../src/components/CalendarFooter.vue","../src/utils/helpers.js","../src/components/FunctionalCalendar.vue","../index.js"],"sourcesContent":["Date.prototype.getWeekNumber = function(sundayStart) {\n if (!sundayStart) {\n // ISO week date weeks start on monday\n // so correct the day number\n let dayNumber = (this.getDay() + 6) % 7\n // Set the target to the thursday of this week so the\n // target date is in the right year\n this.setDate(this.getDate() - dayNumber + 3)\n }\n\n let january4 = new Date(this.getFullYear(), 0, 4)\n return Math.ceil(((this - january4) / 86400000 + january4.getDay() + 1) / 7)\n}\n\nexport default class helpCalendar {\n constructor(sundayStart, leftAndRightDays, dateFormat, dayNames) {\n this.sundayStart = sundayStart\n this.leftAndRightDays = leftAndRightDays\n this.dateFormat = dateFormat\n this.dayNames = dayNames\n }\n\n formatDate(date) {\n let day = date.getDate()\n let month = date.getMonth() + 1\n let year = date.getFullYear()\n\n let formattedDate = this.dateFormat.replace('dd', day.toString())\n formattedDate = formattedDate.replace('mm', month.toString())\n formattedDate = formattedDate.replace('yyyy', year.toString())\n return formattedDate.split(' ')[0]\n }\n\n getDateFromFormat(date) {\n let format = this.dateFormat.split(' ')[0]\n date = date.split(' ')[0]\n if (format.indexOf('/') !== -1) {\n format = format.split('/')\n date = date.split('/')\n } else if (format.indexOf('-') !== -1) {\n format = format.split('-')\n date = date.split('-')\n } else if (format.indexOf('.') !== -1) {\n format = format.split('.')\n date = date.split('.')\n } else {\n throw new Error('Your date format not valid. Please read documentation.!')\n }\n\n let year = format.indexOf('yyyy')\n let month = format.indexOf('mm')\n let day = format.indexOf('dd')\n return new Date(date[year], date[month] - 1, date[day])\n }\n\n checkValidDate(val) {\n val = this.getDateFromFormat(val)\n\n if (val != 'Invalid Date') {\n return true\n }\n\n return false\n }\n\n getWeeksInMonth(month, year) {\n let weeks = [],\n firstDate = new Date(year, month, 1),\n lastDate = new Date(year, month + 1, 0),\n numDays = lastDate.getDate()\n\n let start = 1\n\n let end = !this.sundayStart\n ? firstDate.getDay() === 0\n ? 1\n : 7 - firstDate.getDay() + 1\n : 7 - firstDate.getDay()\n\n while (start <= numDays) {\n weeks.push({\n year,\n start,\n end,\n number: new Date(year, month, start).getWeekNumber(this.sundayStart),\n days: []\n })\n start = end + 1\n end = end + 7\n if (end > numDays) end = numDays\n }\n return {\n weeks,\n month: lastDate.getMonth(),\n year: lastDate.getFullYear()\n }\n }\n\n getLeftMonthDays(month, year) {\n let weeks = this.getWeeksInMonth(month, year)\n let firstWeek = weeks.weeks[0]\n let weekDaysCount = firstWeek.end - firstWeek.start + 1\n\n let days = []\n let finalYear = 0\n let finalMonth = 0\n\n if (weekDaysCount !== 7) {\n let weeksLeftMonth = this.getWeeksInMonth(month - 1, year)\n\n let leftMonthLastWeek =\n weeksLeftMonth.weeks[weeksLeftMonth.weeks.length - 1]\n\n for (let i = leftMonthLastWeek.start; i <= leftMonthLastWeek.end; i++) {\n days.push(i)\n }\n\n finalMonth = weeksLeftMonth.month\n finalYear = weeksLeftMonth.year\n }\n\n return { days: days.reverse(), month: finalMonth, year: finalYear }\n }\n\n getRightMonthDays(month, year) {\n let weeks = this.getWeeksInMonth(month, year)\n let lastWeek = weeks.weeks[weeks.weeks.length - 1]\n\n let weekDaysCount = lastWeek.end - lastWeek.start + 1\n\n let days = []\n let finalYear = 0\n let finalMonth = 0\n\n if (weekDaysCount !== 7) {\n let weeksRightMonth = this.getWeeksInMonth(month + 1, year)\n let rightMonthFirstWeek = weeksRightMonth.weeks[0]\n\n for (\n let i = rightMonthFirstWeek.start;\n i <= rightMonthFirstWeek.end;\n i++\n ) {\n days.push(i)\n }\n\n finalMonth = weeksRightMonth.month\n finalYear = weeksRightMonth.year\n }\n\n return { days, month: finalMonth, year: finalYear }\n }\n\n getFinalizedWeeks(month, year) {\n let monthWeeks = this.getWeeksInMonth(month, year)\n let leftMonthDays = this.getLeftMonthDays(month, year)\n let rightMonthDays = this.getRightMonthDays(month, year)\n\n // Push Current Month Week days\n monthWeeks.weeks.forEach(week => {\n for (let i = week.start; i <= week.end; i++) {\n week.days.push({\n day: i,\n month: monthWeeks.month,\n year: monthWeeks.year,\n hide: false,\n hideLeftAndRightDays: false\n })\n }\n })\n\n // Left month days\n if (leftMonthDays.days.length) {\n leftMonthDays.days.forEach(day => {\n let hideLeftAndRightDays = false\n\n if (!this.leftAndRightDays) {\n day = ''\n hideLeftAndRightDays = true\n }\n\n monthWeeks.weeks[0].days.unshift({\n day,\n month: leftMonthDays.month,\n year: leftMonthDays.year,\n hide: true,\n hideLeftAndRightDays: hideLeftAndRightDays\n })\n })\n }\n\n // Right month days\n if (rightMonthDays.days.length) {\n rightMonthDays.days.forEach(day => {\n let hideLeftAndRightDays = false\n\n if (!this.leftAndRightDays) {\n day = ''\n hideLeftAndRightDays = true\n }\n\n monthWeeks.weeks[monthWeeks.weeks.length - 1].days.push({\n day,\n month: rightMonthDays.month,\n year: rightMonthDays.year,\n hide: true,\n hideLeftAndRightDays: hideLeftAndRightDays\n })\n })\n }\n\n // Remove Week Year\n monthWeeks.weeks.forEach(week => {\n delete week.year\n })\n\n return monthWeeks.weeks\n }\n\n mask(value) {\n let dayLength = this.getDateFromFormat(value)\n .getDate()\n .toString().length\n let month = this.getDateFromFormat(value).getMonth()\n\n let dayMask = '00'\n if (dayLength === 1) {\n dayMask = '0'\n }\n\n let monthMask = '00'\n if (month + 1 <= 9) {\n monthMask = '0'\n }\n\n let mask = this.dateFormat\n .replace('dd', dayMask)\n .replace('mm', monthMask)\n .replace('yyyy', '0000')\n // eslint-disable-next-line\n let literalPattern = /[0\\*]/\n let numberPattern = /[0-9]/\n let newValue = ''\n\n for (let vId = 0, mId = 0; mId < mask.length; ) {\n if (mId >= value.length) break\n\n // Number expected but got a different value, store only the valid portion\n if (mask[mId] === '0' && value[vId].match(numberPattern) == null) {\n break\n }\n\n // Found a literal\n while (mask[mId].match(literalPattern) == null) {\n if (value[vId] === mask[mId]) break\n newValue += mask[mId++]\n }\n\n newValue += value[vId++]\n\n mId++\n }\n\n return newValue\n }\n}\n","const undefinedGenerator = () => undefined\n\nexport const propsAndData = {\n props: {\n activeHours: {\n type: Array,\n required: false\n },\n activeMinutes: {\n type: Array,\n required: false\n },\n borderColor: {\n type: String,\n default: ''\n },\n displayTimeInput: {\n type: Boolean,\n default: false\n },\n configs: {\n type: Object,\n default: () => {}\n },\n sundayStart: {\n type: Boolean,\n default: undefinedGenerator\n },\n placeholder: {\n type: [String, Boolean],\n default: undefinedGenerator\n },\n dateFormat: {\n type: String,\n validator(format) {\n let timeFormat = format.split(' ')[1]\n if (!timeFormat) {\n return true\n }\n const validFormats = ['HH:MM', 'HH:mm', 'hh:MM', 'hh:mm']\n return !!~validFormats.indexOf(timeFormat)\n }\n },\n canClearRange: {\n type: Boolean,\n default: false\n },\n isMultiple: {\n type: Boolean,\n default: undefinedGenerator\n },\n isSeparately: {\n type: Boolean,\n default: undefinedGenerator\n },\n isDatePicker: {\n type: Boolean,\n default: undefinedGenerator\n },\n isMultipleDatePicker: {\n type: Boolean,\n default: undefinedGenerator\n },\n isMultipleDateRange: {\n type: Boolean,\n default: undefinedGenerator\n },\n isDateRange: {\n type: Boolean,\n default: undefinedGenerator\n },\n withTimePicker: {\n type: Boolean,\n default: undefinedGenerator\n },\n calendarsCount: {\n type: Number\n },\n isModal: {\n type: Boolean,\n default: undefinedGenerator\n },\n isTypeable: {\n type: Boolean,\n default: undefinedGenerator\n },\n changeMonthFunction: {\n type: Boolean,\n default: undefinedGenerator\n },\n changeYearFunction: {\n type: Boolean,\n default: undefinedGenerator\n },\n changeYearStep: {\n type: Number,\n default: () => 3\n },\n changeMonthStep: {\n type: Number,\n default: () => 1\n },\n newCurrentDate: {\n type: Date\n },\n markedDates: {\n type: Array,\n default: () => []\n },\n markedDateRange: {\n type: [Object, Array]\n },\n disabledDayNames: {\n type: Array\n },\n disabledDates: {\n type: Array,\n default: () => []\n },\n enabledDates: {\n type: Array,\n default: () => []\n },\n limits: {\n type: [Object, Boolean],\n default: undefinedGenerator\n },\n minSelDays: {\n type: [Number, Boolean],\n default: undefinedGenerator\n },\n maxSelDays: {\n type: [Number, Boolean],\n default: undefinedGenerator\n },\n dayNames: {\n type: Array\n },\n monthNames: {\n type: Array\n },\n shortMonthNames: {\n type: Array\n },\n showWeekNumbers: {\n type: Boolean,\n default: undefinedGenerator\n },\n modelValue: {\n type: Object\n },\n transition: {\n type: Boolean,\n default: undefinedGenerator\n },\n hiddenElements: {\n type: Array\n },\n isAutoCloseable: {\n type: Boolean,\n default: undefined\n },\n isDark: {\n type: Boolean,\n default: undefined\n },\n isLayoutExpandable: {\n type: Boolean,\n default: undefined\n },\n titlePosition: {\n type: String,\n default: 'center'\n },\n arrowsPosition: {\n type: String,\n default: 'space-between'\n },\n alwaysUseDefaultClasses: {\n type: Boolean,\n default: false\n }\n },\n data() {\n return {\n popoverElement: '',\n defaultDateFormat: {\n date: false,\n dateTime: false,\n hour: '00',\n minute: '00'\n },\n hoveredObject: null,\n calendar: {\n currentDate: new Date(),\n selectedDate: false,\n selectedDateTime: false,\n selectedHour: '00',\n selectedMinute: '00',\n selectedDatesItem: '',\n selectedDates: [],\n dateRange: {\n start: '',\n end: ''\n },\n multipleDateRange: []\n },\n transitionPrefix: 'left',\n showCalendar: true,\n showMonthPicker: false,\n showYearPicker: false,\n showTimePicker: false,\n allowPreDate: true,\n allowNextDate: true,\n listCalendars: [],\n fConfigs: {\n sundayStart: false,\n placeholder: false,\n dateFormat: 'dd/mm/yyyy hh:MM',\n isMultipleDateRange: false,\n isDatePicker: false,\n isMultipleDatePicker: false,\n isDateRange: false,\n withTimePicker: false,\n isMultiple: false,\n calendarsCount: 1,\n isSeparately: false,\n\n isModal: false,\n isTypeable: false,\n\n changeMonthFunction: false,\n changeYearFunction: false,\n changeYearStep: 3,\n\n changeMonthStep: 1,\n\n markedDates: [],\n markedDateRange: {\n start: false,\n end: false\n },\n\n limits: false,\n minSelDays: false,\n maxSelDays: false,\n\n disabledDates: [],\n enabledDates: [],\n disabledDayNames: [],\n\n dayNames: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],\n monthNames: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December'\n ],\n shortMonthNames: [\n 'Jan',\n 'Feb',\n 'Mar',\n 'Apr',\n 'May',\n 'Jun',\n 'Jul',\n 'Aug',\n 'Sep',\n 'Oct',\n 'Nov',\n 'Dec'\n ],\n\n showWeekNumbers: false,\n transition: true,\n hiddenElements: [],\n isAutoCloseable: false,\n isDark: false,\n isLayoutExpandable: false,\n\n titlePosition: 'center',\n arrowsPosition: 'space-between'\n }\n }\n }\n}\n","<template>\n <div class=\"vfc-time-picker-container\">\n <div class=\"vfc-close\" @click=\"close()\"></div>\n <div class=\"vfc-modal-time-mechanic\">\n <div id=\"time-line\" class=\"vfc-modal-time-line\">\n <span>\n <template v-if=\"$parent.fConfigs.isDateRange\">\n <span\n @click=\"startDateActive = true\"\n :class=\"{ 'vfc-active': startDateActive }\"\n >{{ $parent.calendar.dateRange.start }}</span\n >\n <template v-if=\"$parent.calendar.dateRange.end\">\n <span>-</span>\n <span\n @click=\"startDateActive = false\"\n :class=\"{ 'vfc-active': !startDateActive }\"\n >{{ $parent.calendar.dateRange.end }}</span\n >\n </template>\n </template>\n <template v-else-if=\"$parent.fConfigs.isMultipleDatePicker\">{{\n getCurrentDateTime\n }}</template>\n <template v-else>{{ $parent.calendar.selectedDateTime }}</template>\n </span>\n </div>\n <div class=\"titles\">\n <div>Hour</div>\n <div>Minute</div>\n </div>\n <div class=\"vfc-time-picker\">\n <div\n class=\"vfc-time-picker__list vfc-time-picker__list--hours\"\n ref=\"hourList\"\n >\n <div\n class=\"vfc-time-picker__item\"\n :class=\"{\n 'vfc-time-picker__item--selected': checkHourActiveClass(i)\n }\"\n v-for=\"i in hours\"\n :key=\"i\"\n @click=\"changeHour(formatTime(i))\"\n >\n {{ formatTime(i) }}\n </div>\n </div>\n <div\n class=\"vfc-time-picker__list vfc-time-picker__list--minutes\"\n ref=\"minuteList\"\n >\n <div\n class=\"vfc-time-picker__item\"\n :class=\"{\n 'vfc-time-picker__item--selected': checkMinuteActiveClass(i)\n }\"\n v-for=\"i in minutes\"\n :key=\"i\"\n @click=\"changeMinute(formatTime(i))\"\n >\n {{ formatTime(i) }}\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'TimePicker',\n data() {\n return {\n startDateActive: true,\n currentSelectedDate: ''\n }\n },\n props: {\n height: {\n type: Number,\n required: true\n },\n hours: {\n type: Array,\n default: function() {\n return [...Array(24).keys()]\n },\n required: false\n },\n minutes: {\n type: Array,\n default: function() {\n return [...Array(60).keys()]\n },\n required: false\n }\n },\n watch: {\n startDateActive: function() {\n this.setScrollPosition()\n }\n },\n computed: {\n getCurrentDate() {\n return this.currentSelectedDate.date\n },\n getCurrentDateTime() {\n return this.currentSelectedDate.dateTime\n }\n },\n created() {\n let selectedDates = this.$parent.calendar.selectedDates\n this.currentSelectedDate = selectedDates[selectedDates.length - 1]\n },\n mounted() {\n let startDate = this.$parent.calendar.dateRange.start.split(' ')[0]\n let endDate = this.$parent.calendar.dateRange.end.split(' ')[0]\n if (\n startDate &&\n this.$parent.helpCalendar.getDateFromFormat(startDate) <\n this.$parent.helpCalendar.getDateFromFormat(endDate)\n ) {\n this.startDateActive = false\n } else {\n this.startDateActive = true\n }\n\n this.setSelectedDateTime()\n this.setStyles()\n },\n methods: {\n formatTime(i) {\n return i < 10 ? '0' + i : i\n },\n close() {\n this.$parent.showTimePicker = false\n },\n addMinuteHour(what, val, to) {\n let res = ''\n res += val.split(' ')[0]\n if (what == 'hour') {\n res += ' ' + to + ':'\n res += val.split(' ')[1].split(':')[1]\n } else {\n res += ' ' + val.split(' ')[1].split(':')[0] + ':'\n res += to\n }\n return res\n },\n changeHour(hour) {\n if (this.$parent.fConfigs.isDateRange) {\n if (this.checkStartDate()) {\n this.$parent.calendar.dateRange.start = this.addMinuteHour(\n 'hour',\n this.$parent.calendar.dateRange.start,\n hour\n )\n } else {\n this.$parent.calendar.dateRange.end = this.addMinuteHour(\n 'hour',\n this.$parent.calendar.dateRange.end,\n hour\n )\n }\n } else if (this.$parent.fConfigs.isMultipleDatePicker) {\n let currentDate = this.$parent.calendar.selectedDates.find(\n date => date.date === this.getCurrentDate\n )\n currentDate.hour = hour\n } else {\n this.$parent.calendar.selectedHour = hour\n }\n\n this.setSelectedDateTime()\n this.setScrollPosition()\n },\n changeMinute(minute) {\n if (this.$parent.fConfigs.isDateRange) {\n if (this.checkStartDate()) {\n this.$parent.calendar.dateRange.start = this.addMinuteHour(\n 'minute',\n this.$parent.calendar.dateRange.start,\n minute\n )\n } else {\n this.$parent.calendar.dateRange.end = this.addMinuteHour(\n 'minute',\n this.$parent.calendar.dateRange.end,\n minute\n )\n }\n } else if (this.$parent.fConfigs.isMultipleDatePicker) {\n let currentDate = this.$parent.calendar.selectedDates.find(\n date => date.date === this.getCurrentDate\n )\n currentDate.minute = minute\n } else {\n this.$parent.calendar.selectedMinute = minute\n }\n\n this.setSelectedDateTime()\n this.setScrollPosition()\n },\n setSelectedDateTime() {\n if (this.$parent.fConfigs.isDatePicker) {\n this.$parent.calendar.selectedDateTime =\n this.$parent.calendar.selectedDate +\n ' ' +\n this.$parent.calendar.selectedHour +\n ':' +\n this.$parent.calendar.selectedMinute\n } else if (this.$parent.fConfigs.isMultipleDatePicker) {\n let currentDate = this.$parent.calendar.selectedDates.find(\n date => date.date === this.getCurrentDate\n )\n currentDate.dateTime =\n currentDate.date + ' ' + currentDate.hour + ':' + currentDate.minute\n }\n },\n checkStartDate() {\n return this.startDateActive\n },\n checkHourActiveClass(i) {\n let hour\n if (this.$parent.fConfigs.isDateRange) {\n if (this.checkStartDate()) {\n hour = this.$parent.calendar.dateRange.start\n .split(' ')[1]\n .split(':')[0]\n } else {\n hour = this.$parent.calendar.dateRange.end.split(' ')[1].split(':')[0]\n }\n } else if (this.$parent.fConfigs.isMultipleDatePicker) {\n hour = this.$parent.calendar.selectedDates.find(\n date => date.date === this.getCurrentDate\n ).hour\n } else {\n hour = this.$parent.calendar.selectedHour\n }\n\n if (this.hours.length && !this.hours.some(el => el == hour)) {\n hour = this.hours[0]\n }\n\n return hour == this.formatTime(i)\n },\n checkMinuteActiveClass(i) {\n let minute\n if (this.$parent.fConfigs.isDateRange) {\n if (this.checkStartDate()) {\n minute = this.$parent.calendar.dateRange.start.split(':')[1]\n } else {\n minute = this.$parent.calendar.dateRange.end.split(':')[1]\n }\n } else if (this.$parent.fConfigs.isMultipleDatePicker) {\n minute = this.$parent.calendar.selectedDates.find(\n date => date.date === this.getCurrentDate\n ).minute\n } else {\n minute = this.$parent.calendar.selectedMinute\n }\n\n if (this.minutes.length && !this.minutes.some(el => el == minute)) {\n minute = this.minutes[0]\n }\n\n return minute == this.formatTime(i)\n },\n setStyles() {\n //let container = this.$parent.$refs.mainContainer\n\n this.setScrollPosition()\n\n let timeLineHeight = +this.height - 35 - 85 // - paddings - titles height\n document.getElementsByClassName('vfc-time-picker__list')[0].style.height =\n timeLineHeight + 'px'\n document.getElementsByClassName('vfc-time-picker__list')[1].style.height =\n timeLineHeight + 'px'\n },\n setScrollPosition() {\n let container = this.$parent.$refs.mainContainer\n\n this.$nextTick(function() {\n const selectedHour = this.$refs.hourList.querySelector(\n '.vfc-time-picker__item--selected'\n )\n const selectedMinute = this.$refs.minuteList.querySelector(\n '.vfc-time-picker__item--selected'\n )\n\n this.$refs.hourList.scrollTop = selectedHour\n ? selectedHour.offsetTop - container.clientHeight / 2\n : 0\n this.$refs.minuteList.scrollTop = selectedMinute\n ? selectedMinute.offsetTop - container.clientHeight / 2\n : 0\n })\n }\n }\n}\n</script>\n\n<style scoped lang=\"scss\">\n.vfc-time-picker-container {\n min-width: 250px;\n .vfc-modal-time-line {\n > span {\n > span:not(:nth-child(2)):not(.vfc-active):hover {\n cursor: pointer;\n }\n }\n }\n .titles {\n display: flex;\n padding: 10px 0;\n > div {\n flex: 1;\n text-align: center;\n color: #66b3cc;\n word-break: break-all;\n font-size: 25px;\n }\n }\n .vfc-time-picker {\n padding-bottom: 20px;\n }\n}\n</style>\n","<template>\n <div>\n <div\n class=\"vfc-separately-navigation-buttons\"\n :class=\"'vfc-' + fConfigs.arrowsPosition\"\n v-if=\"oneArrows || manyArrows\"\n >\n <div\n @click=\"$parent.PreMonth(oneArrows ? 0 : calendarKey)\"\n :class=\"{ 'vfc-cursor-pointer': allowPreDate }\"\n >\n <slot name=\"navigationArrowLeft\">\n <div\n class=\"vfc-arrow-left\"\n :class=\"{ 'vfc-disabled': !allowPreDate }\"\n ></div>\n </slot>\n </div>\n <div\n @click=\"$parent.NextMonth(oneArrows ? 0 : calendarKey)\"\n :class=\"{ 'vfc-cursor-pointer': allowNextDate }\"\n >\n <slot name=\"navigationArrowRight\">\n <div\n class=\"vfc-arrow-right\"\n :class=\"{ 'vfc-disabled': !allowNextDate }\"\n ></div>\n </slot>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'CalendarArrows',\n props: {\n fConfigs: {\n type: Object,\n required: true\n },\n allowPreDate: {\n type: Boolean,\n required: true\n },\n allowNextDate: {\n type: Boolean,\n required: true\n },\n calendarKey: {\n type: Number,\n default: 0\n },\n isMultiple: {\n type: Boolean,\n required: true\n }\n },\n computed: {\n oneArrows() {\n return !this.fConfigs.isSeparately && !this.isMultiple\n },\n manyArrows() {\n return this.fConfigs.isSeparately && this.isMultiple\n }\n }\n}\n</script>\n","<template>\n <div\n class=\"vfc-day vfc-week-number\"\n :style=\"{ borderRightColor: borderColor }\"\n >\n <span class=\"vfc-span-day\">{{ number }}</span>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'WeekNumbers',\n props: {\n number: {\n tyoe: Number,\n required: true\n },\n borderColor: {\n type: String,\n default: ''\n }\n }\n}\n</script>\n\n<style scoped></style>\n","<template>\n <div class=\"vfc-day\">\n <div v-if=\"startActive\" class=\"vfc-base-start\"></div>\n <div v-if=\"endActive\" class=\"vfc-base-end\"></div>\n <span\n v-if=\"!day.hideLeftAndRightDays\"\n :class=\"getClassNames(day)\"\n @click.self=\"$parent.$parent.clickDay(day, isDisabledDate)\"\n @mouseover=\"dayMouseOver\"\n >\n <slot :week=\"week\" :day=\"day\">{{ day.day }}</slot>\n <span v-if=\"timesShow\" @click=\"clearRange\" class=\"times\">×</span>\n <span\n v-if=\"numberShow\"\n @mouseover=\"toolTip && (onNumber = true)\"\n @mouseleave=\"onNumber = false\"\n class=\"number\"\n >{{ getDaysNumber }}\n <div v-show=\"toolTip && onNumber\" class=\"toolTip\">\n {{ toolTipTxt().join(' ') }}\n </div>\n </span>\n </span>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'CalendarDay',\n props: {\n day_key: {\n type: Number,\n required: true\n },\n week: {\n type: Object,\n required: true\n },\n day: {\n type: Object,\n required: true\n },\n helpCalendar: {\n type: Object,\n required: true\n },\n fConfigs: {\n type: Object,\n required: true\n },\n calendar: {\n type: Object,\n required: true\n },\n alwaysUseDefaultClasses: {\n type: Boolean,\n default: false\n }\n },\n emits: ['clearRange', 'dayMouseOver'],\n data() {\n return {\n toolTip: false,\n onNumber: false\n // toolTipTxt\n }\n },\n computed: {\n startActive() {\n if (!this.fConfigs.isMultipleDateRange)\n return (\n (this.day.isDateRangeStart || this.day.isMouseToLeft) &&\n !this.day.hideLeftAndRightDays\n )\n\n if (!''.inRange) this.inRangeInit()\n\n const inAnyRange = this.day.date.inRange(this.calendar.multipleDateRange)\n\n const lastElement = this.calendar.multipleDateRange[\n this.calendar.multipleDateRange.length - 1\n ]\n if (!lastElement) return inAnyRange\n const lastHasDayStart = ~this.calendar.multipleDateRange\n .map(range => range.start)\n .indexOf(this.day.date)\n const lastHasDayEnd = ~this.calendar.multipleDateRange\n .map(range => range.end)\n .indexOf(this.day.date)\n\n if (lastHasDayStart === lastHasDayEnd && lastHasDayEnd) return inAnyRange\n\n if (\n lastHasDayStart &&\n ~lastHasDayStart > -1 &&\n this.calendar.multipleDateRange[~lastHasDayStart].end\n )\n return lastHasDayStart || inAnyRange\n\n if (!lastElement.start && !lastElement.end) {\n return lastHasDayStart || inAnyRange\n }\n // console.log('lastElement')\n\n return (\n ((this.day.isDateRangeStart || this.day.isMouseToLeft) &&\n !this.day.hideLeftAndRightDays) ||\n inAnyRange\n )\n },\n endActive() {\n if (!this.fConfigs.isMultipleDateRange)\n return (\n (this.day.isDateRangeEnd || this.day.isMouseToRight) &&\n !this.day.hideLeftAndRightDays\n )\n\n if (!''.inRange) this.inRangeInit()\n\n const inAnyRange = this.day.date.inRange(this.calendar.multipleDateRange)\n\n const lastElement = this.calendar.multipleDateRange[\n this.calendar.multipleDateRange.length - 1\n ]\n if (!lastElement) return inAnyRange\n\n const lastHasDayStart = ~this.calendar.multipleDateRange\n .map(range => range.start)\n .indexOf(this.day.date)\n const lastHasDayEnd = ~this.calendar.multipleDateRange\n .map(range => range.end)\n .indexOf(this.day.date)\n\n if (lastHasDayStart === lastHasDayEnd && lastHasDayEnd) return inAnyRange\n\n if (lastHasDayEnd) return true\n\n if (!lastElement.start && !lastElement.end) {\n if (lastElement.start === lastElement.end) return false\n return lastHasDayEnd\n }\n return (\n ((this.day.isDateRangeEnd || this.day.isMouseToRight) &&\n !this.day.hideLeftAndRightDays) ||\n inAnyRange\n )\n },\n numberShow() {\n if (!this.fConfigs.isMultipleDateRange) return false\n\n let endPos = this.calendar.multipleDateRange\n .map(range => range.end)\n .indexOf(this.day.date)\n\n return !!(\n ~endPos ||\n ~this.calendar.multipleDateRange\n .map(range => range.start)\n .indexOf(this.day.date)\n )\n },\n timesShow() {\n let res = this.calendar.multipleDateRange\n ? ~this.calendar.multipleDateRange\n .map(range => range.end)\n .indexOf(this.day.date)\n : -1\n return this.fConfigs.isMultipleDateRange && res\n },\n getDaysNumber() {\n const endPosFirst = this.calendar.multipleDateRange\n .map(range => range.end)\n .indexOf(this.day.date)\n const startPosFirst = this.calendar.multipleDateRange\n .map(range => range.start)\n .indexOf(this.day.date)\n const endPosLast = this.calendar.multipleDateRange\n .map(range => range.end)\n .lastIndexOf(this.day.date)\n const startPosLast = this.calendar.multipleDateRange\n .map(range => range.start)\n .lastIndexOf(this.day.date)\n\n // eslint-disable-next-line vue/no-side-effects-in-computed-properties\n this.toolTip =\n endPosFirst !== endPosLast ||\n startPosFirst !== startPosLast ||\n (endPosFirst > -1 && startPosFirst > -1) ||\n (startPosFirst > -1 && endPosFirst > -1)\n\n if (this.toolTip) {\n return '·'\n }\n\n return (endPosFirst > -1 ? Number(endPosFirst) : null) ?? startPosFirst\n }\n },\n methods: {\n toolTipTxt() {\n const numbers = []\n const endArr = this.calendar.multipleDateRange.map(range => range.end)\n const startArr = this.calendar.multipleDateRange.map(range => range.start)\n let endIndex = 0\n let startIndex = 0\n let ind = endArr.indexOf(this.day.date, endIndex)\n while (~endArr.indexOf(this.day.date, endIndex)) {\n ind = endArr.indexOf(this.day.date, endIndex)\n\n numbers.push(ind)\n endIndex = ind + 1\n }\n ind = startArr.indexOf(this.day.date, startIndex)\n while (~startArr.indexOf(this.day.date, startIndex)) {\n ind = startArr.indexOf(this.day.date, startIndex)\n\n numbers.push(ind)\n startIndex = ind + 1\n }\n return numbers.sort((a, b) => a - b)\n },\n inRangeInit() {\n //!!!!\\\\\n const helpCalendar = this.helpCalendar\n String.prototype.inRange = function(arr) {\n let res = false\n arr.forEach(el => {\n const start = +helpCalendar.getDateFromFormat(el.start.split(' ')[0])\n const end = +helpCalendar.getDateFromFormat(el.end.split(' ')[0])\n const current = +helpCalendar.getDateFromFormat(this.split(' ')[0])\n if (start === end) return\n if (start && end) res = res || (start < current && current < end)\n })\n return res\n }\n //!!!!\\\\\n },\n\n clearRange() {\n this.$emit('clearRange', this.day.date)\n },\n dayMouseOver() {\n this.$emit('dayMouseOver', this.day.date)\n },\n hasSlot(name = 'default') {\n return (\n !!this.$parent.$parent.$slots[name]\n )\n },\n isDisabledDate(date) {\n const datesCollection = this.fConfigs.disabledDates\n\n return (\n this.isDateIncludedInDatesCollection(date, datesCollection) ||\n !this.isEnabledDate(date)\n )\n },\n isEnabledDate(date) {\n const datesCollection = this.fConfigs.enabledDates\n\n return (\n !datesCollection.length ||\n this.isDateIncludedInDatesCollection(date, datesCollection)\n )\n },\n isDateIncludedInDatesCollection(date, datesCollection) {\n let today = new Date()\n today.setHours(0, 0, 0, 0)\n let dateObj = this.helpCalendar.getDateFromFormat(date)\n\n return (\n datesCollection.includes(date) ||\n (datesCollection.includes('beforeToday') &&\n dateObj.getTime() < today.getTime()) ||\n (datesCollection.includes('afterToday') &&\n dateObj.getTime() > today.getTime())\n )\n },\n getClassNames(day) {\n let classes = []\n\n if (!this.hasSlot('default') || this.alwaysUseDefaultClasses) {\n classes.push('vfc-span-day')\n }\n\n // Disable days of week if set in configuration\n let dateDay = this.helpCalendar.getDateFromFormat(day.date).getDay() - 1\n if (dateDay === -1) {\n dateDay = 6\n }\n let dayOfWeekString = this.fConfigs.dayNames[dateDay]\n if (this.fConfigs.disabledDayNames.includes(dayOfWeekString)) {\n day.hide = true\n classes.push('vfc-cursor-not-allowed')\n }\n\n let date = this.helpCalendar.getDateFromFormat(day.date)\n let today = new Date()\n today.setHours(0, 0, 0, 0)\n // Disabled dates\n if (this.isDisabledDate(day.date)) {\n classes.push('vfc-disabled')\n classes.push('vfc-cursor-not-allowed')\n }\n\n if (this.fConfigs.limits) {\n let min = this.helpCalendar\n .getDateFromFormat(this.fConfigs.limits.min)\n .getTime()\n let max = this.helpCalendar\n .getDateFromFormat(this.fConfigs.limits.max)\n .getTime()\n\n if (date.getTime() < min || date.getTime() > max) {\n classes.push('vfc-disabled')\n classes.push('vfc-cursor-not-allowed')\n }\n }\n\n if (day.hide) {\n classes.push('vfc-hide')\n }\n\n // Today date\n if (day.isToday) {\n classes.push('vfc-today')\n }\n if (\n !day.hideLeftAndRightDays &&\n !this.fConfigs.disabledDayNames.includes(dayOfWeekString)\n ) {\n // Mark Date\n if (day.isMarked) {\n classes.push('vfc-marked')\n } else if (day.isHovered) {\n classes.push('vfc-hovered')\n }\n if (this.fConfigs.markedDates.includes(day.date)) {\n classes.push('vfc-borderd')\n }\n\n if (Array.isArray(this.fConfigs.markedDateRange)) {\n this.fConfigs.markedDateRange.forEach(range => {\n if (\n this.helpCalendar.getDateFromFormat(range.start) <=\n this.helpCalendar.getDateFromFormat(day.date) &&\n this.helpCalendar.getDateFromFormat(range.end) >=\n this.helpCalendar.getDateFromFormat(day.date)\n ) {\n classes.push('vfc-marked')\n }\n if (day.date === range.start) {\n classes.push('vfc-start-marked')\n } else if (day.date === range.end) {\n classes.push('vfc-end-marked')\n }\n })\n } else if (\n this.fConfigs.markedDateRange.start &&\n this.fConfigs.markedDateRange.end\n ) {\n // Date Range Marked\n\n if (\n this.helpCalendar.getDateFromFormat(\n this.fConfigs.markedDateRange.start\n ) <= this.helpCalendar.getDateFromFormat(day.date) &&\n this.helpCalendar.getDateFromFormat(\n this.fConfigs.markedDateRange.end\n ) >= this.helpCalendar.getDateFromFormat(day.date)\n ) {\n classes.push('vfc-marked')\n }\n if (day.date === this.fConfigs.markedDateRange.start) {\n classes.push('vfc-start-marked')\n } else if (day.date === this.fConfigs.markedDateRange.end) {\n classes.push('vfc-end-marked')\n }\n } else {\n // Only After Start Marked\n if (this.fConfigs.markedDateRange.start) {\n if (\n this.helpCalendar.getDateFromFormat(\n this.fConfigs.markedDateRange.start\n ) <= this.helpCalendar.getDateFromFormat(day.date)\n )\n classes.push('vfc-marked')\n }\n\n // Only Before End Marked\n if (this.fConfigs.markedDateRange.end) {\n if (\n this.helpCalendar.getDateFromFormat(\n this.fConfigs.markedDateRange.end\n ) >= this.helpCalendar.getDateFromFormat(day.date)\n )\n classes.push('vfc-marked')\n }\n }\n\n classes.push('vfc-hover')\n }\n //Date Multiple Range\n if (this.fConfigs.isMultipleDateRange) {\n if (!''.inRange) this.inRangeInit()\n // console.log(day.date.inRange(this.calendar.multipleDateRange))\n if (\n day.isMarked ||\n ~this.calendar.multipleDateRange\n .map(range => range.start.split(' ')[0])\n .indexOf(day.date) ||\n ~this.calendar.multipleDateRange\n .map(range => range.end.split(' ')[0])\n .indexOf(day.date) ||\n day.date.inRange(this.calendar.multipleDateRange)\n ) {\n classes.push('vfc-marked')\n }\n // } else if (day.isHovered) {\n // classes.push('vfc-hovered')\n // }\n if (this.fConfigs.markedDates.includes(day.date)) {\n classes.push('vfc-borderd')\n }\n // console.log(\n // ~this.calendar.multipleDateRange\n // .map(range => range.start)\n // .indexOf(day.date)\n // )\n if (\n ~this.calendar.multipleDateRange\n .map(range => range.start.split(' ')[0])\n .indexOf(day.date)\n ) {\n classes.push('vfc-start-marked')\n }\n\n if (\n ~this.calendar.multipleDateRange\n .map(range => range.end.split(' ')[0])\n .indexOf(day.date)\n ) {\n classes.push('vfc-end-marked')\n }\n }\n // Date Mark With Custom Classes\n if (typeof this.fConfigs.markedDates === 'object') {\n let checkMarked = this.fConfigs.markedDates.find(markDate => {\n return markDate.date === day.date\n })\n\n if (typeof checkMarked !== 'undefined') {\n classes.push(checkMarked.class)\n }\n }\n\n if (day.date === this.calendar.dateRange.start.split(' ')[0]) {\n classes.push('vfc-start-marked')\n }\n\n if (day.date === this.calendar.dateRange.end.split(' ')[0]) {\n classes.push('vfc-end-marked')\n }\n\n if (\n day.date === this.calendar.selectedDate ||\n (Object.prototype.hasOwnProperty.call(this.calendar, 'selectedDates') &&\n this.calendar.selectedDates.find(sDate => sDate.date === day.date))\n ) {\n classes.push('vfc-borderd')\n }\n\n return classes\n }\n }\n}\n</script>\n\n<style scoped lang=\"scss\">\n.vfc-day {\n position: relative;\n .times {\n position: absolute;\n top: -5px;\n background-color: red;\n color: white;\n border-radius: 50%;\n width: 15px;\n z-index: 20;\n height: 15px;\n line-height: 15px;\n &:hover {\n cursor: pointer;\n background-color: rgb(199, 0, 0);\n }\n }\n .number {\n position: absolute;\n top: -5px;\n right: calc(50% + 7px);\n background-color: green;\n color: white;\n font-size: 10px;\n border-radius: 50%;\n width: 15px;\n z-index: 30;\n height: 15px;\n line-height: 15px;\n &:hover {\n background-color: rgb(0, 94, 0);\n }\n }\n .toolTip {\n position: absolute;\n top: -20px;\n left: 0;\n padding: 5px;\n max-width: 108px;\n word-wrap: break-word;\n border-radius: 5px;\n z-index: 200;\n background-color: rgb(0, 94, 0);\n }\n}\n</style>\n","<template>\n <div class=\"vfc-months-container\">\n <div class=\"vfc-content vfc-content-MY-picker\">\n <div class=\"vfc-navigation-buttons\">\n <div @click=\"changePicker('left')\">\n <div class=\"vfc-arrow-left\"></div>\n </div>\n <h2\n :class=\"['vfc-top-date', delta !== 0 && 'vfc-top-date-has-delta']\"\n @click=\"delta = 0\"\n >\n <span class=\"vfc-popover-caret\"></span>\n {{ $parent.listCalendars[calendarKey].date.getFullYear() }}\n </h2>\n <div @click=\"changePicker('right')\">\n <div class=\"vfc-arrow-right\"></div>\n </div>\n </div>\n <div class=\"vfc-months\">\n <template v-if=\"$parent.showMonthPicker\">\n <div\n class=\"vfc-item\"\n v-for=\"(month, key) in $parent.fConfigs.shortMonthNames\"\n :key=\"key\"\n :class=\"{\n 'vfc-selected':\n $parent.listCalendars[calendarKey].date.getMonth() === key\n }\"\n @click=\"$parent.pickMonth(key, calendarKey)\"\n >\n {{ month }}\n </div>\n </template>\n <template v-else-if=\"$parent.showYearPicker\">\n <div\n class=\"vfc-item\"\n v-for=\"(year, key) in $parent.getYearList(\n $parent.listCalendars[calendarKey].date,\n delta\n )\"\n :key=\"key\"\n :class=\"{\n 'vfc-selected':\n $parent.listCalendars[calendarKey].date.getFullYear() ===\n year.year\n }\"\n @click=\"$parent.pickYear(year.year, calendarKey)\"\n >\n {{ year.year }}\n </div>\n </template>\n </div>\n </div>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'MonthYearPicker',\n props: {\n calendarKey: {\n type: Number,\n default: 0\n },\n changeYearStep: {\n type: Number,\n default: 3\n }\n },\n data() {\n return {\n delta: 0\n }\n },\n watch: {\n delta(newDelta) {\n if (newDelta < -new Date().getFullYear()) this.delta = 0\n }\n },\n methods: {\n changePicker(to) {\n if (this.$parent.showMonthPicker) {\n if (to === 'right') this.$parent.NextYear(this.calendarKey)\n else this.$parent.PreYear(this.calendarKey)\n return\n }\n\n if (to === 'right') this.delta += this.changeYearStep\n else this.delta -= this.changeYearStep\n }\n }\n}\n</script>\n\n<style scoped></style>\n","<template>\n <div>\n <div\n class=\"vfc-multiple-input\"\n :class=\"{ 'vfc-dark': fConfigs.isDark }\"\n v-if=\"fConfigs.isModal && fConfigs.isDateRange\"\n >\n <slot\n name=\"dateRangeInputs\"\n :startDate=\"dateRangeSelectedStartDate\"\n :endDate=\"dateRangeSelectedEndDate\"\n :isTypeable=\"fConfigs.isTypeable\"\n >\n <input\n type=\"text\"\n title=\"Start Date\"\n :value=\"dateRangeSelectedStartDate\"\n @input=\"updateDateRangeStart\"\n :placeholder=\"fConfigs.placeholder.split(' ')[0]\"\n :readonly=\"!fConfigs.isTypeable\"\n :maxlength=\"fConfigs.dateFormat.length\"\n />\n <input\n type=\"text\"\n title=\"End Date\"\n :value=\"dateRangeSelectedEndDate\"\n @input=\"updateDateRangeEnd\"\n :placeholder=\"fConfigs.placeholder.split(' ')[0]\"\n :readonly=\"!fConfigs.isTypeable\"\n :maxlength=\"fConfigs.dateFormat.length\"\n />\n </slot>\n </div>\n <div\n :class=\"{ 'vfc-dark': fConfigs.isDark }\"\n v-else-if=\"fConfigs.isModal && fConfigs.isDatePicker\"\n >\n <slot\n name=\"datePickerInput\"\n :selectedDate=\"singleSelectedDate\"\n :isTypeable=\"fConfigs.isTypeable\"\n >\n <input\n class=\"vfc-single-input\"\n type=\"text\"\n title=\"Date\"\n :value=\"singleSelectedDate\"\n @input=\"updateSingleDate\"\n :placeholder=\"fConfigs.placeholder\"\n :readonly=\"!fConfigs.isTypeable\"\n :maxlength=\"fConfigs.dateFormat.length\"\n />\n </slot>\n </div>\n <div\n v-else-if=\"fConfigs.isModal && fConfigs.isMultipleDatePicker\"\n class=\"vfc-tags-input-root\"\n :class=\"{ 'vfc-dark': fConfigs.isDark }\"\n >\n <div class=\"vfc-tags-input-wrapper-default vfc-tags-input\">\n <span\n class=\"vfc-tags-input-badge vfc-tags-input-badge-pill vfc-tags-input-badge-selected-default\"\n v-for=\"(date, index) in calendar.selectedDates\"\n :key=\"index\"\n >\n <span v-html=\"date.date\"></span>\n <a\n href=\"#\"\n class=\"vfc-tags-input-remove\"\n @click.prevent=\"removeFromSelectedDates(index)\"\n ></a>\n </span>\n\n <input\n :value=\"calendar.selectedDatesItem\"\n @input=\"updateSelectedDatesItem\"\n @keydown.enter.prevent=\"$parent.addToSelectedDates\"\n type=\"text\"\n placeholder=\"Add a date\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'PickerInputs',\n props: {\n fConfigs: {\n type: Object,\n required: true\n },\n singleSelectedDate: {\n type: String,\n required: true\n },\n calendar: {\n type: Object,\n required: true\n }\n },\n emits: ['update:singleSelectedDate', 'update:calendar'],\n computed: {\n dateRangeSelectedStartDate: {\n get() {\n return this.calendar.dateRange.start\n ? this.calendar.dateRange.start\n : ''\n },\n set(newValue) {\n newValue = this.helpCalendar.mask(newValue)\n if (this.helpCalendar.getDateFromFormat(newValue).getMonth()) {\n const updatedCalendar = {\n ...this.calendar,\n dateRange: {\n ...this.calendar.dateRange,\n start: newValue\n }\n }\n this.$emit('update:calendar', updatedCalendar)\n }\n }\n },\n dateRangeSelectedEndDate: {\n get() {\n return this.calendar.dateRange.end ? this.calendar.dateRange.end : ''\n },\n set(newValue) {\n newValue = this.helpCalendar.mask(newValue)\n if (this.helpCalendar.getDateFromFormat(newValue).getMonth()) {\n const updatedCalendar = {\n ...this.calendar,\n dateRange: {\n ...this.calendar.dateRange,\n end: newValue\n }\n }\n this.$emit('update:calendar', updatedCalendar)\n }\n }\n }\n },\n methods: {\n updateSingleDate(event) {\n this.$emit('update:singleSelectedDate', event.target.value)\n },\n updateDateRangeStart(event) {\n this.dateRangeSelectedStartDate = event.target.value\n },\n updateDateRangeEnd(event) {\n this.dateRangeSelectedEndDate = event.target.value\n },\n updateSelectedDatesItem(event) {\n const updatedCalendar = {\n ...this.calendar,\n selectedDatesItem: event.target.value\n }\n this.$emit('update:calendar', updatedCalendar)\n },\n removeFromSelectedDates(index) {\n // This method needs to be implemented or moved to parent\n this.$parent.removeFromSelectedDates(index)\n }\n }\n}\n</script>\n\n<style scoped></style>\n","<template>\n <div class=\"footerCon\">\n <slot name=\"cleaner\"></slot>\n <slot name=\"footer\"></slot>\n </div>\n</template>\n\n<script>\nexport default {\n name: 'CalendarFooter'\n}\n</script>\n\n<style scoped lang=\"scss\">\n.footerCon {\n display: flex;\n justify-content: space-between;\n margin: 0 20px 20px;\n}\n</style>\n","/**\n * Check Element Contains\n * @param el\n * @param child\n * @returns {boolean|*}\n */\nexport const hElContains = (el, child) =>\n !!el && !!child && (el === child || el.contains(child))\n\n/**\n * Generate unique ID\n * @returns {number}\n */\nexport const hUniqueID = () => new Date().getUTCMilliseconds()\n","<template>\n <div class=\"vfc-popover-container\" ref=\"popoverElement\" tabindex=\"0\">\n <PickerInputs\n :fConfigs=\"fConfigs\"\n :singleSelectedDate=\"singleSelectedDate\"\n :calendar=\"calendar\"\n @update:si