UNPKG

@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
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