angular-calendar-timeline
Version:
A timeline for angular that shows events on a timeline board in different modes: days, weeks, and months.
922 lines (899 loc) • 88.6 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, inject, Inject, EventEmitter, Component, ChangeDetectionStrategy, Input, Output, ElementRef, PLATFORM_ID, HostListener, NgModule } from '@angular/core';
import * as i1 from '@angular/common';
import { formatDate, getLocaleDayNames, FormStyle, TranslationWidth, isPlatformBrowser, CommonModule } from '@angular/common';
import { BehaviorSubject, Subject, takeUntil, interval } from 'rxjs';
import { startWith } from 'rxjs/operators';
import { __decorate } from 'tslib';
import * as i2 from 'angular-resizable-element';
import { ResizableModule } from 'angular-resizable-element';
import * as i3 from 'angular-draggable-droppable';
import { DragAndDropModule } from 'angular-draggable-droppable';
class DateHelpers {
static generateDateId(date) {
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-${date.getHours()}-${date.getMinutes()}`;
}
static lastDayOfMonth(date) {
const dateWithLastDayOfMonth = new Date(date);
dateWithLastDayOfMonth.setMonth(dateWithLastDayOfMonth.getMonth() + 1);
dateWithLastDayOfMonth.setDate(0);
return dateWithLastDayOfMonth;
}
static getDaysInMonth(date) {
return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
}
static firstMondayOfMonth(date) {
const firstDay = new Date(new Date(date).setDate(1));
const monday = DateHelpers.firstDayOfWeek(firstDay);
return monday.getMonth() === date.getMonth() ? monday : new Date(monday.setDate(monday.getDate() + 7));
}
static firstDayOfWeek(date) {
date = new Date(date);
const first = date.getDate() - date.getDay() + 1;
return new Date(new Date(date).setDate(first));
}
static lastDayOfWeek(date) {
date = new Date(date);
const dayOfWeek = date.getDay();
const diffToSunday = (dayOfWeek === 0) ? 0 : 7 - dayOfWeek;
date.setDate(date.getDate() + diffToSunday);
return date;
}
static dayBeginningTime(day) {
day = new Date(day);
day.setHours(0, 0, 0, 0);
return day;
}
static dayEndingTime(day) {
day = new Date(day);
day.setHours(23, 59, 59, 999);
return day;
}
}
var MillisecondsToTime;
(function (MillisecondsToTime) {
MillisecondsToTime[MillisecondsToTime["Minute"] = 60000] = "Minute";
MillisecondsToTime[MillisecondsToTime["Day"] = 86400000] = "Day";
MillisecondsToTime[MillisecondsToTime["Week"] = 604800000] = "Week";
})(MillisecondsToTime || (MillisecondsToTime = {}));
class ItemsIterator {
constructor() {
this._items = [];
}
get items() {
return this._items;
}
setItems(items) {
this._items = items;
this._validate();
this._createItemsLevels();
}
isEmpty() {
return !this._items?.length;
}
getFirstItem(onlyVisible) {
let firstItem = null;
this.forEach((item, parent) => {
if (!item.startDate || !item.endDate) {
return;
}
if (!firstItem || new Date(firstItem.startDate).getTime() > new Date(item.startDate).getTime()) {
firstItem = item;
}
}, onlyVisible);
return firstItem;
}
getLastItem(onlyVisible) {
let lastItem = null;
this.forEach((item, parent) => {
if (!item.startDate || !item.endDate) {
return;
}
if (!lastItem || new Date(lastItem.endDate).getTime() < new Date(item.endDate).getTime()) {
lastItem = item;
}
}, onlyVisible);
return lastItem;
}
forEach(handler, onlyVisible = false) {
function iterateAll(items, parent) {
(items ?? []).forEach(item => {
handler(item, parent);
iterateAll(item.streamItems ?? [], item);
if (!onlyVisible || item.childrenItemsExpanded) {
iterateAll(item.childrenItems ?? [], item);
}
});
}
iterateAll(this._items, null);
}
_createItemsLevels() {
this.forEach((item, parent) => {
if (item.streamItems) {
item._streamLevels = this._createItemLevels(item);
}
});
}
_createItemLevels(item) {
const levels = [];
item.streamItems.forEach(item => {
let isLevelFound = false;
let currentLevelIndex = 0;
while (!isLevelFound) {
const levelItems = levels[currentLevelIndex];
if (!levelItems) {
levels[currentLevelIndex] = [item];
isLevelFound = true;
break;
}
const isItemCollides = levelItems.some(levelItem => this._isItemsCollides(levelItem, item));
if (!isItemCollides) {
levels[currentLevelIndex].push(item);
isLevelFound = true;
break;
}
currentLevelIndex++;
}
});
return levels;
}
_isItemsCollides(item1, item2) {
const item1Start = item1._left;
const item1End = item1._left + item1._width;
const item2Start = item2._left;
const item2End = item2._left + item2._width;
return item1Start === item2Start || item1End === item2End ||
item1End > item2Start && item1Start < item2End ||
item2End > item1Start && item2Start < item1End;
}
_validate() {
this.forEach((item) => {
if ((item.startDate && !item.endDate) || (item.endDate && !item.startDate)) {
this._removeItemDates(item);
}
if (item.streamItems) {
this._removeItemDates(item);
}
});
}
_removeItemDates(item) {
delete item.startDate;
delete item.endDate;
}
}
class ZoomsHandler {
get activeZoom() {
return this._activeZoom$.value;
}
get zooms() {
return this._zooms;
}
constructor(zooms) {
this._activeZoom$ = new BehaviorSubject(null);
this.activeZoom$ = this._activeZoom$.asObservable();
this.setZooms(zooms);
}
setZooms(zooms) {
this._zooms = (zooms ?? []).map((item, index) => ({ ...item, index }));
this._activeZoom$.next(this.getLastZoom());
}
getFirstZoom() {
return this._zooms[0];
}
getLastZoom() {
return this._zooms[this._zooms.length - 1];
}
zoomIn() {
let newZoomIndex = this.activeZoom.index + 1;
const lastZoomIndex = this.getLastZoom().index;
if (newZoomIndex > lastZoomIndex) {
newZoomIndex = lastZoomIndex;
}
this.changeActiveZoom(this._zooms[newZoomIndex]);
}
zoomOut() {
let newZoomIndex = this.activeZoom.index - 1;
const firstZoomIndex = this.getFirstZoom().index;
if (newZoomIndex < firstZoomIndex) {
newZoomIndex = firstZoomIndex;
}
this.changeActiveZoom(this._zooms[newZoomIndex]);
}
changeActiveZoom(zoom) {
if (zoom) {
this._activeZoom$.next(this._zooms[this._findZoomIndex(zoom)]);
}
}
isZoomActive(zoom) {
return this._findZoomIndex(zoom) === this.activeZoom.index;
}
_findZoomIndex(zoom) {
return this._zooms.findIndex(i => i.columnWidth === zoom.columnWidth && i.viewMode === zoom.viewMode);
}
}
var TimelineViewMode;
(function (TimelineViewMode) {
TimelineViewMode[TimelineViewMode["Month"] = 101] = "Month";
TimelineViewMode[TimelineViewMode["Week"] = 102] = "Week";
TimelineViewMode[TimelineViewMode["Day"] = 103] = "Day";
})(TimelineViewMode || (TimelineViewMode = {}));
const ZOOMS = new InjectionToken('Zooms');
const DefaultZooms = [
{ columnWidth: 45, viewMode: TimelineViewMode.Month },
{ columnWidth: 60, viewMode: TimelineViewMode.Month },
{ columnWidth: 80, viewMode: TimelineViewMode.Month },
{ columnWidth: 110, viewMode: TimelineViewMode.Month },
{ columnWidth: 140, viewMode: TimelineViewMode.Month },
{ columnWidth: 200, viewMode: TimelineViewMode.Month },
{ columnWidth: 240, viewMode: TimelineViewMode.Month },
{ columnWidth: 60, viewMode: TimelineViewMode.Week },
{ columnWidth: 80, viewMode: TimelineViewMode.Week },
{ columnWidth: 110, viewMode: TimelineViewMode.Week },
{ columnWidth: 140, viewMode: TimelineViewMode.Week },
{ columnWidth: 200, viewMode: TimelineViewMode.Week },
{ columnWidth: 240, viewMode: TimelineViewMode.Week },
{ columnWidth: 45, viewMode: TimelineViewMode.Day },
{ columnWidth: 60, viewMode: TimelineViewMode.Day },
{ columnWidth: 80, viewMode: TimelineViewMode.Day },
{ columnWidth: 110, viewMode: TimelineViewMode.Day },
{ columnWidth: 140, viewMode: TimelineViewMode.Day },
{ columnWidth: 200, viewMode: TimelineViewMode.Day },
{ columnWidth: 240, viewMode: TimelineViewMode.Day },
];
class RowDeterminant {
constructor(_itemsIterator) {
this._itemsIterator = _itemsIterator;
this._generateMap();
}
_generateMap() {
const map = [];
const iterate = (items) => {
(items ?? []).forEach(item => {
if (item.streamItems) {
item._streamLevels.forEach((levelArr, index) => {
map.push({ stream: item, items: levelArr });
});
}
else {
map.push({ stream: item, items: [item] });
}
if (item.childrenItemsExpanded) {
iterate(item.childrenItems ?? []);
}
});
};
iterate(this._itemsIterator.items);
this.rows = map;
}
getRowIndexByItem(item) {
let index;
for (let i = 0; i < this.rows.length; i++) {
const group = this.rows[i];
if (item.id === group.stream.id) {
index = i;
break;
}
const hasChild = group.items.find(i => i.id === item.id);
if (hasChild) {
index = i;
}
}
return index;
}
getStreamByRowIndex(index) {
return this.rows[index]?.stream;
}
}
function DatesCacheDecorator() {
return function (target, methodName, descriptor) {
if (!target.__datesCache) {
target.__datesCache = new Map();
}
const originalMethod = descriptor.value;
descriptor.value = function (...args) {
const cacheKey = `${methodName}-${[...args].map(date => DateHelpers.generateDateId(date)).join('-')}`;
if (target.__datesCache.has(cacheKey)) {
return target.__datesCache.get(cacheKey);
}
const result = originalMethod.apply(this, args);
target.__datesCache.set(cacheKey, result);
return result;
};
};
}
class BaseScaleGenerator {
constructor() {
this._config = this._getConfig();
this.formatter = this._config.formatter;
}
getStartDate(itemsBuilder) {
if (this._config.getStartDate) {
return this._config.getStartDate(itemsBuilder);
}
const firstItem = itemsBuilder.getFirstItem(false);
const now = Date.now();
const firstItemTime = new Date(firstItem?.startDate ?? now).getTime();
return this._validateStartDate(firstItemTime < now ? firstItemTime : now);
}
getEndDate(itemsBuilder) {
if (this._config.getEndDate) {
return this._config.getEndDate(itemsBuilder);
}
const lastItem = itemsBuilder.getLastItem(false);
const now = Date.now();
const lastItemDate = new Date(lastItem?.endDate ?? now);
return this._validateEndDate(lastItemDate.getTime() < now ? now : lastItemDate);
}
generateScale(startDate, endDate) {
let currentDate = new Date(startDate);
const endTime = endDate.getTime();
const columns = [];
while (currentDate.getTime() <= endTime) {
const date = new Date(currentDate);
columns.push({
id: DateHelpers.generateDateId(date),
date: date,
index: this._getColumnIndex(date),
groups: this._generateGroups(date),
});
currentDate = this._getNextColumnDate(currentDate);
}
return {
startDate,
endDate,
columns
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseScaleGenerator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseScaleGenerator }); }
}
__decorate([
DatesCacheDecorator()
], BaseScaleGenerator.prototype, "generateScale", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BaseScaleGenerator, decorators: [{
type: Injectable
}], ctorParameters: () => [], propDecorators: { generateScale: [] } });
class DayScaleFormatter {
formatColumn(column, columnWidth, locale) {
if (columnWidth < 65)
return formatDate(column.date, 'dd', locale);
if (columnWidth > 180)
return formatDate(column.date, 'EEEE dd/MM', locale);
return formatDate(column.date, 'EEE dd/MM', locale);
}
formatGroup(group, locale) {
return formatDate(group.date, 'LLLL', locale);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DayScaleFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DayScaleFormatter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DayScaleFormatter, decorators: [{
type: Injectable
}] });
const DAY_SCALE_GENERATOR_CONFIG = new InjectionToken('Day scale config');
const DefaultConfig$2 = {
formatter: new DayScaleFormatter(),
};
class DefaultDayScaleGenerator extends BaseScaleGenerator {
_getConfig() {
return { ...DefaultConfig$2, ...inject(DAY_SCALE_GENERATOR_CONFIG, {}) };
}
_validateStartDate(startDate) {
const countOfEmptyMonthsBefore = 1;
startDate = new Date(startDate);
startDate.setDate(1);
startDate = DateHelpers.dayBeginningTime(startDate);
startDate.setMonth(startDate.getMonth() - countOfEmptyMonthsBefore);
return startDate;
}
_validateEndDate(endDate) {
const countOfEmptyMonthsAfter = 1;
endDate = new Date(endDate);
return new Date(DateHelpers.lastDayOfMonth(endDate).setMonth(endDate.getMonth() + countOfEmptyMonthsAfter));
}
_generateGroups(date) {
date = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0);
return [{ date, id: DateHelpers.generateDateId(date), coverageInPercents: 100 }];
}
_getColumnIndex(date) {
return date.getDate();
}
_getNextColumnDate(date) {
return new Date(date.setDate(date.getDate() + 1));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultDayScaleGenerator, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultDayScaleGenerator }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultDayScaleGenerator, decorators: [{
type: Injectable
}] });
class DayScaleGenerator extends DefaultDayScaleGenerator {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DayScaleGenerator, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DayScaleGenerator }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DayScaleGenerator, decorators: [{
type: Injectable
}] });
class WeekScaleFormatter {
formatColumn(column, columnWidth, locale) {
if (columnWidth > 100) {
const days = getLocaleDayNames(locale, FormStyle.Format, TranslationWidth.Abbreviated);
return `${days[1]}-${days[0]} (${column.index})`;
}
return String(column.index);
}
formatGroup(group, locale) {
return formatDate(group.date, 'LLLL y', locale);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WeekScaleFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WeekScaleFormatter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WeekScaleFormatter, decorators: [{
type: Injectable
}] });
const WEEK_SCALE_GENERATOR_CONFIG = new InjectionToken('Week scale config');
const DefaultConfig$1 = {
formatter: new WeekScaleFormatter(),
};
class DefaultWeekScaleGenerator extends BaseScaleGenerator {
_getConfig() {
return { ...DefaultConfig$1, ...inject(WEEK_SCALE_GENERATOR_CONFIG, {}) };
}
_validateStartDate(startDate) {
const countOfEmptyMonthsBefore = 1;
const newDate = new Date(startDate);
newDate.setMonth(newDate.getMonth() - countOfEmptyMonthsBefore);
return DateHelpers.firstMondayOfMonth(newDate);
}
_validateEndDate(endDate) {
const countOfEmptyMonthsAfter = 1;
const newDate = new Date(endDate);
newDate.setMonth(newDate.getMonth() + countOfEmptyMonthsAfter);
return DateHelpers.lastDayOfWeek(newDate);
}
_generateGroups(date) {
const weekStart = DateHelpers.firstDayOfWeek(date);
const weekEnd = DateHelpers.lastDayOfWeek(date);
const weekRelatedToTwoMonths = weekStart.getMonth() !== weekEnd.getMonth();
const weekStartGroupDate = new Date(weekStart.getFullYear(), weekStart.getMonth(), 1, 0, 0, 0, 0);
const groups = [
{ date: weekStartGroupDate, id: DateHelpers.generateDateId(weekStartGroupDate), coverageInPercents: 100 }
];
if (weekRelatedToTwoMonths) {
groups[0].coverageInPercents = (DateHelpers.getDaysInMonth(weekStart) - (weekStart.getDate() - 1)) / 7 * 100;
const weekEndGroupDate = new Date(weekEnd.getFullYear(), weekEnd.getMonth(), 1, 0, 0, 0, 0);
groups.push({
date: weekEndGroupDate,
id: DateHelpers.generateDateId(weekEndGroupDate),
coverageInPercents: 100 - groups[0].coverageInPercents
});
}
return groups;
}
_getColumnIndex(date) {
const weekMonday = DateHelpers.firstDayOfWeek(date);
return Math.ceil(weekMonday.getDate() / 7);
}
_getNextColumnDate(date) {
return new Date(date.setDate(date.getDate() + 7));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultWeekScaleGenerator, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultWeekScaleGenerator }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultWeekScaleGenerator, decorators: [{
type: Injectable
}] });
class WeekScaleGenerator extends DefaultWeekScaleGenerator {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WeekScaleGenerator, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WeekScaleGenerator }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WeekScaleGenerator, decorators: [{
type: Injectable
}] });
class MonthScaleFormatter {
formatColumn(column, columnWidth, locale) {
if (columnWidth < 65)
return String(column.index);
if (columnWidth > 180)
return formatDate(column.date, 'LLLL', locale);
return formatDate(column.date, 'LLL', locale);
}
formatGroup(group, locale) {
return String(group.date.getFullYear());
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthScaleFormatter, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthScaleFormatter }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthScaleFormatter, decorators: [{
type: Injectable
}] });
const MONTH_SCALE_GENERATOR_CONFIG = new InjectionToken('Month scale config');
const DefaultConfig = {
formatter: new MonthScaleFormatter(),
};
class DefaultMonthScaleGenerator extends BaseScaleGenerator {
_getConfig() {
return { ...DefaultConfig, ...inject(MONTH_SCALE_GENERATOR_CONFIG, {}) };
}
_validateStartDate(startDate) {
const newDate = new Date(startDate);
const countOfEmptyYearsBefore = 1;
newDate.setDate(1);
newDate.setMonth(0);
newDate.setFullYear(newDate.getFullYear() - countOfEmptyYearsBefore);
return newDate;
}
_validateEndDate(endDate) {
const newDate = DateHelpers.lastDayOfMonth(endDate);
const countOfEmptyYearsAfter = 1;
newDate.setMonth(11);
newDate.setFullYear(newDate.getFullYear() + countOfEmptyYearsAfter);
return newDate;
}
_generateGroups(date) {
date = new Date(date.getFullYear(), 1, 0, 0, 0, 0, 0);
return [{ date, id: DateHelpers.generateDateId(date), coverageInPercents: 100 }];
}
_getColumnIndex(date) {
return date.getMonth() + 1;
}
_getNextColumnDate(date) {
return new Date(date.setMonth(date.getMonth() + 1));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultMonthScaleGenerator, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultMonthScaleGenerator }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultMonthScaleGenerator, decorators: [{
type: Injectable
}] });
class MonthScaleGenerator extends DefaultMonthScaleGenerator {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthScaleGenerator, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthScaleGenerator }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MonthScaleGenerator, decorators: [{
type: Injectable
}] });
class BaseViewModeAdaptor {
getMiddleDate(startDate, endDate) {
const uniqueColumns = this.getUniqueColumnsWithinRange(startDate, endDate);
return this.addColumnToDate(this.getBeginningDateOfColumn(startDate), uniqueColumns / 2);
}
}
class DaysViewModeAdaptor extends BaseViewModeAdaptor {
getUniqueColumnsWithinRange(start, end) {
const startDate = new Date(start.getFullYear(), start.getMonth(), start.getDate());
const endDate = new Date(end.getFullYear(), end.getMonth(), end.getDate());
return Math.round(Math.abs((startDate.getTime() - endDate.getTime()) / MillisecondsToTime.Day)) + 1;
}
getDurationInColumns(startDate, endDate) {
return Math.abs((startDate.getTime() - endDate.getTime()) / MillisecondsToTime.Day);
}
addColumnToDate(date, days) {
const newDate = new Date(date);
newDate.setDate(date.getDate() + days);
newDate.setHours(newDate.getHours() + ((days % 1) * 24));
return newDate;
}
getEndingDateOfColumn(date) {
return DateHelpers.dayEndingTime(date);
}
getBeginningDateOfColumn(date) {
return DateHelpers.dayBeginningTime(date);
}
}
__decorate([
DatesCacheDecorator()
], DaysViewModeAdaptor.prototype, "getUniqueColumnsWithinRange", null);
__decorate([
DatesCacheDecorator()
], DaysViewModeAdaptor.prototype, "getDurationInColumns", null);
class WeeksViewModeAdaptor extends BaseViewModeAdaptor {
getUniqueColumnsWithinRange(start, end) {
const monday = DateHelpers.firstDayOfWeek(start);
const last = DateHelpers.lastDayOfWeek(end);
return Math.round(this.getDurationInColumns(monday, last));
}
getDurationInColumns(startDate, endDate) {
return Math.abs((startDate.getTime() - endDate.getTime()) / MillisecondsToTime.Week);
}
addColumnToDate(date, weeks) {
const newDate = new Date(date);
newDate.setDate(date.getDate() + (7 * weeks));
newDate.setHours(newDate.getHours() + (((weeks / 7) % 1) * 24));
return newDate;
}
getBeginningDateOfColumn(date) {
const start = DateHelpers.firstDayOfWeek(new Date(date));
return DateHelpers.dayBeginningTime(start);
}
getEndingDateOfColumn(date) {
const end = DateHelpers.lastDayOfWeek(new Date(date));
return DateHelpers.dayEndingTime(end);
}
}
__decorate([
DatesCacheDecorator()
], WeeksViewModeAdaptor.prototype, "getUniqueColumnsWithinRange", null);
__decorate([
DatesCacheDecorator()
], WeeksViewModeAdaptor.prototype, "getDurationInColumns", null);
class MonthsViewModeAdaptor extends BaseViewModeAdaptor {
getBeginningDateOfColumn(date) {
const start = new Date(date);
start.setDate(1);
return DateHelpers.dayBeginningTime(start);
}
getEndingDateOfColumn(date) {
const end = new Date(date);
end.setDate(DateHelpers.lastDayOfMonth(date).getDate());
return DateHelpers.dayEndingTime(end);
}
getUniqueColumnsWithinRange(startDate, endDate) {
const diff = this._getCountOfFullMonths(startDate, endDate);
return (diff < 0 ? 0 : diff) + 1;
}
getDurationInColumns(startDate, endDate) {
const diff = this._getCountOfFullMonths(startDate, endDate);
const firstMonthCompletedPercent = ((startDate.getDate() - 1) + (startDate.getHours() / 24)) / DateHelpers.getDaysInMonth(startDate);
const secondMonthCompletedPercent = ((endDate.getDate() - 1) + (endDate.getHours() / 24)) / DateHelpers.getDaysInMonth(endDate);
return diff - firstMonthCompletedPercent + secondMonthCompletedPercent;
}
addColumnToDate(date, months) {
const newDate = new Date(date);
newDate.setMonth(date.getMonth() + months);
const days = DateHelpers.getDaysInMonth(newDate) * (months % 1);
newDate.setDate(newDate.getDate() + days);
newDate.setHours(newDate.getHours() + ((days % 1) * 24));
return newDate;
}
_getCountOfFullMonths(startDate, endDate) {
const yearsDiff = endDate.getFullYear() - startDate.getFullYear();
const startMonth = startDate.getMonth();
const endMonth = endDate.getMonth() + (12 * yearsDiff);
return endMonth - startMonth;
}
}
__decorate([
DatesCacheDecorator()
], MonthsViewModeAdaptor.prototype, "getUniqueColumnsWithinRange", null);
__decorate([
DatesCacheDecorator()
], MonthsViewModeAdaptor.prototype, "getDurationInColumns", null);
class DefaultStrategyManager {
constructor(_dayGenerator, _weekGenerator, _monthGenerator) {
this._dayGenerator = _dayGenerator;
this._weekGenerator = _weekGenerator;
this._monthGenerator = _monthGenerator;
this._generatorsDictionary = {
[TimelineViewMode.Day]: this._dayGenerator,
[TimelineViewMode.Week]: this._weekGenerator,
[TimelineViewMode.Month]: this._monthGenerator,
};
this._calculatorsDictionary = {
[TimelineViewMode.Day]: new DaysViewModeAdaptor(),
[TimelineViewMode.Week]: new WeeksViewModeAdaptor(),
[TimelineViewMode.Month]: new MonthsViewModeAdaptor(),
};
}
getViewModeAdaptor(viewMode) {
return this._calculatorsDictionary[viewMode];
}
getScaleGenerator(viewMode) {
return this._generatorsDictionary[viewMode];
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultStrategyManager, deps: [{ token: DayScaleGenerator }, { token: WeekScaleGenerator }, { token: MonthScaleGenerator }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultStrategyManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DefaultStrategyManager, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Inject,
args: [DayScaleGenerator]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [WeekScaleGenerator]
}] }, { type: undefined, decorators: [{
type: Inject,
args: [MonthScaleGenerator]
}] }] });
class StrategyManager extends DefaultStrategyManager {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StrategyManager, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StrategyManager }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: StrategyManager, decorators: [{
type: Injectable
}] });
class TimelineItemComponent {
set item(item) {
this._item = item;
item.updateView = () => this._cdr.detectChanges();
this._checkIsInScaleRange();
}
;
set scale(scale) {
this._scale = scale;
this._checkIsInScaleRange();
}
;
get item() {
return this._item;
}
constructor(_cdr, _renderer) {
this._cdr = _cdr;
this._renderer = _renderer;
this.isInScaleRange = true;
this.isItemResizingStarted = false;
this.itemResized = new EventEmitter();
this.itemMoved = new EventEmitter();
}
onItemResizeStart(event) {
this.isItemResizingStarted = true;
this._cdr.markForCheck();
}
onItemResizeEnd(event) {
this.itemResized.emit({ event, item: this._item });
setTimeout(() => this.isItemResizingStarted = false);
}
onItemDragStart(event) {
this._setRowZIndex(1000);
}
onItemDropped(event) {
if (!this.isItemResizingStarted) {
this.itemMoved.emit({ event, item: this._item });
}
this._setRowZIndex(1);
}
_checkIsInScaleRange() {
if (!this._item || !this._scale) {
return;
}
if (!this._item.startDate || !this._item.endDate) {
this.isInScaleRange = true;
this._cdr.markForCheck();
return;
}
this.isInScaleRange = this._scale.startDate.getTime() <= this._item.startDate.getTime()
&& this._scale.endDate.getTime() >= this._item.endDate.getTime();
this._cdr.markForCheck();
}
_setRowZIndex(index) {
this._renderer.setStyle(this.rowContainer, 'z-index', index);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineItemComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimelineItemComponent, selector: "timeline-item", inputs: { item: "item", scale: "scale", rowContainer: "rowContainer", height: "height", rowHeight: "rowHeight", locale: "locale", contentTemplate: "contentTemplate" }, outputs: { itemResized: "itemResized", itemMoved: "itemMoved" }, ngImport: i0, template: "<div class=\"timeline-item\"\r\n *ngIf=\"isInScaleRange\"\r\n ghostElementPositioning='absolute'\r\n mwlResizable\r\n mwlDraggable\r\n [dragActiveClass]=\"'timeline-item_dragging'\"\r\n (dragStart)='onItemDragStart($event)'\r\n (dragEnd)='onItemDropped($event)'\r\n (resizeEnd)='onItemResizeEnd($event)'\r\n (resizeStart)='onItemResizeStart($event)'\r\n [dragAxis]=\"{y: item.canDragY, x: item.canDragX}\"\r\n [enableGhostResize]='true'\r\n [dragSnapGrid]=\"{y: rowHeight}\"\r\n [style.height.px]='height'\r\n [style.left.px]='item?._left'\r\n [style.width.px]='item?._width'>\r\n <div class=\"item-custom-template\" *ngIf=\"contentTemplate; else nameTemplate\">\r\n <ng-container [ngTemplateOutlet]=\"contentTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: item, locale: locale}\"\r\n ></ng-container>\r\n </div>\r\n\r\n <ng-template #nameTemplate>\r\n <div class=\"default-content\">\r\n {{item.name}}\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf='item.canResizeLeft'\r\n [resizeEdges]='{ left: item.canResizeLeft }'\r\n class='resize-handle-left'\r\n mwlResizeHandle\r\n ></div>\r\n <div *ngIf='item.canResizeRight'\r\n [resizeEdges]='{ right: item.canResizeRight }'\r\n class='resize-handle-right'\r\n mwlResizeHandle\r\n ></div>\r\n</div>\r\n", styles: [".timeline-item{height:100%;position:absolute;box-sizing:border-box;overflow:hidden;top:5px}.item-custom-template{width:100%;height:100%;position:relative;box-sizing:border-box}.default-content{height:100%;width:100%;background-color:#098ed2;padding:2px 10px;display:flex;align-items:center;color:#f1f1f1;box-sizing:border-box;border-radius:2px;cursor:pointer}mwlResizable{box-sizing:border-box}.resize-handle-left,.resize-handle-right{position:absolute;height:100%;cursor:col-resize;width:5px;top:0}.resize-handle-left{left:0}.resize-handle-right{right:0}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i2.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }, { kind: "directive", type: i3.DraggableDirective, selector: "[mwlDraggable]", inputs: ["dropData", "dragAxis", "dragSnapGrid", "ghostDragEnabled", "showOriginalElementWhileDragging", "validateDrag", "dragCursor", "dragActiveClass", "ghostElementAppendTo", "ghostElementTemplate", "touchStartLongPress", "autoScroll"], outputs: ["dragPointerDown", "dragStart", "ghostElementCreated", "dragging", "dragEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineItemComponent, decorators: [{
type: Component,
args: [{ selector: 'timeline-item', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"timeline-item\"\r\n *ngIf=\"isInScaleRange\"\r\n ghostElementPositioning='absolute'\r\n mwlResizable\r\n mwlDraggable\r\n [dragActiveClass]=\"'timeline-item_dragging'\"\r\n (dragStart)='onItemDragStart($event)'\r\n (dragEnd)='onItemDropped($event)'\r\n (resizeEnd)='onItemResizeEnd($event)'\r\n (resizeStart)='onItemResizeStart($event)'\r\n [dragAxis]=\"{y: item.canDragY, x: item.canDragX}\"\r\n [enableGhostResize]='true'\r\n [dragSnapGrid]=\"{y: rowHeight}\"\r\n [style.height.px]='height'\r\n [style.left.px]='item?._left'\r\n [style.width.px]='item?._width'>\r\n <div class=\"item-custom-template\" *ngIf=\"contentTemplate; else nameTemplate\">\r\n <ng-container [ngTemplateOutlet]=\"contentTemplate\"\r\n [ngTemplateOutletContext]=\"{$implicit: item, locale: locale}\"\r\n ></ng-container>\r\n </div>\r\n\r\n <ng-template #nameTemplate>\r\n <div class=\"default-content\">\r\n {{item.name}}\r\n </div>\r\n </ng-template>\r\n\r\n <div *ngIf='item.canResizeLeft'\r\n [resizeEdges]='{ left: item.canResizeLeft }'\r\n class='resize-handle-left'\r\n mwlResizeHandle\r\n ></div>\r\n <div *ngIf='item.canResizeRight'\r\n [resizeEdges]='{ right: item.canResizeRight }'\r\n class='resize-handle-right'\r\n mwlResizeHandle\r\n ></div>\r\n</div>\r\n", styles: [".timeline-item{height:100%;position:absolute;box-sizing:border-box;overflow:hidden;top:5px}.item-custom-template{width:100%;height:100%;position:relative;box-sizing:border-box}.default-content{height:100%;width:100%;background-color:#098ed2;padding:2px 10px;display:flex;align-items:center;color:#f1f1f1;box-sizing:border-box;border-radius:2px;cursor:pointer}mwlResizable{box-sizing:border-box}.resize-handle-left,.resize-handle-right{position:absolute;height:100%;cursor:col-resize;width:5px;top:0}.resize-handle-left{left:0}.resize-handle-right{right:0}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }], propDecorators: { item: [{
type: Input
}], scale: [{
type: Input
}], rowContainer: [{
type: Input
}], height: [{
type: Input
}], rowHeight: [{
type: Input
}], locale: [{
type: Input
}], contentTemplate: [{
type: Input
}], itemResized: [{
type: Output
}], itemMoved: [{
type: Output
}] } });
class TimelineDateMarkerComponent {
set scale(scale) {
this._checkIsInScaleRange(scale);
}
;
constructor(_cdr) {
this._cdr = _cdr;
this.isInScaleRange = true;
this.leftPosition = 0;
}
_checkIsInScaleRange(scale) {
const now = Date.now();
this.isInScaleRange = scale.startDate.getTime() <= now && scale.endDate.getTime() >= now;
this._cdr.detectChanges();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineDateMarkerComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimelineDateMarkerComponent, selector: "timeline-date-marker", inputs: { leftPosition: "leftPosition", headerHeight: "headerHeight", customTemplate: "customTemplate", scale: "scale" }, ngImport: i0, template: "<ng-container *ngIf=\"isInScaleRange\">\r\n <ng-container *ngIf=\"customTemplate; else defaultDateMarkerTemplate\"\r\n [ngTemplateOutlet]=\"customTemplate\"\r\n [ngTemplateOutletContext]=\"{leftPosition: leftPosition}\">\r\n </ng-container>\r\n\r\n <ng-template #defaultDateMarkerTemplate>\r\n <div [style.left.px]=\"leftPosition\"\r\n [style.height]=\"'calc(100% - ' + headerHeight + 'px)'\"\r\n class='date-marker'></div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [".date-marker{position:absolute;width:2px;height:100%;background-color:#2ac226;z-index:2;display:flex;flex-direction:column;transform:translate(-50%)}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineDateMarkerComponent, decorators: [{
type: Component,
args: [{ selector: 'timeline-date-marker', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"isInScaleRange\">\r\n <ng-container *ngIf=\"customTemplate; else defaultDateMarkerTemplate\"\r\n [ngTemplateOutlet]=\"customTemplate\"\r\n [ngTemplateOutletContext]=\"{leftPosition: leftPosition}\">\r\n </ng-container>\r\n\r\n <ng-template #defaultDateMarkerTemplate>\r\n <div [style.left.px]=\"leftPosition\"\r\n [style.height]=\"'calc(100% - ' + headerHeight + 'px)'\"\r\n class='date-marker'></div>\r\n </ng-template>\r\n</ng-container>\r\n", styles: [".date-marker{position:absolute;width:2px;height:100%;background-color:#2ac226;z-index:2;display:flex;flex-direction:column;transform:translate(-50%)}\n"] }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { leftPosition: [{
type: Input
}], headerHeight: [{
type: Input
}], customTemplate: [{
type: Input
}], scale: [{
type: Input
}] } });
class TimelineScaleHeaderComponent {
constructor() {
this.groups = [];
}
get columns() {
return this.scale?.columns ?? [];
}
ngOnChanges(changes) {
this._generateGroups();
}
trackById(index, item) {
return item.id;
}
_groupColumnGroups() {
return this.scale.columns.reduce((groupsMap, column) => {
column.groups.forEach(group => {
groupsMap[group.id] = groupsMap[group.id] ?? [];
groupsMap[group.id].push(group);
});
return groupsMap;
}, {});
}
_generateGroups() {
const groupedGroups = this._groupColumnGroups();
this.groups = Object.keys(groupedGroups).map(groupId => ({
id: groupId,
name: this.formatter.formatGroup(groupedGroups[groupId][0], this.locale),
width: groupedGroups[groupId].reduce((acc, curr) => acc + this.zoom.columnWidth * curr.coverageInPercents / 100, 0)
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineScaleHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimelineScaleHeaderComponent, selector: "timeline-scale-header", inputs: { height: "height", scale: "scale", formatter: "formatter", locale: "locale", zoom: "zoom" }, usesOnChanges: true, ngImport: i0, template: "<div class='wrapper' [style.height.px]=\"height\">\r\n <div class='groups' *ngIf=\"groups.length\">\r\n <div *ngFor='let group of groups; trackBy: trackById; index as i'\r\n [style.width.px]='group.width' class='group'>\r\n <div>{{group.name}}</div>\r\n </div>\r\n </div>\r\n <div class='columns'>\r\n <div *ngFor='let column of columns; trackBy: trackById'>\r\n <div class='column' [style.width.px]='zoom.columnWidth'>\r\n {{formatter.formatColumn(column, zoom.columnWidth, locale)}}\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [":host{z-index:9;position:sticky;top:0;display:flex;flex-direction:row;background:#f8f8f8}.wrapper{display:flex;flex-direction:column}.groups{display:flex;flex-grow:3}.groups .group{height:100%;display:flex;align-items:center;justify-content:center;border-bottom:1px solid #d0d0d0;position:relative;box-sizing:border-box;padding:0 4px}.groups .group:first-child:after{display:none}.groups .group:after{content:\"\";position:absolute;width:1px;height:100%;box-sizing:border-box;left:0;top:0;background:#d0d0d0}.columns{display:flex;flex-grow:2}.columns .column{height:100%;position:relative;display:flex;justify-content:center;align-items:center}.columns .column:after{content:\"\";width:1px;height:100%;left:100%;position:absolute;background:#d0d0d0}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelineScaleHeaderComponent, decorators: [{
type: Component,
args: [{ selector: 'timeline-scale-header', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class='wrapper' [style.height.px]=\"height\">\r\n <div class='groups' *ngIf=\"groups.length\">\r\n <div *ngFor='let group of groups; trackBy: trackById; index as i'\r\n [style.width.px]='group.width' class='group'>\r\n <div>{{group.name}}</div>\r\n </div>\r\n </div>\r\n <div class='columns'>\r\n <div *ngFor='let column of columns; trackBy: trackById'>\r\n <div class='column' [style.width.px]='zoom.columnWidth'>\r\n {{formatter.formatColumn(column, zoom.columnWidth, locale)}}\r\n </div>\r\n </div>\r\n </div>\r\n</div>\r\n\r\n", styles: [":host{z-index:9;position:sticky;top:0;display:flex;flex-direction:row;background:#f8f8f8}.wrapper{display:flex;flex-direction:column}.groups{display:flex;flex-grow:3}.groups .group{height:100%;display:flex;align-items:center;justify-content:center;border-bottom:1px solid #d0d0d0;position:relative;box-sizing:border-box;padding:0 4px}.groups .group:first-child:after{display:none}.groups .group:after{content:\"\";position:absolute;width:1px;height:100%;box-sizing:border-box;left:0;top:0;background:#d0d0d0}.columns{display:flex;flex-grow:2}.columns .column{height:100%;position:relative;display:flex;justify-content:center;align-items:center}.columns .column:after{content:\"\";width:1px;height:100%;left:100%;position:absolute;background:#d0d0d0}\n"] }]
}], propDecorators: { height: [{
type: Input
}], scale: [{
type: Input
}], formatter: [{
type: Input
}], locale: [{
type: Input
}], zoom: [{
type: Input
}] } });
class TimelinePanelComponent {
constructor(_cdr) {
this._cdr = _cdr;
this.items = [];
this.childGroupOffset = 15;
this.widthChanged = new EventEmitter();
}
ngOnChanges(changes) {
if (Object.keys(changes).some(key => ['width', 'minWidth', 'maxWidth'].includes(key))) {
this._validateWidth();
}
}
trackById(index, item) {
return item.id;
}
handleResize(event) {
const newWidth = event.rectangle.width;
if (newWidth < this.minWidth || newWidth > this.maxWidth)
return;
this.width = newWidth;
this.widthChanged.emit(this.width);
}
toggleExpand(item) {
item.childrenItemsExpanded = !item.childrenItemsExpanded;
this._cdr.markForCheck();
}
_validateWidth() {
if (this.width < this.minWidth) {
this.width = this.minWidth;
}
if (this.width > this.maxWidth) {
this.width = this.maxWidth;
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TimelinePanelComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TimelinePanelComponent, selector: "timeline-panel", inputs: { items: "items", label: "label", width: "width", resizable: "resizable", minWidth: "minWidth", maxWidth: "maxWidth", headerHeight: "headerHeight", rowHeight: "rowHeight", locale: "locale", childGroupOffset: "childGroupOffset", itemTemplate: "itemTemplate" }, outputs: { widthChanged: "widthChanged" }, usesOnChanges: true, ngImport: i0, template: "<div class='panel resize-handle-right'\r\n mwlResizable\r\n (resizing)='handleResize($event)'\r\n [style.width.px]='width'>\r\n\r\n <div mwlResizeHandle [resizeEdges]=\"{right: resizable}\"></div>\r\n\r\n <div class='label' [style.height.px]=\"headerHeight\">{{label}}</div>\r\n\r\n <ng-container *ngFor='let item of items; trackBy: trackById; let index = index'\r\n [ngTemplateOutlet]='itemsIterationTemplate'\r\n [ngTemplateOutletContext]='{item: item, index: ind