fundamental-ngx
Version:
SAP Fiori Fundamentals, implemented in Angular
1,233 lines • 160 kB
JavaScript
/**
* @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\