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