UNPKG

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

879 lines (878 loc) 55.8 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Component, Input, NgZone, ViewChild, ViewChildren, QueryList, ElementRef, Renderer2, TemplateRef, ChangeDetectorRef } from '@angular/core'; import { IntlService, DatePipe } from '@progress/kendo-angular-intl'; import { LocalizationService } from '@progress/kendo-angular-l10n'; import { anyChanged, isChanged, ScrollbarWidthService } from '@progress/kendo-angular-common'; import { BehaviorSubject } from 'rxjs'; import { ViewContextService } from '../view-context.service'; import { ViewStateService } from '../view-state.service'; import { DayTimeSlotService } from '../day-time/day-time-slot.service'; import { createTasks, isMultiDay } from './utils'; import { DayTimeViewComponent } from '../day-time/day-time-view.component'; import { HintContainerComponent } from '../common/hint-container.component'; import { toPx, dateWithTime, elementOffset, toUTCTime, toUTCDate } from '../utils'; import { PDFService } from '../../pdf/pdf.service'; import { ResourceIteratorPipe } from '../common/resource-iterator.pipe'; import { ResizeHintComponent } from '../common/resize-hint.component'; import { FocusableDirective } from '../../navigation/focusable.directive'; import { DayTimeViewItemComponent } from '../day-time/day-time-view-item.component'; import { DaySlotDirective, TimeSlotDirective } from '../day-time/event-slot.directive'; import { NgClass, NgTemplateOutlet, NgStyle, AsyncPipe } from '@angular/common'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-l10n"; import * as i2 from "../view-context.service"; import * as i3 from "../view-state.service"; import * as i4 from "@progress/kendo-angular-intl"; import * as i5 from "../day-time/day-time-slot.service"; import * as i6 from "../../pdf/pdf.service"; import * as i7 from "@progress/kendo-angular-common"; /** * @hidden */ export class MultiDayViewRendererComponent extends DayTimeViewComponent { allDaySlot; name = 'day'; slotFill; allDaySlotTemplate; allDayEventTemplate; dayCells; headerHintContainer; dateFormat = { skeleton: 'MEd' }; allDayResizeHintFormat = { skeleton: 'Md' }; allDayItems = new BehaviorSubject(null); get allDaySlotTemplateRef() { return this.allDaySlotTemplate || (this.schedulerAllDaySlotTemplate || {}).templateRef; } get allDayEventTemplateRef() { return this.allDayEventTemplate || (this.schedulerAllDayEventTemplate || {}).templateRef; } get allDayMessage() { return this.localization.get('allDay'); } get allDayResizeHint() { return this.resizing && this.resizing.task.isAllDay; } get allDayDragHint() { return this.dragging && this.dragging.slot.isDaySlot; } schedulerAllDaySlotTemplate; schedulerAllDayEventTemplate; dragContainers; constructor(localization, viewContext, viewState, intl, slotService, zone, renderer, element, changeDetector, pdfService, scrollbarWidthService) { super(changeDetector, viewContext, viewState, intl, slotService, zone, renderer, element, pdfService, localization, scrollbarWidthService); } optionsChange(changes) { this.schedulerAllDaySlotTemplate = changes.allDaySlotTemplate; this.schedulerAllDayEventTemplate = changes.allDayEventTemplate; super.optionsChange(changes); } ngOnChanges(changes) { super.ngOnChanges(changes); if (changes.slotFill) { this.changes.next(null); } if (anyChanged(['startTime', 'endTime', 'showWorkHours', 'workDayStart', 'workDayEnd', 'workWeekStart', 'workWeekEnd', 'allDaySlot'], changes)) { this.viewRangeChange.next(null); } if (isChanged('numberOfDays', changes, true /* skipFirstChange */) || isChanged('weekStart', changes)) { this.daySlots = this.createDaySlots(); this.viewState.notifyDateRange(this.dateRange()); } } horizontalColspan(resourceIndex) { const resources = this.horizontalResources; let result = this.daySlots.length; for (let idx = resourceIndex + 1; idx < resources.length; idx++) { result *= (resources[idx].data || []).length || 1; } return result; } verticalRowspan(resourceIndex) { const resources = this.verticalResources; let result = this.timeSlots.length + 1; for (let idx = resourceIndex + 1; idx < resources.length; idx++) { result *= (resources[idx].data || []).length || 1; } return result; } allDaySlotClass(slot, resourceIndex) { if (this.slotClass) { return this.slotClass({ start: slot.start, end: slot.end, resources: this.resourcesByIndex(resourceIndex), isAllDay: true }); } } createTasks(items, dateRange) { const startTimeSlot = this.timeSlots[0]; const endTimeSlot = this.timeSlots[this.timeSlots.length - 1].end; const nextDateEnd = !(endTimeSlot.getHours() || endTimeSlot.getMinutes()); const ranges = this.daySlots.map(daySlot => ({ start: toUTCTime(daySlot.start, startTimeSlot.start), end: nextDateEnd ? toUTCDate(daySlot.end) : toUTCTime(daySlot.start, endTimeSlot) })); return createTasks(dateRange.start, dateRange.end, items, ranges); } onTasksChange() { this.items.next(this.tasks.filter(task => !task.isAllDay)); this.allDayItems.next(this.tasks.filter(task => task.isAllDay)); } reflow() { const slotService = this.slotService; if (!this.verticalResources.length) { this.updateContentHeight(); this.syncTables(); } this.slotService.containerSize = this.content.nativeElement.clientWidth; slotService.layoutDays(this.eventHeight); this.updateContentHeight(); this.syncTables(); if (this.dayCells.length) { const cells = this.dayCells.toArray(); if (this.verticalResources.length) { slotService.forEachDateRange((range, index) => { const slot = range.firstSlot; cells[index].nativeElement.style.height = `${slot.rect.height - slot.padding}px`; }); } else { const size = slotService.syncDateRanges(); cells[0].nativeElement.style.height = `${size}px`; } } slotService.layoutTimes({ fill: this.slotFill }); this.syncTables(); } dragHorizontal(slot) { return slot.isDaySlot; } updateHintContainer() { if (this.headerHintContainer) { this.headerHintContainer.detectChanges(); } super.updateHintContainer(); } onRelease(args) { super.onRelease(args); this.dragContainers = null; } updateDragContainer(args) { if (!this.dragContainers) { this.dragContainers = this.containers; } const container = this.dragContainers.find(c => { const offset = c.offset; return offset.top <= args.pageY && args.pageY <= offset.top + offset.height; }) || {}; this.container = container.element; this.containerOffset = container.offset; } containerByPosition({ x, y }) { return this.containers.find(c => { const offset = c.offset; return offset.top <= y && y <= offset.top + offset.height && offset.left <= x && x <= offset.left + offset.width; }); } get containers() { const header = this.headerWrap.nativeElement.children[1]; const content = this.content.nativeElement; return [{ element: content, offset: elementOffset(content) }, { element: header, offset: elementOffset(header) }]; } scrollContainer(callback, args) { clearInterval(this.scrollInterval); if (this.container && this.container === this.content.nativeElement) { super.scrollContainer(callback, args); } } dragRanges(slot) { const task = this.dragging.task; if (slot.isDaySlot && !task.isAllDay) { return { ranges: [[slot]], start: dateWithTime(slot.start, task.start.toUTCDate()), end: dateWithTime(slot.start, task.end.toUTCDate()), isAllDay: true }; } const allDayToTime = task.isAllDay && !slot.isDaySlot; const result = this.slotService.dragRanges(slot, allDayToTime ? { start: 0, end: 0 } : this.dragging.offset); if (allDayToTime) { result.end = slot.end; } result.isAllDay = this.draggedIsAllDay(task, slot); return result; } dragHintEventStyleArgs() { return { event: this.dragging.task.event, resources: this.dragging.resourceItems, isAllDay: Boolean(this.allDayDragHint) }; } draggedIsAllDay(task, slot) { return Boolean(slot.isDaySlot && (task.event.isAllDay || !isMultiDay(task))); } dragHintSize(firstSlot, lastSlot) { let width, height; if (firstSlot.isDaySlot) { width = toPx(lastSlot.rect.left - firstSlot.rect.left + lastSlot.rect.width); height = toPx(firstSlot.height); } else { width = toPx(firstSlot.rect.width * 0.9); height = toPx(this.dragging.task.isAllDay ? firstSlot.rect.height : lastSlot.rect.top - firstSlot.rect.top + lastSlot.rect.height); } return { width, height }; } currentTimeArrowOffset() { if (this.verticalResources.length) { const el = this.times.nativeElement.querySelector('.k-scheduler-times-all-day'); const timesEl = this.times.nativeElement; return this.localization.rtl ? timesEl.offsetWidth - el.offsetWidth : el.offsetLeft; } return 0; } isMiddleSlot(index) { return index + 1 < this.timeSlots.length && !this.timeSlots[index + 1].isMajor; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MultiDayViewRendererComponent, deps: [{ token: i1.LocalizationService }, { token: i2.ViewContextService }, { token: i3.ViewStateService }, { token: i4.IntlService }, { token: i5.DayTimeSlotService }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: i6.PDFService }, { token: i7.ScrollbarWidthService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: MultiDayViewRendererComponent, isStandalone: true, selector: "multi-day-view", inputs: { allDaySlot: "allDaySlot", name: "name", slotFill: "slotFill", allDaySlotTemplate: "allDaySlotTemplate", allDayEventTemplate: "allDayEventTemplate" }, providers: [ DayTimeSlotService ], viewQueries: [{ propertyName: "headerHintContainer", first: true, predicate: ["headerHintContainer"], descendants: true }, { propertyName: "dayCells", predicate: ["allDayCell"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: ` <table class="k-scheduler-layout" role="presentation" [ngClass]="classNames"> <tbody> <tr class="k-scheduler-head"> <td> <div class="k-scheduler-times" #timesHeader> <table class="k-scheduler-table" aria-hidden="true"> <tbody> @for (resource of horizontalResources; track itemIndex($index, resource)) { <tr> <th class="k-scheduler-cell k-heading-cell"></th> </tr> } <tr [style.height]="'auto'"> <th class="k-scheduler-cell k-heading-cell"></th> </tr> @if (allDaySlot && !verticalResources.length) { <tr> <th class="k-scheduler-times-all-day k-scheduler-cell k-heading-cell" #allDayCell>{{ allDayMessage }}</th> </tr> } </tbody> </table> </div> </td> <td> <div class="k-scheduler-header" #header> <div class="k-scheduler-header-wrap" #headerWrap> <table class="k-scheduler-table" aria-hidden="true"> <tbody> @for (resource of horizontalResources; track itemIndex(resourceIndex, resource); let resourceIndex = $index) { <tr> @for (item of horizontalResources | resourceIterator : resourceIndex; track itemIndex($index, item)) { <th class="k-scheduler-cell k-heading-cell" [attr.colspan]="horizontalColspan(resourceIndex)"> @if (!groupHeaderTemplateRef) { {{ getField(item, resource.textField) }} } @if (groupHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="groupHeaderTemplateRef" [ngTemplateOutletContext]="{ resource: item }"></ng-container> } </th> } </tr> } <tr class="k-scheduler-date-group"> @for (resource of horizontalResources | resourceIterator; track itemIndex($index, resource)) { @for (slot of daySlots; track itemIndex(index, slot); let index = $index) { <th class="k-scheduler-cell k-heading-cell"> @if (!dateHeaderTemplateRef) { <span class="k-link k-nav-day" [attr.data-dayslot-index]="index">{{ slot.start | kendoDate: dateFormat }}</span> } @if (dateHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="dateHeaderTemplateRef" [ngTemplateOutletContext]="{ date: slot.start }"></ng-container> } </th> } } </tr> </tbody> </table> @if (allDaySlot && !verticalResources.length) { <div [style.position]="'relative'"> <table class="k-scheduler-table k-scheduler-header-all-day" aria-hidden="true"> <tbody> <tr> @for (resource of horizontalResources | resourceIterator; track itemIndex(resourceIndex, resource); let resourceIndex = $index) { @for (slot of daySlots; track itemIndex(index, slot); let index = $index) { <td daySlot [start]="slot.start" [end]="slot.end" [id]="{ resourceIndex: resourceIndex, rangeIndex: 0, index: index }" [class.k-selected]="isSlotSelected({ start: toPlainDate(slot.start), end: toPlainDate(slot.end), isAllDay: true, resources: resourcesByIndex(resourceIndex) })" [ngClass]="allDaySlotClass(slot, resourceIndex)" class="k-scheduler-cell"> @if (allDaySlotTemplateRef) { <ng-container [ngTemplateOutlet]="allDaySlotTemplateRef" [ngTemplateOutletContext]="{ date: slot.start, resources: resourcesByIndex(resourceIndex) }"></ng-container> } </td> } } </tr> </tbody> </table> @for (item of allDayItems | async; track itemIndex($index, item)) { @for (itemResource of item.resources; track itemIndex($index, itemResource)) { <div [ngClass]="getEventClasses(item, itemResource.resources, true)" [ngStyle]="getEventStyles(item, itemResource, true)" role="button" [kendoSchedulerFocusIndex]="itemResource.leafIdx" [id]="item.elementId + '_' + itemResource.leafIdx" dayTimeViewItem [name]="name" [isAllDay]="true" [editable]="editable" [eventTemplate]="allDayEventTemplateRef" [item]="item" [index]="item.index" [rangeIndex]="item.rangeIndex" [resources]="itemResource.resources" [resourceIndex]="itemResource.leafIdx"> </div> } } <kendo-hint-container #headerHintContainer> <ng-template> @if (dragHints.length && allDayDragHint) { <div class="k-event-drag-hint" dayTimeViewItem [isAllDay]="true" [ngStyle]="dragHints[0].style" [ngClass]="dragHints[0].class" [dragHint]="true" [eventTemplate]="eventTemplateRef" [item]="dragHints[0].item" [resources]="dragHints[0].resources"> </div> } @if (resizeHints.length && allDayResizeHint) { <div kendoResizeHint [hint]="resizeHints[0]" [ngClass]="resizeHints[0].class" [format]="allDayResizeHintFormat"> </div> } </ng-template> </kendo-hint-container> </div> } </div> </div> </td> </tr> <tr class="k-scheduler-body"> <td> <div class="k-scheduler-times" #times> @if (showCurrentTime) { @for (resource of verticalResources | resourceIterator; track itemIndex($index, resource)) { <div #currentTimeArrow class="k-current-time k-current-time-arrow-right"> </div> } } <table class="k-scheduler-table" #timesTable aria-hidden="true"> <tbody> @for (resourceItem of verticalResources | resourceIterator; track itemIndex(leafIndex, resourceItem); let leafIndex = $index) { @if (verticalResources.length) { <tr> @for (resource of verticalResources; track itemIndex(resourceIndex, resource); let resourceIndex = $index) { @if (verticalItem(leafIndex, resourceIndex)) { <th [attr.rowspan]="verticalRowspan(resourceIndex)" class="k-scheduler-cell k-slot-cell k-heading-cell"> @if (!groupHeaderTemplateRef) { {{ getField(verticalItem(leafIndex, resourceIndex), resource.textField) }} } @if (groupHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="groupHeaderTemplateRef" [ngTemplateOutletContext]="{ resource: verticalItem(leafIndex, resourceIndex) }"></ng-container> } </th> } } @if (allDaySlot) { <th class="k-scheduler-times-all-day k-scheduler-cell k-heading-cell" #allDayCell>{{ allDayMessage }}</th> } </tr> } @for (slot of timeSlots; track itemIndex(timeSlotIndex, slot); let timeSlotIndex = $index) { <tr> @if (slot.isMajor) { <th [ngClass]="{ 'k-slot-cell': slotDivisions === 1 }" class="k-scheduler-cell k-heading-cell"> @if (!majorTimeHeaderTemplateRef) { {{ slot.start | kendoDate: 't' }} } @if (majorTimeHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="majorTimeHeaderTemplateRef" [ngTemplateOutletContext]="{ date: slot.start }"></ng-container> } </th> } @if (!slot.isMajor) { <th [ngClass]="{ 'k-slot-cell': timeSlotIndex % slotDivisions === slotDivisions - 1 }" class="k-scheduler-cell k-heading-cell"> @if (minorTimeHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="minorTimeHeaderTemplateRef" [ngTemplateOutletContext]="{ date: slot.start }"> </ng-container> } </th> } </tr> } } </tbody> </table> </div> </td> <td> <div class="k-scheduler-content" #content role="group" tabindex="0" [attr.aria-owns]="matchOwned(items | async)"> @if (showCurrentTime) { @for (resource of verticalResources | resourceIterator; track itemIndex($index, resource)) { <div #currentTimeMarker class="k-current-time"> </div> } } <table class="k-scheduler-table" #contentTable role="presentation"> <tbody> @for (resourceItem of verticalResources | resourceIterator; track itemIndex(verticalIndex, resourceItem); let verticalIndex = $index) { @if (allDaySlot && verticalResources.length) { <tr class="k-scheduler-header-all-day"> @for (slot of daySlots; track itemIndex(index, slot); let index = $index) { <td daySlot [start]="slot.start" [end]="slot.end" [class.k-selected]="isSlotSelected({ start: toPlainDate(slot.start), end: toPlainDate(slot.end), isAllDay: true, resources: resourcesByIndex(verticalIndex) })" [id]="{ resourceIndex: verticalIndex, rangeIndex: 0, index: index }"> @if (allDaySlotTemplateRef) { <ng-container [ngTemplateOutlet]="allDaySlotTemplateRef" [ngTemplateOutletContext]="{ date: slot.start, resources: resourcesByIndex(verticalIndex) }"></ng-container> } </td> } </tr> } @for (slot of timeSlots; track itemIndex(index, slot); let index = $index) { <tr [class.k-middle-row]="isMiddleSlot(index)"> @for (resource of horizontalResources | resourceIterator; track itemIndex(horizontalIndex, resource); let horizontalIndex = $index) { @for (daySlot of daySlots; track itemIndex(rangeIndex, daySlot); let rangeIndex = $index) { <td [ngClass]="timeSlotClass(slot, daySlot.start, verticalResources.length ? verticalIndex : horizontalIndex)" timeSlot #timeSlot="timeSlot" [date]="daySlot.start" [invariantStart]="slot.start" [invariantEnd]="slot.end" [workDayStart]="workDayStartTime" [workDayEnd]="workDayEndTime" [workWeekStart]="workWeekStart" [workWeekEnd]="workWeekEnd" [id]="{ resourceIndex: verticalResources.length ? verticalIndex : horizontalIndex, rangeIndex: rangeIndex, index: index }" [class.k-selected]="isSlotSelected({ start: toPlainDateTime(daySlot.start, slot.start), end: toPlainDateTime(daySlot.start, slot.end), isAllDay: false, resources: resourcesByIndex(verticalResources.length ? verticalIndex : horizontalIndex) })" class="k-scheduler-cell" > @if (timeSlotTemplateRef) { <ng-container [ngTemplateOutlet]="timeSlotTemplateRef" [ngTemplateOutletContext]="{ date: timeSlot.startLocalTime, resources: resourcesByIndex(timeSlot.id.resourceIndex) }"> </ng-container> } </td> } } </tr> } } </tbody> </table> @for (item of items | async; track itemIndex($index, item)) { @for (itemResource of item.resources; track itemIndex($index, itemResource)) { <div [ngClass]="getEventClasses(item, itemResource.resources)" [ngStyle]="getEventStyles(item, itemResource)" role="button" [kendoSchedulerFocusIndex]="itemResource.leafIdx" [id]="item.elementId + '_' + itemResource.leafIdx" dayTimeViewItem [editable]="editable" [vertical]="true" [eventTemplate]="eventTemplateRef" [item]="item" [index]="item.index" [rangeIndex]="item.rangeIndex" [resources]="itemResource.resources" [resourceIndex]="itemResource.leafIdx"> </div> } } @if (verticalResources.length) { @for (item of allDayItems | async; track itemIndex($index, item)) { @for (itemResource of item.resources; track itemIndex($index, itemResource)) { <div [ngClass]="getEventClasses(item, itemResource.resources, true)" [ngStyle]="getEventStyles(item, itemResource, true)" role="button" [kendoSchedulerFocusIndex]="itemResource.leafIdx" [id]="item.elementId + '_' + itemResource.leafIdx" dayTimeViewItem [isAllDay]="true" [editable]="editable" [eventTemplate]="allDayEventTemplateRef" [item]="item" [index]="item.index" [rangeIndex]="item.rangeIndex" [resources]="itemResource.resources" [resourceIndex]="itemResource.leafIdx"> </div> } } } <kendo-hint-container #hintContainer> <ng-template> @if (dragHints.length && (!allDayDragHint || verticalResources.length)) { <div class="k-event-drag-hint" role="button" dayTimeViewItem [isAllDay]="allDayDragHint" [ngStyle]="dragHints[0].style" [ngClass]="dragHints[0].class" [dragHint]="true" [eventTemplate]="eventTemplateRef" [resources]="dragHints[0].resources" [item]="dragHints[0].item"> </div> } @if (resizeHints.length && (!allDayResizeHint || verticalResources.length)) { @for (hint of resizeHints; track itemIndex($index, hint)) { <div kendoResizeHint [hint]="hint" [ngClass]="hint.class" [format]="allDayResizeHint ? allDayResizeHintFormat : resizeHintFormat"> </div> } } </ng-template> </kendo-hint-container> </div> </td> </tr> </tbody> </table> `, isInline: true, dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: DaySlotDirective, selector: "[daySlot]", inputs: ["start", "end"] }, { kind: "component", type: DayTimeViewItemComponent, selector: "[dayTimeViewItem]", inputs: ["vertical", "isAllDay", "name"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: FocusableDirective, selector: "[kendoSchedulerFocusIndex]", inputs: ["kendoSchedulerFocusIndex", "containerType"] }, { kind: "component", type: HintContainerComponent, selector: "kendo-hint-container" }, { kind: "component", type: ResizeHintComponent, selector: "[kendoResizeHint]", inputs: ["hint", "format"] }, { kind: "directive", type: TimeSlotDirective, selector: "[timeSlot]", inputs: ["invariantStart", "invariantEnd", "workDayStart", "workDayEnd", "workWeekStart", "workWeekEnd", "date"], exportAs: ["timeSlot"] }, { kind: "pipe", type: ResourceIteratorPipe, name: "resourceIterator" }, { kind: "pipe", type: DatePipe, name: "kendoDate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: MultiDayViewRendererComponent, decorators: [{ type: Component, args: [{ // eslint-disable-next-line @angular-eslint/component-selector selector: 'multi-day-view', providers: [ DayTimeSlotService ], template: ` <table class="k-scheduler-layout" role="presentation" [ngClass]="classNames"> <tbody> <tr class="k-scheduler-head"> <td> <div class="k-scheduler-times" #timesHeader> <table class="k-scheduler-table" aria-hidden="true"> <tbody> @for (resource of horizontalResources; track itemIndex($index, resource)) { <tr> <th class="k-scheduler-cell k-heading-cell"></th> </tr> } <tr [style.height]="'auto'"> <th class="k-scheduler-cell k-heading-cell"></th> </tr> @if (allDaySlot && !verticalResources.length) { <tr> <th class="k-scheduler-times-all-day k-scheduler-cell k-heading-cell" #allDayCell>{{ allDayMessage }}</th> </tr> } </tbody> </table> </div> </td> <td> <div class="k-scheduler-header" #header> <div class="k-scheduler-header-wrap" #headerWrap> <table class="k-scheduler-table" aria-hidden="true"> <tbody> @for (resource of horizontalResources; track itemIndex(resourceIndex, resource); let resourceIndex = $index) { <tr> @for (item of horizontalResources | resourceIterator : resourceIndex; track itemIndex($index, item)) { <th class="k-scheduler-cell k-heading-cell" [attr.colspan]="horizontalColspan(resourceIndex)"> @if (!groupHeaderTemplateRef) { {{ getField(item, resource.textField) }} } @if (groupHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="groupHeaderTemplateRef" [ngTemplateOutletContext]="{ resource: item }"></ng-container> } </th> } </tr> } <tr class="k-scheduler-date-group"> @for (resource of horizontalResources | resourceIterator; track itemIndex($index, resource)) { @for (slot of daySlots; track itemIndex(index, slot); let index = $index) { <th class="k-scheduler-cell k-heading-cell"> @if (!dateHeaderTemplateRef) { <span class="k-link k-nav-day" [attr.data-dayslot-index]="index">{{ slot.start | kendoDate: dateFormat }}</span> } @if (dateHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="dateHeaderTemplateRef" [ngTemplateOutletContext]="{ date: slot.start }"></ng-container> } </th> } } </tr> </tbody> </table> @if (allDaySlot && !verticalResources.length) { <div [style.position]="'relative'"> <table class="k-scheduler-table k-scheduler-header-all-day" aria-hidden="true"> <tbody> <tr> @for (resource of horizontalResources | resourceIterator; track itemIndex(resourceIndex, resource); let resourceIndex = $index) { @for (slot of daySlots; track itemIndex(index, slot); let index = $index) { <td daySlot [start]="slot.start" [end]="slot.end" [id]="{ resourceIndex: resourceIndex, rangeIndex: 0, index: index }" [class.k-selected]="isSlotSelected({ start: toPlainDate(slot.start), end: toPlainDate(slot.end), isAllDay: true, resources: resourcesByIndex(resourceIndex) })" [ngClass]="allDaySlotClass(slot, resourceIndex)" class="k-scheduler-cell"> @if (allDaySlotTemplateRef) { <ng-container [ngTemplateOutlet]="allDaySlotTemplateRef" [ngTemplateOutletContext]="{ date: slot.start, resources: resourcesByIndex(resourceIndex) }"></ng-container> } </td> } } </tr> </tbody> </table> @for (item of allDayItems | async; track itemIndex($index, item)) { @for (itemResource of item.resources; track itemIndex($index, itemResource)) { <div [ngClass]="getEventClasses(item, itemResource.resources, true)" [ngStyle]="getEventStyles(item, itemResource, true)" role="button" [kendoSchedulerFocusIndex]="itemResource.leafIdx" [id]="item.elementId + '_' + itemResource.leafIdx" dayTimeViewItem [name]="name" [isAllDay]="true" [editable]="editable" [eventTemplate]="allDayEventTemplateRef" [item]="item" [index]="item.index" [rangeIndex]="item.rangeIndex" [resources]="itemResource.resources" [resourceIndex]="itemResource.leafIdx"> </div> } } <kendo-hint-container #headerHintContainer> <ng-template> @if (dragHints.length && allDayDragHint) { <div class="k-event-drag-hint" dayTimeViewItem [isAllDay]="true" [ngStyle]="dragHints[0].style" [ngClass]="dragHints[0].class" [dragHint]="true" [eventTemplate]="eventTemplateRef" [item]="dragHints[0].item" [resources]="dragHints[0].resources"> </div> } @if (resizeHints.length && allDayResizeHint) { <div kendoResizeHint [hint]="resizeHints[0]" [ngClass]="resizeHints[0].class" [format]="allDayResizeHintFormat"> </div> } </ng-template> </kendo-hint-container> </div> } </div> </div> </td> </tr> <tr class="k-scheduler-body"> <td> <div class="k-scheduler-times" #times> @if (showCurrentTime) { @for (resource of verticalResources | resourceIterator; track itemIndex($index, resource)) { <div #currentTimeArrow class="k-current-time k-current-time-arrow-right"> </div> } } <table class="k-scheduler-table" #timesTable aria-hidden="true"> <tbody> @for (resourceItem of verticalResources | resourceIterator; track itemIndex(leafIndex, resourceItem); let leafIndex = $index) { @if (verticalResources.length) { <tr> @for (resource of verticalResources; track itemIndex(resourceIndex, resource); let resourceIndex = $index) { @if (verticalItem(leafIndex, resourceIndex)) { <th [attr.rowspan]="verticalRowspan(resourceIndex)" class="k-scheduler-cell k-slot-cell k-heading-cell"> @if (!groupHeaderTemplateRef) { {{ getField(verticalItem(leafIndex, resourceIndex), resource.textField) }} } @if (groupHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="groupHeaderTemplateRef" [ngTemplateOutletContext]="{ resource: verticalItem(leafIndex, resourceIndex) }"></ng-container> } </th> } } @if (allDaySlot) { <th class="k-scheduler-times-all-day k-scheduler-cell k-heading-cell" #allDayCell>{{ allDayMessage }}</th> } </tr> } @for (slot of timeSlots; track itemIndex(timeSlotIndex, slot); let timeSlotIndex = $index) { <tr> @if (slot.isMajor) { <th [ngClass]="{ 'k-slot-cell': slotDivisions === 1 }" class="k-scheduler-cell k-heading-cell"> @if (!majorTimeHeaderTemplateRef) { {{ slot.start | kendoDate: 't' }} } @if (majorTimeHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="majorTimeHeaderTemplateRef" [ngTemplateOutletContext]="{ date: slot.start }"></ng-container> } </th> } @if (!slot.isMajor) { <th [ngClass]="{ 'k-slot-cell': timeSlotIndex % slotDivisions === slotDivisions - 1 }" class="k-scheduler-cell k-heading-cell"> @if (minorTimeHeaderTemplateRef) { <ng-container [ngTemplateOutlet]="minorTimeHeaderTemplateRef" [ngTemplateOutletContext]="{ date: slot.start }"> </ng-container> } </th> } </tr> } } </tbody> </table> </div> </td> <td> <div class="k-scheduler-content" #content role="group" tabindex="0" [attr.aria-owns]="matchOwned(items | async)"> @if (showCurrentTime) { @for (resource of verticalResources | resourceIterator; track itemIndex($index, resource)) { <div #currentTimeMarker class="k-current-time"> </div> } } <table class="k-scheduler-table" #contentTable role="presentation"> <tbody> @for (resourceItem of verticalResources | resourceIterator; track itemIndex(verticalIndex, resourceItem); let verticalIndex = $index) { @if (allDaySlot && verticalResources.length) { <tr class="k-scheduler-header-all-day"> @for (slot of daySlots; track itemIndex(index, slot); let index = $index) { <td daySlot [start]="slot.start" [end]="slot.end" [class.k-selected]="isSlotSelected({ start: toPlainDate(slot.start), end: toPlainDate(slot.end), isAllDay: true, resources: resourcesByIndex(verticalIndex) })" [id]="{ resourceIndex: verticalIndex, rangeIndex: 0, index: index }"> @if (allDaySlotTemplateRef) { <ng-container [ngTemplateOutlet]="allDaySlotTemplateRef" [ngTemplateOutletContext]="{ date: slot.start, resources: resourcesByIndex(verticalIndex) }"></ng-container> } </td> } </tr> } @for (slot of timeSlots; track itemIndex(index, slot); let index = $index) { <tr [class.k-middle-row]="isMiddleSlot(index)"> @for (resource of horizontalResources | resourceIterator; track itemIndex(horizontalIndex, resource); let horizontalIndex = $index) { @for (daySlot of daySlots; track itemIndex(rangeIndex, daySlot); let rangeIndex = $index) { <td [ngClass]="timeSlotClass(slot, daySlot.start, verticalResources.length ? verticalIndex : horizontalIndex)" timeSlot #timeSlot="timeSlot" [date]="daySlot.start" [invariantStart]="slot.start" [invariantEnd]="slot.end" [workDayStart]="workDayStartTime" [workDayEnd]="workDayEndTime" [workWeekStart]="workWeekStart" [workWeekEnd]="workWeekEnd" [id]="{ resourceIndex: verticalResources.length ? verticalIndex : horizontalIndex, rangeIndex: rangeIndex, index: index }" [class.k-selected]="isSlotSelected({ start: toPlainDateTime(daySlot.start, slot.start), end: toPlainDateTime(daySlot.start, slot.end), isAllDay: false, resources: resourcesByIndex(verticalResources.length ? verticalInd