UNPKG

@logscl/ng2-date-picker

Version:

https://github.com/vlio20/angular-datepicker

964 lines (953 loc) 150 kB
import * as i0 from '@angular/core'; import { ElementRef, Injectable, EventEmitter, Output, HostBinding, Input, ChangeDetectionStrategy, ViewEncapsulation, Component, forwardRef, ViewChild, HostListener, Optional, Directive, NgModule } from '@angular/core'; import * as i4 from '@angular/forms'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS, FormsModule } from '@angular/forms'; import * as i3 from '@angular/common'; import { CommonModule } from '@angular/common'; import * as i5 from '@angular/cdk/overlay'; import { OverlayModule } from '@angular/cdk/overlay'; import dayjs from 'dayjs'; import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'; import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'; import isBetween from 'dayjs/plugin/isBetween'; import isoWeek from 'dayjs/plugin/isoWeek'; import customParseFormat from 'dayjs/plugin/customParseFormat'; var ECalendarMode; (function (ECalendarMode) { ECalendarMode[ECalendarMode["Day"] = 0] = "Day"; ECalendarMode[ECalendarMode["DayTime"] = 1] = "DayTime"; ECalendarMode[ECalendarMode["Month"] = 2] = "Month"; ECalendarMode[ECalendarMode["Time"] = 3] = "Time"; })(ECalendarMode || (ECalendarMode = {})); var ECalendarValue; (function (ECalendarValue) { ECalendarValue[ECalendarValue["Dayjs"] = 1] = "Dayjs"; ECalendarValue[ECalendarValue["DayjsArr"] = 2] = "DayjsArr"; ECalendarValue[ECalendarValue["String"] = 3] = "String"; ECalendarValue[ECalendarValue["StringArr"] = 4] = "StringArr"; })(ECalendarValue || (ECalendarValue = {})); var SelectEvent; (function (SelectEvent) { SelectEvent["INPUT"] = "input"; SelectEvent["SELECTION"] = "selection"; })(SelectEvent || (SelectEvent = {})); dayjs.extend(isSameOrAfter); dayjs.extend(isSameOrBefore); dayjs.extend(isBetween); dayjs.extend(isoWeek); dayjs.extend(customParseFormat); const dayjsRef = dayjs; class UtilsService { static debounce(func, wait) { let timeout; return function () { const context = this, args = arguments; timeout = clearTimeout(timeout); setTimeout(() => { func.apply(context, args); }, wait); }; } ; createArray(size) { return new Array(size).fill(1); } convertToDayjs(date, format) { if (!date) { return null; } else if (typeof date === 'string') { return dayjsRef(date, format); } else { return dayjsRef(date.toDate()); } } isDateValid(date, format) { if (date === '') { return true; } return dayjsRef(date, format, true).isValid(); } // todo:: add unit test getDefaultDisplayDate(current, selected, allowMultiSelect, minDate) { if (current) { return dayjsRef(current.toDate()); } else if (minDate && minDate.isAfter(dayjsRef())) { return dayjsRef(minDate.toDate()); } else if (allowMultiSelect) { if (selected && selected[selected.length]) { return dayjsRef(selected[selected.length].toDate()); } } else if (selected && selected[0]) { return dayjsRef(selected[0].toDate()); } return dayjsRef(); } // todo:: add unit test getInputType(value, allowMultiSelect) { if (Array.isArray(value)) { if (!value.length) { return ECalendarValue.DayjsArr; } else if (typeof value[0] === 'string') { return ECalendarValue.StringArr; } else if (dayjsRef.isDayjs(value[0])) { return ECalendarValue.DayjsArr; } } else { if (typeof value === 'string') { return ECalendarValue.String; } else if (dayjsRef.isDayjs(value)) { return ECalendarValue.Dayjs; } } return allowMultiSelect ? ECalendarValue.DayjsArr : ECalendarValue.Dayjs; } // todo:: add unit test convertToDayjsArray(value, config) { let retVal; switch (this.getInputType(value, config.allowMultiSelect)) { case (ECalendarValue.String): retVal = value ? [dayjsRef(value, config.format, true)] : []; break; case (ECalendarValue.StringArr): retVal = value.map(v => v ? dayjsRef(v, config.format, true) : null).filter(Boolean); break; case (ECalendarValue.Dayjs): retVal = value ? [dayjsRef(value.toDate())] : []; break; case (ECalendarValue.DayjsArr): retVal = (value || []).map(v => dayjsRef(v.toDate())); break; default: retVal = []; } return retVal; } // todo:: add unit test convertFromDayjsArray(format, value, convertTo) { switch (convertTo) { case (ECalendarValue.String): return value[0] && value[0].format(format); case (ECalendarValue.StringArr): return value.filter(Boolean).map(v => v.format(format)); case (ECalendarValue.Dayjs): return value[0] ? dayjsRef(value[0].toDate()) : value[0]; case (ECalendarValue.DayjsArr): return value ? value.map(v => dayjsRef(v.toDate())) : value; default: return value; } } convertToString(value, format) { let tmpVal; if (typeof value === 'string') { tmpVal = [value]; } else if (Array.isArray(value)) { if (value.length) { tmpVal = value.map((v) => { return this.convertToDayjs(v, format).format(format); }); } else { tmpVal = value; } } else if (dayjsRef.isDayjs(value)) { tmpVal = [value.format(format)]; } else { return ''; } return tmpVal.filter(Boolean).join(' | '); } // todo:: add unit test clearUndefined(obj) { if (!obj) { return obj; } Object.keys(obj).forEach((key) => (obj[key] === undefined) && delete obj[key]); return obj; } updateSelected(isMultiple, currentlySelected, date, granularity = 'day') { if (isMultiple) { return !date.selected ? currentlySelected.concat([date.date]) : currentlySelected.filter(d => !d.isSame(date.date, granularity)); } else { return !date.selected ? [date.date] : []; } } closestParent(element, selector) { if (!element) { return undefined; } const match = element.querySelector(selector); return match || this.closestParent(element.parentElement, selector); } onlyTime(m) { return m && dayjsRef.isDayjs(m) && dayjsRef(m.format('HH:mm:ss'), 'HH:mm:ss'); } granularityFromType(calendarType) { switch (calendarType) { case 'time': return 'second'; case 'daytime': return 'second'; default: return calendarType; } } createValidator({ minDate, maxDate, minTime, maxTime }, format, calendarType) { let isValid; let value; const validators = []; const granularity = this.granularityFromType(calendarType); if (minDate) { const md = this.convertToDayjs(minDate, format); validators.push({ key: 'minDate', isValid: () => { const _isValid = value.every(val => val.isSameOrAfter(md, granularity)); isValid = isValid ? _isValid : false; return _isValid; } }); } if (maxDate) { const md = this.convertToDayjs(maxDate, format); validators.push({ key: 'maxDate', isValid: () => { const _isValid = value.every(val => val.isSameOrBefore(md, granularity)); isValid = isValid ? _isValid : false; return _isValid; } }); } if (minTime) { const md = this.onlyTime(this.convertToDayjs(minTime, format)); validators.push({ key: 'minTime', isValid: () => { const _isValid = value.every(val => this.onlyTime(val).isSameOrAfter(md)); isValid = isValid ? _isValid : false; return _isValid; } }); } if (maxTime) { const md = this.onlyTime(this.convertToDayjs(maxTime, format)); validators.push({ key: 'maxTime', isValid: () => { const _isValid = value.every(val => this.onlyTime(val).isSameOrBefore(md)); isValid = isValid ? _isValid : false; return _isValid; } }); } return (inputVal) => { isValid = true; value = this.convertToDayjsArray(inputVal, { format, allowMultiSelect: true }).filter(Boolean); if (!value.every(val => val.isValid())) { return { format: { given: inputVal } }; } const errors = validators.reduce((map, err) => { if (!err.isValid()) { map[err.key] = { given: value }; } return map; }, {}); return !isValid ? errors : null; }; } datesStringToStringArray(value) { return (value || '').split('|').map(m => m.trim()).filter(Boolean); } getValidDayjsArray(value, format) { return this.datesStringToStringArray(value) .filter(d => this.isDateValid(d, format)) .map(d => dayjsRef(d, format)); } shouldShowCurrent(showGoToCurrent, mode, min, max) { return showGoToCurrent && mode !== 'time' && this.isDateInRange(dayjsRef(), min, max); } isDateInRange(date, from, to) { if (!date) { return false; } if (!from && !to) { return true; } if (!from && to) { return date.isSameOrBefore(to); } if (from && !to) { return date.isSameOrAfter(from); } return date.isBetween(from, to, 'day', '[]'); } convertPropsToDayjs(obj, format, props) { props.forEach((prop) => { if (obj.hasOwnProperty(prop)) { obj[prop] = this.convertToDayjs(obj[prop], format); } }); } shouldResetCurrentView(prevConf, currentConf) { if (prevConf && currentConf) { if (!prevConf.min && currentConf.min) { return true; } else if (prevConf.min && currentConf.min && !prevConf.min.isSame(currentConf.min, 'd')) { return true; } else if (!prevConf.max && currentConf.max) { return true; } else if (prevConf.max && currentConf.max && !prevConf.max.isSame(currentConf.max, 'd')) { return true; } return false; } return false; } getNativeElement(elem) { if (!elem) { return null; } else if (typeof elem === 'string') { return document.querySelector(elem); } else if (elem instanceof ElementRef) { return elem.nativeElement; } else { return elem; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: UtilsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: UtilsService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: UtilsService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class DayCalendarService { constructor(utilsService) { this.utilsService = utilsService; this.DEFAULT_CONFIG = { showNearMonthDays: true, showWeekNumbers: false, firstDayOfWeek: 'su', weekDayFormat: 'ddd', format: 'DD-MM-YYYY', allowMultiSelect: false, monthFormat: 'MMM, YYYY', enableMonthSelector: true, dayBtnFormat: 'DD', unSelectOnClick: true }; this.DAYS = ['su', 'mo', 'tu', 'we', 'th', 'fr', 'sa']; } getConfig(config) { const _config = { ...this.DEFAULT_CONFIG, ...this.utilsService.clearUndefined(config) }; this.utilsService.convertPropsToDayjs(_config, _config.format, ['min', 'max']); return _config; } generateDaysMap(firstDayOfWeek) { const firstDayIndex = this.DAYS.indexOf(firstDayOfWeek); const daysArr = this.DAYS.slice(firstDayIndex, 7).concat(this.DAYS.slice(0, firstDayIndex)); return daysArr.reduce((map, day, index) => { map[day] = index; return map; }, {}); } generateMonthArray(config, month, selected) { const parsedMonth = month.isValid() ? dayjsRef(month.toDate()) : dayjsRef(); let monthArray = []; const firstDayOfWeekIndex = this.DAYS.indexOf(config.firstDayOfWeek); let firstDayOfBoard = parsedMonth.startOf('month'); while (firstDayOfBoard.day() !== firstDayOfWeekIndex) { firstDayOfBoard = firstDayOfBoard.subtract(1, 'day'); } let current = dayjsRef(firstDayOfBoard.toDate()); const prevMonth = parsedMonth.subtract(1, 'month'); const nextMonth = parsedMonth.add(1, 'month'); const today = dayjsRef(); const daysOfCalendar = this.utilsService.createArray(42) .reduce((array) => { array.push({ date: dayjsRef(current.toDate()), selected: !!selected.find(selectedDay => current.isSame(selectedDay, 'day')), currentMonth: current.isSame(parsedMonth, 'month'), prevMonth: current.isSame(prevMonth, 'month'), nextMonth: current.isSame(nextMonth, 'month'), currentDay: current.isSame(today, 'day'), disabled: this.isDateDisabled(current, config) }); current = current.add(1, 'day'); return array; }, []); daysOfCalendar.forEach((day, index) => { const weekIndex = Math.floor(index / 7); if (!monthArray[weekIndex]) { monthArray.push([]); } monthArray[weekIndex].push(day); }); if (!config.showNearMonthDays) { monthArray = this.removeNearMonthWeeks(parsedMonth, monthArray); } return monthArray; } generateWeekdays(firstDayOfWeek) { const weekdayNames = { su: dayjsRef().day(0), mo: dayjsRef().day(1), tu: dayjsRef().day(2), we: dayjsRef().day(3), th: dayjsRef().day(4), fr: dayjsRef().day(5), sa: dayjsRef().day(6) }; const weekdays = []; const daysMap = this.generateDaysMap(firstDayOfWeek); for (const dayKey in daysMap) { if (daysMap.hasOwnProperty(dayKey)) { weekdays[daysMap[dayKey]] = weekdayNames[dayKey]; } } return weekdays; } isDateDisabled(date, config) { if (config.isDayDisabledCallback) { return config.isDayDisabledCallback(date); } if (config.min && date.isBefore(config.min, 'day')) { return true; } return !!(config.max && date.isAfter(config.max, 'day')); } // todo:: add unit tests getHeaderLabel(config, month) { if (config.monthFormatter) { return config.monthFormatter(month); } return month.format(config.monthFormat); } // todo:: add unit tests shouldShowLeft(min, currentMonthView) { return min ? min.isBefore(currentMonthView, 'month') : true; } // todo:: add unit tests shouldShowRight(max, currentMonthView) { return max ? max.isAfter(currentMonthView, 'month') : true; } generateDaysIndexMap(firstDayOfWeek) { const firstDayIndex = this.DAYS.indexOf(firstDayOfWeek); const daysArr = this.DAYS.slice(firstDayIndex, 7).concat(this.DAYS.slice(0, firstDayIndex)); return daysArr.reduce((map, day, index) => { map[index] = day; return map; }, {}); } getMonthCalendarConfig(componentConfig) { return this.utilsService.clearUndefined({ min: componentConfig.min, max: componentConfig.max, format: componentConfig.format, isNavHeaderBtnClickable: true, allowMultiSelect: false, yearFormat: componentConfig.yearFormat, yearFormatter: componentConfig.yearFormatter, monthBtnFormat: componentConfig.monthBtnFormat, monthBtnFormatter: componentConfig.monthBtnFormatter, monthBtnCssClassCallback: componentConfig.monthBtnCssClassCallback, isMonthDisabledCallback: componentConfig.isMonthDisabledCallback, multipleYearsNavigateBy: componentConfig.multipleYearsNavigateBy, showMultipleYearsNavigation: componentConfig.showMultipleYearsNavigation, showGoToCurrent: componentConfig.showGoToCurrent, numOfMonthRows: componentConfig.numOfMonthRows }); } getDayBtnText(config, day) { if (config.dayBtnFormatter) { return config.dayBtnFormatter(day); } return day.format(config.dayBtnFormat); } getDayBtnCssClass(config, day) { if (config.dayBtnCssClassCallback) { return config.dayBtnCssClassCallback(day); } return ''; } removeNearMonthWeeks(currentMonth, monthArray) { if (monthArray[monthArray.length - 1].find((day) => day.date.isSame(currentMonth, 'month'))) { return monthArray; } else { return monthArray.slice(0, -1); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DayCalendarService, deps: [{ token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DayCalendarService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DayCalendarService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: UtilsService }] }); const FIRST_PM_HOUR = 12; class TimeSelectService { constructor(utilsService) { this.utilsService = utilsService; this.DEFAULT_CONFIG = { hours12Format: 'hh', hours24Format: 'HH', meridiemFormat: 'A', minutesFormat: 'mm', minutesInterval: 1, secondsFormat: 'ss', secondsInterval: 1, showSeconds: false, showTwentyFourHours: false, timeSeparator: ':', }; } getConfig(config) { const timeConfigs = { maxTime: this.utilsService.onlyTime(config && config.maxTime), minTime: this.utilsService.onlyTime(config && config.minTime) }; return { ...this.DEFAULT_CONFIG, ...this.utilsService.clearUndefined(config), ...timeConfigs }; } getTimeFormat(config) { return (config.showTwentyFourHours ? config.hours24Format : config.hours12Format) + config.timeSeparator + config.minutesFormat + (config.showSeconds ? (config.timeSeparator + config.secondsFormat) : '') + (config.showTwentyFourHours ? '' : ' ' + config.meridiemFormat); } getHours(config, t) { const time = t || dayjsRef(); return time && time.format(config.showTwentyFourHours ? config.hours24Format : config.hours12Format); } getMinutes(config, t) { const time = t || dayjsRef(); return time && time.format(config.minutesFormat); } getSeconds(config, t) { const time = t || dayjsRef(); return time && time.format(config.secondsFormat); } getMeridiem(config, time) { return time && time.format(config.meridiemFormat); } decrease(config, time, unit) { let amount = 1; switch (unit) { case 'minute': amount = config.minutesInterval; break; case 'second': amount = config.secondsInterval; break; } return time.subtract(amount, unit); } increase(config, time, unit) { let amount = 1; switch (unit) { case 'minute': amount = config.minutesInterval; break; case 'second': amount = config.secondsInterval; break; } return time.add(amount, unit); } toggleMeridiem(time) { if (time.hour() < FIRST_PM_HOUR) { return time.add(12, 'hour'); } else { return time.subtract(12, 'hour'); } } shouldShowDecrease(config, time, unit) { if (!config.min && !config.minTime) { return true; } const newTime = this.decrease(config, time, unit); return (!config.min || config.min.isSameOrBefore(newTime)) && (!config.minTime || config.minTime.isSameOrBefore(this.utilsService.onlyTime(newTime))); } shouldShowIncrease(config, time, unit) { if (!config.max && !config.maxTime) { return true; } const newTime = this.increase(config, time, unit); return (!config.max || config.max.isSameOrAfter(newTime)) && (!config.maxTime || config.maxTime.isSameOrAfter(this.utilsService.onlyTime(newTime))); } shouldShowToggleMeridiem(config, time) { if (!config.min && !config.max && !config.minTime && !config.maxTime) { return true; } const newTime = this.toggleMeridiem(time); return (!config.max || config.max.isSameOrAfter(newTime)) && (!config.min || config.min.isSameOrBefore(newTime)) && (!config.maxTime || config.maxTime.isSameOrAfter(this.utilsService.onlyTime(newTime))) && (!config.minTime || config.minTime.isSameOrBefore(this.utilsService.onlyTime(newTime))); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TimeSelectService, deps: [{ token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TimeSelectService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: TimeSelectService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: UtilsService }] }); const DAY_FORMAT = 'YYYYMMDD'; const TIME_FORMAT = 'HH:mm:ss'; const COMBINED_FORMAT = DAY_FORMAT + TIME_FORMAT; class DayTimeCalendarService { constructor(utilsService, dayCalendarService, timeSelectService) { this.utilsService = utilsService; this.dayCalendarService = dayCalendarService; this.timeSelectService = timeSelectService; this.DEFAULT_CONFIG = {}; } getConfig(config) { const _config = { ...this.DEFAULT_CONFIG, ...this.timeSelectService.getConfig(config), ...this.dayCalendarService.getConfig(config) }; this.utilsService.convertPropsToDayjs(_config, _config.format, ['min', 'max']); return _config; } updateDay(current, day, config) { const time = current ? current : dayjsRef(); let updated = dayjsRef(day.format(DAY_FORMAT) + time.format(TIME_FORMAT), COMBINED_FORMAT); if (config.min) { const min = config.min; updated = min.isAfter(updated) ? min : updated; } if (config.max) { const max = config.max; updated = max.isBefore(updated) ? max : updated; } return updated; } updateTime(current, time) { const day = current ? current : dayjsRef(); return dayjsRef(day.format(DAY_FORMAT) + time.format(TIME_FORMAT), COMBINED_FORMAT); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DayTimeCalendarService, deps: [{ token: UtilsService }, { token: DayCalendarService }, { token: TimeSelectService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DayTimeCalendarService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DayTimeCalendarService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: UtilsService }, { type: DayCalendarService }, { type: TimeSelectService }] }); class DatePickerService { constructor(utilsService, timeSelectService, daytimeCalendarService) { this.utilsService = utilsService; this.timeSelectService = timeSelectService; this.daytimeCalendarService = daytimeCalendarService; this.onPickerClosed = new EventEmitter(); this.defaultConfig = { closeOnSelect: true, closeOnSelectDelay: 100, closeOnEnter: true, format: 'DD-MM-YYYY', openOnFocus: true, openOnClick: true, onOpenDelay: 0, disableKeypress: false, showNearMonthDays: true, showWeekNumbers: false, enableMonthSelector: true, showGoToCurrent: true, hideOnOutsideClick: true, }; } // todo:: add unit tests getConfig(config, mode = 'daytime') { const _config = { ...this.defaultConfig, format: DatePickerService.getDefaultFormatByMode(mode), ...this.utilsService.clearUndefined(config) }; this.utilsService.convertPropsToDayjs(_config, _config.format, ['min', 'max']); if (config && config.allowMultiSelect && config.closeOnSelect === undefined) { _config.closeOnSelect = false; } return _config; } getDayConfigService(pickerConfig) { return { min: pickerConfig.min, max: pickerConfig.max, isDayDisabledCallback: pickerConfig.isDayDisabledCallback, weekDayFormat: pickerConfig.weekDayFormat, weekDayFormatter: pickerConfig.weekDayFormatter, showNearMonthDays: pickerConfig.showNearMonthDays, showWeekNumbers: pickerConfig.showWeekNumbers, firstDayOfWeek: pickerConfig.firstDayOfWeek, format: pickerConfig.format, allowMultiSelect: pickerConfig.allowMultiSelect, monthFormat: pickerConfig.monthFormat, monthFormatter: pickerConfig.monthFormatter, enableMonthSelector: pickerConfig.enableMonthSelector, yearFormat: pickerConfig.yearFormat, yearFormatter: pickerConfig.yearFormatter, dayBtnFormat: pickerConfig.dayBtnFormat, dayBtnFormatter: pickerConfig.dayBtnFormatter, dayBtnCssClassCallback: pickerConfig.dayBtnCssClassCallback, monthBtnFormat: pickerConfig.monthBtnFormat, monthBtnFormatter: pickerConfig.monthBtnFormatter, monthBtnCssClassCallback: pickerConfig.monthBtnCssClassCallback, isMonthDisabledCallback: pickerConfig.isMonthDisabledCallback, multipleYearsNavigateBy: pickerConfig.multipleYearsNavigateBy, showMultipleYearsNavigation: pickerConfig.showMultipleYearsNavigation, returnedValueType: pickerConfig.returnedValueType, showGoToCurrent: pickerConfig.showGoToCurrent, unSelectOnClick: pickerConfig.unSelectOnClick, numOfMonthRows: pickerConfig.numOfMonthRows }; } getDayTimeConfig(pickerConfig) { return this.daytimeCalendarService.getConfig(pickerConfig); } getTimeConfig(pickerConfig) { return this.timeSelectService.getConfig(pickerConfig); } pickerClosed() { this.onPickerClosed.emit(); } // todo:: add unit tests isValidInputDateValue(value, config) { value = value ? value : ''; const datesStrArr = this.utilsService.datesStringToStringArray(value); return datesStrArr.every(date => this.utilsService.isDateValid(date, config.format)); } // todo:: add unit tests convertInputValueToDayjsArray(value, config) { value = value ? value : ''; const datesStrArr = this.utilsService.datesStringToStringArray(value); return this.utilsService.convertToDayjsArray(datesStrArr, config); } getOverlayPosition({ drops, opens }) { if (!drops && !opens) { return undefined; } return [{ originX: opens ? opens === 'left' ? 'start' : 'end' : 'start', originY: drops ? drops === 'up' ? 'top' : 'bottom' : 'bottom', overlayX: opens ? opens === 'left' ? 'start' : 'end' : 'start', overlayY: drops ? drops === 'up' ? 'bottom' : 'top' : 'top', }]; } static getDefaultFormatByMode(mode) { switch (mode) { case 'day': return 'DD-MM-YYYY'; case 'daytime': return 'DD-MM-YYYY HH:mm:ss'; case 'time': return 'HH:mm:ss'; case 'month': return 'MMM, YYYY'; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DatePickerService, deps: [{ token: UtilsService }, { token: TimeSelectService }, { token: DayTimeCalendarService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DatePickerService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: DatePickerService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: UtilsService }, { type: TimeSelectService }, { type: DayTimeCalendarService }] }); class MonthCalendarService { constructor(utilsService) { this.utilsService = utilsService; this.DEFAULT_CONFIG = { allowMultiSelect: false, yearFormat: 'YYYY', format: 'MM-YYYY', isNavHeaderBtnClickable: false, monthBtnFormat: 'MMM', multipleYearsNavigateBy: 10, showMultipleYearsNavigation: false, unSelectOnClick: true, numOfMonthRows: 3 }; } getConfig(config) { const _config = { ...this.DEFAULT_CONFIG, ...this.utilsService.clearUndefined(config) }; MonthCalendarService.validateConfig(_config); this.utilsService.convertPropsToDayjs(_config, _config.format, ['min', 'max']); return _config; } generateYear(config, year, selected = null) { let index = year.startOf('year'); return this.utilsService.createArray(config.numOfMonthRows).map(() => { return this.utilsService.createArray(12 / config.numOfMonthRows).map(() => { const date = dayjsRef(index); const month = { date, selected: !!selected.find(s => index.isSame(s, 'month')), currentMonth: index.isSame(dayjsRef(), 'month'), disabled: this.isMonthDisabled(date, config), text: this.getMonthBtnText(config, date) }; index = index.add(1, 'month'); return month; }); }); } isMonthDisabled(date, config) { if (config.isMonthDisabledCallback) { return config.isMonthDisabledCallback(date); } if (config.min && date.isBefore(config.min, 'month')) { return true; } return !!(config.max && date.isAfter(config.max, 'month')); } shouldShowLeft(min, currentMonthView) { return min ? min.isBefore(currentMonthView, 'year') : true; } shouldShowRight(max, currentMonthView) { return max ? max.isAfter(currentMonthView, 'year') : true; } getHeaderLabel(config, year) { if (config.yearFormatter) { return config.yearFormatter(year); } return year.format(config.yearFormat); } getMonthBtnText(config, month) { if (config.monthBtnFormatter) { return config.monthBtnFormatter(month); } return month.format(config.monthBtnFormat); } getMonthBtnCssClass(config, month) { if (config.monthBtnCssClassCallback) { return config.monthBtnCssClassCallback(month); } return ''; } static validateConfig(config) { if (config.numOfMonthRows < 1 || config.numOfMonthRows > 12 || !Number.isInteger(12 / config.numOfMonthRows)) { throw new Error('numOfMonthRows has to be between 1 - 12 and divide 12 to integer'); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: MonthCalendarService, deps: [{ token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: MonthCalendarService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: MonthCalendarService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: UtilsService }] }); class CalendarNavComponent { constructor() { this.isLabelClickable = false; this.showLeftNav = true; this.showLeftSecondaryNav = false; this.showRightNav = true; this.showRightSecondaryNav = false; this.leftNavDisabled = false; this.leftSecondaryNavDisabled = false; this.rightNavDisabled = false; this.rightSecondaryNavDisabled = false; this.showGoToCurrent = true; this.onLeftNav = new EventEmitter(); this.onLeftSecondaryNav = new EventEmitter(); this.onRightNav = new EventEmitter(); this.onRightSecondaryNav = new EventEmitter(); this.onLabelClick = new EventEmitter(); this.onGoToCurrent = new EventEmitter(); } leftNavClicked() { this.onLeftNav.emit(); } leftSecondaryNavClicked() { this.onLeftSecondaryNav.emit(); } rightNavClicked() { this.onRightNav.emit(); } rightSecondaryNavClicked() { this.onRightSecondaryNav.emit(); } labelClicked() { this.onLabelClick.emit(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: CalendarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: CalendarNavComponent, isStandalone: false, selector: "dp-calendar-nav", inputs: { label: "label", isLabelClickable: "isLabelClickable", showLeftNav: "showLeftNav", showLeftSecondaryNav: "showLeftSecondaryNav", showRightNav: "showRightNav", showRightSecondaryNav: "showRightSecondaryNav", leftNavDisabled: "leftNavDisabled", leftSecondaryNavDisabled: "leftSecondaryNavDisabled", rightNavDisabled: "rightNavDisabled", rightSecondaryNavDisabled: "rightSecondaryNavDisabled", showGoToCurrent: "showGoToCurrent", theme: "theme" }, outputs: { onLeftNav: "onLeftNav", onLeftSecondaryNav: "onLeftSecondaryNav", onRightNav: "onRightNav", onRightSecondaryNav: "onRightSecondaryNav", onLabelClick: "onLabelClick", onGoToCurrent: "onGoToCurrent" }, host: { properties: { "class": "this.theme" } }, ngImport: i0, template: "<div class=\"dp-calendar-nav-container\" dir=\"ltr\">\n <div class=\"dp-nav-header\">\n <span [attr.data-hidden]=\"isLabelClickable\"\n [hidden]=\"isLabelClickable\"\n [innerText]=\"label\">\n </span>\n <button (click)=\"labelClicked()\"\n [attr.data-hidden]=\"!isLabelClickable\"\n [hidden]=\"!isLabelClickable\"\n [innerText]=\"label\"\n class=\"dp-nav-header-btn\"\n type=\"button\">\n </button>\n </div>\n\n <div class=\"dp-nav-btns-container\">\n <div class=\"dp-calendar-nav-container-left\">\n <button (click)=\"leftSecondaryNavClicked()\"\n *ngIf=\"showLeftSecondaryNav\"\n [disabled]=\"leftSecondaryNavDisabled\"\n class=\"dp-calendar-secondary-nav-left\"\n type=\"button\">\n </button>\n <button (click)=\"leftNavClicked()\"\n [attr.data-hidden]=\"!showLeftNav\"\n [disabled]=\"leftNavDisabled\"\n [hidden]=\"!showLeftNav\"\n class=\"dp-calendar-nav-left\"\n type=\"button\">\n </button>\n </div>\n <button (click)=\"onGoToCurrent.emit()\"\n *ngIf=\"showGoToCurrent\"\n class=\"dp-current-location-btn\"\n type=\"button\">\n </button>\n <div class=\"dp-calendar-nav-container-right\">\n <button (click)=\"rightNavClicked()\"\n [attr.data-hidden]=\"!showRightNav\"\n [disabled]=\"rightNavDisabled\"\n [hidden]=\"!showRightNav\"\n class=\"dp-calendar-nav-right\"\n type=\"button\">\n </button>\n <button (click)=\"rightSecondaryNavClicked()\"\n *ngIf=\"showRightSecondaryNav\"\n [disabled]=\"rightSecondaryNavDisabled\"\n class=\"dp-calendar-secondary-nav-right\"\n type=\"button\">\n </button>\n </div>\n </div>\n</div>\n", styles: ["dp-calendar-nav .dp-calendar-nav-container{position:relative;box-sizing:border-box;height:25px;border:1px solid #000000;border-bottom:none}dp-calendar-nav .dp-nav-date-btn{box-sizing:border-box;height:25px;border:1px solid #000000;border-bottom:none}dp-calendar-nav .dp-nav-btns-container{position:absolute;top:50%;transform:translateY(-50%);right:5px;display:inline-block}dp-calendar-nav .dp-calendar-nav-container-left,dp-calendar-nav .dp-calendar-nav-container-right{display:inline-block}dp-calendar-nav .dp-calendar-nav-left,dp-calendar-nav .dp-calendar-nav-right,dp-calendar-nav .dp-calendar-secondary-nav-left,dp-calendar-nav .dp-calendar-secondary-nav-right{position:relative;width:16px;cursor:pointer}dp-calendar-nav .dp-calendar-nav-left,dp-calendar-nav .dp-calendar-nav-right{line-height:0}dp-calendar-nav .dp-calendar-nav-left:before,dp-calendar-nav .dp-calendar-nav-right:before{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(45deg)}dp-calendar-nav .dp-calendar-secondary-nav-left,dp-calendar-nav .dp-calendar-secondary-nav-right{padding:0}dp-calendar-nav .dp-calendar-secondary-nav-left:before,dp-calendar-nav .dp-calendar-secondary-nav-right:before,dp-calendar-nav .dp-calendar-secondary-nav-left:after,dp-calendar-nav .dp-calendar-secondary-nav-right:after{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(45deg)}dp-calendar-nav .dp-calendar-secondary-nav-left:before,dp-calendar-nav .dp-calendar-secondary-nav-right:before{right:-10px}dp-calendar-nav .dp-calendar-secondary-nav-right{left:initial;right:5px}dp-calendar-nav .dp-calendar-nav-left:before{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(-135deg)}dp-calendar-nav .dp-calendar-secondary-nav-left:before,dp-calendar-nav .dp-calendar-secondary-nav-left:after{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(-135deg)}dp-calendar-nav .dp-calendar-secondary-nav-left:before{right:-10px}dp-calendar-nav .dp-nav-header{position:absolute;top:50%;transform:translateY(-50%);left:5px;display:inline-block;font-size:13px}dp-calendar-nav .dp-nav-header-btn{cursor:pointer}dp-calendar-nav .dp-current-location-btn{position:relative;top:-1px;height:16px;width:16px;vertical-align:middle;background:#0009;border:1px solid rgba(0,0,0,.6);outline:none;border-radius:50%;box-shadow:inset 0 0 0 3px #fff;cursor:pointer}dp-calendar-nav .dp-current-location-btn:hover{background:#000}dp-calendar-nav.dp-material .dp-calendar-nav-container{height:30px;border:1px solid #E0E0E0}dp-calendar-nav.dp-material .dp-calendar-nav-left,dp-calendar-nav.dp-material .dp-calendar-nav-right,dp-calendar-nav.dp-material .dp-calendar-secondary-nav-left,dp-calendar-nav.dp-material .dp-calendar-secondary-nav-right{border:none;background:#fff;outline:none;font-size:16px;padding:0}dp-calendar-nav.dp-material .dp-calendar-secondary-nav-left,dp-calendar-nav.dp-material .dp-calendar-secondary-nav-right{width:20px}dp-calendar-nav.dp-material .dp-nav-header-btn{height:20px;width:80px;border:none;background:#fff;outline:none}dp-calendar-nav.dp-material .dp-nav-header-btn:hover{background:#0000000d}dp-calendar-nav.dp-material .dp-nav-header-btn:active{background:#0000001a}\n"], dependencies: [{ kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.ɵɵDir, selector: "[dir]", inputs: ["dir"], outputs: ["dirChange"], exportAs: ["dir"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: CalendarNavComponent, decorators: [{ type: Component, args: [{ selector: 'dp-calendar-nav', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div class=\"dp-calendar-nav-container\" dir=\"ltr\">\n <div class=\"dp-nav-header\">\n <span [attr.data-hidden]=\"isLabelClickable\"\n [hidden]=\"isLabelClickable\"\n [innerText]=\"label\">\n </span>\n <button (click)=\"labelClicked()\"\n [attr.data-hidden]=\"!isLabelClickable\"\n [hidden]=\"!isLabelClickable\"\n [innerText]=\"label\"\n class=\"dp-nav-header-btn\"\n type=\"button\">\n </button>\n </div>\n\n <div class=\"dp-nav-btns-container\">\n <div class=\"dp-calendar-nav-container-left\">\n <button (click)=\"leftSecondaryNavClicked()\"\n *ngIf=\"showLeftSecondaryNav\"\n [disabled]=\"leftSecondaryNavDisabled\"\n class=\"dp-calendar-secondary-nav-left\"\n type=\"button\">\n </button>\n <button (click)=\"leftNavClicked()\"\n [attr.data-hidden]=\"!showLeftNav\"\n [disabled]=\"leftNavDisabled\"\n [hidden]=\"!showLeftNav\"\n class=\"dp-calendar-nav-left\"\n type=\"button\">\n </button>\n </div>\n <button (click)=\"onGoToCurrent.emit()\"\n *ngIf=\"showGoToCurrent\"\n class=\"dp-current-location-btn\"\n type=\"button\">\n </button>\n <div class=\"dp-calendar-nav-container-right\">\n <button (click)=\"rightNavClicked()\"\n [attr.data-hidden]=\"!showRightNav\"\n [disabled]=\"rightNavDisabled\"\n [hidden]=\"!showRightNav\"\n class=\"dp-calendar-nav-right\"\n type=\"button\">\n </button>\n <button (click)=\"rightSecondaryNavClicked()\"\n *ngIf=\"showRightSecondaryNav\"\n [disabled]=\"rightSecondaryNavDisabled\"\n class=\"dp-calendar-secondary-nav-right\"\n type=\"button\">\n </button>\n </div>\n </div>\n</div>\n", styles: ["dp-calendar-nav .dp-calendar-nav-container{position:relative;box-sizing:border-box;height:25px;border:1px solid #000000;border-bottom:none}dp-calendar-nav .dp-nav-date-btn{box-sizing:border-box;height:25px;border:1px solid #000000;border-bottom:none}dp-calendar-nav .dp-nav-btns-container{position:absolute;top:50%;transform:translateY(-50%);right:5px;display:inline-block}dp-calendar-nav .dp-calendar-nav-container-left,dp-calendar-nav .dp-calendar-nav-container-right{display:inline-block}dp-calendar-nav .dp-calendar-nav-left,dp-calendar-nav .dp-calendar-nav-right,dp-calendar-nav .dp-calendar-secondary-nav-left,dp-calendar-nav .dp-calendar-secondary-nav-right{position:relative;width:16px;cursor:pointer}dp-calendar-nav .dp-calendar-nav-left,dp-calendar-nav .dp-calendar-nav-right{line-height:0}dp-calendar-nav .dp-calendar-nav-left:before,dp-calendar-nav .dp-calendar-nav-right:before{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(45deg)}dp-calendar-nav .dp-calendar-secondary-nav-left,dp-calendar-nav .dp-calendar-secondary-nav-right{padding:0}dp-calendar-nav .dp-calendar-secondary-nav-left:before,dp-calendar-nav .dp-calendar-secondary-nav-right:before,dp-calendar-nav .dp-calendar-secondary-nav-left:after,dp-calendar-nav .dp-calendar-secondary-nav-right:after{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(45deg)}dp-calendar-nav .dp-calendar-secondary-nav-left:before,dp-calendar-nav .dp-calendar-secondary-nav-right:before{right:-10px}dp-calendar-nav .dp-calendar-secondary-nav-right{left:initial;right:5px}dp-calendar-nav .dp-calendar-nav-left:before{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(-135deg)}dp-calendar-nav .dp-calendar-secondary-nav-left:before,dp-calendar-nav .dp-calendar-secondary-nav-left:after{position:relative;content:\"\";display:inline-block;height:8px;width:8px;vertical-align:baseline;border-style:solid;border-width:2px 2px 0 0;transform:rotate(-135deg)}dp-calendar-nav .dp-calendar-secondary-nav-left:before{right:-10px}dp-calendar-nav .dp-nav-header{position:absolute;top:50%;transform:translateY(-50%);left:5px;display:inline-block;font-size:13px}dp-calendar-nav .dp-nav-header-btn{cursor:pointer}dp-calendar-nav .dp-current-location-btn{position:relative;top:-1px;height:16px;width:16px;vertical-align:middle;background:#0009;border:1px solid rgba(0,0,0,.6);outline:none;border-radius:50%;box-shadow:inset 0 0 0 3px #fff;cursor:pointer}dp-calendar-nav .dp-current-location-btn:hover{background:#000}dp-calendar-nav.dp-material .dp-calendar-nav-container{height:30px;border:1px solid #E0E0E0}dp-calendar-nav.dp-material .dp-calendar-nav-left,dp-calendar-nav.dp-material .dp-calendar-nav-right,dp-calendar-nav.dp-material .dp-calendar-secondary-nav-left,dp-calendar-nav.dp-material .dp-calendar-secondary-nav-right{border:none;background:#fff;outline:none;font-size:16px;padding:0}dp-calendar-nav.dp-material .dp-calendar-secondary-nav-left,dp-calendar-nav.dp-material .dp-calendar-secondary-nav-right{width:20px}dp-calendar-nav.dp-material .dp-nav-header-btn{height:20px;width:80px;border:none;background:#fff;outline:none}dp-calendar-nav.dp-material .dp-nav-header-btn:hover{background:#0000000d}dp-calendar-nav.dp-material .dp-nav-header-btn:active{background:#0000001a}\n"] }] }], propDecorators: { label: [{ type: Input }], isLabelClickable: [{ type: Input }], showLeftNav: [{ type: Input }], showLeftSecondaryNav: [{ type: Input }], showRightNav: [{ type: Input }], showRightSecondaryNav: [{ type: Input }], leftNavDisabled: [{ type: Input }], leftSecondaryNavDisabled: [{ type: