UNPKG

angular-weblineindia-date-picker

Version:

Date Picker component built in AngularJS to select date and time. Supports Angular 9 version.

1,287 lines (1,277 loc) 116 kB
import { __decorate, __param } from 'tslib'; import { ɵɵdefineInjectable, Injectable, EventEmitter, ElementRef, Renderer2, ChangeDetectorRef, Input, HostBinding, Output, ViewChild, HostListener, Component, ViewEncapsulation, ChangeDetectionStrategy, forwardRef, ViewContainerRef, ComponentFactoryResolver, Optional, Directive, NgModule } from '@angular/core'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS, NgControl, FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import * as momentNs from 'moment'; 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["Moment"] = 1] = "Moment"; ECalendarValue[ECalendarValue["MomentArr"] = 2] = "MomentArr"; ECalendarValue[ECalendarValue["String"] = 3] = "String"; ECalendarValue[ECalendarValue["StringArr"] = 4] = "StringArr"; })(ECalendarValue || (ECalendarValue = {})); var SelectEvent; (function (SelectEvent) { SelectEvent["INPUT"] = "input"; SelectEvent["SELECTION"] = "selection"; })(SelectEvent || (SelectEvent = {})); var DomHelper_1; let DomHelper = DomHelper_1 = class DomHelper { static setYAxisPosition(element, container, anchor, drops) { const anchorRect = anchor.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); const bottom = anchorRect.bottom - containerRect.top; const top = anchorRect.top - containerRect.top; if (drops === 'down') { element.style.top = (bottom + 1 + 'px'); } else { element.style.top = (top - 1 - element.scrollHeight) + 'px'; } } static setXAxisPosition(element, container, anchor, dimElem, opens) { const anchorRect = anchor.getBoundingClientRect(); const containerRect = container.getBoundingClientRect(); const left = anchorRect.left - containerRect.left; if (opens === 'right') { element.style.left = left + 'px'; } else { element.style.left = left - dimElem.offsetWidth + anchor.offsetWidth + 'px'; } } static isTopInView(el) { const { top } = el.getBoundingClientRect(); return (top >= 0); } static isBottomInView(el) { const { bottom } = el.getBoundingClientRect(); return (bottom <= window.innerHeight); } static isLeftInView(el) { const { left } = el.getBoundingClientRect(); return (left >= 0); } static isRightInView(el) { const { right } = el.getBoundingClientRect(); return (right <= window.innerWidth); } appendElementToPosition(config) { const { container, element } = config; if (!container.style.position || container.style.position === 'static') { container.style.position = 'relative'; } if (element.style.position !== 'absolute') { element.style.position = 'absolute'; } element.style.visibility = 'hidden'; setTimeout(() => { this.setElementPosition(config); element.style.visibility = 'visible'; }); } setElementPosition({ element, container, anchor, dimElem, drops, opens }) { DomHelper_1.setYAxisPosition(element, container, anchor, 'down'); DomHelper_1.setXAxisPosition(element, container, anchor, dimElem, 'right'); if (drops !== 'down' && drops !== 'up') { if (DomHelper_1.isBottomInView(dimElem)) { DomHelper_1.setYAxisPosition(element, container, anchor, 'down'); } else if (DomHelper_1.isTopInView(dimElem)) { DomHelper_1.setYAxisPosition(element, container, anchor, 'up'); } } else { DomHelper_1.setYAxisPosition(element, container, anchor, drops); } if (opens !== 'left' && opens !== 'right') { if (DomHelper_1.isRightInView(dimElem)) { DomHelper_1.setXAxisPosition(element, container, anchor, dimElem, 'right'); } else if (DomHelper_1.isLeftInView(dimElem)) { DomHelper_1.setXAxisPosition(element, container, anchor, dimElem, 'left'); } } else { DomHelper_1.setXAxisPosition(element, container, anchor, dimElem, opens); } } }; DomHelper.ɵprov = ɵɵdefineInjectable({ factory: function DomHelper_Factory() { return new DomHelper(); }, token: DomHelper, providedIn: "root" }); DomHelper = DomHelper_1 = __decorate([ Injectable({ providedIn: 'root' }) ], DomHelper); const moment = momentNs; let UtilsService = 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); } convertToMoment(date, format) { if (!date) { return null; } else if (typeof date === 'string') { return moment(date, format); } else { return date.clone(); } } isDateValid(date, format) { if (date === '') { return true; } return moment(date, format, true).isValid(); } // todo:: add unit test getDefaultDisplayDate(current, selected, allowMultiSelect, minDate) { if (current) { return current.clone(); } else if (minDate && minDate.isAfter(moment())) { return minDate.clone(); } else if (allowMultiSelect) { if (selected && selected[selected.length]) { return selected[selected.length].clone(); } } else if (selected && selected[0]) { return selected[0].clone(); } return moment(); } // todo:: add unit test getInputType(value, allowMultiSelect) { if (Array.isArray(value)) { if (!value.length) { return ECalendarValue.MomentArr; } else if (typeof value[0] === 'string') { return ECalendarValue.StringArr; } else if (moment.isMoment(value[0])) { return ECalendarValue.MomentArr; } } else { if (typeof value === 'string') { return ECalendarValue.String; } else if (moment.isMoment(value)) { return ECalendarValue.Moment; } } return allowMultiSelect ? ECalendarValue.MomentArr : ECalendarValue.Moment; } // todo:: add unit test convertToMomentArray(value, config) { let retVal; switch (this.getInputType(value, config.allowMultiSelect)) { case (ECalendarValue.String): retVal = value ? [moment(value, config.format, true)] : []; break; case (ECalendarValue.StringArr): retVal = value.map(v => v ? moment(v, config.format, true) : null).filter(Boolean); break; case (ECalendarValue.Moment): retVal = value ? [value.clone()] : []; break; case (ECalendarValue.MomentArr): retVal = (value || []).map(v => v.clone()); break; default: retVal = []; } return retVal; } // todo:: add unit test convertFromMomentArray(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.Moment): return value[0] ? value[0].clone() : value[0]; case (ECalendarValue.MomentArr): return value ? value.map(v => v.clone()) : 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.convertToMoment(v, format).format(format); }); } else { tmpVal = value; } } else if (moment.isMoment(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 && moment.isMoment(m) && moment(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.convertToMoment(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.convertToMoment(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.convertToMoment(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.convertToMoment(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.convertToMomentArray(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); } getValidMomentArray(value, format) { return this.datesStringToStringArray(value) .filter(d => this.isDateValid(d, format)) .map(d => moment(d, format)); } shouldShowCurrent(showGoToCurrent, mode, min, max) { return showGoToCurrent && mode !== 'time' && this.isDateInRange(moment(), min, max); } isDateInRange(date, from, to) { return date.isBetween(from, to, 'day', '[]'); } convertPropsToMoment(obj, format, props) { props.forEach((prop) => { if (obj.hasOwnProperty(prop)) { obj[prop] = this.convertToMoment(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 { return elem; } } }; UtilsService.ɵprov = ɵɵdefineInjectable({ factory: function UtilsService_Factory() { return new UtilsService(); }, token: UtilsService, providedIn: "root" }); UtilsService = __decorate([ Injectable({ providedIn: 'root' }) ], UtilsService); const moment$1 = momentNs; let DayCalendarService = 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, locale: moment$1.locale(), dayBtnFormat: 'DD', unSelectOnClick: true }; this.DAYS = ['su', 'mo', 'tu', 'we', 'th', 'fr', 'sa']; } getConfig(config) { const _config = Object.assign(Object.assign({}, this.DEFAULT_CONFIG), this.utilsService.clearUndefined(config)); this.utilsService.convertPropsToMoment(_config, _config.format, ['min', 'max']); moment$1.locale(_config.locale); 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) { let monthArray = []; const firstDayOfWeekIndex = this.DAYS.indexOf(config.firstDayOfWeek); const firstDayOfBoard = month.clone().startOf('month'); while (firstDayOfBoard.day() !== firstDayOfWeekIndex) { firstDayOfBoard.subtract(1, 'day'); } const current = firstDayOfBoard.clone(); const prevMonth = month.clone().subtract(1, 'month'); const nextMonth = month.clone().add(1, 'month'); const today = moment$1(); const daysOfCalendar = this.utilsService.createArray(42) .reduce((array) => { array.push({ date: current.clone(), selected: !!selected.find(selectedDay => current.isSame(selectedDay, 'day')), currentMonth: current.isSame(month, 'month'), prevMonth: current.isSame(prevMonth, 'month'), nextMonth: current.isSame(nextMonth, 'month'), currentDay: current.isSame(today, 'day'), disabled: this.isDateDisabled(current, config) }); 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(month, monthArray); } return monthArray; } generateWeekdays(firstDayOfWeek) { const weekdayNames = { su: moment$1().day(0), mo: moment$1().day(1), tu: moment$1().day(2), we: moment$1().day(3), th: moment$1().day(4), fr: moment$1().day(5), sa: moment$1().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, locale: componentConfig.locale, yearFormat: componentConfig.yearFormat, yearFormatter: componentConfig.yearFormatter, monthBtnFormat: componentConfig.monthBtnFormat, monthBtnFormatter: componentConfig.monthBtnFormatter, monthBtnCssClassCallback: componentConfig.monthBtnCssClassCallback, 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); } } }; DayCalendarService.ctorParameters = () => [ { type: UtilsService } ]; DayCalendarService = __decorate([ Injectable() ], DayCalendarService); const moment$2 = momentNs; const FIRST_PM_HOUR = 12; let TimeSelectService = 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: ':', locale: moment$2.locale() }; } getConfig(config) { const timeConfigs = { maxTime: this.utilsService.onlyTime(config && config.maxTime), minTime: this.utilsService.onlyTime(config && config.minTime) }; const _config = Object.assign(Object.assign(Object.assign({}, this.DEFAULT_CONFIG), this.utilsService.clearUndefined(config)), timeConfigs); moment$2.locale(_config.locale); return _config; } 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 || moment$2(); return time && time.format(config.showTwentyFourHours ? config.hours24Format : config.hours12Format); } getMinutes(config, t) { const time = t || moment$2(); return time && time.format(config.minutesFormat); } getSeconds(config, t) { const time = t || moment$2(); 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.clone().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.clone().add(amount, unit); } toggleMeridiem(time) { if (time.hours() < FIRST_PM_HOUR) { return time.clone().add(12, 'hour'); } else { return time.clone().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))); } }; TimeSelectService.ctorParameters = () => [ { type: UtilsService } ]; TimeSelectService = __decorate([ Injectable() ], TimeSelectService); const moment$3 = momentNs; const DAY_FORMAT = 'YYYYMMDD'; const TIME_FORMAT = 'HH:mm:ss'; const COMBINED_FORMAT = DAY_FORMAT + TIME_FORMAT; let DayTimeCalendarService = class DayTimeCalendarService { constructor(utilsService, dayCalendarService, timeSelectService) { this.utilsService = utilsService; this.dayCalendarService = dayCalendarService; this.timeSelectService = timeSelectService; this.DEFAULT_CONFIG = { locale: moment$3.locale() }; } getConfig(config) { const _config = Object.assign(Object.assign(Object.assign({}, this.DEFAULT_CONFIG), this.timeSelectService.getConfig(config)), this.dayCalendarService.getConfig(config)); moment$3.locale(config.locale); return _config; } updateDay(current, day, config) { const time = current ? current : moment$3(); let updated = moment$3(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 : moment$3(); return moment$3(day.format(DAY_FORMAT) + time.format(TIME_FORMAT), COMBINED_FORMAT); } }; DayTimeCalendarService.ctorParameters = () => [ { type: UtilsService }, { type: DayCalendarService }, { type: TimeSelectService } ]; DayTimeCalendarService = __decorate([ Injectable() ], DayTimeCalendarService); const moment$4 = momentNs; let DatePickerService = 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, locale: moment$4.locale(), hideOnOutsideClick: true }; } // todo:: add unit tests getConfig(config, mode = 'daytime') { const _config = Object.assign(Object.assign(Object.assign({}, this.defaultConfig), { format: this.getDefaultFormatByMode(mode) }), this.utilsService.clearUndefined(config)); this.utilsService.convertPropsToMoment(_config, _config.format, ['min', 'max']); if (config && config.allowMultiSelect && config.closeOnSelect === undefined) { _config.closeOnSelect = false; } moment$4.locale(_config.locale); 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, multipleYearsNavigateBy: pickerConfig.multipleYearsNavigateBy, showMultipleYearsNavigation: pickerConfig.showMultipleYearsNavigation, locale: pickerConfig.locale, returnedValueType: pickerConfig.returnedValueType, showGoToCurrent: pickerConfig.showGoToCurrent, unSelectOnClick: pickerConfig.unSelectOnClick, numOfMonthRows: pickerConfig.numOfMonthRows }; } getDayTimeConfigService(pickerConfig) { return this.daytimeCalendarService.getConfig(pickerConfig); } getTimeConfigService(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 convertInputValueToMomentArray(value, config) { value = value ? value : ''; const datesStrArr = this.utilsService.datesStringToStringArray(value); return this.utilsService.convertToMomentArray(datesStrArr, config); } 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'; } } }; DatePickerService.ctorParameters = () => [ { type: UtilsService }, { type: TimeSelectService }, { type: DayTimeCalendarService } ]; DatePickerService = __decorate([ Injectable() ], DatePickerService); var DatePickerComponent_1; let DatePickerComponent = DatePickerComponent_1 = class DatePickerComponent { constructor(dayPickerService, domHelper, elemRef, renderer, utilsService, cd) { this.dayPickerService = dayPickerService; this.domHelper = domHelper; this.elemRef = elemRef; this.renderer = renderer; this.utilsService = utilsService; this.cd = cd; this.isInitialized = false; this.mode = 'day'; this.placeholder = ''; this.disabled = false; this.open = new EventEmitter(); this.close = new EventEmitter(); this.onChange = new EventEmitter(); this.onGoToCurrent = new EventEmitter(); this.onLeftNav = new EventEmitter(); this.onRightNav = new EventEmitter(); this.onSelect = new EventEmitter(); this.hideStateHelper = false; this.isFocusedTrigger = false; this.handleInnerElementClickUnlisteners = []; this.globalListenersUnlisteners = []; this.api = { open: this.showCalendars.bind(this), close: this.hideCalendar.bind(this), moveCalendarTo: this.moveCalendarTo.bind(this) }; this.selectEvent = SelectEvent; this._areCalendarsShown = false; this._selected = []; } get openOnFocus() { return this.componentConfig.openOnFocus; } get openOnClick() { return this.componentConfig.openOnClick; } get areCalendarsShown() { return this._areCalendarsShown; } set areCalendarsShown(value) { if (value) { this.startGlobalListeners(); this.domHelper.appendElementToPosition({ container: this.appendToElement, element: this.calendarWrapper, anchor: this.inputElementContainer, dimElem: this.popupElem, drops: this.componentConfig.drops, opens: this.componentConfig.opens }); } else { this.stopGlobalListeners(); this.dayPickerService.pickerClosed(); } this._areCalendarsShown = value; } get selected() { return this._selected; } set selected(selected) { this._selected = selected; this.inputElementValue = this.utilsService .convertFromMomentArray(this.componentConfig.format, selected, ECalendarValue.StringArr) .join(' | '); const val = this.processOnChangeCallback(selected); this.onChangeCallback(val, false); this.onChange.emit(val); } get currentDateView() { return this._currentDateView; } set currentDateView(date) { this._currentDateView = date; if (this.dayCalendarRef) { this.dayCalendarRef.moveCalendarTo(date); } if (this.monthCalendarRef) { this.monthCalendarRef.moveCalendarTo(date); } if (this.dayTimeCalendarRef) { this.dayTimeCalendarRef.moveCalendarTo(date); } } onClick() { if (!this.openOnClick) { return; } if (!this.isFocusedTrigger && !this.disabled) { this.hideStateHelper = true; if (!this.areCalendarsShown) { this.showCalendars(); } } } onBodyClick() { if (this.componentConfig.hideOnOutsideClick) { if (!this.hideStateHelper && this.areCalendarsShown) { this.hideCalendar(); } this.hideStateHelper = false; } } onScroll() { if (this.areCalendarsShown) { this.domHelper.setElementPosition({ container: this.appendToElement, element: this.calendarWrapper, anchor: this.inputElementContainer, dimElem: this.popupElem, drops: this.componentConfig.drops, opens: this.componentConfig.opens }); } } writeValue(value) { this.inputValue = value; if (value || value === '') { this.selected = this.utilsService .convertToMomentArray(value, this.componentConfig); this.init(); } else { this.selected = []; } this.cd.markForCheck(); } registerOnChange(fn) { this.onChangeCallback = fn; } onChangeCallback(_, changedByInput) { } registerOnTouched(fn) { this.onTouchedCallback = fn; } onTouchedCallback() { } validate(formControl) { return this.validateFn(formControl.value); } processOnChangeCallback(selected) { if (typeof selected === 'string') { return selected; } else { return this.utilsService.convertFromMomentArray(this.componentConfig.format, selected, this.componentConfig.returnedValueType || this.utilsService.getInputType(this.inputValue, this.componentConfig.allowMultiSelect)); } } initValidators() { this.validateFn = this.utilsService.createValidator({ minDate: this.minDate, maxDate: this.maxDate, minTime: this.minTime, maxTime: this.maxTime }, this.componentConfig.format, this.mode); this.onChangeCallback(this.processOnChangeCallback(this.selected), false); } ngOnInit() { this.isInitialized = true; this.init(); } ngOnChanges(changes) { if (this.isInitialized) { this.init(); } } ngAfterViewInit() { this.setElementPositionInDom(); } setDisabledState(isDisabled) { this.disabled = isDisabled; this.cd.markForCheck(); } setElementPositionInDom() { this.calendarWrapper = this.calendarContainer.nativeElement; this.setInputElementContainer(); this.popupElem = this.elemRef.nativeElement.querySelector('.dp-popup'); this.handleInnerElementClick(this.popupElem); const { appendTo } = this.componentConfig; if (appendTo) { if (typeof appendTo === 'string') { this.appendToElement = document.querySelector(appendTo); } else { this.appendToElement = appendTo; } } else { this.appendToElement = this.elemRef.nativeElement; } this.appendToElement.appendChild(this.calendarWrapper); } setInputElementContainer() { this.inputElementContainer = this.utilsService.getNativeElement(this.componentConfig.inputElementContainer) || this.elemRef.nativeElement.querySelector('.dp-input-container') || document.body; } handleInnerElementClick(element) { this.handleInnerElementClickUnlisteners.push(this.renderer.listen(element, 'click', () => { this.hideStateHelper = true; })); } init() { this.componentConfig = this.dayPickerService.getConfig(this.config, this.mode); this.currentDateView = this.displayDate ? this.utilsService.convertToMoment(this.displayDate, this.componentConfig.format).clone() : this.utilsService .getDefaultDisplayDate(this.currentDateView, this.selected, this.componentConfig.allowMultiSelect, this.componentConfig.min); this.dayCalendarConfig = this.dayPickerService.getDayConfigService(this.componentConfig); this.dayTimeCalendarConfig = this.dayPickerService.getDayTimeConfigService(this.componentConfig); this.timeSelectConfig = this.dayPickerService.getTimeConfigService(this.componentConfig); this.initValidators(); } inputFocused() { if (!this.openOnFocus) { return; } clearTimeout(this.onOpenDelayTimeoutHandler); this.isFocusedTrigger = true; this.onOpenDelayTimeoutHandler = setTimeout(() => { if (!this.areCalendarsShown) { this.showCalendars(); } this.hideStateHelper = false; this.isFocusedTrigger = false; this.cd.markForCheck(); }, this.componentConfig.onOpenDelay); } inputBlurred() { clearTimeout(this.onOpenDelayTimeoutHandler); this.onTouchedCallback(); } showCalendars() { this.hideStateHelper = true; this.areCalendarsShown = true; if (this.timeSelectRef) { this.timeSelectRef.api.triggerChange(); } this.open.emit(); this.cd.markForCheck(); } hideCalendar() { this.areCalendarsShown = false; if (this.dayCalendarRef) { this.dayCalendarRef.api.toggleCalendarMode(ECalendarMode.Day); } this.close.emit(); this.cd.markForCheck(); } onViewDateChange(value) { const strVal = value ? this.utilsService.convertToString(value, this.componentConfig.format) : ''; if (this.dayPickerService.isValidInputDateValue(strVal, this.componentConfig)) { this.selected = this.dayPickerService.convertInputValueToMomentArray(strVal, this.componentConfig); this.currentDateView = this.selected.length ? this.utilsService.getDefaultDisplayDate(null, this.selected, this.componentConfig.allowMultiSelect, this.componentConfig.min) : this.currentDateView; this.onSelect.emit({ date: strVal, type: SelectEvent.INPUT, granularity: null }); } else { this._selected = this.utilsService .getValidMomentArray(strVal, this.componentConfig.format); this.onChangeCallback(this.processOnChangeCallback(strVal), true); } } dateSelected(date, granularity, type, ignoreClose) { this.selected = this.utilsService .updateSelected(this.componentConfig.allowMultiSelect, this.selected, date, granularity); if (!ignoreClose) { this.onDateClick(); } this.onSelect.emit({ date: date.date, granularity, type }); } onDateClick() { if (this.componentConfig.closeOnSelect) { setTimeout(this.hideCalendar.bind(this), this.componentConfig.closeOnSelectDelay); } } onKeyPress(event) { switch (event.keyCode) { case (9): case (27): this.hideCalendar(); break; } } moveCalendarTo(date) { const momentDate = this.utilsService.convertToMoment(date, this.componentConfig.format); this.currentDateView = momentDate; } onLeftNavClick(change) { this.onLeftNav.emit(change); } onRightNavClick(change) { this.onRightNav.emit(change); } startGlobalListeners() { this.globalListenersUnlisteners.push(this.renderer.listen(document, 'keydown', (e) => { this.onKeyPress(e); }), this.renderer.listen(document, 'scroll', () => { this.onScroll(); }), this.renderer.listen(document, 'click', () => { this.onBodyClick(); })); } stopGlobalListeners() { this.globalListenersUnlisteners.forEach((ul) => ul()); this.globalListenersUnlisteners = []; } ngOnDestroy() { this.handleInnerElementClickUnlisteners.forEach(ul => ul()); if (this.appendToElement) { this.appendToElement.removeChild(this.calendarWrapper); } } }; DatePickerComponent.ctorParameters = () => [ { type: DatePickerService }, { type: DomHelper }, { type: ElementRef }, { type: Renderer2 }, { type: UtilsService }, { type: ChangeDetectorRef } ]; __decorate([ Input() ], DatePickerComponent.prototype, "config", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "mode", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "placeholder", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "disabled", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "displayDate", void 0); __decorate([ HostBinding('class'), Input() ], DatePickerComponent.prototype, "theme", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "minDate", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "maxDate", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "minTime", void 0); __decorate([ Input() ], DatePickerComponent.prototype, "maxTime", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "open", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "close", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "onChange", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "onGoToCurrent", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "onLeftNav", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "onRightNav", void 0); __decorate([ Output() ], DatePickerComponent.prototype, "onSelect", void 0); __decorate([ ViewChild('container') ], DatePickerComponent.prototype, "calendarContainer", void 0); __decorate([ ViewChild('dayCalendar') ], DatePickerComponent.prototype, "dayCalendarRef", void 0); __decorate([ ViewChild('monthCalendar') ], DatePickerComponent.prototype, "monthCalendarRef", void 0); __decorate([ ViewChild('daytimeCalendar') ], DatePickerComponent.prototype, "dayTimeCalendarRef", void 0); __decorate([ ViewChild('timeSelect') ], DatePickerComponent.prototype, "timeSelectRef", void 0); __decorate([ HostListener('click') ], DatePickerComponent.prototype, "onClick", null); __decorate([ HostListener('window:resize') ], DatePickerComponent.prototype, "onScroll", null); DatePickerComponent = DatePickerComponent_1 = __decorate([ Component({ selector: 'dp-date-picker', template: "<div [ngClass]=\"{'dp-open': areCalendarsShown}\">\n <div [attr.data-hidden]=\"componentConfig.hideInputContainer\"\n [hidden]=\"componentConfig.hideInputContainer\"\n class=\"dp-input-container\">\n <input (blur)=\"inputBlurred()\"\n (focus)=\"inputFocused()\"\n (ngModelChange)=\"onViewDateChange($event)\"\n (keydown.enter)=\"componentConfig.closeOnEnter && hideCalendar()\"\n [disabled]=\"disabled\"\n [ngModel]=\"inputElementValue\"\n [placeholder]=\"placeholder\"\n [readonly]=\"componentConfig.disableKeypress\"\n class=\"dp-picker-input\"\n type=\"text\"/>\n </div>\n <div #container>\n <div [attr.data-hidden]=\"!_areCalendarsShown\"\n [hidden]=\"!_areCalendarsShown\"\n [ngSwitch]=\"mode\"\n class=\"dp-popup {{theme}}\">\n <dp-day-calendar #dayCalendar\n (onGoToCurrent)=\"onGoToCurrent.emit()\"\n (onLeftNav)=\"onLeftNavClick($event)\"\n (onRightNav)=\"onRightNavClick($event)\"\n (onSelect)=\"dateSelected($event, 'day', selectEvent.SELECTION, false)\"\n *ngSwitchCase=\"'day'\"\n [config]=\"dayCalendarConfig\"\n [displayDate]=\"displayDate\"\n [ngModel]=\"_selected\"\n [theme]=\"theme\">\n </dp-day-calendar>\n\n <dp-month-calendar #monthCalendar\n (onGoToCurrent)=\"onGoToCurrent.emit()\"\n (onLeftNav)=\"onLeftNavClick($event)\"\n (onRightNav)=\"onRightNavClick($event)\"\n (onSelect)=\"dateSelected($event, 'month', selectEvent.SELECTION, false)\"\n *ngSwitchCase=\"'month'\"\n [config]=\"dayCalendarConfig\"\n [displayDate]=\"displayDate\"\n [ngModel]=\"_selected\"\n [theme]=\"theme\">\n </dp-month-calendar>\n\n <dp-time-select #timeSelect\n (onChange)=\"dateSelected($event, 'second', selectEvent.SELECTION, true)\"\n *ngSwitchCase=\"'time'\"\n [config]=\"timeSelectConfig\"\n [ngModel]=\"_selected && _selected[0]\"\n [theme]=\"theme\">\n </dp-time-select>\n\n <dp-day-time-calendar #daytimeCalendar\n (onChange)=\"dateSelected($event, 'second', selectEvent.SELECTION, true)\"\n (onGoToCurrent)=\"onGoToCurrent.emit()\"\n (onLeftNav)=\"onLeftNavClick($event)\"\n (onRightNav)=\"onRightNavClick($event)\"\n *ngSwitchCase=\"'daytime'\"\n [config]=\"dayTimeCalendarConfig\"\n [displayDate]=\"displayDate\"\n [ngModel]=\"_selected && _selected[0]\"\n [theme]=\"theme\">\n </dp-day-time-calendar>\n </div>\n </div>\n</div>\n", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [ DatePickerService, DayTimeCalendarService, DayCalendarService, TimeSelectService, { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DatePickerComponent_1), multi: true }, { provide: NG_VALIDATORS, useExisting: forwardRef(() => DatePickerComponent_1), multi: true } ], styles: ["dp-date-picker{display:inline-block}dp-date-picker.dp-material .dp-picker-input{box-sizing:border-box;height:30px;width:213px;font-size:13px;outline:0}dp-date-picker .dp-input-container{position:relative}dp-date-