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).

224 lines (223 loc) 9.54 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Injectable } from '@angular/core'; import { IntlService } from '@progress/kendo-angular-intl'; import { addDays, addWeeks, addMonths, cloneDate, dayOfWeek, durationInMonths, getDate, firstDayOfMonth, lastDayOfMonth, createDate } from '@progress/kendo-date-math'; import { Action } from '../models/navigation-action.enum'; import { EMPTY_SELECTIONRANGE } from '../models/selection-range.interface'; import { getToday, isInSelectionRange, range } from '../../util'; import { isPresent } from '../../common/utils'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-intl"; const EMPTY_DATA = [[]]; const CELLS_LENGTH = 7; const ROWS_LENGTH = 6; const ACTIONS = { [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 */ export 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; } 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); const today = getToday(); return range(0, ROWS_LENGTH).map(rowOffset => { const baseDate = addDays(date, rowOffset * CELLS_LENGTH); 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[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 + (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 }]; } });