@asadi/angular-date-components
Version:
`Angular Date Components` is a comprehensive angular library of date-related components designed to meet the needs of applications that require localization based on various calendar systems. While the package currently includes two powerful components (S
1,093 lines (1,084 loc) • 55.5 kB
JavaScript
import * as i0 from '@angular/core';
import { EventEmitter, Directive, Output, Input, inject, Component, NgModule, booleanAttribute, Inject, Optional } from '@angular/core';
import * as i3 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i1 from '@asadi/angular-date-components/core';
import { ADCDateTimeTools, DateChangeService, ADC_DATE_ADAPTER, ADC_DATE_FORMATTER, ADC_LABELS, ADC_OPTIONS, ADCStaticValues, ADCCommonService, TableSelection, FlatEventBuilder, ADCTableComponent, ADCBaseContainerComponent } from '@asadi/angular-date-components/core';
import { BehaviorSubject, Subject, takeUntil } from 'rxjs';
/**
* Directive to manage and emit events related to the scheduler, such as date range selection and event selection.
* It handles holidays, weekends, and events and provides observables for changes in these values.
*/
class ADCSchedulerSource {
constructor() {
this._events = new BehaviorSubject([]);
this._holidays = new BehaviorSubject([]);
this._weekends = new BehaviorSubject([]);
/**
* Emitted when a date range is selected by the user.
* This output allows handling of date range selection events in the parent component.
*
* @example
* <div SchedulerSource (DateRangeSelect)="onDateRangeSelect($event)"></div>
*/
this.dateRangeSelect = new EventEmitter();
/**
* Emitted when an event is selected in the scheduler.
* This output allows handling of event selection events in the parent component.
*
* @example
* <div SchedulerSource (EventSelect)="onEventSelect($event)"></div>
*/
this.EventSelect = new EventEmitter();
/**
* Emitted when the date range is changed.
* This output allows handling of date range change events in the parent component.
*
* @example
* <div SchedulerSource (DateRangeChange)="onDateRangeChange($event)"></div>
*/
this.dateRangeChange = new EventEmitter();
this.startOf = null;
}
/**
* The list of holiday dates to exclude in the scheduler.
* When this value is updated, it updates the internal holidays list.
*
* @example
* <div SchedulerSource [Holidays]="holidayList"></div>
*/
set holidays(value) {
if (value == null) {
this._holidays.next([]);
}
else {
this._holidays.next(value);
}
}
get holidays() {
return this._holidays.value;
}
/**
* The list of weekend days (represented as day numbers, e.g., [0, 6] for Sunday and Saturday).
* When this value is updated, it updates the internal weekends list.
*
* @example
* <div SchedulerSource [Weekends]="[0, 6]"></div>
*/
set weekends(value) {
if (value == null) {
this._weekends.next([]);
}
else {
this._weekends.next(value);
}
}
get weekends() {
return this._weekends.value;
}
/**
* The list of scheduler events to be displayed in the scheduler.
* When this value is updated, it updates the internal events list.
*
* @example
* <div SchedulerSource [Events]="eventList"></div>
*/
set events(value) {
if (value == null) {
this._events.next([]);
}
else {
this._events.next(value);
}
}
get events() {
return this._events.value;
}
eventChanges() {
return this._events.asObservable();
}
holidayChanges() {
return this._holidays.asObservable();
}
weekendChanges() {
return this._weekends.asObservable();
}
onEventSelect(e) {
this.EventSelect.emit(e);
}
onDateRangeSelect(e) {
this.dateRangeSelect.next(e);
}
;
onDateRangeChange(e) {
this.dateRangeChange.next(e);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerSource, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.0.7", type: ADCSchedulerSource, isStandalone: true, selector: "[SchedulerSource]", inputs: { holidays: "holidays", weekends: "weekends", startOf: "startOf", events: "events" }, outputs: { dateRangeSelect: "dateRangeSelect", EventSelect: "eventSelect", dateRangeChange: "dateRangeChange" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerSource, decorators: [{
type: Directive,
args: [{
selector: '[SchedulerSource]',
standalone: true
}]
}], propDecorators: { dateRangeSelect: [{
type: Output,
args: ['dateRangeSelect']
}], EventSelect: [{
type: Output,
args: ['eventSelect']
}], dateRangeChange: [{
type: Output,
args: ['dateRangeChange']
}], holidays: [{
type: Input,
args: ['holidays']
}], weekends: [{
type: Input,
args: ['weekends']
}], startOf: [{
type: Input,
args: ['startOf']
}], events: [{
type: Input,
args: ['events']
}] } });
/**
* Utility class for handling event-related operations within a scheduler.
* This class provides methods for filtering events based on a date range.
*/
class ADCSchedulerEventTools {
constructor() {
this.tools = new ADCDateTimeTools();
}
/**
* Filters events that fall within a given date range.
* This method checks whether the start date or end date of an event falls within the specified range.
* It returns an array of events that are within the date range or span across it.
*
* @param startDate - The start date of the date range to filter by.
* @param endDate - The end date of the date range to filter by.
* @param events - An array of events to be filtered.
*
* @returns An array of events that fall within or span across the given date range.
*
* @example
* ```typescript
* const events: ADCISchedulerEvent[] = [
* { startDate: '2024-11-01', endDate: '2024-11-02', title: 'Event 1' },
* { startDate: '2024-11-03', endDate: '2024-11-04', title: 'Event 2' },
* ];
* const filteredEvents = schedulerEventTools.getEventsBetweenDateRange('2024-11-01', '2024-11-03', events);
* console.log(filteredEvents); // Outputs events within the range
* ```
*/
getEventsBetweenDateRange(startDate, endDate, events) {
if (events == null)
return [];
const rangeStart = this.tools.dateOnly(startDate);
const rangeEnd = this.tools.dateOnly(endDate);
return events.filter((e) => {
const eventStart = this.tools.dateOnly(e.startDate);
const eventEnd = this.tools.dateOnly(e.endDate);
return eventStart >= rangeStart && eventStart <= rangeEnd ||
eventEnd >= rangeStart && eventEnd <= rangeEnd ||
eventStart < rangeStart && eventEnd > rangeEnd;
});
}
}
class ADCSchedulerTools {
constructor() {
this.dateTime = new ADCDateTimeTools();
this.scheduler = new ADCSchedulerEventTools();
}
}
/**
* Base class for the ADC scheduler. This class provides fundamental functionality for managing date changes,
* event handling, and interacting with the scheduler source. It handles the event subscription and delegates
* specific logic to abstract methods for customization.
*/
class AdcSchedulerBase {
constructor() {
// Private members
this.destroy$ = new Subject();
this.dateChangeService = inject(DateChangeService);
this.schedulerSource = inject(ADCSchedulerSource);
this.isViewReady = false;
/**
* The date adapter used for managing date-related operations.
*/
this.dateAdapter = inject(ADC_DATE_ADAPTER);
/**
* The date formatter used for formatting dates.
*/
this.dateFormatter = inject(ADC_DATE_FORMATTER);
/**
* A utility toolset for the scheduler, offering additional methods for scheduling operations.
*/
this.tools = new ADCSchedulerTools();
/**
* The optional set of labels used for UI display.
*/
this.labels = inject(ADC_LABELS);
this.options = inject(ADC_OPTIONS);
/**
* start of date provided in the scheduler component use it to set initial date range.
*/
this.startOf = this.schedulerSource.startOf;
}
/**
* Initializes the scheduler by setting up event subscriptions and handlers.
* Subscribes to date change and event change notifications from the date change service and scheduler source.
*
* @returns void
*/
init() {
this.initViewHanlder();
// Subscribe to date change events
this.dateChangeService.onNext().pipe(takeUntil(this.destroy$)).subscribe(() => {
this.isViewReady = false;
this.nextButtonHandler();
});
this.dateChangeService.onPrevious().pipe(takeUntil(this.destroy$)).subscribe(() => {
this.isViewReady = false;
this.previousButtonHandler();
});
this.dateChangeService.onToday().pipe(takeUntil(this.destroy$)).subscribe(() => {
this.isViewReady = false;
this.todayButtonHandler();
});
// Subscribe to event changes from the scheduler source
this.schedulerSource.eventChanges().pipe(takeUntil(this.destroy$)).subscribe((e) => {
if (!this.isViewReady)
return;
this.eventChangesHandler(e);
});
// Subscribe to holiday changes
this.schedulerSource.holidayChanges().pipe(takeUntil(this.destroy$)).subscribe((value) => {
this.holidaysChangesHandler(value);
});
// Subscribe to weekend changes
this.schedulerSource.weekendChanges().pipe(takeUntil(this.destroy$)).subscribe((value) => {
this.weekendsChangesHandler(value);
});
}
/**
* Sends a date range change event to the scheduler source.
*
* @param e - The date range change event to be emitted.
* @returns void
*/
dateRangeChange(e) {
this.schedulerSource.onDateRangeChange(e);
}
/**
* Sends a date range selection event to the scheduler source.
*
* @param e - The date range selection event to be emitted.
* @returns void
*/
dateRangeSelect(e) {
this.schedulerSource.onDateRangeSelect(e);
}
/**
* Sends an event selection event to the scheduler source.
*
* @param e - The event selection event to be emitted.
* @returns void
*/
eventClick(e) {
this.schedulerSource.onEventSelect(e);
}
/**
* Marks the view as ready to process events.
*
* Once this method is called:
* - The `eventChangesHandler` will be triggered immediately with the current list of events.
* - Subsequent updates to events will also be handled automatically until the view is marked as unready.
*
* @returns void
*/
markViewAsReady() {
this.isViewReady = true;
this.eventChangesHandler(this.schedulerSource.events);
}
/**
* Cleans up subscriptions when the component or service is destroyed.
*
* @returns void
*/
destroy() {
this.destroy$.next();
}
}
class ADCDayViewComponent extends AdcSchedulerBase {
constructor() {
super();
this.year = 0;
this.week = 0;
this.day = 0;
this.currentDate = '';
this.title = '';
this.hoursOfDay = ADCStaticValues.getHoursOfDay();
this.daysOfweek = ADCStaticValues.getDaysOfWeek();
this.monthsOfYear = this.dateAdapter.getMonthsOfYear();
this.dateSplitter = this.dateFormatter.DateSplitter;
this.events = [];
this.rows = [];
this.weekends = [];
this.holidays = [];
this.today = this.dateAdapter.today();
this.commonService = new ADCCommonService(this.dateAdapter, this.labels);
this.selectionManager = new TableSelection(this.dateFilter);
this.eventBuilder = new FlatEventBuilder();
}
ngOnInit() {
super.init();
this.selectionManager.cellSelectionStream.subscribe(event => this.onDateRangeSelect(event.start, event.end));
this.eventBuilder.eventSelectionStream.subscribe(e => {
this.onEventClick(e.event, e.dom, e.jsEvent);
});
}
dateFilter(cell1, cell2) {
return (cell2.rowValue == cell1.rowValue && cell2.columnValue >= cell1.columnValue) || (cell2.rowValue > cell1.rowValue);
}
initViewHanlder() {
if (this.startOf == null) {
this.todayButtonHandler();
}
else {
this.day = this.dateAdapter.getDayIndexOf(this.startOf);
this.week = this.dateAdapter.getWeekOf(this.startOf);
this.year = this.dateAdapter.getYearOf(this.startOf);
this.calculateCurrentDate();
}
}
todayButtonHandler() {
this.day = this.dateAdapter.getCurrentDay();
this.week = this.dateAdapter.getCurrentWeek();
this.year = this.dateAdapter.getCurrentYear();
this.calculateCurrentDate();
}
previousButtonHandler() {
this.day--;
if (this.day < 0) {
this.day = 6;
this.week--;
if (this.week < 1) {
this.year--;
this.week = this.dateAdapter.getWeeksOfYear(this.year);
}
}
this.calculateCurrentDate();
}
nextButtonHandler() {
this.day++;
if (this.day > 6) {
this.day = 0;
this.week++;
const weeksOfYear = this.dateAdapter.getWeeksOfYear(this.year);
if (this.week > weeksOfYear) {
this.week = 1;
this.year++;
}
}
this.calculateCurrentDate();
}
calculateCurrentDate() {
const date = this.dateAdapter.getDateOfDay(this.year, this.week, this.day);
this.currentDate = this.dateAdapter.transformDate(+date.split(this.dateSplitter)[0], +date.split(this.dateSplitter)[1], +date.split(this.dateSplitter)[2]);
const day = this.labels?.daysOfWeek[this.commonService.getDayIndex(this.day)] || this.daysOfweek[this.day];
const month = this.monthsOfYear[+date.split(this.dateSplitter)[1] - 1];
this.title = `${day}
${+date.split(this.dateSplitter)[2]}
${this.commonService.getMonthName(month) || month} ${this.labels?.year || "Year"}
${this.year}`;
this.dateChangesHandler();
super.dateRangeChange({ startDate: this.currentDate, endDate: this.currentDate });
}
eventChangesHandler(schedulerEvents) {
const tableEvents = [];
this.events = schedulerEvents;
const viewEvents = this.tools.scheduler.getEventsBetweenDateRange(this.currentDate, this.currentDate, this.events);
viewEvents.forEach((e) => {
const row = this.rows[1];
const rowDate = this.tools.dateTime.dateOnly(row.value);
const eventStartDate = this.tools.dateTime.dateOnly(e.startDate);
const eventEndDate = this.tools.dateTime.dateOnly(e.endDate);
const eventStartHour = this.tools.dateTime.hourOrDefault(e.startTime, '00');
const eventEndHour = this.tools.dateTime.hourOrDefault(e.endTime, '23');
const startColumnIndex = eventStartDate != rowDate ? -1 : row.columns.findIndex(c => {
return this.tools.dateTime.hour(c.value) == eventStartHour;
});
const endColumnIndex = eventEndDate != rowDate ? -1 : row.columns.findIndex(c => {
return this.tools.dateTime.hour(c.value) == eventEndHour;
});
const startTime = +this.tools.dateTime.minutesOrDefault(e.startTime, '00');
const endTime = +this.tools.dateTime.minutesOrDefault(e.endTime, '60');
const cellEvent = {
columnStart: startColumnIndex != -1 ? startColumnIndex : null,
columnEnd: endColumnIndex != -1 ? endColumnIndex : null,
data: e,
rowStart: 1,
rowEnd: 1,
offsetX: startTime / 60,
fractionX: endTime / 60,
overlapTolerance: this.options.eventOverlapTolerance / 60
};
if (e.allDay == true) {
const eventHourEnd = +this.tools.dateTime.hourOrDefault(e.endTime, '23');
cellEvent.fractionX = 24 - eventHourEnd;
}
tableEvents.push(cellEvent);
});
this.eventBuilder.data = tableEvents;
}
dateChangesHandler() {
this.rows = this.getRowInitialValue();
const date = this.dateAdapter.getDateOfDay(this.year, this.week, this.day);
const splittedDate = date.split(this.dateSplitter);
const dayIndex = this.commonService.getDayIndex(this.day);
const transformDate = this.dateAdapter.transformDate(+splittedDate[0], +splittedDate[1], +splittedDate[2]);
const row = {
label: this.labels?.daysOfWeek[dayIndex] || this.daysOfweek[dayIndex],
verticalAlign: 'center',
horizontalAlign: 'center',
prefix: '',
suffix: `${splittedDate[0]}${this.dateSplitter}${splittedDate[1]}${this.dateSplitter}${splittedDate[2]}`,
value: transformDate.split('T')[0],
classList: ''.concat(this.weekends.includes(this.day) || this.holidays.includes(this.currentDate.split('T')[0]) ? ' holiday ' : ' '),
columns: []
};
this.hoursOfDay.forEach((hour) => {
row.columns.push({
verticalAlign: 'center',
horizontalAlign: 'center',
selectable: true,
classList: '',
label: '',
prefix: '',
suffix: '',
value: hour,
});
});
this.rows.push(row);
}
weekendsChangesHandler(weekends) {
this.weekends = weekends;
this.dateChangesHandler();
}
holidaysChangesHandler(holidays) {
this.holidays = holidays;
this.dateChangesHandler();
}
onDateRangeSelect(start, end) {
const e = {
endDate: end.rowValue.split('T')[0],
endTime: end.columnValue,
startDate: start.rowValue.split('T')[0],
startTime: start.columnValue,
};
super.dateRangeSelect(e);
}
onEventClick(event, dom, jsEvent) {
const schedulerEvent = this.events.filter(item => item.id == event.data.id)[0];
super.eventClick({ dom: dom, event: schedulerEvent, jsEvent: jsEvent });
}
ngOnDestroy() {
super.destroy();
}
getRowInitialValue() {
return [{
classList: '',
label: '',
prefix: '',
suffix: '',
value: '',
verticalAlign: 'center',
horizontalAlign: 'center',
columns: ADCStaticValues.getHoursOfDay().map((hour, hourIndex) => {
return {
verticalAlign: 'center',
horizontalAlign: 'center',
selectable: false,
label: hour,
prefix: '',
suffix: '',
value: hour,
classList: ''
};
})
}];
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCDayViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.7", type: ADCDayViewComponent, selector: "adc-day-view", usesInheritance: true, ngImport: i0, template: "\r\n<adc-table\r\n[rows]=\"rows\"\r\n[title]=\"title\"\r\n[titleClass]=\"''.concat(\r\n today == currentDate.split('T')[0] ? ' today ' : ' ',\r\n weekends.includes(day) || holidays.includes(currentDate.split('T')[0]) ? ' holiday ' : ' '\r\n)\"\r\n[selectionManager]=\"selectionManager\"\r\n[eventBuilder]=\"eventBuilder\"\r\n(viewReady)=\"markViewAsReady()\"\r\n></adc-table>\r\n\r\n", styles: [".w-full{width:100%}.w-auto{width:calc(100% - 120px)}.w-12{width:3rem}.border-collapse{border-collapse:collapse}.table-layout-fixed{table-layout:fixed}.h-12{height:3rem}.text-center{text-align:center}.events{height:100%;width:100%;overflow:visible;padding:0;margin:0;height:0}.over-flow-hidden{overflow:hidden}\n"], dependencies: [{ kind: "component", type: i1.ADCTableComponent, selector: "adc-table", inputs: ["rows", "showRowDetails", "title", "titleClass", "eventBuilder", "selectionManager"], outputs: ["viewReady"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCDayViewComponent, decorators: [{
type: Component,
args: [{ selector: 'adc-day-view', template: "\r\n<adc-table\r\n[rows]=\"rows\"\r\n[title]=\"title\"\r\n[titleClass]=\"''.concat(\r\n today == currentDate.split('T')[0] ? ' today ' : ' ',\r\n weekends.includes(day) || holidays.includes(currentDate.split('T')[0]) ? ' holiday ' : ' '\r\n)\"\r\n[selectionManager]=\"selectionManager\"\r\n[eventBuilder]=\"eventBuilder\"\r\n(viewReady)=\"markViewAsReady()\"\r\n></adc-table>\r\n\r\n", styles: [".w-full{width:100%}.w-auto{width:calc(100% - 120px)}.w-12{width:3rem}.border-collapse{border-collapse:collapse}.table-layout-fixed{table-layout:fixed}.h-12{height:3rem}.text-center{text-align:center}.events{height:100%;width:100%;overflow:visible;padding:0;margin:0;height:0}.over-flow-hidden{overflow:hidden}\n"] }]
}], ctorParameters: () => [] });
class ADCWeekViewComponent extends AdcSchedulerBase {
constructor() {
super();
this.week = 0;
this.year = 0;
this.daysOfWeek = ADCStaticValues.getDaysOfWeek();
this.title = '';
this.dateSplitter = this.dateFormatter.DateSplitter;
this.events = [];
this.rows = [];
this.startOfWeek = '';
this.endOfWeek = '';
this.weekends = [];
this.holidays = [];
this.today = this.dateAdapter.today();
this.commonService = new ADCCommonService(this.dateAdapter, this.labels);
this.selectionManager = new TableSelection(this.dateFilter);
this.eventBuilder = new FlatEventBuilder();
}
ngOnInit() {
super.init();
this.selectionManager.cellSelectionStream.subscribe(event => this.onDateRangeSelect(event.start, event.end));
this.eventBuilder.eventSelectionStream.subscribe(e => {
this.onEventClick(e.event, e.dom, e.jsEvent);
});
}
dateFilter(cell1, cell2) {
return cell2.rowValue > cell1.rowValue || (cell2.rowValue == cell1.rowValue && cell2.columnIndex >= cell1.columnIndex);
}
initViewHanlder() {
if (this.startOf == null) {
this.todayButtonHandler();
}
else {
this.week = this.dateAdapter.getWeekOf(this.startOf);
this.year = this.dateAdapter.getYearOf(this.startOf);
this.calculateCurrentDate();
}
}
todayButtonHandler() {
this.week = this.dateAdapter.getCurrentWeek();
this.year = this.dateAdapter.getCurrentYear();
this.calculateCurrentDate();
}
previousButtonHandler() {
this.week--;
if (this.week < 1) {
this.year--;
this.week = this.dateAdapter.getWeeksOfYear(this.year) - 1;
}
this.calculateCurrentDate();
}
nextButtonHandler() {
this.week++;
const weeksOfYear = this.dateAdapter.getWeeksOfYear(this.year);
if (this.week >= weeksOfYear) {
this.year++;
this.week = 1;
}
this.calculateCurrentDate();
}
calculateCurrentDate() {
const start = this.dateAdapter.getDateOfDay(this.year, this.week, 0);
const end = this.dateAdapter.getDateOfDay(this.year, this.week, 6);
this.startOfWeek = this.dateAdapter.transformDate(+start.split(this.dateSplitter)[0], +start.split(this.dateSplitter)[1], +start.split(this.dateSplitter)[2]);
this.endOfWeek = this.dateAdapter.transformDate(+end.split(this.dateSplitter)[0], +end.split(this.dateSplitter)[1], +end.split(this.dateSplitter)[2]);
this.title = `${this.labels?.week || "Week"} ${this.week} ${this.labels?.year || "Year"} ${this.year}`;
this.dateChangesHandler();
super.dateRangeChange({ startDate: this.startOfWeek, endDate: this.endOfWeek });
}
eventChangesHandler(schedulerEvents) {
const tableEvents = [];
this.events = schedulerEvents;
const viewEvents = this.tools.scheduler.getEventsBetweenDateRange(this.startOfWeek, this.endOfWeek, this.events);
viewEvents.forEach((e) => {
const startRowIndex = this.rows.findIndex((r, i) => {
if (i == 0)
return;
return this.tools.dateTime.dateOnly(r.value) == this.tools.dateTime.dateOnly(e.startDate);
});
const startColumnIndex = startRowIndex == -1 ? 0 : this.rows[startRowIndex].columns.findIndex(c => this.tools.dateTime.hour(c.value) === this.tools.dateTime.hourOrDefault(e.startTime, '00'));
const endRowIndex = this.rows.findIndex((r, i) => {
if (i == 0)
return;
return this.tools.dateTime.dateOnly(r.value) == this.tools.dateTime.dateOnly(e.endDate);
});
const endColumnIndex = endRowIndex == -1 ? this.rows[this.rows.length - 1].columns.length - 1 : this.rows[endRowIndex].columns.findIndex(c => this.tools.dateTime.hour(c.value) === this.tools.dateTime.hourOrDefault(e.endTime, '23'));
const startTime = +this.tools.dateTime.minutesOrDefault(e.startTime, '00');
const endTime = +this.tools.dateTime.minutesOrDefault(e.endTime, '60');
const cellEvent = {
columnStart: startRowIndex != -1 ? startColumnIndex : null,
columnEnd: endRowIndex != -1 ? endColumnIndex : null,
data: e,
rowStart: startRowIndex != -1 ? startRowIndex : 0,
rowEnd: endRowIndex != -1 ? endRowIndex : this.rows.length - 1,
offsetX: startTime / 60,
fractionX: endTime / 60,
overlapTolerance: this.options.eventOverlapTolerance / 60
};
if (e.allDay == true) {
const eventHourEnd = +this.tools.dateTime.hourOrDefault(e.endTime, '23');
cellEvent.fractionX = 24 - eventHourEnd;
}
tableEvents.push(cellEvent);
});
this.eventBuilder.data = tableEvents;
}
dateChangesHandler() {
this.rows = this.getInitialRowValue();
this.daysOfWeek.forEach((day, index) => {
const dayIndex = this.commonService.getDayIndex(index);
const date = this.dateAdapter.getDateOfDay(this.year, +this.week, index);
const splittedDate = date.split(this.dateSplitter);
const transformedDate = this.dateAdapter.transformDate(+splittedDate[0], +splittedDate[1], +splittedDate[2]);
const row = {
label: this.labels?.daysOfWeek[dayIndex] || day,
prefix: '',
suffix: splittedDate[1] + this.dateSplitter + splittedDate[2],
verticalAlign: 'center',
horizontalAlign: 'center',
classList: ''.concat(transformedDate.split('T')[0] == this.today ? ' today ' : ' ', this.weekends.includes(index) || this.holidays.includes(transformedDate.split('T')[0]) ? ' holiday ' : ' '),
value: transformedDate.split('T')[0],
columns: []
};
ADCStaticValues.getHoursOfDay().forEach((hour, hourIndex) => {
const column = {
label: '',
prefix: '',
suffix: '',
verticalAlign: 'center',
horizontalAlign: 'center',
classList: '',
value: `${hour}`,
selectable: true
};
row.columns.push(column);
});
this.rows.push(row);
});
}
weekendsChangesHandler(weekends) {
this.weekends = weekends;
this.dateChangesHandler();
}
holidaysChangesHandler(holidays) {
this.holidays = holidays;
this.dateChangesHandler();
}
onDateRangeSelect(start, end) {
const e = {
endDate: end.rowValue,
endTime: end.columnValue,
startDate: start.rowValue,
startTime: start.columnValue,
};
super.dateRangeSelect(e);
}
onEventClick(event, dom, jsEvent) {
const schedulerEvent = this.events.filter(item => item.id == event.data.id)[0];
super.eventClick({ dom: dom, event: schedulerEvent, jsEvent: jsEvent });
}
ngOnDestroy() {
super.destroy();
}
getInitialRowValue() {
return [{
verticalAlign: 'center',
horizontalAlign: 'center',
classList: '',
label: '',
prefix: '',
suffix: '',
value: '',
columns: ADCStaticValues.getHoursOfDay().map((hour, hourIndex) => {
return {
verticalAlign: 'center',
horizontalAlign: 'center',
classList: '',
selectable: false,
label: hour,
prefix: '',
suffix: '',
value: hour,
};
})
}];
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCWeekViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.7", type: ADCWeekViewComponent, selector: "adc-week-view", usesInheritance: true, ngImport: i0, template: "\r\n\r\n \r\n<adc-table\r\n[rows]=\"rows\"\r\n[title]=\"title\"\r\n[selectionManager]=\"selectionManager\"\r\n[eventBuilder]=\"eventBuilder\"\r\n(viewReady)=\"markViewAsReady()\"\r\n></adc-table>\r\n<!-- \r\n[eventBuilder]=\"builder\"\r\n<div flatEventBuilder [columns]=\"columns.length\" [rows]=\"rows.length\" #builder=\"eventBuilder\"></div> -->\r\n\r\n\r\n\r\n", styles: [".w-full{width:100%}.table-layout-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.h-12{height:3rem}.text-center{text-align:center}.events{height:100%;width:100%;overflow:visible;padding:0;margin:0}.h-1152{height:1152px}.over-flow-hidden{overflow:hidden}table{border-spacing:0}\n"], dependencies: [{ kind: "component", type: i1.ADCTableComponent, selector: "adc-table", inputs: ["rows", "showRowDetails", "title", "titleClass", "eventBuilder", "selectionManager"], outputs: ["viewReady"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCWeekViewComponent, decorators: [{
type: Component,
args: [{ selector: 'adc-week-view', template: "\r\n\r\n \r\n<adc-table\r\n[rows]=\"rows\"\r\n[title]=\"title\"\r\n[selectionManager]=\"selectionManager\"\r\n[eventBuilder]=\"eventBuilder\"\r\n(viewReady)=\"markViewAsReady()\"\r\n></adc-table>\r\n<!-- \r\n[eventBuilder]=\"builder\"\r\n<div flatEventBuilder [columns]=\"columns.length\" [rows]=\"rows.length\" #builder=\"eventBuilder\"></div> -->\r\n\r\n\r\n\r\n", styles: [".w-full{width:100%}.table-layout-fixed{table-layout:fixed}.border-collapse{border-collapse:collapse}.h-12{height:3rem}.text-center{text-align:center}.events{height:100%;width:100%;overflow:visible;padding:0;margin:0}.h-1152{height:1152px}.over-flow-hidden{overflow:hidden}table{border-spacing:0}\n"] }]
}], ctorParameters: () => [] });
class ADCMonthViewComponent extends AdcSchedulerBase {
constructor() {
super();
this.month = 0;
this.year = 0;
this.daysOfWeek = ADCStaticValues.getDaysOfWeek();
this.monthsOfYear = this.dateAdapter.getMonthsOfYear();
this.weeksOfMonth = [];
this.title = '';
this.dateSplitter = this.dateFormatter.DateSplitter;
this.events = [];
this.rows = [];
this.startOfMonth = '';
this.endOfMonth = '';
this.weekends = [];
this.holidays = [];
this.today = this.dateAdapter.today();
this.commonService = new ADCCommonService(this.dateAdapter, this.labels);
this.selectionManager = new TableSelection(this.dateFilter);
this.eventBuilder = new FlatEventBuilder();
}
ngOnInit() {
super.init();
this.selectionManager.cellSelectionStream.subscribe(e => {
this.onDateRangeSelect(e.start, e.end);
});
this.eventBuilder.eventSelectionStream.subscribe(e => {
this.onEventClick(e.event, e.dom, e.jsEvent);
});
}
dateFilter(cell1, cell2) {
return +cell2.rowValue > +cell1.rowValue || (cell2.rowValue == cell1.rowValue && cell2.columnIndex >= cell1.columnIndex);
}
todayButtonHandler() {
this.month = this.dateAdapter.getCurrentMonth();
this.year = this.dateAdapter.getCurrentYear();
this.calculateCurrentDate();
}
previousButtonHandler() {
this.month--;
if (this.month < 1) {
this.month = 12;
this.year--;
}
this.calculateCurrentDate();
}
nextButtonHandler() {
this.month++;
if (this.month > 12) {
this.month = 1;
this.year++;
}
this.calculateCurrentDate();
}
calculateCurrentDate() {
this.weeksOfMonth = this.dateAdapter.getWeeksOfMonth(this.year, this.month);
this.startOfMonth = this.dateAdapter.transformDate(this.year, this.month, 1);
const daysOfMonth = this.dateAdapter.getDaysOfMonth(this.year, this.month);
this.endOfMonth = this.dateAdapter.transformDate(this.year, this.month, daysOfMonth);
const month = this.monthsOfYear[this.month - 1];
this.title = this.commonService.getMonthName(month) || month + ' ' + this.year;
this.dateChangesHandler();
super.dateRangeChange({ startDate: this.startOfMonth, endDate: this.endOfMonth });
}
initViewHanlder() {
if (this.startOf == null) {
this.todayButtonHandler();
}
else {
this.month = this.dateAdapter.getMonthOf(this.startOf);
this.year = this.dateAdapter.getYearOf(this.startOf);
this.calculateCurrentDate();
}
}
eventChangesHandler(schedulerEvents) {
const tableEvents = [];
this.events = schedulerEvents;
const viewEvents = this.tools.scheduler.getEventsBetweenDateRange(this.startOfMonth, this.endOfMonth, this.events);
viewEvents.forEach((e) => {
const startRowIndex = this.rows.findIndex((r, i) => {
if (i == 0)
return;
return r.columns.map(c => (this.tools.dateTime.dateOnly(c.value))).includes(this.tools.dateTime.dateOnly(e.startDate));
});
const startColumnIndex = startRowIndex == -1 ? 0 : this.rows[startRowIndex].columns.findIndex(c => this.tools.dateTime.dateOnly(c.value) == this.tools.dateTime.dateOnly(e.startDate));
const endRowIndex = this.rows.findIndex((r, i) => {
if (i == 0)
return;
return r.columns.map(c => (this.tools.dateTime.dateOnly(c.value))).includes(this.tools.dateTime.dateOnly(e.endDate));
});
const endColumnIndex = endRowIndex == -1 ? this.rows[this.rows.length - 1].columns.length - 1 : this.rows[endRowIndex].columns.findIndex(c => this.tools.dateTime.dateOnly(c.value) == this.tools.dateTime.dateOnly(e.endDate));
const startTime = +this.tools.dateTime.hourOrDefault(e.startTime, '00');
const endTime = +this.tools.dateTime.hourOrDefault(e.endTime, '24');
const cellEvent = {
columnStart: startRowIndex != -1 ? startColumnIndex : null,
columnEnd: endRowIndex != -1 ? endColumnIndex : null,
data: e,
rowStart: startRowIndex != -1 ? startRowIndex : 0,
rowEnd: endRowIndex != -1 ? endRowIndex : this.rows.length - 1,
offsetX: startTime / 24,
fractionX: e.allDay == true ? 1 : (endTime / 24),
overlapTolerance: this.options.eventOverlapTolerance / 24
};
tableEvents.push(cellEvent);
});
this.eventBuilder.data = tableEvents;
}
dateChangesHandler() {
this.rows = this.getRowsInitialValue();
this.weeksOfMonth.forEach((week, weekIndex) => {
const row = {
verticalAlign: 'start',
horizontalAlign: 'start',
label: '',
classList: '',
prefix: '',
suffix: '',
value: week,
columns: []
};
this.daysOfWeek.forEach((day, dayIndex) => {
const date = this.dateAdapter.getDateOfDay(this.year, +week, dayIndex);
const splittedDate = date.split(this.dateSplitter);
const transformedDate = this.dateAdapter.transformDate(+splittedDate[0], +splittedDate[1], +splittedDate[2]);
row.columns.push({
classList: ''.concat(transformedDate.split('T')[0] == this.today && this.month == +splittedDate[1] ? ' today ' : ' ', this.weekends.includes(dayIndex) || this.holidays.includes(transformedDate.split('T')[0]) ? ' holiday ' : ' ', this.month != +splittedDate[1] ? ' unavailable ' : ' '),
label: splittedDate[2],
prefix: '',
suffix: '',
value: transformedDate.split('T')[0],
verticalAlign: 'start',
horizontalAlign: 'start',
selectable: true
});
});
this.rows.push(row);
});
}
weekendsChangesHandler(weekends) {
this.weekends = weekends;
this.dateChangesHandler();
}
holidaysChangesHandler(holidays) {
this.holidays = holidays;
this.dateChangesHandler();
}
onDateRangeSelect(startCell, endCell) {
const startDate = this.dateAdapter.getDateOfDay(this.year, +startCell.rowValue, +startCell.columnIndex).split(this.dateSplitter);
const transformedStart = this.dateAdapter.transformDate(+startDate[0], +startDate[1], +startDate[2]);
const endDate = this.dateAdapter.getDateOfDay(this.year, +endCell.rowValue, +endCell.columnIndex).split(this.dateSplitter);
const transformedEnd = this.dateAdapter.transformDate(+endDate[0], +endDate[1], +endDate[2]);
const e = {
endDate: transformedEnd,
endTime: '00:00',
startDate: transformedStart,
startTime: '00:00',
};
super.dateRangeSelect(e);
}
onEventClick(event, dom, jsEvent) {
const schedulerEvent = this.events.filter(item => item.id == event.data.id)[0];
super.eventClick({ dom: dom, event: schedulerEvent, jsEvent: jsEvent });
}
ngOnDestroy() {
super.destroy();
}
getRowsInitialValue() {
return [{
label: '',
prefix: '',
suffix: '',
verticalAlign: 'center',
horizontalAlign: 'center',
classList: '',
value: '',
columns: this.daysOfWeek.map((dayName, index) => {
const dIndex = this.commonService.getDayIndex(index);
return {
label: this.labels?.daysOfWeek[dIndex] || dayName,
prefix: '',
suffix: '',
verticalAlign: 'center',
horizontalAlign: 'center',
classList: this.weekends.includes(index) ? 'holiday' : '',
display: true,
value: index.toString(),
selectable: false,
};
}),
}];
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCMonthViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.0.7", type: ADCMonthViewComponent, selector: "adc-month-view", usesInheritance: true, ngImport: i0, template: " \r\n<adc-table\r\n[rows]=\"rows\"\r\n[title]=\"title\"\r\n[showRowDetails]=\"false\"\r\n[selectionManager]=\"selectionManager\"\r\n[eventBuilder]=\"eventBuilder\"\r\n(viewReady)=\"markViewAsReady()\"\r\n></adc-table>\r\n\r\n<!-- [eventBuilder]=\"builder\" -->\r\n\r\n<!-- [tableEvents]=\"tableEvents\" -->\r\n\r\n<!-- <div flatEventBuilder [columns]=\"columns.length\" [rows]=\"rows.length\" #builder=\"eventBuilder\"></div> -->\r\n\r\n\r\n\r\n", styles: ["table{border-collapse:collapse;table-layout:fixed}.w-full{width:100%}.h-full{height:100%}.table-border{border:1px solid #000}.relative{position:relative}.disabled{pointer-events:none;opacity:.5}.date{font-weight:500}.text-left{text-align:left}.vertical-text-top{vertical-align:text-top}.min-h-24{height:6rem}\n"], dependencies: [{ kind: "component", type: i1.ADCTableComponent, selector: "adc-table", inputs: ["rows", "showRowDetails", "title", "titleClass", "eventBuilder", "selectionManager"], outputs: ["viewReady"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCMonthViewComponent, decorators: [{
type: Component,
args: [{ selector: 'adc-month-view', template: " \r\n<adc-table\r\n[rows]=\"rows\"\r\n[title]=\"title\"\r\n[showRowDetails]=\"false\"\r\n[selectionManager]=\"selectionManager\"\r\n[eventBuilder]=\"eventBuilder\"\r\n(viewReady)=\"markViewAsReady()\"\r\n></adc-table>\r\n\r\n<!-- [eventBuilder]=\"builder\" -->\r\n\r\n<!-- [tableEvents]=\"tableEvents\" -->\r\n\r\n<!-- <div flatEventBuilder [columns]=\"columns.length\" [rows]=\"rows.length\" #builder=\"eventBuilder\"></div> -->\r\n\r\n\r\n\r\n", styles: ["table{border-collapse:collapse;table-layout:fixed}.w-full{width:100%}.h-full{height:100%}.table-border{border:1px solid #000}.relative{position:relative}.disabled{pointer-events:none;opacity:.5}.date{font-weight:500}.text-left{text-align:left}.vertical-text-top{vertical-align:text-top}.min-h-24{height:6rem}\n"] }]
}], ctorParameters: () => [] });
class ADCSchedulerModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerModule, declarations: [ADCDayViewComponent,
ADCWeekViewComponent,
ADCMonthViewComponent], imports: [CommonModule,
ADCTableComponent], exports: [ADCDayViewComponent,
ADCWeekViewComponent,
ADCMonthViewComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerModule, imports: [CommonModule,
ADCTableComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerModule, decorators: [{
type: NgModule,
args: [{
declarations: [
ADCDayViewComponent,
ADCWeekViewComponent,
ADCMonthViewComponent,
],
imports: [
CommonModule,
ADCTableComponent,
],
exports: [
ADCDayViewComponent,
ADCWeekViewComponent,
ADCMonthViewComponent
]
}]
}] });
const defaultViews = ['month', 'week', 'day'];
/**
* A component for rendering and managing a scheduler interface with different views (month, week, day).
* The component allows navigation between views, changing the displayed date, and adding custom views.
*
* ### Usage Example
* ```html
* <adc-scheduler
* [DefaultViews]="['month', 'week']"
* [CustomViews]="customViews"
* (ViewChange)="onViewChanged($event)"
* (Next)="onNextClicked()"
* (Previous)="onPreviousClicked()">
* </adc-scheduler>
* ```
*/
class ADCSchedulerComponent {
/**
* The default views to be shown in the scheduler (month, week, etc.).
* This input allows you to customize the views shown by default.
*
* @example
* <adc-scheduler [DefaultViews]="['month', 'week']"></adc-scheduler>
*/
set defaultViews(value) {
this._defaultViews = value;
this.onViewSet();
}
get defaultViews() {
return this._defaultViews;
}
/**
* Custom views that can be added to the scheduler. These views are added to the list of available views.
*
* @example
* <adc-scheduler [CustomViews]="customViews"></adc-scheduler>
*/
set customViews(value) {
this._customViews = value;
this.onViewSet();
}
get customViews() {
return this._customViews;
}
constructor(schedulerOptions, labels, dateChangeService) {
this.schedulerOptions = schedulerOptions;
this.labels = labels;
this.dateChangeService = dateChangeService;
this.currentView = this.schedulerOptions.initialView;
this.defaultViewComponents = [
{
id: 'month',
name: this.labels?.month || 'month',
component: ADCMonthViewComponent
},
{
id: 'week',
name: this.labels?.week || 'week',
component: ADCWeekViewComponent
},
{
id: 'day',
name: this.labels?.day || 'day',
component: ADCDayViewComponent
}
];
this.viewButtons = [];
this.schedulerViews = this.defaultViewComponents;
this._defaultViews = [];
this._customViews = [];
/**
* disables next button for scheduler component
*
* @example
* <adc-scheduler disableNext></adc-scheduler>
*/
this.disableNext = false;
/**
* disables previous button for scheduler component
*
* @example
* <adc-scheduler disablePrevious></adc-scheduler>
*/
this.disablePrevious = false;
/**
* disables today button for scheduler component
*
* @example
* <adc-scheduler disableToday></adc-scheduler>
*/
this.disableToday = false;
/**
* Event emitted when the current view changes.
*
* @event
* @example
* <adc-scheduler (ViewChange)="onViewChanged($event)"></adc-scheduler>
*/
this.onViewChangeEvent = new EventEmitter();
/**
* Event emitted when the "Next" button is clicked, indicating the user wants to move to the next date range.
*
* @event
* @example
* <adc-scheduler (Next)="onNextClicked()"></adc-scheduler>
*/
this.onNextEvent = new EventEmitter();
/**
* Event emitted when the "Previous" button is clicked, indicating the user wants to move to the previous date range.
*
* @event
* @example
* <adc-scheduler (Previous)="onPreviousClicked()"></adc-scheduler>
*/
this.onPreviousEvent = new EventEmitter();
this.defaultViews = defaultViews;
}
onToday() {
this.dateChangeService.today();
}
onViewChange(currentView) {
this.currentView = currentView;
this.onViewChangeEvent.emit(this.currentView);
}
onPrevious() {
this.dateChangeService.previous();
this.onPreviousEvent.emit();
}
oNext() {
this.dateChangeService.next();
this.onNextEvent.emit();
}
onViewSet() {
this.schedulerViews = this.defaultViewComponents.filter(v => this.defaultViews.includes(v.id)).concat(this.customViews);
this.viewButtons = this.schedulerViews.map(v => {
return {
id: v.id,
name: v.name,
};
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.0.7", ngImport: i0, type: ADCSchedulerComponent, deps: [{ token: ADC_OPTIONS }, { token: ADC_LABELS, optional: true }, { token: i1.DateChangeService }], target: i0.ɵɵFactoryTarge