UNPKG

angular-calendar

Version:

A calendar component for angular 15.0+ that can display events on a month, week or day view

1,179 lines (1,178 loc) 147 kB
import { Component, Input, Output, EventEmitter, LOCALE_ID, Inject, } from '@angular/core'; import { CalendarDragHelper } from '../../common/calendar-drag-helper/calendar-drag-helper.provider'; import { CalendarResizeHelper } from '../../common/calendar-resize-helper/calendar-resize-helper.provider'; import { CalendarEventTimesChangedEventType, } from '../../common/calendar-event-times-changed-event/calendar-event-times-changed-event.interface'; import { validateEvents, roundToNearest, trackByWeekDayHeaderDate, trackByHourSegment, trackByHour, getMinutesMoved, getDefaultEventEnd, addDaysWithExclusions, isDraggedWithinPeriod, shouldFireDroppedEvent, getWeekViewPeriod, trackByWeekAllDayEvent, trackByWeekTimeEvent, } from '../../common/util/util'; import * as i0 from "@angular/core"; import * as i1 from "../../common/calendar-utils/calendar-utils.provider"; import * as i2 from "../../../date-adapters/date-adapter"; import * as i3 from "@angular/common"; import * as i4 from "angular-resizable-element"; import * as i5 from "angular-draggable-droppable"; import * as i6 from "../../common/click/click.directive"; import * as i7 from "./calendar-week-view-header/calendar-week-view-header.component"; import * as i8 from "./calendar-week-view-event/calendar-week-view-event.component"; import * as i9 from "./calendar-week-view-hour-segment/calendar-week-view-hour-segment.component"; import * as i10 from "./calendar-week-view-current-time-marker/calendar-week-view-current-time-marker.component"; /** * Shows all events on a given week. Example usage: * * ```typescript * <mwl-calendar-week-view * [viewDate]="viewDate" * [events]="events"> * </mwl-calendar-week-view> * ``` */ export class CalendarWeekViewComponent { /** * @hidden */ constructor(cdr, utils, locale, dateAdapter, element) { this.cdr = cdr; this.utils = utils; this.dateAdapter = dateAdapter; this.element = element; /** * An array of events to display on view * The schema is available here: https://github.com/mattlewis92/calendar-utils/blob/c51689985f59a271940e30bc4e2c4e1fee3fcb5c/src/calendarUtils.ts#L49-L63 */ this.events = []; /** * An array of day indexes (0 = sunday, 1 = monday etc) that will be hidden on the view */ this.excludeDays = []; /** * The placement of the event tooltip */ this.tooltipPlacement = 'auto'; /** * Whether to append tooltips to the body or next to the trigger element */ this.tooltipAppendToBody = true; /** * The delay in milliseconds before the tooltip should be displayed. If not provided the tooltip * will be displayed immediately. */ this.tooltipDelay = null; /** * The precision to display events. * `days` will round event start and end dates to the nearest day and `minutes` will not do this rounding */ this.precision = 'days'; /** * Whether to snap events to a grid when dragging */ this.snapDraggedEvents = true; /** * The number of segments in an hour. Must divide equally into 60. */ this.hourSegments = 2; /** * The height in pixels of each hour segment */ this.hourSegmentHeight = 30; /** * The minimum height in pixels of each event */ this.minimumEventHeight = 30; /** * The day start hours in 24 hour time. Must be 0-23 */ this.dayStartHour = 0; /** * The day start minutes. Must be 0-59 */ this.dayStartMinute = 0; /** * The day end hours in 24 hour time. Must be 0-23 */ this.dayEndHour = 23; /** * The day end minutes. Must be 0-59 */ this.dayEndMinute = 59; /** * Called when a header week day is clicked. Adding a `cssClass` property on `$event.day` will add that class to the header element */ this.dayHeaderClicked = new EventEmitter(); /** * Called when an event title is clicked */ this.eventClicked = new EventEmitter(); /** * Called when an event is resized or dragged and dropped */ this.eventTimesChanged = new EventEmitter(); /** * An output that will be called before the view is rendered for the current week. * If you add the `cssClass` property to a day in the header it will add that class to the cell element in the template */ this.beforeViewRender = new EventEmitter(); /** * Called when an hour segment is clicked */ this.hourSegmentClicked = new EventEmitter(); /** * @hidden */ this.allDayEventResizes = new Map(); /** * @hidden */ this.timeEventResizes = new Map(); /** * @hidden */ this.eventDragEnterByType = { allDay: 0, time: 0, }; /** * @hidden */ this.dragActive = false; /** * @hidden */ this.dragAlreadyMoved = false; /** * @hidden */ this.calendarId = Symbol('angular calendar week view id'); /** * @hidden */ this.rtl = false; /** * @hidden */ this.trackByWeekDayHeaderDate = trackByWeekDayHeaderDate; /** * @hidden */ this.trackByHourSegment = trackByHourSegment; /** * @hidden */ this.trackByHour = trackByHour; /** * @hidden */ this.trackByWeekAllDayEvent = trackByWeekAllDayEvent; /** * @hidden */ this.trackByWeekTimeEvent = trackByWeekTimeEvent; /** * @hidden */ this.trackByHourColumn = (index, column) => column.hours[0] ? column.hours[0].segments[0].date.toISOString() : column; /** * @hidden */ this.trackById = (index, row) => row.id; this.locale = locale; } /** * @hidden */ ngOnInit() { if (this.refresh) { this.refreshSubscription = this.refresh.subscribe(() => { this.refreshAll(); this.cdr.markForCheck(); }); } } /** * @hidden */ ngOnChanges(changes) { const refreshHeader = changes.viewDate || changes.excludeDays || changes.weekendDays || changes.daysInWeek || changes.weekStartsOn; const refreshBody = changes.viewDate || changes.dayStartHour || changes.dayStartMinute || changes.dayEndHour || changes.dayEndMinute || changes.hourSegments || changes.hourDuration || changes.weekStartsOn || changes.weekendDays || changes.excludeDays || changes.hourSegmentHeight || changes.events || changes.daysInWeek || changes.minimumEventHeight; if (refreshHeader) { this.refreshHeader(); } if (changes.events) { validateEvents(this.events); } if (refreshBody) { this.refreshBody(); } if (refreshHeader || refreshBody) { this.emitBeforeViewRender(); } } /** * @hidden */ ngOnDestroy() { if (this.refreshSubscription) { this.refreshSubscription.unsubscribe(); } } /** * @hidden */ ngAfterViewInit() { this.rtl = typeof window !== 'undefined' && getComputedStyle(this.element.nativeElement).direction === 'rtl'; this.cdr.detectChanges(); } /** * @hidden */ timeEventResizeStarted(eventsContainer, timeEvent, resizeEvent) { this.timeEventResizes.set(timeEvent.event, resizeEvent); this.resizeStarted(eventsContainer, timeEvent); } /** * @hidden */ timeEventResizing(timeEvent, resizeEvent) { this.timeEventResizes.set(timeEvent.event, resizeEvent); const adjustedEvents = new Map(); const tempEvents = [...this.events]; this.timeEventResizes.forEach((lastResizeEvent, event) => { const newEventDates = this.getTimeEventResizedDates(event, lastResizeEvent); const adjustedEvent = { ...event, ...newEventDates }; adjustedEvents.set(adjustedEvent, event); const eventIndex = tempEvents.indexOf(event); tempEvents[eventIndex] = adjustedEvent; }); this.restoreOriginalEvents(tempEvents, adjustedEvents, true); } /** * @hidden */ timeEventResizeEnded(timeEvent) { this.view = this.getWeekView(this.events); const lastResizeEvent = this.timeEventResizes.get(timeEvent.event); if (lastResizeEvent) { this.timeEventResizes.delete(timeEvent.event); const newEventDates = this.getTimeEventResizedDates(timeEvent.event, lastResizeEvent); this.eventTimesChanged.emit({ newStart: newEventDates.start, newEnd: newEventDates.end, event: timeEvent.event, type: CalendarEventTimesChangedEventType.Resize, }); } } /** * @hidden */ allDayEventResizeStarted(allDayEventsContainer, allDayEvent, resizeEvent) { this.allDayEventResizes.set(allDayEvent, { originalOffset: allDayEvent.offset, originalSpan: allDayEvent.span, edge: typeof resizeEvent.edges.left !== 'undefined' ? 'left' : 'right', }); this.resizeStarted(allDayEventsContainer, allDayEvent, this.getDayColumnWidth(allDayEventsContainer)); } /** * @hidden */ allDayEventResizing(allDayEvent, resizeEvent, dayWidth) { const currentResize = this.allDayEventResizes.get(allDayEvent); const modifier = this.rtl ? -1 : 1; if (typeof resizeEvent.edges.left !== 'undefined') { const diff = Math.round(+resizeEvent.edges.left / dayWidth) * modifier; allDayEvent.offset = currentResize.originalOffset + diff; allDayEvent.span = currentResize.originalSpan - diff; } else if (typeof resizeEvent.edges.right !== 'undefined') { const diff = Math.round(+resizeEvent.edges.right / dayWidth) * modifier; allDayEvent.span = currentResize.originalSpan + diff; } } /** * @hidden */ allDayEventResizeEnded(allDayEvent) { const currentResize = this.allDayEventResizes.get(allDayEvent); if (currentResize) { const allDayEventResizingBeforeStart = currentResize.edge === 'left'; let daysDiff; if (allDayEventResizingBeforeStart) { daysDiff = allDayEvent.offset - currentResize.originalOffset; } else { daysDiff = allDayEvent.span - currentResize.originalSpan; } allDayEvent.offset = currentResize.originalOffset; allDayEvent.span = currentResize.originalSpan; const newDates = this.getAllDayEventResizedDates(allDayEvent.event, daysDiff, allDayEventResizingBeforeStart); this.eventTimesChanged.emit({ newStart: newDates.start, newEnd: newDates.end, event: allDayEvent.event, type: CalendarEventTimesChangedEventType.Resize, }); this.allDayEventResizes.delete(allDayEvent); } } /** * @hidden */ getDayColumnWidth(eventRowContainer) { return Math.floor(eventRowContainer.offsetWidth / this.days.length); } /** * @hidden */ dateDragEnter(date) { this.lastDragEnterDate = date; } /** * @hidden */ eventDropped(dropEvent, date, allDay) { if (shouldFireDroppedEvent(dropEvent, date, allDay, this.calendarId) && this.lastDragEnterDate.getTime() === date.getTime() && (!this.snapDraggedEvents || dropEvent.dropData.event !== this.lastDraggedEvent)) { this.eventTimesChanged.emit({ type: CalendarEventTimesChangedEventType.Drop, event: dropEvent.dropData.event, newStart: date, allDay, }); } this.lastDraggedEvent = null; } /** * @hidden */ dragEnter(type) { this.eventDragEnterByType[type]++; } /** * @hidden */ dragLeave(type) { this.eventDragEnterByType[type]--; } /** * @hidden */ dragStarted(eventsContainerElement, eventElement, event, useY) { this.dayColumnWidth = this.getDayColumnWidth(eventsContainerElement); const dragHelper = new CalendarDragHelper(eventsContainerElement, eventElement); this.validateDrag = ({ x, y, transform }) => { const isAllowed = this.allDayEventResizes.size === 0 && this.timeEventResizes.size === 0 && dragHelper.validateDrag({ x, y, snapDraggedEvents: this.snapDraggedEvents, dragAlreadyMoved: this.dragAlreadyMoved, transform, }); if (isAllowed && this.validateEventTimesChanged) { const newEventTimes = this.getDragMovedEventTimes(event, { x, y }, this.dayColumnWidth, useY); return this.validateEventTimesChanged({ type: CalendarEventTimesChangedEventType.Drag, event: event.event, newStart: newEventTimes.start, newEnd: newEventTimes.end, }); } return isAllowed; }; this.dragActive = true; this.dragAlreadyMoved = false; this.lastDraggedEvent = null; this.eventDragEnterByType = { allDay: 0, time: 0, }; if (!this.snapDraggedEvents && useY) { this.view.hourColumns.forEach((column) => { const linkedEvent = column.events.find((columnEvent) => columnEvent.event === event.event && columnEvent !== event); // hide any linked events while dragging if (linkedEvent) { linkedEvent.width = 0; linkedEvent.height = 0; } }); } this.cdr.markForCheck(); } /** * @hidden */ dragMove(dayEvent, dragEvent) { const newEventTimes = this.getDragMovedEventTimes(dayEvent, dragEvent, this.dayColumnWidth, true); const originalEvent = dayEvent.event; const adjustedEvent = { ...originalEvent, ...newEventTimes }; const tempEvents = this.events.map((event) => { if (event === originalEvent) { return adjustedEvent; } return event; }); this.restoreOriginalEvents(tempEvents, new Map([[adjustedEvent, originalEvent]]), this.snapDraggedEvents); this.dragAlreadyMoved = true; } /** * @hidden */ allDayEventDragMove() { this.dragAlreadyMoved = true; } /** * @hidden */ dragEnded(weekEvent, dragEndEvent, dayWidth, useY = false) { this.view = this.getWeekView(this.events); this.dragActive = false; this.validateDrag = null; const { start, end } = this.getDragMovedEventTimes(weekEvent, dragEndEvent, dayWidth, useY); if ((this.snapDraggedEvents || this.eventDragEnterByType[useY ? 'time' : 'allDay'] > 0) && isDraggedWithinPeriod(start, end, this.view.period)) { this.lastDraggedEvent = weekEvent.event; this.eventTimesChanged.emit({ newStart: start, newEnd: end, event: weekEvent.event, type: CalendarEventTimesChangedEventType.Drag, allDay: !useY, }); } } refreshHeader() { this.days = this.utils.getWeekViewHeader({ viewDate: this.viewDate, weekStartsOn: this.weekStartsOn, excluded: this.excludeDays, weekendDays: this.weekendDays, ...getWeekViewPeriod(this.dateAdapter, this.viewDate, this.weekStartsOn, this.excludeDays, this.daysInWeek), }); } refreshBody() { this.view = this.getWeekView(this.events); } refreshAll() { this.refreshHeader(); this.refreshBody(); this.emitBeforeViewRender(); } emitBeforeViewRender() { if (this.days && this.view) { this.beforeViewRender.emit({ header: this.days, ...this.view, }); } } getWeekView(events) { return this.utils.getWeekView({ events, viewDate: this.viewDate, weekStartsOn: this.weekStartsOn, excluded: this.excludeDays, precision: this.precision, absolutePositionedEvents: true, hourSegments: this.hourSegments, hourDuration: this.hourDuration, dayStart: { hour: this.dayStartHour, minute: this.dayStartMinute, }, dayEnd: { hour: this.dayEndHour, minute: this.dayEndMinute, }, segmentHeight: this.hourSegmentHeight, weekendDays: this.weekendDays, minimumEventHeight: this.minimumEventHeight, ...getWeekViewPeriod(this.dateAdapter, this.viewDate, this.weekStartsOn, this.excludeDays, this.daysInWeek), }); } getDragMovedEventTimes(weekEvent, dragEndEvent, dayWidth, useY) { const daysDragged = (roundToNearest(dragEndEvent.x, dayWidth) / dayWidth) * (this.rtl ? -1 : 1); const minutesMoved = useY ? getMinutesMoved(dragEndEvent.y, this.hourSegments, this.hourSegmentHeight, this.eventSnapSize, this.hourDuration) : 0; const start = this.dateAdapter.addMinutes(addDaysWithExclusions(this.dateAdapter, weekEvent.event.start, daysDragged, this.excludeDays), minutesMoved); let end; if (weekEvent.event.end) { end = this.dateAdapter.addMinutes(addDaysWithExclusions(this.dateAdapter, weekEvent.event.end, daysDragged, this.excludeDays), minutesMoved); } return { start, end }; } restoreOriginalEvents(tempEvents, adjustedEvents, snapDraggedEvents = true) { const previousView = this.view; if (snapDraggedEvents) { this.view = this.getWeekView(tempEvents); } const adjustedEventsArray = tempEvents.filter((event) => adjustedEvents.has(event)); this.view.hourColumns.forEach((column, columnIndex) => { previousView.hourColumns[columnIndex].hours.forEach((hour, hourIndex) => { hour.segments.forEach((segment, segmentIndex) => { column.hours[hourIndex].segments[segmentIndex].cssClass = segment.cssClass; }); }); adjustedEventsArray.forEach((adjustedEvent) => { const originalEvent = adjustedEvents.get(adjustedEvent); const existingColumnEvent = column.events.find((columnEvent) => columnEvent.event === (snapDraggedEvents ? adjustedEvent : originalEvent)); if (existingColumnEvent) { // restore the original event so trackBy kicks in and the dom isn't changed existingColumnEvent.event = originalEvent; existingColumnEvent['tempEvent'] = adjustedEvent; if (!snapDraggedEvents) { existingColumnEvent.height = 0; existingColumnEvent.width = 0; } } else { // add a dummy event to the drop so if the event was removed from the original column the drag doesn't end early const event = { event: originalEvent, left: 0, top: 0, height: 0, width: 0, startsBeforeDay: false, endsAfterDay: false, tempEvent: adjustedEvent, }; column.events.push(event); } }); }); adjustedEvents.clear(); } getTimeEventResizedDates(calendarEvent, resizeEvent) { const newEventDates = { start: calendarEvent.start, end: getDefaultEventEnd(this.dateAdapter, calendarEvent, this.minimumEventHeight), }; const { end, ...eventWithoutEnd } = calendarEvent; const smallestResizes = { start: this.dateAdapter.addMinutes(newEventDates.end, this.minimumEventHeight * -1), end: getDefaultEventEnd(this.dateAdapter, eventWithoutEnd, this.minimumEventHeight), }; const modifier = this.rtl ? -1 : 1; if (typeof resizeEvent.edges.left !== 'undefined') { const daysDiff = Math.round(+resizeEvent.edges.left / this.dayColumnWidth) * modifier; const newStart = addDaysWithExclusions(this.dateAdapter, newEventDates.start, daysDiff, this.excludeDays); if (newStart < smallestResizes.start) { newEventDates.start = newStart; } else { newEventDates.start = smallestResizes.start; } } else if (typeof resizeEvent.edges.right !== 'undefined') { const daysDiff = Math.round(+resizeEvent.edges.right / this.dayColumnWidth) * modifier; const newEnd = addDaysWithExclusions(this.dateAdapter, newEventDates.end, daysDiff, this.excludeDays); if (newEnd > smallestResizes.end) { newEventDates.end = newEnd; } else { newEventDates.end = smallestResizes.end; } } if (typeof resizeEvent.edges.top !== 'undefined') { const minutesMoved = getMinutesMoved(resizeEvent.edges.top, this.hourSegments, this.hourSegmentHeight, this.eventSnapSize, this.hourDuration); const newStart = this.dateAdapter.addMinutes(newEventDates.start, minutesMoved); if (newStart < smallestResizes.start) { newEventDates.start = newStart; } else { newEventDates.start = smallestResizes.start; } } else if (typeof resizeEvent.edges.bottom !== 'undefined') { const minutesMoved = getMinutesMoved(resizeEvent.edges.bottom, this.hourSegments, this.hourSegmentHeight, this.eventSnapSize, this.hourDuration); const newEnd = this.dateAdapter.addMinutes(newEventDates.end, minutesMoved); if (newEnd > smallestResizes.end) { newEventDates.end = newEnd; } else { newEventDates.end = smallestResizes.end; } } return newEventDates; } resizeStarted(eventsContainer, event, dayWidth) { this.dayColumnWidth = this.getDayColumnWidth(eventsContainer); const resizeHelper = new CalendarResizeHelper(eventsContainer, dayWidth, this.rtl); this.validateResize = ({ rectangle, edges }) => { const isWithinBoundary = resizeHelper.validateResize({ rectangle: { ...rectangle }, edges, }); if (isWithinBoundary && this.validateEventTimesChanged) { let newEventDates; if (!dayWidth) { newEventDates = this.getTimeEventResizedDates(event.event, { rectangle, edges, }); } else { const modifier = this.rtl ? -1 : 1; if (typeof edges.left !== 'undefined') { const diff = Math.round(+edges.left / dayWidth) * modifier; newEventDates = this.getAllDayEventResizedDates(event.event, diff, !this.rtl); } else { const diff = Math.round(+edges.right / dayWidth) * modifier; newEventDates = this.getAllDayEventResizedDates(event.event, diff, this.rtl); } } return this.validateEventTimesChanged({ type: CalendarEventTimesChangedEventType.Resize, event: event.event, newStart: newEventDates.start, newEnd: newEventDates.end, }); } return isWithinBoundary; }; this.cdr.markForCheck(); } /** * @hidden */ getAllDayEventResizedDates(event, daysDiff, beforeStart) { let start = event.start; let end = event.end || event.start; if (beforeStart) { start = addDaysWithExclusions(this.dateAdapter, start, daysDiff, this.excludeDays); } else { end = addDaysWithExclusions(this.dateAdapter, end, daysDiff, this.excludeDays); } return { start, end }; } } CalendarWeekViewComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: CalendarWeekViewComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.CalendarUtils }, { token: LOCALE_ID }, { token: i2.DateAdapter }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); CalendarWeekViewComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.0.3", type: CalendarWeekViewComponent, selector: "mwl-calendar-week-view", inputs: { viewDate: "viewDate", events: "events", excludeDays: "excludeDays", refresh: "refresh", locale: "locale", tooltipPlacement: "tooltipPlacement", tooltipTemplate: "tooltipTemplate", tooltipAppendToBody: "tooltipAppendToBody", tooltipDelay: "tooltipDelay", weekStartsOn: "weekStartsOn", headerTemplate: "headerTemplate", eventTemplate: "eventTemplate", eventTitleTemplate: "eventTitleTemplate", eventActionsTemplate: "eventActionsTemplate", precision: "precision", weekendDays: "weekendDays", snapDraggedEvents: "snapDraggedEvents", hourSegments: "hourSegments", hourDuration: "hourDuration", hourSegmentHeight: "hourSegmentHeight", minimumEventHeight: "minimumEventHeight", dayStartHour: "dayStartHour", dayStartMinute: "dayStartMinute", dayEndHour: "dayEndHour", dayEndMinute: "dayEndMinute", hourSegmentTemplate: "hourSegmentTemplate", eventSnapSize: "eventSnapSize", allDayEventsLabelTemplate: "allDayEventsLabelTemplate", daysInWeek: "daysInWeek", currentTimeMarkerTemplate: "currentTimeMarkerTemplate", validateEventTimesChanged: "validateEventTimesChanged", resizeCursors: "resizeCursors" }, outputs: { dayHeaderClicked: "dayHeaderClicked", eventClicked: "eventClicked", eventTimesChanged: "eventTimesChanged", beforeViewRender: "beforeViewRender", hourSegmentClicked: "hourSegmentClicked" }, usesOnChanges: true, ngImport: i0, template: ` <div class="cal-week-view" role="grid"> <mwl-calendar-week-view-header [days]="days" [locale]="locale" [customTemplate]="headerTemplate" (dayHeaderClicked)="dayHeaderClicked.emit($event)" (eventDropped)=" eventDropped({ dropData: $event }, $event.newStart, true) " (dragEnter)="dateDragEnter($event.date)" > </mwl-calendar-week-view-header> <div class="cal-all-day-events" #allDayEventsContainer *ngIf="view.allDayEventRows.length > 0" mwlDroppable (dragEnter)="dragEnter('allDay')" (dragLeave)="dragLeave('allDay')" > <div class="cal-day-columns"> <div class="cal-time-label-column"> <ng-container *ngTemplateOutlet="allDayEventsLabelTemplate" ></ng-container> </div> <div class="cal-day-column" *ngFor="let day of days; trackBy: trackByWeekDayHeaderDate" mwlDroppable dragOverClass="cal-drag-over" (drop)="eventDropped($event, day.date, true)" (dragEnter)="dateDragEnter(day.date)" ></div> </div> <div *ngFor="let eventRow of view.allDayEventRows; trackBy: trackById" #eventRowContainer class="cal-events-row" > <div *ngFor=" let allDayEvent of eventRow.row; trackBy: trackByWeekAllDayEvent " #event class="cal-event-container" [class.cal-draggable]=" allDayEvent.event.draggable && allDayEventResizes.size === 0 " [class.cal-starts-within-week]="!allDayEvent.startsBeforeWeek" [class.cal-ends-within-week]="!allDayEvent.endsAfterWeek" [ngClass]="allDayEvent.event?.cssClass" [style.width.%]="(100 / days.length) * allDayEvent.span" [style.marginLeft.%]=" rtl ? null : (100 / days.length) * allDayEvent.offset " [style.marginRight.%]=" rtl ? (100 / days.length) * allDayEvent.offset : null " mwlResizable [resizeCursors]="resizeCursors" [resizeSnapGrid]="{ left: dayColumnWidth, right: dayColumnWidth }" [validateResize]="validateResize" (resizeStart)=" allDayEventResizeStarted(eventRowContainer, allDayEvent, $event) " (resizing)=" allDayEventResizing(allDayEvent, $event, dayColumnWidth) " (resizeEnd)="allDayEventResizeEnded(allDayEvent)" mwlDraggable dragActiveClass="cal-drag-active" [dropData]="{ event: allDayEvent.event, calendarId: calendarId }" [dragAxis]="{ x: allDayEvent.event.draggable && allDayEventResizes.size === 0, y: !snapDraggedEvents && allDayEvent.event.draggable && allDayEventResizes.size === 0 }" [dragSnapGrid]="snapDraggedEvents ? { x: dayColumnWidth } : {}" [validateDrag]="validateDrag" [touchStartLongPress]="{ delay: 300, delta: 30 }" (dragStart)=" dragStarted(eventRowContainer, event, allDayEvent, false) " (dragging)="allDayEventDragMove()" (dragEnd)="dragEnded(allDayEvent, $event, dayColumnWidth)" > <div class="cal-resize-handle cal-resize-handle-before-start" *ngIf=" allDayEvent.event?.resizable?.beforeStart && !allDayEvent.startsBeforeWeek " mwlResizeHandle [resizeEdges]="{ left: true }" ></div> <mwl-calendar-week-view-event [locale]="locale" [weekEvent]="allDayEvent" [tooltipPlacement]="tooltipPlacement" [tooltipTemplate]="tooltipTemplate" [tooltipAppendToBody]="tooltipAppendToBody" [tooltipDelay]="tooltipDelay" [customTemplate]="eventTemplate" [eventTitleTemplate]="eventTitleTemplate" [eventActionsTemplate]="eventActionsTemplate" [daysInWeek]="daysInWeek" (eventClicked)=" eventClicked.emit({ event: allDayEvent.event, sourceEvent: $event.sourceEvent }) " > </mwl-calendar-week-view-event> <div class="cal-resize-handle cal-resize-handle-after-end" *ngIf=" allDayEvent.event?.resizable?.afterEnd && !allDayEvent.endsAfterWeek " mwlResizeHandle [resizeEdges]="{ right: true }" ></div> </div> </div> </div> <div class="cal-time-events" mwlDroppable (dragEnter)="dragEnter('time')" (dragLeave)="dragLeave('time')" > <div class="cal-time-label-column" *ngIf="view.hourColumns.length > 0 && daysInWeek !== 1" > <div *ngFor=" let hour of view.hourColumns[0].hours; trackBy: trackByHour; let odd = odd " class="cal-hour" [class.cal-hour-odd]="odd" > <mwl-calendar-week-view-hour-segment *ngFor="let segment of hour.segments; trackBy: trackByHourSegment" [style.height.px]="hourSegmentHeight" [segment]="segment" [segmentHeight]="hourSegmentHeight" [locale]="locale" [customTemplate]="hourSegmentTemplate" [isTimeLabel]="true" [daysInWeek]="daysInWeek" > </mwl-calendar-week-view-hour-segment> </div> </div> <div class="cal-day-columns" [class.cal-resize-active]="timeEventResizes.size > 0" #dayColumns > <div class="cal-day-column" *ngFor="let column of view.hourColumns; trackBy: trackByHourColumn" > <mwl-calendar-week-view-current-time-marker [columnDate]="column.date" [dayStartHour]="dayStartHour" [dayStartMinute]="dayStartMinute" [dayEndHour]="dayEndHour" [dayEndMinute]="dayEndMinute" [hourSegments]="hourSegments" [hourDuration]="hourDuration" [hourSegmentHeight]="hourSegmentHeight" [customTemplate]="currentTimeMarkerTemplate" ></mwl-calendar-week-view-current-time-marker> <div class="cal-events-container"> <div *ngFor=" let timeEvent of column.events; trackBy: trackByWeekTimeEvent " #event class="cal-event-container" [class.cal-draggable]=" timeEvent.event.draggable && timeEventResizes.size === 0 " [class.cal-starts-within-day]="!timeEvent.startsBeforeDay" [class.cal-ends-within-day]="!timeEvent.endsAfterDay" [ngClass]="timeEvent.event.cssClass" [hidden]="timeEvent.height === 0 && timeEvent.width === 0" [style.top.px]="timeEvent.top" [style.height.px]="timeEvent.height" [style.left.%]="timeEvent.left" [style.width.%]="timeEvent.width" mwlResizable [resizeCursors]="resizeCursors" [resizeSnapGrid]="{ left: dayColumnWidth, right: dayColumnWidth, top: eventSnapSize || hourSegmentHeight, bottom: eventSnapSize || hourSegmentHeight }" [validateResize]="validateResize" [allowNegativeResizes]="true" (resizeStart)=" timeEventResizeStarted(dayColumns, timeEvent, $event) " (resizing)="timeEventResizing(timeEvent, $event)" (resizeEnd)="timeEventResizeEnded(timeEvent)" mwlDraggable dragActiveClass="cal-drag-active" [dropData]="{ event: timeEvent.event, calendarId: calendarId }" [dragAxis]="{ x: timeEvent.event.draggable && timeEventResizes.size === 0, y: timeEvent.event.draggable && timeEventResizes.size === 0 }" [dragSnapGrid]=" snapDraggedEvents ? { x: dayColumnWidth, y: eventSnapSize || hourSegmentHeight } : {} " [touchStartLongPress]="{ delay: 300, delta: 30 }" [ghostDragEnabled]="!snapDraggedEvents" [ghostElementTemplate]="weekEventTemplate" [validateDrag]="validateDrag" (dragStart)="dragStarted(dayColumns, event, timeEvent, true)" (dragging)="dragMove(timeEvent, $event)" (dragEnd)="dragEnded(timeEvent, $event, dayColumnWidth, true)" > <div class="cal-resize-handle cal-resize-handle-before-start" *ngIf=" timeEvent.event?.resizable?.beforeStart && !timeEvent.startsBeforeDay " mwlResizeHandle [resizeEdges]="{ left: true, top: true }" ></div> <ng-template [ngTemplateOutlet]="weekEventTemplate" ></ng-template> <ng-template #weekEventTemplate> <mwl-calendar-week-view-event [locale]="locale" [weekEvent]="timeEvent" [tooltipPlacement]="tooltipPlacement" [tooltipTemplate]="tooltipTemplate" [tooltipAppendToBody]="tooltipAppendToBody" [tooltipDisabled]="dragActive || timeEventResizes.size > 0" [tooltipDelay]="tooltipDelay" [customTemplate]="eventTemplate" [eventTitleTemplate]="eventTitleTemplate" [eventActionsTemplate]="eventActionsTemplate" [column]="column" [daysInWeek]="daysInWeek" (eventClicked)=" eventClicked.emit({ event: timeEvent.event, sourceEvent: $event.sourceEvent }) " > </mwl-calendar-week-view-event> </ng-template> <div class="cal-resize-handle cal-resize-handle-after-end" *ngIf=" timeEvent.event?.resizable?.afterEnd && !timeEvent.endsAfterDay " mwlResizeHandle [resizeEdges]="{ right: true, bottom: true }" ></div> </div> </div> <div *ngFor=" let hour of column.hours; trackBy: trackByHour; let odd = odd " class="cal-hour" [class.cal-hour-odd]="odd" > <mwl-calendar-week-view-hour-segment *ngFor=" let segment of hour.segments; trackBy: trackByHourSegment " [style.height.px]="hourSegmentHeight" [segment]="segment" [segmentHeight]="hourSegmentHeight" [locale]="locale" [customTemplate]="hourSegmentTemplate" [daysInWeek]="daysInWeek" (mwlClick)=" hourSegmentClicked.emit({ date: segment.date, sourceEvent: $event }) " [clickListenerDisabled]=" hourSegmentClicked.observers.length === 0 " mwlDroppable [dragOverClass]=" !dragActive || !snapDraggedEvents ? 'cal-drag-over' : null " dragActiveClass="cal-drag-active" (drop)="eventDropped($event, segment.date, false)" (dragEnter)="dateDragEnter(segment.date)" [isTimeLabel]="daysInWeek === 1" > </mwl-calendar-week-view-hour-segment> </div> </div> </div> </div> </div> `, isInline: true, dependencies: [{ kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i4.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }, { kind: "directive", type: i5.DraggableDirective, selector: "[mwlDraggable]", inputs: ["dropData", "dragAxis", "dragSnapGrid", "ghostDragEnabled", "showOriginalElementWhileDragging", "validateDrag", "dragCursor", "dragActiveClass", "ghostElementAppendTo", "ghostElementTemplate", "touchStartLongPress", "autoScroll"], outputs: ["dragPointerDown", "dragStart", "ghostElementCreated", "dragging", "dragEnd"] }, { kind: "directive", type: i5.DroppableDirective, selector: "[mwlDroppable]", inputs: ["dragOverClass", "dragActiveClass", "validateDrop"], outputs: ["dragEnter", "dragLeave", "dragOver", "drop"] }, { kind: "directive", type: i6.ClickDirective, selector: "[mwlClick]", inputs: ["clickListenerDisabled"], outputs: ["mwlClick"] }, { kind: "component", type: i7.CalendarWeekViewHeaderComponent, selector: "mwl-calendar-week-view-header", inputs: ["days", "locale", "customTemplate"], outputs: ["dayHeaderClicked", "eventDropped", "dragEnter"] }, { kind: "component", type: i8.CalendarWeekViewEventComponent, selector: "mwl-calendar-week-view-event", inputs: ["locale", "weekEvent", "tooltipPlacement", "tooltipAppendToBody", "tooltipDisabled", "tooltipDelay", "customTemplate", "eventTitleTemplate", "eventActionsTemplate", "tooltipTemplate", "column", "daysInWeek"], outputs: ["eventClicked"] }, { kind: "component", type: i9.CalendarWeekViewHourSegmentComponent, selector: "mwl-calendar-week-view-hour-segment", inputs: ["segment", "segmentHeight", "locale", "isTimeLabel", "daysInWeek", "customTemplate"] }, { kind: "component", type: i10.CalendarWeekViewCurrentTimeMarkerComponent, selector: "mwl-calendar-week-view-current-time-marker", inputs: ["columnDate", "dayStartHour", "dayStartMinute", "dayEndHour", "dayEndMinute", "hourSegments", "hourDuration", "hourSegmentHeight", "customTemplate"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: CalendarWeekViewComponent, decorators: [{ type: Component, args: [{ selector: 'mwl-calendar-week-view', template: ` <div class="cal-week-view" role="grid"> <mwl-calendar-week-view-header [days]="days" [locale]="locale" [customTemplate]="headerTemplate" (dayHeaderClicked)="dayHeaderClicked.emit($event)" (eventDropped)=" eventDropped({ dropData: $event }, $event.newStart, true) " (dragEnter)="dateDragEnter($event.date)" > </mwl-calendar-week-view-header> <div class="cal-all-day-events" #allDayEventsContainer *ngIf="view.allDayEventRows.length > 0" mwlDroppable (dragEnter)="dragEnter('allDay')" (dragLeave)="dragLeave('allDay')" > <div class="cal-day-columns"> <div class="cal-time-label-column"> <ng-container *ngTemplateOutlet="allDayEventsLabelTemplate" ></ng-container> </div> <div class="cal-day-column" *ngFor="let day of days; trackBy: trackByWeekDayHeaderDate" mwlDroppable dragOverClass="cal-drag-over" (drop)="eventDropped($event, day.date, true)" (dragEnter)="dateDragEnter(day.date)" ></div> </div> <div *ngFor="let eventRow of view.allDayEventRows; trackBy: trackById" #eventRowContainer class="cal-events-row" > <div *ngFor=" let allDayEvent of eventRow.row; trackBy: trackByWeekAllDayEvent " #event class="cal-event-container" [class.cal-draggable]=" allDayEvent.event.draggable && allDayEventResizes.size === 0 " [class.cal-starts-within-week]="!allDayEvent.startsBeforeWeek" [class.cal-ends-within-week]="!allDayEvent.endsAfterWeek" [ngClass]="allDayEvent.event?.cssClass" [style.width.%]="(100 / days.length) * allDayEvent.span" [style.marginLeft.%]=" rtl ? null : (100 / days.length) * allDayEvent.offset " [style.marginRight.%]=" rtl ? (100 / days.length) * allDayEvent.offset : null " mwlResizable [resizeCursors]="resizeCursors" [resizeSnapGrid]="{ left: dayColumnWidth, right: dayColumnWidth }" [validateResize]="validateResize" (resizeStart)=" allDayEventResizeStarted(eventRowContainer, allDayEvent, $event) " (resizing)=" allDayEventResizing(allDayEvent, $event, dayColumnWidth) " (resizeEnd)="allDayEventResizeEnded(allDayEvent)" mwlDraggable dragActiveClass="cal-drag-active" [dropData]="{ event: allDayEvent.event, calendarId: calendarId }" [dragAxis]="{ x: allDayEvent.event.draggable && allDayEventResizes.size === 0, y: !snapDraggedEvents && allDayEvent.event.draggable && allDayEventResizes.size === 0 }" [dragSnapGrid]="snapDraggedEvents ? { x: dayColumnWidth } : {}" [validateDrag]="validateDrag" [touchStartLongPress]="{ delay: 300, delta: 30 }" (dragStart)=" dragStarted(eventRowContainer, event, allDayEvent, false) " (dragging)="allDayEventDragMove()" (dragEnd)="dragEnded(allDayEvent, $event, dayColumnWidth)" > <div class="cal-resize-handle cal-resize-handle-before-start" *ngIf=" allDayEvent.event?.resizable?.beforeStart && !allDayEvent.startsBeforeWeek " mwlResizeHandle [resizeEdges]="{ left: true }" ></div> <mwl-calendar-week-view-event [locale]="locale" [weekEvent]="allDayEvent" [tooltipPlacement]="tooltipPlacement" [tooltipTemplate]="tooltipTemplate" [tooltipAppendToBody]="tooltipAppendToBody" [tooltipDelay]="tooltipDelay" [customTemplate]="eventTemplate" [eventTitleTemplate]="eventTitleTemplate" [eventActionsTemplate]="eventActionsTemplate" [daysInWeek]="daysInWeek" (eventClicked)=" eventClicked.emit({ event: allDayEvent.event, sourceEvent: $event.sourceEvent }) " > </mwl-calendar-week-view-event> <div class="cal-resize-handle cal-resize-handle-after-end" *ngIf=" allDayEvent.event?.resizable?.afterEnd && !allDayEvent.endsAfterWeek " mwlResizeHandle [resizeEdges]="{ right: true }" ></div> </div> </div> </div> <div class="cal-time-events" mwlDroppable (dragEnter)="dragEnter('time')" (dragLeave)="dragLeave('time')" > <div class="cal-time-label-column" *ngIf="view.hourColumns.length > 0 && daysInWeek !== 1" > <div *ngFor=" let hour of view.hourColumns[0].hours; trackBy: trackByHour; let odd = odd " class="cal-hour" [class.cal-hour-odd]="odd" > <mwl-calendar-week-view-hour-segment *ngFor="let segment of hour.segments; trackBy: trackByHourSegment" [style.height.px]="hourSegmentHeight" [segment]="segment" [segmentHeight]="hourSegmentHeight" [locale]="locale" [customTemplate]="hourSegmentTemplate" [isTimeLabel]="true" [daysInWeek]="daysInWeek" > </mwl-calendar-week-view-hour-segm