3953 lines
486 KiB
JavaScript
3953 lines
486 KiB
JavaScript
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||
|
import { CommonModule, DOCUMENT } from '@angular/common';
|
||
|
import { booleanAttribute, ChangeDetectionStrategy, Component, ContentChildren, EventEmitter, forwardRef, Inject, Input, NgModule, numberAttribute, Output, ViewChild, ViewEncapsulation } from '@angular/core';
|
||
|
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
||
|
import { PrimeTemplate, SharedModule, TranslationKeys } from 'primeng/api';
|
||
|
import { ButtonModule } from 'primeng/button';
|
||
|
import { ConnectedOverlayScrollHandler, DomHandler } from 'primeng/dom';
|
||
|
import { RippleModule } from 'primeng/ripple';
|
||
|
import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils';
|
||
|
import { ChevronLeftIcon } from 'primeng/icons/chevronleft';
|
||
|
import { ChevronRightIcon } from 'primeng/icons/chevronright';
|
||
|
import { ChevronUpIcon } from 'primeng/icons/chevronup';
|
||
|
import { ChevronDownIcon } from 'primeng/icons/chevrondown';
|
||
|
import { TimesIcon } from 'primeng/icons/times';
|
||
|
import { CalendarIcon } from 'primeng/icons/calendar';
|
||
|
import { AutoFocusModule } from 'primeng/autofocus';
|
||
|
import * as i0 from "@angular/core";
|
||
|
import * as i1 from "primeng/api";
|
||
|
import * as i2 from "@angular/common";
|
||
|
import * as i3 from "primeng/button";
|
||
|
import * as i4 from "primeng/ripple";
|
||
|
import * as i5 from "primeng/autofocus";
|
||
|
export const CALENDAR_VALUE_ACCESSOR = {
|
||
|
provide: NG_VALUE_ACCESSOR,
|
||
|
useExisting: forwardRef(() => Calendar),
|
||
|
multi: true
|
||
|
};
|
||
|
/**
|
||
|
* Calendar also known as DatePicker, is a form component to work with dates.
|
||
|
* @group Components
|
||
|
*/
|
||
|
export class Calendar {
|
||
|
document;
|
||
|
el;
|
||
|
renderer;
|
||
|
cd;
|
||
|
zone;
|
||
|
config;
|
||
|
overlayService;
|
||
|
iconDisplay = 'button';
|
||
|
/**
|
||
|
* Inline style of the component.
|
||
|
* @group Props
|
||
|
*/
|
||
|
style;
|
||
|
/**
|
||
|
* Style class of the component.
|
||
|
* @group Props
|
||
|
*/
|
||
|
styleClass;
|
||
|
/**
|
||
|
* Inline style of the input field.
|
||
|
* @group Props
|
||
|
*/
|
||
|
inputStyle;
|
||
|
/**
|
||
|
* Identifier of the focus input to match a label defined for the component.
|
||
|
* @group Props
|
||
|
*/
|
||
|
inputId;
|
||
|
/**
|
||
|
* Name of the input element.
|
||
|
* @group Props
|
||
|
*/
|
||
|
name;
|
||
|
/**
|
||
|
* Style class of the input field.
|
||
|
* @group Props
|
||
|
*/
|
||
|
inputStyleClass;
|
||
|
/**
|
||
|
* Placeholder text for the input.
|
||
|
* @group Props
|
||
|
*/
|
||
|
placeholder;
|
||
|
/**
|
||
|
* Establishes relationships between the component and label(s) where its value should be one or more element IDs.
|
||
|
* @group Props
|
||
|
*/
|
||
|
ariaLabelledBy;
|
||
|
/**
|
||
|
* Defines a string that labels the input for accessibility.
|
||
|
* @group Props
|
||
|
*/
|
||
|
ariaLabel;
|
||
|
/**
|
||
|
* Defines a string that labels the icon button for accessibility.
|
||
|
* @group Props
|
||
|
*/
|
||
|
iconAriaLabel;
|
||
|
/**
|
||
|
* When specified, disables the component.
|
||
|
* @group Props
|
||
|
*/
|
||
|
disabled;
|
||
|
/**
|
||
|
* Format of the date which can also be defined at locale settings.
|
||
|
* @group Props
|
||
|
*/
|
||
|
dateFormat;
|
||
|
/**
|
||
|
* Separator for multiple selection mode.
|
||
|
* @group Props
|
||
|
*/
|
||
|
multipleSeparator = ',';
|
||
|
/**
|
||
|
* Separator for joining start and end dates on range selection mode.
|
||
|
* @group Props
|
||
|
*/
|
||
|
rangeSeparator = '-';
|
||
|
/**
|
||
|
* When enabled, displays the calendar as inline. Default is false for popup mode.
|
||
|
* @group Props
|
||
|
*/
|
||
|
inline = false;
|
||
|
/**
|
||
|
* Whether to display dates in other months (non-selectable) at the start or end of the current month. To make these days selectable use the selectOtherMonths option.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showOtherMonths = true;
|
||
|
/**
|
||
|
* Whether days in other months shown before or after the current month are selectable. This only applies if the showOtherMonths option is set to true.
|
||
|
* @group Props
|
||
|
*/
|
||
|
selectOtherMonths;
|
||
|
/**
|
||
|
* When enabled, displays a button with icon next to input.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showIcon;
|
||
|
/**
|
||
|
* Icon of the calendar button.
|
||
|
* @group Props
|
||
|
*/
|
||
|
icon;
|
||
|
/**
|
||
|
* Target element to attach the overlay, valid values are "body" or a local ng-template variable of another element (note: use binding with brackets for template variables, e.g. [appendTo]="mydiv" for a div element having#mydiv as variable name).
|
||
|
* @group Props
|
||
|
*/
|
||
|
appendTo;
|
||
|
/**
|
||
|
* When specified, prevents entering the date manually with keyboard.
|
||
|
* @group Props
|
||
|
*/
|
||
|
readonlyInput;
|
||
|
/**
|
||
|
* The cutoff year for determining the century for a date.
|
||
|
* @group Props
|
||
|
*/
|
||
|
shortYearCutoff = '+10';
|
||
|
/**
|
||
|
* Whether the month should be rendered as a dropdown instead of text.
|
||
|
* @group Props
|
||
|
* @deprecated Navigator is always on.
|
||
|
*/
|
||
|
monthNavigator;
|
||
|
/**
|
||
|
* Whether the year should be rendered as a dropdown instead of text.
|
||
|
* @group Props
|
||
|
* @deprecated Navigator is always on.
|
||
|
*/
|
||
|
yearNavigator;
|
||
|
/**
|
||
|
* Specifies 12 or 24 hour format.
|
||
|
* @group Props
|
||
|
*/
|
||
|
hourFormat = '24';
|
||
|
/**
|
||
|
* Whether to display timepicker only.
|
||
|
* @group Props
|
||
|
*/
|
||
|
timeOnly;
|
||
|
/**
|
||
|
* Hours to change per step.
|
||
|
* @group Props
|
||
|
*/
|
||
|
stepHour = 1;
|
||
|
/**
|
||
|
* Minutes to change per step.
|
||
|
* @group Props
|
||
|
*/
|
||
|
stepMinute = 1;
|
||
|
/**
|
||
|
* Seconds to change per step.
|
||
|
* @group Props
|
||
|
*/
|
||
|
stepSecond = 1;
|
||
|
/**
|
||
|
* Whether to show the seconds in time picker.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showSeconds = false;
|
||
|
/**
|
||
|
* When present, it specifies that an input field must be filled out before submitting the form.
|
||
|
* @group Props
|
||
|
*/
|
||
|
required;
|
||
|
/**
|
||
|
* When disabled, datepicker will not be visible with input focus.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showOnFocus = true;
|
||
|
/**
|
||
|
* When enabled, calendar will show week numbers.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showWeek = false;
|
||
|
/**
|
||
|
* When enabled, calendar will start week numbers from first day of the year.
|
||
|
* @group Props
|
||
|
*/
|
||
|
startWeekFromFirstDayOfYear = false;
|
||
|
/**
|
||
|
* When enabled, a clear icon is displayed to clear the value.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showClear = false;
|
||
|
/**
|
||
|
* Type of the value to write back to ngModel, default is date and alternative is string.
|
||
|
* @group Props
|
||
|
*/
|
||
|
dataType = 'date';
|
||
|
/**
|
||
|
* Defines the quantity of the selection, valid values are "single", "multiple" and "range".
|
||
|
* @group Props
|
||
|
*/
|
||
|
selectionMode = 'single';
|
||
|
/**
|
||
|
* Maximum number of selectable dates in multiple mode.
|
||
|
* @group Props
|
||
|
*/
|
||
|
maxDateCount;
|
||
|
/**
|
||
|
* Whether to display today and clear buttons at the footer
|
||
|
* @group Props
|
||
|
*/
|
||
|
showButtonBar;
|
||
|
/**
|
||
|
* Style class of the today button.
|
||
|
* @group Props
|
||
|
*/
|
||
|
todayButtonStyleClass = 'p-button-text';
|
||
|
/**
|
||
|
* Style class of the clear button.
|
||
|
* @group Props
|
||
|
*/
|
||
|
clearButtonStyleClass = 'p-button-text';
|
||
|
/**
|
||
|
* When present, it specifies that the component should automatically get focus on load.
|
||
|
* @group Props
|
||
|
*/
|
||
|
autofocus;
|
||
|
/**
|
||
|
* Whether to automatically manage layering.
|
||
|
* @group Props
|
||
|
*/
|
||
|
autoZIndex = true;
|
||
|
/**
|
||
|
* Base zIndex value to use in layering.
|
||
|
* @group Props
|
||
|
*/
|
||
|
baseZIndex = 0;
|
||
|
/**
|
||
|
* Style class of the datetimepicker container element.
|
||
|
* @group Props
|
||
|
*/
|
||
|
panelStyleClass;
|
||
|
/**
|
||
|
* Inline style of the datetimepicker container element.
|
||
|
* @group Props
|
||
|
*/
|
||
|
panelStyle;
|
||
|
/**
|
||
|
* Keep invalid value when input blur.
|
||
|
* @group Props
|
||
|
*/
|
||
|
keepInvalid = false;
|
||
|
/**
|
||
|
* Whether to hide the overlay on date selection.
|
||
|
* @group Props
|
||
|
*/
|
||
|
hideOnDateTimeSelect = true;
|
||
|
/**
|
||
|
* When enabled, calendar overlay is displayed as optimized for touch devices.
|
||
|
* @group Props
|
||
|
*/
|
||
|
touchUI;
|
||
|
/**
|
||
|
* Separator of time selector.
|
||
|
* @group Props
|
||
|
*/
|
||
|
timeSeparator = ':';
|
||
|
/**
|
||
|
* When enabled, can only focus on elements inside the calendar.
|
||
|
* @group Props
|
||
|
*/
|
||
|
focusTrap = true;
|
||
|
/**
|
||
|
* Transition options of the show animation.
|
||
|
* @group Props
|
||
|
*/
|
||
|
showTransitionOptions = '.12s cubic-bezier(0, 0, 0.2, 1)';
|
||
|
/**
|
||
|
* Transition options of the hide animation.
|
||
|
* @group Props
|
||
|
*/
|
||
|
hideTransitionOptions = '.1s linear';
|
||
|
/**
|
||
|
* Index of the element in tabbing order.
|
||
|
* @group Props
|
||
|
*/
|
||
|
tabindex;
|
||
|
/**
|
||
|
* Specifies the input variant of the component.
|
||
|
* @group Props
|
||
|
*/
|
||
|
variant = 'outlined';
|
||
|
/**
|
||
|
* The minimum selectable date.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get minDate() {
|
||
|
return this._minDate;
|
||
|
}
|
||
|
set minDate(date) {
|
||
|
this._minDate = date;
|
||
|
if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) {
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* The maximum selectable date.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get maxDate() {
|
||
|
return this._maxDate;
|
||
|
}
|
||
|
set maxDate(date) {
|
||
|
this._maxDate = date;
|
||
|
if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) {
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Array with dates that should be disabled (not selectable).
|
||
|
* @group Props
|
||
|
*/
|
||
|
get disabledDates() {
|
||
|
return this._disabledDates;
|
||
|
}
|
||
|
set disabledDates(disabledDates) {
|
||
|
this._disabledDates = disabledDates;
|
||
|
if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) {
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Array with weekday numbers that should be disabled (not selectable).
|
||
|
* @group Props
|
||
|
*/
|
||
|
get disabledDays() {
|
||
|
return this._disabledDays;
|
||
|
}
|
||
|
set disabledDays(disabledDays) {
|
||
|
this._disabledDays = disabledDays;
|
||
|
if (this.currentMonth != undefined && this.currentMonth != null && this.currentYear) {
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* The range of years displayed in the year drop-down in (nnnn:nnnn) format such as (2000:2020).
|
||
|
* @group Props
|
||
|
* @deprecated Years are based on decades by default.
|
||
|
*/
|
||
|
get yearRange() {
|
||
|
return this._yearRange;
|
||
|
}
|
||
|
set yearRange(yearRange) {
|
||
|
this._yearRange = yearRange;
|
||
|
if (yearRange) {
|
||
|
const years = yearRange.split(':');
|
||
|
const yearStart = parseInt(years[0]);
|
||
|
const yearEnd = parseInt(years[1]);
|
||
|
this.populateYearOptions(yearStart, yearEnd);
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* Whether to display timepicker.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get showTime() {
|
||
|
return this._showTime;
|
||
|
}
|
||
|
set showTime(showTime) {
|
||
|
this._showTime = showTime;
|
||
|
if (this.currentHour === undefined) {
|
||
|
this.initTime(this.value || new Date());
|
||
|
}
|
||
|
this.updateInputfield();
|
||
|
}
|
||
|
/**
|
||
|
* An array of options for responsive design.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get responsiveOptions() {
|
||
|
return this._responsiveOptions;
|
||
|
}
|
||
|
set responsiveOptions(responsiveOptions) {
|
||
|
this._responsiveOptions = responsiveOptions;
|
||
|
this.destroyResponsiveStyleElement();
|
||
|
this.createResponsiveStyle();
|
||
|
}
|
||
|
/**
|
||
|
* Number of months to display.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get numberOfMonths() {
|
||
|
return this._numberOfMonths;
|
||
|
}
|
||
|
set numberOfMonths(numberOfMonths) {
|
||
|
this._numberOfMonths = numberOfMonths;
|
||
|
this.destroyResponsiveStyleElement();
|
||
|
this.createResponsiveStyle();
|
||
|
}
|
||
|
/**
|
||
|
* Defines the first of the week for various date calculations.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get firstDayOfWeek() {
|
||
|
return this._firstDayOfWeek;
|
||
|
}
|
||
|
set firstDayOfWeek(firstDayOfWeek) {
|
||
|
this._firstDayOfWeek = firstDayOfWeek;
|
||
|
this.createWeekDays();
|
||
|
}
|
||
|
/**
|
||
|
* Option to set calendar locale.
|
||
|
* @group Props
|
||
|
* @deprecated Locale property has no effect, use new i18n API instead.
|
||
|
*/
|
||
|
set locale(newLocale) {
|
||
|
console.warn('Locale property has no effect, use new i18n API instead.');
|
||
|
}
|
||
|
/**
|
||
|
* Type of view to display, valid values are "date" for datepicker and "month" for month picker.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get view() {
|
||
|
return this._view;
|
||
|
}
|
||
|
set view(view) {
|
||
|
this._view = view;
|
||
|
this.currentView = this._view;
|
||
|
}
|
||
|
/**
|
||
|
* Set the date to highlight on first opening if the field is blank.
|
||
|
* @group Props
|
||
|
*/
|
||
|
get defaultDate() {
|
||
|
return this._defaultDate;
|
||
|
}
|
||
|
set defaultDate(defaultDate) {
|
||
|
this._defaultDate = defaultDate;
|
||
|
if (this.initialized) {
|
||
|
const date = defaultDate || new Date();
|
||
|
this.currentMonth = date.getMonth();
|
||
|
this.currentYear = date.getFullYear();
|
||
|
this.initTime(date);
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
get inputClass() {
|
||
|
return {
|
||
|
'p-inputtext p-component': true,
|
||
|
'p-variant-filled': this.variant === 'filled' || this.config.inputStyle() === 'filled'
|
||
|
};
|
||
|
}
|
||
|
/**
|
||
|
* Callback to invoke on focus of input field.
|
||
|
* @param {Event} event - browser event.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onFocus = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke on blur of input field.
|
||
|
* @param {Event} event - browser event.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onBlur = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when date panel closed.
|
||
|
* @param {Event} event - Mouse event
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onClose = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke on date select.
|
||
|
* @param {Date} date - date value.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onSelect = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when input field cleared.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onClear = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when input field is being typed.
|
||
|
* @param {Event} event - browser event
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onInput = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when today button is clicked.
|
||
|
* @param {Date} date - today as a date instance.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onTodayClick = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when clear button is clicked.
|
||
|
* @param {Event} event - browser event.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onClearClick = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when a month is changed using the navigators.
|
||
|
* @param {CalendarMonthChangeEvent} event - custom month change event.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onMonthChange = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when a year is changed using the navigators.
|
||
|
* @param {CalendarYearChangeEvent} event - custom year change event.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onYearChange = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when clicked outside of the date panel.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onClickOutside = new EventEmitter();
|
||
|
/**
|
||
|
* Callback to invoke when datepicker panel is shown.
|
||
|
* @group Emits
|
||
|
*/
|
||
|
onShow = new EventEmitter();
|
||
|
templates;
|
||
|
containerViewChild;
|
||
|
inputfieldViewChild;
|
||
|
set content(content) {
|
||
|
this.contentViewChild = content;
|
||
|
if (this.contentViewChild) {
|
||
|
if (this.isMonthNavigate) {
|
||
|
Promise.resolve(null).then(() => this.updateFocus());
|
||
|
this.isMonthNavigate = false;
|
||
|
}
|
||
|
else {
|
||
|
if (!this.focus && !this.inline) {
|
||
|
this.initFocusableCell();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
contentViewChild;
|
||
|
value;
|
||
|
dates;
|
||
|
months;
|
||
|
weekDays;
|
||
|
currentMonth;
|
||
|
currentYear;
|
||
|
currentHour;
|
||
|
currentMinute;
|
||
|
currentSecond;
|
||
|
pm;
|
||
|
mask;
|
||
|
maskClickListener;
|
||
|
overlay;
|
||
|
responsiveStyleElement;
|
||
|
overlayVisible;
|
||
|
onModelChange = () => { };
|
||
|
onModelTouched = () => { };
|
||
|
calendarElement;
|
||
|
timePickerTimer;
|
||
|
documentClickListener;
|
||
|
animationEndListener;
|
||
|
ticksTo1970;
|
||
|
yearOptions;
|
||
|
focus;
|
||
|
isKeydown;
|
||
|
filled;
|
||
|
inputFieldValue = null;
|
||
|
_minDate;
|
||
|
_maxDate;
|
||
|
_showTime;
|
||
|
_yearRange;
|
||
|
preventDocumentListener;
|
||
|
dateTemplate;
|
||
|
headerTemplate;
|
||
|
footerTemplate;
|
||
|
disabledDateTemplate;
|
||
|
decadeTemplate;
|
||
|
previousIconTemplate;
|
||
|
nextIconTemplate;
|
||
|
triggerIconTemplate;
|
||
|
clearIconTemplate;
|
||
|
decrementIconTemplate;
|
||
|
incrementIconTemplate;
|
||
|
inputIconTemplate;
|
||
|
_disabledDates;
|
||
|
_disabledDays;
|
||
|
selectElement;
|
||
|
todayElement;
|
||
|
focusElement;
|
||
|
scrollHandler;
|
||
|
documentResizeListener;
|
||
|
navigationState = null;
|
||
|
isMonthNavigate;
|
||
|
initialized;
|
||
|
translationSubscription;
|
||
|
_locale;
|
||
|
_responsiveOptions;
|
||
|
currentView;
|
||
|
attributeSelector;
|
||
|
panelId;
|
||
|
_numberOfMonths = 1;
|
||
|
_firstDayOfWeek;
|
||
|
_view = 'date';
|
||
|
preventFocus;
|
||
|
_defaultDate;
|
||
|
_focusKey = null;
|
||
|
window;
|
||
|
get locale() {
|
||
|
return this._locale;
|
||
|
}
|
||
|
get iconButtonAriaLabel() {
|
||
|
return this.iconAriaLabel ? this.iconAriaLabel : this.getTranslation('chooseDate');
|
||
|
}
|
||
|
get prevIconAriaLabel() {
|
||
|
return this.currentView === 'year' ? this.getTranslation('prevDecade') : this.currentView === 'month' ? this.getTranslation('prevYear') : this.getTranslation('prevMonth');
|
||
|
}
|
||
|
get nextIconAriaLabel() {
|
||
|
return this.currentView === 'year' ? this.getTranslation('nextDecade') : this.currentView === 'month' ? this.getTranslation('nextYear') : this.getTranslation('nextMonth');
|
||
|
}
|
||
|
constructor(document, el, renderer, cd, zone, config, overlayService) {
|
||
|
this.document = document;
|
||
|
this.el = el;
|
||
|
this.renderer = renderer;
|
||
|
this.cd = cd;
|
||
|
this.zone = zone;
|
||
|
this.config = config;
|
||
|
this.overlayService = overlayService;
|
||
|
this.window = this.document.defaultView;
|
||
|
}
|
||
|
ngOnInit() {
|
||
|
this.attributeSelector = UniqueComponentId();
|
||
|
this.panelId = this.attributeSelector + '_panel';
|
||
|
const date = this.defaultDate || new Date();
|
||
|
this.createResponsiveStyle();
|
||
|
this.currentMonth = date.getMonth();
|
||
|
this.currentYear = date.getFullYear();
|
||
|
this.yearOptions = [];
|
||
|
this.currentView = this.view;
|
||
|
if (this.view === 'date') {
|
||
|
this.createWeekDays();
|
||
|
this.initTime(date);
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
this.ticksTo1970 = ((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000;
|
||
|
}
|
||
|
this.translationSubscription = this.config.translationObserver.subscribe(() => {
|
||
|
this.createWeekDays();
|
||
|
this.cd.markForCheck();
|
||
|
});
|
||
|
this.initialized = true;
|
||
|
}
|
||
|
ngAfterContentInit() {
|
||
|
this.templates.forEach((item) => {
|
||
|
switch (item.getType()) {
|
||
|
case 'date':
|
||
|
this.dateTemplate = item.template;
|
||
|
break;
|
||
|
case 'decade':
|
||
|
this.decadeTemplate = item.template;
|
||
|
break;
|
||
|
case 'disabledDate':
|
||
|
this.disabledDateTemplate = item.template;
|
||
|
break;
|
||
|
case 'header':
|
||
|
this.headerTemplate = item.template;
|
||
|
break;
|
||
|
case 'inputicon':
|
||
|
this.inputIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'previousicon':
|
||
|
this.previousIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'nexticon':
|
||
|
this.nextIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'triggericon':
|
||
|
this.triggerIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'clearicon':
|
||
|
this.clearIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'decrementicon':
|
||
|
this.decrementIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'incrementicon':
|
||
|
this.incrementIconTemplate = item.template;
|
||
|
break;
|
||
|
case 'footer':
|
||
|
this.footerTemplate = item.template;
|
||
|
break;
|
||
|
default:
|
||
|
this.dateTemplate = item.template;
|
||
|
break;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
ngAfterViewInit() {
|
||
|
if (this.inline) {
|
||
|
this.contentViewChild && this.contentViewChild.nativeElement.setAttribute(this.attributeSelector, '');
|
||
|
if (!this.disabled && !this.inline) {
|
||
|
this.initFocusableCell();
|
||
|
if (this.numberOfMonths === 1) {
|
||
|
if (this.contentViewChild && this.contentViewChild.nativeElement) {
|
||
|
this.contentViewChild.nativeElement.style.width = DomHandler.getOuterWidth(this.containerViewChild?.nativeElement) + 'px';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
getTranslation(option) {
|
||
|
return this.config.getTranslation(option);
|
||
|
}
|
||
|
populateYearOptions(start, end) {
|
||
|
this.yearOptions = [];
|
||
|
for (let i = start; i <= end; i++) {
|
||
|
this.yearOptions.push(i);
|
||
|
}
|
||
|
}
|
||
|
createWeekDays() {
|
||
|
this.weekDays = [];
|
||
|
let dayIndex = this.getFirstDateOfWeek();
|
||
|
let dayLabels = this.getTranslation(TranslationKeys.DAY_NAMES_MIN);
|
||
|
for (let i = 0; i < 7; i++) {
|
||
|
this.weekDays.push(dayLabels[dayIndex]);
|
||
|
dayIndex = dayIndex == 6 ? 0 : ++dayIndex;
|
||
|
}
|
||
|
}
|
||
|
monthPickerValues() {
|
||
|
let monthPickerValues = [];
|
||
|
for (let i = 0; i <= 11; i++) {
|
||
|
monthPickerValues.push(this.config.getTranslation('monthNamesShort')[i]);
|
||
|
}
|
||
|
return monthPickerValues;
|
||
|
}
|
||
|
yearPickerValues() {
|
||
|
let yearPickerValues = [];
|
||
|
let base = this.currentYear - (this.currentYear % 10);
|
||
|
for (let i = 0; i < 10; i++) {
|
||
|
yearPickerValues.push(base + i);
|
||
|
}
|
||
|
return yearPickerValues;
|
||
|
}
|
||
|
createMonths(month, year) {
|
||
|
this.months = this.months = [];
|
||
|
for (let i = 0; i < this.numberOfMonths; i++) {
|
||
|
let m = month + i;
|
||
|
let y = year;
|
||
|
if (m > 11) {
|
||
|
m = (m % 11) - 1;
|
||
|
y = year + 1;
|
||
|
}
|
||
|
this.months.push(this.createMonth(m, y));
|
||
|
}
|
||
|
}
|
||
|
getWeekNumber(date) {
|
||
|
let checkDate = new Date(date.getTime());
|
||
|
if (this.startWeekFromFirstDayOfYear) {
|
||
|
let firstDayOfWeek = +this.getFirstDateOfWeek();
|
||
|
checkDate.setDate(checkDate.getDate() + 6 + firstDayOfWeek - checkDate.getDay());
|
||
|
}
|
||
|
else {
|
||
|
checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
|
||
|
}
|
||
|
let time = checkDate.getTime();
|
||
|
checkDate.setMonth(0);
|
||
|
checkDate.setDate(1);
|
||
|
return Math.floor(Math.round((time - checkDate.getTime()) / 86400000) / 7) + 1;
|
||
|
}
|
||
|
createMonth(month, year) {
|
||
|
let dates = [];
|
||
|
let firstDay = this.getFirstDayOfMonthIndex(month, year);
|
||
|
let daysLength = this.getDaysCountInMonth(month, year);
|
||
|
let prevMonthDaysLength = this.getDaysCountInPrevMonth(month, year);
|
||
|
let dayNo = 1;
|
||
|
let today = new Date();
|
||
|
let weekNumbers = [];
|
||
|
let monthRows = Math.ceil((daysLength + firstDay) / 7);
|
||
|
for (let i = 0; i < monthRows; i++) {
|
||
|
let week = [];
|
||
|
if (i == 0) {
|
||
|
for (let j = prevMonthDaysLength - firstDay + 1; j <= prevMonthDaysLength; j++) {
|
||
|
let prev = this.getPreviousMonthAndYear(month, year);
|
||
|
week.push({ day: j, month: prev.month, year: prev.year, otherMonth: true, today: this.isToday(today, j, prev.month, prev.year), selectable: this.isSelectable(j, prev.month, prev.year, true) });
|
||
|
}
|
||
|
let remainingDaysLength = 7 - week.length;
|
||
|
for (let j = 0; j < remainingDaysLength; j++) {
|
||
|
week.push({ day: dayNo, month: month, year: year, today: this.isToday(today, dayNo, month, year), selectable: this.isSelectable(dayNo, month, year, false) });
|
||
|
dayNo++;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
for (let j = 0; j < 7; j++) {
|
||
|
if (dayNo > daysLength) {
|
||
|
let next = this.getNextMonthAndYear(month, year);
|
||
|
week.push({
|
||
|
day: dayNo - daysLength,
|
||
|
month: next.month,
|
||
|
year: next.year,
|
||
|
otherMonth: true,
|
||
|
today: this.isToday(today, dayNo - daysLength, next.month, next.year),
|
||
|
selectable: this.isSelectable(dayNo - daysLength, next.month, next.year, true)
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
week.push({ day: dayNo, month: month, year: year, today: this.isToday(today, dayNo, month, year), selectable: this.isSelectable(dayNo, month, year, false) });
|
||
|
}
|
||
|
dayNo++;
|
||
|
}
|
||
|
}
|
||
|
if (this.showWeek) {
|
||
|
weekNumbers.push(this.getWeekNumber(new Date(week[0].year, week[0].month, week[0].day)));
|
||
|
}
|
||
|
dates.push(week);
|
||
|
}
|
||
|
return {
|
||
|
month: month,
|
||
|
year: year,
|
||
|
dates: dates,
|
||
|
weekNumbers: weekNumbers
|
||
|
};
|
||
|
}
|
||
|
initTime(date) {
|
||
|
this.pm = date.getHours() > 11;
|
||
|
if (this.showTime) {
|
||
|
this.currentMinute = date.getMinutes();
|
||
|
this.currentSecond = date.getSeconds();
|
||
|
this.setCurrentHourPM(date.getHours());
|
||
|
}
|
||
|
else if (this.timeOnly) {
|
||
|
this.currentMinute = 0;
|
||
|
this.currentHour = 0;
|
||
|
this.currentSecond = 0;
|
||
|
}
|
||
|
}
|
||
|
navBackward(event) {
|
||
|
if (this.disabled) {
|
||
|
event.preventDefault();
|
||
|
return;
|
||
|
}
|
||
|
this.isMonthNavigate = true;
|
||
|
if (this.currentView === 'month') {
|
||
|
this.decrementYear();
|
||
|
setTimeout(() => {
|
||
|
this.updateFocus();
|
||
|
}, 1);
|
||
|
}
|
||
|
else if (this.currentView === 'year') {
|
||
|
this.decrementDecade();
|
||
|
setTimeout(() => {
|
||
|
this.updateFocus();
|
||
|
}, 1);
|
||
|
}
|
||
|
else {
|
||
|
if (this.currentMonth === 0) {
|
||
|
this.currentMonth = 11;
|
||
|
this.decrementYear();
|
||
|
}
|
||
|
else {
|
||
|
this.currentMonth--;
|
||
|
}
|
||
|
this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear });
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
navForward(event) {
|
||
|
if (this.disabled) {
|
||
|
event.preventDefault();
|
||
|
return;
|
||
|
}
|
||
|
this.isMonthNavigate = true;
|
||
|
if (this.currentView === 'month') {
|
||
|
this.incrementYear();
|
||
|
setTimeout(() => {
|
||
|
this.updateFocus();
|
||
|
}, 1);
|
||
|
}
|
||
|
else if (this.currentView === 'year') {
|
||
|
this.incrementDecade();
|
||
|
setTimeout(() => {
|
||
|
this.updateFocus();
|
||
|
}, 1);
|
||
|
}
|
||
|
else {
|
||
|
if (this.currentMonth === 11) {
|
||
|
this.currentMonth = 0;
|
||
|
this.incrementYear();
|
||
|
}
|
||
|
else {
|
||
|
this.currentMonth++;
|
||
|
}
|
||
|
this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear });
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
}
|
||
|
decrementYear() {
|
||
|
this.currentYear--;
|
||
|
let _yearOptions = this.yearOptions;
|
||
|
if (this.yearNavigator && this.currentYear < _yearOptions[0]) {
|
||
|
let difference = _yearOptions[_yearOptions.length - 1] - _yearOptions[0];
|
||
|
this.populateYearOptions(_yearOptions[0] - difference, _yearOptions[_yearOptions.length - 1] - difference);
|
||
|
}
|
||
|
}
|
||
|
decrementDecade() {
|
||
|
this.currentYear = this.currentYear - 10;
|
||
|
}
|
||
|
incrementDecade() {
|
||
|
this.currentYear = this.currentYear + 10;
|
||
|
}
|
||
|
incrementYear() {
|
||
|
this.currentYear++;
|
||
|
let _yearOptions = this.yearOptions;
|
||
|
if (this.yearNavigator && this.currentYear > _yearOptions[_yearOptions.length - 1]) {
|
||
|
let difference = _yearOptions[_yearOptions.length - 1] - _yearOptions[0];
|
||
|
this.populateYearOptions(_yearOptions[0] + difference, _yearOptions[_yearOptions.length - 1] + difference);
|
||
|
}
|
||
|
}
|
||
|
switchToMonthView(event) {
|
||
|
this.setCurrentView('month');
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
switchToYearView(event) {
|
||
|
this.setCurrentView('year');
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
onDateSelect(event, dateMeta) {
|
||
|
if (this.disabled || !dateMeta.selectable) {
|
||
|
event.preventDefault();
|
||
|
return;
|
||
|
}
|
||
|
if (this.isMultipleSelection() && this.isSelected(dateMeta)) {
|
||
|
this.value = this.value.filter((date, i) => {
|
||
|
return !this.isDateEquals(date, dateMeta);
|
||
|
});
|
||
|
if (this.value.length === 0) {
|
||
|
this.value = null;
|
||
|
}
|
||
|
this.updateModel(this.value);
|
||
|
}
|
||
|
else {
|
||
|
if (this.shouldSelectDate(dateMeta)) {
|
||
|
this.selectDate(dateMeta);
|
||
|
}
|
||
|
}
|
||
|
if ((this.isSingleSelection() && this.hideOnDateTimeSelect) || (this.isRangeSelection() && this.value[1])) {
|
||
|
setTimeout(() => {
|
||
|
event.preventDefault();
|
||
|
this.hideOverlay();
|
||
|
if (this.mask) {
|
||
|
this.disableModality();
|
||
|
}
|
||
|
this.cd.markForCheck();
|
||
|
}, 150);
|
||
|
}
|
||
|
this.updateInputfield();
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
shouldSelectDate(dateMeta) {
|
||
|
if (this.isMultipleSelection())
|
||
|
return this.maxDateCount != null ? this.maxDateCount > (this.value ? this.value.length : 0) : true;
|
||
|
else
|
||
|
return true;
|
||
|
}
|
||
|
onMonthSelect(event, index) {
|
||
|
if (this.view === 'month') {
|
||
|
this.onDateSelect(event, { year: this.currentYear, month: index, day: 1, selectable: true });
|
||
|
}
|
||
|
else {
|
||
|
this.currentMonth = index;
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
this.setCurrentView('date');
|
||
|
this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear });
|
||
|
}
|
||
|
}
|
||
|
onYearSelect(event, year) {
|
||
|
if (this.view === 'year') {
|
||
|
this.onDateSelect(event, { year: year, month: 0, day: 1, selectable: true });
|
||
|
}
|
||
|
else {
|
||
|
this.currentYear = year;
|
||
|
this.setCurrentView('month');
|
||
|
this.onYearChange.emit({ month: this.currentMonth + 1, year: this.currentYear });
|
||
|
}
|
||
|
}
|
||
|
updateInputfield() {
|
||
|
let formattedValue = '';
|
||
|
if (this.value) {
|
||
|
if (this.isSingleSelection()) {
|
||
|
formattedValue = this.formatDateTime(this.value);
|
||
|
}
|
||
|
else if (this.isMultipleSelection()) {
|
||
|
for (let i = 0; i < this.value.length; i++) {
|
||
|
let dateAsString = this.formatDateTime(this.value[i]);
|
||
|
formattedValue += dateAsString;
|
||
|
if (i !== this.value.length - 1) {
|
||
|
formattedValue += this.multipleSeparator + ' ';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (this.isRangeSelection()) {
|
||
|
if (this.value && this.value.length) {
|
||
|
let startDate = this.value[0];
|
||
|
let endDate = this.value[1];
|
||
|
formattedValue = this.formatDateTime(startDate);
|
||
|
if (endDate) {
|
||
|
formattedValue += ' ' + this.rangeSeparator + ' ' + this.formatDateTime(endDate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this.inputFieldValue = formattedValue;
|
||
|
this.updateFilledState();
|
||
|
if (this.inputfieldViewChild && this.inputfieldViewChild.nativeElement) {
|
||
|
this.inputfieldViewChild.nativeElement.value = this.inputFieldValue;
|
||
|
}
|
||
|
}
|
||
|
formatDateTime(date) {
|
||
|
let formattedValue = this.keepInvalid ? date : null;
|
||
|
const isDateValid = this.isValidDateForTimeConstraints(date);
|
||
|
if (this.isValidDate(date)) {
|
||
|
if (this.timeOnly) {
|
||
|
formattedValue = this.formatTime(date);
|
||
|
}
|
||
|
else {
|
||
|
formattedValue = this.formatDate(date, this.getDateFormat());
|
||
|
if (this.showTime) {
|
||
|
formattedValue += ' ' + this.formatTime(date);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (this.dataType === 'string') {
|
||
|
formattedValue = date;
|
||
|
}
|
||
|
formattedValue = isDateValid ? formattedValue : '';
|
||
|
return formattedValue;
|
||
|
}
|
||
|
formatDateMetaToDate(dateMeta) {
|
||
|
return new Date(dateMeta.year, dateMeta.month, dateMeta.day);
|
||
|
}
|
||
|
formatDateKey(date) {
|
||
|
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
|
||
|
}
|
||
|
setCurrentHourPM(hours) {
|
||
|
if (this.hourFormat == '12') {
|
||
|
this.pm = hours > 11;
|
||
|
if (hours >= 12) {
|
||
|
this.currentHour = hours == 12 ? 12 : hours - 12;
|
||
|
}
|
||
|
else {
|
||
|
this.currentHour = hours == 0 ? 12 : hours;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this.currentHour = hours;
|
||
|
}
|
||
|
}
|
||
|
setCurrentView(currentView) {
|
||
|
this.currentView = currentView;
|
||
|
this.cd.detectChanges();
|
||
|
this.alignOverlay();
|
||
|
}
|
||
|
selectDate(dateMeta) {
|
||
|
let date = this.formatDateMetaToDate(dateMeta);
|
||
|
if (this.showTime) {
|
||
|
if (this.hourFormat == '12') {
|
||
|
if (this.currentHour === 12)
|
||
|
date.setHours(this.pm ? 12 : 0);
|
||
|
else
|
||
|
date.setHours(this.pm ? this.currentHour + 12 : this.currentHour);
|
||
|
}
|
||
|
else {
|
||
|
date.setHours(this.currentHour);
|
||
|
}
|
||
|
date.setMinutes(this.currentMinute);
|
||
|
date.setSeconds(this.currentSecond);
|
||
|
}
|
||
|
if (this.minDate && this.minDate > date) {
|
||
|
date = this.minDate;
|
||
|
this.setCurrentHourPM(date.getHours());
|
||
|
this.currentMinute = date.getMinutes();
|
||
|
this.currentSecond = date.getSeconds();
|
||
|
}
|
||
|
if (this.maxDate && this.maxDate < date) {
|
||
|
date = this.maxDate;
|
||
|
this.setCurrentHourPM(date.getHours());
|
||
|
this.currentMinute = date.getMinutes();
|
||
|
this.currentSecond = date.getSeconds();
|
||
|
}
|
||
|
if (this.isSingleSelection()) {
|
||
|
this.updateModel(date);
|
||
|
}
|
||
|
else if (this.isMultipleSelection()) {
|
||
|
this.updateModel(this.value ? [...this.value, date] : [date]);
|
||
|
}
|
||
|
else if (this.isRangeSelection()) {
|
||
|
if (this.value && this.value.length) {
|
||
|
let startDate = this.value[0];
|
||
|
let endDate = this.value[1];
|
||
|
if (!endDate && date.getTime() >= startDate.getTime()) {
|
||
|
endDate = date;
|
||
|
}
|
||
|
else {
|
||
|
startDate = date;
|
||
|
endDate = null;
|
||
|
}
|
||
|
this.updateModel([startDate, endDate]);
|
||
|
}
|
||
|
else {
|
||
|
this.updateModel([date, null]);
|
||
|
}
|
||
|
}
|
||
|
this.onSelect.emit(date);
|
||
|
}
|
||
|
updateModel(value) {
|
||
|
this.value = value;
|
||
|
if (this.dataType == 'date') {
|
||
|
this.onModelChange(this.value);
|
||
|
}
|
||
|
else if (this.dataType == 'string') {
|
||
|
if (this.isSingleSelection()) {
|
||
|
this.onModelChange(this.formatDateTime(this.value));
|
||
|
}
|
||
|
else {
|
||
|
let stringArrValue = null;
|
||
|
if (Array.isArray(this.value)) {
|
||
|
stringArrValue = this.value.map((date) => this.formatDateTime(date));
|
||
|
}
|
||
|
this.onModelChange(stringArrValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
getFirstDayOfMonthIndex(month, year) {
|
||
|
let day = new Date();
|
||
|
day.setDate(1);
|
||
|
day.setMonth(month);
|
||
|
day.setFullYear(year);
|
||
|
let dayIndex = day.getDay() + this.getSundayIndex();
|
||
|
return dayIndex >= 7 ? dayIndex - 7 : dayIndex;
|
||
|
}
|
||
|
getDaysCountInMonth(month, year) {
|
||
|
return 32 - this.daylightSavingAdjust(new Date(year, month, 32)).getDate();
|
||
|
}
|
||
|
getDaysCountInPrevMonth(month, year) {
|
||
|
let prev = this.getPreviousMonthAndYear(month, year);
|
||
|
return this.getDaysCountInMonth(prev.month, prev.year);
|
||
|
}
|
||
|
getPreviousMonthAndYear(month, year) {
|
||
|
let m, y;
|
||
|
if (month === 0) {
|
||
|
m = 11;
|
||
|
y = year - 1;
|
||
|
}
|
||
|
else {
|
||
|
m = month - 1;
|
||
|
y = year;
|
||
|
}
|
||
|
return { month: m, year: y };
|
||
|
}
|
||
|
getNextMonthAndYear(month, year) {
|
||
|
let m, y;
|
||
|
if (month === 11) {
|
||
|
m = 0;
|
||
|
y = year + 1;
|
||
|
}
|
||
|
else {
|
||
|
m = month + 1;
|
||
|
y = year;
|
||
|
}
|
||
|
return { month: m, year: y };
|
||
|
}
|
||
|
getSundayIndex() {
|
||
|
let firstDayOfWeek = this.getFirstDateOfWeek();
|
||
|
return firstDayOfWeek > 0 ? 7 - firstDayOfWeek : 0;
|
||
|
}
|
||
|
isSelected(dateMeta) {
|
||
|
if (this.value) {
|
||
|
if (this.isSingleSelection()) {
|
||
|
return this.isDateEquals(this.value, dateMeta);
|
||
|
}
|
||
|
else if (this.isMultipleSelection()) {
|
||
|
let selected = false;
|
||
|
for (let date of this.value) {
|
||
|
selected = this.isDateEquals(date, dateMeta);
|
||
|
if (selected) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return selected;
|
||
|
}
|
||
|
else if (this.isRangeSelection()) {
|
||
|
if (this.value[1])
|
||
|
return this.isDateEquals(this.value[0], dateMeta) || this.isDateEquals(this.value[1], dateMeta) || this.isDateBetween(this.value[0], this.value[1], dateMeta);
|
||
|
else
|
||
|
return this.isDateEquals(this.value[0], dateMeta);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
isComparable() {
|
||
|
return this.value != null && typeof this.value !== 'string';
|
||
|
}
|
||
|
isMonthSelected(month) {
|
||
|
if (this.isComparable() && !this.isMultipleSelection()) {
|
||
|
const [start, end] = this.isRangeSelection() ? this.value : [this.value, this.value];
|
||
|
const selected = new Date(this.currentYear, month, 1);
|
||
|
return selected >= start && selected <= (end ?? start);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
isMonthDisabled(month, year) {
|
||
|
const yearToCheck = year ?? this.currentYear;
|
||
|
for (let day = 1; day < this.getDaysCountInMonth(month, yearToCheck) + 1; day++) {
|
||
|
if (this.isSelectable(day, month, yearToCheck, false)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
isYearDisabled(year) {
|
||
|
return Array(12)
|
||
|
.fill(0)
|
||
|
.every((v, month) => this.isMonthDisabled(month, year));
|
||
|
}
|
||
|
isYearSelected(year) {
|
||
|
if (this.isComparable()) {
|
||
|
let value = this.isRangeSelection() ? this.value[0] : this.value;
|
||
|
return !this.isMultipleSelection() ? value.getFullYear() === year : false;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
isDateEquals(value, dateMeta) {
|
||
|
if (value && ObjectUtils.isDate(value))
|
||
|
return value.getDate() === dateMeta.day && value.getMonth() === dateMeta.month && value.getFullYear() === dateMeta.year;
|
||
|
else
|
||
|
return false;
|
||
|
}
|
||
|
isDateBetween(start, end, dateMeta) {
|
||
|
let between = false;
|
||
|
if (ObjectUtils.isDate(start) && ObjectUtils.isDate(end)) {
|
||
|
let date = this.formatDateMetaToDate(dateMeta);
|
||
|
return start.getTime() <= date.getTime() && end.getTime() >= date.getTime();
|
||
|
}
|
||
|
return between;
|
||
|
}
|
||
|
isSingleSelection() {
|
||
|
return this.selectionMode === 'single';
|
||
|
}
|
||
|
isRangeSelection() {
|
||
|
return this.selectionMode === 'range';
|
||
|
}
|
||
|
isMultipleSelection() {
|
||
|
return this.selectionMode === 'multiple';
|
||
|
}
|
||
|
isToday(today, day, month, year) {
|
||
|
return today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
|
||
|
}
|
||
|
isSelectable(day, month, year, otherMonth) {
|
||
|
let validMin = true;
|
||
|
let validMax = true;
|
||
|
let validDate = true;
|
||
|
let validDay = true;
|
||
|
if (otherMonth && !this.selectOtherMonths) {
|
||
|
return false;
|
||
|
}
|
||
|
if (this.minDate) {
|
||
|
if (this.minDate.getFullYear() > year) {
|
||
|
validMin = false;
|
||
|
}
|
||
|
else if (this.minDate.getFullYear() === year && this.currentView != 'year') {
|
||
|
if (this.minDate.getMonth() > month) {
|
||
|
validMin = false;
|
||
|
}
|
||
|
else if (this.minDate.getMonth() === month) {
|
||
|
if (this.minDate.getDate() > day) {
|
||
|
validMin = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (this.maxDate) {
|
||
|
if (this.maxDate.getFullYear() < year) {
|
||
|
validMax = false;
|
||
|
}
|
||
|
else if (this.maxDate.getFullYear() === year) {
|
||
|
if (this.maxDate.getMonth() < month) {
|
||
|
validMax = false;
|
||
|
}
|
||
|
else if (this.maxDate.getMonth() === month) {
|
||
|
if (this.maxDate.getDate() < day) {
|
||
|
validMax = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (this.disabledDates) {
|
||
|
validDate = !this.isDateDisabled(day, month, year);
|
||
|
}
|
||
|
if (this.disabledDays) {
|
||
|
validDay = !this.isDayDisabled(day, month, year);
|
||
|
}
|
||
|
return validMin && validMax && validDate && validDay;
|
||
|
}
|
||
|
isDateDisabled(day, month, year) {
|
||
|
if (this.disabledDates) {
|
||
|
for (let disabledDate of this.disabledDates) {
|
||
|
if (disabledDate.getFullYear() === year && disabledDate.getMonth() === month && disabledDate.getDate() === day) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
isDayDisabled(day, month, year) {
|
||
|
if (this.disabledDays) {
|
||
|
let weekday = new Date(year, month, day);
|
||
|
let weekdayNumber = weekday.getDay();
|
||
|
return this.disabledDays.indexOf(weekdayNumber) !== -1;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
onInputFocus(event) {
|
||
|
this.focus = true;
|
||
|
if (this.showOnFocus) {
|
||
|
this.showOverlay();
|
||
|
}
|
||
|
this.onFocus.emit(event);
|
||
|
}
|
||
|
onInputClick() {
|
||
|
if (this.showOnFocus && !this.overlayVisible) {
|
||
|
this.showOverlay();
|
||
|
}
|
||
|
}
|
||
|
onInputBlur(event) {
|
||
|
this.focus = false;
|
||
|
this.onBlur.emit(event);
|
||
|
if (!this.keepInvalid) {
|
||
|
this.updateInputfield();
|
||
|
}
|
||
|
this.onModelTouched();
|
||
|
}
|
||
|
onButtonClick(event, inputfield = this.inputfieldViewChild?.nativeElement) {
|
||
|
if (!this.overlayVisible) {
|
||
|
inputfield.focus();
|
||
|
this.showOverlay();
|
||
|
}
|
||
|
else {
|
||
|
this.hideOverlay();
|
||
|
}
|
||
|
}
|
||
|
clear() {
|
||
|
this.inputFieldValue = null;
|
||
|
this.value = null;
|
||
|
this.onModelChange(this.value);
|
||
|
this.onClear.emit();
|
||
|
}
|
||
|
onOverlayClick(event) {
|
||
|
this.overlayService.add({
|
||
|
originalEvent: event,
|
||
|
target: this.el.nativeElement
|
||
|
});
|
||
|
}
|
||
|
getMonthName(index) {
|
||
|
return this.config.getTranslation('monthNames')[index];
|
||
|
}
|
||
|
getYear(month) {
|
||
|
return this.currentView === 'month' ? this.currentYear : month.year;
|
||
|
}
|
||
|
switchViewButtonDisabled() {
|
||
|
return this.numberOfMonths > 1 || this.disabled;
|
||
|
}
|
||
|
onPrevButtonClick(event) {
|
||
|
this.navigationState = { backward: true, button: true };
|
||
|
this.navBackward(event);
|
||
|
}
|
||
|
onNextButtonClick(event) {
|
||
|
this.navigationState = { backward: false, button: true };
|
||
|
this.navForward(event);
|
||
|
}
|
||
|
onContainerButtonKeydown(event) {
|
||
|
switch (event.which) {
|
||
|
//tab
|
||
|
case 9:
|
||
|
if (!this.inline) {
|
||
|
this.trapFocus(event);
|
||
|
}
|
||
|
if (this.inline) {
|
||
|
const headerElements = DomHandler.findSingle(this.containerViewChild?.nativeElement, '.p-datepicker-header');
|
||
|
const element = event.target;
|
||
|
if (this.timeOnly) {
|
||
|
return;
|
||
|
}
|
||
|
else {
|
||
|
if (element == headerElements.children[headerElements?.children?.length - 1]) {
|
||
|
this.initFocusableCell();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
//escape
|
||
|
case 27:
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
this.overlayVisible = false;
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
default:
|
||
|
//Noop
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
onInputKeydown(event) {
|
||
|
this.isKeydown = true;
|
||
|
if (event.keyCode === 40 && this.contentViewChild) {
|
||
|
this.trapFocus(event);
|
||
|
}
|
||
|
else if (event.keyCode === 27) {
|
||
|
if (this.overlayVisible) {
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
this.overlayVisible = false;
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
}
|
||
|
else if (event.keyCode === 13) {
|
||
|
if (this.overlayVisible) {
|
||
|
this.overlayVisible = false;
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
}
|
||
|
else if (event.keyCode === 9 && this.contentViewChild) {
|
||
|
DomHandler.getFocusableElements(this.contentViewChild.nativeElement).forEach((el) => (el.tabIndex = '-1'));
|
||
|
if (this.overlayVisible) {
|
||
|
this.overlayVisible = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
onDateCellKeydown(event, dateMeta, groupIndex) {
|
||
|
const cellContent = event.currentTarget;
|
||
|
const cell = cellContent.parentElement;
|
||
|
const currentDate = this.formatDateMetaToDate(dateMeta);
|
||
|
switch (event.which) {
|
||
|
//down arrow
|
||
|
case 40: {
|
||
|
cellContent.tabIndex = '-1';
|
||
|
let cellIndex = DomHandler.index(cell);
|
||
|
let nextRow = cell.parentElement.nextElementSibling;
|
||
|
if (nextRow) {
|
||
|
let focusCell = nextRow.children[cellIndex].children[0];
|
||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||
|
this.navigationState = { backward: false };
|
||
|
this.navForward(event);
|
||
|
}
|
||
|
else {
|
||
|
nextRow.children[cellIndex].children[0].tabIndex = '0';
|
||
|
nextRow.children[cellIndex].children[0].focus();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this.navigationState = { backward: false };
|
||
|
this.navForward(event);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//up arrow
|
||
|
case 38: {
|
||
|
cellContent.tabIndex = '-1';
|
||
|
let cellIndex = DomHandler.index(cell);
|
||
|
let prevRow = cell.parentElement.previousElementSibling;
|
||
|
if (prevRow) {
|
||
|
let focusCell = prevRow.children[cellIndex].children[0];
|
||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||
|
this.navigationState = { backward: true };
|
||
|
this.navBackward(event);
|
||
|
}
|
||
|
else {
|
||
|
focusCell.tabIndex = '0';
|
||
|
focusCell.focus();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this.navigationState = { backward: true };
|
||
|
this.navBackward(event);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//left arrow
|
||
|
case 37: {
|
||
|
cellContent.tabIndex = '-1';
|
||
|
let prevCell = cell.previousElementSibling;
|
||
|
if (prevCell) {
|
||
|
let focusCell = prevCell.children[0];
|
||
|
if (DomHandler.hasClass(focusCell, 'p-disabled') || DomHandler.hasClass(focusCell.parentElement, 'p-datepicker-weeknumber')) {
|
||
|
this.navigateToMonth(true, groupIndex);
|
||
|
}
|
||
|
else {
|
||
|
focusCell.tabIndex = '0';
|
||
|
focusCell.focus();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this.navigateToMonth(true, groupIndex);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//right arrow
|
||
|
case 39: {
|
||
|
cellContent.tabIndex = '-1';
|
||
|
let nextCell = cell.nextElementSibling;
|
||
|
if (nextCell) {
|
||
|
let focusCell = nextCell.children[0];
|
||
|
if (DomHandler.hasClass(focusCell, 'p-disabled')) {
|
||
|
this.navigateToMonth(false, groupIndex);
|
||
|
}
|
||
|
else {
|
||
|
focusCell.tabIndex = '0';
|
||
|
focusCell.focus();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
this.navigateToMonth(false, groupIndex);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//enter
|
||
|
//space
|
||
|
case 13:
|
||
|
case 32: {
|
||
|
this.onDateSelect(event, dateMeta);
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//escape
|
||
|
case 27: {
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
this.overlayVisible = false;
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//tab
|
||
|
case 9: {
|
||
|
if (!this.inline) {
|
||
|
this.trapFocus(event);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
// page up
|
||
|
case 33: {
|
||
|
cellContent.tabIndex = '-1';
|
||
|
const dateToFocus = new Date(currentDate.getFullYear(), currentDate.getMonth() - 1, currentDate.getDate());
|
||
|
const focusKey = this.formatDateKey(dateToFocus);
|
||
|
this.navigateToMonth(true, groupIndex, `span[data-date='${focusKey}']:not(.p-disabled):not(.p-ink)`);
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
// page down
|
||
|
case 34: {
|
||
|
cellContent.tabIndex = '-1';
|
||
|
const dateToFocus = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, currentDate.getDate());
|
||
|
const focusKey = this.formatDateKey(dateToFocus);
|
||
|
this.navigateToMonth(false, groupIndex, `span[data-date='${focusKey}']:not(.p-disabled):not(.p-ink)`);
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//home
|
||
|
case 36:
|
||
|
cellContent.tabIndex = '-1';
|
||
|
const firstDayDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
|
||
|
const firstDayDateKey = this.formatDateKey(firstDayDate);
|
||
|
const firstDayCell = DomHandler.findSingle(cellContent.offsetParent, `span[data-date='${firstDayDateKey}']:not(.p-disabled):not(.p-ink)`);
|
||
|
if (firstDayCell) {
|
||
|
firstDayCell.tabIndex = '0';
|
||
|
firstDayCell.focus();
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
//end
|
||
|
case 35:
|
||
|
cellContent.tabIndex = '-1';
|
||
|
const lastDayDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
|
||
|
const lastDayDateKey = this.formatDateKey(lastDayDate);
|
||
|
const lastDayCell = DomHandler.findSingle(cellContent.offsetParent, `span[data-date='${lastDayDateKey}']:not(.p-disabled):not(.p-ink)`);
|
||
|
if (lastDayDate) {
|
||
|
lastDayCell.tabIndex = '0';
|
||
|
lastDayCell.focus();
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
default:
|
||
|
//no op
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
onMonthCellKeydown(event, index) {
|
||
|
const cell = event.currentTarget;
|
||
|
switch (event.which) {
|
||
|
//arrows
|
||
|
case 38:
|
||
|
case 40: {
|
||
|
cell.tabIndex = '-1';
|
||
|
var cells = cell.parentElement.children;
|
||
|
var cellIndex = DomHandler.index(cell);
|
||
|
let nextCell = cells[event.which === 40 ? cellIndex + 3 : cellIndex - 3];
|
||
|
if (nextCell) {
|
||
|
nextCell.tabIndex = '0';
|
||
|
nextCell.focus();
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//left arrow
|
||
|
case 37: {
|
||
|
cell.tabIndex = '-1';
|
||
|
let prevCell = cell.previousElementSibling;
|
||
|
if (prevCell) {
|
||
|
prevCell.tabIndex = '0';
|
||
|
prevCell.focus();
|
||
|
}
|
||
|
else {
|
||
|
this.navigationState = { backward: true };
|
||
|
this.navBackward(event);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//right arrow
|
||
|
case 39: {
|
||
|
cell.tabIndex = '-1';
|
||
|
let nextCell = cell.nextElementSibling;
|
||
|
if (nextCell) {
|
||
|
nextCell.tabIndex = '0';
|
||
|
nextCell.focus();
|
||
|
}
|
||
|
else {
|
||
|
this.navigationState = { backward: false };
|
||
|
this.navForward(event);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//enter
|
||
|
//space
|
||
|
case 13:
|
||
|
case 32: {
|
||
|
this.onMonthSelect(event, index);
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//escape
|
||
|
case 27: {
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
this.overlayVisible = false;
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//tab
|
||
|
case 9: {
|
||
|
if (!this.inline) {
|
||
|
this.trapFocus(event);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
//no op
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
onYearCellKeydown(event, index) {
|
||
|
const cell = event.currentTarget;
|
||
|
switch (event.which) {
|
||
|
//arrows
|
||
|
case 38:
|
||
|
case 40: {
|
||
|
cell.tabIndex = '-1';
|
||
|
var cells = cell.parentElement.children;
|
||
|
var cellIndex = DomHandler.index(cell);
|
||
|
let nextCell = cells[event.which === 40 ? cellIndex + 2 : cellIndex - 2];
|
||
|
if (nextCell) {
|
||
|
nextCell.tabIndex = '0';
|
||
|
nextCell.focus();
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//left arrow
|
||
|
case 37: {
|
||
|
cell.tabIndex = '-1';
|
||
|
let prevCell = cell.previousElementSibling;
|
||
|
if (prevCell) {
|
||
|
prevCell.tabIndex = '0';
|
||
|
prevCell.focus();
|
||
|
}
|
||
|
else {
|
||
|
this.navigationState = { backward: true };
|
||
|
this.navBackward(event);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//right arrow
|
||
|
case 39: {
|
||
|
cell.tabIndex = '-1';
|
||
|
let nextCell = cell.nextElementSibling;
|
||
|
if (nextCell) {
|
||
|
nextCell.tabIndex = '0';
|
||
|
nextCell.focus();
|
||
|
}
|
||
|
else {
|
||
|
this.navigationState = { backward: false };
|
||
|
this.navForward(event);
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//enter
|
||
|
//space
|
||
|
case 13:
|
||
|
case 32: {
|
||
|
this.onYearSelect(event, index);
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//escape
|
||
|
case 27: {
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
this.overlayVisible = false;
|
||
|
event.preventDefault();
|
||
|
break;
|
||
|
}
|
||
|
//tab
|
||
|
case 9: {
|
||
|
this.trapFocus(event);
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
//no op
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
navigateToMonth(prev, groupIndex, focusKey) {
|
||
|
if (prev) {
|
||
|
if (this.numberOfMonths === 1 || groupIndex === 0) {
|
||
|
this.navigationState = { backward: true };
|
||
|
this._focusKey = focusKey;
|
||
|
this.navBackward(event);
|
||
|
}
|
||
|
else {
|
||
|
let prevMonthContainer = this.contentViewChild.nativeElement.children[groupIndex - 1];
|
||
|
if (focusKey) {
|
||
|
const firstDayCell = DomHandler.findSingle(prevMonthContainer, focusKey);
|
||
|
firstDayCell.tabIndex = '0';
|
||
|
firstDayCell.focus();
|
||
|
}
|
||
|
else {
|
||
|
let cells = DomHandler.find(prevMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled):not(.p-ink)');
|
||
|
let focusCell = cells[cells.length - 1];
|
||
|
focusCell.tabIndex = '0';
|
||
|
focusCell.focus();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (this.numberOfMonths === 1 || groupIndex === this.numberOfMonths - 1) {
|
||
|
this.navigationState = { backward: false };
|
||
|
this._focusKey = focusKey;
|
||
|
this.navForward(event);
|
||
|
}
|
||
|
else {
|
||
|
let nextMonthContainer = this.contentViewChild.nativeElement.children[groupIndex + 1];
|
||
|
if (focusKey) {
|
||
|
const firstDayCell = DomHandler.findSingle(nextMonthContainer, focusKey);
|
||
|
firstDayCell.tabIndex = '0';
|
||
|
firstDayCell.focus();
|
||
|
}
|
||
|
else {
|
||
|
let focusCell = DomHandler.findSingle(nextMonthContainer, '.p-datepicker-calendar td span:not(.p-disabled):not(.p-ink)');
|
||
|
focusCell.tabIndex = '0';
|
||
|
focusCell.focus();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
updateFocus() {
|
||
|
let cell;
|
||
|
if (this.navigationState) {
|
||
|
if (this.navigationState.button) {
|
||
|
this.initFocusableCell();
|
||
|
if (this.navigationState.backward)
|
||
|
DomHandler.findSingle(this.contentViewChild.nativeElement, '.p-datepicker-prev').focus();
|
||
|
else
|
||
|
DomHandler.findSingle(this.contentViewChild.nativeElement, '.p-datepicker-next').focus();
|
||
|
}
|
||
|
else {
|
||
|
if (this.navigationState.backward) {
|
||
|
let cells;
|
||
|
if (this.currentView === 'month') {
|
||
|
cells = DomHandler.find(this.contentViewChild.nativeElement, '.p-monthpicker .p-monthpicker-month:not(.p-disabled)');
|
||
|
}
|
||
|
else if (this.currentView === 'year') {
|
||
|
cells = DomHandler.find(this.contentViewChild.nativeElement, '.p-yearpicker .p-yearpicker-year:not(.p-disabled)');
|
||
|
}
|
||
|
else {
|
||
|
cells = DomHandler.find(this.contentViewChild.nativeElement, this._focusKey || '.p-datepicker-calendar td span:not(.p-disabled):not(.p-ink)');
|
||
|
}
|
||
|
if (cells && cells.length > 0) {
|
||
|
cell = cells[cells.length - 1];
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (this.currentView === 'month') {
|
||
|
cell = DomHandler.findSingle(this.contentViewChild.nativeElement, '.p-monthpicker .p-monthpicker-month:not(.p-disabled)');
|
||
|
}
|
||
|
else if (this.currentView === 'year') {
|
||
|
cell = DomHandler.findSingle(this.contentViewChild.nativeElement, '.p-yearpicker .p-yearpicker-year:not(.p-disabled)');
|
||
|
}
|
||
|
else {
|
||
|
cell = DomHandler.findSingle(this.contentViewChild.nativeElement, this._focusKey || '.p-datepicker-calendar td span:not(.p-disabled):not(.p-ink)');
|
||
|
}
|
||
|
}
|
||
|
if (cell) {
|
||
|
cell.tabIndex = '0';
|
||
|
cell.focus();
|
||
|
}
|
||
|
}
|
||
|
this.navigationState = null;
|
||
|
this._focusKey = null;
|
||
|
}
|
||
|
else {
|
||
|
this.initFocusableCell();
|
||
|
}
|
||
|
}
|
||
|
initFocusableCell() {
|
||
|
const contentEl = this.contentViewChild?.nativeElement;
|
||
|
let cell;
|
||
|
if (this.currentView === 'month') {
|
||
|
let cells = DomHandler.find(contentEl, '.p-monthpicker .p-monthpicker-month:not(.p-disabled)');
|
||
|
let selectedCell = DomHandler.findSingle(contentEl, '.p-monthpicker .p-monthpicker-month.p-highlight');
|
||
|
cells.forEach((cell) => (cell.tabIndex = -1));
|
||
|
cell = selectedCell || cells[0];
|
||
|
if (cells.length === 0) {
|
||
|
let disabledCells = DomHandler.find(contentEl, '.p-monthpicker .p-monthpicker-month.p-disabled[tabindex = "0"]');
|
||
|
disabledCells.forEach((cell) => (cell.tabIndex = -1));
|
||
|
}
|
||
|
}
|
||
|
else if (this.currentView === 'year') {
|
||
|
let cells = DomHandler.find(contentEl, '.p-yearpicker .p-yearpicker-year:not(.p-disabled)');
|
||
|
let selectedCell = DomHandler.findSingle(contentEl, '.p-yearpicker .p-yearpicker-year.p-highlight');
|
||
|
cells.forEach((cell) => (cell.tabIndex = -1));
|
||
|
cell = selectedCell || cells[0];
|
||
|
if (cells.length === 0) {
|
||
|
let disabledCells = DomHandler.find(contentEl, '.p-yearpicker .p-yearpicker-year.p-disabled[tabindex = "0"]');
|
||
|
disabledCells.forEach((cell) => (cell.tabIndex = -1));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
cell = DomHandler.findSingle(contentEl, 'span.p-highlight');
|
||
|
if (!cell) {
|
||
|
let todayCell = DomHandler.findSingle(contentEl, 'td.p-datepicker-today span:not(.p-disabled):not(.p-ink)');
|
||
|
if (todayCell)
|
||
|
cell = todayCell;
|
||
|
else
|
||
|
cell = DomHandler.findSingle(contentEl, '.p-datepicker-calendar td span:not(.p-disabled):not(.p-ink)');
|
||
|
}
|
||
|
}
|
||
|
if (cell) {
|
||
|
cell.tabIndex = '0';
|
||
|
if (!this.preventFocus && (!this.navigationState || !this.navigationState.button)) {
|
||
|
setTimeout(() => {
|
||
|
if (!this.disabled) {
|
||
|
cell.focus();
|
||
|
}
|
||
|
}, 1);
|
||
|
}
|
||
|
this.preventFocus = false;
|
||
|
}
|
||
|
}
|
||
|
trapFocus(event) {
|
||
|
let focusableElements = DomHandler.getFocusableElements(this.contentViewChild.nativeElement);
|
||
|
if (focusableElements && focusableElements.length > 0) {
|
||
|
if (!focusableElements[0].ownerDocument.activeElement) {
|
||
|
focusableElements[0].focus();
|
||
|
}
|
||
|
else {
|
||
|
let focusedIndex = focusableElements.indexOf(focusableElements[0].ownerDocument.activeElement);
|
||
|
if (event.shiftKey) {
|
||
|
if (focusedIndex == -1 || focusedIndex === 0) {
|
||
|
if (this.focusTrap) {
|
||
|
focusableElements[focusableElements.length - 1].focus();
|
||
|
}
|
||
|
else {
|
||
|
if (focusedIndex === -1)
|
||
|
return this.hideOverlay();
|
||
|
else if (focusedIndex === 0)
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
focusableElements[focusedIndex - 1].focus();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (focusedIndex == -1) {
|
||
|
if (this.timeOnly) {
|
||
|
focusableElements[0].focus();
|
||
|
}
|
||
|
else {
|
||
|
let spanIndex = 0;
|
||
|
for (let i = 0; i < focusableElements.length; i++) {
|
||
|
if (focusableElements[i].tagName === 'SPAN')
|
||
|
spanIndex = i;
|
||
|
}
|
||
|
focusableElements[spanIndex].focus();
|
||
|
}
|
||
|
}
|
||
|
else if (focusedIndex === focusableElements.length - 1) {
|
||
|
if (!this.focusTrap && focusedIndex != -1)
|
||
|
return this.hideOverlay();
|
||
|
focusableElements[0].focus();
|
||
|
}
|
||
|
else {
|
||
|
focusableElements[focusedIndex + 1].focus();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
onMonthDropdownChange(m) {
|
||
|
this.currentMonth = parseInt(m);
|
||
|
this.onMonthChange.emit({ month: this.currentMonth + 1, year: this.currentYear });
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
onYearDropdownChange(y) {
|
||
|
this.currentYear = parseInt(y);
|
||
|
this.onYearChange.emit({ month: this.currentMonth + 1, year: this.currentYear });
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
}
|
||
|
convertTo24Hour(hours, pm) {
|
||
|
//@ts-ignore
|
||
|
if (this.hourFormat == '12') {
|
||
|
if (hours === 12) {
|
||
|
return pm ? 12 : 0;
|
||
|
}
|
||
|
else {
|
||
|
return pm ? hours + 12 : hours;
|
||
|
}
|
||
|
}
|
||
|
return hours;
|
||
|
}
|
||
|
constrainTime(hour, minute, second, pm) {
|
||
|
let returnTimeTriple = [hour, minute, second];
|
||
|
let minHoursExceeds12;
|
||
|
let value = this.value;
|
||
|
const convertedHour = this.convertTo24Hour(hour, pm);
|
||
|
const isRange = this.isRangeSelection(), isMultiple = this.isMultipleSelection(), isMultiValue = isRange || isMultiple;
|
||
|
if (isMultiValue) {
|
||
|
if (!this.value) {
|
||
|
this.value = [new Date(), new Date()];
|
||
|
}
|
||
|
if (isRange) {
|
||
|
value = this.value[1] || this.value[0];
|
||
|
}
|
||
|
if (isMultiple) {
|
||
|
value = this.value[this.value.length - 1];
|
||
|
}
|
||
|
}
|
||
|
const valueDateString = value ? value.toDateString() : null;
|
||
|
let isMinDate = this.minDate && valueDateString && this.minDate.toDateString() === valueDateString;
|
||
|
let isMaxDate = this.maxDate && valueDateString && this.maxDate.toDateString() === valueDateString;
|
||
|
if (isMinDate) {
|
||
|
minHoursExceeds12 = this.minDate.getHours() >= 12;
|
||
|
}
|
||
|
switch (true // intentional fall through
|
||
|
) {
|
||
|
case isMinDate && minHoursExceeds12 && this.minDate.getHours() === 12 && this.minDate.getHours() > convertedHour:
|
||
|
returnTimeTriple[0] = 11;
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute:
|
||
|
returnTimeTriple[1] = this.minDate.getMinutes();
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second:
|
||
|
returnTimeTriple[2] = this.minDate.getSeconds();
|
||
|
break;
|
||
|
case isMinDate && !minHoursExceeds12 && this.minDate.getHours() - 1 === convertedHour && this.minDate.getHours() > convertedHour:
|
||
|
returnTimeTriple[0] = 11;
|
||
|
this.pm = true;
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute:
|
||
|
returnTimeTriple[1] = this.minDate.getMinutes();
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second:
|
||
|
returnTimeTriple[2] = this.minDate.getSeconds();
|
||
|
break;
|
||
|
case isMinDate && minHoursExceeds12 && this.minDate.getHours() > convertedHour && convertedHour !== 12:
|
||
|
this.setCurrentHourPM(this.minDate.getHours());
|
||
|
returnTimeTriple[0] = this.currentHour;
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute:
|
||
|
returnTimeTriple[1] = this.minDate.getMinutes();
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second:
|
||
|
returnTimeTriple[2] = this.minDate.getSeconds();
|
||
|
break;
|
||
|
case isMinDate && this.minDate.getHours() > convertedHour:
|
||
|
returnTimeTriple[0] = this.minDate.getHours();
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() > minute:
|
||
|
returnTimeTriple[1] = this.minDate.getMinutes();
|
||
|
case isMinDate && this.minDate.getHours() === convertedHour && this.minDate.getMinutes() === minute && this.minDate.getSeconds() > second:
|
||
|
returnTimeTriple[2] = this.minDate.getSeconds();
|
||
|
break;
|
||
|
case isMaxDate && this.maxDate.getHours() < convertedHour:
|
||
|
returnTimeTriple[0] = this.maxDate.getHours();
|
||
|
case isMaxDate && this.maxDate.getHours() === convertedHour && this.maxDate.getMinutes() < minute:
|
||
|
returnTimeTriple[1] = this.maxDate.getMinutes();
|
||
|
case isMaxDate && this.maxDate.getHours() === convertedHour && this.maxDate.getMinutes() === minute && this.maxDate.getSeconds() < second:
|
||
|
returnTimeTriple[2] = this.maxDate.getSeconds();
|
||
|
break;
|
||
|
}
|
||
|
return returnTimeTriple;
|
||
|
}
|
||
|
incrementHour(event) {
|
||
|
const prevHour = this.currentHour ?? 0;
|
||
|
let newHour = (this.currentHour ?? 0) + this.stepHour;
|
||
|
let newPM = this.pm;
|
||
|
if (this.hourFormat == '24')
|
||
|
newHour = newHour >= 24 ? newHour - 24 : newHour;
|
||
|
else if (this.hourFormat == '12') {
|
||
|
// Before the AM/PM break, now after
|
||
|
if (prevHour < 12 && newHour > 11) {
|
||
|
newPM = !this.pm;
|
||
|
}
|
||
|
newHour = newHour >= 13 ? newHour - 12 : newHour;
|
||
|
}
|
||
|
this.toggleAMPMIfNotMinDate(newPM);
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(newHour, this.currentMinute, this.currentSecond, newPM);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
toggleAMPMIfNotMinDate(newPM) {
|
||
|
let value = this.value;
|
||
|
const valueDateString = value ? value.toDateString() : null;
|
||
|
let isMinDate = this.minDate && valueDateString && this.minDate.toDateString() === valueDateString;
|
||
|
if (isMinDate && this.minDate.getHours() >= 12) {
|
||
|
this.pm = true;
|
||
|
}
|
||
|
else {
|
||
|
this.pm = newPM;
|
||
|
}
|
||
|
}
|
||
|
onTimePickerElementMouseDown(event, type, direction) {
|
||
|
if (!this.disabled) {
|
||
|
this.repeat(event, null, type, direction);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
}
|
||
|
onTimePickerElementMouseUp(event) {
|
||
|
if (!this.disabled) {
|
||
|
this.clearTimePickerTimer();
|
||
|
this.updateTime();
|
||
|
}
|
||
|
}
|
||
|
onTimePickerElementMouseLeave() {
|
||
|
if (!this.disabled && this.timePickerTimer) {
|
||
|
this.clearTimePickerTimer();
|
||
|
this.updateTime();
|
||
|
}
|
||
|
}
|
||
|
repeat(event, interval, type, direction) {
|
||
|
let i = interval || 500;
|
||
|
this.clearTimePickerTimer();
|
||
|
this.timePickerTimer = setTimeout(() => {
|
||
|
this.repeat(event, 100, type, direction);
|
||
|
this.cd.markForCheck();
|
||
|
}, i);
|
||
|
switch (type) {
|
||
|
case 0:
|
||
|
if (direction === 1)
|
||
|
this.incrementHour(event);
|
||
|
else
|
||
|
this.decrementHour(event);
|
||
|
break;
|
||
|
case 1:
|
||
|
if (direction === 1)
|
||
|
this.incrementMinute(event);
|
||
|
else
|
||
|
this.decrementMinute(event);
|
||
|
break;
|
||
|
case 2:
|
||
|
if (direction === 1)
|
||
|
this.incrementSecond(event);
|
||
|
else
|
||
|
this.decrementSecond(event);
|
||
|
break;
|
||
|
}
|
||
|
this.updateInputfield();
|
||
|
}
|
||
|
clearTimePickerTimer() {
|
||
|
if (this.timePickerTimer) {
|
||
|
clearTimeout(this.timePickerTimer);
|
||
|
this.timePickerTimer = null;
|
||
|
}
|
||
|
}
|
||
|
decrementHour(event) {
|
||
|
let newHour = (this.currentHour ?? 0) - this.stepHour;
|
||
|
let newPM = this.pm;
|
||
|
if (this.hourFormat == '24')
|
||
|
newHour = newHour < 0 ? 24 + newHour : newHour;
|
||
|
else if (this.hourFormat == '12') {
|
||
|
// If we were at noon/midnight, then switch
|
||
|
if (this.currentHour === 12) {
|
||
|
newPM = !this.pm;
|
||
|
}
|
||
|
newHour = newHour <= 0 ? 12 + newHour : newHour;
|
||
|
}
|
||
|
this.toggleAMPMIfNotMinDate(newPM);
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(newHour, this.currentMinute, this.currentSecond, newPM);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
incrementMinute(event) {
|
||
|
let newMinute = (this.currentMinute ?? 0) + this.stepMinute;
|
||
|
newMinute = newMinute > 59 ? newMinute - 60 : newMinute;
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, newMinute, this.currentSecond, this.pm);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
decrementMinute(event) {
|
||
|
let newMinute = (this.currentMinute ?? 0) - this.stepMinute;
|
||
|
newMinute = newMinute < 0 ? 60 + newMinute : newMinute;
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, newMinute, this.currentSecond, this.pm);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
incrementSecond(event) {
|
||
|
let newSecond = this.currentSecond + this.stepSecond;
|
||
|
newSecond = newSecond > 59 ? newSecond - 60 : newSecond;
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, this.currentMinute, newSecond, this.pm);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
decrementSecond(event) {
|
||
|
let newSecond = this.currentSecond - this.stepSecond;
|
||
|
newSecond = newSecond < 0 ? 60 + newSecond : newSecond;
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, this.currentMinute, newSecond, this.pm);
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
updateTime() {
|
||
|
let value = this.value;
|
||
|
if (this.isRangeSelection()) {
|
||
|
value = this.value[1] || this.value[0];
|
||
|
}
|
||
|
if (this.isMultipleSelection()) {
|
||
|
value = this.value[this.value.length - 1];
|
||
|
}
|
||
|
value = value ? new Date(value.getTime()) : new Date();
|
||
|
if (this.hourFormat == '12') {
|
||
|
if (this.currentHour === 12)
|
||
|
value.setHours(this.pm ? 12 : 0);
|
||
|
else
|
||
|
value.setHours(this.pm ? this.currentHour + 12 : this.currentHour);
|
||
|
}
|
||
|
else {
|
||
|
value.setHours(this.currentHour);
|
||
|
}
|
||
|
value.setMinutes(this.currentMinute);
|
||
|
value.setSeconds(this.currentSecond);
|
||
|
if (this.isRangeSelection()) {
|
||
|
if (this.value[1])
|
||
|
value = [this.value[0], value];
|
||
|
else
|
||
|
value = [value, null];
|
||
|
}
|
||
|
if (this.isMultipleSelection()) {
|
||
|
value = [...this.value.slice(0, -1), value];
|
||
|
}
|
||
|
this.updateModel(value);
|
||
|
this.onSelect.emit(value);
|
||
|
this.updateInputfield();
|
||
|
}
|
||
|
toggleAMPM(event) {
|
||
|
const newPM = !this.pm;
|
||
|
this.pm = newPM;
|
||
|
[this.currentHour, this.currentMinute, this.currentSecond] = this.constrainTime(this.currentHour, this.currentMinute, this.currentSecond, newPM);
|
||
|
this.updateTime();
|
||
|
event.preventDefault();
|
||
|
}
|
||
|
onUserInput(event) {
|
||
|
// IE 11 Workaround for input placeholder : https://github.com/primefaces/primeng/issues/2026
|
||
|
if (!this.isKeydown) {
|
||
|
return;
|
||
|
}
|
||
|
this.isKeydown = false;
|
||
|
let val = event.target.value;
|
||
|
try {
|
||
|
let value = this.parseValueFromString(val);
|
||
|
if (this.isValidSelection(value)) {
|
||
|
this.updateModel(value);
|
||
|
this.updateUI();
|
||
|
}
|
||
|
else if (this.keepInvalid) {
|
||
|
this.updateModel(value);
|
||
|
}
|
||
|
}
|
||
|
catch (err) {
|
||
|
//invalid date
|
||
|
let value = this.keepInvalid ? val : null;
|
||
|
this.updateModel(value);
|
||
|
}
|
||
|
this.filled = (val != null && val.length);
|
||
|
this.onInput.emit(event);
|
||
|
}
|
||
|
isValidSelection(value) {
|
||
|
if (this.isSingleSelection()) {
|
||
|
return this.isSelectable(value.getDate(), value.getMonth(), value.getFullYear(), false);
|
||
|
}
|
||
|
let isValid = value.every((v) => this.isSelectable(v.getDate(), v.getMonth(), v.getFullYear(), false));
|
||
|
if (isValid && this.isRangeSelection()) {
|
||
|
isValid = value.length === 1 || (value.length > 1 && value[1] >= value[0]);
|
||
|
}
|
||
|
return isValid;
|
||
|
}
|
||
|
parseValueFromString(text) {
|
||
|
if (!text || text.trim().length === 0) {
|
||
|
return null;
|
||
|
}
|
||
|
let value;
|
||
|
if (this.isSingleSelection()) {
|
||
|
value = this.parseDateTime(text);
|
||
|
}
|
||
|
else if (this.isMultipleSelection()) {
|
||
|
let tokens = text.split(this.multipleSeparator);
|
||
|
value = [];
|
||
|
for (let token of tokens) {
|
||
|
value.push(this.parseDateTime(token.trim()));
|
||
|
}
|
||
|
}
|
||
|
else if (this.isRangeSelection()) {
|
||
|
let tokens = text.split(' ' + this.rangeSeparator + ' ');
|
||
|
value = [];
|
||
|
for (let i = 0; i < tokens.length; i++) {
|
||
|
value[i] = this.parseDateTime(tokens[i].trim());
|
||
|
}
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
parseDateTime(text) {
|
||
|
let date;
|
||
|
let parts = text.split(' ');
|
||
|
if (this.timeOnly) {
|
||
|
date = new Date();
|
||
|
this.populateTime(date, parts[0], parts[1]);
|
||
|
}
|
||
|
else {
|
||
|
const dateFormat = this.getDateFormat();
|
||
|
if (this.showTime) {
|
||
|
let ampm = this.hourFormat == '12' ? parts.pop() : null;
|
||
|
let timeString = parts.pop();
|
||
|
date = this.parseDate(parts.join(' '), dateFormat);
|
||
|
this.populateTime(date, timeString, ampm);
|
||
|
}
|
||
|
else {
|
||
|
date = this.parseDate(text, dateFormat);
|
||
|
}
|
||
|
}
|
||
|
return date;
|
||
|
}
|
||
|
populateTime(value, timeString, ampm) {
|
||
|
if (this.hourFormat == '12' && !ampm) {
|
||
|
throw 'Invalid Time';
|
||
|
}
|
||
|
this.pm = ampm === 'PM' || ampm === 'pm';
|
||
|
let time = this.parseTime(timeString);
|
||
|
value.setHours(time.hour);
|
||
|
value.setMinutes(time.minute);
|
||
|
value.setSeconds(time.second);
|
||
|
}
|
||
|
isValidDate(date) {
|
||
|
return ObjectUtils.isDate(date) && ObjectUtils.isNotEmpty(date);
|
||
|
}
|
||
|
updateUI() {
|
||
|
let propValue = this.value;
|
||
|
if (Array.isArray(propValue)) {
|
||
|
propValue = propValue.length === 2 ? propValue[1] : propValue[0];
|
||
|
}
|
||
|
let val = this.defaultDate && this.isValidDate(this.defaultDate) && !this.value ? this.defaultDate : propValue && this.isValidDate(propValue) ? propValue : new Date();
|
||
|
this.currentMonth = val.getMonth();
|
||
|
this.currentYear = val.getFullYear();
|
||
|
this.createMonths(this.currentMonth, this.currentYear);
|
||
|
if (this.showTime || this.timeOnly) {
|
||
|
this.setCurrentHourPM(val.getHours());
|
||
|
this.currentMinute = val.getMinutes();
|
||
|
this.currentSecond = val.getSeconds();
|
||
|
}
|
||
|
}
|
||
|
showOverlay() {
|
||
|
if (!this.overlayVisible) {
|
||
|
this.updateUI();
|
||
|
if (!this.touchUI) {
|
||
|
this.preventFocus = true;
|
||
|
}
|
||
|
this.overlayVisible = true;
|
||
|
}
|
||
|
}
|
||
|
hideOverlay() {
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
this.overlayVisible = false;
|
||
|
this.clearTimePickerTimer();
|
||
|
if (this.touchUI) {
|
||
|
this.disableModality();
|
||
|
}
|
||
|
this.cd.markForCheck();
|
||
|
}
|
||
|
toggle() {
|
||
|
if (!this.inline) {
|
||
|
if (!this.overlayVisible) {
|
||
|
this.showOverlay();
|
||
|
this.inputfieldViewChild?.nativeElement.focus();
|
||
|
}
|
||
|
else {
|
||
|
this.hideOverlay();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
onOverlayAnimationStart(event) {
|
||
|
switch (event.toState) {
|
||
|
case 'visible':
|
||
|
case 'visibleTouchUI':
|
||
|
if (!this.inline) {
|
||
|
this.overlay = event.element;
|
||
|
this.overlay?.setAttribute(this.attributeSelector, '');
|
||
|
this.appendOverlay();
|
||
|
this.updateFocus();
|
||
|
if (this.autoZIndex) {
|
||
|
if (this.touchUI)
|
||
|
ZIndexUtils.set('modal', this.overlay, this.baseZIndex || this.config.zIndex.modal);
|
||
|
else
|
||
|
ZIndexUtils.set('overlay', this.overlay, this.baseZIndex || this.config.zIndex.overlay);
|
||
|
}
|
||
|
this.alignOverlay();
|
||
|
this.onShow.emit(event);
|
||
|
}
|
||
|
break;
|
||
|
case 'void':
|
||
|
this.onOverlayHide();
|
||
|
this.onClose.emit(event);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
onOverlayAnimationDone(event) {
|
||
|
switch (event.toState) {
|
||
|
case 'visible':
|
||
|
case 'visibleTouchUI':
|
||
|
if (!this.inline) {
|
||
|
this.bindDocumentClickListener();
|
||
|
this.bindDocumentResizeListener();
|
||
|
this.bindScrollListener();
|
||
|
}
|
||
|
break;
|
||
|
case 'void':
|
||
|
if (this.autoZIndex) {
|
||
|
ZIndexUtils.clear(event.element);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
appendOverlay() {
|
||
|
if (this.appendTo) {
|
||
|
if (this.appendTo === 'body')
|
||
|
this.document.body.appendChild(this.overlay);
|
||
|
else
|
||
|
DomHandler.appendChild(this.overlay, this.appendTo);
|
||
|
}
|
||
|
}
|
||
|
restoreOverlayAppend() {
|
||
|
if (this.overlay && this.appendTo) {
|
||
|
this.el.nativeElement.appendChild(this.overlay);
|
||
|
}
|
||
|
}
|
||
|
alignOverlay() {
|
||
|
if (this.touchUI) {
|
||
|
this.enableModality(this.overlay);
|
||
|
}
|
||
|
else if (this.overlay) {
|
||
|
if (this.appendTo) {
|
||
|
if (this.view === 'date') {
|
||
|
this.overlay.style.width = DomHandler.getOuterWidth(this.overlay) + 'px';
|
||
|
this.overlay.style.minWidth = DomHandler.getOuterWidth(this.inputfieldViewChild?.nativeElement) + 'px';
|
||
|
}
|
||
|
else {
|
||
|
this.overlay.style.width = DomHandler.getOuterWidth(this.inputfieldViewChild?.nativeElement) + 'px';
|
||
|
}
|
||
|
DomHandler.absolutePosition(this.overlay, this.inputfieldViewChild?.nativeElement);
|
||
|
}
|
||
|
else {
|
||
|
DomHandler.relativePosition(this.overlay, this.inputfieldViewChild?.nativeElement);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
enableModality(element) {
|
||
|
if (!this.mask && this.touchUI) {
|
||
|
this.mask = this.renderer.createElement('div');
|
||
|
this.renderer.setStyle(this.mask, 'zIndex', String(parseInt(element.style.zIndex) - 1));
|
||
|
let maskStyleClass = 'p-component-overlay p-datepicker-mask p-datepicker-mask-scrollblocker p-component-overlay p-component-overlay-enter';
|
||
|
DomHandler.addMultipleClasses(this.mask, maskStyleClass);
|
||
|
this.maskClickListener = this.renderer.listen(this.mask, 'click', (event) => {
|
||
|
this.disableModality();
|
||
|
this.overlayVisible = false;
|
||
|
});
|
||
|
this.renderer.appendChild(this.document.body, this.mask);
|
||
|
DomHandler.blockBodyScroll();
|
||
|
}
|
||
|
}
|
||
|
disableModality() {
|
||
|
if (this.mask) {
|
||
|
DomHandler.addClass(this.mask, 'p-component-overlay-leave');
|
||
|
if (!this.animationEndListener) {
|
||
|
this.animationEndListener = this.renderer.listen(this.mask, 'animationend', this.destroyMask.bind(this));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
destroyMask() {
|
||
|
if (!this.mask) {
|
||
|
return;
|
||
|
}
|
||
|
this.renderer.removeChild(this.document.body, this.mask);
|
||
|
let bodyChildren = this.document.body.children;
|
||
|
let hasBlockerMasks;
|
||
|
for (let i = 0; i < bodyChildren.length; i++) {
|
||
|
let bodyChild = bodyChildren[i];
|
||
|
if (DomHandler.hasClass(bodyChild, 'p-datepicker-mask-scrollblocker')) {
|
||
|
hasBlockerMasks = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!hasBlockerMasks) {
|
||
|
DomHandler.unblockBodyScroll();
|
||
|
}
|
||
|
this.unbindAnimationEndListener();
|
||
|
this.unbindMaskClickListener();
|
||
|
this.mask = null;
|
||
|
}
|
||
|
unbindMaskClickListener() {
|
||
|
if (this.maskClickListener) {
|
||
|
this.maskClickListener();
|
||
|
this.maskClickListener = null;
|
||
|
}
|
||
|
}
|
||
|
unbindAnimationEndListener() {
|
||
|
if (this.animationEndListener && this.mask) {
|
||
|
this.animationEndListener();
|
||
|
this.animationEndListener = null;
|
||
|
}
|
||
|
}
|
||
|
writeValue(value) {
|
||
|
this.value = value;
|
||
|
if (this.value && typeof this.value === 'string') {
|
||
|
try {
|
||
|
this.value = this.parseValueFromString(this.value);
|
||
|
}
|
||
|
catch {
|
||
|
if (this.keepInvalid) {
|
||
|
this.value = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
this.updateInputfield();
|
||
|
this.updateUI();
|
||
|
this.cd.markForCheck();
|
||
|
}
|
||
|
registerOnChange(fn) {
|
||
|
this.onModelChange = fn;
|
||
|
}
|
||
|
registerOnTouched(fn) {
|
||
|
this.onModelTouched = fn;
|
||
|
}
|
||
|
setDisabledState(val) {
|
||
|
this.disabled = val;
|
||
|
this.cd.markForCheck();
|
||
|
}
|
||
|
getDateFormat() {
|
||
|
return this.dateFormat || this.getTranslation('dateFormat');
|
||
|
}
|
||
|
getFirstDateOfWeek() {
|
||
|
return this._firstDayOfWeek || this.getTranslation(TranslationKeys.FIRST_DAY_OF_WEEK);
|
||
|
}
|
||
|
// Ported from jquery-ui datepicker formatDate
|
||
|
formatDate(date, format) {
|
||
|
if (!date) {
|
||
|
return '';
|
||
|
}
|
||
|
let iFormat;
|
||
|
const lookAhead = (match) => {
|
||
|
const matches = iFormat + 1 < format.length && format.charAt(iFormat + 1) === match;
|
||
|
if (matches) {
|
||
|
iFormat++;
|
||
|
}
|
||
|
return matches;
|
||
|
}, formatNumber = (match, value, len) => {
|
||
|
let num = '' + value;
|
||
|
if (lookAhead(match)) {
|
||
|
while (num.length < len) {
|
||
|
num = '0' + num;
|
||
|
}
|
||
|
}
|
||
|
return num;
|
||
|
}, formatName = (match, value, shortNames, longNames) => {
|
||
|
return lookAhead(match) ? longNames[value] : shortNames[value];
|
||
|
};
|
||
|
let output = '';
|
||
|
let literal = false;
|
||
|
if (date) {
|
||
|
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
||
|
if (literal) {
|
||
|
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
||
|
literal = false;
|
||
|
}
|
||
|
else {
|
||
|
output += format.charAt(iFormat);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
switch (format.charAt(iFormat)) {
|
||
|
case 'd':
|
||
|
output += formatNumber('d', date.getDate(), 2);
|
||
|
break;
|
||
|
case 'D':
|
||
|
output += formatName('D', date.getDay(), this.getTranslation(TranslationKeys.DAY_NAMES_SHORT), this.getTranslation(TranslationKeys.DAY_NAMES));
|
||
|
break;
|
||
|
case 'o':
|
||
|
output += formatNumber('o', Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
|
||
|
break;
|
||
|
case 'm':
|
||
|
output += formatNumber('m', date.getMonth() + 1, 2);
|
||
|
break;
|
||
|
case 'M':
|
||
|
output += formatName('M', date.getMonth(), this.getTranslation(TranslationKeys.MONTH_NAMES_SHORT), this.getTranslation(TranslationKeys.MONTH_NAMES));
|
||
|
break;
|
||
|
case 'y':
|
||
|
output += lookAhead('y') ? date.getFullYear() : (date.getFullYear() % 100 < 10 ? '0' : '') + (date.getFullYear() % 100);
|
||
|
break;
|
||
|
case '@':
|
||
|
output += date.getTime();
|
||
|
break;
|
||
|
case '!':
|
||
|
output += date.getTime() * 10000 + this.ticksTo1970;
|
||
|
break;
|
||
|
case "'":
|
||
|
if (lookAhead("'")) {
|
||
|
output += "'";
|
||
|
}
|
||
|
else {
|
||
|
literal = true;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
output += format.charAt(iFormat);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return output;
|
||
|
}
|
||
|
formatTime(date) {
|
||
|
if (!date) {
|
||
|
return '';
|
||
|
}
|
||
|
let output = '';
|
||
|
let hours = date.getHours();
|
||
|
let minutes = date.getMinutes();
|
||
|
let seconds = date.getSeconds();
|
||
|
if (this.hourFormat == '12' && hours > 11 && hours != 12) {
|
||
|
hours -= 12;
|
||
|
}
|
||
|
if (this.hourFormat == '12') {
|
||
|
output += hours === 0 ? 12 : hours < 10 ? '0' + hours : hours;
|
||
|
}
|
||
|
else {
|
||
|
output += hours < 10 ? '0' + hours : hours;
|
||
|
}
|
||
|
output += ':';
|
||
|
output += minutes < 10 ? '0' + minutes : minutes;
|
||
|
if (this.showSeconds) {
|
||
|
output += ':';
|
||
|
output += seconds < 10 ? '0' + seconds : seconds;
|
||
|
}
|
||
|
if (this.hourFormat == '12') {
|
||
|
output += date.getHours() > 11 ? ' PM' : ' AM';
|
||
|
}
|
||
|
return output;
|
||
|
}
|
||
|
parseTime(value) {
|
||
|
let tokens = value.split(':');
|
||
|
let validTokenLength = this.showSeconds ? 3 : 2;
|
||
|
if (tokens.length !== validTokenLength) {
|
||
|
throw 'Invalid time';
|
||
|
}
|
||
|
let h = parseInt(tokens[0]);
|
||
|
let m = parseInt(tokens[1]);
|
||
|
let s = this.showSeconds ? parseInt(tokens[2]) : null;
|
||
|
if (isNaN(h) || isNaN(m) || h > 23 || m > 59 || (this.hourFormat == '12' && h > 12) || (this.showSeconds && (isNaN(s) || s > 59))) {
|
||
|
throw 'Invalid time';
|
||
|
}
|
||
|
else {
|
||
|
if (this.hourFormat == '12') {
|
||
|
if (h !== 12 && this.pm) {
|
||
|
h += 12;
|
||
|
}
|
||
|
else if (!this.pm && h === 12) {
|
||
|
h -= 12;
|
||
|
}
|
||
|
}
|
||
|
return { hour: h, minute: m, second: s };
|
||
|
}
|
||
|
}
|
||
|
// Ported from jquery-ui datepicker parseDate
|
||
|
parseDate(value, format) {
|
||
|
if (format == null || value == null) {
|
||
|
throw 'Invalid arguments';
|
||
|
}
|
||
|
value = typeof value === 'object' ? value.toString() : value + '';
|
||
|
if (value === '') {
|
||
|
return null;
|
||
|
}
|
||
|
let iFormat, dim, extra, iValue = 0, shortYearCutoff = typeof this.shortYearCutoff !== 'string' ? this.shortYearCutoff : (new Date().getFullYear() % 100) + parseInt(this.shortYearCutoff, 10), year = -1, month = -1, day = -1, doy = -1, literal = false, date, lookAhead = (match) => {
|
||
|
let matches = iFormat + 1 < format.length && format.charAt(iFormat + 1) === match;
|
||
|
if (matches) {
|
||
|
iFormat++;
|
||
|
}
|
||
|
return matches;
|
||
|
}, getNumber = (match) => {
|
||
|
let isDoubled = lookAhead(match), size = match === '@' ? 14 : match === '!' ? 20 : match === 'y' && isDoubled ? 4 : match === 'o' ? 3 : 2, minSize = match === 'y' ? size : 1, digits = new RegExp('^\\d{' + minSize + ',' + size + '}'), num = value.substring(iValue).match(digits);
|
||
|
if (!num) {
|
||
|
throw 'Missing number at position ' + iValue;
|
||
|
}
|
||
|
iValue += num[0].length;
|
||
|
return parseInt(num[0], 10);
|
||
|
}, getName = (match, shortNames, longNames) => {
|
||
|
let index = -1;
|
||
|
let arr = lookAhead(match) ? longNames : shortNames;
|
||
|
let names = [];
|
||
|
for (let i = 0; i < arr.length; i++) {
|
||
|
names.push([i, arr[i]]);
|
||
|
}
|
||
|
names.sort((a, b) => {
|
||
|
return -(a[1].length - b[1].length);
|
||
|
});
|
||
|
for (let i = 0; i < names.length; i++) {
|
||
|
let name = names[i][1];
|
||
|
if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
|
||
|
index = names[i][0];
|
||
|
iValue += name.length;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (index !== -1) {
|
||
|
return index + 1;
|
||
|
}
|
||
|
else {
|
||
|
throw 'Unknown name at position ' + iValue;
|
||
|
}
|
||
|
}, checkLiteral = () => {
|
||
|
if (value.charAt(iValue) !== format.charAt(iFormat)) {
|
||
|
throw 'Unexpected literal at position ' + iValue;
|
||
|
}
|
||
|
iValue++;
|
||
|
};
|
||
|
if (this.view === 'month') {
|
||
|
day = 1;
|
||
|
}
|
||
|
for (iFormat = 0; iFormat < format.length; iFormat++) {
|
||
|
if (literal) {
|
||
|
if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
|
||
|
literal = false;
|
||
|
}
|
||
|
else {
|
||
|
checkLiteral();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
switch (format.charAt(iFormat)) {
|
||
|
case 'd':
|
||
|
day = getNumber('d');
|
||
|
break;
|
||
|
case 'D':
|
||
|
getName('D', this.getTranslation(TranslationKeys.DAY_NAMES_SHORT), this.getTranslation(TranslationKeys.DAY_NAMES));
|
||
|
break;
|
||
|
case 'o':
|
||
|
doy = getNumber('o');
|
||
|
break;
|
||
|
case 'm':
|
||
|
month = getNumber('m');
|
||
|
break;
|
||
|
case 'M':
|
||
|
month = getName('M', this.getTranslation(TranslationKeys.MONTH_NAMES_SHORT), this.getTranslation(TranslationKeys.MONTH_NAMES));
|
||
|
break;
|
||
|
case 'y':
|
||
|
year = getNumber('y');
|
||
|
break;
|
||
|
case '@':
|
||
|
date = new Date(getNumber('@'));
|
||
|
year = date.getFullYear();
|
||
|
month = date.getMonth() + 1;
|
||
|
day = date.getDate();
|
||
|
break;
|
||
|
case '!':
|
||
|
date = new Date((getNumber('!') - this.ticksTo1970) / 10000);
|
||
|
year = date.getFullYear();
|
||
|
month = date.getMonth() + 1;
|
||
|
day = date.getDate();
|
||
|
break;
|
||
|
case "'":
|
||
|
if (lookAhead("'")) {
|
||
|
checkLiteral();
|
||
|
}
|
||
|
else {
|
||
|
literal = true;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
checkLiteral();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (iValue < value.length) {
|
||
|
extra = value.substr(iValue);
|
||
|
if (!/^\s+/.test(extra)) {
|
||
|
throw 'Extra/unparsed characters found in date: ' + extra;
|
||
|
}
|
||
|
}
|
||
|
if (year === -1) {
|
||
|
year = new Date().getFullYear();
|
||
|
}
|
||
|
else if (year < 100) {
|
||
|
year += new Date().getFullYear() - (new Date().getFullYear() % 100) + (year <= shortYearCutoff ? 0 : -100);
|
||
|
}
|
||
|
if (doy > -1) {
|
||
|
month = 1;
|
||
|
day = doy;
|
||
|
do {
|
||
|
dim = this.getDaysCountInMonth(year, month - 1);
|
||
|
if (day <= dim) {
|
||
|
break;
|
||
|
}
|
||
|
month++;
|
||
|
day -= dim;
|
||
|
} while (true);
|
||
|
}
|
||
|
if (this.view === 'year') {
|
||
|
month = month === -1 ? 1 : month;
|
||
|
day = day === -1 ? 1 : day;
|
||
|
}
|
||
|
date = this.daylightSavingAdjust(new Date(year, month - 1, day));
|
||
|
if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
|
||
|
throw 'Invalid date'; // E.g. 31/02/00
|
||
|
}
|
||
|
return date;
|
||
|
}
|
||
|
daylightSavingAdjust(date) {
|
||
|
if (!date) {
|
||
|
return null;
|
||
|
}
|
||
|
date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
|
||
|
return date;
|
||
|
}
|
||
|
updateFilledState() {
|
||
|
this.filled = (this.inputFieldValue && this.inputFieldValue != '');
|
||
|
}
|
||
|
isValidDateForTimeConstraints(selectedDate) {
|
||
|
if (this.keepInvalid) {
|
||
|
return true; // If we are keeping invalid dates, we don't need to check for time constraints
|
||
|
}
|
||
|
return (!this.minDate || selectedDate >= this.minDate) && (!this.maxDate || selectedDate <= this.maxDate);
|
||
|
}
|
||
|
onTodayButtonClick(event) {
|
||
|
const date = new Date();
|
||
|
const dateMeta = { day: date.getDate(), month: date.getMonth(), year: date.getFullYear(), otherMonth: date.getMonth() !== this.currentMonth || date.getFullYear() !== this.currentYear, today: true, selectable: true };
|
||
|
this.createMonths(date.getMonth(), date.getFullYear());
|
||
|
this.onDateSelect(event, dateMeta);
|
||
|
this.onTodayClick.emit(date);
|
||
|
}
|
||
|
onClearButtonClick(event) {
|
||
|
this.updateModel(null);
|
||
|
this.updateInputfield();
|
||
|
this.hideOverlay();
|
||
|
this.onClearClick.emit(event);
|
||
|
}
|
||
|
createResponsiveStyle() {
|
||
|
if (this.numberOfMonths > 1 && this.responsiveOptions) {
|
||
|
if (!this.responsiveStyleElement) {
|
||
|
this.responsiveStyleElement = this.renderer.createElement('style');
|
||
|
this.responsiveStyleElement.type = 'text/css';
|
||
|
this.renderer.appendChild(this.document.body, this.responsiveStyleElement);
|
||
|
}
|
||
|
let innerHTML = '';
|
||
|
if (this.responsiveOptions) {
|
||
|
let responsiveOptions = [...this.responsiveOptions].filter((o) => !!(o.breakpoint && o.numMonths)).sort((o1, o2) => -1 * o1.breakpoint.localeCompare(o2.breakpoint, undefined, { numeric: true }));
|
||
|
for (let i = 0; i < responsiveOptions.length; i++) {
|
||
|
let { breakpoint, numMonths } = responsiveOptions[i];
|
||
|
let styles = `
|
||
|
.p-datepicker[${this.attributeSelector}] .p-datepicker-group:nth-child(${numMonths}) .p-datepicker-next {
|
||
|
display: inline-flex !important;
|
||
|
}
|
||
|
`;
|
||
|
for (let j = numMonths; j < this.numberOfMonths; j++) {
|
||
|
styles += `
|
||
|
.p-datepicker[${this.attributeSelector}] .p-datepicker-group:nth-child(${j + 1}) {
|
||
|
display: none !important;
|
||
|
}
|
||
|
`;
|
||
|
}
|
||
|
innerHTML += `
|
||
|
@media screen and (max-width: ${breakpoint}) {
|
||
|
${styles}
|
||
|
}
|
||
|
`;
|
||
|
}
|
||
|
}
|
||
|
this.responsiveStyleElement.innerHTML = innerHTML;
|
||
|
}
|
||
|
}
|
||
|
destroyResponsiveStyleElement() {
|
||
|
if (this.responsiveStyleElement) {
|
||
|
this.responsiveStyleElement.remove();
|
||
|
this.responsiveStyleElement = null;
|
||
|
}
|
||
|
}
|
||
|
bindDocumentClickListener() {
|
||
|
if (!this.documentClickListener) {
|
||
|
this.zone.runOutsideAngular(() => {
|
||
|
const documentTarget = this.el ? this.el.nativeElement.ownerDocument : this.document;
|
||
|
this.documentClickListener = this.renderer.listen(documentTarget, 'mousedown', (event) => {
|
||
|
if (this.isOutsideClicked(event) && this.overlayVisible) {
|
||
|
this.zone.run(() => {
|
||
|
this.hideOverlay();
|
||
|
this.onClickOutside.emit(event);
|
||
|
this.cd.markForCheck();
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
unbindDocumentClickListener() {
|
||
|
if (this.documentClickListener) {
|
||
|
this.documentClickListener();
|
||
|
this.documentClickListener = null;
|
||
|
}
|
||
|
}
|
||
|
bindDocumentResizeListener() {
|
||
|
if (!this.documentResizeListener && !this.touchUI) {
|
||
|
this.documentResizeListener = this.renderer.listen(this.window, 'resize', this.onWindowResize.bind(this));
|
||
|
}
|
||
|
}
|
||
|
unbindDocumentResizeListener() {
|
||
|
if (this.documentResizeListener) {
|
||
|
this.documentResizeListener();
|
||
|
this.documentResizeListener = null;
|
||
|
}
|
||
|
}
|
||
|
bindScrollListener() {
|
||
|
if (!this.scrollHandler) {
|
||
|
this.scrollHandler = new ConnectedOverlayScrollHandler(this.containerViewChild?.nativeElement, () => {
|
||
|
if (this.overlayVisible) {
|
||
|
this.hideOverlay();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
this.scrollHandler.bindScrollListener();
|
||
|
}
|
||
|
unbindScrollListener() {
|
||
|
if (this.scrollHandler) {
|
||
|
this.scrollHandler.unbindScrollListener();
|
||
|
}
|
||
|
}
|
||
|
isOutsideClicked(event) {
|
||
|
return !(this.el.nativeElement.isSameNode(event.target) || this.isNavIconClicked(event) || this.el.nativeElement.contains(event.target) || (this.overlay && this.overlay.contains(event.target)));
|
||
|
}
|
||
|
isNavIconClicked(event) {
|
||
|
return (DomHandler.hasClass(event.target, 'p-datepicker-prev') || DomHandler.hasClass(event.target, 'p-datepicker-prev-icon') || DomHandler.hasClass(event.target, 'p-datepicker-next') || DomHandler.hasClass(event.target, 'p-datepicker-next-icon'));
|
||
|
}
|
||
|
onWindowResize() {
|
||
|
if (this.overlayVisible && !DomHandler.isTouchDevice()) {
|
||
|
this.hideOverlay();
|
||
|
}
|
||
|
}
|
||
|
onOverlayHide() {
|
||
|
this.currentView = this.view;
|
||
|
if (this.mask) {
|
||
|
this.destroyMask();
|
||
|
}
|
||
|
this.unbindDocumentClickListener();
|
||
|
this.unbindDocumentResizeListener();
|
||
|
this.unbindScrollListener();
|
||
|
this.overlay = null;
|
||
|
}
|
||
|
ngOnDestroy() {
|
||
|
if (this.scrollHandler) {
|
||
|
this.scrollHandler.destroy();
|
||
|
this.scrollHandler = null;
|
||
|
}
|
||
|
if (this.translationSubscription) {
|
||
|
this.translationSubscription.unsubscribe();
|
||
|
}
|
||
|
if (this.overlay && this.autoZIndex) {
|
||
|
ZIndexUtils.clear(this.overlay);
|
||
|
}
|
||
|
this.destroyResponsiveStyleElement();
|
||
|
this.clearTimePickerTimer();
|
||
|
this.restoreOverlayAppend();
|
||
|
this.onOverlayHide();
|
||
|
}
|
||
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: Calendar, deps: [{ token: DOCUMENT }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i1.PrimeNGConfig }, { token: i1.OverlayService }], target: i0.ɵɵFactoryTarget.Component });
|
||
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "17.3.7", type: Calendar, selector: "p-calendar", inputs: { iconDisplay: "iconDisplay", style: "style", styleClass: "styleClass", inputStyle: "inputStyle", inputId: "inputId", name: "name", inputStyleClass: "inputStyleClass", placeholder: "placeholder", ariaLabelledBy: "ariaLabelledBy", ariaLabel: "ariaLabel", iconAriaLabel: "iconAriaLabel", disabled: ["disabled", "disabled", booleanAttribute], dateFormat: "dateFormat", multipleSeparator: "multipleSeparator", rangeSeparator: "rangeSeparator", inline: ["inline", "inline", booleanAttribute], showOtherMonths: ["showOtherMonths", "showOtherMonths", booleanAttribute], selectOtherMonths: ["selectOtherMonths", "selectOtherMonths", booleanAttribute], showIcon: ["showIcon", "showIcon", booleanAttribute], icon: "icon", appendTo: "appendTo", readonlyInput: ["readonlyInput", "readonlyInput", booleanAttribute], shortYearCutoff: "shortYearCutoff", monthNavigator: ["monthNavigator", "monthNavigator", booleanAttribute], yearNavigator: ["yearNavigator", "yearNavigator", booleanAttribute], hourFormat: "hourFormat", timeOnly: ["timeOnly", "timeOnly", booleanAttribute], stepHour: ["stepHour", "stepHour", numberAttribute], stepMinute: ["stepMinute", "stepMinute", numberAttribute], stepSecond: ["stepSecond", "stepSecond", numberAttribute], showSeconds: ["showSeconds", "showSeconds", booleanAttribute], required: ["required", "required", booleanAttribute], showOnFocus: ["showOnFocus", "showOnFocus", booleanAttribute], showWeek: ["showWeek", "showWeek", booleanAttribute], startWeekFromFirstDayOfYear: "startWeekFromFirstDayOfYear", showClear: ["showClear", "showClear", booleanAttribute], dataType: "dataType", selectionMode: "selectionMode", maxDateCount: ["maxDateCount", "maxDateCount", numberAttribute], showButtonBar: ["showButtonBar", "showButtonBar", booleanAttribute], todayButtonStyleClass: "todayButtonStyleClass", clearButtonStyleClass: "clearButtonStyleClass", autofocus: ["autofocus", "autofocus", booleanAttribute], autoZIndex: ["autoZIndex", "autoZIndex", booleanAttribute], baseZIndex: ["baseZIndex", "baseZIndex", numberAttribute], panelStyleClass: "panelStyleClass", panelStyle: "panelStyle", keepInvalid: ["keepInvalid", "keepInvalid", booleanAttribute], hideOnDateTimeSelect: ["hideOnDateTimeSelect", "hideOnDateTimeSelect", booleanAttribute], touchUI: ["touchUI", "touchUI", booleanAttribute], timeSeparator: "timeSeparator", focusTrap: ["focusTrap", "focusTrap", booleanAttribute], showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", tabindex: ["tabindex", "tabindex", numberAttribute], variant: "variant", minDate: "minDate", maxDate: "maxDate", disabledDates: "disabledDates", disabledDays: "disabledDays", yearRange: "yearRange", showTime: "showTime", responsiveOptions: "responsiveOptions", numberOfMonths: "numberOfMonths", firstDayOfWeek: "firstDayOfWeek", locale: "locale", view: "view", defaultDate: "defaultDate" }, outputs: { onFocus: "onFocus", onBlur: "onBlur", onClose: "onClose", onSelect: "onSelect", onClear: "onClear", onInput: "onInput", onTodayClick: "onTodayClick", onClearClick: "onClearClick", onMonthChange: "onMonthChange", onYearChange: "onYearChange", onClickOutside: "onClickOutside", onShow: "onShow" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focus", "class.p-calendar-clearable": "showClear && !disabled" }, classAttribute: "p-element p-inputwrapper" }, providers: [CALENDAR_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "inputfieldViewChild", first: true, predicate: ["inputfield"], descendants: true }, { propertyName: "content", first: true, predicate: ["contentWrapper"], descendants: true }], ngImport: i0, template: `
|
||
|
<span
|
||
|
#container
|
||
|
[ngClass]="{
|
||
|
'p-calendar': true,
|
||
|
'p-input-icon-right': showIcon && iconDisplay === 'input',
|
||
|
'p-calendar-w-btn': showIcon && iconDisplay === 'button',
|
||
|
'p-calendar-timeonly': timeOnly,
|
||
|
'p-calendar-disabled': disabled,
|
||
|
'p-focus': focus || overlayVisible
|
||
|
}"
|
||
|
[ngStyle]="style"
|
||
|
[class]="styleClass"
|
||
|
>
|
||
|
<ng-template [ngIf]="!inline">
|
||
|
<input
|
||
|
#inputfield
|
||
|
type="text"
|
||
|
role="combobox"
|
||
|
[attr.id]="inputId"
|
||
|
[attr.name]="name"
|
||
|
[attr.required]="required"
|
||
|
[attr.aria-required]="required"
|
||
|
aria-autocomplete="none"
|
||
|
aria-haspopup="dialog"
|
||
|
[attr.aria-expanded]="overlayVisible ?? false"
|
||
|
[attr.aria-controls]="overlayVisible ? panelId : null"
|
||
|
[attr.aria-labelledby]="ariaLabelledBy"
|
||
|
[attr.aria-label]="ariaLabel"
|
||
|
[value]="inputFieldValue"
|
||
|
(focus)="onInputFocus($event)"
|
||
|
(keydown)="onInputKeydown($event)"
|
||
|
(click)="onInputClick()"
|
||
|
(blur)="onInputBlur($event)"
|
||
|
[readonly]="readonlyInput"
|
||
|
(input)="onUserInput($event)"
|
||
|
[ngStyle]="inputStyle"
|
||
|
[class]="inputStyleClass"
|
||
|
[placeholder]="placeholder || ''"
|
||
|
[disabled]="disabled"
|
||
|
[attr.tabindex]="tabindex"
|
||
|
[attr.inputmode]="touchUI ? 'off' : null"
|
||
|
[ngClass]="inputClass"
|
||
|
autocomplete="off"
|
||
|
pAutoFocus
|
||
|
[autofocus]="autofocus"
|
||
|
/>
|
||
|
<ng-container *ngIf="showClear && !disabled && value != null">
|
||
|
<TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-calendar-clear-icon'" (click)="clear()" />
|
||
|
<span *ngIf="clearIconTemplate" class="p-calendar-clear-icon" (click)="clear()">
|
||
|
<ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
|
||
|
</span>
|
||
|
</ng-container>
|
||
|
<button
|
||
|
type="button"
|
||
|
[attr.aria-label]="iconButtonAriaLabel"
|
||
|
aria-haspopup="dialog"
|
||
|
[attr.aria-expanded]="overlayVisible ?? false"
|
||
|
[attr.aria-controls]="overlayVisible ? panelId : null"
|
||
|
pButton
|
||
|
pRipple
|
||
|
*ngIf="showIcon && iconDisplay === 'button'"
|
||
|
(click)="onButtonClick($event, inputfield)"
|
||
|
class="p-datepicker-trigger p-button-icon-only"
|
||
|
[disabled]="disabled"
|
||
|
tabindex="0"
|
||
|
>
|
||
|
<span *ngIf="icon" [ngClass]="icon"></span>
|
||
|
<ng-container *ngIf="!icon">
|
||
|
<CalendarIcon *ngIf="!triggerIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="triggerIconTemplate"></ng-template>
|
||
|
</ng-container>
|
||
|
</button>
|
||
|
<ng-container *ngIf="iconDisplay === 'input' && showIcon">
|
||
|
<CalendarIcon
|
||
|
(click)="onButtonClick($event)"
|
||
|
*ngIf="!inputIconTemplate"
|
||
|
[ngClass]="{
|
||
|
'p-datepicker-icon': showOnFocus
|
||
|
}"
|
||
|
/>
|
||
|
<ng-container *ngTemplateOutlet="inputIconTemplate; context: { clickCallBack: onButtonClick.bind(this) }"></ng-container>
|
||
|
</ng-container>
|
||
|
</ng-template>
|
||
|
<div
|
||
|
#contentWrapper
|
||
|
[attr.id]="panelId"
|
||
|
[class]="panelStyleClass"
|
||
|
[ngStyle]="panelStyle"
|
||
|
[ngClass]="{
|
||
|
'p-datepicker p-component': true,
|
||
|
'p-datepicker-inline': inline,
|
||
|
'p-disabled': disabled,
|
||
|
'p-datepicker-timeonly': timeOnly,
|
||
|
'p-datepicker-multiple-month': this.numberOfMonths > 1,
|
||
|
'p-datepicker-monthpicker': view === 'month',
|
||
|
'p-datepicker-touch-ui': touchUI
|
||
|
}"
|
||
|
[@overlayAnimation]="
|
||
|
touchUI
|
||
|
? { value: 'visibleTouchUI', params: { showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions } }
|
||
|
: { value: 'visible', params: { showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions } }
|
||
|
"
|
||
|
[attr.aria-label]="getTranslation('chooseDate')"
|
||
|
[attr.role]="inline ? null : 'dialog'"
|
||
|
[attr.aria-modal]="inline ? null : 'true'"
|
||
|
[@.disabled]="inline === true"
|
||
|
(@overlayAnimation.start)="onOverlayAnimationStart($event)"
|
||
|
(@overlayAnimation.done)="onOverlayAnimationDone($event)"
|
||
|
(click)="onOverlayClick($event)"
|
||
|
*ngIf="inline || overlayVisible"
|
||
|
>
|
||
|
<ng-content select="p-header"></ng-content>
|
||
|
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
||
|
<ng-container *ngIf="!timeOnly">
|
||
|
<div class="p-datepicker-group-container">
|
||
|
<div class="p-datepicker-group" *ngFor="let month of months; let i = index">
|
||
|
<div class="p-datepicker-header">
|
||
|
<button (keydown)="onContainerButtonKeydown($event)" class="p-datepicker-prev p-link" (click)="onPrevButtonClick($event)" *ngIf="i === 0" type="button" [attr.aria-label]="prevIconAriaLabel" pRipple>
|
||
|
<ChevronLeftIcon [styleClass]="'p-datepicker-prev-icon'" *ngIf="!previousIconTemplate" />
|
||
|
<span *ngIf="previousIconTemplate" class="p-datepicker-prev-icon">
|
||
|
<ng-template *ngTemplateOutlet="previousIconTemplate"></ng-template>
|
||
|
</span>
|
||
|
</button>
|
||
|
<div class="p-datepicker-title">
|
||
|
<button
|
||
|
type="button"
|
||
|
(click)="switchToMonthView($event)"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
*ngIf="currentView === 'date'"
|
||
|
class="p-datepicker-month p-link"
|
||
|
[disabled]="switchViewButtonDisabled()"
|
||
|
[attr.aria-label]="this.getTranslation('chooseMonth')"
|
||
|
>
|
||
|
{{ getMonthName(month.month) }}
|
||
|
</button>
|
||
|
<button
|
||
|
type="button"
|
||
|
(click)="switchToYearView($event)"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
*ngIf="currentView !== 'year'"
|
||
|
class="p-datepicker-year p-link"
|
||
|
[disabled]="switchViewButtonDisabled()"
|
||
|
[attr.aria-label]="getTranslation('chooseYear')"
|
||
|
>
|
||
|
{{ getYear(month) }}
|
||
|
</button>
|
||
|
<span class="p-datepicker-decade" *ngIf="currentView === 'year'">
|
||
|
<ng-container *ngIf="!decadeTemplate">{{ yearPickerValues()[0] }} - {{ yearPickerValues()[yearPickerValues().length - 1] }}</ng-container>
|
||
|
<ng-container *ngTemplateOutlet="decadeTemplate; context: { $implicit: yearPickerValues }"></ng-container>
|
||
|
</span>
|
||
|
</div>
|
||
|
<button
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
class="p-datepicker-next p-link"
|
||
|
(click)="onNextButtonClick($event)"
|
||
|
[style.display]="numberOfMonths === 1 ? 'inline-flex' : i === numberOfMonths - 1 ? 'inline-flex' : 'none'"
|
||
|
type="button"
|
||
|
[attr.aria-label]="nextIconAriaLabel"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronRightIcon [styleClass]="'p-datepicker-next-icon'" *ngIf="!nextIconTemplate" />
|
||
|
<span *ngIf="nextIconTemplate" class="p-datepicker-next-icon">
|
||
|
<ng-template *ngTemplateOutlet="nextIconTemplate"></ng-template>
|
||
|
</span>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-datepicker-calendar-container" *ngIf="currentView === 'date'">
|
||
|
<table class="p-datepicker-calendar" role="grid">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th *ngIf="showWeek" class="p-datepicker-weekheader p-disabled">
|
||
|
<span>{{ getTranslation('weekHeader') }}</span>
|
||
|
</th>
|
||
|
<th scope="col" *ngFor="let weekDay of weekDays; let begin = first; let end = last">
|
||
|
<span>{{ weekDay }}</span>
|
||
|
</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
<tr *ngFor="let week of month.dates; let j = index">
|
||
|
<td *ngIf="showWeek" class="p-datepicker-weeknumber">
|
||
|
<span class="p-disabled">
|
||
|
{{ month.weekNumbers[j] }}
|
||
|
</span>
|
||
|
</td>
|
||
|
<td *ngFor="let date of week" [attr.aria-label]="date.day" [ngClass]="{ 'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today }">
|
||
|
<ng-container *ngIf="date.otherMonth ? showOtherMonths : true">
|
||
|
<span
|
||
|
[ngClass]="{ 'p-highlight': isSelected(date) && date.selectable, 'p-disabled': !date.selectable }"
|
||
|
(click)="onDateSelect($event, date)"
|
||
|
draggable="false"
|
||
|
[attr.data-date]="formatDateKey(formatDateMetaToDate(date))"
|
||
|
(keydown)="onDateCellKeydown($event, date, i)"
|
||
|
pRipple
|
||
|
>
|
||
|
<ng-container *ngIf="!dateTemplate && (date.selectable || !disabledDateTemplate)">{{ date.day }}</ng-container>
|
||
|
<ng-container *ngIf="date.selectable || !disabledDateTemplate">
|
||
|
<ng-container *ngTemplateOutlet="dateTemplate; context: { $implicit: date }"></ng-container>
|
||
|
</ng-container>
|
||
|
<ng-container *ngIf="!date.selectable">
|
||
|
<ng-container *ngTemplateOutlet="disabledDateTemplate; context: { $implicit: date }"></ng-container>
|
||
|
</ng-container>
|
||
|
</span>
|
||
|
<div *ngIf="isSelected(date)" class="p-hidden-accessible" aria-live="polite">
|
||
|
{{ date.day }}
|
||
|
</div>
|
||
|
</ng-container>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="p-monthpicker" *ngIf="currentView === 'month'">
|
||
|
<span
|
||
|
*ngFor="let m of monthPickerValues(); let i = index"
|
||
|
(click)="onMonthSelect($event, i)"
|
||
|
(keydown)="onMonthCellKeydown($event, i)"
|
||
|
class="p-monthpicker-month"
|
||
|
[ngClass]="{ 'p-highlight': isMonthSelected(i), 'p-disabled': isMonthDisabled(i) }"
|
||
|
pRipple
|
||
|
>
|
||
|
{{ m }}
|
||
|
<div *ngIf="isMonthSelected(i)" class="p-hidden-accessible" aria-live="polite">
|
||
|
{{ m }}
|
||
|
</div>
|
||
|
</span>
|
||
|
</div>
|
||
|
<div class="p-yearpicker" *ngIf="currentView === 'year'">
|
||
|
<span
|
||
|
*ngFor="let y of yearPickerValues()"
|
||
|
(click)="onYearSelect($event, y)"
|
||
|
(keydown)="onYearCellKeydown($event, y)"
|
||
|
class="p-yearpicker-year"
|
||
|
[ngClass]="{ 'p-highlight': isYearSelected(y), 'p-disabled': isYearDisabled(y) }"
|
||
|
pRipple
|
||
|
>
|
||
|
{{ y }}
|
||
|
<div *ngIf="isYearSelected(y)" class="p-hidden-accessible" aria-live="polite">
|
||
|
{{ y }}
|
||
|
</div>
|
||
|
</span>
|
||
|
</div>
|
||
|
</ng-container>
|
||
|
<div class="p-timepicker" *ngIf="(showTime || timeOnly) && currentView === 'date'">
|
||
|
<div class="p-hour-picker">
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="incrementHour($event)"
|
||
|
(keydown.space)="incrementHour($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 0, 1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('nextHour')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span><ng-container *ngIf="currentHour < 10">0</ng-container>{{ currentHour }}</span>
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="decrementHour($event)"
|
||
|
(keydown.space)="decrementHour($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 0, -1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('prevHour')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-separator">
|
||
|
<span>{{ timeSeparator }}</span>
|
||
|
</div>
|
||
|
<div class="p-minute-picker">
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="incrementMinute($event)"
|
||
|
(keydown.space)="incrementMinute($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 1, 1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('nextMinute')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span><ng-container *ngIf="currentMinute < 10">0</ng-container>{{ currentMinute }}</span>
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="decrementMinute($event)"
|
||
|
(keydown.space)="decrementMinute($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 1, -1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('prevMinute')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-separator" *ngIf="showSeconds">
|
||
|
<span>{{ timeSeparator }}</span>
|
||
|
</div>
|
||
|
<div class="p-second-picker" *ngIf="showSeconds">
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="incrementSecond($event)"
|
||
|
(keydown.space)="incrementSecond($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 2, 1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('nextSecond')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span><ng-container *ngIf="currentSecond < 10">0</ng-container>{{ currentSecond }}</span>
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="decrementSecond($event)"
|
||
|
(keydown.space)="decrementSecond($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 2, -1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('prevSecond')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-ampm-picker" *ngIf="hourFormat == '12'">
|
||
|
<button class="p-link" type="button" (keydown)="onContainerButtonKeydown($event)" (click)="toggleAMPM($event)" (keydown.enter)="toggleAMPM($event)" [attr.aria-label]="getTranslation('am')" pRipple>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span>{{ pm ? 'PM' : 'AM' }}</span>
|
||
|
<button class="p-link" type="button" (keydown)="onContainerButtonKeydown($event)" (click)="toggleAMPM($event)" (keydown.enter)="toggleAMPM($event)" [attr.aria-label]="getTranslation('pm')" pRipple>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="p-datepicker-buttonbar" *ngIf="showButtonBar">
|
||
|
<button type="button" [label]="getTranslation('today')" (keydown)="onContainerButtonKeydown($event)" (click)="onTodayButtonClick($event)" pButton pRipple [ngClass]="[todayButtonStyleClass]"></button>
|
||
|
<button type="button" [label]="getTranslation('clear')" (keydown)="onContainerButtonKeydown($event)" (click)="onClearButtonClick($event)" pButton pRipple [ngClass]="[clearButtonStyleClass]"></button>
|
||
|
</div>
|
||
|
<ng-content select="p-footer"></ng-content>
|
||
|
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
|
||
|
</div>
|
||
|
</span>
|
||
|
`, isInline: true, styles: ["@layer primeng{.p-calendar{position:relative;display:inline-flex;max-width:100%}.p-calendar .p-inputtext{flex:1 1 auto;width:1%;text-overflow:ellipsis}.p-calendar-w-btn .p-inputtext{border-top-right-radius:0;border-bottom-right-radius:0}.p-calendar-w-btn .p-datepicker-trigger{border-top-left-radius:0;border-bottom-left-radius:0}.p-fluid .p-calendar{display:flex}.p-fluid .p-calendar .p-inputtext{width:1%}.p-calendar .p-datepicker{min-width:100%}.p-datepicker{width:auto;position:absolute;top:0;left:0}.p-datepicker-inline{display:inline-block;position:static;overflow-x:auto}.p-datepicker-header{display:flex;align-items:center;justify-content:space-between}.p-datepicker-header .p-datepicker-title{margin:0 auto}.p-datepicker-prev,.p-datepicker-next{cursor:pointer;display:inline-flex;justify-content:center;align-items:center;overflow:hidden;position:relative}.p-datepicker-multiple-month .p-datepicker-group-container .p-datepicker-group{flex:1 1 auto}.p-datepicker-multiple-month .p-datepicker-group-container{display:flex}.p-datepicker table{width:100%;border-collapse:collapse}.p-datepicker td>span{display:flex;justify-content:center;align-items:center;cursor:pointer;margin:0 auto;overflow:hidden;position:relative}.p-monthpicker-month{width:33.3%;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;position:relative}.p-datepicker-buttonbar{display:flex;justify-content:space-between;align-items:center}.p-timepicker{display:flex;justify-content:center;align-items:center}.p-timepicker button{display:flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;position:relative}.p-timepicker>div{display:flex;align-items:center;flex-direction:column}.p-datepicker-touch-ui,.p-calendar .p-datepicker-touch-ui{position:fixed;top:50%;left:50%;min-width:80vw;transform:translate(-50%,-50%)}.p-yearpicker-year{width:50%;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;position:relative}.p-calendar-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-datepicker-icon{pointer-events:none}.p-calendar-clearable{position:relative}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(() => i2.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgForOf), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgTemplateOutlet), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(() => i2.NgStyle), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i0.forwardRef(() => i3.ButtonDirective), selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain"] }, { kind: "directive", type: i0.forwardRef(() => i4.Ripple), selector: "[pRipple]" }, { kind: "component", type: i0.forwardRef(() => ChevronLeftIcon), selector: "ChevronLeftIcon" }, { kind: "component", type: i0.forwardRef(() => ChevronRightIcon), selector: "ChevronRightIcon" }, { kind: "component", type: i0.forwardRef(() => ChevronUpIcon), selector: "ChevronUpIcon" }, { kind: "component", type: i0.forwardRef(() => ChevronDownIcon), selector: "ChevronDownIcon" }, { kind: "component", type: i0.forwardRef(() => TimesIcon), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(() => CalendarIcon), selector: "CalendarIcon" }, { kind: "directive", type: i0.forwardRef(() => i5.AutoFocus), selector: "[pAutoFocus]", inputs: ["autofocus"] }], animations: [
|
||
|
trigger('overlayAnimation', [
|
||
|
state('visibleTouchUI', style({
|
||
|
transform: 'translate(-50%,-50%)',
|
||
|
opacity: 1
|
||
|
})),
|
||
|
transition('void => visible', [style({ opacity: 0, transform: 'scaleY(0.8)' }), animate('{{showTransitionParams}}', style({ opacity: 1, transform: '*' }))]),
|
||
|
transition('visible => void', [animate('{{hideTransitionParams}}', style({ opacity: 0 }))]),
|
||
|
transition('void => visibleTouchUI', [style({ opacity: 0, transform: 'translate3d(-50%, -40%, 0) scale(0.9)' }), animate('{{showTransitionParams}}')]),
|
||
|
transition('visibleTouchUI => void', [
|
||
|
animate('{{hideTransitionParams}}', style({
|
||
|
opacity: 0,
|
||
|
transform: 'translate3d(-50%, -40%, 0) scale(0.9)'
|
||
|
}))
|
||
|
])
|
||
|
])
|
||
|
], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
||
|
}
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: Calendar, decorators: [{
|
||
|
type: Component,
|
||
|
args: [{ selector: 'p-calendar', template: `
|
||
|
<span
|
||
|
#container
|
||
|
[ngClass]="{
|
||
|
'p-calendar': true,
|
||
|
'p-input-icon-right': showIcon && iconDisplay === 'input',
|
||
|
'p-calendar-w-btn': showIcon && iconDisplay === 'button',
|
||
|
'p-calendar-timeonly': timeOnly,
|
||
|
'p-calendar-disabled': disabled,
|
||
|
'p-focus': focus || overlayVisible
|
||
|
}"
|
||
|
[ngStyle]="style"
|
||
|
[class]="styleClass"
|
||
|
>
|
||
|
<ng-template [ngIf]="!inline">
|
||
|
<input
|
||
|
#inputfield
|
||
|
type="text"
|
||
|
role="combobox"
|
||
|
[attr.id]="inputId"
|
||
|
[attr.name]="name"
|
||
|
[attr.required]="required"
|
||
|
[attr.aria-required]="required"
|
||
|
aria-autocomplete="none"
|
||
|
aria-haspopup="dialog"
|
||
|
[attr.aria-expanded]="overlayVisible ?? false"
|
||
|
[attr.aria-controls]="overlayVisible ? panelId : null"
|
||
|
[attr.aria-labelledby]="ariaLabelledBy"
|
||
|
[attr.aria-label]="ariaLabel"
|
||
|
[value]="inputFieldValue"
|
||
|
(focus)="onInputFocus($event)"
|
||
|
(keydown)="onInputKeydown($event)"
|
||
|
(click)="onInputClick()"
|
||
|
(blur)="onInputBlur($event)"
|
||
|
[readonly]="readonlyInput"
|
||
|
(input)="onUserInput($event)"
|
||
|
[ngStyle]="inputStyle"
|
||
|
[class]="inputStyleClass"
|
||
|
[placeholder]="placeholder || ''"
|
||
|
[disabled]="disabled"
|
||
|
[attr.tabindex]="tabindex"
|
||
|
[attr.inputmode]="touchUI ? 'off' : null"
|
||
|
[ngClass]="inputClass"
|
||
|
autocomplete="off"
|
||
|
pAutoFocus
|
||
|
[autofocus]="autofocus"
|
||
|
/>
|
||
|
<ng-container *ngIf="showClear && !disabled && value != null">
|
||
|
<TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-calendar-clear-icon'" (click)="clear()" />
|
||
|
<span *ngIf="clearIconTemplate" class="p-calendar-clear-icon" (click)="clear()">
|
||
|
<ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
|
||
|
</span>
|
||
|
</ng-container>
|
||
|
<button
|
||
|
type="button"
|
||
|
[attr.aria-label]="iconButtonAriaLabel"
|
||
|
aria-haspopup="dialog"
|
||
|
[attr.aria-expanded]="overlayVisible ?? false"
|
||
|
[attr.aria-controls]="overlayVisible ? panelId : null"
|
||
|
pButton
|
||
|
pRipple
|
||
|
*ngIf="showIcon && iconDisplay === 'button'"
|
||
|
(click)="onButtonClick($event, inputfield)"
|
||
|
class="p-datepicker-trigger p-button-icon-only"
|
||
|
[disabled]="disabled"
|
||
|
tabindex="0"
|
||
|
>
|
||
|
<span *ngIf="icon" [ngClass]="icon"></span>
|
||
|
<ng-container *ngIf="!icon">
|
||
|
<CalendarIcon *ngIf="!triggerIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="triggerIconTemplate"></ng-template>
|
||
|
</ng-container>
|
||
|
</button>
|
||
|
<ng-container *ngIf="iconDisplay === 'input' && showIcon">
|
||
|
<CalendarIcon
|
||
|
(click)="onButtonClick($event)"
|
||
|
*ngIf="!inputIconTemplate"
|
||
|
[ngClass]="{
|
||
|
'p-datepicker-icon': showOnFocus
|
||
|
}"
|
||
|
/>
|
||
|
<ng-container *ngTemplateOutlet="inputIconTemplate; context: { clickCallBack: onButtonClick.bind(this) }"></ng-container>
|
||
|
</ng-container>
|
||
|
</ng-template>
|
||
|
<div
|
||
|
#contentWrapper
|
||
|
[attr.id]="panelId"
|
||
|
[class]="panelStyleClass"
|
||
|
[ngStyle]="panelStyle"
|
||
|
[ngClass]="{
|
||
|
'p-datepicker p-component': true,
|
||
|
'p-datepicker-inline': inline,
|
||
|
'p-disabled': disabled,
|
||
|
'p-datepicker-timeonly': timeOnly,
|
||
|
'p-datepicker-multiple-month': this.numberOfMonths > 1,
|
||
|
'p-datepicker-monthpicker': view === 'month',
|
||
|
'p-datepicker-touch-ui': touchUI
|
||
|
}"
|
||
|
[@overlayAnimation]="
|
||
|
touchUI
|
||
|
? { value: 'visibleTouchUI', params: { showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions } }
|
||
|
: { value: 'visible', params: { showTransitionParams: showTransitionOptions, hideTransitionParams: hideTransitionOptions } }
|
||
|
"
|
||
|
[attr.aria-label]="getTranslation('chooseDate')"
|
||
|
[attr.role]="inline ? null : 'dialog'"
|
||
|
[attr.aria-modal]="inline ? null : 'true'"
|
||
|
[@.disabled]="inline === true"
|
||
|
(@overlayAnimation.start)="onOverlayAnimationStart($event)"
|
||
|
(@overlayAnimation.done)="onOverlayAnimationDone($event)"
|
||
|
(click)="onOverlayClick($event)"
|
||
|
*ngIf="inline || overlayVisible"
|
||
|
>
|
||
|
<ng-content select="p-header"></ng-content>
|
||
|
<ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
|
||
|
<ng-container *ngIf="!timeOnly">
|
||
|
<div class="p-datepicker-group-container">
|
||
|
<div class="p-datepicker-group" *ngFor="let month of months; let i = index">
|
||
|
<div class="p-datepicker-header">
|
||
|
<button (keydown)="onContainerButtonKeydown($event)" class="p-datepicker-prev p-link" (click)="onPrevButtonClick($event)" *ngIf="i === 0" type="button" [attr.aria-label]="prevIconAriaLabel" pRipple>
|
||
|
<ChevronLeftIcon [styleClass]="'p-datepicker-prev-icon'" *ngIf="!previousIconTemplate" />
|
||
|
<span *ngIf="previousIconTemplate" class="p-datepicker-prev-icon">
|
||
|
<ng-template *ngTemplateOutlet="previousIconTemplate"></ng-template>
|
||
|
</span>
|
||
|
</button>
|
||
|
<div class="p-datepicker-title">
|
||
|
<button
|
||
|
type="button"
|
||
|
(click)="switchToMonthView($event)"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
*ngIf="currentView === 'date'"
|
||
|
class="p-datepicker-month p-link"
|
||
|
[disabled]="switchViewButtonDisabled()"
|
||
|
[attr.aria-label]="this.getTranslation('chooseMonth')"
|
||
|
>
|
||
|
{{ getMonthName(month.month) }}
|
||
|
</button>
|
||
|
<button
|
||
|
type="button"
|
||
|
(click)="switchToYearView($event)"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
*ngIf="currentView !== 'year'"
|
||
|
class="p-datepicker-year p-link"
|
||
|
[disabled]="switchViewButtonDisabled()"
|
||
|
[attr.aria-label]="getTranslation('chooseYear')"
|
||
|
>
|
||
|
{{ getYear(month) }}
|
||
|
</button>
|
||
|
<span class="p-datepicker-decade" *ngIf="currentView === 'year'">
|
||
|
<ng-container *ngIf="!decadeTemplate">{{ yearPickerValues()[0] }} - {{ yearPickerValues()[yearPickerValues().length - 1] }}</ng-container>
|
||
|
<ng-container *ngTemplateOutlet="decadeTemplate; context: { $implicit: yearPickerValues }"></ng-container>
|
||
|
</span>
|
||
|
</div>
|
||
|
<button
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
class="p-datepicker-next p-link"
|
||
|
(click)="onNextButtonClick($event)"
|
||
|
[style.display]="numberOfMonths === 1 ? 'inline-flex' : i === numberOfMonths - 1 ? 'inline-flex' : 'none'"
|
||
|
type="button"
|
||
|
[attr.aria-label]="nextIconAriaLabel"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronRightIcon [styleClass]="'p-datepicker-next-icon'" *ngIf="!nextIconTemplate" />
|
||
|
<span *ngIf="nextIconTemplate" class="p-datepicker-next-icon">
|
||
|
<ng-template *ngTemplateOutlet="nextIconTemplate"></ng-template>
|
||
|
</span>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-datepicker-calendar-container" *ngIf="currentView === 'date'">
|
||
|
<table class="p-datepicker-calendar" role="grid">
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th *ngIf="showWeek" class="p-datepicker-weekheader p-disabled">
|
||
|
<span>{{ getTranslation('weekHeader') }}</span>
|
||
|
</th>
|
||
|
<th scope="col" *ngFor="let weekDay of weekDays; let begin = first; let end = last">
|
||
|
<span>{{ weekDay }}</span>
|
||
|
</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
<tr *ngFor="let week of month.dates; let j = index">
|
||
|
<td *ngIf="showWeek" class="p-datepicker-weeknumber">
|
||
|
<span class="p-disabled">
|
||
|
{{ month.weekNumbers[j] }}
|
||
|
</span>
|
||
|
</td>
|
||
|
<td *ngFor="let date of week" [attr.aria-label]="date.day" [ngClass]="{ 'p-datepicker-other-month': date.otherMonth, 'p-datepicker-today': date.today }">
|
||
|
<ng-container *ngIf="date.otherMonth ? showOtherMonths : true">
|
||
|
<span
|
||
|
[ngClass]="{ 'p-highlight': isSelected(date) && date.selectable, 'p-disabled': !date.selectable }"
|
||
|
(click)="onDateSelect($event, date)"
|
||
|
draggable="false"
|
||
|
[attr.data-date]="formatDateKey(formatDateMetaToDate(date))"
|
||
|
(keydown)="onDateCellKeydown($event, date, i)"
|
||
|
pRipple
|
||
|
>
|
||
|
<ng-container *ngIf="!dateTemplate && (date.selectable || !disabledDateTemplate)">{{ date.day }}</ng-container>
|
||
|
<ng-container *ngIf="date.selectable || !disabledDateTemplate">
|
||
|
<ng-container *ngTemplateOutlet="dateTemplate; context: { $implicit: date }"></ng-container>
|
||
|
</ng-container>
|
||
|
<ng-container *ngIf="!date.selectable">
|
||
|
<ng-container *ngTemplateOutlet="disabledDateTemplate; context: { $implicit: date }"></ng-container>
|
||
|
</ng-container>
|
||
|
</span>
|
||
|
<div *ngIf="isSelected(date)" class="p-hidden-accessible" aria-live="polite">
|
||
|
{{ date.day }}
|
||
|
</div>
|
||
|
</ng-container>
|
||
|
</td>
|
||
|
</tr>
|
||
|
</tbody>
|
||
|
</table>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="p-monthpicker" *ngIf="currentView === 'month'">
|
||
|
<span
|
||
|
*ngFor="let m of monthPickerValues(); let i = index"
|
||
|
(click)="onMonthSelect($event, i)"
|
||
|
(keydown)="onMonthCellKeydown($event, i)"
|
||
|
class="p-monthpicker-month"
|
||
|
[ngClass]="{ 'p-highlight': isMonthSelected(i), 'p-disabled': isMonthDisabled(i) }"
|
||
|
pRipple
|
||
|
>
|
||
|
{{ m }}
|
||
|
<div *ngIf="isMonthSelected(i)" class="p-hidden-accessible" aria-live="polite">
|
||
|
{{ m }}
|
||
|
</div>
|
||
|
</span>
|
||
|
</div>
|
||
|
<div class="p-yearpicker" *ngIf="currentView === 'year'">
|
||
|
<span
|
||
|
*ngFor="let y of yearPickerValues()"
|
||
|
(click)="onYearSelect($event, y)"
|
||
|
(keydown)="onYearCellKeydown($event, y)"
|
||
|
class="p-yearpicker-year"
|
||
|
[ngClass]="{ 'p-highlight': isYearSelected(y), 'p-disabled': isYearDisabled(y) }"
|
||
|
pRipple
|
||
|
>
|
||
|
{{ y }}
|
||
|
<div *ngIf="isYearSelected(y)" class="p-hidden-accessible" aria-live="polite">
|
||
|
{{ y }}
|
||
|
</div>
|
||
|
</span>
|
||
|
</div>
|
||
|
</ng-container>
|
||
|
<div class="p-timepicker" *ngIf="(showTime || timeOnly) && currentView === 'date'">
|
||
|
<div class="p-hour-picker">
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="incrementHour($event)"
|
||
|
(keydown.space)="incrementHour($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 0, 1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('nextHour')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span><ng-container *ngIf="currentHour < 10">0</ng-container>{{ currentHour }}</span>
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="decrementHour($event)"
|
||
|
(keydown.space)="decrementHour($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 0, -1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('prevHour')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-separator">
|
||
|
<span>{{ timeSeparator }}</span>
|
||
|
</div>
|
||
|
<div class="p-minute-picker">
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="incrementMinute($event)"
|
||
|
(keydown.space)="incrementMinute($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 1, 1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('nextMinute')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span><ng-container *ngIf="currentMinute < 10">0</ng-container>{{ currentMinute }}</span>
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="decrementMinute($event)"
|
||
|
(keydown.space)="decrementMinute($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 1, -1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('prevMinute')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-separator" *ngIf="showSeconds">
|
||
|
<span>{{ timeSeparator }}</span>
|
||
|
</div>
|
||
|
<div class="p-second-picker" *ngIf="showSeconds">
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="incrementSecond($event)"
|
||
|
(keydown.space)="incrementSecond($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 2, 1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('nextSecond')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span><ng-container *ngIf="currentSecond < 10">0</ng-container>{{ currentSecond }}</span>
|
||
|
<button
|
||
|
class="p-link"
|
||
|
type="button"
|
||
|
(keydown)="onContainerButtonKeydown($event)"
|
||
|
(keydown.enter)="decrementSecond($event)"
|
||
|
(keydown.space)="decrementSecond($event)"
|
||
|
(mousedown)="onTimePickerElementMouseDown($event, 2, -1)"
|
||
|
(mouseup)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.enter)="onTimePickerElementMouseUp($event)"
|
||
|
(keyup.space)="onTimePickerElementMouseUp($event)"
|
||
|
(mouseleave)="onTimePickerElementMouseLeave()"
|
||
|
[attr.aria-label]="getTranslation('prevSecond')"
|
||
|
pRipple
|
||
|
>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
<div class="p-ampm-picker" *ngIf="hourFormat == '12'">
|
||
|
<button class="p-link" type="button" (keydown)="onContainerButtonKeydown($event)" (click)="toggleAMPM($event)" (keydown.enter)="toggleAMPM($event)" [attr.aria-label]="getTranslation('am')" pRipple>
|
||
|
<ChevronUpIcon *ngIf="!incrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="incrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
<span>{{ pm ? 'PM' : 'AM' }}</span>
|
||
|
<button class="p-link" type="button" (keydown)="onContainerButtonKeydown($event)" (click)="toggleAMPM($event)" (keydown.enter)="toggleAMPM($event)" [attr.aria-label]="getTranslation('pm')" pRipple>
|
||
|
<ChevronDownIcon *ngIf="!decrementIconTemplate" />
|
||
|
<ng-template *ngTemplateOutlet="decrementIconTemplate"></ng-template>
|
||
|
</button>
|
||
|
</div>
|
||
|
</div>
|
||
|
<div class="p-datepicker-buttonbar" *ngIf="showButtonBar">
|
||
|
<button type="button" [label]="getTranslation('today')" (keydown)="onContainerButtonKeydown($event)" (click)="onTodayButtonClick($event)" pButton pRipple [ngClass]="[todayButtonStyleClass]"></button>
|
||
|
<button type="button" [label]="getTranslation('clear')" (keydown)="onContainerButtonKeydown($event)" (click)="onClearButtonClick($event)" pButton pRipple [ngClass]="[clearButtonStyleClass]"></button>
|
||
|
</div>
|
||
|
<ng-content select="p-footer"></ng-content>
|
||
|
<ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
|
||
|
</div>
|
||
|
</span>
|
||
|
`, animations: [
|
||
|
trigger('overlayAnimation', [
|
||
|
state('visibleTouchUI', style({
|
||
|
transform: 'translate(-50%,-50%)',
|
||
|
opacity: 1
|
||
|
})),
|
||
|
transition('void => visible', [style({ opacity: 0, transform: 'scaleY(0.8)' }), animate('{{showTransitionParams}}', style({ opacity: 1, transform: '*' }))]),
|
||
|
transition('visible => void', [animate('{{hideTransitionParams}}', style({ opacity: 0 }))]),
|
||
|
transition('void => visibleTouchUI', [style({ opacity: 0, transform: 'translate3d(-50%, -40%, 0) scale(0.9)' }), animate('{{showTransitionParams}}')]),
|
||
|
transition('visibleTouchUI => void', [
|
||
|
animate('{{hideTransitionParams}}', style({
|
||
|
opacity: 0,
|
||
|
transform: 'translate3d(-50%, -40%, 0) scale(0.9)'
|
||
|
}))
|
||
|
])
|
||
|
])
|
||
|
], host: {
|
||
|
class: 'p-element p-inputwrapper',
|
||
|
'[class.p-inputwrapper-filled]': 'filled',
|
||
|
'[class.p-inputwrapper-focus]': 'focus',
|
||
|
'[class.p-calendar-clearable]': 'showClear && !disabled'
|
||
|
}, providers: [CALENDAR_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-calendar{position:relative;display:inline-flex;max-width:100%}.p-calendar .p-inputtext{flex:1 1 auto;width:1%;text-overflow:ellipsis}.p-calendar-w-btn .p-inputtext{border-top-right-radius:0;border-bottom-right-radius:0}.p-calendar-w-btn .p-datepicker-trigger{border-top-left-radius:0;border-bottom-left-radius:0}.p-fluid .p-calendar{display:flex}.p-fluid .p-calendar .p-inputtext{width:1%}.p-calendar .p-datepicker{min-width:100%}.p-datepicker{width:auto;position:absolute;top:0;left:0}.p-datepicker-inline{display:inline-block;position:static;overflow-x:auto}.p-datepicker-header{display:flex;align-items:center;justify-content:space-between}.p-datepicker-header .p-datepicker-title{margin:0 auto}.p-datepicker-prev,.p-datepicker-next{cursor:pointer;display:inline-flex;justify-content:center;align-items:center;overflow:hidden;position:relative}.p-datepicker-multiple-month .p-datepicker-group-container .p-datepicker-group{flex:1 1 auto}.p-datepicker-multiple-month .p-datepicker-group-container{display:flex}.p-datepicker table{width:100%;border-collapse:collapse}.p-datepicker td>span{display:flex;justify-content:center;align-items:center;cursor:pointer;margin:0 auto;overflow:hidden;position:relative}.p-monthpicker-month{width:33.3%;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;position:relative}.p-datepicker-buttonbar{display:flex;justify-content:space-between;align-items:center}.p-timepicker{display:flex;justify-content:center;align-items:center}.p-timepicker button{display:flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;position:relative}.p-timepicker>div{display:flex;align-items:center;flex-direction:column}.p-datepicker-touch-ui,.p-calendar .p-datepicker-touch-ui{position:fixed;top:50%;left:50%;min-width:80vw;transform:translate(-50%,-50%)}.p-yearpicker-year{width:50%;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;overflow:hidden;position:relative}.p-calendar-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-datepicker-icon{pointer-events:none}.p-calendar-clearable{position:relative}}\n"] }]
|
||
|
}], ctorParameters: () => [{ type: Document, decorators: [{
|
||
|
type: Inject,
|
||
|
args: [DOCUMENT]
|
||
|
}] }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i1.PrimeNGConfig }, { type: i1.OverlayService }], propDecorators: { iconDisplay: [{
|
||
|
type: Input
|
||
|
}], style: [{
|
||
|
type: Input
|
||
|
}], styleClass: [{
|
||
|
type: Input
|
||
|
}], inputStyle: [{
|
||
|
type: Input
|
||
|
}], inputId: [{
|
||
|
type: Input
|
||
|
}], name: [{
|
||
|
type: Input
|
||
|
}], inputStyleClass: [{
|
||
|
type: Input
|
||
|
}], placeholder: [{
|
||
|
type: Input
|
||
|
}], ariaLabelledBy: [{
|
||
|
type: Input
|
||
|
}], ariaLabel: [{
|
||
|
type: Input
|
||
|
}], iconAriaLabel: [{
|
||
|
type: Input
|
||
|
}], disabled: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], dateFormat: [{
|
||
|
type: Input
|
||
|
}], multipleSeparator: [{
|
||
|
type: Input
|
||
|
}], rangeSeparator: [{
|
||
|
type: Input
|
||
|
}], inline: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], showOtherMonths: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], selectOtherMonths: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], showIcon: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], icon: [{
|
||
|
type: Input
|
||
|
}], appendTo: [{
|
||
|
type: Input
|
||
|
}], readonlyInput: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], shortYearCutoff: [{
|
||
|
type: Input
|
||
|
}], monthNavigator: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], yearNavigator: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], hourFormat: [{
|
||
|
type: Input
|
||
|
}], timeOnly: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], stepHour: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: numberAttribute }]
|
||
|
}], stepMinute: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: numberAttribute }]
|
||
|
}], stepSecond: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: numberAttribute }]
|
||
|
}], showSeconds: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], required: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], showOnFocus: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], showWeek: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], startWeekFromFirstDayOfYear: [{
|
||
|
type: Input
|
||
|
}], showClear: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], dataType: [{
|
||
|
type: Input
|
||
|
}], selectionMode: [{
|
||
|
type: Input
|
||
|
}], maxDateCount: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: numberAttribute }]
|
||
|
}], showButtonBar: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], todayButtonStyleClass: [{
|
||
|
type: Input
|
||
|
}], clearButtonStyleClass: [{
|
||
|
type: Input
|
||
|
}], autofocus: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], autoZIndex: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], baseZIndex: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: numberAttribute }]
|
||
|
}], panelStyleClass: [{
|
||
|
type: Input
|
||
|
}], panelStyle: [{
|
||
|
type: Input
|
||
|
}], keepInvalid: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], hideOnDateTimeSelect: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], touchUI: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], timeSeparator: [{
|
||
|
type: Input
|
||
|
}], focusTrap: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: booleanAttribute }]
|
||
|
}], showTransitionOptions: [{
|
||
|
type: Input
|
||
|
}], hideTransitionOptions: [{
|
||
|
type: Input
|
||
|
}], tabindex: [{
|
||
|
type: Input,
|
||
|
args: [{ transform: numberAttribute }]
|
||
|
}], variant: [{
|
||
|
type: Input
|
||
|
}], minDate: [{
|
||
|
type: Input
|
||
|
}], maxDate: [{
|
||
|
type: Input
|
||
|
}], disabledDates: [{
|
||
|
type: Input
|
||
|
}], disabledDays: [{
|
||
|
type: Input
|
||
|
}], yearRange: [{
|
||
|
type: Input
|
||
|
}], showTime: [{
|
||
|
type: Input
|
||
|
}], responsiveOptions: [{
|
||
|
type: Input
|
||
|
}], numberOfMonths: [{
|
||
|
type: Input
|
||
|
}], firstDayOfWeek: [{
|
||
|
type: Input
|
||
|
}], locale: [{
|
||
|
type: Input
|
||
|
}], view: [{
|
||
|
type: Input
|
||
|
}], defaultDate: [{
|
||
|
type: Input
|
||
|
}], onFocus: [{
|
||
|
type: Output
|
||
|
}], onBlur: [{
|
||
|
type: Output
|
||
|
}], onClose: [{
|
||
|
type: Output
|
||
|
}], onSelect: [{
|
||
|
type: Output
|
||
|
}], onClear: [{
|
||
|
type: Output
|
||
|
}], onInput: [{
|
||
|
type: Output
|
||
|
}], onTodayClick: [{
|
||
|
type: Output
|
||
|
}], onClearClick: [{
|
||
|
type: Output
|
||
|
}], onMonthChange: [{
|
||
|
type: Output
|
||
|
}], onYearChange: [{
|
||
|
type: Output
|
||
|
}], onClickOutside: [{
|
||
|
type: Output
|
||
|
}], onShow: [{
|
||
|
type: Output
|
||
|
}], templates: [{
|
||
|
type: ContentChildren,
|
||
|
args: [PrimeTemplate]
|
||
|
}], containerViewChild: [{
|
||
|
type: ViewChild,
|
||
|
args: ['container', { static: false }]
|
||
|
}], inputfieldViewChild: [{
|
||
|
type: ViewChild,
|
||
|
args: ['inputfield', { static: false }]
|
||
|
}], content: [{
|
||
|
type: ViewChild,
|
||
|
args: ['contentWrapper', { static: false }]
|
||
|
}] } });
|
||
|
export class CalendarModule {
|
||
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: CalendarModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
||
|
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.3.7", ngImport: i0, type: CalendarModule, declarations: [Calendar], imports: [CommonModule, ButtonModule, SharedModule, RippleModule, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, TimesIcon, CalendarIcon, AutoFocusModule], exports: [Calendar, ButtonModule, SharedModule] });
|
||
|
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: CalendarModule, imports: [CommonModule, ButtonModule, SharedModule, RippleModule, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, TimesIcon, CalendarIcon, AutoFocusModule, ButtonModule, SharedModule] });
|
||
|
}
|
||
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.7", ngImport: i0, type: CalendarModule, decorators: [{
|
||
|
type: NgModule,
|
||
|
args: [{
|
||
|
imports: [CommonModule, ButtonModule, SharedModule, RippleModule, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, TimesIcon, CalendarIcon, AutoFocusModule],
|
||
|
exports: [Calendar, ButtonModule, SharedModule],
|
||
|
declarations: [Calendar]
|
||
|
}]
|
||
|
}] });
|
||
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsZW5kYXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBwL2NvbXBvbmVudHMvY2FsZW5kYXIvY2FsZW5kYXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE9BQU8sRUFBa0IsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakcsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6RCxPQUFPLEVBQ0gsZ0JBQWdCLEVBQ2hCLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsZUFBZSxFQUVmLFlBQVksRUFDWixVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssRUFDTCxRQUFRLEVBRVIsZUFBZSxFQUdmLE1BQU0sRUFJTixTQUFTLEVBQ1QsaUJBQWlCLEVBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBd0IsaUJBQWlCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RSxPQUFPLEVBQWlDLGFBQWEsRUFBRSxZQUFZLEVBQUUsZUFBZSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzFHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsNkJBQTZCLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsV0FBVyxFQUFFLGlCQUFpQixFQUFFLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUU1RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDNUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDOUQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR3RELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQzs7Ozs7OztBQUVwRCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBUTtJQUN4QyxPQUFPLEVBQUUsaUJBQWlCO0lBQzFCLFdBQVcsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDO0lBQ3ZDLEtBQUssRUFBRSxJQUFJO0NBQ2QsQ0FBQztBQUNGOzs7R0FHRztBQXNhSCxNQUFNLE9BQU8sUUFBUTtJQXNyQnFCO0lBQTJCO0lBQXVCO0lBQTRCO0lBQStCO0lBQXNCO0lBQThCO0lBcnJCOUwsV0FBVyxHQUF1QixRQUFRLENBQUM7SUFDcEQ7OztPQUdHO0lBQ00sS0FBSyxDQUE4QztJQUM1RDs7O09BR0c7SUFDTSxVQUFVLENBQXFCO0lBQ3hDOzs7T0FHRztJQUNNLFVBQVUsQ0FBOEM7SUFDakU7OztPQUdHO0lBQ00sT0FBTyxDQUFxQjtJQUNyQzs7O09BR0c7SUFDTSxJQUFJLENBQXFCO0lBQ2xDOzs7T0FHRztJQUNNLGVBQWUsQ0FBcUI7SUFDN0M7OztPQUdHO0lBQ00sV0FBVyxDQUFxQjtJQUN6Qzs7O09BR0c7SUFDTSxjQUFjLENBQXFCO0lBQzVDOzs7T0FHRztJQUNNLFNBQVMsQ0FBcUI7SUFFdkM7OztPQUdHO0lBQ00sYUFBYSxDQUFxQjtJQUMzQzs7O09BR0c7SUFDcUMsUUFBUSxDQUFzQjtJQUN0RTs7O09BR0c7SUFDTSxVQUFVLENBQXFCO0lBQ3hDOzs7T0FHRztJQUNNLGlCQUFpQixHQUFXLEdBQUcsQ0FBQztJQUN6Qzs7O09BR0c7SUFDTSxjQUFjLEdBQVcsR0FBRyxDQUFDO0lBQ3RDOzs7T0FHRztJQUNxQyxNQUFNLEdBQVksS0FBSyxDQUFDO0lBQ2hFOzs7T0FHRztJQUNxQyxlQUFlLEdBQVksSUFBSSxDQUFDO0lBQ3hFOzs7T0FHRztJQUNxQyxpQkFBaUIsQ0FBc0I7SUFDL0U7OztPQUdHO0lBQ3FDLFFBQVEsQ0FBc0I7SUFDdEU7OztPQUdHO0lBQ00sSUFBSSxDQUFxQjtJQUNsQzs7O09BR0c7SUFDTSxRQUFRLENBQWdGO0lBQ2pHOzs7T0FHRztJQUNxQyxhQUFhLENBQXNCO0lBQzNFOzs7T0FHRztJQUNNLGVBQWUsR0FBUSxLQUFLLENBQUM7SUFDdEM7Ozs7T0FJRztJQUNxQyxjQUFjLENBQXNCO0lBQzVFOzs7O09BSUc7SUFDcUMsYUFBYSxDQUFzQjtJQUMzRTs7O09BR0c7SUFDTSxVQUFVLEdBQVcsSUFBSSxDQUFDO0lBQ25DOzs7T0FHRztJQUNxQyxRQUFRLENBQXNCO0lBQ3RFOzs7T0FHRztJQUNvQyxRQUFRLEdBQVcsQ0FBQyxDQUFDO0lBQzVEOzs7T0FHRztJQUNvQyxVQUFVLEdBQVcsQ0FBQyxDQUFDO0lBQzlEOzs7T0FHRztJQUNvQyxVQUFVLEdBQVcsQ0FBQyxDQUFDO0lBQzlEOzs7T0FHRztJQUNxQyxXQUFXLEdBQVksS0FBSyxDQUFDO0lBQ3JFOzs7T0FHRztJQUNxQyxRQUFRLENBQXNCO0lBQ3RFOzs7T0FHRztJQUNxQyxXQUFXLEdBQVksSUFBSSxDQUFDO0lBQ3BFOzs7T0FHRztJQUNxQyxRQUFRLEdBQVksS0FBSyxDQUFDO0lBQ2xFOzs7T0FHRztJQUNNLDJCQUEyQixHQUFZLEtBQUssQ0FBQztJQUN0RDs7O09BR0c7SUFDcUMsU0FBUyxHQUFZLEtBQUssQ0FBQztJQUNuRTs7O09BR0c7SUFDTSxRQUFRLEdBQVcsTUFBTSxDQUFDO0lBQ25DOzs7T0FHRztJQUNNLGFBQWEsR0FBZ0QsUUFBUSxDQUFDO0lBQy9FOzs7T0FHRztJQUNvQyxZQUFZLENBQXFCO0lBQ3hFOzs7T0FHRztJQUNxQyxhQUFhLENBQXNCO0lBQzNFOzs7T0FHRztJQUNNLHFCQUFxQixHQUFXLGVBQWUsQ0FBQztJQUN6RDs7O09BR0c7SUFDTSxxQkFBcUIsR0FBVyxlQUFlLENBQUM7SUFDekQ7OztPQUdHO0lBQ3FDLFNBQVMsQ0FBc0I7SUFDdkU7OztPQUdHO0lBQ3FDLFVBQVUsR0FBWSxJQUFJLENBQUM7SUFDbkU7OztPQUdHO0lBQ29DLFVBQVUsR0FBVyxDQUFDLENBQUM7SUFDOUQ7OztPQUdHO0lBQ00sZUFBZSxDQUFxQjtJQUM3Qzs7O09BR0c7SUFDTSxVQUFVLENBQU07SUFDekI7OztPQUdHO0lBQ3FDLFdBQVcsR0FBWSxLQUFLLENBQUM7SUFDckU7OztPQUdHO0lBQ3FDLG9CQUFvQixHQUFZLElBQUksQ0FBQztJQUM3RTs7O09BR0c7SUFDcUMsT0FBTyxDQUFzQjtJQUNyRTs7O09BR0c7SUFDTSxhQUFhLEdBQVcsR0FBRyxDQUFDO0lBQ3JDOzs7T0FHRztJQUNxQyxTQUFTLEdBQVksSUFBS
|