@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
JavaScript
/**-----------------------------------------------------------------------------------------
* 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 }]; } });