@progress/kendo-angular-dateinputs
Version:
Kendo UI for Angular Date Inputs Package - Everything you need to add date selection functionality to apps (DatePicker, TimePicker, DateInput, DateRangePicker, DateTimePicker, Calendar, and MultiViewCalendar).
1,371 lines (1,361 loc) • 836 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Directive, Input, isDevMode, Component, Output, ChangeDetectionStrategy, HostListener, HostBinding, forwardRef, ElementRef, ContentChild, ViewChild, InjectionToken, Inject, NgZone, Optional, ViewContainerRef, ViewChildren, TemplateRef, ContentChildren, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, NgControl } from '@angular/forms';
import * as i1$1 from '@progress/kendo-angular-l10n';
import { ComponentMessages, LocalizationService, L10N_PREFIX, RTL } from '@progress/kendo-angular-l10n';
import { cloneDate, MS_PER_HOUR, MS_PER_MINUTE, addDays, getDate, isEqual, addDecades, addCenturies, firstDecadeOfCentury, lastDecadeOfCentury, lastYearOfDecade, firstYearOfDecade, createDate, lastMonthOfYear, lastDayOfMonth, durationInCenturies, addYears, durationInDecades, addWeeks, addMonths, firstDayOfMonth, dayOfWeek, durationInMonths, firstMonthOfYear, durationInYears, weekInYear } from '@progress/kendo-date-math';
import * as i19 from '@progress/kendo-angular-common';
import { isDocumentAvailable, EventsOutsideAngularDirective, guid, Keys as Keys$1, hasObservers, isObject, KendoInput, ResizeSensorComponent, isObjectPresent, removeHTMLAttributes, parseAttributes, anyChanged, isControlRequired, setHTMLAttributes, MultiTabStop, ToggleButtonTabStopDirective, ResizeBatchService, KENDO_TOGGLEBUTTONTABSTOP } from '@progress/kendo-angular-common';
export { ToggleButtonTabStopDirective } from '@progress/kendo-angular-common';
import { validatePackage } from '@progress/kendo-licensing';
import * as i1 from '@progress/kendo-angular-intl';
import { localeData } from '@progress/kendo-angular-intl';
import { Subject, Subscription, ReplaySubject, Observable, combineLatest, of, interval, animationFrameScheduler, fromEvent, EMPTY, from, BehaviorSubject, merge } from 'rxjs';
import { NgIf, NgTemplateOutlet, NgClass, NgFor, NgStyle } from '@angular/common';
import { chevronRightIcon, chevronLeftIcon, caretAltUpIcon, xIcon, caretAltDownIcon, calendarIcon, checkIcon, clockIcon } from '@progress/kendo-svg-icons';
import { ButtonComponent } from '@progress/kendo-angular-buttons';
import { map, scan, takeWhile, debounceTime, tap, filter } from 'rxjs/operators';
import { DateInput } from '@progress/kendo-dateinputs-common';
import { IconWrapperComponent, IconsService } from '@progress/kendo-angular-icons';
import * as i1$2 from '@progress/kendo-angular-popup';
import { PopupService } from '@progress/kendo-angular-popup';
import { ActionSheetComponent, ActionSheetTemplateDirective } from '@progress/kendo-angular-navigation';
import { touchEnabled } from '@progress/kendo-common';
import * as i6 from '@progress/kendo-angular-utils';
import { AdaptiveService } from '@progress/kendo-angular-utils';
/**
* @hidden
*/
const packageMetadata = {
name: '@progress/kendo-angular-dateinputs',
productName: 'Kendo UI for Angular',
productCode: 'KENDOUIANGULAR',
productCodes: ['KENDOUIANGULAR'],
publishDate: 1750770915,
version: '19.1.2',
licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
};
/**
* @hidden
*/
var Action;
(function (Action) {
Action[Action["Left"] = 0] = "Left";
Action[Action["Right"] = 1] = "Right";
Action[Action["Up"] = 2] = "Up";
Action[Action["Down"] = 3] = "Down";
Action[Action["PrevView"] = 4] = "PrevView";
Action[Action["NextView"] = 5] = "NextView";
Action[Action["FirstInView"] = 6] = "FirstInView";
Action[Action["LastInView"] = 7] = "LastInView";
Action[Action["LowerView"] = 8] = "LowerView";
Action[Action["UpperView"] = 9] = "UpperView";
})(Action || (Action = {}));
/**
* A constant representing an empty selection range with both start and end set to null.
*
* @hidden
*/
const EMPTY_SELECTIONRANGE = { start: null, end: null };
/**
* @hidden
*/
const MIDNIGHT_DATE = new Date(1980, 0, 1);
/**
* @hidden
*/
const MIN_DATE = new Date(1900, 0, 1);
/**
* @hidden
*/
const MAX_DATE = new Date(2099, 11, 31);
/**
* @hidden
*/
const MIN_TIME = new Date(1980, 0, 1);
/**
* @hidden
*/
const MAX_TIME = new Date(1980, 0, 1, 23, 59, 59);
/**
* @hidden
*/
const requiresZoneOnBlur = (ngControl) => ngControl &&
(!ngControl.touched || (ngControl.control && ngControl.control.updateOn === 'blur'));
/**
* @hidden
*/
const preventDefault = (args) => args.preventDefault();
/**
* @hidden
*/
const currentFocusTarget = (blurArgs) => blurArgs.relatedTarget || document.activeElement;
/**
* @hidden
*/
const isPresent = (value) => value !== undefined && value !== null;
/**
* @hidden
*/
const isNullOrDate = (value) => value === null || value instanceof Date;
/**
* @hidden
*/
const isTruthy = (value) => !!value;
/**
* @hidden
*
* If the provided parameter is an array with at least one item
* and all items in the array are numbers, returns `true.
*/
const isNumberArray = (value) => Array.isArray(value) && value.length > 0 && value.every(item => typeof item === 'number');
/**
* @hidden
*
* If the provided parameter is an array with at least one item
* and all items in the array are dates, returns `true`.
*/
const isDateArray = (value) => Array.isArray(value) && value.length > 0 && value.every(item => item instanceof Date);
/**
* @hidden
*/
const isArrowWithShiftPressed = (args) => args.shiftKey && (args.keyCode === Keys.ArrowRight || args.keyCode === Keys.ArrowLeft || args.keyCode === Keys.ArrowDown || args.keyCode === Keys.ArrowUp);
/**
* @hidden
* Enum with key codes.
*/
var Keys;
(function (Keys) {
Keys[Keys["ArrowDown"] = 40] = "ArrowDown";
Keys[Keys["ArrowLeft"] = 37] = "ArrowLeft";
Keys[Keys["ArrowRight"] = 39] = "ArrowRight";
Keys[Keys["ArrowUp"] = 38] = "ArrowUp";
})(Keys || (Keys = {}));
/**
* @hidden
*/
const selectors = {
infiniteCalendarTable: '.k-content .k-calendar-table',
multiViewCalendarTable: '.k-calendar-table'
};
/**
* @hidden
*/
const attributeNames = {
ariaActiveDescendant: 'aria-activedescendant',
ariaControls: 'aria-controls',
ariaExpanded: 'aria-expanded',
ariaHasPopup: 'aria-haspopup',
valueNow: 'aria-valuenow',
valuetext: 'aria-valuetext',
ariaInvalid: 'aria-invalid'
};
const isSet = (value) => value !== null && value !== undefined;
const setter = (method) => (date, value) => {
const clone = cloneDate(date);
clone[method](value);
return clone;
};
/**
* @hidden
*/
const setTime = (origin, candidate) => {
const date = cloneDate(origin);
date.setHours(candidate.getHours(), candidate.getMinutes(), candidate.getSeconds(), candidate.getMilliseconds());
return date;
};
/**
* @hidden
*/
const getTimeInMilliseconds = (candidate) => {
const hoursInMilliseconds = candidate.getHours() * MS_PER_HOUR;
const minutesInMilliseconds = candidate.getMinutes() * MS_PER_MINUTE;
const secondsInMilliseconds = candidate.getSeconds() * 1000;
return hoursInMilliseconds + minutesInMilliseconds + secondsInMilliseconds + candidate.getMilliseconds();
};
const normalizeTimes = (candidate, min, max) => {
return {
candidateValue: setTime(MIDNIGHT_DATE, candidate),
maxValue: addDays(setTime(MIDNIGHT_DATE, max), getTimeInMilliseconds(min) < getTimeInMilliseconds(max) ? 0 : 1),
minValue: setTime(MIDNIGHT_DATE, min)
};
};
/**
* @hidden
*/
const setYears = setter('setFullYear');
/**
* @hidden
*/
const setHours$1 = setter('setHours');
/**
* @hidden
*/
const setMinutes = setter('setMinutes');
/**
* @hidden
*/
const setSeconds = setter('setSeconds');
/**
* @hidden
*/
const setMilliseconds = setter('setMilliseconds');
/**
* @hidden
*/
const range = (start, end, step = 1) => {
const result = [];
for (let i = start; i < end; i = i + step) {
result.push(i);
}
return result;
};
/**
* @hidden
*/
const isInRange = (candidate, min, max) => (!candidate || !((min && min > candidate) || (max && max < candidate)));
/**
* @hidden
*/
const isInTimeRange = (candidate, min, max) => {
if (!candidate || !min || !max) {
return true;
}
const { candidateValue, minValue, maxValue } = normalizeTimes(candidate, min, max);
return minValue <= candidateValue && candidateValue <= maxValue;
};
/**
* @hidden
*/
const isValidRange = (min, max) => (!isSet(min) || !isSet(max) || min <= max);
/**
* @hidden
*/
const dateInRange = (candidate, min, max) => {
if (!candidate) {
return candidate;
}
if (min && candidate < min) {
return cloneDate(min);
}
if (max && candidate > max) {
return cloneDate(max);
}
return candidate;
};
/**
* @hidden
*/
const timeInRange = (candidate, min, max) => {
if (!candidate || !min || !max) {
return candidate;
}
const { candidateValue, minValue, maxValue } = normalizeTimes(candidate, min, max);
if (candidateValue < minValue) {
return setTime(candidate, min);
}
if (candidateValue > maxValue) {
return setTime(candidate, max);
}
return candidate;
};
/**
* @hidden
*/
const getNow = () => new Date();
/**
* @hidden
*/
const getToday = () => getDate(new Date());
/**
* @hidden
*/
const noop$2 = (_) => { }; // eslint-disable-line no-empty
/**
* @hidden
*/
const isWindowAvailable = () => {
return typeof window !== 'undefined';
};
/**
* @hidden
*/
const stringifyClassObject = (classes) => {
const pushToAcc = (acc, cls) => classes[cls] ? acc.concat(cls) : acc;
return Object.keys(classes).reduce(pushToAcc, []).join(' ');
};
/**
* @hidden
*/
const shiftWeekNames = (names, offset) => (names.slice(offset).concat(names.slice(0, offset)));
/**
* @hidden
*/
const approximateStringMatching = (oldTextOrigin, oldFormat, newTextOrigin, caret) => {
// Remove the right part of the cursor.
//oldFormat = oldFormat.substring(0, caret + oldText.length - newText.length);
const oldIndex = caret + oldTextOrigin.length - newTextOrigin.length;
const oldTextSeparator = oldTextOrigin[oldIndex];
const oldText = oldTextOrigin.substring(0, caret + oldTextOrigin.length - newTextOrigin.length);
const newText = newTextOrigin.substring(0, caret);
const diff = [];
// Handle typing a single character over the same selection.
if (oldText === newText && caret > 0) {
diff.push([oldFormat[caret - 1], newText[caret - 1]]);
return diff;
}
if (oldText.indexOf(newText) === 0 && (newText.length === 0 || oldFormat[newText.length - 1] !== oldFormat[newText.length])) {
// Handle Delete/Backspace.
let deletedSymbol = "";
//XXX:
// Whole text is replaced with a same char
// Nasty patch required to keep the selection in the first segment
if (newText.length === 1) {
diff.push([oldFormat[0], newText[0]]);
}
for (let i = newText.length; i < oldText.length; i++) {
if (oldFormat[i] !== deletedSymbol && oldFormat[i] !== "_") {
deletedSymbol = oldFormat[i];
diff.push([deletedSymbol, ""]);
}
}
return diff;
}
// Handle inserting text (the new text is longer than the previous one).
// Handle typing over a literal as well.
if (newText.indexOf(oldText) === 0 || oldFormat[caret - 1] === "_") {
let symbol = oldFormat[0];
for (let i = Math.max(0, oldText.length - 1); i < oldFormat.length; i++) {
if (oldFormat[i] !== "_") {
symbol = oldFormat[i];
break;
}
}
return [[symbol, newText[caret - 1]]];
}
// Handle entering a space or a separator, for navigation to the next item.
if (newText[newText.length - 1] === " " || (newText[newText.length - 1] === oldTextSeparator && oldFormat[oldIndex] === '_')) {
return [[oldFormat[caret - 1], "_"]];
}
// Handle typing over a correctly selected part.
return [[oldFormat[caret - 1], newText[caret - 1]]];
};
/**
* @hidden
*/
const domContainerFactory = (type) => (children, classes = "", styles = {}) => {
const container = document.createElement(type);
container.className = classes;
Object.keys(styles).map(key => container.style[key] = styles[key]);
if (typeof children === 'string') {
container.innerHTML = children || '';
}
else {
(children || []).forEach(child => child && container.appendChild(child));
}
return container;
};
/**
* @hidden
*/
const hasChange = (changes, field) => changes[field] !== undefined;
/**
* @hidden
*/
const hasExistingValue = (changes, field) => changes[field] && changes[field].currentValue !== undefined && changes[field].currentValue !== null;
/**
* @hidden
*/
const last = (list = []) => list && list[list.length - 1];
/**
* @hidden
*/
const isInSelectionRange = (value, selectionRange) => {
const { start, end } = selectionRange || EMPTY_SELECTIONRANGE;
if (!start || !end) {
return false;
}
return start < value && value < end;
};
/**
* @hidden
*/
const either = (value1, value2) => value1 || value2;
/**
* @hidden
*/
const clampRange = (value) => ({ start: value, end: value });
/**
* @hidden
*/
const isEqualRange = (initial, updated) => {
const { start: initialStart, end: initialEnd } = initial || EMPTY_SELECTIONRANGE;
const { start: updatedStart, end: updatedEnd } = updated || EMPTY_SELECTIONRANGE;
return isEqual(initialStart, updatedStart) && isEqual(initialEnd, updatedEnd);
};
/**
* @hidden
*/
const areDatesEqual = (first, second) => {
first = first || [];
second = second || [];
return first.length === second.length && first.every((date, index) => isEqual(date, second[index]));
};
/**
* @hidden
*/
const sortDates = (dates) => {
return dates.filter(date => isPresent(date)).sort((a, b) => a.getTime() - b.getTime());
};
/**
* @hidden
*
* Creates a new date based on the date information from the specified date portion
* and the time information from the time portion.
* If a parameter is not provided, returns `null`.
*/
const mergeDateAndTime = (date, time) => {
if (!(date && time)) {
return null;
}
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds());
};
/**
* @hidden
*/
const lastMillisecondOfDate = (date) => {
if (!date) {
return null;
}
return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 999);
};
/**
* @hidden
*
* Returns an array with dates ranging between and including the specified start and
* end dates that are evaluated as disabled.
*/
const disabledDatesInRange = (start, end, isDateDisabled) => {
if (!(start && end && isDateDisabled) || (start > end)) {
return [];
}
const dates = [];
let current = start;
while (current <= end) {
if (isDateDisabled(current)) {
dates.push(current);
}
current = addDays(current, 1);
}
return dates;
};
/**
* @hidden
*
* Crops the last two digits from the year of the provided date value.
*/
const cropTwoDigitYear = (date) => {
if (!isPresent(date) || isNaN(date.getTime())) {
return 0;
}
return Number(date
.getFullYear()
.toString()
.slice(-2));
};
/**
* @hidden
*
* Used when resetting millisecond segment value in the DateInput
*/
const msPaddingFromFormat = (format) => {
return Array(format.match(/S+(\1)/)[0].length).join("0"); // eslint-disable-line no-useless-backreference
};
/**
* @hidden
*/
const millisecondDigitsInFormat = (format) => {
const result = format && format.match(/S+(\1)/); // eslint-disable-line no-useless-backreference
return result ? result[0].length : 0;
};
/**
* @hidden
*/
const millisecondStepFor = (digits) => {
return Math.pow(10, 3 - digits);
};
/**
* @hidden
*
* Checks if a tab keydown would would move the focus outside of the calendar.
*/
const isTabExitingCalendar = (calendarType, focusedElement, shiftKey) => {
if (!isPresent(focusedElement)) {
return false;
}
return calendarType === 'infinite' || ( // infinte calendar is always exited on first tab keydown
calendarType === 'classic' &&
(shiftKey && focusedElement.classList.contains('k-calendar-table')) || // exited on main calendar element focused and back-tab
(!shiftKey && focusedElement.classList.contains('k-calendar-table')) // exited on next button focused and regular tab
);
};
/**
* @hidden
* Returns the size class based on the component and size input.
*/
const getSizeClass = (component, size) => {
const SIZE_CLASSES = {
'small': `k-${component}-sm`,
'medium': `k-${component}-md`,
'large': `k-${component}-lg`
};
return SIZE_CLASSES[size];
};
/**
* @hidden
* Returns the rounded class based on the rounded input.
*/
const getRoundedClass = (rounded) => {
const ROUNDED_CLASSES = {
'small': 'k-rounded-sm',
'medium': 'k-rounded-md',
'large': 'k-rounded-lg',
'full': 'k-rounded-full'
};
return ROUNDED_CLASSES[rounded];
};
/**
* @hidden
* Return the fillMode class based on the component and fillMode input.
*/
const getFillModeClass = (component, fillMode) => {
const FILLMODE_CLASSES = {
'solid': `k-${component}-solid`,
'flat': `k-${component}-flat`,
'outline': `k-${component}-outline`
};
return FILLMODE_CLASSES[fillMode];
};
/**
* @hidden
*/
const DEFAULT_ROUNDED = 'medium';
/**
* @hidden
*/
const DEFAULT_SIZE = 'medium';
/**
* @hidden
*/
const DEFAULT_FILL_MODE = 'solid';
const EMPTY_DATA$3 = [[]];
const CELLS_LENGTH$3 = 4;
const ROWS_LENGTH$3 = 3;
const upStep$1 = (year) => {
const decadeOfCentury = Number(year.toString().slice(-2, -1));
if (decadeOfCentury < 2) {
return -2;
}
if (decadeOfCentury < 4) {
return -6;
}
return -4;
};
const downStep$1 = (year) => {
const decadeOfCentury = Number(year.toString().slice(-2, -1));
if (decadeOfCentury > 7) {
return 2;
}
if (decadeOfCentury > 5) {
return 6;
}
return 4;
};
const ACTIONS$3 = {
[Action.Left]: (date) => addDecades(date, -1),
[Action.Up]: (date) => addDecades(date, upStep$1(date.getFullYear())),
[Action.Right]: (date) => addDecades(date, 1),
[Action.Down]: (date) => addDecades(date, downStep$1(date.getFullYear())),
[Action.PrevView]: (date) => addCenturies(date, -1),
[Action.NextView]: (date) => addCenturies(date, 1),
[Action.FirstInView]: (date) => firstDecadeOfCentury(date),
[Action.LastInView]: (date) => lastDecadeOfCentury(date)
};
/**
* @hidden
*/
class CenturyViewService {
addToDate(min, skip) {
return addCenturies(min, skip);
}
datesList(start, count) {
return range(0, count).map(i => addCenturies(start, i));
}
data(options) {
const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, allowReverse } = options;
if (!viewDate) {
return EMPTY_DATA$3;
}
const cells = range(0, CELLS_LENGTH$3);
const firstDate = firstDecadeOfCentury(viewDate);
const lastDate = lastDecadeOfCentury(viewDate);
const lastYearOfCentury = lastYearOfDecade(lastDate).getFullYear() + 1;
const today = getToday();
return range(0, ROWS_LENGTH$3).map(rowOffset => {
const baseDate = addDecades(firstDate, rowOffset * CELLS_LENGTH$3);
return cells.map(cellOffset => {
const cellDate = this.normalize(addDecades(baseDate, cellOffset), min, max);
const nextCentury = cellDate.getFullYear() >= lastYearOfCentury;
if (!this.isInRange(cellDate, min, max) || nextCentury) {
return null;
}
let isRangeStart = false;
let isRangeEnd = false;
if (allowReverse) {
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
isRangeStart = true;
}
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
isRangeEnd = true;
}
}
else {
isRangeStart = this.isEqual(cellDate, selectionRange.start);
isRangeEnd = this.isEqual(cellDate, selectionRange.end);
}
const isInMiddle = !isRangeStart && !isRangeEnd;
let isRangeMid;
if (allowReverse) {
isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
}
else {
isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
}
return {
formattedValue: this.value(cellDate),
id: `${cellUID}${cellDate.getTime()}`,
isFocused: this.isEqual(cellDate, focusedDate),
isSelected: isActiveView && selectedDates.some(date => this.isEqual(cellDate, date)),
isWeekend: false,
isRangeStart: isRangeStart,
isRangeMid: isRangeMid,
isRangeEnd: isRangeEnd,
isRangeSplitEnd: isRangeMid && this.isEqual(cellDate, lastDate),
isRangeSplitStart: isRangeMid && this.isEqual(cellDate, firstDate),
isToday: this.isEqual(cellDate, today),
title: this.cellTitle(cellDate),
value: cellDate,
allowReverse: allowReverse
};
});
});
}
isEqual(candidate, expected) {
if (!candidate || !expected) {
return false;
}
return firstYearOfDecade(candidate).getFullYear() === firstYearOfDecade(expected).getFullYear();
}
isInArray(date, dates) {
if (!dates.length) {
return false;
}
const year = date.getFullYear();
return dates[0].getFullYear() <= year && year <= (dates[dates.length - 1].getFullYear() + 99);
}
isInRange(candidate, min, max) {
const year = firstYearOfDecade(candidate).getFullYear();
const aboveMin = !min || firstYearOfDecade(min).getFullYear() <= year;
const belowMax = !max || year <= firstYearOfDecade(max).getFullYear();
return aboveMin && belowMax;
}
beginningOfPeriod(date) {
if (!date) {
return date;
}
const firstYear = firstYearOfDecade(firstDecadeOfCentury(date));
return createDate(firstYear.getFullYear(), 0, 1);
}
lastDayOfPeriod(date) {
const decade = lastDecadeOfCentury(date);
const year = lastYearOfDecade(decade);
const month = lastMonthOfYear(year);
return lastDayOfMonth(month);
}
isRangeStart(value) {
return value.getFullYear() % 1000 === 0;
}
move(value, action) {
const modifier = ACTIONS$3[action];
if (!modifier) {
return value;
}
return modifier(value);
}
cellTitle(value) {
return firstYearOfDecade(value).getFullYear().toString();
}
navigationTitle(value) {
return value ? firstDecadeOfCentury(value).getFullYear().toString() : '';
}
title(value) {
if (!value) {
return '';
}
return `${firstDecadeOfCentury(value).getFullYear()} - ${lastDecadeOfCentury(value).getFullYear()}`;
}
rowLength() {
return CELLS_LENGTH$3;
}
skip(value, min) {
return durationInCenturies(min, value);
}
total(min, max) {
return durationInCenturies(min, max) + 1;
}
value(current) {
return current ? firstYearOfDecade(current).getFullYear().toString() : '';
}
viewDate(date, max, viewsCount = 1) {
const viewsInRange = this.total(date, max);
if (viewsInRange < viewsCount) {
const centuriesToSubtract = viewsCount - viewsInRange;
return addCenturies(date, -1 * centuriesToSubtract);
}
return date;
}
dateRange = (start, end) => {
if (!isPresent(start) || !isPresent(end)) {
return [];
}
const result = [];
let current = start;
while (current <= end) {
result.push(current);
current = addDecades(current, 1);
}
return result;
};
normalize(cellDate, min, max) {
if (cellDate < min && this.isEqual(cellDate, min)) {
return cloneDate(min);
}
if (cellDate > max && this.isEqual(cellDate, max)) {
return cloneDate(max);
}
return cellDate;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CenturyViewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CenturyViewService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CenturyViewService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
const EMPTY_DATA$2 = [[]];
const CELLS_LENGTH$2 = 4;
const ROWS_LENGTH$2 = 3;
const upStep = (year) => {
const yearOfDecade = Number(year.toString().slice(-1));
if (yearOfDecade < 2) {
return -2;
}
if (yearOfDecade < 4) {
return -6;
}
return -4;
};
const downStep = (year) => {
const yearOfDecade = Number(year.toString().slice(-1));
if (yearOfDecade > 7) {
return 2;
}
if (yearOfDecade > 5) {
return 6;
}
return 4;
};
const ACTIONS$2 = {
[Action.Left]: (date) => addYears(date, -1),
[Action.Up]: (date) => addYears(date, upStep(date.getFullYear())),
[Action.Right]: (date) => addYears(date, 1),
[Action.Down]: (date) => addYears(date, downStep(date.getFullYear())),
[Action.PrevView]: (date) => addDecades(date, -1),
[Action.NextView]: (date) => addDecades(date, 1),
[Action.FirstInView]: (date) => firstYearOfDecade(date),
[Action.LastInView]: (date) => lastYearOfDecade(date)
};
/**
* @hidden
*/
class DecadeViewService {
addToDate(min, skip) {
return addDecades(min, skip);
}
datesList(start, count) {
return range(0, count).map(i => addDecades(start, i));
}
data(options) {
const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, allowReverse } = options;
if (!viewDate) {
return EMPTY_DATA$2;
}
const cells = range(0, CELLS_LENGTH$2);
const firstDate = firstYearOfDecade(viewDate);
const lastDate = lastYearOfDecade(viewDate);
const today = getToday();
return range(0, ROWS_LENGTH$2).map(rowOffset => {
const baseDate = addYears(firstDate, rowOffset * CELLS_LENGTH$2);
return cells.map(cellOffset => {
const cellDate = this.normalize(addYears(baseDate, cellOffset), min, max);
const nextDecade = cellDate.getFullYear() > lastDate.getFullYear();
if (!this.isInRange(cellDate, min, max) || nextDecade) {
return null;
}
let isRangeStart = false;
let isRangeEnd = false;
if (allowReverse) {
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
isRangeStart = true;
}
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
isRangeEnd = true;
}
}
else {
isRangeStart = this.isEqual(cellDate, selectionRange.start);
isRangeEnd = this.isEqual(cellDate, selectionRange.end);
}
const isInMiddle = !isRangeStart && !isRangeEnd;
let isRangeMid;
if (allowReverse) {
isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
}
else {
isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
}
return {
formattedValue: this.value(cellDate),
id: `${cellUID}${cellDate.getTime()}`,
isFocused: this.isEqual(cellDate, focusedDate),
isSelected: isActiveView && selectedDates.some(date => this.isEqual(cellDate, date)),
isWeekend: false,
isRangeStart: isRangeStart,
isRangeMid: isRangeMid,
isRangeEnd: isRangeEnd,
isRangeSplitEnd: isRangeMid && this.isEqual(cellDate, lastDate),
isRangeSplitStart: isRangeMid && this.isEqual(cellDate, firstDate),
isToday: this.isEqual(cellDate, today),
title: this.cellTitle(cellDate),
value: cellDate,
allowReverse: allowReverse
};
});
});
}
isEqual(candidate, expected) {
if (!candidate || !expected) {
return false;
}
return candidate.getFullYear() === expected.getFullYear();
}
isInArray(date, dates) {
if (!dates.length) {
return false;
}
const year = date.getFullYear();
return dates[0].getFullYear() <= year && year <= (dates[dates.length - 1].getFullYear() + 9);
}
isInRange(candidate, min, max) {
const year = candidate.getFullYear();
const aboveMin = !min || min.getFullYear() <= year;
const belowMax = !max || year <= max.getFullYear();
return aboveMin && belowMax;
}
beginningOfPeriod(date) {
if (!date) {
return date;
}
const firstYear = firstYearOfDecade(date);
return createDate(firstYear.getFullYear(), 0, 1);
}
lastDayOfPeriod(date) {
const year = lastYearOfDecade(date);
const month = lastMonthOfYear(year);
return lastDayOfMonth(month);
}
isRangeStart(value) {
return value.getFullYear() % 100 === 0;
}
move(value, action) {
const modifier = ACTIONS$2[action];
if (!modifier) {
return value;
}
return modifier(value);
}
cellTitle(value) {
return value.getFullYear().toString();
}
navigationTitle(value) {
return value ? firstYearOfDecade(value).getFullYear().toString() : '';
}
title(value) {
if (!value) {
return '';
}
return `${firstYearOfDecade(value).getFullYear()} - ${lastYearOfDecade(value).getFullYear()}`;
}
rowLength() {
return CELLS_LENGTH$2;
}
skip(value, min) {
return durationInDecades(min, value);
}
total(min, max) {
return durationInDecades(min, max) + 1;
}
value(current) {
return current ? current.getFullYear().toString() : '';
}
viewDate(date, max, viewsCount = 1) {
const viewsInRange = this.total(date, max);
if (viewsInRange < viewsCount) {
const decadesToSubtract = viewsCount - viewsInRange;
return addDecades(date, -1 * decadesToSubtract);
}
return date;
}
dateRange = (start, end) => {
if (!isPresent(start) || !isPresent(end)) {
return [];
}
const result = [];
let current = start;
while (current <= end) {
result.push(current);
current = addYears(current, 1);
}
return result;
};
normalize(cellDate, min, max) {
if (cellDate < min && this.isEqual(cellDate, min)) {
return cloneDate(min);
}
if (cellDate > max && this.isEqual(cellDate, max)) {
return cloneDate(max);
}
return cellDate;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DecadeViewService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DecadeViewService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DecadeViewService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}] });
const EMPTY_DATA$1 = [[]];
const CELLS_LENGTH$1 = 7;
const ROWS_LENGTH$1 = 6;
const ACTIONS$1 = {
[Action.Left]: (date) => addDays(date, -1),
[Action.Up]: (date) => addWeeks(date, -1),
[Action.Right]: (date) => addDays(date, 1),
[Action.Down]: (date) => addWeeks(date, 1),
[Action.PrevView]: (date) => addMonths(date, -1),
[Action.NextView]: (date) => addMonths(date, 1),
[Action.FirstInView]: (date) => firstDayOfMonth(date),
[Action.LastInView]: (date) => lastDayOfMonth(date)
};
/**
* @hidden
*/
class MonthViewService {
_intlService;
constructor(_intlService) {
this._intlService = _intlService;
}
addToDate(min, skip) {
return addMonths(min, skip);
}
datesList(start, count) {
return range(0, count).map(i => addMonths(start, i));
}
data(options) {
const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, isDateDisabled = () => false, allowReverse } = options;
if (!viewDate) {
return EMPTY_DATA$1;
}
const firstMonthDate = firstDayOfMonth(viewDate);
const firstMonthDay = getDate(firstMonthDate);
const lastMonthDate = lastDayOfMonth(viewDate);
const lastMonthDay = getDate(lastMonthDate);
const backward = -1;
const date = dayOfWeek(firstMonthDate, this._intlService.firstDay(), backward);
const cells = range(0, CELLS_LENGTH$1);
const today = getToday();
return range(0, ROWS_LENGTH$1).map(rowOffset => {
const baseDate = addDays(date, rowOffset * CELLS_LENGTH$1);
return cells.map(cellOffset => {
const cellDate = this.normalize(addDays(baseDate, cellOffset), min, max);
const cellDay = getDate(cellDate);
const otherMonth = cellDay < firstMonthDay || cellDay > lastMonthDay;
const outOfRange = cellDate < min || cellDate > max;
if (outOfRange) {
return null;
}
let isRangeStart = false;
let isRangeEnd = false;
if (allowReverse) {
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
isRangeStart = true;
}
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
isRangeEnd = true;
}
}
else {
isRangeStart = this.isEqual(cellDate, selectionRange.start);
isRangeEnd = this.isEqual(cellDate, selectionRange.end);
}
const isInMiddle = !isRangeStart && !isRangeEnd;
let isRangeMid;
if (allowReverse) {
isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
}
else {
isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
}
return {
formattedValue: this.value(cellDate),
id: `${cellUID}${otherMonth ? cellDate.getTime() + '1' : cellDate.getTime()}`,
isFocused: this.isEqual(cellDate, focusedDate),
isSelected: isActiveView && selectedDates.some(date => this.isEqual(cellDate, date)),
isWeekend: this.isWeekend(cellDate),
isRangeStart: isRangeStart,
isRangeMid: isRangeMid,
isRangeEnd: isRangeEnd,
isRangeSplitStart: isRangeMid && this.isEqual(cellDate, firstMonthDate),
isRangeSplitEnd: isRangeMid && this.isEqual(cellDate, lastMonthDate),
isToday: this.isEqual(cellDate, today),
title: this.cellTitle(cellDate),
value: cellDate,
isDisabled: isDateDisabled(cellDate),
isOtherMonth: otherMonth,
allowReverse: allowReverse
};
});
});
}
isEqual(candidate, expected) {
if (!candidate || !expected) {
return false;
}
return getDate(candidate).getTime() === getDate(expected).getTime();
}
isInArray(date, dates) {
if (dates.length === 0) {
return false;
}
const lowerBound = this.beginningOfPeriod(dates[0]);
const upperBound = this.beginningOfPeriod(addMonths(dates[dates.length - 1], 1));
return lowerBound <= date && date < upperBound;
}
isInRange(candidate, min, max) {
const value = getDate(candidate);
const aboveMin = !min || getDate(min) <= value;
const belowMax = !max || value <= getDate(max);
return aboveMin && belowMax;
}
beginningOfPeriod(date) {
if (!date) {
return date;
}
return createDate(date.getFullYear(), date.getMonth(), 1);
}
lastDayOfPeriod(date) {
return lastDayOfMonth(date);
}
isRangeStart(value) {
return !value.getMonth();
}
move(value, action) {
const modifier = ACTIONS$1[action];
if (!modifier) {
return value;
}
return modifier(value);
}
cellTitle(value) {
return this._intlService.formatDate(value, 'D');
}
navigationTitle(value) {
if (!value) {
return '';
}
return this.isRangeStart(value) ? value.getFullYear().toString() : this.abbrMonthNames()[value.getMonth()];
}
title(current) {
return `${this.wideMonthNames()[current.getMonth()]} ${current.getFullYear()}`;
}
rowLength(options = {}) {
return CELLS_LENGTH$1 + (options.prependCell ? 1 : 0);
}
skip(value, min) {
return durationInMonths(min, value);
}
total(min, max) {
return durationInMonths(min, max) + 1;
}
value(current) {
return current ? current.getDate().toString() : "";
}
viewDate(date, max, viewsCount = 1) {
const viewsInRange = this.total(date, max);
if (viewsInRange < viewsCount) {
const monthsToSubtract = viewsCount - viewsInRange;
return addMonths(date, -1 * monthsToSubtract);
}
return date;
}
isWeekend(date) {
const { start, end } = this._intlService.weekendRange();
const day = date.getDay();
if (end < start) {
return day <= end || start <= day;
}
return start <= day && day <= end;
}
dateRange = (start, end) => {
if (!isPresent(start) || !isPresent(end)) {
return [];
}
const result = [];
let current = start;
while (current <= end) {
result.push(current);
current = addDays(current, 1);
}
return result;
};
abbrMonthNames() {
return this._intlService.dateFormatNames({ nameType: 'abbreviated', type: 'months' });
}
normalize(cellDate, min, max) {
if (cellDate < min && this.isEqual(cellDate, min)) {
return cloneDate(min);
}
if (cellDate > max && this.isEqual(cellDate, max)) {
return cloneDate(max);
}
return cellDate;
}
wideMonthNames() {
return this._intlService.dateFormatNames({ nameType: 'wide', type: 'months' });
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MonthViewService, deps: [{ token: i1.IntlService }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MonthViewService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MonthViewService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return [{ type: i1.IntlService }]; } });
const EMPTY_DATA = [[]];
const CELLS_LENGTH = 4;
const ROWS_LENGTH = 3;
const ACTIONS = {
[Action.Left]: (date) => addMonths(date, -1),
[Action.Up]: (date) => addMonths(date, -4),
[Action.Right]: (date) => addMonths(date, 1),
[Action.Down]: (date) => addMonths(date, 4),
[Action.PrevView]: (date) => addYears(date, -1),
[Action.NextView]: (date) => addYears(date, 1),
[Action.FirstInView]: (date) => firstMonthOfYear(date),
[Action.LastInView]: (date) => lastMonthOfYear(date)
};
/**
* @hidden
*/
class YearViewService {
_intlService;
constructor(_intlService) {
this._intlService = _intlService;
}
addToDate(min, skip) {
return addYears(min, skip);
}
datesList(start, count) {
return range(0, count).map(i => addYears(start, i));
}
data(options) {
const { cellUID, focusedDate, isActiveView, max, min, selectedDates, selectionRange = EMPTY_SELECTIONRANGE, viewDate, allowReverse } = options;
if (!viewDate) {
return EMPTY_DATA;
}
const months = this.abbrMonthNames();
const firstDate = firstMonthOfYear(viewDate);
const lastDate = lastMonthOfYear(viewDate);
const currentYear = firstDate.getFullYear();
const cells = range(0, CELLS_LENGTH);
const today = getToday();
return range(0, ROWS_LENGTH).map(rowOffset => {
const baseDate = addMonths(firstDate, rowOffset * CELLS_LENGTH);
return cells.map(cellOffset => {
const cellDate = this.normalize(addMonths(baseDate, cellOffset), min, max);
const changedYear = currentYear < cellDate.getFullYear();
if (!this.isInRange(cellDate, min, max) || changedYear) {
return null;
}
let isRangeStart = false;
let isRangeEnd = false;
if (allowReverse) {
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start <= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end <= selectionRange.start)) {
isRangeStart = true;
}
if ((this.isEqual(cellDate, selectionRange.start) && selectionRange.start >= selectionRange.end) ||
(this.isEqual(cellDate, selectionRange.end) && selectionRange.end >= selectionRange.start)) {
isRangeEnd = true;
}
}
else {
isRangeStart = this.isEqual(cellDate, selectionRange.start);
isRangeEnd = this.isEqual(cellDate, selectionRange.end);
}
const isInMiddle = !isRangeStart && !isRangeEnd;
let isRangeMid;
if (allowReverse) {
isRangeMid = isInMiddle && (isInSelectionRange(cellDate, selectionRange) || isInSelectionRange(cellDate, { start: selectionRange.end, end: selectionRange.start }));
}
else {
isRangeMid = isInMiddle && isInSelectionRange(cellDate, selectionRange);
}
return {
formattedValue: months[cellDate.getMonth()],
id: `${cellUID}${cellDate.getTime()}`,
isFocused: this.isEqual(cellDate, focusedDate),
isSelected: isActiveView && selectedDates.some(date => this.isEqual(cellDate, date)),
isWeekend: false,
isRangeStart: isRangeStart,
isRangeMid: isRangeMid,
isRangeEnd: isRangeEnd,
isRangeSplitEnd: isRangeMid && this.isEqual(cellDate, lastDate),
isRangeSplitStart: isRangeMid && this.isEqual(cellDate, firstDate),
isToday: this.isEqual(cellDate, today),
title: this.cellTitle(cellDate),
value: cellDate,
allowReverse: allowReverse
};
});
});
}
isEqual(candidate, expected) {
if (!candidate || !expected) {
return false;
}
return candidate.getFullYear() === expected.getFullYear() &&
candidate.getMonth() === expected.getMonth();
}
isInArray(date, dates) {
if (!dates.length) {
return false;
}
const year = date.getFullYear();
return dates[0].getFullYear() <= year && year <= dates[dates.length - 1].getFullYear();
}
isInRange(candidate, min, max) {
const candidateValue = createDate(candidate.getFullYear(), candidate.getMonth(), 1);
const aboveMin = !min || createDate(min.getFullYear(), min.getMonth(), 1) <= candidateValue;
const belowMax = !max || candidateValue <= createDate(max.getFullYear(), max.getMonth(), 1);
return aboveMin && belowMax;
}
beginningOfPeriod(date) {
if (!date) {
return date;
}
return createDate(date.getFullYear(), 0, 1);
}
lastDayOfPeriod(date) {
const month = lastMonthOfYear(date);
return lastDayOfMonth(month);
}
isRangeStart(value) {
return value.getFullYear() % 10 === 0;
}
move(value, action) {
const modifier = ACTIONS[action];
if (!modifier) {
return value;
}
return modifier(value);
}
cellTitle(value) {
return `${value.getFullYear()} ${this.value(value)}`;
}
navigationTitle(value) {
return this.title(value);
}
title(current) {
return current ? current.getFullYear().toString() : '';
}
rowLength() {
return CELLS_LENGTH;
}
skip(value, min) {
return durationInYears(min, value);
}
total(min, max) {
return durationInYears(min, max) + 1;
}
value(current) {
return current ? this.abbrMonthNames()[current.getMonth()] : '';
}
viewDate(date, max, viewsCount = 1) {
const viewsInRange = this.total(date, max);
if (viewsInRange < viewsCount) {
const yearsToSubtract = viewsCount - viewsInRange;
return addYears(date, -1 * yearsToSubtract);
}
return date;
}
dateRange = (start, end) => {
if (!isPresent(start) || !isPresent(end)) {
return [];
}
const result = [];
let current = start;
while (current <= end) {
result.push(current);
current = addMonths(current, 1);
}
return result;
};
abbrMonthNames() {
return this._intlService.dateFormatNames({ nameType: 'abbreviated', type: 'months' });
}
normalize(cellDate, min, max) {
if (cellDate < min && this.isEqual(cellDate, min)) {
return cloneDate(min);
}
if (cellDate > max && this.isEqual(cellDate, max)) {
return cloneDate(max);
}
return cellDate;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: YearViewServic