UNPKG

fundamental-ngx

Version:

SAP Fiori Fundamentals, implemented in Angular

1,233 lines 160 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Component, EventEmitter, Input, Output, HostListener, ElementRef, forwardRef, ChangeDetectorRef, HostBinding, ViewEncapsulation } from '@angular/core'; import { HashService } from '../utils/hash.service'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { Subject } from 'rxjs'; import { CalendarI18n } from './i18n/calendar-i18n'; import { CalendarI18nLabels } from './i18n/calendar-i18n-labels'; import { DateFormatParser } from './format/date-parser'; /** * @record */ export function CalendarDay() { } if (false) { /** @type {?} */ CalendarDay.prototype.date; /** @type {?|undefined} */ CalendarDay.prototype.day; /** @type {?|undefined} */ CalendarDay.prototype.weekDay; /** @type {?|undefined} */ CalendarDay.prototype.monthStatus; /** @type {?|undefined} */ CalendarDay.prototype.disabled; /** @type {?|undefined} */ CalendarDay.prototype.blocked; /** @type {?|undefined} */ CalendarDay.prototype.selected; /** @type {?|undefined} */ CalendarDay.prototype.selectedFirst; /** @type {?|undefined} */ CalendarDay.prototype.selectedRange; /** @type {?|undefined} */ CalendarDay.prototype.selectedLast; /** @type {?|undefined} */ CalendarDay.prototype.today; /** @type {?|undefined} */ CalendarDay.prototype.isTabIndexed; /** @type {?|undefined} */ CalendarDay.prototype.ariaLabel; } /** * @record */ export function EmittedDate() { } if (false) { /** @type {?|undefined} */ EmittedDate.prototype.selectedDay; /** @type {?|undefined} */ EmittedDate.prototype.selectedFirstDay; /** @type {?|undefined} */ EmittedDate.prototype.selectedLastDay; } export class CalendarComponent { /** * @param {?} hasher * @param {?} eRef * @param {?} cd * @param {?} calendarI18nLabels * @param {?} calendarI18n * @param {?} dateAdapter */ constructor(hasher, eRef, cd, calendarI18nLabels, calendarI18n, dateAdapter) { this.hasher = hasher; this.eRef = eRef; this.cd = cd; this.calendarI18nLabels = calendarI18nLabels; this.calendarI18n = calendarI18n; this.dateAdapter = dateAdapter; this.init = false; this.fdCalendarClass = true; this.calType = 'single'; this.startingDayOfWeek = 0; this.isInvalidDateInput = new EventEmitter(); this.isDateTimePicker = false; this.invalidDate = false; this.showCalendarMonths = false; this.showCalendarYears = false; this.showCalendarDates = true; this.daysPerMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; this.calendarGrid = []; this.calendarYearsList = []; this.today = new Date(); this.todayMonth = this.today.getMonth(); this.todayYear = this.today.getFullYear(); this.date = new Date(); this.month = this.date.getMonth(); this.year = this.date.getFullYear(); this.day = this.date.getDate(); this.firstYearCalendarList = this.year; this.selectCounter = 0; this.selectedDay = { date: null }; this.selectedDayChange = new EventEmitter(); this.selectedRangeFirst = { date: null }; this.selectedRangeFirstChange = new EventEmitter(); this.selectedRangeLast = { date: null }; this.selectedRangeLastChange = new EventEmitter(); this.emittedDate = { selectedDay: this.selectedDay, selectedFirstDay: this.selectedRangeFirst, selectedLastDay: this.selectedRangeLast }; this.closeCalendar = new EventEmitter(); this.disableFunction = (/** * @param {?} d * @return {?} */ function (d) { return false; }); this.disableRangeStartFunction = (/** * @param {?} d * @return {?} */ function (d) { return false; }); this.disableRangeEndFunction = (/** * @param {?} d * @return {?} */ function (d) { return false; }); this.blockRangeStartFunction = (/** * @param {?} d * @return {?} */ function (d) { return false; }); this.blockRangeEndFunction = (/** * @param {?} d * @return {?} */ function (d) { return false; }); this.blockFunction = (/** * @param {?} d * @return {?} */ function (d) { return false; }); this.onChange = (/** * @return {?} */ () => { }); this.onTouched = (/** * @return {?} */ () => { }); // A function that determines the number of days in a particular month this.determineDaysInMonth = (/** * @param {?} month * @param {?} year * @return {?} */ function (month, year) { if (month === 1) { if ((year % 100 !== 0 && year % 4 === 0) || year % 400 === 0) { return 29; } else { return this.daysPerMonth[month]; } } else { return this.daysPerMonth[month]; } }); } /** * @return {?} */ setWeekDaysOrder() { this.weekDays = this.calendarI18n.getAllShortWeekdays().map((/** * @param {?} item * @return {?} */ item => item[0])); if (this.startingDayOfWeek <= 6 && this.startingDayOfWeek >= 0) { for (let i = this.startingDayOfWeek; i > 0; i--) { this.weekDays.push(this.weekDays.shift()); } } } /** * @param {?} calendarMonth * @return {?} */ getPreviousMonthDays(calendarMonth) { // Previous month days /** @type {?} */ let prevMonthLastDate; this.setWeekDaysOrder(); prevMonthLastDate = new Date(this.date.getFullYear(), this.date.getMonth(), 0); /** @type {?} */ const prevMonth = prevMonthLastDate.getMonth(); /** @type {?} */ const prevMonthYear = prevMonthLastDate.getFullYear(); /** @type {?} */ const prevMonthLastDay = prevMonthLastDate.getDate(); /** @type {?} */ let prevMonthLastWeekDay = prevMonthLastDate.getDay() - this.startingDayOfWeek; if (prevMonthLastWeekDay < 6) { while (prevMonthLastWeekDay >= 0) { /** @type {?} */ const prevMonthDay = prevMonthLastDay - prevMonthLastWeekDay; /** @type {?} */ const calDate = new Date(prevMonthYear, prevMonth, prevMonthDay); /** @type {?} */ const previousMonthCalendarDay = { date: calDate, day: calDate.getDate(), weekDay: calDate.getDay(), monthStatus: 'previous', disabled: this.disableFunction(calDate), blocked: this.blockFunction(calDate), selected: (this.selectedDay.date && calDate.toDateString() === this.selectedDay.date.toDateString()) || (this.selectedRangeFirst.date && calDate.toDateString() === this.selectedRangeFirst.date.toDateString()) || (this.selectedRangeLast.date && calDate.toDateString() === this.selectedRangeLast.date.toDateString()), selectedFirst: this.selectedRangeFirst.date && calDate.toDateString() === this.selectedRangeFirst.date.toDateString(), selectedLast: this.selectedRangeLast.date && calDate.toDateString() === this.selectedRangeLast.date.toDateString(), selectedRange: this.selectedRangeFirst.date && calDate.getTime() > this.selectedRangeFirst.date.getTime() && this.selectedRangeLast.date && calDate.getTime() < this.selectedRangeLast.date.getTime(), ariaLabel: this.calendarI18n.getDayAriaLabel(calDate) }; if (this.selectCounter === 0) { if (this.disableRangeStartFunction && !previousMonthCalendarDay.disabled) { previousMonthCalendarDay.disabled = this.disableRangeStartFunction(calDate); } if (this.blockRangeStartFunction && !previousMonthCalendarDay.blocked) { previousMonthCalendarDay.blocked = this.blockRangeStartFunction(calDate); } } else if (this.selectCounter === 1) { if (this.disableRangeEndFunction && !previousMonthCalendarDay.disabled) { previousMonthCalendarDay.disabled = this.disableRangeEndFunction(calDate); } if (this.blockRangeEndFunction && !previousMonthCalendarDay.blocked) { previousMonthCalendarDay.blocked = this.blockRangeEndFunction(calDate); } } calendarMonth.push(previousMonthCalendarDay); prevMonthLastWeekDay--; } } return calendarMonth; } /** * @param {?} calendarMonth * @return {?} */ getCurrentMonthDays(calendarMonth) { /** @type {?} */ const numOfDaysInCurrentMonth = this.determineDaysInMonth(this.month, this.year); // Current month days /** @type {?} */ let foundSelected = false; for (let d = 1; d <= numOfDaysInCurrentMonth; d++) { /** @type {?} */ const calDate = new Date(this.date.getFullYear(), this.date.getMonth(), d); /** @type {?} */ const currMonthCalendarDay = { date: calDate, day: calDate.getDate(), weekDay: calDate.getDay(), monthStatus: 'current', disabled: this.disableFunction(calDate), blocked: this.blockFunction(calDate), selected: (this.selectedDay.date && calDate.toDateString() === this.selectedDay.date.toDateString()) || (this.selectedRangeFirst.date && calDate.toDateString() === this.selectedRangeFirst.date.toDateString()) || (this.selectedRangeLast.date && calDate.toDateString() === this.selectedRangeLast.date.toDateString()), selectedFirst: this.selectedRangeFirst.date && calDate.toDateString() === this.selectedRangeFirst.date.toDateString(), selectedLast: this.selectedRangeLast.date && calDate.toDateString() === this.selectedRangeLast.date.toDateString(), selectedRange: this.selectedRangeFirst.date && calDate.getTime() > this.selectedRangeFirst.date.getTime() && this.selectedRangeLast.date && calDate.getTime() < this.selectedRangeLast.date.getTime(), today: calDate.toDateString() === this.today.toDateString(), isTabIndexed: false, ariaLabel: this.calendarI18n.getDayAriaLabel(calDate) }; if (this.selectCounter === 0 || this.selectCounter === 2) { if (this.disableRangeStartFunction && !currMonthCalendarDay.disabled) { currMonthCalendarDay.disabled = this.disableRangeStartFunction(calDate); } if (this.blockRangeStartFunction && !currMonthCalendarDay.blocked) { currMonthCalendarDay.blocked = this.blockRangeStartFunction(calDate); } } else if (this.selectCounter === 1) { if (this.disableRangeEndFunction && !currMonthCalendarDay.disabled) { currMonthCalendarDay.disabled = this.disableRangeEndFunction(calDate); } if (this.blockRangeEndFunction && !currMonthCalendarDay.blocked) { currMonthCalendarDay.blocked = this.blockRangeEndFunction(calDate); } } // if a day is selected, it should be tab indexed if (currMonthCalendarDay.selected) { foundSelected = true; currMonthCalendarDay.isTabIndexed = true; } calendarMonth.push(currMonthCalendarDay); } if (!foundSelected) { /** @type {?} */ let foundToday = false; for (let d = 0; d < numOfDaysInCurrentMonth; d++) { // if no day is selected, tab index today if (calendarMonth[d] && calendarMonth[d].today) { foundToday = true; calendarMonth[d].isTabIndexed = true; } } // if today isn't present on the calendarGrid, tab index the first day if (!foundToday) { calendarMonth[0].isTabIndexed = true; } } return calendarMonth; } /** * @param {?} calendarMonth * @return {?} */ getNextMonthDays(calendarMonth) { // Next month days /** @type {?} */ let nextMonthDisplayedDays = 0; // The calendar grid can have either 5 (35 days) or 6 (42 days) weeks // depending on the week day of the first day of the current month // and the number of days in the current month if (calendarMonth.length > 35) { nextMonthDisplayedDays = 42 - calendarMonth.length; } else { nextMonthDisplayedDays = 35 - calendarMonth.length; } for (let nextD = 1; nextD <= nextMonthDisplayedDays; nextD++) { /** @type {?} */ let nextMonthFirstDate; if (this.date.getMonth() === 11) { nextMonthFirstDate = new Date(this.date.getFullYear() + 1, 0, 1); } else { nextMonthFirstDate = new Date(this.date.getFullYear(), this.date.getMonth() + 1, 1); } /** @type {?} */ const nextMonth = nextMonthFirstDate.getMonth(); /** @type {?} */ const nextMonthYear = nextMonthFirstDate.getFullYear(); /** @type {?} */ const calDate = new Date(nextMonthYear, nextMonth, nextD); /** @type {?} */ const nextMonthCalendarDay = { date: calDate, day: calDate.getDate(), weekDay: calDate.getDay(), monthStatus: 'next', disabled: this.disableFunction(calDate), blocked: this.blockFunction(calDate), selected: (this.selectedDay.date && calDate.toDateString() === this.selectedDay.date.toDateString()) || (this.selectedRangeFirst.date && calDate.toDateString() === this.selectedRangeFirst.date.toDateString()) || (this.selectedRangeLast.date && calDate.toDateString() === this.selectedRangeLast.date.toDateString()), selectedFirst: this.selectedRangeFirst.date && calDate.toDateString() === this.selectedRangeFirst.date.toDateString(), selectedLast: this.selectedRangeLast.date && calDate.toDateString() === this.selectedRangeLast.date.toDateString(), selectedRange: this.selectedRangeFirst.date && calDate.getTime() > this.selectedRangeFirst.date.getTime() && this.selectedRangeLast.date && calDate.getTime() < this.selectedRangeLast.date.getTime(), ariaLabel: this.calendarI18n.getDayAriaLabel(calDate) }; if (this.selectCounter === 0) { if (this.disableRangeStartFunction && !nextMonthCalendarDay.disabled) { nextMonthCalendarDay.disabled = this.disableRangeStartFunction(calDate); } if (this.blockRangeStartFunction && !nextMonthCalendarDay.blocked) { nextMonthCalendarDay.blocked = this.blockRangeStartFunction(calDate); } } else if (this.selectCounter === 1) { if (this.disableRangeEndFunction && !nextMonthCalendarDay.disabled) { nextMonthCalendarDay.disabled = this.disableRangeEndFunction(calDate); } if (this.blockRangeEndFunction && !nextMonthCalendarDay.blocked) { nextMonthCalendarDay.blocked = this.blockRangeEndFunction(calDate); } } calendarMonth.push(nextMonthCalendarDay); } return calendarMonth; } /** * @return {?} */ populateCalendar() { /** @type {?} */ let calendarMonth = []; calendarMonth = this.getPreviousMonthDays(calendarMonth); calendarMonth = this.getCurrentMonthDays(calendarMonth); calendarMonth = this.getNextMonthDays(calendarMonth); return calendarMonth; } // Construction functions /** * @return {?} */ constructCalendar() { /** @type {?} */ const calendarDays = this.populateCalendar(); /** @type {?} */ const calendarGrid = []; while (calendarDays.length > 0) { calendarGrid.push(calendarDays.splice(0, 7)); } this.calendarGrid = calendarGrid; } /** * @return {?} */ refreshSelected() { this.calendarGrid.forEach((/** * @param {?} grid * @return {?} */ grid => { grid.forEach((/** * @param {?} day * @return {?} */ day => { day.selected = (this.selectedDay.date && day.date && day.date.toDateString() === this.selectedDay.date.toDateString()) || (this.selectedRangeFirst.date && day.date.toDateString() === this.selectedRangeFirst.date.toDateString()) || (this.selectedRangeLast.date && day.date.toDateString() === this.selectedRangeLast.date.toDateString()); day.selectedFirst = this.selectedRangeFirst.date && day.date && day.date.toDateString() === this.selectedRangeFirst.date.toDateString(); day.selectedLast = this.selectedRangeLast.date && day.date && day.date.toDateString() === this.selectedRangeLast.date.toDateString(); day.selectedRange = this.selectedRangeFirst.date && day.date.getTime() > this.selectedRangeFirst.date.getTime() && this.selectedRangeLast.date && day.date.getTime() < this.selectedRangeLast.date.getTime(); })); })); } /** * @return {?} */ updateDatePickerInputEmitter() { if (this.calType === 'single') { this.emittedDate.selectedDay = this.selectedDay; } else { this.emittedDate.selectedFirstDay = this.selectedRangeFirst; this.emittedDate.selectedLastDay = this.selectedRangeLast; } if (this.dateFromDatePicker) { this.dateFromDatePicker.next(this.emittedDate); } } /** * @return {?} */ constructCalendarYearsList() { this.calendarYearsList = []; for (let y = 0; y < 12; y++) { this.calendarYearsList.push(this.firstYearCalendarList + y); } } /** * @param {?} year * @param {?} i * @return {?} */ getYearTabIndex(year, i) { /** @type {?} */ let retVal = -1; // tab index currently selected year if (year === this.year) { retVal = 0; } else { // if no year on the calendarYearsList is selected, tab index the first /** @type {?} */ let foundYear = false; this.calendarYearsList.forEach((/** * @param {?} yearFromList * @return {?} */ yearFromList => { if (this.year === yearFromList) { foundYear = true; } })); if (!foundYear) { if (i === 0) { retVal = 0; } } } return retVal; } // Functions that handle calendar navigation /** * @return {?} */ goToPreviousMonth() { this.setCurrentMonth(this.date.getMonth() - 1); this.selectedMonth = this.month; this.constructCalendar(); } /** * @return {?} */ goToNextMonth() { this.setCurrentMonth(this.date.getMonth() + 1); this.selectedMonth = this.month; this.constructCalendar(); } /** * @return {?} */ loadNextYearsList() { this.calendarYearsList = []; this.firstYearCalendarList += 12; this.constructCalendarYearsList(); } /** * @return {?} */ loadPrevYearsList() { this.calendarYearsList = []; this.firstYearCalendarList -= 12; this.constructCalendarYearsList(); } // Functions that handle selection (day, month, year) /** * @param {?} day * @param {?=} formEvent * @param {?=} event * @param {?=} closeCalendar * @return {?} */ selectDate(day, formEvent = true, event, closeCalendar) { if (event) { event.stopPropagation(); } if (!day.blocked && !day.disabled) { if (this.calType === 'single') { this.selectedDay = day; this.selectedDayChange.emit(this.selectedDay); this.refreshSelected(); if (this.init) { this.updateDatePickerInputEmitter(); } if (formEvent) { this.onChange({ date: day.date }); } if (closeCalendar) { this.closeCalendar.emit(); } } else { if (this.selectCounter === 2) { this.selectCounter = 0; } if (this.selectCounter === 1 && day.date !== this.selectedRangeLast.date) { this.selectedRangeLast = day; this.selectedRangeLastChange.emit(this.selectedRangeLast); this.selectCounter++; this.refreshSelected(); this.constructCalendar(); if (this.init) { this.updateDatePickerInputEmitter(); } if (formEvent) { this.onChange({ date: this.selectedRangeFirst.date, rangeEnd: day.date }); } } if (this.selectCounter === 0) { this.selectedRangeLast = day; this.selectedRangeLastChange.emit(this.selectedRangeLast); this.selectedRangeFirst = day; this.selectedRangeFirstChange.emit(this.selectedRangeFirst); this.selectCounter++; this.refreshSelected(); this.constructCalendar(); if (this.init) { this.updateDatePickerInputEmitter(); } if (formEvent) { this.onChange({ date: day.date, rangeEnd: day.date }); } } if (this.selectedRangeFirst.date > this.selectedRangeLast.date) { /** @type {?} */ const tempSelectedRangeFirst = this.selectedRangeFirst; this.selectedRangeFirst = this.selectedRangeLast; this.selectedRangeFirstChange.emit(this.selectedRangeFirst); this.selectedRangeLast = tempSelectedRangeFirst; this.selectedRangeLastChange.emit(this.selectedRangeLast); this.refreshSelected(); this.constructCalendar(); if (this.init) { this.updateDatePickerInputEmitter(); } if (formEvent) { this.onChange({ date: this.selectedRangeFirst.date, rangeEnd: this.selectedRangeLast.date }); } } } } this.isInvalidDateInput.emit(false); } /** * @param {?} month * @return {?} */ setCurrentMonth(month) { this.date.setMonth(month); this.month = this.date.getMonth(); this.monthName = this.monthsFullName[this.date.getMonth()]; this.year = this.date.getFullYear(); } /** * @param {?} selectedMonth * @param {?=} event * @return {?} */ selectMonth(selectedMonth, event) { if (event) { event.stopPropagation(); } this.selectedMonth = selectedMonth; this.setCurrentMonth(selectedMonth); this.constructCalendar(); this.openDaySelection(); } /** * @param {?} year * @return {?} */ setCurrentYear(year) { this.date.setFullYear(year); this.year = this.date.getFullYear(); } /** * @param {?} selectedYear * @param {?=} event * @return {?} */ selectYear(selectedYear, event) { if (event) { event.stopPropagation(); } this.selectedMonth = this.month; this.setCurrentYear(selectedYear); this.constructCalendar(); this.openDaySelection(); } // Functions that handle the calendar content - show/hide calendar dates, months list, years list /** * @return {?} */ openMonthSelection() { if (this.showCalendarYears) { this.showCalendarYears = false; this.showCalendarMonths = true; this.showCalendarDates = false; } else { this.showCalendarMonths = !this.showCalendarMonths; this.showCalendarYears = false; this.showCalendarDates = !this.showCalendarDates; } } /** * @return {?} */ openYearSelection() { if (this.showCalendarMonths) { this.showCalendarMonths = false; this.showCalendarYears = true; this.showCalendarDates = false; } else { this.showCalendarYears = !this.showCalendarYears; this.showCalendarMonths = false; this.showCalendarDates = !this.showCalendarDates; } } /** * @return {?} */ openDaySelection() { this.showCalendarMonths = false; this.showCalendarYears = false; this.showCalendarDates = true; } /** * @return {?} */ onEscapeKeydownHandler() { this.showCalendarDates = true; this.showCalendarMonths = false; this.showCalendarYears = false; } /** * @param {?} e * @return {?} */ onClickHandler(e) { /** @type {?} */ const target = e.target; if (!this.eRef.nativeElement.contains(target)) { this.showCalendarDates = true; this.showCalendarMonths = false; this.showCalendarYears = false; } } /** * @param {?} date * @return {?} */ validateDateFromDatePicker(date) { if (!date) { return true; } /** @type {?} */ const month = date.getMonth(); /** @type {?} */ const day = date.getDate(); /** @type {?} */ const year = date.getFullYear(); if (isNaN(month) || isNaN(day) || isNaN(year)) { return true; } if (year < 1000 || year > 3000 || month < 0 || month > 11) { return true; } if (day < 1 || day > this.determineDaysInMonth(month, year)) { return true; } return false; } /** * @return {?} */ resetSelection() { if (this.calType === 'single') { this.selectedDay = { date: null }; this.selectedDayChange.emit(this.selectedDay); } else { this.selectedRangeFirst = { date: null }; this.selectedRangeFirstChange.emit(this.selectedRangeFirst); this.selectedRangeLast = { date: null }; this.selectedRangeLastChange.emit(this.selectedRangeLast); } this.date = new Date(); this.year = this.date.getFullYear(); this.month = this.date.getMonth(); this.monthName = this.monthsFullName[this.date.getMonth()]; this.day = this.date.getDate(); this.selectedMonth = null; this.firstYearCalendarList = this.year; this.selectCounter = 0; this.calendarYearsList = []; this.constructCalendarYearsList(); this.constructCalendar(); } /** * @param {?} event * @param {?} year * @return {?} */ onKeydownYearHandler(event, year) { /** @type {?} */ let newFocusedYearId; if (event.code === 'Space' || event.code === 'Enter') { event.preventDefault(); this.selectYear(year); } else if (event.code === 'ArrowUp') { event.preventDefault(); if (this.calendarYearsList.indexOf(year) <= 3) { this.loadPrevYearsList(); this.cd.detectChanges(); } newFocusedYearId = '#' + this.calendarId + '-fd-year-' + (year - 4); } else if (event.code === 'ArrowDown') { event.preventDefault(); if (this.calendarYearsList.indexOf(year) >= 8) { this.loadNextYearsList(); this.cd.detectChanges(); } newFocusedYearId = '#' + this.calendarId + '-fd-year-' + (year + 4); } else if (event.code === 'ArrowLeft') { event.preventDefault(); if (year === this.calendarYearsList[0]) { this.loadPrevYearsList(); this.cd.detectChanges(); } newFocusedYearId = '#' + this.calendarId + '-fd-year-' + (year - 1); } else if (event.code === 'ArrowRight') { event.preventDefault(); if (year === this.calendarYearsList[this.calendarYearsList.length - 1]) { this.loadNextYearsList(); this.cd.detectChanges(); } newFocusedYearId = '#' + this.calendarId + '-fd-year-' + (year + 1); } else if (event.code === 'Tab' && !event.shiftKey) { if (!this.isDateTimePicker) { event.preventDefault(); this.focusElement('#arrowLeft'); } } if (newFocusedYearId) { this.focusElement(newFocusedYearId); } } /** * @param {?} event * @param {?} month * @return {?} */ onKeydownMonthHandler(event, month) { /** @type {?} */ let newFocusedMonthId; if (event.code === 'Space' || event.code === 'Enter') { event.preventDefault(); this.selectMonth(month); } else if (event.code === 'ArrowUp') { event.preventDefault(); newFocusedMonthId = '#' + this.calendarId + '-fd-month-' + (month - 4); } else if (event.code === 'ArrowDown') { event.preventDefault(); newFocusedMonthId = '#' + this.calendarId + '-fd-month-' + (month + 4); } else if (event.code === 'ArrowLeft') { event.preventDefault(); if (month === 0) { newFocusedMonthId = '#' + this.calendarId + '-fd-month-11'; } else { newFocusedMonthId = '#' + this.calendarId + '-fd-month-' + (month - 1); } } else if (event.code === 'ArrowRight') { event.preventDefault(); if (month === 11) { newFocusedMonthId = '#' + this.calendarId + '-fd-month-0'; } else { newFocusedMonthId = '#' + this.calendarId + '-fd-month-' + (month + 1); } } else if (event.code === 'Tab' && !event.shiftKey) { if (!this.isDateTimePicker) { event.preventDefault(); this.focusElement('#arrowLeft'); } } if (newFocusedMonthId) { this.focusElement(newFocusedMonthId); } } /** * @param {?} event * @param {?} cell * @return {?} */ onKeydownDayHandler(event, cell) { if (event.code === 'Tab' && !event.shiftKey) { if (!this.isDateTimePicker) { event.preventDefault(); this.focusElement('#arrowLeft'); } } else { // if the grid has 6 rows, the last cell id is 66, if it has 5 rows it's 56 /** @type {?} */ let lastDay = this.calendarGrid.length === 6 ? 66 : 56; /** @type {?} */ const currentId = parseInt(event.currentTarget.id.split('-').pop(), 10); if (event.code === 'Space' || event.code === 'Enter') { event.preventDefault(); /** @type {?} */ const closeCalendarPopover = true; this.selectDate(cell, true, null, closeCalendarPopover); this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + currentId; } else if (event.code === 'ArrowUp') { event.preventDefault(); if (currentId >= 10 && currentId <= 16) { // if first row, go to previous month this.goToPreviousMonth(); /** @type {?} */ const lastDigit = currentId.toString().split('').pop(); this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + this.calendarGrid.length.toString() + lastDigit; } else { this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + (currentId - 10); } } else if (event.code === 'ArrowDown') { event.preventDefault(); if (currentId >= lastDay - 6 && currentId <= lastDay) { // if last row, go to next month this.goToNextMonth(); /** @type {?} */ const lastDigit = currentId.toString().split('').pop(); this.newFocusedDayId = '#' + this.calendarId + '-fd-day-1' + lastDigit; } else { this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + (currentId + 10); } } else if (event.code === 'ArrowLeft') { event.preventDefault(); if (currentId === 10) { // if the first day is selected, go to the last day of the previous month this.goToPreviousMonth(); lastDay = this.calendarGrid.length === 6 ? 66 : 56; this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + lastDay; } else if (currentId.toString().split('').pop() === '0') { // if the last digit is 0, skip to the last day of the previous week this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + (currentId - 4); } else { this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + (currentId - 1); } } else if (event.code === 'ArrowRight') { event.preventDefault(); if (currentId === lastDay) { // if the last day is selected, go to the first day of the next month this.goToNextMonth(); this.newFocusedDayId = '#' + this.calendarId + '-fd-day-10'; } else if (currentId.toString().split('').pop() === '6') { // else if the last digit is 6, skip to the first day of the next week this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + (currentId + 4); } else { this.newFocusedDayId = '#' + this.calendarId + '-fd-day-' + (currentId + 1); } } if (this.newFocusedDayId) { this.focusElement(this.newFocusedDayId); } } } /** * @param {?} elementSelector * @return {?} */ focusElement(elementSelector) { /** @type {?} */ const elementToFocus = this.eRef.nativeElement.querySelector(elementSelector); if (elementToFocus) { elementToFocus.focus(); } } /** * @param {?} date * @return {?} */ updateFromDatePicker(date) { if (this.calType === 'single') { /** @type {?} */ const singleDate = this.dateAdapter.parse(date); this.invalidDate = this.validateDateFromDatePicker(singleDate); if (!this.invalidDate) { this.selectedDay.date = new Date(singleDate.getFullYear(), singleDate.getMonth(), singleDate.getDate()); this.date = new Date(singleDate.getFullYear(), singleDate.getMonth(), singleDate.getDate()); this.year = this.date.getFullYear(); this.month = this.date.getMonth(); this.monthName = this.monthsFullName[this.date.getMonth()]; this.isInvalidDateInput.emit(this.invalidDate); this.constructCalendar(); this.constructCalendarYearsList(); this.updateDatePickerInputEmitter(); } else { this.isInvalidDateInput.emit(this.invalidDate); this.resetSelection(); } } else { /** @type {?} */ const currentDates = date.split(this.dateAdapter.rangeDelimiter); /** @type {?} */ const firstDate = this.dateAdapter.parse(currentDates[0]); /** @type {?} */ const secondDate = this.dateAdapter.parse(currentDates[1]); this.invalidDate = this.validateDateFromDatePicker(firstDate) || this.validateDateFromDatePicker(secondDate); if (!this.invalidDate) { /** @type {?} */ const fDate = firstDate; /** @type {?} */ const lDate = secondDate; if (fDate.getTime() > lDate.getTime()) { this.selectedRangeFirst.date = lDate; this.selectedRangeLast.date = fDate; } else { this.selectedRangeFirst.date = fDate; this.selectedRangeLast.date = lDate; } this.date = firstDate; this.year = this.date.getFullYear(); this.month = this.date.getMonth(); this.monthName = this.monthsFullName[this.date.getMonth()]; this.isInvalidDateInput.emit(this.invalidDate); this.constructCalendar(); this.constructCalendarYearsList(); this.updateDatePickerInputEmitter(); } else { this.resetSelection(); this.isInvalidDateInput.emit(this.invalidDate); } } } /** * @return {?} */ ngOnInit() { // Localization setup this.setupLocalization(); if (!this.date) { this.date = new Date(); } this.constructCalendar(); this.constructCalendarYearsList(); this.calendarId = this.hasher.hash(); if (this.month) { this.selectMonth(this.month); } else { this.selectMonth(this.date.getMonth()); } if (this.year) { this.selectYear(this.year); } else { this.selectMonth(this.date.getFullYear()); } if (this.dateFromDatePicker) { this.dateFromDatePicker.subscribe((/** * @param {?} date * @return {?} */ date => { if (date && typeof date === 'string') { this.updateFromDatePicker(date); } this.constructCalendarYearsList(); })); } this.init = true; } /** * @return {?} */ ngAfterViewChecked() { if (this.newFocusedDayId) { this.focusElement(this.newFocusedDayId); this.newFocusedDayId = null; } } /** * @return {?} */ ngOnDestroy() { if (this.dateFromDatePicker) { this.dateFromDatePicker.unsubscribe(); } if (this.i18nLocalSub) { this.i18nLocalSub.unsubscribe(); } } /** * @param {?} changes * @return {?} */ ngOnChanges(changes) { if (changes && (changes.disableFunction || changes.blockFunction)) { this.constructCalendar(); } } /** * @param {?} fn * @return {?} */ registerOnChange(fn) { this.onChange = fn; } /** * @param {?} fn * @return {?} */ registerOnTouched(fn) { this.onTouched = fn; } /** * @param {?} isDisabled * @return {?} */ setDisabledState(isDisabled) { // void } /** * @param {?} selected * @return {?} */ writeValue(selected) { if (selected && this.calType) { if (selected.date && this.calType === 'single') { this.singleFormsSetup(selected); } else if (selected.date && selected.rangeEnd && this.calType === 'range') { this.rangeFormsSetup(selected); } } } /** * @private * @param {?} selected * @return {?} */ singleFormsSetup(selected) { this.selectedDay.date = new Date(selected.date.getFullYear(), selected.date.getMonth(), selected.date.getDate()); this.date = new Date(selected.date.getFullYear(), selected.date.getMonth(), selected.date.getDate()); this.year = this.date.getFullYear(); this.month = this.date.getMonth(); this.monthName = this.monthsFullName[this.date.getMonth()]; this.firstYearCalendarList = this.year; this.constructCalendar(); this.constructCalendarYearsList(); } /** * @private * @param {?} selected * @return {?} */ rangeFormsSetup(selected) { /** @type {?} */ const fDate = new Date(selected.date.getFullYear(), selected.date.getMonth(), selected.date.getDate()); /** @type {?} */ const lDate = new Date(selected.rangeEnd.getFullYear(), selected.rangeEnd.getMonth(), selected.rangeEnd.getDate()); if (fDate.getTime() > lDate.getTime()) { this.selectedRangeFirst.date = lDate; this.selectedRangeLast.date = fDate; } else { this.selectedRangeFirst.date = fDate; this.selectedRangeLast.date = lDate; } this.date = new Date(selected.date.getFullYear(), selected.date.getMonth(), selected.date.getDate()); this.year = this.date.getFullYear(); this.month = this.date.getMonth(); this.monthName = this.monthsFullName[this.date.getMonth()]; this.firstYearCalendarList = this.year; this.constructCalendar(); this.constructCalendarYearsList(); } /** * @private * @return {?} */ setupLocalization() { this.monthsFullName = this.calendarI18n.getAllFullMonthNames(); this.monthsShortName = this.calendarI18n.getAllShortMonthNames(); this.monthName = this.monthsFullName[this.month]; this.i18nLocalSub = this.calendarI18n.i18nChange.subscribe((/** * @return {?} */ () => { this.monthsFullName = this.calendarI18n.getAllFullMonthNames(); this.monthsShortName = this.calendarI18n.getAllShortMonthNames(); this.monthName = this.monthsFullName[this.month]; this.setWeekDaysOrder(); this.cd.detectChanges(); })); // Will also need to subscribe to labelsChange when we go to OnPush change detection. } } CalendarComponent.decorators = [ { type: Component, args: [{ selector: 'fd-calendar', template: "<header class=\"fd-calendar__header\">\n <div class=\"fd-calendar__navigation\">\n <div class=\"fd-calendar__action\">\n <button id=\"arrowLeft\" class=\"fd-button--toolbar fd-button--xs sap-icon--slim-arrow-left\"\n [attr.aria-label]=\"showCalendarYears ? calendarI18nLabels?.previousYearLabel : calendarI18nLabels?.previousMonthLabel\"\n (click)=\"showCalendarYears ? loadPrevYearsList() : goToPreviousMonth()\"></button>\n </div>\n <div class=\"fd-calendar__action\">\n <button class=\" fd-button--light fd-button--s\"\n [attr.aria-label]=\"calendarI18nLabels?.monthSelectionLabel\"\n (click)=\"openMonthSelection()\">{{monthName}}</button>\n </div>\n <div class=\"fd-calendar__action\">\n <button class=\" fd-button--light fd-button--s\"\n [attr.aria-label]=\"calendarI18nLabels?.yearSelectionLabel\"\n (click)=\"openYearSelection()\">{{year}}</button>\n </div>\n <div class=\"fd-calendar__action\">\n <button class=\"fd-button--toolbar fd-button--xs sap-icon--slim-arrow-right\"\n [attr.aria-label]=\"showCalendarYears ? calendarI18nLabels?.nextYearLabel : calendarI18nLabels?.nextMonthLabel\"\n (click)=\"showCalendarYears ? loadNextYearsList() : goToNextMonth()\"></button>\n </div>\n </div>\n</header>\n<div class=\"fd-calendar__content\">\n <div class=\"fd-calendar__years\"\n *ngIf=\"showCalendarYears\">\n <ul class=\"fd-calendar__list\">\n <li class=\"fd-calendar__item\"\n *ngFor=\"let listYear of calendarYearsList; let i = index;\"\n [ngClass]='(listYear===todayYear ? \" fd-calendar__item--current\" : \"\") + (listYear===year ? \" is-selected\" : \"\")'\n (click)=\"selectYear(listYear, $event)\">\n <span role=\"button\" [attr.tabIndex]=\"getYearTabIndex(listYear, i)\"\n [attr.id]=\"calendarId + '-fd-year-' + listYear\"\n (keydown)=\"onKeydownYearHandler($event, listYear)\"\n class=\"fd-calendar__text\">{{listYear}}</span>\n </li>\n </ul>\n </div>\n\n <div class=\"fd-calendar__months\"\n *ngIf=\"showCalendarMonths\">\n <ul class=\"fd-calendar__list\">\n <li class=\"fd-calendar__item\"\n *ngFor=\"let monthShortName of monthsShortName, let i=index\"\n [ngClass]='(i===todayMonth && year===todayYear ? \" fd-calendar__item--current\" : \"\") + (i===selectedMonth ? \" is-selected\" : \"\") '\n (click)=\"selectMonth(i, $event)\">\n <span role=\"button\" [attr.tabIndex]=\"i === selectedMonth ? 0 : -1\"\n [attr.id]=\"calendarId + '-fd-month-' + i\" (keydown)=\"onKeydownMonthHandler($event, i)\"\n class=\"fd-calendar__text\">{{monthShortName}}</span>\n </li>\n </ul>\n </div>\n\n <div class=\"fd-calendar__dates\"\n *ngIf=\"showCalendarDates\">\n <table class=\"fd-calendar__table\"\n role=\"grid\">\n <thead class=\"fd-calendar__group\">\n <tr class=\"fd-calendar__row\">\n <th class=\"fd-calendar__column-header\"\n *ngFor=\"let day of weekDays\">\n <span class=\"fd-calendar__day-of-week\">{{day}}</span>\n </th>\n </tr>\n </thead>\n <tbody class=\"fd-calendar__group\" [attr.id]=\"calendarId + '-dates-table'\">\n <tr class=\"fd-calendar__row\"\n *ngFor=\"let row of calendarGrid; let i = index;\">\n <td class=\"fd-calendar__item\"\n role=\"gridcell\"\n [attr.aria-label]=\"cell.ariaLabel\"\n *ngFor=\"let cell of row; let cellIndex = index;\"\n [ngClass]='(cell.monthStatus !== \"current\" ? \" fd-calendar__item--other-month\": \"\") +\n (cell.selected ? \" is-selected\