UNPKG

@syncfusion/ej2-calendars

Version:

A complete package of date or time components with built-in features such as date formatting, inline editing, multiple (range) selection, range restriction, month and year selection, strict mode, and globalization.

1,088 lines (1,087 loc) 684 kB
import { Component, Internationalization, isNullOrUndefined, Browser, attributes, closest, addClass, removeClass, rippleEffect, EventHandler, getValue, getDefaultDateObject, cldrData, detach, L10n, extend, KeyboardEvents, getUniqueID, Property, Event, NotifyPropertyChanges, throwError, HijriParser, Touch, formatUnit, Animation, setValue, ChildProperty, merge, isUndefined, createElement, select, remove, prepend, Collection, append, setStyleAttribute } from '@syncfusion/ej2-base'; import { Popup } from '@syncfusion/ej2-popups'; import { Input } from '@syncfusion/ej2-inputs'; import { Button } from '@syncfusion/ej2-buttons'; import { ListBase } from '@syncfusion/ej2-lists'; var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; //class constant defination. const OTHERMONTH = 'e-other-month'; const OTHERDECADE = 'e-other-year'; const ROOT = 'e-calendar'; const DEVICE = 'e-device'; const HEADER = 'e-header'; const RTL = 'e-rtl'; const CONTENT = 'e-content'; const CONTENTTABLE = 'e-calendar-content-table'; const YEAR = 'e-year'; const MONTH = 'e-month'; const DECADE = 'e-decade'; const ICON = 'e-icons'; const PREVICON = 'e-prev'; const NEXTICON = 'e-next'; const PREVSPAN = 'e-date-icon-prev'; const NEXTSPAN = 'e-date-icon-next '; const ICONCONTAINER = 'e-icon-container'; const DISABLED = 'e-disabled'; const OVERLAY = 'e-overlay'; const WEEKEND = 'e-weekend'; const WEEKNUMBER = 'e-week-number'; const SELECTED = 'e-selected'; const FOCUSEDDATE = 'e-focused-date'; const FOCUSEDCELL = 'e-focused-cell'; const OTHERMONTHROW = 'e-month-hide'; const TODAY = 'e-today'; const TITLE = 'e-title'; const LINK = 'e-day'; const CELL = 'e-cell'; const WEEKHEADER = 'e-week-header'; const ZOOMIN = 'e-zoomin'; const FOOTER = 'e-footer-container'; const BTN = 'e-btn'; const FLAT = 'e-flat'; const CSS = 'e-css'; const PRIMARY = 'e-primary'; const DAYHEADERLONG = 'e-calendar-day-header-lg'; const dayMilliSeconds = 86400000; const minutesMilliSeconds = 60000; /** * * @private */ let CalendarBase = class CalendarBase extends Component { /** * Initialized new instance of Calendar Class. * Constructor for creating the widget * * @param {CalendarBaseModel} options - Specifies the CalendarBase model. * @param {string | HTMLElement} element - Specifies the element to render as component. * @private */ constructor(options, element) { super(options, element); this.effect = ''; this.isPopupClicked = false; this.isDateSelected = true; this.isTodayClicked = false; this.preventChange = false; this.previousDates = false; } /** * To Initialize the control rendering. * * @returns {void} * @private */ render() { this.rangeValidation(this.min, this.max); this.calendarEleCopy = this.element.cloneNode(true); if (this.calendarMode === 'Islamic') { if (+(this.min.setSeconds(0)) === +new Date(1900, 0, 1, 0, 0, 0)) { this.min = new Date(1944, 2, 18); } if (+this.max === +new Date(2099, 11, 31)) { this.max = new Date(2069, 10, 16); } } this.globalize = new Internationalization(this.locale); if (isNullOrUndefined(this.firstDayOfWeek) || this.firstDayOfWeek > 6 || this.firstDayOfWeek < 0) { this.setProperties({ firstDayOfWeek: this.globalize.getFirstDayOfWeek() }, true); } this.todayDisabled = false; this.todayDate = new Date(new Date().setHours(0, 0, 0, 0)); if (this.getModuleName() === 'calendar') { this.element.classList.add(ROOT); if (this.enableRtl) { this.element.classList.add(RTL); } if (Browser.isDevice) { this.element.classList.add(DEVICE); } attributes(this.element, { 'data-role': 'calendar' }); this.tabIndex = this.element.hasAttribute('tabindex') ? this.element.getAttribute('tabindex') : '0'; this.element.setAttribute('tabindex', this.tabIndex); } else { this.calendarElement = this.createElement('div'); this.calendarElement.classList.add(ROOT); if (this.enableRtl) { this.calendarElement.classList.add(RTL); } if (Browser.isDevice) { this.calendarElement.classList.add(DEVICE); } attributes(this.calendarElement, { 'data-role': 'calendar' }); } if (!isNullOrUndefined(closest(this.element, 'fieldset')) && closest(this.element, 'fieldset').disabled) { this.enabled = false; } this.createHeader(); this.createContent(); this.wireEvents(); } rangeValidation(min, max) { if (isNullOrUndefined(min)) { this.setProperties({ min: new Date(1900, 0, 1) }, true); } if (isNullOrUndefined(max)) { this.setProperties({ max: new Date(2099, 11, 31) }, true); } } getDefaultKeyConfig() { this.defaultKeyConfigs = { controlUp: 'ctrl+38', controlDown: 'ctrl+40', moveDown: 'downarrow', moveUp: 'uparrow', moveLeft: 'leftarrow', moveRight: 'rightarrow', select: 'enter', home: 'home', end: 'end', pageUp: 'pageup', pageDown: 'pagedown', shiftPageUp: 'shift+pageup', shiftPageDown: 'shift+pagedown', controlHome: 'ctrl+home', controlEnd: 'ctrl+end', altUpArrow: 'alt+uparrow', spacebar: 'space', altRightArrow: 'alt+rightarrow', altLeftArrow: 'alt+leftarrow' }; return this.defaultKeyConfigs; } validateDate(value) { this.setProperties({ min: this.checkDateValue(new Date(this.checkValue(this.min))) }, true); this.setProperties({ max: this.checkDateValue(new Date(this.checkValue(this.max))) }, true); this.currentDate = this.currentDate ? this.currentDate : new Date(new Date().setHours(0, 0, 0, 0)); if (!isNullOrUndefined(value) && this.min <= this.max && value >= this.min && value <= this.max) { this.currentDate = new Date(this.checkValue(value)); } } setOverlayIndex(popupWrapper, popupElement, modal, isDevice) { if (isDevice && !isNullOrUndefined(popupElement) && !isNullOrUndefined(modal) && !isNullOrUndefined(popupWrapper)) { const index = parseInt(popupElement.style.zIndex, 10) ? parseInt(popupElement.style.zIndex, 10) : 1000; modal.style.zIndex = (index - 1).toString(); popupWrapper.style.zIndex = index.toString(); } } minMaxUpdate(value) { if (!(+this.min <= +this.max)) { this.setProperties({ min: this.min }, true); addClass([this.element], OVERLAY); } else { removeClass([this.element], OVERLAY); } this.min = isNullOrUndefined(this.min) || !(+this.min) ? this.min = new Date(1900, 0, 1) : this.min; this.max = isNullOrUndefined(this.max) || !(+this.max) ? this.max = new Date(2099, 11, 31) : this.max; if (+this.min <= +this.max && value && +value <= +this.max && +value >= +this.min) { this.currentDate = new Date(this.checkValue(value)); } else { if (+this.min <= +this.max && !value && +this.currentDate > +this.max) { this.currentDate = new Date(this.checkValue(this.max)); } else { if (+this.currentDate < +this.min) { this.currentDate = new Date(this.checkValue(this.min)); } } } } createHeader() { const ariaPrevAttrs = { 'aria-disabled': 'false', 'aria-label': 'previous month' }; const ariaNextAttrs = { 'aria-disabled': 'false', 'aria-label': 'next month' }; const ariaTitleAttrs = { 'aria-atomic': 'true', 'aria-live': 'assertive', 'aria-label': 'title' }; const tabIndexAttr = { 'tabindex': '0' }; this.headerElement = this.createElement('div', { className: HEADER }); const iconContainer = this.createElement('div', { className: ICONCONTAINER }); this.previousIcon = this.createElement('button', { className: '' + PREVICON, attrs: { type: 'button' } }); rippleEffect(this.previousIcon, { duration: 400, selector: '.e-prev', isCenterRipple: true }); attributes(this.previousIcon, ariaPrevAttrs); attributes(this.previousIcon, tabIndexAttr); this.nextIcon = this.createElement('button', { className: '' + NEXTICON, attrs: { type: 'button' } }); rippleEffect(this.nextIcon, { selector: '.e-next', duration: 400, isCenterRipple: true }); if (this.getModuleName() === 'daterangepicker') { attributes(this.previousIcon, { tabIndex: '-1' }); attributes(this.nextIcon, { tabIndex: '-1' }); } attributes(this.nextIcon, ariaNextAttrs); attributes(this.nextIcon, tabIndexAttr); this.headerTitleElement = this.createElement('div', { className: '' + LINK + ' ' + TITLE }); attributes(this.headerTitleElement, ariaTitleAttrs); attributes(this.headerTitleElement, tabIndexAttr); this.headerElement.appendChild(this.headerTitleElement); this.previousIcon.appendChild(this.createElement('span', { className: '' + PREVSPAN + ' ' + ICON })); this.nextIcon.appendChild(this.createElement('span', { className: '' + NEXTSPAN + ' ' + ICON })); iconContainer.appendChild(this.previousIcon); iconContainer.appendChild(this.nextIcon); this.headerElement.appendChild(iconContainer); if (this.getModuleName() === 'calendar') { this.element.appendChild(this.headerElement); } else { this.calendarElement.appendChild(this.headerElement); } this.adjustLongHeaderSize(); } createContent() { this.contentElement = this.createElement('div', { className: CONTENT }); this.table = this.createElement('table', { attrs: { 'class': CONTENTTABLE, 'tabIndex': '0', 'role': 'grid', 'aria-activedescendant': '', 'aria-labelledby': this.element.id } }); if (this.getModuleName() === 'calendar') { this.element.appendChild(this.contentElement); } else { this.calendarElement.appendChild(this.contentElement); } this.contentElement.appendChild(this.table); this.createContentHeader(); this.createContentBody(); if (this.showTodayButton) { this.createContentFooter(); } if (this.getModuleName() !== 'daterangepicker') { EventHandler.add(this.table, 'focus', this.addContentFocus, this); EventHandler.add(this.table, 'blur', this.removeContentFocus, this); } } addContentFocus(args) { const focusedDate = this.tableBodyElement.querySelector('tr td.e-focused-date'); const selectedDate = this.tableBodyElement.querySelector('tr td.e-selected'); if (!isNullOrUndefined(selectedDate)) { selectedDate.classList.add(FOCUSEDCELL); } else if (!isNullOrUndefined(focusedDate)) { focusedDate.classList.add(FOCUSEDCELL); } } removeContentFocus(args) { const focusedDate = !isNullOrUndefined(this.tableBodyElement) ? this.tableBodyElement.querySelector('tr td.e-focused-date') : null; const selectedDate = !isNullOrUndefined(this.tableBodyElement) ? this.tableBodyElement.querySelector('tr td.e-selected') : null; if (!isNullOrUndefined(selectedDate)) { selectedDate.classList.remove(FOCUSEDCELL); } else if (!isNullOrUndefined(focusedDate)) { focusedDate.classList.remove(FOCUSEDCELL); } } getCultureValues() { const culShortNames = []; let cldrObj; const dayFormat = !isNullOrUndefined(this.dayHeaderFormat) ? 'days.stand-alone.' + this.dayHeaderFormat.toLowerCase() : null; if ((this.locale === 'en' || this.locale === 'en-US') && !isNullOrUndefined(dayFormat)) { cldrObj = (getValue(dayFormat, getDefaultDateObject())); } else { cldrObj = (this.getCultureObjects(cldrData, '' + this.locale)); } if (!isNullOrUndefined(cldrObj)) { for (const obj of Object.keys(cldrObj)) { culShortNames.push(getValue(obj, cldrObj)); } } return culShortNames; } toCapitalize(text) { return !isNullOrUndefined(text) && text.length ? text[0].toUpperCase() + text.slice(1) : text; } createContentHeader() { if (this.getModuleName() === 'calendar') { if (!isNullOrUndefined(this.element.querySelectorAll('.e-content .e-week-header')[0])) { detach(this.element.querySelectorAll('.e-content .e-week-header')[0]); } } else { if (!isNullOrUndefined(this.calendarElement.querySelectorAll('.e-content .e-week-header')[0])) { detach(this.calendarElement.querySelectorAll('.e-content .e-week-header')[0]); } } const daysCount = 6; let html = ''; if (this.firstDayOfWeek > 6 || this.firstDayOfWeek < 0) { this.setProperties({ firstDayOfWeek: 0 }, true); } this.tableHeadElement = this.createElement('thead', { className: WEEKHEADER }); if (this.weekNumber) { html += '<th class="e-week-number" aria-hidden="true"></th>'; if (this.getModuleName() === 'calendar') { addClass([this.element], '' + WEEKNUMBER); } else { addClass([this.calendarElement], '' + WEEKNUMBER); } } const shortNames = this.getCultureValues().length > 0 && this.getCultureValues() ? this.shiftArray(((this.getCultureValues().length > 0 && this.getCultureValues())), this.firstDayOfWeek) : null; if (!isNullOrUndefined(shortNames)) { for (let days = 0; days <= daysCount; days++) { html += '<th class="">' + this.toCapitalize(shortNames[days]) + '</th>'; } } html = '<tr>' + html + '</tr>'; this.tableHeadElement.innerHTML = html; this.table.appendChild(this.tableHeadElement); } createContentBody() { if (this.getModuleName() === 'calendar') { if (!isNullOrUndefined(this.element.querySelectorAll('.e-content tbody')[0])) { detach(this.element.querySelectorAll('.e-content tbody')[0]); } } else { if (!isNullOrUndefined(this.calendarElement.querySelectorAll('.e-content tbody')[0])) { detach(this.calendarElement.querySelectorAll('.e-content tbody')[0]); } } switch (this.start) { case 'Year': this.renderYears(); break; case 'Decade': this.renderDecades(); break; default: this.renderMonths(); } } updateFooter() { this.todayElement.textContent = this.l10.getConstant('today'); this.todayElement.setAttribute('aria-label', this.l10.getConstant('today')); this.todayElement.setAttribute('tabindex', '0'); } createContentFooter() { if (this.showTodayButton) { const minimum = new Date(+this.min); const maximum = new Date(+this.max); const l10nLocale = { today: 'Today' }; this.globalize = new Internationalization(this.locale); this.l10 = new L10n(this.getModuleName(), l10nLocale, this.locale); this.todayElement = this.createElement('button', { attrs: { role: 'button' } }); rippleEffect(this.todayElement); this.updateFooter(); addClass([this.todayElement], [BTN, TODAY, FLAT, PRIMARY, CSS]); if ((!(+new Date(minimum.setHours(0, 0, 0, 0)) <= +this.todayDate && +this.todayDate <= +new Date(maximum.setHours(0, 0, 0, 0)))) || (this.todayDisabled)) { addClass([this.todayElement], DISABLED); } this.footer = this.createElement('div', { className: FOOTER }); this.footer.appendChild(this.todayElement); if (this.getModuleName() === 'calendar') { this.element.appendChild(this.footer); } if (this.getModuleName() === 'datepicker') { this.calendarElement.appendChild(this.footer); } if (this.getModuleName() === 'datetimepicker') { this.calendarElement.appendChild(this.footer); } if (!this.todayElement.classList.contains(DISABLED)) { EventHandler.add(this.todayElement, 'click', this.todayButtonClick, this); } } } wireEvents(id, ref, keyConfig, moduleName) { EventHandler.add(this.headerTitleElement, 'click', this.navigateTitle, this); this.defaultKeyConfigs = extend(this.defaultKeyConfigs, this.keyConfigs); if (this.getModuleName() === 'calendar') { this.keyboardModule = new KeyboardEvents(this.element, { eventName: 'keydown', keyAction: this.keyActionHandle.bind(this), keyConfigs: this.defaultKeyConfigs }); } else { this.keyboardModule = new KeyboardEvents(this.calendarElement, { eventName: 'keydown', keyAction: this.keyActionHandle.bind(this), keyConfigs: this.defaultKeyConfigs }); } } dateWireEvents(id, ref, keyConfig, moduleName) { this.defaultKeyConfigs = this.getDefaultKeyConfig(); this.defaultKeyConfigs = extend(this.defaultKeyConfigs, keyConfig); this.serverModuleName = moduleName; } todayButtonClick(e, value, isCustomDate) { if (this.showTodayButton) { if (this.currentView() === this.depth) { this.effect = ''; } else { this.effect = 'e-zoomin'; } if (this.getViewNumber(this.start) >= this.getViewNumber(this.depth)) { this.navigateTo(this.depth, new Date(this.checkValue(value)), isCustomDate); } else { this.navigateTo('Month', new Date(this.checkValue(value)), isCustomDate); } } } resetCalendar() { this.calendarElement && detach(this.calendarElement); this.tableBodyElement && detach(this.tableBodyElement); this.table && detach(this.table); this.tableHeadElement && detach(this.tableHeadElement); this.nextIcon && detach(this.nextIcon); this.previousIcon && detach(this.previousIcon); this.footer && detach(this.footer); this.todayElement = null; this.renderDayCellArgs = null; this.calendarElement = this.tableBodyElement = this.footer = this.tableHeadElement = this.nextIcon = this.previousIcon = this.table = null; } keyActionHandle(e, value, multiSelection) { if (this.calendarElement === null && e.action === 'escape') { return; } const focusedDate = this.tableBodyElement.querySelector('tr td.e-focused-date'); let selectedDate; if (multiSelection) { if (!isNullOrUndefined(focusedDate) && +value === parseInt(focusedDate.getAttribute('id').split('_')[0], 10)) { selectedDate = focusedDate; } else { selectedDate = this.tableBodyElement.querySelector('tr td.e-selected'); } } else { selectedDate = this.tableBodyElement.querySelector('tr td.e-selected'); } let view = this.getViewNumber(this.currentView()); const depthValue = this.getViewNumber(this.depth); const levelRestrict = (view === depthValue && this.getViewNumber(this.start) >= depthValue); this.effect = ''; switch (e.action) { case 'moveLeft': if (this.getModuleName() !== 'daterangepicker' && !isNullOrUndefined(e.target)) { this.keyboardNavigate(-1, view, e, this.max, this.min); e.preventDefault(); } break; case 'moveRight': if (this.getModuleName() !== 'daterangepicker' && !isNullOrUndefined(e.target)) { this.keyboardNavigate(1, view, e, this.max, this.min); e.preventDefault(); } break; case 'moveUp': if (this.getModuleName() !== 'daterangepicker' && !isNullOrUndefined(e.target)) { if (view === 0) { this.keyboardNavigate(-7, view, e, this.max, this.min); // move the current date to the previous seven days. } else { this.keyboardNavigate(-4, view, e, this.max, this.min); // move the current year to the previous four days. } e.preventDefault(); } break; case 'moveDown': if (this.getModuleName() !== 'daterangepicker' && !isNullOrUndefined(e.target)) { if (view === 0) { this.keyboardNavigate(7, view, e, this.max, this.min); } else { this.keyboardNavigate(4, view, e, this.max, this.min); } e.preventDefault(); } break; case 'select': if (e.target === this.headerTitleElement) { this.navigateTitle(e); } else if (e.target === this.previousIcon && !e.target.className.includes(DISABLED)) { this.navigatePrevious(e); } else if (e.target === this.nextIcon && !e.target.className.includes(DISABLED)) { this.navigateNext(e); } else if (e.target === this.todayElement && !e.target.className.includes(DISABLED)) { this.todayButtonClick(e, value); if (this.getModuleName() === 'datepicker' || this.getModuleName() === 'datetimepicker') { if (this.isAngular) { this.inputElement.focus(); } else { this.element.focus(); } } } else { const element = !isNullOrUndefined(focusedDate) ? focusedDate : selectedDate; if (!isNullOrUndefined(element) && !element.classList.contains(DISABLED)) { if (levelRestrict) { // eslint-disable-next-line radix const d = new Date(parseInt('' + (element).id, 0)); this.selectDate(e, d, (element)); if (this.getModuleName() === 'datepicker' || this.getModuleName() === 'datetimepicker') { if (this.isAngular) { this.inputElement.focus(); } else { this.element.focus(); } } } else { if (!e.target.className.includes(DISABLED)) { this.contentClick(null, --view, (element), value); } } } } break; case 'controlUp': this.title(); e.preventDefault(); break; case 'controlDown': if (!isNullOrUndefined(focusedDate) && !levelRestrict || !isNullOrUndefined(selectedDate) && !levelRestrict) { this.contentClick(null, --view, (focusedDate || selectedDate), value); } e.preventDefault(); break; case 'home': this.currentDate = this.firstDay(this.currentDate); detach(this.tableBodyElement); if (view === 0) { this.renderMonths(e); } else if (view === 1) { this.renderYears(e); } else { this.renderDecades(e); } e.preventDefault(); break; case 'end': this.currentDate = this.lastDay(this.currentDate, view); detach(this.tableBodyElement); if (view === 0) { this.renderMonths(e); } else if (view === 1) { this.renderYears(e); } else { this.renderDecades(e); } e.preventDefault(); break; case 'pageUp': this.addMonths(this.currentDate, -1); this.navigateTo('Month', this.currentDate); e.preventDefault(); break; case 'pageDown': this.addMonths(this.currentDate, 1); this.navigateTo('Month', this.currentDate); e.preventDefault(); break; case 'shiftPageUp': this.addYears(this.currentDate, -1); this.navigateTo('Month', this.currentDate); e.preventDefault(); break; case 'shiftPageDown': this.addYears(this.currentDate, 1); this.navigateTo('Month', this.currentDate); e.preventDefault(); break; case 'controlHome': this.navigateTo('Month', new Date(this.currentDate.getFullYear(), 0, 1)); e.preventDefault(); break; case 'controlEnd': this.navigateTo('Month', new Date(this.currentDate.getFullYear(), 11, 31)); e.preventDefault(); break; case 'tab': if ((this.getModuleName() === 'datepicker' || this.getModuleName() === 'datetimepicker') && e.target === this.todayElement) { e.preventDefault(); if (this.isAngular) { this.inputElement.focus(); } else { this.element.focus(); } this.hide(); } break; case 'shiftTab': if ((this.getModuleName() === 'datepicker' || this.getModuleName() === 'datetimepicker') && e.target === this.headerTitleElement) { e.preventDefault(); if (this.isAngular) { this.inputElement.focus(); } else { this.element.focus(); } this.hide(); } break; case 'escape': if ((this.getModuleName() === 'datepicker' || this.getModuleName() === 'datetimepicker') && (e.target === this.headerTitleElement || e.target === this.previousIcon || e.target === this.nextIcon || e.target === this.todayElement)) { this.hide(); } break; } } keyboardNavigate(number, currentView, e, max, min) { const date = new Date(this.checkValue(this.currentDate)); switch (currentView) { case 2: this.addYears(this.currentDate, number); if (this.isMonthYearRange(this.currentDate)) { detach(this.tableBodyElement); this.renderDecades(e); } else { this.currentDate = date; } break; case 1: this.addMonths(this.currentDate, number); if (this.calendarMode === 'Gregorian') { if (this.isMonthYearRange(this.currentDate)) { detach(this.tableBodyElement); this.renderYears(e); } else { this.currentDate = date; } } else { if (this.isMonthYearRange(this.currentDate)) { detach(this.tableBodyElement); this.renderYears(e); } else { this.currentDate = date; } } break; case 0: this.addDay(this.currentDate, number, e, max, min); if (this.isMinMaxRange(this.currentDate)) { detach(this.tableBodyElement); this.renderMonths(e); } else { this.currentDate = date; } break; } } /** * Initialize the event handler * * @param {Date} value - Specifies value of date. * @returns {void} * @private */ // eslint-disable-next-line @typescript-eslint/no-unused-vars preRender(value) { this.navigatePreviousHandler = this.navigatePrevious.bind(this); this.navigateNextHandler = this.navigateNext.bind(this); this.defaultKeyConfigs = this.getDefaultKeyConfig(); this.navigateHandler = (e) => { this.triggerNavigate(e); }; } minMaxDate(localDate) { const currentDate = new Date(new Date(+localDate).setHours(0, 0, 0, 0)); const minDate = new Date(new Date(+this.min).setHours(0, 0, 0, 0)); const maxDate = new Date(new Date(+this.max).setHours(0, 0, 0, 0)); if (+currentDate === +minDate || +currentDate === +maxDate) { if (+localDate < +this.min) { localDate = new Date(+this.min); } if (+localDate > +this.max) { localDate = new Date(+this.max); } } return localDate; } renderMonths(e, value, isCustomDate) { const numCells = this.weekNumber ? 8 : 7; let tdEles; if (this.calendarMode === 'Gregorian') { tdEles = this.renderDays(this.currentDate, value, null, null, isCustomDate, e); } else { tdEles = !isNullOrUndefined(this.islamicModule) ? this.islamicModule.islamicRenderDays(this.currentDate, value) : null; } this.createContentHeader(); if (this.calendarMode === 'Gregorian') { this.renderTemplate(tdEles, numCells, MONTH, e, value); } else if (!isNullOrUndefined(this.islamicModule)) { this.islamicModule.islamicRenderTemplate(tdEles, numCells, MONTH, e, value); } } renderDays(currentDate, value, multiSelection, values, isTodayDate, e) { const tdEles = []; const cellsCount = 42; const todayDate = isTodayDate ? new Date(+currentDate) : this.getDate(new Date(), this.timezone); let localDate = new Date(this.checkValue(currentDate)); let minMaxDate; const currentMonth = localDate.getMonth(); this.titleUpdate(currentDate, 'days'); const d = localDate; localDate = new Date(d.getFullYear(), d.getMonth(), 0, d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()); while (localDate.getDay() !== this.firstDayOfWeek) { this.setStartDate(localDate, -1 * dayMilliSeconds); } for (let day = 0; day < cellsCount; ++day) { const weekEle = this.createElement('td', { className: CELL }); const weekAnchor = this.createElement('span'); if (day % 7 === 0 && this.weekNumber) { // 6 days are added to get Last day of the week and 3 days are added to get middle day of the week. const numberOfDays = this.weekRule === 'FirstDay' ? 6 : (this.weekRule === 'FirstFourDayWeek' ? 3 : 0); const finalDate = new Date(localDate.getFullYear(), localDate.getMonth(), (localDate.getDate() + numberOfDays)); weekAnchor.textContent = '' + this.getWeek(finalDate); weekEle.appendChild(weekAnchor); addClass([weekEle], '' + WEEKNUMBER); tdEles.push(weekEle); } minMaxDate = new Date(+localDate); localDate = this.minMaxDate(localDate); const dateFormatOptions = { type: 'dateTime', skeleton: 'full' }; const date = this.globalize.parseDate(this.globalize.formatDate(localDate, dateFormatOptions), dateFormatOptions); const tdEle = this.dayCell(localDate); const title = this.globalize.formatDate(localDate, { type: 'date', skeleton: 'full' }); const dayLink = this.createElement('span'); dayLink.textContent = this.globalize.formatDate(localDate, { format: 'd', type: 'date', skeleton: 'yMd' }); const disabled = (this.min > localDate) || (this.max < localDate); if (disabled) { addClass([tdEle], DISABLED); addClass([tdEle], OVERLAY); } else { dayLink.setAttribute('title', '' + title); } if (currentMonth !== localDate.getMonth()) { addClass([tdEle], OTHERMONTH); dayLink.setAttribute('aria-disabled', 'true'); } if (localDate.getDay() === 0 || localDate.getDay() === 6) { addClass([tdEle], WEEKEND); } tdEle.appendChild(dayLink); this.renderDayCellArgs = { date: localDate, isDisabled: false, element: tdEle, isOutOfRange: disabled }; const argument = this.renderDayCellArgs; this.renderDayCellEvent(argument); if (argument.isDisabled) { const selectDate = new Date(this.checkValue(value)); const argsDate = new Date(this.checkValue(argument.date)); if (multiSelection) { if (!isNullOrUndefined(values) && values.length > 0) { for (let index = 0; index < values.length; index++) { const localDateString = +new Date(this.globalize.formatDate(argument.date, { type: 'date', skeleton: 'yMd' })); const tempDateString = +new Date(this.globalize.formatDate(values[index], { type: 'date', skeleton: 'yMd' })); if (localDateString === tempDateString) { values.splice(index, 1); index = -1; } } } } else if (selectDate && +selectDate === +argsDate) { this.setProperties({ value: null }, true); } } if (this.renderDayCellArgs.isDisabled && !tdEle.classList.contains(SELECTED)) { addClass([tdEle], DISABLED); addClass([tdEle], OVERLAY); dayLink.setAttribute('aria-disabled', 'true'); if (+this.renderDayCellArgs.date === +this.todayDate) { this.todayDisabled = true; } } const otherMnthBool = tdEle.classList.contains(OTHERMONTH); const disabledCls = tdEle.classList.contains(DISABLED); if (!disabledCls) { EventHandler.add(tdEle, 'click', this.clickHandler, this); } // to set the value as null while setting the disabled date onProperty change. // if (args.isDisabled && +this.value === +args.date) { // this.setProperties({ value: null }, true); // } let currentTarget; if (!isNullOrUndefined(e) && e.type === 'click') { currentTarget = e.currentTarget; } if (multiSelection && !isNullOrUndefined(values) && !disabledCls) { for (let tempValue = 0; tempValue < values.length; tempValue++) { const type = (this.calendarMode === 'Gregorian') ? 'gregorian' : 'islamic'; const formatOptions = { format: null, type: 'date', skeleton: 'short', calendar: type }; const localDateString = this.globalize.formatDate(localDate, formatOptions); const tempDateString = this.globalize.formatDate(values[tempValue], formatOptions); if ((localDateString === tempDateString && this.getDateVal(localDate, values[tempValue])) || (this.getDateVal(localDate, value))) { addClass([tdEle], SELECTED); } if (!isNullOrUndefined(currentTarget) && currentTarget.innerText === tdEle.innerText && this.previousDates && tdEle.classList.contains(SELECTED) && currentTarget.classList.contains(SELECTED)) { removeClass([tdEle], SELECTED); this.previousDates = false; const copyValues = this.copyValues(values); for (let i = 0; i < copyValues.length; i++) { const type = (this.calendarMode === 'Gregorian') ? 'gregorian' : 'islamic'; const formatOptions = { format: null, type: 'date', skeleton: 'short', calendar: type }; const localDateString = this.globalize.formatDate(date, formatOptions); const tempDateString = this.globalize.formatDate(copyValues[i], formatOptions); if (localDateString === tempDateString) { const index = copyValues.indexOf(copyValues[i]); copyValues.splice(index, 1); values.splice(index, 1); } } this.setProperties({ values: copyValues }, true); } else { this.updateFocus(otherMnthBool, disabledCls, localDate, tdEle, currentDate); } } if (values.length <= 0) { this.updateFocus(otherMnthBool, disabledCls, localDate, tdEle, currentDate); } } else if (!disabledCls && this.getDateVal(localDate, value)) { addClass([tdEle], SELECTED); } this.updateFocus(otherMnthBool, disabledCls, localDate, tdEle, currentDate); if (!isNullOrUndefined(date) && date.getFullYear() === todayDate.getFullYear() && date.getMonth() === todayDate.getMonth() && date.getDate() === todayDate.getDate()) { addClass([tdEle], TODAY); } tdEles.push(this.renderDayCellArgs.element); localDate = new Date(+minMaxDate); this.addDay(localDate, 1, null, this.max, this.min); } return tdEles; } updateFocus(otherMonth, disabled, localDate, tableElement, currentDate) { if (currentDate.getDate() === localDate.getDate() && !otherMonth && !disabled) { addClass([tableElement], FOCUSEDDATE); } else { // eslint-disable-next-line radix if (currentDate >= this.max && parseInt(tableElement.id, 0) === +this.max && !otherMonth && !disabled) { addClass([tableElement], FOCUSEDDATE); } // eslint-disable-next-line radix if (currentDate <= this.min && parseInt(tableElement.id, 0) === +this.min && !otherMonth && !disabled) { addClass([tableElement], FOCUSEDDATE); } } } renderYears(e, value) { this.removeTableHeadElement(); const numCells = 4; const tdEles = []; const valueUtil = isNullOrUndefined(value); const curDate = new Date(this.checkValue(this.currentDate)); const mon = curDate.getMonth(); const yr = curDate.getFullYear(); const localDate = curDate; const curYrs = localDate.getFullYear(); const minYr = new Date(this.checkValue(this.min)).getFullYear(); const minMonth = new Date(this.checkValue(this.min)).getMonth(); const maxYr = new Date(this.checkValue(this.max)).getFullYear(); const maxMonth = new Date(this.checkValue(this.max)).getMonth(); localDate.setMonth(0); this.titleUpdate(this.currentDate, 'months'); localDate.setDate(1); for (let month = 0; month < 12; ++month) { const tdEle = this.dayCell(localDate); const dayLink = this.createElement('span'); const localMonth = (value && (value).getMonth() === localDate.getMonth()); const select = (value && (value).getFullYear() === yr && localMonth); const title = this.globalize.formatDate(localDate, { type: 'date', format: 'MMM y' }); dayLink.textContent = this.toCapitalize(this.globalize.formatDate(localDate, { format: null, type: 'dateTime', skeleton: 'MMM' })); if ((this.min && (curYrs < minYr || (month < minMonth && curYrs === minYr))) || (this.max && (curYrs > maxYr || (month > maxMonth && curYrs >= maxYr)))) { addClass([tdEle], DISABLED); } else if (!valueUtil && select) { addClass([tdEle], SELECTED); } else { if (localDate.getMonth() === mon && this.currentDate.getMonth() === mon) { addClass([tdEle], FOCUSEDDATE); } } localDate.setDate(1); localDate.setMonth(localDate.getMonth() + 1); if (!tdEle.classList.contains(DISABLED)) { EventHandler.add(tdEle, 'click', this.clickHandler, this); dayLink.setAttribute('title', '' + title); } tdEle.appendChild(dayLink); tdEles.push(tdEle); } this.renderTemplate(tdEles, numCells, YEAR, e, value); } renderDecades(e, value) { this.removeTableHeadElement(); const numCells = 4; const yearCell = 12; const tdEles = []; const localDate = new Date(this.checkValue(this.currentDate)); localDate.setMonth(0); localDate.setDate(1); const localYr = localDate.getFullYear(); const startYr = new Date(localDate.setFullYear((localYr - localYr % 10))); const endYr = new Date(localDate.setFullYear((localYr - localYr % 10 + (10 - 1)))); const startFullYr = startYr.getFullYear(); const endFullYr = endYr.getFullYear(); const startHdrYr = this.globalize.formatDate(startYr, { format: null, type: 'dateTime', skeleton: 'y' }); const endHdrYr = this.globalize.formatDate(endYr, { format: null, type: 'dateTime', skeleton: 'y' }); this.headerTitleElement.textContent = startHdrYr + ' - ' + (endHdrYr); const start = new Date(localYr - (localYr % 10) - 1, 0, 1); const startYear = start.getFullYear(); for (let rowIterator = 0; rowIterator < yearCell; ++rowIterator) { const year = startYear + rowIterator; localDate.setFullYear(year); const tdEle = this.dayCell(localDate); const dayLink = this.createElement('span'); dayLink.textContent = this.globalize.formatDate(localDate, { format: null, type: 'dateTime', skeleton: 'y' }); if ((year < startFullYr) || (year > endFullYr)) { addClass([tdEle], OTHERDECADE); dayLink.setAttribute('aria-disabled', 'true'); if (!isNullOrUndefined(value) && localDate.getFullYear() === (value).getFullYear()) { addClass([tdEle], SELECTED); } if (year < new Date(this.checkValue(this.min)).getFullYear() || year > new Date(this.checkValue(this.max)).getFullYear()) { addClass([tdEle], DISABLED); } } else if (year < new Date(this.checkValue(this.min)).getFullYear() || year > new Date(this.checkValue(this.max)).getFullYear()) { addClass([tdEle], DISABLED); } else if (!isNullOrUndefined(value) && localDate.getFullYear() === (value).getFullYear()) { addClass([tdEle], SELECTED); } else { if (localDate.getFullYear() === this.currentDate.getFullYear() && !tdEle.classList.contains(DISABLED)) { addClass([tdEle], FOCUSEDDATE); } } if (!tdEle.classList.contains(DISABLED)) { EventHandler.add(tdEle, 'click', this.clickHandler, this); dayLink.setAttribute('title', '' + dayLink.textContent); } tdEle.appendChild(dayLink); tdEles.push(tdEle); } this.renderTemplate(tdEles, numCells, 'e-decade', e, value); } dayCell(localDate) { const type = (this.calendarMode === 'Gregorian') ? 'gregorian' : 'islamic'; const dateFormatOptions = { skeleton: 'full', type: 'dateTime', calendar: type }; const date = this.globalize.parseDate(this.globalize.formatDate(localDate, dateFormatOptions), dateFormatOptions); let value; if (!isNullOrUndefined(date)) { value = date.valueOf(); } const attrs = { className: CELL, attrs: { 'id': '' + getUniqueID('' + value), 'aria-selected': 'false' } }; return this.createElement('td', attrs); } firstDay(date) { const collection = this.currentView() !== 'Decade' ? this.tableBodyElement.querySelectorAll('td:not(.' + OTHERMONTH + '):not(.' + WEEKNUMBER + ')') : this.tableBodyElement.querySelectorAll('td' + ':not(.' + OTHERDECADE + ''); if (collection.length) { for (let i = 0; i < collection.length; i++) { if (!collection[i].classList.contains(DISABLED)) { // eslint-disable-next-line radix date = new Date(parseInt(collection[i].id, 0)); break; } } } return date; } lastDay(date, view) { const lastDate = new Date(date.getFullYear(), date.getMonth() + 1, 0); if (view !== 2) { const timeOffset = Math.abs(lastDate.getTimezoneOffset() - this.firstDay(date).getTimezoneOffset()); if (timeOffset) { lastDate.setHours(this.firstDay(date).getHours() + (timeOffset / 60)); } return this.findLastDay(lastDate); } else { return this.findLastDay(this.firstDay(lastDate)); } } checkDateValue(value) { return (!isNullOrUndefined(value) && value instanceof Date && !isNaN(+value)) ? value : null; } findLastDay(date) { const collection = this.currentView() === 'Decade' ? this.tableBodyElement.querySelectorAll('td' + ':not(.' + OTHERDECADE + '') : this.tableBodyElement.querySelectorAll('td:not(.' + OTHERMONTH + '):not(.' + WEEKNUMBER + ')'); if (collection.length) { for (let i = collection.length - 1; i >= 0; i--) { if (!collection[i].classList.contains(DISABLED)) { // eslint-disable-next-line radix date = new Date(parseInt(collection[i].id, 0)); break; } } } return date; } removeTableHeadElement() { if (this.getModuleName() === 'calendar') { if (!isNullOrUndefined(this.element.querySelectorAll('.e-content table thead')[0])) { detach(this.tableHeadElement); } } else { if (!isNullOrU