UNPKG

@startinfinity/vue-datepicker

Version:

A simple Vue.js datepicker component. Supports disabling of dates, inline mode, translations

2,062 lines (1,816 loc) 89.3 kB
/* * @startinfinity/vue-datepicker v3.2.6 * (c) 2018-2021 sum.cumo GmbH * Released under the Apache-2.0 License. */ class Language { // eslint-disable-next-line max-params constructor(language, months, monthsAbbr, days, rtl = false, ymd = false, yearSuffix = '') { this.language = language; this.months = months; this.monthsAbbr = monthsAbbr; this.days = days; this.rtl = rtl; this.ymd = ymd; this.yearSuffix = yearSuffix; } /* eslint-disable no-underscore-dangle */ get language() { return this._language; } set language(language) { if (typeof language !== 'string') { throw new TypeError('Language must be a string'); } this._language = language; } get months() { return this._months; } set months(months) { if (months.length !== 12) { throw new RangeError(`There must be 12 months for ${this.language} language`); } this._months = months; } get monthsAbbr() { return this._monthsAbbr; } set monthsAbbr(monthsAbbr) { if (monthsAbbr.length !== 12) { throw new RangeError(`There must be 12 abbreviated months for ${this.language} language`); } this._monthsAbbr = monthsAbbr; } get days() { return this._days; } set days(days) { if (days.length !== 7) { throw new RangeError(`There must be 7 days for ${this.language} language`); } this._days = days; } getDaysStartingOn(firstDayOfWeek) { const firstDays = this._days.slice(firstDayOfWeek); const lastDays = this._days.slice(0, firstDayOfWeek); return firstDays.concat(lastDays); } getMonthByAbbrName(name) { const monthValue = this._monthsAbbr.findIndex(month => month === name) + 1; return monthValue < 10 ? `0${monthValue}` : `${monthValue}`; } getMonthByName(name) { const monthValue = this._months.findIndex(month => month === name) + 1; return monthValue < 10 ? `0${monthValue}` : `${monthValue}`; } } var en = new Language('English', ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']); var calendarSlots = ['beforeCalendarHeaderDay', 'calendarFooterDay', 'beforeCalendarHeaderMonth', 'calendarFooterMonth', 'beforeCalendarHeaderYear', 'calendarFooterYear', 'nextIntervalBtn', 'prevIntervalBtn']; const getParsedDate = ({ formatStr, dateStr, translation }) => { const splitter = formatStr.match(/-|\/|\s|\./) || ['-']; const df = formatStr.split(splitter[0]); const ds = dateStr.split(splitter[0]); const ymd = [new Date().getFullYear(), '01', '01']; for (let i = 0; i < df.length; i += 1) { if (/yyyy/i.test(df[i])) { ymd[0] = ds[i]; } else if (/mmmm/i.test(df[i])) { ymd[1] = translation.getMonthByName(ds[i]); } else if (/mmm/i.test(df[i])) { ymd[1] = translation.getMonthByAbbrName(ds[i]); } else if (/mm/i.test(df[i])) { ymd[1] = ds[i]; } else if (/m/i.test(df[i])) { ymd[1] = ds[i]; } else if (/dd/i.test(df[i])) { ymd[2] = ds[i]; } else if (/d/i.test(df[i])) { const tmp = ds[i].replace(/st|rd|nd|th/g, ''); ymd[2] = tmp < 10 ? `0${tmp}` : `${tmp}`; } } return ymd; }; const utils = { /** * @type {Boolean} */ useUtc: false, /** * Returns the full year, using UTC or not * @param {Date} date */ getFullYear(date) { return this.useUtc ? date.getUTCFullYear() : date.getFullYear(); }, /** * Returns the month, using UTC or not * @param {Date} date */ getMonth(date) { return this.useUtc ? date.getUTCMonth() : date.getMonth(); }, /** * Returns the number of days in the month, using UTC or not * @param {Date} date */ getDaysInMonth(date) { return this.daysInMonth(this.getFullYear(date), this.getMonth(date)); }, /** * Returns the date, using UTC or not * @param {Date} date */ getDate(date) { return this.useUtc ? date.getUTCDate() : date.getDate(); }, /** * Returns the day, using UTC or not * @param {Date} date */ getDay(date) { return this.useUtc ? date.getUTCDay() : date.getDay(); }, /** * Returns the hours, using UTC or not * @param {Date} date */ getHours(date) { return this.useUtc ? date.getUTCHours() : date.getHours(); }, /** * Returns the minutes, using UTC or not * @param {Date} date */ getMinutes(date) { return this.useUtc ? date.getUTCMinutes() : date.getMinutes(); }, /** * Sets the full year, using UTC or not * @param {Date} date * @param {String, Number} value */ setFullYear(date, value) { return this.useUtc ? date.setUTCFullYear(value) : date.setFullYear(value); }, /** * Sets the month, using UTC or not * @param {Date} date * @param {String, Number} value */ setMonth(date, value) { return this.useUtc ? date.setUTCMonth(value) : date.setMonth(value); }, /** * Sets the date, using UTC or not * @param {Date} date * @param {String, Number} value */ setDate(date, value) { return this.useUtc ? date.setUTCDate(value) : date.setDate(value); }, /** * Check if date1 is equivalent to date2, without comparing the time * @see https://stackoverflow.com/a/6202196/4455925 * @param {Date} date1 * @param {Date} date2 */ compareDates(date1, date2) { const d1 = new Date(date1.valueOf()); const d2 = new Date(date2.valueOf()); this.resetDateTime(d1); this.resetDateTime(d2); return d1.valueOf() === d2.valueOf(); }, /** * Validates a date object * @param {Date} date - an object instantiated with the new Date constructor * @return {Boolean} */ isValidDate(date) { if (Object.prototype.toString.call(date) !== '[object Date]') { return false; } return !Number.isNaN(date.valueOf()); }, /** * Return abbreviated week day name * @param {Date} date * @param {Array} days * @return {String} */ getDayNameAbbr(date, days) { if (typeof date !== 'object') { throw TypeError('Invalid Type'); } return days[this.getDay(date)]; }, /** * Return day number from abbreviated week day name * @param {String} abbr * @return {Number} */ getDayFromAbbr(abbr) { for (let i = 0; i < en.days.length; i += 1) { if (abbr.toLowerCase() === en.days[i].toLowerCase()) { return i; } } throw TypeError('Invalid week day'); }, /** * Return name of the month * @param {Number|Date} month * @param {Array} months * @return {String} */ getMonthName(month, months) { if (!months) { throw Error('missing 2nd parameter Months array'); } if (typeof month === 'object') { return months[this.getMonth(month)]; } if (typeof month === 'number') { return months[month]; } throw TypeError('Invalid type'); }, /** * Return an abbreviated version of the month * @param {Number|Date} month * @param {Array} monthsAbbr * @return {String} */ getMonthNameAbbr(month, monthsAbbr) { if (!monthsAbbr) { throw Error('missing 2nd paramter Months array'); } if (typeof month === 'object') { return monthsAbbr[this.getMonth(month)]; } if (typeof month === 'number') { return monthsAbbr[month]; } throw TypeError('Invalid type'); }, /** * Alternative get total number of days in month * @param {Number} year * @param {Number} month * @return {Number} */ // eslint-disable-next-line complexity daysInMonth(year, month) { if (/8|3|5|10/.test(month)) { return 30; } if (month === 1) { return !(year % 4) && year % 100 || !(year % 400) ? 29 : 28; } return 31; }, /** * Get nth suffix for date * @param {Number} day * @return {String} */ // eslint-disable-next-line complexity getNthSuffix(day) { switch (day) { case 1: case 21: case 31: return 'st'; case 2: case 22: return 'nd'; case 3: case 23: return 'rd'; default: return 'th'; } }, /** * Formats date object * @param {Date} date * @param {String} formatStr * @param {Object} translation * @return {String} */ formatDate(date, formatStr, translation = en) { const year = this.getFullYear(date); const month = this.getMonth(date) + 1; const day = this.getDate(date); const matches = { dd: `0${day}`.slice(-2), d: day, yyyy: year, yy: String(year).slice(2), MMMM: this.getMonthName(this.getMonth(date), translation.months), MMM: this.getMonthNameAbbr(this.getMonth(date), translation.monthsAbbr), MM: `0${month}`.slice(-2), M: month, o: this.getNthSuffix(this.getDate(date)), E: this.getDayNameAbbr(date, translation.days) }; const REGEX_FORMAT = /y{4}|y{2}|M{1,4}(?![aäe])|d{1,2}|o{1}|E{1}(?![eéi])/g; return formatStr.replace(REGEX_FORMAT, match => matches[match] || match); }, /** * makes date parseable * to use with international dates * @param {String} dateStr * @param {String|Function} formatStr * @param {Object} translation * @param {Function} parser * @return {Date | String} */ // eslint-disable-next-line max-params,complexity,max-statements parseDate(dateStr, formatStr, translation = en, parser = null) { if (!(dateStr && formatStr)) { return dateStr; } if (typeof formatStr === 'function') { if (!parser || typeof parser !== 'function') { throw new Error('Parser needs to be a function if you are using a custom formatter'); } return parser(dateStr); } const ymd = getParsedDate({ formatStr, dateStr, translation }); const dat = `${ymd.join('-')}${this.getTime()}`; if (Number.isNaN(Date.parse(dat))) { return dateStr; } return dat; }, getTime() { const time = 'T00:00:00'; if (this.useUtc) { return `${time}Z`; } return time; }, /** * Creates an array of dates for each day in between two dates. * @param {Date} start * @param {Date} end * @return {Array} */ createDateArray(start, end) { const dates = []; let startTemp = start; while (startTemp <= end) { dates.push(new Date(startTemp)); startTemp = this.setDate(new Date(startTemp), this.getDate(new Date(startTemp)) + 1); } return dates; }, /** * Remove hours/minutes/seconds/milliseconds from a date object * @param {Date} date * @return {Date} */ resetDateTime(date) { return new Date(this.useUtc ? date.setUTCHours(0, 0, 0, 0) : date.setHours(0, 0, 0, 0)); }, /** * Return a new date object with hours/minutes/seconds/milliseconds removed * @return {Date} */ getNewDateObject(date) { return date ? this.resetDateTime(new Date(date)) : this.resetDateTime(new Date()); } }; var makeDateUtils = (useUtc => ({ ...utils, useUtc })); var script$9 = { props: { autofocus: { type: Boolean, default: false }, bootstrapStyling: { type: Boolean, default: false }, clearButton: { type: Boolean, default: false }, clearButtonIcon: { type: String, default: '' }, calendarButton: { type: Boolean, default: false }, calendarButtonIcon: { type: String, default: '' }, calendarButtonIconContent: { type: String, default: '' }, disabled: { type: Boolean, default: false }, format: { type: [String, Function], default: 'dd MMM yyyy' }, id: { type: String, default: null }, inline: { type: Boolean, default: false }, inputClass: { type: [String, Object, Array], default: null }, maxlength: { type: [Number, String], default: null }, name: { type: String, default: null }, openDate: { type: [String, Date, Number], default: null, validator: val => val === null || val instanceof Date || typeof val === 'string' || typeof val === 'number' }, parser: { type: Function, default: null }, pattern: { type: String, default: null }, placeholder: { type: String, default: null }, refName: { type: String, default: '' }, required: { type: Boolean, default: false }, showCalendarOnButtonClick: { type: Boolean, default: false }, showCalendarOnFocus: { type: Boolean, default: false }, tabindex: { type: [Number, String], default: null }, typeable: { type: Boolean, default: false }, useUtc: { type: Boolean, default: false } } }; function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) { if (typeof shadowMode !== 'boolean') { createInjectorSSR = createInjector; createInjector = shadowMode; shadowMode = false; } // Vue.extend constructor export interop. const options = typeof script === 'function' ? script.options : script; // render functions if (template && template.render) { options.render = template.render; options.staticRenderFns = template.staticRenderFns; options._compiled = true; // functional template if (isFunctionalTemplate) { options.functional = true; } } // scopedId if (scopeId) { options._scopeId = scopeId; } let hook; if (moduleIdentifier) { // server build hook = function (context) { // 2.3 injection context = context || // cached call (this.$vnode && this.$vnode.ssrContext) || // stateful (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional // 2.2 with runInNewContext: true if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') { context = __VUE_SSR_CONTEXT__; } // inject component styles if (style) { style.call(this, createInjectorSSR(context)); } // register component module identifier for async chunk inference if (context && context._registeredComponents) { context._registeredComponents.add(moduleIdentifier); } }; // used by ssr in case component is cached and beforeCreate // never gets called options._ssrRegister = hook; } else if (style) { hook = shadowMode ? function (context) { style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot)); } : function (context) { style.call(this, createInjector(context)); }; } if (hook) { if (options.functional) { // register for functional component in vue file const originalRender = options.render; options.render = function renderWithStyleInjection(h, context) { hook.call(context); return originalRender(h, context); }; } else { // inject component registration as beforeCreate hook const existing = options.beforeCreate; options.beforeCreate = existing ? [].concat(existing, hook) : [hook]; } } return script; } /* script */ const __vue_script__$9 = script$9; /* template */ /* style */ const __vue_inject_styles__$9 = undefined; /* scoped */ const __vue_scope_id__$9 = undefined; /* module identifier */ const __vue_module_identifier__$9 = undefined; /* functional template */ const __vue_is_functional_template__$9 = undefined; /* style inject */ /* style inject SSR */ /* style inject shadow dom */ const __vue_component__$9 = /*#__PURE__*/normalizeComponent( {}, __vue_inject_styles__$9, __vue_script__$9, __vue_scope_id__$9, __vue_is_functional_template__$9, __vue_module_identifier__$9, false, undefined, undefined, undefined ); // var script$8 = { name: 'DateInput', mixins: [__vue_component__$9], props: { isOpen: { type: Boolean, default: false }, selectedDate: { type: Date, default: null }, translation: { type: Object, default() { return {}; } } }, data() { return { input: null, isFocusedUsed: false, isBlurred: false, typedDate: '', utils: makeDateUtils(this.useUtc) }; }, computed: { computedInputClass() { if (this.bootstrapStyling) { if (typeof this.inputClass === 'string') { return [this.inputClass, 'form-control'].join(' '); } return { 'form-control': true, ...this.inputClass }; } return this.inputClass; }, formattedDate() { return typeof this.format === 'function' ? this.format(new Date(this.selectedDate)) : this.utils.formatDate(new Date(this.selectedDate), this.format, this.translation); }, formattedValue() { if (!this.selectedDate) { return null; } if (this.typedDate.length) { return this.typedDate; } return this.formattedDate; } }, mounted() { this.input = this.$el.querySelector('input'); }, methods: { /** * Emits a `clear-date` event */ clearDate() { this.$emit('clear-date'); }, /** * Submit typedDate and emit a `blur` event */ handleInputBlur() { this.isBlurred = this.isOpen; if (this.typeable) { this.submitTypedDate(); } this.$emit('blur'); this.$emit('close'); this.isFocusedUsed = false; }, /** * Toggles the calendar (unless `show-calendar-on-button-click` is true) */ handleInputClick() { const isFocusedUsed = this.showCalendarOnFocus && !this.isFocusedUsed; if (!this.showCalendarOnButtonClick && !isFocusedUsed) { this.toggle(); } if (this.showCalendarOnFocus) { this.isFocusedUsed = true; } }, /** * Opens the calendar when `show-calendar-on-focus` is true */ handleInputFocus() { if (this.showCalendarOnFocus) { this.$emit('open'); } this.isBlurred = false; this.$emit('focus'); }, /** * Submits a typed date */ handleKeydownEnter() { if (this.typeable) { this.submitTypedDate(); } this.$emit('close'); }, /** * Parses a date from a string * @param {String} value */ parseDate(value) { return this.utils.parseDate(value, this.format, this.translation, this.parser); }, /** * Attempt to parse a typed date */ parseTypedDate() { if (this.typeable) { const parsableDate = this.parseDate(this.input.value); const parsedDate = Date.parse(parsableDate); if (!Number.isNaN(parsedDate)) { this.typedDate = this.input.value; this.$emit('typed-date', new Date(parsedDate)); } } }, /** * Submits a typed date if it's valid */ submitTypedDate() { const parsableDate = this.parseDate(this.input.value); const parsedDate = Date.parse(parsableDate); if (Number.isNaN(parsedDate)) { this.clearDate(); } else { this.input.value = this.formattedDate; this.typedDate = ''; this.$emit('typed-date', parsedDate); } }, /** * Opens or closes the calendar */ toggle() { if (!this.isOpen && this.isBlurred) { this.isBlurred = false; return; } this.$emit(this.isOpen ? 'close' : 'open'); } } }; /* script */ const __vue_script__$8 = script$8; /* template */ var __vue_render__$6 = function() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c( "div", { class: { "input-group": _vm.bootstrapStyling } }, [ _vm._t("beforeDateInput"), _vm._v(" "), _vm.calendarButton ? _c( "span", { staticClass: "vdp-datepicker__calendar-button", class: { "input-group-prepend": _vm.bootstrapStyling, "calendar-btn-disabled": _vm.disabled }, on: { click: _vm.toggle } }, [ _c( "span", { class: { "input-group-text": _vm.bootstrapStyling } }, [ _vm._t("calendarBtn", [ _c("i", { class: _vm.calendarButtonIcon }, [ _vm._v( "\n " + _vm._s(_vm.calendarButtonIconContent) + "\n " ), !_vm.calendarButtonIcon ? _c("span", [_vm._v("…")]) : _vm._e() ]) ]) ], 2 ) ] ) : _vm._e(), _vm._v(" "), _c("input", { ref: _vm.refName, class: _vm.computedInputClass, attrs: { id: _vm.id, autocomplete: "off", autofocus: _vm.autofocus, "clear-button": _vm.clearButton, disabled: _vm.disabled, maxlength: _vm.maxlength, name: _vm.name, pattern: _vm.pattern, placeholder: _vm.placeholder, readonly: !_vm.typeable, required: _vm.required, tabindex: _vm.tabindex, type: _vm.inline ? "hidden" : null }, domProps: { value: _vm.formattedValue }, on: { blur: _vm.handleInputBlur, click: _vm.handleInputClick, focus: _vm.handleInputFocus, keydown: [ function($event) { if ( !$event.type.indexOf("key") && _vm._k($event.keyCode, "enter", 13, $event.key, "Enter") ) { return null } $event.preventDefault(); return _vm.handleKeydownEnter($event) }, function($event) { if ( !$event.type.indexOf("key") && _vm._k( $event.keyCode, "escape", undefined, $event.key, undefined ) ) { return null } $event.preventDefault(); return _vm.$emit("close") } ], keyup: _vm.parseTypedDate } }), _vm._v(" "), _vm.clearButton && _vm.selectedDate ? _c( "span", { staticClass: "vdp-datepicker__clear-button", class: { "input-group-append": _vm.bootstrapStyling }, on: { click: function($event) { return _vm.clearDate() } } }, [ _c( "span", { class: { "input-group-text": _vm.bootstrapStyling } }, [ _vm._t("clearBtn", [ _c("i", { class: _vm.clearButtonIcon }, [ !_vm.clearButtonIcon ? _c("span", [_vm._v("×")]) : _vm._e() ]) ]) ], 2 ) ] ) : _vm._e(), _vm._v(" "), _vm._t("afterDateInput") ], 2 ) }; var __vue_staticRenderFns__$6 = []; __vue_render__$6._withStripped = true; /* style */ const __vue_inject_styles__$8 = undefined; /* scoped */ const __vue_scope_id__$8 = undefined; /* module identifier */ const __vue_module_identifier__$8 = undefined; /* functional template */ const __vue_is_functional_template__$8 = false; /* style inject */ /* style inject SSR */ /* style inject shadow dom */ const __vue_component__$8 = /*#__PURE__*/normalizeComponent( { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 }, __vue_inject_styles__$8, __vue_script__$8, __vue_scope_id__$8, __vue_is_functional_template__$8, __vue_module_identifier__$8, false, undefined, undefined, undefined ); const cellUtils = { configExists(obj) { return typeof obj !== 'undefined' && Object.keys(obj).length > 0; }, isDefined(obj, prop) { return this.configExists(obj) && typeof obj[prop] !== 'undefined'; }, hasArray(obj, prop) { return this.isDefined(obj, prop) && obj[prop].length > 0; }, hasDate(obj, prop) { return this.isDefined(obj, prop) && this.utils.isValidDate(obj[prop]); }, dayMonthYear(obj, prop) { const { utils } = this; const hasDate = this.hasDate(obj, prop); if (!hasDate) { return { day: undefined, month: undefined, year: undefined }; } const d = obj[prop]; return { day: utils.getDate(d), month: utils.getMonth(d), year: utils.getFullYear(d) }; } }; var makeCellUtils = (utils => ({ ...cellUtils, utils })); /* eslint-disable no-underscore-dangle */ class DisabledDate { constructor(utils, disabledDates) { this._utils = utils; this._disabledDates = disabledDates; } get config() { const disabledDates = this._disabledDates; const utils = makeCellUtils(this._utils); return { exists: utils.configExists(disabledDates), to: utils.dayMonthYear(disabledDates, 'to'), from: utils.dayMonthYear(disabledDates, 'from'), has: { customPredictor: utils.isDefined(disabledDates, 'customPredictor'), daysOfMonth: utils.hasArray(disabledDates, 'daysOfMonth'), daysOfWeek: utils.hasArray(disabledDates, 'days'), from: utils.hasDate(disabledDates, 'from'), ranges: utils.hasArray(disabledDates, 'ranges'), specificDates: utils.hasArray(disabledDates, 'dates'), to: utils.hasDate(disabledDates, 'to') } }; } daysInMonth(date) { const utils = this._utils; const month = utils.getMonth(date); const year = utils.getFullYear(date); return utils.daysInMonth(year, month); } isDateDisabledVia(date) { const disabledDates = this._disabledDates; const { has } = this.config; return { to: () => { return has.to && date < disabledDates.to; }, from: () => { return has.from && date > disabledDates.from; }, range: () => { if (!has.ranges) return false; const { ranges } = disabledDates; const u = makeCellUtils(this._utils); return ranges.some(thisRange => { const hasFrom = u.isDefined(thisRange, 'from'); const hasTo = u.isDefined(thisRange, 'to'); return hasFrom && hasTo && date < thisRange.to && date > thisRange.from; }); }, customPredictor: () => { return has.customPredictor && disabledDates.customPredictor(date); }, specificDate: () => { if (!has.specificDates) return false; return disabledDates.dates.some(d => { return this._utils.compareDates(date, d); }); }, daysOfWeek: () => { if (!has.daysOfWeek) return false; return disabledDates.days.indexOf(this._utils.getDay(date)) !== -1; }, daysOfMonth: () => { if (!has.daysOfMonth) return false; return disabledDates.daysOfMonth.indexOf(this._utils.getDate(date)) !== -1; } }; } isMonthDisabledVia(date) { const { from, has, to } = this.config; const month = this._utils.getMonth(date); const year = this._utils.getFullYear(date); return { to: () => { const isYearInPast = has.to && year < to.year; if (isYearInPast) { return true; } return has.to && month < to.month && year <= to.year; }, from: () => { const isYearInFuture = has.from && year > from.year; if (isYearInFuture) { return true; } return has.from && month > from.month && year >= from.year; } }; } isYearDisabledVia(date) { const { from, has, to } = this.config; const year = this._utils.getFullYear(date); return { to: () => { return has.to && year < to.year; }, from: () => { return has.from && year > from.year; } }; } /** * Checks if the given date should be disabled * @param {Date} date * @return {Boolean} */ // eslint-disable-next-line complexity,max-statements isDateDisabled(date) { if (!this.config.exists) return false; const isDisabledVia = this.isDateDisabledVia(date); return isDisabledVia.to() || isDisabledVia.from() || isDisabledVia.range() || isDisabledVia.specificDate() || isDisabledVia.daysOfWeek() || isDisabledVia.daysOfMonth() || isDisabledVia.customPredictor(); } /** * Checks if the given month should be disabled * @param {Date} date * @return {Boolean} */ // eslint-disable-next-line complexity,max-statements isMonthDisabled(date) { const { config } = this; const isDisabledVia = this.isMonthDisabledVia(date); if (!config.exists) { return false; } if (isDisabledVia.to() || isDisabledVia.from()) { return true; } // now we have to check each day of the month for (let i = 1; i <= this.daysInMonth(date); i += 1) { const dayDate = new Date(date); dayDate.setDate(i); // if at least one day of this month is NOT disabled, // we can conclude that this month SHOULD be selectable if (!this.isDateDisabled(dayDate)) { return false; } } return true; } /** * Checks if the given year should be disabled * @param {Date} date * @return {Boolean} */ // eslint-disable-next-line complexity,max-statements isYearDisabled(date) { const { config } = this; const isDisabledVia = this.isYearDisabledVia(date); if (!config.exists) { return false; } if (isDisabledVia.to() || isDisabledVia.from()) { return true; } // now we have to check each month of the year for (let i = 0; i < 12; i += 1) { const monthDate = new Date(date); monthDate.setMonth(i); // if at least one month of this year is NOT disabled, // we can conclude that this year SHOULD be selectable if (!this.isMonthDisabled(monthDate)) { return false; } } return true; } } // // // // // // // // // // // // // // // // // // // // // // // // var script$7 = { name: 'PickerHeader', props: { isNextDisabled: { type: Boolean, required: true }, isPreviousDisabled: { type: Boolean, required: true }, isRtl: { type: Boolean, required: true } } }; /* script */ const __vue_script__$7 = script$7; /* template */ var __vue_render__$5 = function() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c( "header", [ _c( "span", { staticClass: "prev", class: { disabled: _vm.isPreviousDisabled, rtl: _vm.isRtl }, on: { click: function($event) { _vm.isPreviousDisabled ? null : _vm.$emit("page-change", -1); } } }, [ _vm._t("prevIntervalBtn", [ _c("span", { staticClass: "default" }, [_vm._v("<")]) ]) ], 2 ), _vm._v(" "), _vm._t("default"), _vm._v(" "), _c( "span", { staticClass: "next", class: { disabled: _vm.isNextDisabled, rtl: _vm.isRtl }, on: { click: function($event) { _vm.isNextDisabled ? null : _vm.$emit("page-change", 1); } } }, [ _vm._t("nextIntervalBtn", [ _c("span", { staticClass: "default" }, [_vm._v(">")]) ]) ], 2 ) ], 2 ) }; var __vue_staticRenderFns__$5 = []; __vue_render__$5._withStripped = true; /* style */ const __vue_inject_styles__$7 = undefined; /* scoped */ const __vue_scope_id__$7 = undefined; /* module identifier */ const __vue_module_identifier__$7 = undefined; /* functional template */ const __vue_is_functional_template__$7 = false; /* style inject */ /* style inject SSR */ /* style inject shadow dom */ const __vue_component__$7 = /*#__PURE__*/normalizeComponent( { render: __vue_render__$5, staticRenderFns: __vue_staticRenderFns__$5 }, __vue_inject_styles__$7, __vue_script__$7, __vue_scope_id__$7, __vue_is_functional_template__$7, __vue_module_identifier__$7, false, undefined, undefined, undefined ); var script$6 = { components: { PickerHeader: __vue_component__$7 }, inheritAttrs: false, props: { disabledDates: { type: Object, default() { return {}; } }, isRtl: { type: Boolean, default: false }, isUpDisabled: { type: Boolean, default: false }, pageDate: { type: Date, default: null }, selectedDate: { type: Date, default: null }, showHeader: { type: Boolean, default: true }, transitionName: { type: String, default: '' }, translation: { type: Object, default() { return {}; } }, useUtc: { type: Boolean, default: false }, view: { type: String, default: 'day' } }, data() { return { utils: makeDateUtils(this.useUtc) }; }, computed: { /** * A look-up object created from 'disabledDates' prop * @return {Object} */ disabledConfig() { return new DisabledDate(this.utils, this.disabledDates).config; }, /** * Returns the current page's full year as an integer. * @return {Number} */ pageYear() { return this.utils.getFullYear(this.pageDate); } }, methods: { /** * Changes the page up or down * @param {Number} incrementBy */ changePage(incrementBy) { const { pageDate, utils } = this; const units = this.view === 'year' ? incrementBy * this.yearRange : incrementBy; this.$emit('set-transition-name', incrementBy); if (this.view === 'day') { utils.setMonth(pageDate, utils.getMonth(pageDate) + units); } else { utils.setFullYear(pageDate, utils.getFullYear(pageDate) + units); } this.$emit('page-change', pageDate); }, /** * Determines which transition to use (for edge dates) and emits a 'select' or 'select-disabled' event * @param {Object} cell */ select(cell) { if (cell.isDisabled) { this.$emit('select-disabled', cell); return; } if (cell.isPreviousMonth) { this.$emit('set-transition-name', -1); } if (cell.isNextMonth) { this.$emit('set-transition-name', 1); } this.$emit('select', cell); } } }; /* script */ const __vue_script__$6 = script$6; /* template */ /* style */ const __vue_inject_styles__$6 = undefined; /* scoped */ const __vue_scope_id__$6 = undefined; /* module identifier */ const __vue_module_identifier__$6 = undefined; /* functional template */ const __vue_is_functional_template__$6 = undefined; /* style inject */ /* style inject SSR */ /* style inject shadow dom */ const __vue_component__$6 = /*#__PURE__*/normalizeComponent( {}, __vue_inject_styles__$6, __vue_script__$6, __vue_scope_id__$6, __vue_is_functional_template__$6, __vue_module_identifier__$6, false, undefined, undefined, undefined ); /* eslint-disable no-underscore-dangle */ class HighlightedDate { constructor(utils, disabledDates, highlighted) { this._utils = utils; this._disabledDates = disabledDates; this._highlighted = highlighted; } get config() { const highlightedDates = this._highlighted; const utils = makeCellUtils(this._utils); return { exists: utils.configExists(highlightedDates), to: utils.dayMonthYear(highlightedDates, 'to'), from: utils.dayMonthYear(highlightedDates, 'from'), has: { customPredictor: utils.isDefined(highlightedDates, 'customPredictor'), daysOfMonth: utils.hasArray(highlightedDates, 'daysOfMonth'), daysOfWeek: utils.hasArray(highlightedDates, 'days'), from: utils.hasDate(highlightedDates, 'from'), specificDates: utils.hasArray(highlightedDates, 'dates'), to: utils.hasDate(highlightedDates, 'to'), includeDisabled: utils.isDefined(highlightedDates, 'includeDisabled') && highlightedDates.includeDisabled } }; } isDateDisabled(date) { const utils = this._utils; const disabledDates = this._disabledDates; return new DisabledDate(utils, disabledDates).isDateDisabled(date); } isHighlightingNotPossible(date) { const { config } = this; if (!config.exists) return false; return !config.has.includeDisabled && this.isDateDisabled(date); } isDateHighlightedVia(date) { const highlightedDates = this._highlighted; const { has } = this.config; return { to: () => { return has.to && date <= highlightedDates.to; }, from: () => { return has.from && date >= highlightedDates.from; }, customPredictor: () => { return has.customPredictor && highlightedDates.customPredictor(date); }, specificDate: () => { if (!has.specificDates) return false; return highlightedDates.dates.some(d => { return this._utils.compareDates(date, d); }); }, daysOfWeek: () => { if (!has.daysOfWeek) return false; return highlightedDates.days.indexOf(this._utils.getDay(date)) !== -1; }, daysOfMonth: () => { if (!has.daysOfMonth) return false; return highlightedDates.daysOfMonth.indexOf(this._utils.getDate(date)) !== -1; } }; } // eslint-disable-next-line complexity,max-statements isDateHighlighted(date) { if (this.isHighlightingNotPossible(date)) return false; const isHighlightedVia = this.isDateHighlightedVia(date); return isHighlightedVia.to() && isHighlightedVia.from() || isHighlightedVia.specificDate() || isHighlightedVia.daysOfWeek() || isHighlightedVia.daysOfMonth() || isHighlightedVia.customPredictor(); } } // // // // // // // // // // // // // var script$5 = { name: 'PickerCells', props: { cells: { type: Array, required: true }, showEdgeDates: { type: Boolean, default: true }, view: { type: String, validator: val => ['day', 'month', 'year'].includes(val), required: true } }, methods: { /** * Set the classes for a specific cell * @return {Array} */ // eslint-disable-next-line complexity cellClasses(cell) { return ['cell', this.view, { 'disabled': cell.isDisabled, 'highlight-start': cell.isHighlightStart, 'highlight-end': cell.isHighlightEnd, 'highlighted': cell.isHighlighted, 'muted': cell.isPreviousMonth || cell.isNextMonth, 'sat': cell.isSaturday, 'sun': cell.isSunday, 'selected': this.showEdgeDates ? cell.isSelected : cell.isSelected && !cell.isPreviousMonth && !cell.isNextMonth, 'today': this.showEdgeDates ? cell.isToday : cell.isToday && !cell.isPreviousMonth && !cell.isNextMonth, 'weekend': cell.isWeekend }]; } } }; /* script */ const __vue_script__$5 = script$5; /* template */ var __vue_render__$4 = function() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _h; return _c( "div", { staticClass: "picker-cells" }, _vm._l(_vm.cells, function(cell) { return _c( "span", { key: cell.timestamp, class: _vm.cellClasses(cell), on: { click: function($event) { return _vm.$emit("select", cell) } } }, [_vm._t("default", null, { cell: cell })], 2 ) }), 0 ) }; var __vue_staticRenderFns__$4 = []; __vue_render__$4._withStripped = true; /* style */ const __vue_inject_styles__$5 = undefined; /* scoped */ const __vue_scope_id__$5 = undefined; /* module identifier */ const __vue_module_identifier__$5 = undefined; /* functional template */ const __vue_is_functional_template__$5 = false; /* style inject */ /* style inject SSR */ /* style inject shadow dom */ const __vue_component__$5 = /*#__PURE__*/normalizeComponent( { render: __vue_render__$4, staticRenderFns: __vue_staticRenderFns__$4 }, __vue_inject_styles__$5, __vue_script__$5, __vue_scope_id__$5, __vue_is_functional_template__$5, __vue_module_identifier__$5, false, undefined, undefined, undefined ); // var script$4 = { name: 'PickerDay', components: { PickerCells: __vue_component__$5 }, mixins: [__vue_component__$6], props: { dayCellContent: { type: Function, default: day => day.date }, firstDayOfWeek: { type: String, default: 'sun' }, highlighted: { type: Object, default() { return {}; } }, showFullMonthName: { type: Boolean, default: false }, showEdgeDates: { type: Boolean, default: true } }, computed: { /** * Sets an array with all days to show this month * @return {Array} */ cells() { const days = []; const daysInCalendar = this.daysFromPrevMonth + this.daysInMonth + this.daysFromNextMonth; const dObj = this.firstCellDate(); for (let i = 0; i < daysInCalendar; i += 1) { days.push(this.makeDay(i, dObj)); this.utils.setDate(dObj, this.utils.getDate(dObj) + 1); } return days; }, /** * Gets the name of the month the current page is on * @return {String} */ currMonthName() { const monthName = this.showFullMonthName ? this.translation.months : this.translation.monthsAbbr; return this.utils.getMonthNameAbbr(this.pageMonth, monthName); }, /** * Gets the name of the year that current page is on * @return {String} */ currYearName() { const { yearSuffix } = this.translation; return `${this.pageYear}${yearSuffix}`; }, /** * Returns an array of day names * @return {String[]} */ daysOfWeek() { return this.translation.getDaysStartingOn(this.firstDayOfWeekNumber); }, /** * Returns the number of days in this month * @return {String[]} */ daysInMonth() { return this.utils.getDaysInMonth(this.pageDate); }, /** * Calculates how many days to show from the previous month * @return {number} */ daysFromPrevMonth() { const firstOfMonthDayNumber = this.utils.getDay(this.pageDate); return (7 - this.firstDayOfWeekNumber + firstOfMonthDayNumber) % 7; }, /** * Calculates how many days to show from the next month * @return {number} */ daysFromNextMonth() { const daysThisAndPrevMonth = this.daysFromPrevMonth + this.daysInMonth; return Math.ceil(daysThisAndPrevMonth / 7) * 7 - daysThisAndPrevMonth; }, /** * Returns first-day-of-week as a number (Sunday is 0) * @return {Number} */ firstDayOfWeekNumber() { return this.utils.getDayFromAbbr(this.firstDayOfWeek); }, /** * The first day of the next page's month. * @return {Date} */ firstOfNextMonth() { const d = new Date(this.pageDate); return new Date(this.utils.setMonth(d, this.utils.getMonth(d) + 1)); }, /** * A look-up object created from 'highlighted' prop * @return {Object} */ highlightedConfig() { return new HighlightedDate(this.utils, this.disabledDates, this.highlighted).config; }, /** * Is the next month disabled? * @return {Boolean} */ isNextDisabled() { if (!this.disabledConfig.has.from) { return false; } return this.disabledConfig.from.month <= this.pageMonth && this.disabledConfig.from.year <= this.pageYear; }, /** * Is the previous month disabled? * @return {Boolean} */ isPreviousDisabled() { if (!this.disabledConfig.has.to) { return false; } return this.disabledConfig.to.month >= this.pageMonth && this.disabledConfig.to.year >= this.pageYear; }, /** * Returns the current page's month as an integer. * @return {Number} */ pageMonth() { return this.utils.getMonth(this.pageDate); }, /** * Display the current page's month & year as the title. * @return {String} */ pageTitleDay() { return this.translation.ymd ? `${this.currYearName} ${this.currMonthName}` : `${this.currMonthName} ${this.currYearName}`; } }, methods: { /** * Set up a new date object to the first day of the current 'page' * @return Date */ firstCellDate() { const d = this.pageDate; const firstOfMonth = this.useUtc ? new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1)) : new Date(d.getFullYear(), d.getMonth(), 1, d.getHours(), d.getMinutes()); return new Date(firstOfMonth.setDate(firstOfMonth.getDate() - this.daysFromPrevMonth)); }, /** * Whether a day is disabled * @param {Date} date to check if disabled * @return {Boolean} */ isDisabledDate(date) { return new DisabledDate(this.utils, this.disabledDates).isDateDisabled(date); }, /** * Whether a day is highlighted * (only if it is not disabled already except when highlighted.includeDisabled is true) * @param {Date} date to check if highlighted * @return {Boolean} */ isHighlightedDate(date) { const dateWithoutTime = this.utils.resetDateTime(date); return new HighlightedDate(this.utils, this.disabledDates, this.highlighted).isDateHighlighted(dateWithoutTime); }, /** * Whether a day is highlighted and it is the last date * in the highlighted range of dates * @param {Date} date end highlight * @return {Boolean} */ isHighlightEnd(date) { const config = this.highlightedConfig; return this.isHighlightedDate(date) && config.to.year === this.utils.getFullYear(date) && config.to.month === this.utils.getMonth(date) && config.to.day === this.utils.getDate(date); }, /** * Whether a day is highlighted and it is the first date * in the highlighted range of dates * @param {Date} date start highlight * @return {Boolean} */ isHighlightStart(date) { const config = this.highlightedConfig; return this.isHighlightedDate(date) && config.from.year === this.utils.getFullYear(date) && config.from.month === this.utils.getMonth(date) && config.from.day === this.utils.getDate(date); }, /** * Whether a day is selected * @param {Date} dObj to check if selected * @return {Boolean} */ isSelectedDate(dObj) { return this.selectedDate && this.utils.compareDates(this.selectedDate, dObj); }, /** * Defines the objects within the days array * @param {id} id * @param {Date} dObj * @return {Object} */ // eslint-disable-next-line complexity makeDay(id, dObj) { const isNextMonth = dObj >= this.firstOfNextMonth; const isPreviousMonth = dObj < this.pageDate; const isSaturday = this.utils.getDay(dObj) === 6; const isSunday = this.utils.getDay(dObj) === 0; const showDate = this.showEdgeDates || !(isPreviousMonth || isNextMonth); return { date: showDate ? this.utils.getDate(dObj) : '', timestamp: dObj.valueOf(), isSelected: this.isSelectedDate(dObj), isDisabled: showDate ? this.isDisabledDate(dObj) : true, isHighlighted: this.isHighlightedDate(dObj), isHighlightStart: this.isHighlightStart(dObj), isHighlightEnd: this.isHighlightEnd(dObj), isToday: this.utils.compareDates(dObj, new Date()), isWeekend: isSaturday || isSunday, isSaturday, isSunday, isPreviousMonth, isNextMonth }; } } }; /* script */ const __vue_script__$4 = script$4; /* template */ var __vue_render__$3 = function() { var _vm = this; var _h = _vm.$createElement; var _c = _vm._self._c || _