@progress/kendo-angular-scheduler
Version:
Kendo UI Scheduler Angular - Outlook or Google-style angular scheduler calendar. Full-featured and customizable embedded scheduling from the creator developers trust for professional UI components.
163 lines (162 loc) • 6.37 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 { ChangeDetectorRef, Directive, Input } from '@angular/core';
import { OCCURRENCE_ID } from './common/constants';
import { SchedulerComponent } from './scheduler.component';
import { parseRule, expand } from '@progress/kendo-recurrence';
import { toUTCDateTime } from './views/utils';
import { ZonedDate } from '@progress/kendo-date-math';
import { LocalDataChangesService } from './editing/local-data-changes.service';
import { clone, setField, getField } from './common/util';
import { IntlService } from '@progress/kendo-angular-intl';
import * as i0 from "@angular/core";
import * as i1 from "./scheduler.component";
import * as i2 from "@progress/kendo-angular-intl";
import * as i3 from "./editing/local-data-changes.service";
// TODO
// Extract as public method
const occurrences = (item, fields, range, timezone, weekStart) => {
const rrule = parseRule({
recurrenceRule: getField(item, fields.recurrenceRule),
weekStart: weekStart
});
if (!rrule.start) {
const start = getField(item, fields.start);
rrule.start = ZonedDate.fromLocalDate(start, timezone);
}
if (!rrule.end) {
const end = getField(item, fields.end);
rrule.end = ZonedDate.fromLocalDate(end, timezone);
}
const exceptions = getField(item, fields.recurrenceExceptions);
if (exceptions) {
rrule.exceptionDates = exceptions
.map(exDate => ZonedDate.fromLocalDate(exDate, timezone));
// TODO: Merge exceptions from recurrence rule with event.recurrenceException
}
const utcRangeStart = toUTCDateTime(range.start);
const utcRangeEnd = toUTCDateTime(range.end);
const series = expand(rrule, {
rangeStart: ZonedDate.fromUTCDate(utcRangeStart, timezone),
rangeEnd: ZonedDate.fromUTCDate(utcRangeEnd, timezone)
});
if (!series.events.length) {
return [];
}
const expanded = series.events.map(occ => {
const event = clone(item);
setField(event, fields.id, OCCURRENCE_ID);
setField(event, fields.recurrenceId, getField(item, fields.id));
setField(event, fields.start, occ.start.toLocalDate());
setField(event, fields.end, occ.end.toLocalDate());
return event;
});
return [item, ...expanded];
};
/**
* A directive that processes Scheduler events in memory ([see example](slug:databinding_scheduler#automatic-data-processing)).
*
* Processing includes expanding of recurring events and filtering data for
* the currently active period.
*
* @example
* ```html
* <kendo-scheduler [kendoSchedulerBinding]="data">
* </kendo-scheduler>
* ```
*
* @remarks
* Applied to: {@link SchedulerComponent}
*/
export class DataBindingDirective {
scheduler;
changeDetector;
intl;
localDataChangesService;
/**
* Sets the data array for the Scheduler.
*/
set data(value) {
this.originalData = value || [];
if (this.localDataChangesService) {
this.localDataChangesService.data = value;
}
this.scheduler.events = this.process();
}
dateRange;
originalData = [];
subscription;
dataChangedSubscription;
constructor(scheduler, changeDetector, intl, localDataChangesService) {
this.scheduler = scheduler;
this.changeDetector = changeDetector;
this.intl = intl;
this.localDataChangesService = localDataChangesService;
if (localDataChangesService) {
this.dataChangedSubscription = this.localDataChangesService.changes.subscribe(this.rebind.bind(this));
}
}
/**
* @hidden
*/
ngOnInit() {
this.subscription = this.scheduler
.dateChange
.subscribe(e => this.onDateChange(e));
}
/**
* @hidden
*/
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
if (this.dataChangedSubscription) {
this.dataChangedSubscription.unsubscribe();
}
}
/**
* @hidden
*/
rebind() {
this.data = this.originalData;
this.changeDetector.markForCheck();
}
process() {
if (!this.dateRange) {
// No processing until a date range is set
return [];
}
const data = [];
const fields = this.scheduler.modelFields;
this.originalData
.forEach(item => {
if (getField(item, fields.recurrenceRule)) {
const series = occurrences(item, fields, this.dateRange, this.scheduler.timezone, this.scheduler.weekStart);
data.push(...series);
}
else {
data.push(item);
}
});
return data;
}
onDateChange(e) {
this.dateRange = e.dateRange;
this.rebind();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, deps: [{ token: i1.SchedulerComponent }, { token: i0.ChangeDetectorRef }, { token: i2.IntlService }, { token: i3.LocalDataChangesService }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DataBindingDirective, isStandalone: true, selector: "[kendoSchedulerBinding]", inputs: { data: ["kendoSchedulerBinding", "data"] }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoSchedulerBinding]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i1.SchedulerComponent }, { type: i0.ChangeDetectorRef }, { type: i2.IntlService }, { type: i3.LocalDataChangesService }]; }, propDecorators: { data: [{
type: Input,
args: ['kendoSchedulerBinding']
}] } });