UNPKG

angular-calendar

Version:

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

1 lines 250 kB
{"version":3,"file":"angular-calendar.mjs","sources":["../../../projects/angular-calendar/src/modules/common/click/click.directive.ts","../../../projects/angular-calendar/src/modules/common/keydown-enter/keydown-enter.directive.ts","../../../projects/angular-calendar/src/modules/common/calendar-a11y/calendar-a11y.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-a11y/calendar-a11y.pipe.ts","../../../projects/angular-calendar/src/modules/common/calendar-event-actions/calendar-event-actions.component.ts","../../../projects/angular-calendar/src/modules/common/calendar-event-title-formatter/calendar-event-title-formatter.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-event-title/calendar-event-title.pipe.ts","../../../projects/angular-calendar/src/modules/common/calendar-event-title/calendar-event-title.component.ts","../../../projects/angular-calendar/src/modules/common/calendar-tooltip/calendar-tooltip.directive.ts","../../../projects/angular-calendar/src/modules/common/calendar-view/calendar-view.enum.ts","../../../projects/angular-calendar/src/modules/common/util/util.ts","../../../projects/angular-calendar/src/date-adapters/date-adapter.ts","../../../projects/angular-calendar/src/modules/common/calendar-previous-view/calendar-previous-view.directive.ts","../../../projects/angular-calendar/src/modules/common/calendar-next-view/calendar-next-view.directive.ts","../../../projects/angular-calendar/src/modules/common/calendar-today/calendar-today.directive.ts","../../../projects/angular-calendar/src/modules/common/calendar-angular-date-formatter/calendar-angular-date-formatter.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-date-formatter/calendar-date-formatter.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-date/calendar-date.pipe.ts","../../../projects/angular-calendar/src/modules/common/calendar-utils/calendar-utils.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-moment-date-formatter/calendar-moment-date-formatter.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-native-date-formatter/calendar-native-date-formatter.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-event-times-changed-event/calendar-event-times-changed-event.interface.ts","../../../projects/angular-calendar/src/modules/common/calendar-common.module.ts","../../../projects/angular-calendar/src/modules/month/calendar-month-view/calendar-month-cell/calendar-month-cell.component.ts","../../../projects/angular-calendar/src/modules/month/calendar-month-view/calendar-open-day-events/calendar-open-day-events.component.ts","../../../projects/angular-calendar/src/modules/month/calendar-month-view/calendar-month-view-header/calendar-month-view-header.component.ts","../../../projects/angular-calendar/src/modules/month/calendar-month-view/calendar-month-view.component.ts","../../../projects/angular-calendar/src/modules/month/calendar-month.module.ts","../../../projects/angular-calendar/src/modules/common/calendar-drag-helper/calendar-drag-helper.provider.ts","../../../projects/angular-calendar/src/modules/common/calendar-resize-helper/calendar-resize-helper.provider.ts","../../../projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-header/calendar-week-view-header.component.ts","../../../projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-event/calendar-week-view-event.component.ts","../../../projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-hour-segment/calendar-week-view-hour-segment.component.ts","../../../projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-current-time-marker/calendar-week-view-current-time-marker.component.ts","../../../projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view.component.ts","../../../projects/angular-calendar/src/modules/week/calendar-week.module.ts","../../../projects/angular-calendar/src/modules/day/calendar-day-view/calendar-day-view.component.ts","../../../projects/angular-calendar/src/modules/day/calendar-day.module.ts","../../../projects/angular-calendar/src/modules/calendar.module.ts","../../../projects/angular-calendar/src/index.ts","../../../projects/angular-calendar/src/angular-calendar.ts"],"sourcesContent":["import {\n Directive,\n Renderer2,\n ElementRef,\n OnInit,\n OnDestroy,\n Output,\n EventEmitter,\n Inject,\n Input,\n NgZone,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { Observable, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\n@Directive({\n selector: '[mwlClick]',\n})\nexport class ClickDirective implements OnInit, OnDestroy {\n @Input() clickListenerDisabled = false;\n\n @Output('mwlClick') click = new EventEmitter<MouseEvent>(); // eslint-disable-line\n\n private destroy$ = new Subject<void>();\n\n constructor(\n private renderer: Renderer2,\n private elm: ElementRef<HTMLElement>,\n @Inject(DOCUMENT) private document\n ) {}\n\n ngOnInit(): void {\n if (!this.clickListenerDisabled) {\n this.listen()\n .pipe(takeUntil(this.destroy$))\n .subscribe((event) => {\n event.stopPropagation();\n this.click.emit(event);\n });\n }\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n }\n\n private listen() {\n return new Observable<MouseEvent>((observer) => {\n return this.renderer.listen(this.elm.nativeElement, 'click', (event) => {\n observer.next(event);\n });\n });\n }\n}\n","import {\n Directive,\n Output,\n EventEmitter,\n ElementRef,\n NgZone,\n Renderer2,\n OnInit,\n OnDestroy,\n} from '@angular/core';\n\n@Directive({\n selector: '[mwlKeydownEnter]',\n})\nexport class KeydownEnterDirective implements OnInit, OnDestroy {\n @Output('mwlKeydownEnter') keydown = new EventEmitter<KeyboardEvent>(); // eslint-disable-line\n\n private keydownListener: VoidFunction | null = null;\n\n constructor(\n private host: ElementRef<HTMLElement>,\n private ngZone: NgZone,\n private renderer: Renderer2\n ) {}\n\n ngOnInit(): void {\n this.ngZone.runOutsideAngular(() => {\n this.keydownListener = this.renderer.listen(\n this.host.nativeElement,\n 'keydown',\n (event: KeyboardEvent) => {\n if (\n event.keyCode === 13 ||\n event.which === 13 ||\n event.key === 'Enter'\n ) {\n event.preventDefault();\n event.stopPropagation();\n\n this.ngZone.run(() => {\n this.keydown.emit(event);\n });\n }\n }\n );\n });\n }\n\n ngOnDestroy(): void {\n if (this.keydownListener !== null) {\n this.keydownListener();\n this.keydownListener = null;\n }\n }\n}\n","import { Injectable } from '@angular/core';\nimport { formatDate, I18nPluralPipe } from '@angular/common';\nimport { A11yParams } from './calendar-a11y.interface';\n\n/**\n * This class is responsible for adding accessibility to the calendar.\n * You may override any of its methods via angulars DI to suit your requirements.\n * For example:\n *\n * ```typescript\n * import { A11yParams, CalendarA11y } from 'angular-calendar';\n * import { formatDate, I18nPluralPipe } from '@angular/common';\n * import { Injectable } from '@angular/core';\n *\n * // adding your own a11y params\n * export interface CustomA11yParams extends A11yParams {\n * isDrSuess?: boolean;\n * }\n *\n * @Injectable()\n * export class CustomCalendarA11y extends CalendarA11y {\n * constructor(protected i18nPlural: I18nPluralPipe) {\n * super(i18nPlural);\n * }\n *\n * // overriding a function\n * public openDayEventsLandmark({ date, locale, isDrSuess }: CustomA11yParams): string {\n * if (isDrSuess) {\n * return `\n * ${formatDate(date, 'EEEE MMMM d', locale)}\n * Today you are you! That is truer than true! There is no one alive\n * who is you-er than you!\n * `;\n * }\n * }\n * }\n *\n * // in your component that uses the calendar\n * providers: [{\n * provide: CalendarA11y,\n * useClass: CustomCalendarA11y\n * }]\n * ```\n */\n@Injectable()\nexport class CalendarA11y {\n constructor(protected i18nPlural: I18nPluralPipe) {}\n\n /**\n * Aria label for the badges/date of a cell\n * @example: `Saturday October 19 1 event click to expand`\n */\n public monthCell({ day, locale }: A11yParams): string {\n if (day.badgeTotal > 0) {\n return `\n ${formatDate(day.date, 'EEEE MMMM d', locale)},\n ${this.i18nPlural.transform(day.badgeTotal, {\n '=0': 'No events',\n '=1': 'One event',\n other: '# events',\n })},\n click to expand\n `;\n } else {\n return `${formatDate(day.date, 'EEEE MMMM d', locale)}`;\n }\n }\n\n /**\n * Aria label for the open day events start landmark\n * @example: `Saturday October 19 expanded view`\n */\n public openDayEventsLandmark({ date, locale }: A11yParams): string {\n return `\n Beginning of expanded view for ${formatDate(date, 'EEEE MMMM dd', locale)}\n `;\n }\n\n /**\n * Aria label for alert that a day in the month view was expanded\n * @example: `Saturday October 19 expanded`\n */\n public openDayEventsAlert({ date, locale }: A11yParams): string {\n return `${formatDate(date, 'EEEE MMMM dd', locale)} expanded`;\n }\n\n /**\n * Descriptive aria label for an event\n * @example: `Saturday October 19th, Scott's Pizza Party, from 11:00am to 5:00pm`\n */\n public eventDescription({ event, locale }: A11yParams): string {\n if (event.allDay === true) {\n return this.allDayEventDescription({ event, locale });\n }\n\n const aria = `\n ${formatDate(event.start, 'EEEE MMMM dd', locale)},\n ${event.title}, from ${formatDate(event.start, 'hh:mm a', locale)}\n `;\n if (event.end) {\n return aria + ` to ${formatDate(event.end, 'hh:mm a', locale)}`;\n }\n return aria;\n }\n\n /**\n * Descriptive aria label for an all day event\n * @example:\n * `Scott's Party, event spans multiple days: start time October 19 5:00pm, no stop time`\n */\n public allDayEventDescription({ event, locale }: A11yParams): string {\n const aria = `\n ${event.title}, event spans multiple days:\n start time ${formatDate(event.start, 'MMMM dd hh:mm a', locale)}\n `;\n if (event.end) {\n return (\n aria + `, stop time ${formatDate(event.end, 'MMMM d hh:mm a', locale)}`\n );\n }\n return aria + `, no stop time`;\n }\n\n /**\n * Aria label for the calendar event actions icons\n * @returns 'Edit' for fa-pencil icons, and 'Delete' for fa-times icons\n */\n public actionButtonLabel({ action }: A11yParams): string {\n return action.a11yLabel;\n }\n\n /**\n * @returns {number} Tab index to be given to month cells\n */\n public monthCellTabIndex(): number {\n return 0;\n }\n\n /**\n * @returns true if the events inside the month cell should be aria-hidden\n */\n public hideMonthCellEvents(): boolean {\n return true;\n }\n\n /**\n * @returns true if event titles should be aria-hidden (global)\n */\n public hideEventTitle(): boolean {\n return true;\n }\n\n /**\n * @returns true if hour segments in the week view should be aria-hidden\n */\n public hideWeekHourSegment(): boolean {\n return true;\n }\n\n /**\n * @returns true if hour segments in the day view should be aria-hidden\n */\n public hideDayHourSegment(): boolean {\n return true;\n }\n}\n","import { Pipe, PipeTransform, LOCALE_ID, Inject } from '@angular/core';\nimport { CalendarA11y } from './calendar-a11y.provider';\nimport { A11yParams } from './calendar-a11y.interface';\n\n/**\n * This pipe is primarily for rendering aria labels. Example usage:\n * ```typescript\n * // where `myEvent` is a `CalendarEvent` and myLocale is a locale identifier\n * {{ { event: myEvent, locale: myLocale } | calendarA11y: 'eventDescription' }}\n * ```\n */\n@Pipe({\n name: 'calendarA11y',\n})\nexport class CalendarA11yPipe implements PipeTransform {\n constructor(\n private calendarA11y: CalendarA11y,\n @Inject(LOCALE_ID) private locale: string\n ) {}\n\n transform(a11yParams: A11yParams, method: string): string {\n a11yParams.locale = a11yParams.locale || this.locale;\n if (typeof this.calendarA11y[method] === 'undefined') {\n const allowedMethods = Object.getOwnPropertyNames(\n Object.getPrototypeOf(CalendarA11y.prototype)\n ).filter((iMethod) => iMethod !== 'constructor');\n throw new Error(\n `${method} is not a valid a11y method. Can only be one of ${allowedMethods.join(\n ', '\n )}`\n );\n }\n return this.calendarA11y[method](a11yParams);\n }\n}\n","import { Component, Input, TemplateRef } from '@angular/core';\nimport { CalendarEvent, EventAction } from 'calendar-utils';\n\n@Component({\n selector: 'mwl-calendar-event-actions',\n template: `\n <ng-template\n #defaultTemplate\n let-event=\"event\"\n let-trackByActionId=\"trackByActionId\"\n >\n <span *ngIf=\"event.actions\" class=\"cal-event-actions\">\n <a\n class=\"cal-event-action\"\n href=\"javascript:;\"\n *ngFor=\"let action of event.actions; trackBy: trackByActionId\"\n (mwlClick)=\"action.onClick({ event: event, sourceEvent: $event })\"\n (mwlKeydownEnter)=\"\n action.onClick({ event: event, sourceEvent: $event })\n \"\n [ngClass]=\"action.cssClass\"\n [innerHtml]=\"action.label\"\n tabindex=\"0\"\n role=\"button\"\n [attr.aria-label]=\"\n { action: action } | calendarA11y : 'actionButtonLabel'\n \"\n >\n </a>\n </span>\n </ng-template>\n <ng-template\n [ngTemplateOutlet]=\"customTemplate || defaultTemplate\"\n [ngTemplateOutletContext]=\"{\n event: event,\n trackByActionId: trackByActionId\n }\"\n >\n </ng-template>\n `,\n})\nexport class CalendarEventActionsComponent {\n @Input() event: CalendarEvent;\n\n @Input() customTemplate: TemplateRef<any>;\n\n trackByActionId = (index: number, action: EventAction) =>\n action.id ? action.id : action;\n}\n","import { CalendarEvent } from 'calendar-utils';\n\n/**\n * This class is responsible for displaying all event titles within the calendar. You may override any of its methods via angulars DI to suit your requirements. For example:\n *\n * ```typescript\n * import { Injectable } from '@angular/core';\n * import { CalendarEventTitleFormatter, CalendarEvent } from 'angular-calendar';\n *\n * @Injectable()\n * class CustomEventTitleFormatter extends CalendarEventTitleFormatter {\n *\n * month(event: CalendarEvent): string {\n * return `Custom prefix: ${event.title}`;\n * }\n *\n * }\n *\n * // in your component\n * providers: [{\n * provide: CalendarEventTitleFormatter,\n * useClass: CustomEventTitleFormatter\n * }]\n * ```\n */\nexport class CalendarEventTitleFormatter {\n /**\n * The month view event title.\n */\n month(event: CalendarEvent, title: string): string {\n return event.title;\n }\n\n /**\n * The month view event tooltip. Return a falsey value from this to disable the tooltip.\n */\n monthTooltip(event: CalendarEvent, title: string): string {\n return event.title;\n }\n\n /**\n * The week view event title.\n */\n week(event: CalendarEvent, title: string): string {\n return event.title;\n }\n\n /**\n * The week view event tooltip. Return a falsey value from this to disable the tooltip.\n */\n weekTooltip(event: CalendarEvent, title: string): string {\n return event.title;\n }\n\n /**\n * The day view event title.\n */\n day(event: CalendarEvent, title: string): string {\n return event.title;\n }\n\n /**\n * The day view event tooltip. Return a falsey value from this to disable the tooltip.\n */\n dayTooltip(event: CalendarEvent, title: string): string {\n return event.title;\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\nimport { CalendarEvent } from 'calendar-utils';\nimport { CalendarEventTitleFormatter } from '../calendar-event-title-formatter/calendar-event-title-formatter.provider';\n\n@Pipe({\n name: 'calendarEventTitle',\n})\nexport class CalendarEventTitlePipe implements PipeTransform {\n constructor(private calendarEventTitle: CalendarEventTitleFormatter) {}\n\n transform(title: string, titleType: string, event: CalendarEvent): string {\n return this.calendarEventTitle[titleType](event, title);\n }\n}\n","import { Component, Input, TemplateRef } from '@angular/core';\nimport { CalendarEvent } from 'calendar-utils';\n\n@Component({\n selector: 'mwl-calendar-event-title',\n template: `\n <ng-template #defaultTemplate let-event=\"event\" let-view=\"view\">\n <span\n class=\"cal-event-title\"\n [innerHTML]=\"event.title | calendarEventTitle : view : event\"\n [attr.aria-hidden]=\"{} | calendarA11y : 'hideEventTitle'\"\n >\n </span>\n </ng-template>\n <ng-template\n [ngTemplateOutlet]=\"customTemplate || defaultTemplate\"\n [ngTemplateOutletContext]=\"{\n event: event,\n view: view\n }\"\n >\n </ng-template>\n `,\n})\nexport class CalendarEventTitleComponent {\n @Input() event: CalendarEvent;\n\n @Input() customTemplate: TemplateRef<any>;\n\n @Input() view: string;\n}\n","import {\n Directive,\n Component,\n HostListener,\n OnDestroy,\n Input,\n ComponentRef,\n Injector,\n ComponentFactoryResolver,\n ViewContainerRef,\n ElementRef,\n ComponentFactory,\n Inject,\n Renderer2,\n TemplateRef,\n OnChanges,\n SimpleChanges,\n} from '@angular/core';\nimport { DOCUMENT } from '@angular/common';\nimport { PlacementArray, positionElements } from 'positioning';\nimport { CalendarEvent } from 'calendar-utils';\nimport { Observable, of, Subject, timer } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\n@Component({\n selector: 'mwl-calendar-tooltip-window',\n template: `\n <ng-template\n #defaultTemplate\n let-contents=\"contents\"\n let-placement=\"placement\"\n let-event=\"event\"\n >\n <div class=\"cal-tooltip\" [ngClass]=\"'cal-tooltip-' + placement\">\n <div class=\"cal-tooltip-arrow\"></div>\n <div class=\"cal-tooltip-inner\" [innerHtml]=\"contents\"></div>\n </div>\n </ng-template>\n <ng-template\n [ngTemplateOutlet]=\"customTemplate || defaultTemplate\"\n [ngTemplateOutletContext]=\"{\n contents: contents,\n placement: placement,\n event: event\n }\"\n >\n </ng-template>\n `,\n})\nexport class CalendarTooltipWindowComponent {\n @Input() contents: string;\n\n @Input() placement: string;\n\n @Input() event: CalendarEvent;\n\n @Input() customTemplate: TemplateRef<any>;\n}\n\n@Directive({\n selector: '[mwlCalendarTooltip]',\n})\nexport class CalendarTooltipDirective implements OnDestroy, OnChanges {\n @Input('mwlCalendarTooltip') contents: string; // eslint-disable-line @angular-eslint/no-input-rename\n\n @Input('tooltipPlacement') placement: PlacementArray = 'auto'; // eslint-disable-line @angular-eslint/no-input-rename\n\n @Input('tooltipTemplate') customTemplate: TemplateRef<any>; // eslint-disable-line @angular-eslint/no-input-rename\n\n @Input('tooltipEvent') event: CalendarEvent; // eslint-disable-line @angular-eslint/no-input-rename\n\n @Input('tooltipAppendToBody') appendToBody: boolean; // eslint-disable-line @angular-eslint/no-input-rename\n\n @Input('tooltipDelay') delay: number | null = null; // eslint-disable-line @angular-eslint/no-input-rename\n\n private tooltipFactory: ComponentFactory<CalendarTooltipWindowComponent>;\n private tooltipRef: ComponentRef<CalendarTooltipWindowComponent>;\n private cancelTooltipDelay$ = new Subject<void>();\n\n constructor(\n private elementRef: ElementRef,\n private injector: Injector,\n private renderer: Renderer2,\n componentFactoryResolver: ComponentFactoryResolver,\n private viewContainerRef: ViewContainerRef,\n @Inject(DOCUMENT) private document // eslint-disable-line\n ) {\n this.tooltipFactory = componentFactoryResolver.resolveComponentFactory(\n CalendarTooltipWindowComponent\n );\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (\n this.tooltipRef &&\n (changes.contents || changes.customTemplate || changes.event)\n ) {\n this.tooltipRef.instance.contents = this.contents;\n this.tooltipRef.instance.customTemplate = this.customTemplate;\n this.tooltipRef.instance.event = this.event;\n this.tooltipRef.changeDetectorRef.markForCheck();\n\n if (!this.contents) {\n this.hide();\n }\n }\n }\n\n ngOnDestroy(): void {\n this.hide();\n }\n\n @HostListener('mouseenter')\n onMouseOver(): void {\n const delay$: Observable<any> =\n this.delay === null ? of('now') : timer(this.delay);\n delay$.pipe(takeUntil(this.cancelTooltipDelay$)).subscribe(() => {\n this.show();\n });\n }\n\n @HostListener('mouseleave')\n onMouseOut(): void {\n this.hide();\n }\n\n private show(): void {\n if (!this.tooltipRef && this.contents) {\n this.tooltipRef = this.viewContainerRef.createComponent(\n this.tooltipFactory,\n 0,\n this.injector,\n []\n );\n this.tooltipRef.instance.contents = this.contents;\n this.tooltipRef.instance.customTemplate = this.customTemplate;\n this.tooltipRef.instance.event = this.event;\n if (this.appendToBody) {\n this.document.body.appendChild(this.tooltipRef.location.nativeElement);\n }\n requestAnimationFrame(() => {\n this.positionTooltip();\n });\n }\n }\n\n private hide(): void {\n if (this.tooltipRef) {\n this.viewContainerRef.remove(\n this.viewContainerRef.indexOf(this.tooltipRef.hostView)\n );\n this.tooltipRef = null;\n }\n this.cancelTooltipDelay$.next();\n }\n\n private positionTooltip(previousPositions: string[] = []): void {\n if (this.tooltipRef) {\n this.tooltipRef.changeDetectorRef.detectChanges();\n this.tooltipRef.instance.placement = positionElements(\n this.elementRef.nativeElement,\n this.tooltipRef.location.nativeElement.children[0],\n this.placement,\n this.appendToBody\n );\n // keep re-positioning the tooltip until the arrow position doesn't make a difference\n if (\n previousPositions.indexOf(this.tooltipRef.instance.placement) === -1\n ) {\n this.positionTooltip([\n ...previousPositions,\n this.tooltipRef.instance.placement,\n ]);\n }\n }\n }\n}\n","export enum CalendarView {\n Month = 'month',\n Week = 'week',\n Day = 'day',\n}\n","import {\n CalendarEvent,\n WeekViewTimeEvent,\n WeekViewHour,\n WeekViewHourSegment,\n validateEvents as validateEventsWithoutLog,\n ViewPeriod,\n WeekDay,\n WeekViewAllDayEvent,\n} from 'calendar-utils';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\n\nexport const validateEvents = (events: CalendarEvent[]) => {\n const warn = (...args) => console.warn('angular-calendar', ...args);\n return validateEventsWithoutLog(events, warn);\n};\n\nexport function isInsideLeftAndRight(\n outer: ClientRect,\n inner: ClientRect\n): boolean {\n return (\n Math.floor(outer.left) <= Math.ceil(inner.left) &&\n Math.floor(inner.left) <= Math.ceil(outer.right) &&\n Math.floor(outer.left) <= Math.ceil(inner.right) &&\n Math.floor(inner.right) <= Math.ceil(outer.right)\n );\n}\n\nfunction isInsideTopAndBottom(outer: ClientRect, inner: ClientRect): boolean {\n return (\n Math.floor(outer.top) <= Math.ceil(inner.top) &&\n Math.floor(inner.top) <= Math.ceil(outer.bottom) &&\n Math.floor(outer.top) <= Math.ceil(inner.bottom) &&\n Math.floor(inner.bottom) <= Math.ceil(outer.bottom)\n );\n}\n\nexport function isInside(outer: ClientRect, inner: ClientRect): boolean {\n return (\n isInsideLeftAndRight(outer, inner) && isInsideTopAndBottom(outer, inner)\n );\n}\n\nexport function roundToNearest(amount: number, precision: number) {\n return Math.round(amount / precision) * precision;\n}\n\nexport const trackByEventId = (index: number, event: CalendarEvent) =>\n event.id ? event.id : event;\n\nexport const trackByWeekDayHeaderDate = (index: number, day: WeekDay) =>\n day.date.toISOString();\n\nexport const trackByHourSegment = (\n index: number,\n segment: WeekViewHourSegment\n) => segment.date.toISOString();\n\nexport const trackByHour = (index: number, hour: WeekViewHour) =>\n hour.segments[0].date.toISOString();\n\nexport const trackByWeekAllDayEvent = (\n index: number,\n weekEvent: WeekViewAllDayEvent\n) => (weekEvent.event.id ? weekEvent.event.id : weekEvent.event);\n\nexport const trackByWeekTimeEvent = (\n index: number,\n weekEvent: WeekViewTimeEvent\n) => (weekEvent.event.id ? weekEvent.event.id : weekEvent.event);\n\nconst MINUTES_IN_HOUR = 60;\n\nfunction getPixelAmountInMinutes(\n hourSegments: number,\n hourSegmentHeight: number,\n hourDuration?: number\n) {\n return (hourDuration || MINUTES_IN_HOUR) / (hourSegments * hourSegmentHeight);\n}\n\nexport function getMinutesMoved(\n movedY: number,\n hourSegments: number,\n hourSegmentHeight: number,\n eventSnapSize: number,\n hourDuration?: number\n): number {\n const draggedInPixelsSnapSize = roundToNearest(\n movedY,\n eventSnapSize || hourSegmentHeight\n );\n const pixelAmountInMinutes = getPixelAmountInMinutes(\n hourSegments,\n hourSegmentHeight,\n hourDuration\n );\n return draggedInPixelsSnapSize * pixelAmountInMinutes;\n}\n\nexport function getDefaultEventEnd(\n dateAdapter: DateAdapter,\n event: CalendarEvent,\n minimumMinutes: number\n): Date {\n if (event.end) {\n return event.end;\n } else {\n return dateAdapter.addMinutes(event.start, minimumMinutes);\n }\n}\n\nexport function addDaysWithExclusions(\n dateAdapter: DateAdapter,\n date: Date,\n days: number,\n excluded: number[]\n): Date {\n let daysCounter = 0;\n let daysToAdd = 0;\n const changeDays = days < 0 ? dateAdapter.subDays : dateAdapter.addDays;\n let result = date;\n while (daysToAdd <= Math.abs(days)) {\n result = changeDays(date, daysCounter);\n const day = dateAdapter.getDay(result);\n if (excluded.indexOf(day) === -1) {\n daysToAdd++;\n }\n daysCounter++;\n }\n return result;\n}\n\nexport function isDraggedWithinPeriod(\n newStart: Date,\n newEnd: Date,\n period: ViewPeriod\n): boolean {\n const end = newEnd || newStart;\n return (\n (period.start <= newStart && newStart <= period.end) ||\n (period.start <= end && end <= period.end)\n );\n}\n\nexport function shouldFireDroppedEvent(\n dropEvent: { dropData?: { event?: CalendarEvent; calendarId?: symbol } },\n date: Date,\n allDay: boolean,\n calendarId: symbol\n) {\n return (\n dropEvent.dropData &&\n dropEvent.dropData.event &&\n (dropEvent.dropData.calendarId !== calendarId ||\n (dropEvent.dropData.event.allDay && !allDay) ||\n (!dropEvent.dropData.event.allDay && allDay))\n );\n}\n\nexport function getWeekViewPeriod(\n dateAdapter: DateAdapter,\n viewDate: Date,\n weekStartsOn: number,\n excluded: number[] = [],\n daysInWeek?: number\n): { viewStart: Date; viewEnd: Date } {\n let viewStart = daysInWeek\n ? dateAdapter.startOfDay(viewDate)\n : dateAdapter.startOfWeek(viewDate, { weekStartsOn });\n const endOfWeek = dateAdapter.endOfWeek(viewDate, { weekStartsOn });\n while (\n excluded.indexOf(dateAdapter.getDay(viewStart)) > -1 &&\n viewStart < endOfWeek\n ) {\n viewStart = dateAdapter.addDays(viewStart, 1);\n }\n if (daysInWeek) {\n const viewEnd = dateAdapter.endOfDay(\n addDaysWithExclusions(dateAdapter, viewStart, daysInWeek - 1, excluded)\n );\n return { viewStart, viewEnd };\n } else {\n let viewEnd = endOfWeek;\n while (\n excluded.indexOf(dateAdapter.getDay(viewEnd)) > -1 &&\n viewEnd > viewStart\n ) {\n viewEnd = dateAdapter.subDays(viewEnd, 1);\n }\n return { viewStart, viewEnd };\n }\n}\n\nexport function isWithinThreshold({ x, y }: { x: number; y: number }) {\n const DRAG_THRESHOLD = 1;\n return Math.abs(x) > DRAG_THRESHOLD || Math.abs(y) > DRAG_THRESHOLD;\n}\n","import { DateAdapter as BaseDateAdapter } from 'calendar-utils/date-adapters/date-adapter';\n\nexport abstract class DateAdapter implements BaseDateAdapter {\n abstract addWeeks(date: Date | number, amount: number): Date;\n\n abstract addMonths(date: Date | number, amount: number): Date;\n\n abstract subDays(date: Date | number, amount: number): Date;\n\n abstract subWeeks(date: Date | number, amount: number): Date;\n\n abstract subMonths(date: Date | number, amount: number): Date;\n\n abstract getISOWeek(date: Date | number): number;\n\n abstract setDate(date: Date | number, dayOfMonth: number): Date;\n\n abstract setMonth(date: Date | number, month: number): Date;\n\n abstract setYear(date: Date | number, year: number): Date;\n\n abstract getDate(date: Date | number): number;\n\n abstract getMonth(date: Date | number): number;\n\n abstract getYear(date: Date | number): number;\n\n abstract addDays(date: Date | number, amount: number): Date;\n\n abstract addHours(date: Date | number, amount: number): Date;\n\n abstract addMinutes(date: Date | number, amount: number): Date;\n\n abstract addSeconds(date: Date | number, amount: number): Date;\n\n abstract differenceInDays(\n dateLeft: Date | number,\n dateRight: Date | number\n ): number;\n\n abstract differenceInMinutes(\n dateLeft: Date | number,\n dateRight: Date | number\n ): number;\n\n abstract differenceInSeconds(\n dateLeft: Date | number,\n dateRight: Date | number\n ): number;\n\n abstract endOfDay(date: Date | number): Date;\n\n abstract endOfMonth(date: Date | number): Date;\n\n abstract endOfWeek(\n date: Date | number,\n options?: { weekStartsOn?: number }\n ): Date;\n\n abstract getDay(date: Date | number): number;\n\n abstract isSameDay(\n dateLeft: Date | number,\n dateRight: Date | number\n ): boolean;\n\n abstract isSameMonth(\n dateLeft: Date | number,\n dateRight: Date | number\n ): boolean;\n\n abstract isSameSecond(\n dateLeft: Date | number,\n dateRight: Date | number\n ): boolean;\n\n abstract max(dates: (Date | number)[]): Date;\n\n abstract setHours(date: Date | number, hours: number): Date;\n\n abstract setMinutes(date: Date | number, minutes: number): Date;\n\n abstract startOfDay(date: Date | number): Date;\n\n abstract startOfMinute(date: Date | number): Date;\n\n abstract startOfMonth(date: Date | number): Date;\n\n abstract startOfWeek(\n date: Date | number,\n options?: { weekStartsOn?: number }\n ): Date;\n\n abstract getHours(date: Date | number): number;\n\n abstract getMinutes(date: Date | number): number;\n\n abstract getTimezoneOffset(date: Date | number): number;\n}\n","import {\n Directive,\n HostListener,\n Input,\n Output,\n EventEmitter,\n} from '@angular/core';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\nimport { CalendarView } from '../calendar-view/calendar-view.enum';\nimport { addDaysWithExclusions } from '../util/util';\n\n/**\n * Change the view date to the previous view. For example:\n *\n * ```typescript\n * <button\n * mwlCalendarPreviousView\n * [(viewDate)]=\"viewDate\"\n * [view]=\"view\">\n * Previous\n * </button>\n * ```\n */\n@Directive({\n selector: '[mwlCalendarPreviousView]',\n})\nexport class CalendarPreviousViewDirective {\n /**\n * The current view\n */\n @Input() view: CalendarView | 'month' | 'week' | 'day';\n\n /**\n * The current view date\n */\n @Input() viewDate: Date;\n\n /**\n * Days to skip when going back by 1 day\n */\n @Input() excludeDays: number[] = [];\n\n /**\n * The number of days in a week. If set will subtract this amount of days instead of 1 week\n */\n @Input() daysInWeek: number;\n\n /**\n * Called when the view date is changed\n */\n @Output() viewDateChange: EventEmitter<Date> = new EventEmitter();\n\n constructor(private dateAdapter: DateAdapter) {}\n\n /**\n * @hidden\n */\n @HostListener('click')\n onClick(): void {\n const subFn: any = {\n day: this.dateAdapter.subDays,\n week: this.dateAdapter.subWeeks,\n month: this.dateAdapter.subMonths,\n }[this.view];\n\n if (this.view === CalendarView.Day) {\n this.viewDateChange.emit(\n addDaysWithExclusions(\n this.dateAdapter,\n this.viewDate,\n -1,\n this.excludeDays\n )\n );\n } else if (this.view === CalendarView.Week && this.daysInWeek) {\n this.viewDateChange.emit(\n addDaysWithExclusions(\n this.dateAdapter,\n this.viewDate,\n -this.daysInWeek,\n this.excludeDays\n )\n );\n } else {\n this.viewDateChange.emit(subFn(this.viewDate, 1));\n }\n }\n}\n","import {\n Directive,\n EventEmitter,\n HostListener,\n Input,\n Output,\n} from '@angular/core';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\nimport { CalendarView } from '../calendar-view/calendar-view.enum';\nimport { addDaysWithExclusions } from '../util/util';\n\n/**\n * Change the view date to the next view. For example:\n *\n * ```typescript\n * <button\n * mwlCalendarNextView\n * [(viewDate)]=\"viewDate\"\n * [view]=\"view\">\n * Next\n * </button>\n * ```\n */\n@Directive({\n selector: '[mwlCalendarNextView]',\n})\nexport class CalendarNextViewDirective {\n /**\n * The current view\n */\n @Input() view: CalendarView | 'month' | 'week' | 'day';\n\n /**\n * The current view date\n */\n @Input() viewDate: Date;\n\n /**\n * Days to skip when going forward by 1 day\n */\n @Input() excludeDays: number[] = [];\n\n /**\n * The number of days in a week. If set will add this amount of days instead of 1 week\n */\n @Input() daysInWeek: number;\n\n /**\n * Called when the view date is changed\n */\n @Output() viewDateChange: EventEmitter<Date> = new EventEmitter();\n\n constructor(private dateAdapter: DateAdapter) {}\n\n /**\n * @hidden\n */\n @HostListener('click')\n onClick(): void {\n const addFn: any = {\n day: this.dateAdapter.addDays,\n week: this.dateAdapter.addWeeks,\n month: this.dateAdapter.addMonths,\n }[this.view];\n\n if (this.view === CalendarView.Day) {\n this.viewDateChange.emit(\n addDaysWithExclusions(\n this.dateAdapter,\n this.viewDate,\n 1,\n this.excludeDays\n )\n );\n } else if (this.view === CalendarView.Week && this.daysInWeek) {\n this.viewDateChange.emit(\n addDaysWithExclusions(\n this.dateAdapter,\n this.viewDate,\n this.daysInWeek,\n this.excludeDays\n )\n );\n } else {\n this.viewDateChange.emit(addFn(this.viewDate, 1));\n }\n }\n}\n","import {\n Directive,\n HostListener,\n Input,\n Output,\n EventEmitter,\n} from '@angular/core';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\n\n/**\n * Change the view date to the current day. For example:\n *\n * ```typescript\n * <button\n * mwlCalendarToday\n * [(viewDate)]=\"viewDate\">\n * Today\n * </button>\n * ```\n */\n@Directive({\n selector: '[mwlCalendarToday]',\n})\nexport class CalendarTodayDirective {\n /**\n * The current view date\n */\n @Input() viewDate: Date;\n\n /**\n * Called when the view date is changed\n */\n @Output() viewDateChange: EventEmitter<Date> = new EventEmitter();\n\n constructor(private dateAdapter: DateAdapter) {}\n\n /**\n * @hidden\n */\n @HostListener('click')\n onClick(): void {\n this.viewDateChange.emit(this.dateAdapter.startOfDay(new Date()));\n }\n}\n","import {\n CalendarDateFormatterInterface,\n DateFormatterParams,\n} from '../calendar-date-formatter/calendar-date-formatter.interface';\nimport { formatDate } from '@angular/common';\nimport { Injectable } from '@angular/core';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\nimport { getWeekViewPeriod } from '../util/util';\n\n/**\n * This will use the angular date pipe to do all date formatting. It is the default date formatter used by the calendar.\n */\n@Injectable()\nexport class CalendarAngularDateFormatter\n implements CalendarDateFormatterInterface\n{\n constructor(protected dateAdapter: DateAdapter) {}\n\n /**\n * The month view header week day labels\n */\n public monthViewColumnHeader({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'EEEE', locale);\n }\n\n /**\n * The month view cell day number\n */\n public monthViewDayNumber({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'd', locale);\n }\n\n /**\n * The month view title\n */\n public monthViewTitle({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'LLLL y', locale);\n }\n\n /**\n * The week view header week day labels\n */\n public weekViewColumnHeader({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'EEEE', locale);\n }\n\n /**\n * The week view sub header day and month labels\n */\n public weekViewColumnSubHeader({\n date,\n locale,\n }: DateFormatterParams): string {\n return formatDate(date, 'MMM d', locale);\n }\n\n /**\n * The week view title\n */\n public weekViewTitle({\n date,\n locale,\n weekStartsOn,\n excludeDays,\n daysInWeek,\n }: DateFormatterParams): string {\n const { viewStart, viewEnd } = getWeekViewPeriod(\n this.dateAdapter,\n date,\n weekStartsOn,\n excludeDays,\n daysInWeek\n );\n const format = (dateToFormat: Date, showYear: boolean) =>\n formatDate(dateToFormat, 'MMM d' + (showYear ? ', yyyy' : ''), locale);\n return `${format(\n viewStart,\n viewStart.getUTCFullYear() !== viewEnd.getUTCFullYear()\n )} - ${format(viewEnd, true)}`;\n }\n\n /**\n * The time formatting down the left hand side of the week view\n */\n public weekViewHour({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'h a', locale);\n }\n\n /**\n * The time formatting down the left hand side of the day view\n */\n public dayViewHour({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'h a', locale);\n }\n\n /**\n * The day view title\n */\n public dayViewTitle({ date, locale }: DateFormatterParams): string {\n return formatDate(date, 'EEEE, MMMM d, y', locale);\n }\n}\n","import { CalendarAngularDateFormatter } from '../calendar-angular-date-formatter/calendar-angular-date-formatter.provider';\nimport { Injectable } from '@angular/core';\n\n/**\n * This class is responsible for all formatting of dates. There are 3 implementations available, the `CalendarAngularDateFormatter` (default) which uses the angular date pipe to format dates, the `CalendarNativeDateFormatter` which will use the <a href=\"https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl\" target=\"_blank\">Intl</a> API to format dates, or there is the `CalendarMomentDateFormatter` which uses <a href=\"http://momentjs.com/\" target=\"_blank\">moment</a>.\n *\n * If you wish, you may override any of the defaults via angulars DI. For example:\n *\n * ```typescript\n * import { CalendarDateFormatter, DateFormatterParams } from 'angular-calendar';\n * import { formatDate } from '@angular/common';\n * import { Injectable } from '@angular/core';\n *\n * @Injectable()\n * class CustomDateFormatter extends CalendarDateFormatter {\n *\n * public monthViewColumnHeader({date, locale}: DateFormatterParams): string {\n * return formatDate(date, 'EEE', locale); // use short week days\n * }\n *\n * }\n *\n * // in your component that uses the calendar\n * providers: [{\n * provide: CalendarDateFormatter,\n * useClass: CustomDateFormatter\n * }]\n * ```\n */\n@Injectable()\nexport class CalendarDateFormatter extends CalendarAngularDateFormatter {}\n","import { Pipe, PipeTransform, LOCALE_ID, Inject } from '@angular/core';\nimport { CalendarDateFormatter } from '../calendar-date-formatter/calendar-date-formatter.provider';\n\n/**\n * This pipe is primarily for rendering the current view title. Example usage:\n * ```typescript\n * // where `viewDate` is a `Date` and view is `'month' | 'week' | 'day'`\n * {{ viewDate | calendarDate:(view + 'ViewTitle'):'en' }}\n * ```\n */\n@Pipe({\n name: 'calendarDate',\n})\nexport class CalendarDatePipe implements PipeTransform {\n constructor(\n private dateFormatter: CalendarDateFormatter,\n @Inject(LOCALE_ID) private locale: string\n ) {}\n\n transform(\n date: Date,\n method: string,\n locale: string = this.locale,\n weekStartsOn: number = 0,\n excludeDays: number[] = [],\n daysInWeek?: number\n ): string {\n if (typeof this.dateFormatter[method] === 'undefined') {\n const allowedMethods = Object.getOwnPropertyNames(\n Object.getPrototypeOf(CalendarDateFormatter.prototype)\n ).filter((iMethod) => iMethod !== 'constructor');\n throw new Error(\n `${method} is not a valid date formatter. Can only be one of ${allowedMethods.join(\n ', '\n )}`\n );\n }\n return this.dateFormatter[method]({\n date,\n locale,\n weekStartsOn,\n excludeDays,\n daysInWeek,\n });\n }\n}\n","import { Injectable } from '@angular/core';\nimport {\n GetMonthViewArgs,\n MonthView,\n GetWeekViewHeaderArgs,\n WeekDay,\n GetWeekViewArgs,\n WeekView,\n getMonthView,\n getWeekViewHeader,\n getWeekView,\n} from 'calendar-utils';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\n\n@Injectable()\nexport class CalendarUtils {\n constructor(protected dateAdapter: DateAdapter) {}\n\n getMonthView(args: GetMonthViewArgs): MonthView {\n return getMonthView(this.dateAdapter, args);\n }\n\n getWeekViewHeader(args: GetWeekViewHeaderArgs): WeekDay[] {\n return getWeekViewHeader(this.dateAdapter, args);\n }\n\n getWeekView(args: GetWeekViewArgs): WeekView {\n return getWeekView(this.dateAdapter, args);\n }\n}\n","import { InjectionToken, Inject, Injectable } from '@angular/core';\nimport {\n CalendarDateFormatterInterface,\n DateFormatterParams,\n} from '../calendar-date-formatter/calendar-date-formatter.interface';\nimport { getWeekViewPeriod } from '../util/util';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\n\nexport const MOMENT: InjectionToken<string> = new InjectionToken('Moment');\n\n/**\n * This will use <a href=\"http://momentjs.com/\" target=\"_blank\">moment</a> to do all date formatting. To use this class:\n *\n * ```typescript\n * import { CalendarDateFormatter, CalendarMomentDateFormatter, MOMENT } from 'angular-calendar';\n * import moment from 'moment';\n *\n * // in your component\n * provide: [{\n * provide: MOMENT, useValue: moment\n * }, {\n * provide: CalendarDateFormatter, useClass: CalendarMomentDateFormatter\n * }]\n *\n * ```\n */\n@Injectable()\nexport class CalendarMomentDateFormatter\n implements CalendarDateFormatterInterface\n{\n /**\n * @hidden\n */\n constructor(\n @Inject(MOMENT) protected moment: any,\n protected dateAdapter: DateAdapter\n ) {}\n\n /**\n * The month view header week day labels\n */\n public monthViewColumnHeader({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('dddd');\n }\n\n /**\n * The month view cell day number\n */\n public monthViewDayNumber({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('D');\n }\n\n /**\n * The month view title\n */\n public monthViewTitle({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('MMMM YYYY');\n }\n\n /**\n * The week view header week day labels\n */\n public weekViewColumnHeader({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('dddd');\n }\n\n /**\n * The week view sub header day and month labels\n */\n public weekViewColumnSubHeader({\n date,\n locale,\n }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('MMM D');\n }\n\n /**\n * The week view title\n */\n public weekViewTitle({\n date,\n locale,\n weekStartsOn,\n excludeDays,\n daysInWeek,\n }: DateFormatterParams): string {\n const { viewStart, viewEnd } = getWeekViewPeriod(\n this.dateAdapter,\n date,\n weekStartsOn,\n excludeDays,\n daysInWeek\n );\n const format = (dateToFormat: Date, showYear: boolean) =>\n this.moment(dateToFormat)\n .locale(locale)\n .format('MMM D' + (showYear ? ', YYYY' : ''));\n return `${format(\n viewStart,\n viewStart.getUTCFullYear() !== viewEnd.getUTCFullYear()\n )} - ${format(viewEnd, true)}`;\n }\n\n /**\n * The time formatting down the left hand side of the week view\n */\n public weekViewHour({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('ha');\n }\n\n /**\n * The time formatting down the left hand side of the day view\n */\n public dayViewHour({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('ha');\n }\n\n /**\n * The day view title\n */\n public dayViewTitle({ date, locale }: DateFormatterParams): string {\n return this.moment(date).locale(locale).format('dddd, LL'); // dddd = Thursday\n } // LL = locale-dependent Month Day, Year\n}\n","import {\n CalendarDateFormatterInterface,\n DateFormatterParams,\n} from '../calendar-date-formatter/calendar-date-formatter.interface';\nimport { Injectable } from '@angular/core';\nimport { DateAdapter } from '../../../date-adapters/date-adapter';\nimport { getWeekViewPeriod } from '../util/util';\n\n/**\n * This will use <a href=\"https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl\" target=\"_blank\">Intl</a> API to do all date formatting.\n *\n * You will need to include a <a href=\"https://github.com/andyearnshaw/Intl.js/\">polyfill</a> for older browsers.\n */\n@Injectable()\nexport class CalendarNativeDateFormatter\n implements CalendarDateFormatterInterface\n{\n constructor(protected dateAdapter: DateAdapter) {}\n\n /**\n * The month view header week day labels\n */\n public monthViewColumnHeader({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(date);\n }\n\n /**\n * The month view cell day number\n */\n public monthViewDayNumber({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, { day: 'numeric' }).format(date);\n }\n\n /**\n * The month view title\n */\n public monthViewTitle({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, {\n year: 'numeric',\n month: 'long',\n }).format(date);\n }\n\n /**\n * The week view header week day labels\n */\n public weekViewColumnHeader({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, { weekday: 'long' }).format(date);\n }\n\n /**\n * The week view sub header day and month labels\n */\n public weekViewColumnSubHeader({\n date,\n locale,\n }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, {\n day: 'numeric',\n month: 'short',\n }).format(date);\n }\n\n /**\n * The week view title\n */\n public weekViewTitle({\n date,\n locale,\n weekStartsOn,\n excludeDays,\n daysInWeek,\n }: DateFormatterParams): string {\n const { viewStart, viewEnd } = getWeekViewPeriod(\n this.dateAdapter,\n date,\n weekStartsOn,\n excludeDays,\n daysInWeek\n );\n\n const format = (dateToFormat: Date, showYear: boolean) =>\n new Intl.DateTimeFormat(locale, {\n day: 'numeric',\n month: 'short',\n year: showYear ? 'numeric' : undefined,\n }).format(dateToFormat);\n\n return `${format(\n viewStart,\n viewStart.getUTCFullYear() !== viewEnd.getUTCFullYear()\n )} - ${format(viewEnd, true)}`;\n }\n\n /**\n * The time formatting down the left hand side of the week view\n */\n public weekViewHour({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, { hour: 'numeric' }).format(date);\n }\n\n /**\n * The time formatting down the left hand side of the day view\n */\n public dayViewHour({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, { hour: 'numeric' }).format(date);\n }\n\n /**\n * The day view title\n */\n public dayViewTitle({ date, locale }: DateFormatterParams): string {\n return new Intl.DateTimeFormat(locale, {\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n weekday: 'long',\n }).format(date);\n }\n}\n","import { CalendarEvent } from 'calendar-utils';\n\nexport enum CalendarEventTimesChangedEventType {\n Drag = 'drag',\n Drop = 'drop',\n Resize = 'resize',\n}\n\n/**\n