UNPKG

@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,370 lines (1,360 loc) 842 kB
/**----------------------------------------------------------------------------------------- * 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: 1749540135, version: '19.1.1', 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 = {})); /** * @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: YearViewService, deps: [{ token: i1.IntlService }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵ