ionic2-calendar
Version:
Ionic calendar component
762 lines (758 loc) • 185 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Component, ViewChild, Input, Output, ViewEncapsulation, HostBinding, LOCALE_ID, Inject, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { DatePipe, CommonModule } from '@angular/common';
import * as i2$1 from '@ionic/angular';
import { IonicSlides, IonicModule } from '@ionic/angular';
import SwiperCore, { Swiper } from 'swiper';
import { Subject } from 'rxjs';
class CalendarService {
constructor() {
this._currentDate = new Date();
this.currentDateChangedFromParent = new Subject();
this.currentDateChangedFromChildren = new Subject();
this.eventSourceChanged = new Subject();
this.slideChanged = new Subject();
this.slideUpdated = new Subject();
this.currentDateChangedFromParent$ = this.currentDateChangedFromParent.asObservable();
this.currentDateChangedFromChildren$ = this.currentDateChangedFromChildren.asObservable();
this.eventSourceChanged$ = this.eventSourceChanged.asObservable();
this.slideChanged$ = this.slideChanged.asObservable();
this.slideUpdated$ = this.slideUpdated.asObservable();
}
setCurrentDate(val, fromParent = false) {
this._currentDate = new Date(val);
if (fromParent) {
this.currentDateChangedFromParent.next(val);
}
else {
this.currentDateChangedFromChildren.next(val);
}
}
get currentDate() {
return this._currentDate;
}
rangeChanged(component) {
if (this.queryMode === 'local') {
if (component.eventSource && component.onDataLoaded) {
component.onDataLoaded();
}
}
else if (this.queryMode === 'remote') {
let rangeStart = new Date(component.range.startTime.getTime()), rangeEnd = new Date(component.range.endTime.getTime());
rangeStart.setHours(0);
if (rangeStart.getHours() === 23) {
rangeStart.setTime(rangeStart.getTime() + 3600000);
}
rangeEnd.setHours(0);
if (rangeEnd.getHours() === 23) {
rangeEnd.setTime(rangeEnd.getTime() + 3600000);
}
component.onRangeChanged.emit({
startTime: rangeStart,
endTime: rangeEnd
});
}
}
getStep(mode) {
switch (mode) {
case 'month':
return {
years: 0,
months: 1,
days: 0
};
case 'week':
return {
years: 0,
months: 0,
days: 7
};
case 'day':
return {
years: 0,
months: 0,
days: 1
};
}
}
getAdjacentCalendarDate(mode, direction) {
let calculateCalendarDate = this.currentDate;
const step = this.getStep(mode), year = calculateCalendarDate.getFullYear() + direction * step.years, month = calculateCalendarDate.getMonth() + direction * step.months, date = calculateCalendarDate.getDate() + direction * step.days;
calculateCalendarDate = new Date(year, month, date, 12, 0, 0);
if (mode === 'month') {
const firstDayInNextMonth = new Date(year, month + 1, 1, 12, 0, 0);
if (firstDayInNextMonth.getTime() <= calculateCalendarDate.getTime()) {
calculateCalendarDate = new Date(firstDayInNextMonth.getTime() - 24 * 60 * 60 * 1000);
}
}
return calculateCalendarDate;
}
getAdjacentViewStartTime(component, direction) {
let adjacentCalendarDate = this.getAdjacentCalendarDate(component.mode, direction);
return component.getRange(adjacentCalendarDate).startTime;
}
populateAdjacentViews(component) {
let currentViewStartDate, currentViewData, toUpdateViewIndex, currentViewIndex = component.currentViewIndex;
if (component.direction === 1) {
currentViewStartDate = this.getAdjacentViewStartTime(component, 1);
toUpdateViewIndex = (currentViewIndex + 1) % 3;
component.views[toUpdateViewIndex] = component.getViewData(currentViewStartDate);
}
else if (component.direction === -1) {
currentViewStartDate = this.getAdjacentViewStartTime(component, -1);
toUpdateViewIndex = (currentViewIndex + 2) % 3;
component.views[toUpdateViewIndex] = component.getViewData(currentViewStartDate);
}
else {
if (!component.views) {
currentViewData = [];
currentViewStartDate = component.range.startTime;
currentViewData.push(component.getViewData(currentViewStartDate));
currentViewStartDate = this.getAdjacentViewStartTime(component, 1);
currentViewData.push(component.getViewData(currentViewStartDate));
currentViewStartDate = this.getAdjacentViewStartTime(component, -1);
currentViewData.push(component.getViewData(currentViewStartDate));
component.views = currentViewData;
}
else {
currentViewStartDate = component.range.startTime;
component.views[currentViewIndex] = component.getViewData(currentViewStartDate);
currentViewStartDate = this.getAdjacentViewStartTime(component, -1);
toUpdateViewIndex = (currentViewIndex + 2) % 3;
component.views[toUpdateViewIndex] = component.getViewData(currentViewStartDate);
currentViewStartDate = this.getAdjacentViewStartTime(component, 1);
toUpdateViewIndex = (currentViewIndex + 1) % 3;
component.views[toUpdateViewIndex] = component.getViewData(currentViewStartDate);
}
}
}
loadEvents() {
this.eventSourceChanged.next();
}
slide(direction) {
this.slideChanged.next(direction);
}
update() {
this.slideUpdated.next();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CalendarService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CalendarService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: CalendarService, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
class MonthViewComponent {
constructor(calendarService, zone) {
this.calendarService = calendarService;
this.zone = zone;
this.autoSelect = true;
this.dir = '';
this.lockSwipeToPrev = false;
this.lockSwipeToNext = false;
this.lockSwipes = false;
this.onRangeChanged = new EventEmitter();
this.onEventSelected = new EventEmitter();
this.onTimeSelected = new EventEmitter();
this.onTitleChanged = new EventEmitter();
this.views = [];
this.currentViewIndex = 0;
this.mode = 'month';
this.direction = 0;
this.moveOnSelected = false;
this.inited = false;
}
static getDates(startDate, n) {
const dates = new Array(n), current = new Date(startDate.getTime());
let i = 0;
while (i < n) {
dates[i++] = new Date(current.getTime());
current.setDate(current.getDate() + 1);
}
return dates;
}
ngOnInit() {
if (!this.sliderOptions) {
this.sliderOptions = {};
}
this.sliderOptions.loop = true;
this.sliderOptions.allowSlidePrev = !this.lockSwipeToPrev;
this.sliderOptions.allowSlideNext = !this.lockSwipeToNext;
this.sliderOptions.allowTouchMove = !this.lockSwipes;
if (this.dateFormatter && this.dateFormatter.formatMonthViewDay) {
this.formatDayLabel = this.dateFormatter.formatMonthViewDay;
}
else {
const dayLabelDatePipe = new DatePipe('en-US');
this.formatDayLabel = function (date) {
return dayLabelDatePipe.transform(date, this.formatDay) || '';
};
}
if (this.dateFormatter && this.dateFormatter.formatMonthViewDayHeader) {
this.formatDayHeaderLabel = this.dateFormatter.formatMonthViewDayHeader;
}
else {
const datePipe = new DatePipe(this.locale);
this.formatDayHeaderLabel = function (date) {
return datePipe.transform(date, this.formatDayHeader) || '';
};
}
if (this.dateFormatter && this.dateFormatter.formatMonthViewTitle) {
this.formatTitle = this.dateFormatter.formatMonthViewTitle;
}
else {
const datePipe = new DatePipe(this.locale);
this.formatTitle = function (date) {
return datePipe.transform(date, this.formatMonthTitle) || '';
};
}
this.refreshView();
this.inited = true;
this.currentDateChangedFromParentSubscription = this.calendarService.currentDateChangedFromParent$.subscribe(currentDate => {
this.refreshView();
});
this.eventSourceChangedSubscription = this.calendarService.eventSourceChanged$.subscribe(() => {
this.onDataLoaded();
});
this.slideChangedSubscription = this.calendarService.slideChanged$.subscribe(direction => {
if (direction === 1) {
this.slider.slideNext();
}
else if (direction === -1) {
this.slider.slidePrev();
}
});
this.slideUpdatedSubscription = this.calendarService.slideUpdated$.subscribe(() => {
this.slider.update();
});
}
ngOnDestroy() {
if (this.currentDateChangedFromParentSubscription) {
this.currentDateChangedFromParentSubscription.unsubscribe();
this.currentDateChangedFromParentSubscription = undefined;
}
if (this.eventSourceChangedSubscription) {
this.eventSourceChangedSubscription.unsubscribe();
this.eventSourceChangedSubscription = undefined;
}
if (this.slideChangedSubscription) {
this.slideChangedSubscription.unsubscribe();
this.slideChangedSubscription = undefined;
}
if (this.slideUpdatedSubscription) {
this.slideUpdatedSubscription.unsubscribe();
this.slideUpdatedSubscription = undefined;
}
}
ngOnChanges(changes) {
if (!this.inited) {
return;
}
const eventSourceChange = changes['eventSource'];
if (eventSourceChange && eventSourceChange.currentValue) {
this.onDataLoaded();
}
const lockSwipeToPrev = changes['lockSwipeToPrev'];
if (lockSwipeToPrev) {
this.slider.allowSlidePrev = !lockSwipeToPrev.currentValue;
}
const lockSwipeToNext = changes['lockSwipeToNext'];
if (lockSwipeToNext) {
this.slider.allowSlideNext = !lockSwipeToNext.currentValue;
}
const lockSwipes = changes['lockSwipes'];
if (lockSwipes) {
this.slider.allowTouchMove = !lockSwipes.currentValue;
}
}
ngAfterViewInit() {
this.slider = new Swiper(this.swiperElement?.nativeElement, this.sliderOptions);
let me = this;
this.slider.on('slideNextTransitionEnd', function () {
me.onSlideChanged(1);
});
this.slider.on('slidePrevTransitionEnd', function () {
me.onSlideChanged(-1);
});
if (this.dir == 'rtl') {
this.slider.changeLanguageDirection('rtl');
}
const title = this.getTitle();
this.onTitleChanged.emit(title);
}
setSwiperInstance(swiper) {
this.slider = swiper;
}
onSlideChanged(direction) {
this.currentViewIndex = (this.currentViewIndex + direction + 3) % 3;
this.move(direction);
}
move(direction) {
if (direction === 0) {
return;
}
this.direction = direction;
if (!this.moveOnSelected) {
const adjacentDate = this.calendarService.getAdjacentCalendarDate(this.mode, direction);
this.calendarService.setCurrentDate(adjacentDate);
}
this.refreshView();
this.direction = 0;
this.moveOnSelected = false;
}
createDateObject(date) {
let disabled = false;
if (this.markDisabled) {
disabled = this.markDisabled(date);
}
return {
date,
events: [],
label: this.formatDayLabel(date),
secondary: false,
disabled
};
}
getViewData(startTime) {
const startDate = startTime, date = startDate.getDate(), month = (startDate.getMonth() + (date !== 1 ? 1 : 0)) % 12;
const dates = MonthViewComponent.getDates(startDate, 42);
const days = [];
for (let i = 0; i < 42; i++) {
const dateObject = this.createDateObject(dates[i]);
dateObject.secondary = dates[i].getMonth() !== month;
days[i] = dateObject;
}
const dayHeaders = [];
for (let i = 0; i < 7; i++) {
dayHeaders.push(this.formatDayHeaderLabel(days[i].date));
}
return {
dates: days,
dayHeaders
};
}
getHighlightClass(date) {
let className = '';
if (date.hasEvent) {
if (date.secondary) {
className = 'monthview-secondary-with-event';
}
else {
className = 'monthview-primary-with-event';
}
}
if (date.selected) {
if (className) {
className += ' ';
}
className += 'monthview-selected';
}
if (date.current) {
if (className) {
className += ' ';
}
className += 'monthview-current';
}
if (date.secondary) {
if (className) {
className += ' ';
}
className += 'text-muted';
}
if (date.disabled) {
if (className) {
className += ' ';
}
className += 'monthview-disabled';
}
return className;
}
getRange(currentDate) {
const year = currentDate.getFullYear(), month = currentDate.getMonth(), firstDayOfMonth = new Date(year, month, 1, 12, 0, 0), // set hour to 12 to avoid DST problem
difference = this.startingDayMonth - firstDayOfMonth.getDay(), numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : -difference, startDate = new Date(firstDayOfMonth.getTime());
if (numDisplayedFromPreviousMonth > 0) {
startDate.setDate(-numDisplayedFromPreviousMonth + 1);
}
const endDate = new Date(startDate.getTime());
endDate.setDate(endDate.getDate() + 42);
return {
startTime: startDate,
endTime: endDate
};
}
onDataLoaded() {
const range = this.range, eventSource = this.eventSource, len = eventSource ? eventSource.length : 0, startTime = range.startTime, endTime = range.endTime, utcStartTime = Date.UTC(startTime.getFullYear(), startTime.getMonth(), startTime.getDate()), utcEndTime = Date.UTC(endTime.getFullYear(), endTime.getMonth(), endTime.getDate()), currentViewIndex = this.currentViewIndex, dates = this.views[currentViewIndex].dates, oneDay = 86400000, eps = 0.0006;
for (let r = 0; r < 42; r += 1) {
if (dates[r].hasEvent) {
dates[r].hasEvent = false;
dates[r].events = [];
}
}
for (let i = 0; i < len; i += 1) {
const event = eventSource[i], eventStartTime = event.startTime, eventEndTime = event.endTime;
let eventUTCStartTime, eventUTCEndTime;
if (event.allDay) {
eventUTCStartTime = eventStartTime.getTime();
eventUTCEndTime = eventEndTime.getTime();
}
else {
eventUTCStartTime = Date.UTC(eventStartTime.getFullYear(), eventStartTime.getMonth(), eventStartTime.getDate());
eventUTCEndTime = Date.UTC(eventEndTime.getFullYear(), eventEndTime.getMonth(), eventEndTime.getDate() + 1);
}
if (eventUTCEndTime <= utcStartTime || eventUTCStartTime >= utcEndTime) {
continue;
}
let timeDifferenceStart, timeDifferenceEnd;
if (eventUTCStartTime < utcStartTime) {
timeDifferenceStart = 0;
}
else {
timeDifferenceStart = (eventUTCStartTime - utcStartTime) / oneDay;
}
if (eventUTCEndTime > utcEndTime) {
timeDifferenceEnd = (utcEndTime - utcStartTime) / oneDay;
}
else {
timeDifferenceEnd = (eventUTCEndTime - utcStartTime) / oneDay;
}
let index = Math.floor(timeDifferenceStart);
const endIndex = Math.ceil(timeDifferenceEnd - eps);
while (index < endIndex) {
dates[index].hasEvent = true;
let eventSet = dates[index].events;
if (eventSet) {
eventSet.push(event);
}
else {
eventSet = [];
eventSet.push(event);
dates[index].events = eventSet;
}
index += 1;
}
}
for (let r = 0; r < 42; r += 1) {
if (dates[r].hasEvent) {
dates[r].events.sort(this.compareEvent);
}
}
if (this.autoSelect) {
let findSelected = false;
for (let r = 0; r < 42; r += 1) {
if (dates[r].selected) {
this.selectedDate = dates[r];
findSelected = true;
break;
}
}
if (findSelected && this.selectedDate) {
this.onTimeSelected.emit({
selectedTime: this.selectedDate.date,
events: this.selectedDate.events,
disabled: this.selectedDate.disabled
});
}
}
}
refreshView() {
this.range = this.getRange(this.calendarService.currentDate);
if (this.inited) {
const title = this.getTitle();
this.onTitleChanged.emit(title);
}
this.calendarService.populateAdjacentViews(this);
this.updateCurrentView(this.range.startTime, this.views[this.currentViewIndex]);
this.calendarService.rangeChanged(this);
}
getTitle() {
const currentViewStartDate = this.range.startTime, date = currentViewStartDate.getDate(), month = (currentViewStartDate.getMonth() + (date !== 1 ? 1 : 0)) % 12, year = currentViewStartDate.getFullYear() + (date !== 1 && month === 0 ? 1 : 0), headerDate = new Date(year, month, 1, 12, 0, 0, 0);
return this.formatTitle(headerDate);
}
compareEvent(event1, event2) {
if (event1.allDay) {
return 1;
}
else if (event2.allDay) {
return -1;
}
else {
return (event1.startTime.getTime() - event2.startTime.getTime());
}
}
select(viewDate) {
if (!this.views) {
return;
}
const selectedDate = viewDate.date, events = viewDate.events;
if (!viewDate.disabled) {
const dates = this.views[this.currentViewIndex].dates, currentCalendarDate = this.calendarService.currentDate, currentMonth = currentCalendarDate.getMonth(), currentYear = currentCalendarDate.getFullYear(), selectedMonth = selectedDate.getMonth(), selectedYear = selectedDate.getFullYear();
let direction = 0;
if (currentYear === selectedYear) {
if (currentMonth !== selectedMonth) {
direction = currentMonth < selectedMonth ? 1 : -1;
}
}
else {
direction = currentYear < selectedYear ? 1 : -1;
}
this.calendarService.setCurrentDate(selectedDate);
if (direction === 0) {
const currentViewStartDate = this.range.startTime, oneDay = 86400000, selectedDayDifference = Math.round((Date.UTC(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate()) - Date.UTC(currentViewStartDate.getFullYear(), currentViewStartDate.getMonth(), currentViewStartDate.getDate())) / oneDay);
for (let r = 0; r < 42; r += 1) {
dates[r].selected = false;
}
if (selectedDayDifference >= 0 && selectedDayDifference < 42) {
dates[selectedDayDifference].selected = true;
this.selectedDate = dates[selectedDayDifference];
}
}
else {
this.moveOnSelected = true;
this.slideView(direction);
}
}
this.onTimeSelected.emit({ selectedTime: selectedDate, events, disabled: viewDate.disabled });
}
slideView(direction) {
if (direction === 1) {
this.slider.slideNext();
}
else if (direction === -1) {
this.slider.slidePrev();
}
}
updateCurrentView(currentViewStartDate, view) {
const currentCalendarDate = this.calendarService.currentDate, today = new Date(), oneDay = 86400000, selectedDayDifference = Math.round((Date.UTC(currentCalendarDate.getFullYear(), currentCalendarDate.getMonth(), currentCalendarDate.getDate()) - Date.UTC(currentViewStartDate.getFullYear(), currentViewStartDate.getMonth(), currentViewStartDate.getDate())) / oneDay), currentDayDifference = Math.round((Date.UTC(today.getFullYear(), today.getMonth(), today.getDate()) - Date.UTC(currentViewStartDate.getFullYear(), currentViewStartDate.getMonth(), currentViewStartDate.getDate())) / oneDay);
for (let r = 0; r < 42; r += 1) {
view.dates[r].selected = false;
}
if (selectedDayDifference >= 0 && selectedDayDifference < 42 && !view.dates[selectedDayDifference].disabled && (this.autoSelect || this.moveOnSelected)) {
view.dates[selectedDayDifference].selected = true;
this.selectedDate = view.dates[selectedDayDifference];
}
else {
this.selectedDate = undefined;
}
if (currentDayDifference >= 0 && currentDayDifference < 42) {
view.dates[currentDayDifference].current = true;
}
}
eventSelected(event) {
this.onEventSelected.emit(event);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MonthViewComponent, deps: [{ token: CalendarService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: MonthViewComponent, isStandalone: false, selector: "monthview", inputs: { monthviewDisplayEventTemplate: "monthviewDisplayEventTemplate", monthviewInactiveDisplayEventTemplate: "monthviewInactiveDisplayEventTemplate", monthviewEventDetailTemplate: "monthviewEventDetailTemplate", formatDay: "formatDay", formatDayHeader: "formatDayHeader", formatMonthTitle: "formatMonthTitle", eventSource: "eventSource", startingDayMonth: "startingDayMonth", showEventDetail: "showEventDetail", noEventsLabel: "noEventsLabel", autoSelect: "autoSelect", markDisabled: "markDisabled", locale: "locale", dateFormatter: "dateFormatter", dir: "dir", lockSwipeToPrev: "lockSwipeToPrev", lockSwipeToNext: "lockSwipeToNext", lockSwipes: "lockSwipes", sliderOptions: "sliderOptions" }, outputs: { onRangeChanged: "onRangeChanged", onEventSelected: "onEventSelected", onTimeSelected: "onTimeSelected", onTitleChanged: "onTitleChanged" }, viewQueries: [{ propertyName: "swiperElement", first: true, predicate: ["monthViewSwiper"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"swiper monthview-swiper\" #monthViewSwiper>\r\n <div class=\"swiper-wrapper\">\r\n <div class=\"swiper-slide\">\r\n <table *ngIf=\"0===currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let dayHeader of views[0].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\" tappable (click)=\"select(views[0].dates[row*7+col])\"\r\n [ngClass]=\"getHighlightClass(views[0].dates[row*7+col])\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[0], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n <table *ngIf=\"0!==currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr class=\"text-center\">\r\n <th *ngFor=\"let dayHeader of views[0].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewInactiveDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[0], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n <tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"swiper-slide\">\r\n <table *ngIf=\"1===currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let dayHeader of views[1].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\" tappable (click)=\"select(views[1].dates[row*7+col])\"\r\n [ngClass]=\"getHighlightClass(views[1].dates[row*7+col])\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[1], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n <table *ngIf=\"1!==currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr class=\"text-center\">\r\n <th *ngFor=\"let dayHeader of views[1].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewInactiveDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[1], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n <tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"swiper-slide\">\r\n <table *ngIf=\"2===currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let dayHeader of views[2].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\" tappable (click)=\"select(views[2].dates[row*7+col])\"\r\n [ngClass]=\"getHighlightClass(views[2].dates[row*7+col])\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[2], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n <table *ngIf=\"2!==currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr class=\"text-center\">\r\n <th *ngFor=\"let dayHeader of views[2].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewInactiveDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[2], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n <tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n <ng-template [ngTemplateOutlet]=\"monthviewEventDetailTemplate\"\r\n [ngTemplateOutletContext]=\"{showEventDetail:showEventDetail, selectedDate: selectedDate, noEventsLabel: noEventsLabel}\">\r\n </ng-template>\r\n</div>", styles: [".text-muted{color:#999}.table-fixed{table-layout:fixed}.table{width:100%;max-width:100%;background-color:transparent}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:20px;vertical-align:top}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>thead:first-child>tr:first-child>th,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.monthview-primary-with-event{background-color:#3a87ad;color:#fff}.monthview-current{background-color:#f0f0f0}.monthview-selected{background-color:#090;color:#fff}.monthview-datetable td.monthview-disabled{color:#d3d3d3;cursor:default}.monthview-datetable th{text-align:center}.monthview-datetable td{cursor:pointer;text-align:center}.monthview-secondary-with-event{background-color:#d9edf7}::-webkit-scrollbar,*::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: MonthViewComponent, decorators: [{
type: Component,
args: [{ selector: 'monthview', standalone: false, template: "<div class=\"swiper monthview-swiper\" #monthViewSwiper>\r\n <div class=\"swiper-wrapper\">\r\n <div class=\"swiper-slide\">\r\n <table *ngIf=\"0===currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let dayHeader of views[0].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\" tappable (click)=\"select(views[0].dates[row*7+col])\"\r\n [ngClass]=\"getHighlightClass(views[0].dates[row*7+col])\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[0], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n <table *ngIf=\"0!==currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr class=\"text-center\">\r\n <th *ngFor=\"let dayHeader of views[0].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewInactiveDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[0], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n <tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"swiper-slide\">\r\n <table *ngIf=\"1===currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let dayHeader of views[1].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\" tappable (click)=\"select(views[1].dates[row*7+col])\"\r\n [ngClass]=\"getHighlightClass(views[1].dates[row*7+col])\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[1], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n <table *ngIf=\"1!==currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr class=\"text-center\">\r\n <th *ngFor=\"let dayHeader of views[1].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewInactiveDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[1], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n <tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n <div class=\"swiper-slide\">\r\n <table *ngIf=\"2===currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr>\r\n <th *ngFor=\"let dayHeader of views[2].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\" tappable (click)=\"select(views[2].dates[row*7+col])\"\r\n [ngClass]=\"getHighlightClass(views[2].dates[row*7+col])\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[2], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n <table *ngIf=\"2!==currentViewIndex\" class=\"table table-bordered table-fixed monthview-datetable\">\r\n <thead>\r\n <tr class=\"text-center\">\r\n <th *ngFor=\"let dayHeader of views[2].dayHeaders\">\r\n <small>{{dayHeader}}</small>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of [0,1,2,3,4,5]\">\r\n <td *ngFor=\"let col of [0,1,2,3,4,5,6]\">\r\n <ng-template [ngTemplateOutlet]=\"monthviewInactiveDisplayEventTemplate\"\r\n [ngTemplateOutletContext]=\"{view: views[2], row: row, col: col}\">\r\n </ng-template>\r\n </td>\r\n <tr>\r\n </tbody>\r\n </table>\r\n </div>\r\n </div>\r\n <ng-template [ngTemplateOutlet]=\"monthviewEventDetailTemplate\"\r\n [ngTemplateOutletContext]=\"{showEventDetail:showEventDetail, selectedDate: selectedDate, noEventsLabel: noEventsLabel}\">\r\n </ng-template>\r\n</div>", styles: [".text-muted{color:#999}.table-fixed{table-layout:fixed}.table{width:100%;max-width:100%;background-color:transparent}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:20px;vertical-align:top}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>thead:first-child>tr:first-child>th,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.monthview-primary-with-event{background-color:#3a87ad;color:#fff}.monthview-current{background-color:#f0f0f0}.monthview-selected{background-color:#090;color:#fff}.monthview-datetable td.monthview-disabled{color:#d3d3d3;cursor:default}.monthview-datetable th{text-align:center}.monthview-datetable td{cursor:pointer;text-align:center}.monthview-secondary-with-event{background-color:#d9edf7}::-webkit-scrollbar,*::-webkit-scrollbar{display:none}\n"] }]
}], ctorParameters: () => [{ type: CalendarService }, { type: i0.NgZone }], propDecorators: { swiperElement: [{
type: ViewChild,
args: ['monthViewSwiper']
}], monthviewDisplayEventTemplate: [{
type: Input
}], monthviewInactiveDisplayEventTemplate: [{
type: Input
}], monthviewEventDetailTemplate: [{
type: Input
}], formatDay: [{
type: Input
}], formatDayHeader: [{
type: Input
}], formatMonthTitle: [{
type: Input
}], eventSource: [{
type: Input
}], startingDayMonth: [{
type: Input
}], showEventDetail: [{
type: Input
}], noEventsLabel: [{
type: Input
}], autoSelect: [{
type: Input
}], markDisabled: [{
type: Input
}], locale: [{
type: Input
}], dateFormatter: [{
type: Input
}], dir: [{
type: Input
}], lockSwipeToPrev: [{
type: Input
}], lockSwipeToNext: [{
type: Input
}], lockSwipes: [{
type: Input
}], sliderOptions: [{
type: Input
}], onRangeChanged: [{
type: Output
}], onEventSelected: [{
type: Output
}], onTimeSelected: [{
type: Output
}], onTitleChanged: [{
type: Output
}] } });
class initPositionScrollComponent {
constructor(el, ngZone) {
this.ngZone = ngZone;
this.onScroll = new EventEmitter();
this.listenerAttached = false;
this.element = el;
}
ngOnChanges(changes) {
let initPosition = changes['initPosition'];
if (initPosition && initPosition.currentValue !== undefined && this.scrollContent && initPosition.currentValue != this.scrollContent.scrollTop) {
const me = this;
this.ngZone.run(() => {
me.scrollContent.scrollTop = initPosition.currentValue;
});
}
}
ngAfterViewInit() {
const scrollContent = this.scrollContent = this.element.nativeElement.querySelector('.scroll-content');
if (this.initPosition !== undefined) {
scrollContent.scrollTop = this.initPosition;
}
if (this.emitEvent && !this.listenerAttached) {
let onScroll = this.onScroll;
let me = this;
this.handler = function () {
if (me.initPosition != scrollContent.scrollTop) {
onScroll.emit(scrollContent.scrollTop);
}
};
this.listenerAttached = true;
scrollContent.addEventListener('scroll', this.handler);
}
}
ngOnDestroy() {
if (this.listenerAttached) {
this.scrollContent.removeEventListener('scroll', this.handler);
this.listenerAttached = false;
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: initPositionScrollComponent, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: initPositionScrollComponent, isStandalone: false, selector: "init-position-scroll", inputs: { initPosition: "initPosition", emitEvent: "emitEvent" }, outputs: { onScroll: "onScroll" }, usesOnChanges: true, ngImport: i0, template: `
<div class="scroll-content" style="height:100%">
<ng-content></ng-content>
</div>
`, isInline: true, styles: [".scroll-content{overflow-y:auto;overflow-x:hidden}\n"], encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: initPositionScrollComponent, decorators: [{
type: Component,
args: [{ selector: 'init-position-scroll', template: `
<div class="scroll-content" style="height:100%">
<ng-content></ng-content>
</div>
`, encapsulation: ViewEncapsulation.None, standalone: false, styles: [".scroll-content{overflow-y:auto;overflow-x:hidden}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { initPosition: [{
type: Input
}], emitEvent: [{
type: Input
}], onScroll: [{
type: Output
}] } });
class WeekViewComponent {
constructor(calendarService, elm, zone) {
this.calendarService = calendarService;
this.elm = elm;
this.zone = zone;
this.class = true;
this.autoSelect = true;
this.dir = '';
this.scrollToHour = 0;
this.onRangeChanged = new EventEmitter();
this.onEventSelected = new EventEmitter();
this.onTimeSelected = new EventEmitter();
this.onDayHeaderSelected = new EventEmitter();
this.onTitleChanged = new EventEmitter();
this.sliderIndexList = [0, 1, 2];
this.views = [];
this.currentViewIndex = 0;
this.direction = 0;
this.mode = 'week';
this.inited = false;
}
static createDateObjects(startTime, startHour, endHour, timeInterval) {
const times = [], currentHour = 0, currentDate = startTime.getDate();
let hourStep, minStep;
if (timeInterval < 1) {
hourStep = Math.floor(1 / timeInterval);
minStep = 60;
}
else {
hourStep = 1;
minStep = Math.floor(60 / timeInterval);
}
for (let hour = startHour; hour < endHour; hour += hourStep) {
for (let interval = 0; interval < 60; interval += minStep) {
const row = [];
for (let day = 0; day < 7; day += 1) {
const time = new Date(startTime.getTime());
time.setHours(currentHour + hour, interval);
time.setDate(currentDate + day);
row.push({
events: [],
time
});
}
times.push(row);
}
}
return times;
}
static getDates(startTime, n) {
const dates = new Array(n), current = new Date(startTime.getTime());
let i = 0;
while (i < n) {
dates[i++] = {
date: new Date(current.getTime()),
events: [],
dayHeader: ''
};
current.setDate(current.getDate() + 1);
}
return dates;
}
static compareEventByStartOffset(eventA, eventB) {
return eventA.startOffset - eventB.startOffset;
}
static calculateWidth(orderedEvents, size, hourParts) {
const totalSize = size * hourParts, cells = new Array(totalSize);
// sort by position in descending order, the right most columns should be calculated first
orderedEvents.sort((eventA, eventB) => {
return eventB.position - eventA.position;
});
for (let i = 0; i < totalSize; i += 1) {
cells[i] = {
calculated: false,
events: []
};
}
const len = orderedEvents.length;
for (let i = 0; i < len; i += 1) {
const event = orderedEvents[i];
let index = event.startIndex * hourParts + event.startOffset;
while (index < event.endIndex * hourParts - event.endOffset) {
cells[index].events.push(event);
index += 1;
}
}
let i = 0;
while (i < len) {
let event = orderedEvents[i];
if (!event.overlapNumber) {
const overlapNumber = event.position + 1;
event.overlapNumber = overlapNumber;
const eventQueue = [event];
while (event = eventQueue.shift()) {
let index = event.startIndex * hourParts + event.startOffset;
while (index < event.endIndex * hourParts - event.endOffset) {
if (!cells[index].calculated) {
cells[index].calculated = true;
if (cells[index].events) {
const eventCountInCell = cells[index].events.le