@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).
226 lines (225 loc) • 8.74 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, Renderer2, Optional } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { EMPTY_SELECTIONRANGE } from '../calendar/models/selection-range.interface';
import { isEqual } from '@progress/kendo-date-math';
import { attributeNames } from '../common/utils';
import * as i0 from "@angular/core";
const isActive = (cmp) => (cmp && cmp.isActive) || false;
const hasActiveContent = (popup) => popup && popup.hasActiveContent();
/**
* A service that handles the communication between the components that are placed inside the DateRangeComponent.
* For example, the start and end `DateInput` and `DateRangePopup` components.
*/
export class DateRangeService {
renderer;
/**
* An Observable instance that notifies when the `activeRangeEnd` state is changed.
*/
activeRangeEnd$ = new BehaviorSubject(null);
/**
* An Observable instance that notifies when the `focusedDate` is changed.
*/
focusedDate$ = new BehaviorSubject(null);
/**
* An Observable instance that notifies when the end `DateInput` component is changed.
* For example, when a new end `DateInput` is attached or when the old one is detached.
*/
endInput$ = new BehaviorSubject(null);
/**
* An Observable instance that notifies when the start `DateInput` component is changed.
* For example, when a new start `DateInput` is attached or the old one is detached.
*/
startInput$ = new BehaviorSubject(null);
/**
* An Observable instance that notifies when the `DateRangePopup` component is changed.
*/
dateRangePopup$ = new BehaviorSubject(null);
/**
* An Observable instance that notifies when the state of the selection range is changed.
*/
range$ = new BehaviorSubject(EMPTY_SELECTIONRANGE);
/**
* Gets the current `activeRangeEnd` value.
*/
get activeRangeEnd() {
return this.activeRangeEnd$.value;
}
/**
* Gets the current `focusedDate` value.
*/
get focusedDate() {
return this.focusedDate$.value;
}
/**
* Gets the `min` range value.
* The `min` value is extracted from the `start` DateInput value or the `min` value of the Calendar.
*/
get min() {
return (this.startInput$.value || {}).min || null;
}
/**
* Gets the `max` range value.
* The `max` value is extracted from the `end` DateInput value or the `max` value of the Calendar.
*/
get max() {
return (this.endInput$.value || {}).max || null;
}
/**
* Gets the current `selectionRange` value.
*/
get selectionRange() {
return this.range$.value;
}
/**
* @hidden
* Gets the start input element.
*/
get inputStartElement() {
return this.startInput$.value.inputElement;
}
/**
* @hidden
* Gets the end input element.
*/
get inputEndElement() {
return this.endInput$.value.inputElement;
}
/** @hidden */
constructor(renderer) {
this.renderer = renderer;
}
/**
* Activates the registered `DateRangePopup` component.
* The method opens the popup and focuses the calendar.
*/
activatePopup() {
const dateRangePopup = this.dateRangePopup$.value;
if (!dateRangePopup) {
return;
}
if (this.startInput$.value) {
this.renderer.setAttribute(this.inputStartElement, attributeNames.ariaControls, dateRangePopup.popupUID);
this.renderer.setAttribute(this.inputStartElement, attributeNames.ariaExpanded, 'true');
this.renderer.setAttribute(this.inputEndElement, attributeNames.ariaControls, dateRangePopup.popupUID);
this.renderer.setAttribute(this.inputEndElement, attributeNames.ariaExpanded, 'true');
}
dateRangePopup.activate();
}
/**
* Deactivates the registered `DateRangePopup` component.
* The method closes the popup.
*/
deactivatePopup() {
const dateRangePopup = this.dateRangePopup$.value;
if (this.startInput$.value) {
this.renderer.removeAttribute(this.inputStartElement, attributeNames.ariaControls);
this.renderer.setAttribute(this.inputStartElement, attributeNames.ariaExpanded, 'false');
this.renderer.removeAttribute(this.inputStartElement, attributeNames.ariaActiveDescendant);
this.renderer.removeAttribute(this.inputEndElement, attributeNames.ariaControls);
this.renderer.setAttribute(this.inputEndElement, attributeNames.ariaExpanded, 'false');
this.renderer.removeAttribute(this.inputEndElement, attributeNames.ariaActiveDescendant);
}
if (!(dateRangePopup && dateRangePopup.show)) {
return;
}
dateRangePopup.show = false;
}
/**
* @hidden
*/
setActiveDescendent(id) {
this.renderer.setAttribute(this.inputStartElement, attributeNames.ariaActiveDescendant, id);
this.renderer.setAttribute(this.inputEndElement, attributeNames.ariaActiveDescendant, id);
}
/**
* @hidden
*
* Deactivates the registered `DateRangePopup` component and fires the `cancel` event.
* The method closes the popup.
*/
cancelPopup() {
const dateRangePopup = this.dateRangePopup$.value;
if (!(dateRangePopup && dateRangePopup.show)) {
return;
}
dateRangePopup.cancelPopup();
}
/**
* Completes all observables to mitigate possible memory leaks.
* Calls the method when a component that uses it is destroyed.
*/
destroy() {
this.activeRangeEnd$.complete();
this.dateRangePopup$.complete();
this.focusedDate$.complete();
this.endInput$.complete();
this.startInput$.complete();
this.range$.complete();
}
/**
* Returns `true` when an active component that is placed inside the `DateRangeComponent` is detected.
* For example, the opened popup or the focused DateInput.
*
* @returns `true` if an active component is present.
*/
hasActiveComponent() {
const popup = this.dateRangePopup$.value;
const isPopup = isActive(popup);
const isStart = isActive(this.startInput$.value);
const isEnd = isActive(this.endInput$.value);
return isPopup || isStart || isEnd || hasActiveContent(popup) || false;
}
/**
* Registers a new start `DateInput` component. Notifies all `startInput$` listeners.
*/
registerStartInput(startInput) {
this.startInput$.next(startInput);
}
/**
* Registers a new end `DateInput` component. Notifies all `endInput$` listeners.
*/
registerEndInput(endInput) {
this.endInput$.next(endInput);
}
/**
* Registers a new `DateRangePopup` component. Notifies all `dateRangePopup$` listeners.
*/
registerPopup(dateRangePopup) {
this.dateRangePopup$.next(dateRangePopup);
}
/**
* Updates the `activeRangeEnd` value. Notifies all `activeRangeEnd$` listeners.
*/
setActiveRangeEnd(activeRange) {
if (!activeRange || this.activeRangeEnd === activeRange) {
return;
}
this.activeRangeEnd$.next(activeRange);
}
/**
* Updates the focused date. Notifies all `focusedDate$` listeners.
*/
setFocusedDate(value) {
if (isEqual(this.focusedDate$.value, value)) {
return;
}
this.focusedDate$.next(value);
}
/**
* Updates the selection range. Notifies all `range$` listeners.
*/
setRange(range = EMPTY_SELECTIONRANGE) {
this.range$.next(range);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DateRangeService, deps: [{ token: i0.Renderer2, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DateRangeService });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DateRangeService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: i0.Renderer2, decorators: [{
type: Optional
}] }]; } });