@syncfusion/ej2-schedule 30.2.7 → 31.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ej2-schedule.min.js +2 -2
- package/dist/ej2-schedule.umd.min.js +2 -2
- package/dist/ej2-schedule.umd.min.js.map +1 -1
- package/dist/es6/ej2-schedule.es2015.js +110 -36
- package/dist/es6/ej2-schedule.es2015.js.map +1 -1
- package/dist/es6/ej2-schedule.es5.js +110 -36
- package/dist/es6/ej2-schedule.es5.js.map +1 -1
- package/dist/global/ej2-schedule.min.js +2 -2
- package/dist/global/ej2-schedule.min.js.map +1 -1
- package/dist/global/index.d.ts +1 -1
- package/dist/ts/common/calendar-util.d.ts +92 -0
- package/dist/ts/common/calendar-util.ts +261 -0
- package/dist/ts/common/index.d.ts +4 -0
- package/dist/ts/common/index.ts +4 -0
- package/dist/ts/components.d.ts +5 -0
- package/dist/ts/components.ts +5 -0
- package/dist/ts/index.d.ts +6 -0
- package/dist/ts/index.ts +7 -0
- package/dist/ts/recurrence-editor/date-generator.d.ts +76 -0
- package/dist/ts/recurrence-editor/date-generator.ts +1699 -0
- package/dist/ts/recurrence-editor/index.d.ts +6 -0
- package/dist/ts/recurrence-editor/index.ts +6 -0
- package/dist/ts/recurrence-editor/recurrence-editor-model.d.ts +112 -0
- package/dist/ts/recurrence-editor/recurrence-editor.d.ts +245 -0
- package/dist/ts/recurrence-editor/recurrence-editor.ts +1257 -0
- package/dist/ts/schedule/actions/action-base.d.ts +44 -0
- package/dist/ts/schedule/actions/action-base.ts +493 -0
- package/dist/ts/schedule/actions/crud.d.ts +41 -0
- package/dist/ts/schedule/actions/crud.ts +784 -0
- package/dist/ts/schedule/actions/data.d.ts +63 -0
- package/dist/ts/schedule/actions/data.ts +128 -0
- package/dist/ts/schedule/actions/drag.d.ts +75 -0
- package/dist/ts/schedule/actions/drag.ts +1401 -0
- package/dist/ts/schedule/actions/keyboard.d.ts +100 -0
- package/dist/ts/schedule/actions/keyboard.ts +1435 -0
- package/dist/ts/schedule/actions/resize.d.ts +27 -0
- package/dist/ts/schedule/actions/resize.ts +602 -0
- package/dist/ts/schedule/actions/scroll.d.ts +69 -0
- package/dist/ts/schedule/actions/scroll.ts +105 -0
- package/dist/ts/schedule/actions/touch.d.ts +32 -0
- package/dist/ts/schedule/actions/touch.ts +314 -0
- package/dist/ts/schedule/actions/virtual-scroll.d.ts +55 -0
- package/dist/ts/schedule/actions/virtual-scroll.ts +596 -0
- package/dist/ts/schedule/actions/work-cells.d.ts +14 -0
- package/dist/ts/schedule/actions/work-cells.ts +151 -0
- package/dist/ts/schedule/base/constant.d.ts +102 -0
- package/dist/ts/schedule/base/constant.ts +103 -0
- package/dist/ts/schedule/base/css-constant.d.ts +475 -0
- package/dist/ts/schedule/base/css-constant.ts +475 -0
- package/dist/ts/schedule/base/interface.d.ts +673 -0
- package/dist/ts/schedule/base/interface.ts +738 -0
- package/dist/ts/schedule/base/resource.d.ts +59 -0
- package/dist/ts/schedule/base/resource.ts +1091 -0
- package/dist/ts/schedule/base/schedule-model.d.ts +930 -0
- package/dist/ts/schedule/base/schedule.d.ts +1967 -0
- package/dist/ts/schedule/base/schedule.ts +4221 -0
- package/dist/ts/schedule/base/type.d.ts +134 -0
- package/dist/ts/schedule/base/type.ts +142 -0
- package/dist/ts/schedule/base/util.d.ts +266 -0
- package/dist/ts/schedule/base/util.ts +492 -0
- package/dist/ts/schedule/event-renderer/agenda-base.d.ts +15 -0
- package/dist/ts/schedule/event-renderer/agenda-base.ts +423 -0
- package/dist/ts/schedule/event-renderer/event-base.d.ts +101 -0
- package/dist/ts/schedule/event-renderer/event-base.ts +1501 -0
- package/dist/ts/schedule/event-renderer/inline-edit.d.ts +23 -0
- package/dist/ts/schedule/event-renderer/inline-edit.ts +287 -0
- package/dist/ts/schedule/event-renderer/month.d.ts +60 -0
- package/dist/ts/schedule/event-renderer/month.ts +760 -0
- package/dist/ts/schedule/event-renderer/timeline-view.d.ts +51 -0
- package/dist/ts/schedule/event-renderer/timeline-view.ts +606 -0
- package/dist/ts/schedule/event-renderer/vertical-view.d.ts +57 -0
- package/dist/ts/schedule/event-renderer/vertical-view.ts +898 -0
- package/dist/ts/schedule/event-renderer/year.d.ts +27 -0
- package/dist/ts/schedule/event-renderer/year.ts +623 -0
- package/dist/ts/schedule/exports/calendar-export.d.ts +16 -0
- package/dist/ts/schedule/exports/calendar-export.ts +160 -0
- package/dist/ts/schedule/exports/calendar-import.d.ts +18 -0
- package/dist/ts/schedule/exports/calendar-import.ts +277 -0
- package/dist/ts/schedule/exports/excel-export.d.ts +14 -0
- package/dist/ts/schedule/exports/excel-export.ts +89 -0
- package/dist/ts/schedule/exports/index.d.ts +7 -0
- package/dist/ts/schedule/exports/index.ts +7 -0
- package/dist/ts/schedule/exports/print.d.ts +20 -0
- package/dist/ts/schedule/exports/print.ts +233 -0
- package/dist/ts/schedule/index.d.ts +26 -0
- package/dist/ts/schedule/index.ts +26 -0
- package/dist/ts/schedule/models/event-settings-model.d.ts +165 -0
- package/dist/ts/schedule/models/event-settings.d.ts +149 -0
- package/dist/ts/schedule/models/event-settings.ts +187 -0
- package/dist/ts/schedule/models/field-options-model.d.ts +37 -0
- package/dist/ts/schedule/models/field-options.d.ts +31 -0
- package/dist/ts/schedule/models/field-options.ts +41 -0
- package/dist/ts/schedule/models/fields-model.d.ts +129 -0
- package/dist/ts/schedule/models/fields.d.ts +117 -0
- package/dist/ts/schedule/models/fields.ts +149 -0
- package/dist/ts/schedule/models/group-model.d.ts +69 -0
- package/dist/ts/schedule/models/group.d.ts +60 -0
- package/dist/ts/schedule/models/group.ts +75 -0
- package/dist/ts/schedule/models/header-rows-model.d.ts +33 -0
- package/dist/ts/schedule/models/header-rows.d.ts +30 -0
- package/dist/ts/schedule/models/header-rows.ts +35 -0
- package/dist/ts/schedule/models/models.d.ts +14 -0
- package/dist/ts/schedule/models/models.ts +15 -0
- package/dist/ts/schedule/models/quick-info-templates-model.d.ts +52 -0
- package/dist/ts/schedule/models/quick-info-templates.d.ts +47 -0
- package/dist/ts/schedule/models/quick-info-templates.ts +56 -0
- package/dist/ts/schedule/models/resources-model.d.ts +122 -0
- package/dist/ts/schedule/models/resources.d.ts +106 -0
- package/dist/ts/schedule/models/resources.ts +138 -0
- package/dist/ts/schedule/models/time-scale-model.d.ts +57 -0
- package/dist/ts/schedule/models/time-scale.d.ts +50 -0
- package/dist/ts/schedule/models/time-scale.ts +61 -0
- package/dist/ts/schedule/models/toolbar-model.d.ts +196 -0
- package/dist/ts/schedule/models/toolbar.d.ts +176 -0
- package/dist/ts/schedule/models/toolbar.ts +196 -0
- package/dist/ts/schedule/models/views-model.d.ts +370 -0
- package/dist/ts/schedule/models/views.d.ts +335 -0
- package/dist/ts/schedule/models/views.ts +408 -0
- package/dist/ts/schedule/models/work-hours-model.d.ts +29 -0
- package/dist/ts/schedule/models/work-hours.d.ts +24 -0
- package/dist/ts/schedule/models/work-hours.ts +31 -0
- package/dist/ts/schedule/popups/event-tooltip.d.ts +16 -0
- package/dist/ts/schedule/popups/event-tooltip.ts +203 -0
- package/dist/ts/schedule/popups/event-window.d.ts +118 -0
- package/dist/ts/schedule/popups/event-window.ts +2055 -0
- package/dist/ts/schedule/popups/form-validator.d.ts +16 -0
- package/dist/ts/schedule/popups/form-validator.ts +110 -0
- package/dist/ts/schedule/popups/quick-popups.d.ts +78 -0
- package/dist/ts/schedule/popups/quick-popups.ts +1470 -0
- package/dist/ts/schedule/renderer/agenda.d.ts +45 -0
- package/dist/ts/schedule/renderer/agenda.ts +497 -0
- package/dist/ts/schedule/renderer/day.d.ts +20 -0
- package/dist/ts/schedule/renderer/day.ts +28 -0
- package/dist/ts/schedule/renderer/header-renderer.d.ts +48 -0
- package/dist/ts/schedule/renderer/header-renderer.ts +736 -0
- package/dist/ts/schedule/renderer/month-agenda.d.ts +29 -0
- package/dist/ts/schedule/renderer/month-agenda.ts +184 -0
- package/dist/ts/schedule/renderer/month.d.ts +61 -0
- package/dist/ts/schedule/renderer/month.ts +766 -0
- package/dist/ts/schedule/renderer/renderer.d.ts +13 -0
- package/dist/ts/schedule/renderer/renderer.ts +165 -0
- package/dist/ts/schedule/renderer/timeline-header-row.d.ts +15 -0
- package/dist/ts/schedule/renderer/timeline-header-row.ts +132 -0
- package/dist/ts/schedule/renderer/timeline-month.d.ts +29 -0
- package/dist/ts/schedule/renderer/timeline-month.ts +184 -0
- package/dist/ts/schedule/renderer/timeline-view.d.ts +31 -0
- package/dist/ts/schedule/renderer/timeline-view.ts +308 -0
- package/dist/ts/schedule/renderer/timeline-year.d.ts +22 -0
- package/dist/ts/schedule/renderer/timeline-year.ts +450 -0
- package/dist/ts/schedule/renderer/vertical-view.d.ts +63 -0
- package/dist/ts/schedule/renderer/vertical-view.ts +911 -0
- package/dist/ts/schedule/renderer/view-base.d.ts +83 -0
- package/dist/ts/schedule/renderer/view-base.ts +709 -0
- package/dist/ts/schedule/renderer/week.d.ts +22 -0
- package/dist/ts/schedule/renderer/week.ts +35 -0
- package/dist/ts/schedule/renderer/work-week.d.ts +22 -0
- package/dist/ts/schedule/renderer/work-week.ts +36 -0
- package/dist/ts/schedule/renderer/year.d.ts +46 -0
- package/dist/ts/schedule/renderer/year.ts +470 -0
- package/dist/ts/schedule/timezone/timezone.d.ts +16 -0
- package/dist/ts/schedule/timezone/timezone.ts +313 -0
- package/package.json +56 -21
- package/src/schedule/actions/action-base.js +3 -0
- package/src/schedule/actions/drag.js +11 -4
- package/src/schedule/actions/keyboard.js +1 -1
- package/src/schedule/actions/resize.js +8 -5
- package/src/schedule/base/css-constant.d.ts +2 -0
- package/src/schedule/base/css-constant.js +2 -0
- package/src/schedule/base/schedule.js +15 -1
- package/src/schedule/event-renderer/agenda-base.d.ts +1 -1
- package/src/schedule/event-renderer/agenda-base.js +5 -4
- package/src/schedule/event-renderer/inline-edit.js +11 -6
- package/src/schedule/event-renderer/month.js +5 -3
- package/src/schedule/event-renderer/vertical-view.js +3 -0
- package/src/schedule/event-renderer/year.d.ts +2 -0
- package/src/schedule/event-renderer/year.js +28 -4
- package/src/schedule/popups/event-tooltip.js +4 -0
- package/src/schedule/popups/event-window.js +2 -2
- package/src/schedule/popups/quick-popups.js +5 -1
- package/src/schedule/renderer/agenda.js +3 -2
- package/src/schedule/renderer/vertical-view.js +1 -1
- package/src/schedule/renderer/year.js +3 -2
- package/styles/bds-lite.css +11 -8
- package/styles/bds.css +11 -8
- package/styles/bootstrap-dark-lite.css +12 -9
- package/styles/bootstrap-dark.css +12 -9
- package/styles/bootstrap-lite.css +12 -9
- package/styles/bootstrap.css +12 -9
- package/styles/bootstrap4-lite.css +11 -8
- package/styles/bootstrap4.css +11 -8
- package/styles/bootstrap5-dark-lite.css +11 -8
- package/styles/bootstrap5-dark.css +11 -8
- package/styles/bootstrap5-lite.css +11 -8
- package/styles/bootstrap5.3-lite.css +11 -8
- package/styles/bootstrap5.3.css +11 -8
- package/styles/bootstrap5.css +11 -8
- package/styles/fabric-dark-lite.css +12 -9
- package/styles/fabric-dark.css +12 -9
- package/styles/fabric-lite.css +12 -9
- package/styles/fabric.css +12 -9
- package/styles/fluent-dark-lite.css +13 -10
- package/styles/fluent-dark.css +13 -10
- package/styles/fluent-lite.css +13 -10
- package/styles/fluent.css +13 -10
- package/styles/fluent2-lite.css +11 -8
- package/styles/fluent2.css +11 -8
- package/styles/highcontrast-light-lite.css +12 -9
- package/styles/highcontrast-light.css +12 -9
- package/styles/highcontrast-lite.css +12 -9
- package/styles/highcontrast.css +12 -9
- package/styles/material-dark-lite.css +12 -9
- package/styles/material-dark.css +12 -9
- package/styles/material-lite.css +12 -9
- package/styles/material.css +12 -9
- package/styles/material3-dark-lite.css +11 -8
- package/styles/material3-dark.css +11 -8
- package/styles/material3-lite.css +11 -8
- package/styles/material3.css +11 -8
- package/styles/recurrence-editor/_bds-definition.scss +1 -0
- package/styles/recurrence-editor/_bootstrap-dark-definition.scss +1 -0
- package/styles/recurrence-editor/_bootstrap-definition.scss +1 -0
- package/styles/recurrence-editor/_bootstrap4-definition.scss +1 -0
- package/styles/recurrence-editor/_bootstrap5-definition.scss +1 -0
- package/styles/recurrence-editor/_bootstrap5.3-definition.scss +1 -0
- package/styles/recurrence-editor/_fabric-dark-definition.scss +1 -0
- package/styles/recurrence-editor/_fabric-definition.scss +1 -0
- package/styles/recurrence-editor/_fluent-definition.scss +1 -0
- package/styles/recurrence-editor/_fluent2-definition.scss +1 -0
- package/styles/recurrence-editor/_fusionnew-definition.scss +1 -0
- package/styles/recurrence-editor/_highcontrast-definition.scss +1 -0
- package/styles/recurrence-editor/_highcontrast-light-definition.scss +1 -0
- package/styles/recurrence-editor/_layout.scss +5 -1
- package/styles/recurrence-editor/_material-dark-definition.scss +1 -0
- package/styles/recurrence-editor/_material-definition.scss +1 -0
- package/styles/recurrence-editor/_material3-definition.scss +1 -0
- package/styles/recurrence-editor/_tailwind-definition.scss +1 -0
- package/styles/recurrence-editor/_tailwind3-definition.scss +1 -0
- package/styles/recurrence-editor/bds.css +3 -0
- package/styles/recurrence-editor/bootstrap-dark.css +4 -1
- package/styles/recurrence-editor/bootstrap.css +4 -1
- package/styles/recurrence-editor/bootstrap4.css +3 -0
- package/styles/recurrence-editor/bootstrap5-dark.css +3 -0
- package/styles/recurrence-editor/bootstrap5.3.css +3 -0
- package/styles/recurrence-editor/bootstrap5.css +3 -0
- package/styles/recurrence-editor/fabric-dark.css +4 -1
- package/styles/recurrence-editor/fabric.css +4 -1
- package/styles/recurrence-editor/fluent-dark.css +4 -1
- package/styles/recurrence-editor/fluent.css +4 -1
- package/styles/recurrence-editor/fluent2.css +3 -0
- package/styles/recurrence-editor/highcontrast-light.css +4 -1
- package/styles/recurrence-editor/highcontrast.css +4 -1
- package/styles/recurrence-editor/material-dark.css +4 -1
- package/styles/recurrence-editor/material.css +4 -1
- package/styles/recurrence-editor/material3-dark.css +3 -0
- package/styles/recurrence-editor/material3.css +3 -0
- package/styles/recurrence-editor/tailwind-dark.css +3 -0
- package/styles/recurrence-editor/tailwind.css +3 -0
- package/styles/recurrence-editor/tailwind3.css +3 -0
- package/styles/schedule/_bds-definition.scss +2 -0
- package/styles/schedule/_bootstrap-dark-definition.scss +2 -0
- package/styles/schedule/_bootstrap-definition.scss +2 -0
- package/styles/schedule/_bootstrap4-definition.scss +2 -0
- package/styles/schedule/_bootstrap5-definition.scss +2 -0
- package/styles/schedule/_bootstrap5.3-definition.scss +2 -0
- package/styles/schedule/_fabric-dark-definition.scss +2 -0
- package/styles/schedule/_fabric-definition.scss +2 -0
- package/styles/schedule/_fluent-definition.scss +3 -1
- package/styles/schedule/_fluent2-definition.scss +2 -0
- package/styles/schedule/_fusionnew-definition.scss +2 -0
- package/styles/schedule/_highcontrast-definition.scss +2 -0
- package/styles/schedule/_highcontrast-light-definition.scss +2 -0
- package/styles/schedule/_layout.scss +12 -11
- package/styles/schedule/_material-dark-definition.scss +2 -0
- package/styles/schedule/_material-definition.scss +2 -0
- package/styles/schedule/_material3-definition.scss +2 -0
- package/styles/schedule/_tailwind-definition.scss +2 -0
- package/styles/schedule/_tailwind3-definition.scss +2 -0
- package/styles/schedule/bds.css +8 -8
- package/styles/schedule/bootstrap-dark.css +8 -8
- package/styles/schedule/bootstrap.css +8 -8
- package/styles/schedule/bootstrap4.css +8 -8
- package/styles/schedule/bootstrap5-dark.css +8 -8
- package/styles/schedule/bootstrap5.3.css +8 -8
- package/styles/schedule/bootstrap5.css +8 -8
- package/styles/schedule/fabric-dark.css +8 -8
- package/styles/schedule/fabric.css +8 -8
- package/styles/schedule/fluent-dark.css +9 -9
- package/styles/schedule/fluent.css +9 -9
- package/styles/schedule/fluent2.css +8 -8
- package/styles/schedule/highcontrast-light.css +8 -8
- package/styles/schedule/highcontrast.css +8 -8
- package/styles/schedule/material-dark.css +8 -8
- package/styles/schedule/material.css +8 -8
- package/styles/schedule/material3-dark.css +8 -8
- package/styles/schedule/material3.css +8 -8
- package/styles/schedule/tailwind-dark.css +8 -8
- package/styles/schedule/tailwind.css +8 -8
- package/styles/schedule/tailwind3.css +8 -8
- package/styles/tailwind-dark-lite.css +11 -8
- package/styles/tailwind-dark.css +11 -8
- package/styles/tailwind-lite.css +11 -8
- package/styles/tailwind.css +11 -8
- package/styles/tailwind3-lite.css +11 -8
- package/styles/tailwind3.css +11 -8
|
@@ -0,0 +1,1501 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable max-len */
|
|
3
|
+
import { isNullOrUndefined, closest, extend, EventHandler, setStyleAttribute } from '@syncfusion/ej2-base';
|
|
4
|
+
import { createElement, prepend, append, addClass, removeClass } from '@syncfusion/ej2-base';
|
|
5
|
+
import { DataManager, Query, Predicate } from '@syncfusion/ej2-data';
|
|
6
|
+
import { EventFieldsMapping, EventClickArgs, CellClickEventArgs, TdData, SelectEventArgs, InlineClickArgs, CallbackFunction } from '../base/interface';
|
|
7
|
+
import { Schedule } from '../base/schedule';
|
|
8
|
+
import { ResourcesModel } from '../models/resources-model';
|
|
9
|
+
import { generate, getDateFromRecurrenceDateString } from '../../recurrence-editor/date-generator';
|
|
10
|
+
import { CalendarType } from '../../common/calendar-util';
|
|
11
|
+
import * as util from '../base/util';
|
|
12
|
+
import * as cls from '../base/css-constant';
|
|
13
|
+
import * as event from '../base/constant';
|
|
14
|
+
import { CurrentAction } from '../base/type';
|
|
15
|
+
/**
|
|
16
|
+
* EventBase for appointment rendering
|
|
17
|
+
*/
|
|
18
|
+
export class EventBase {
|
|
19
|
+
public parent: Schedule;
|
|
20
|
+
public slots: number[] = [];
|
|
21
|
+
public cssClass: string;
|
|
22
|
+
public groupOrder: string[];
|
|
23
|
+
public processedData: Record<string, any>[] = [];
|
|
24
|
+
private isDoubleTapped: boolean = false;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Constructor for EventBase
|
|
28
|
+
*
|
|
29
|
+
* @param {Schedule} parent Accepts the schedule instance
|
|
30
|
+
*/
|
|
31
|
+
constructor(parent: Schedule) {
|
|
32
|
+
this.parent = parent;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public processData(events: Record<string, any>[], timeZonePropChanged?: boolean, oldTimezone?: string): Record<string, any>[] {
|
|
36
|
+
const start: Date = this.parent.activeView.startDate();
|
|
37
|
+
const end: Date = this.parent.activeView.endDate();
|
|
38
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
39
|
+
let processed: Record<string, any>[] = [];
|
|
40
|
+
let temp: number = 1;
|
|
41
|
+
let generateID: boolean = false;
|
|
42
|
+
const resourceCollection: ResourcesModel[] = this.parent.resourceBase ? this.parent.resourceBase.resourceCollection : [];
|
|
43
|
+
if (events.length > 0 && isNullOrUndefined(events[0][fields.id])) {
|
|
44
|
+
generateID = true;
|
|
45
|
+
}
|
|
46
|
+
for (let event of events) {
|
|
47
|
+
if (generateID) {
|
|
48
|
+
event[fields.id] = temp++;
|
|
49
|
+
}
|
|
50
|
+
event = this.updateEventDateTime(event);
|
|
51
|
+
if (timeZonePropChanged) {
|
|
52
|
+
this.processTimezoneChange(event, oldTimezone);
|
|
53
|
+
} else if (!this.parent.isPrinting && !this.parent.uiStateValues.isPreventTimezone) {
|
|
54
|
+
event = this.processTimezone(event);
|
|
55
|
+
}
|
|
56
|
+
for (let level: number = 0; level < resourceCollection.length; level++) {
|
|
57
|
+
if (event[resourceCollection[parseInt(level.toString(), 10)].field] === null || event[resourceCollection[parseInt(level.toString(), 10)].field] === 0) {
|
|
58
|
+
event[resourceCollection[parseInt(level.toString(), 10)].field] = undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!isNullOrUndefined(event[fields.recurrenceRule]) && event[fields.recurrenceRule] === '') {
|
|
62
|
+
event[fields.recurrenceRule] = null;
|
|
63
|
+
}
|
|
64
|
+
if (!isNullOrUndefined(event[fields.recurrenceRule]) && isNullOrUndefined(event[fields.recurrenceID]) &&
|
|
65
|
+
!(this.parent.crudModule && this.parent.crudModule.crudObj.isCrudAction)) {
|
|
66
|
+
processed = processed.concat(this.generateOccurrence(event, null, true));
|
|
67
|
+
} else {
|
|
68
|
+
if (this.parent.crudModule && this.parent.crudModule.crudObj.isCrudAction) {
|
|
69
|
+
if (!isNullOrUndefined(event[fields.recurrenceRule]) && isNullOrUndefined(event[fields.recurrenceID])) {
|
|
70
|
+
const recurrenceEvent: Record<string, any>[] = this.generateOccurrence(event, null, true);
|
|
71
|
+
for (const occurrence of recurrenceEvent) {
|
|
72
|
+
const app: Record<string, any>[] = this.parent.eventsProcessed.filter((data: Record<string, Date>) =>
|
|
73
|
+
data[fields.startTime].getTime() - (<Date>occurrence[fields.startTime]).getTime() === 0 &&
|
|
74
|
+
data[fields.id] === occurrence[fields.id]);
|
|
75
|
+
occurrence.Guid = (app.length > 0) ? app[0].Guid : this.generateGuid();
|
|
76
|
+
processed.push(occurrence);
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const app: Record<string, any>[] = this.parent.eventsProcessed.filter((data: Record<string, any>) =>
|
|
80
|
+
data[this.parent.eventFields.id] === event[this.parent.eventFields.id]);
|
|
81
|
+
event.Guid = (app.length > 0) ? app[0].Guid : this.generateGuid();
|
|
82
|
+
processed.push(event);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
event.Guid = this.generateGuid();
|
|
86
|
+
processed.push(event);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
this.parent.eventsProcessed = [];
|
|
91
|
+
const eventData: Record<string, any>[] = processed.filter((data: Record<string, any>) =>
|
|
92
|
+
!data[this.parent.eventFields.isBlock]);
|
|
93
|
+
this.parent.eventsProcessed = this.filterEvents(start, end, eventData);
|
|
94
|
+
if (!this.parent.activeViewOptions.allowOverlap && this.parent.eventsProcessed.length > 0) {
|
|
95
|
+
this.processedData = this.parent.eventsProcessed;
|
|
96
|
+
const nonOverlapList: Record<string, any>[] = [];
|
|
97
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
98
|
+
for (const data of this.parent.eventsProcessed as Record<string, any>[]) {
|
|
99
|
+
const overlappingData: Record<string, any> = this.findOverlappingData(data, nonOverlapList);
|
|
100
|
+
if (!overlappingData) {
|
|
101
|
+
nonOverlapList.push(data);
|
|
102
|
+
} else if (!this.parent.eventSettings.sortComparer) {
|
|
103
|
+
const dataDuration: number = new Date(data[fields.endTime]).getTime() - new Date(data[fields.startTime]).getTime();
|
|
104
|
+
const duplicateDuration: number = new Date(overlappingData[fields.endTime]).getTime() - new Date(overlappingData[fields.startTime]).getTime();
|
|
105
|
+
if ((dataDuration > duplicateDuration && data[fields.startTime] === overlappingData[fields.startTime]) || (data[fields.isAllDay] === true)) {
|
|
106
|
+
const index: number = nonOverlapList.indexOf(overlappingData);
|
|
107
|
+
if (index !== -1) { nonOverlapList.splice(index, 1); }
|
|
108
|
+
nonOverlapList.push(data);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
this.parent.eventsProcessed = nonOverlapList;
|
|
113
|
+
}
|
|
114
|
+
const blockData: Record<string, any>[] = processed.filter((data: Record<string, any>) =>
|
|
115
|
+
data[this.parent.eventFields.isBlock]);
|
|
116
|
+
for (const eventObj of blockData) {
|
|
117
|
+
if (eventObj[fields.isAllDay]) {
|
|
118
|
+
const isDifferentDate: boolean = util.resetTime(new Date((eventObj[fields.startTime] as Date).getTime())) <
|
|
119
|
+
util.resetTime(new Date((eventObj[fields.endTime] as Date).getTime()));
|
|
120
|
+
if (!isDifferentDate) {
|
|
121
|
+
eventObj[fields.startTime] = util.resetTime(eventObj[fields.startTime] as Date);
|
|
122
|
+
eventObj[fields.endTime] = util.addDays(util.resetTime(eventObj[fields.endTime] as Date), 1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
this.parent.blockProcessed = blockData;
|
|
127
|
+
return eventData;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
private findOverlappingData(eventData: Record<string, any>, eventList: Record<string, any>[]): Record<string, any> | undefined {
|
|
131
|
+
const isResource: boolean = this.parent.activeViewOptions.group.resources.length > 0;
|
|
132
|
+
const resourceCollection: ResourcesModel[] = isResource ? this.parent.resourceBase.resourceCollection : [];
|
|
133
|
+
const lastLevelResource: string = isResource ? resourceCollection[resourceCollection.length - 1].field : null;
|
|
134
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
135
|
+
const newStartTime: Date = new Date(eventData[fields.startTime]);
|
|
136
|
+
const newEndTime: Date = new Date(eventData[fields.endTime]);
|
|
137
|
+
for (const existingEvent of eventList) {
|
|
138
|
+
if (
|
|
139
|
+
newStartTime < existingEvent[fields.endTime] &&
|
|
140
|
+
newEndTime > existingEvent[fields.startTime] &&
|
|
141
|
+
existingEvent[fields.id] !== eventData[fields.id] &&
|
|
142
|
+
(!isResource || isNullOrUndefined(lastLevelResource) ||
|
|
143
|
+
this.compareResourceValues(existingEvent[`${lastLevelResource}`], eventData[`${lastLevelResource}`]))
|
|
144
|
+
) {
|
|
145
|
+
return existingEvent;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private isOverlapRange(eventData: Record<string, any> | Record<string, any>[], currentAction: CurrentAction = null): boolean {
|
|
152
|
+
const isResource: boolean = this.parent.activeViewOptions.group.resources.length > 0;
|
|
153
|
+
const resourceCollection: ResourcesModel[] = isResource ? this.parent.resourceBase.resourceCollection : [];
|
|
154
|
+
const lastLevelResource: string = isResource ? resourceCollection[resourceCollection.length - 1].field : null;
|
|
155
|
+
const eventCollection: Record<string, any>[] = Array.isArray(eventData) ? eventData : [eventData];
|
|
156
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
157
|
+
|
|
158
|
+
const processOverlappingEvents: (data: Record<string, any>) => Record<string, any>[] = (data: Record<string, any>) => {
|
|
159
|
+
return this.processedData.filter((x: Record<string, any>) =>
|
|
160
|
+
data[fields.startTime] < x[fields.endTime] &&
|
|
161
|
+
data[fields.endTime] > x[fields.startTime] &&
|
|
162
|
+
x[fields.id] !== data[fields.id] &&
|
|
163
|
+
(!isResource || isNullOrUndefined(lastLevelResource) || this.compareResourceValues(x[`${lastLevelResource}`], data[`${lastLevelResource}`]))
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
const overlappedEvents: Record<string, any>[] = [];
|
|
167
|
+
let isOverlapAlert: boolean = false;
|
|
168
|
+
|
|
169
|
+
for (const event of eventCollection) {
|
|
170
|
+
const dataCol: Record<string, any>[] = !isNullOrUndefined(event[fields.recurrenceRule]) &&
|
|
171
|
+
(isNullOrUndefined(event[fields.recurrenceID]) || event[fields.recurrenceID] === event[fields.id]) &&
|
|
172
|
+
(isNullOrUndefined(event[fields.recurrenceID]) || currentAction === 'EditSeries')
|
|
173
|
+
? this.generateOccurrence(event)
|
|
174
|
+
: [event];
|
|
175
|
+
|
|
176
|
+
for (const data of dataCol) {
|
|
177
|
+
const overlappingEvents: Record<string, any>[] = processOverlappingEvents(data);
|
|
178
|
+
if (overlappingEvents.length > 0) {
|
|
179
|
+
overlappedEvents.push(...overlappingEvents);
|
|
180
|
+
}
|
|
181
|
+
if (this.findOverlappingData(data, this.parent.eventsProcessed)) {
|
|
182
|
+
isOverlapAlert = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
this.parent.overlapAppointments = overlappedEvents;
|
|
187
|
+
return isOverlapAlert;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private compareResourceValues(a: string | number | (string | number)[], b: string | number | (string | number)[]): boolean {
|
|
191
|
+
type GetValueFunction = (value: string | number | (string | number)[]) => string | number;
|
|
192
|
+
const getValue: GetValueFunction = (value: string | number | (string | number)[]) => Array.isArray(value) ? value[0] : value;
|
|
193
|
+
return getValue(a) === getValue(b);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public checkOverlap(eventData: Record<string, any> | Record<string, any>[]): boolean {
|
|
197
|
+
if (!this.parent.activeViewOptions.allowOverlap) {
|
|
198
|
+
if (this.isOverlapRange(eventData)) {
|
|
199
|
+
this.parent.quickPopup.openValidationError('overlapAlert', eventData);
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public updateEventDateTime(eventData: Record<string, any>): Record<string, any> {
|
|
207
|
+
if (typeof eventData[this.parent.eventFields.startTime] === 'string') {
|
|
208
|
+
eventData[this.parent.eventFields.startTime] = util.getDateFromString(eventData[this.parent.eventFields.startTime]);
|
|
209
|
+
}
|
|
210
|
+
if (typeof eventData[this.parent.eventFields.endTime] === 'string') {
|
|
211
|
+
eventData[this.parent.eventFields.endTime] = util.getDateFromString(eventData[this.parent.eventFields.endTime]);
|
|
212
|
+
}
|
|
213
|
+
return eventData;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
public getProcessedEvents(eventCollection: Record<string, any>[] = this.parent.eventsData): Record<string, any>[] {
|
|
217
|
+
let processed: Record<string, any>[] = [];
|
|
218
|
+
for (const event of eventCollection) {
|
|
219
|
+
if (!isNullOrUndefined(event[this.parent.eventFields.recurrenceRule]) &&
|
|
220
|
+
isNullOrUndefined(event[this.parent.eventFields.recurrenceID])) {
|
|
221
|
+
processed = processed.concat(this.generateOccurrence(event));
|
|
222
|
+
} else {
|
|
223
|
+
processed.push(event);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return processed;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public timezonePropertyChange(oldTimezone: string): void {
|
|
230
|
+
const data: Record<string, any>[] = this.parent.eventsData.concat(this.parent.blockData) as Record<string, any>[];
|
|
231
|
+
const processed: Record<string, any>[] = this.processData(data, true, oldTimezone);
|
|
232
|
+
this.parent.notify(event.dataReady, { processedData: processed });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public timezoneConvert(eventData: Record<string, any>): void {
|
|
236
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
237
|
+
eventData[fields.startTimezone] = eventData[fields.startTimezone] || eventData[fields.endTimezone];
|
|
238
|
+
eventData[fields.endTimezone] = eventData[fields.endTimezone] || eventData[fields.startTimezone];
|
|
239
|
+
if (this.parent.timezone) {
|
|
240
|
+
const startTz: string = eventData[fields.startTimezone] as string;
|
|
241
|
+
const endTz: string = eventData[fields.endTimezone] as string;
|
|
242
|
+
eventData[fields.startTime] = this.parent.tzModule.convert(<Date>eventData[fields.startTime], this.parent.timezone, startTz);
|
|
243
|
+
eventData[fields.endTime] = this.parent.tzModule.convert(<Date>eventData[fields.endTime], this.parent.timezone, endTz);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
private processTimezoneChange(event: Record<string, any>, oldTimezone: string): void {
|
|
248
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
249
|
+
if (event[fields.isAllDay]) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (oldTimezone && this.parent.timezone) {
|
|
253
|
+
event[fields.startTime] = this.parent.tzModule.convert(<Date>event[fields.startTime], oldTimezone, this.parent.timezone);
|
|
254
|
+
event[fields.endTime] = this.parent.tzModule.convert(<Date>event[fields.endTime], oldTimezone, this.parent.timezone);
|
|
255
|
+
} else if (!oldTimezone && this.parent.timezone) {
|
|
256
|
+
event[fields.startTime] = this.parent.tzModule.add(<Date>event[fields.startTime], this.parent.timezone);
|
|
257
|
+
event[fields.endTime] = this.parent.tzModule.add(<Date>event[fields.endTime], this.parent.timezone);
|
|
258
|
+
} else if (oldTimezone && !this.parent.timezone) {
|
|
259
|
+
event[fields.startTime] = this.parent.tzModule.remove(<Date>event[fields.startTime], oldTimezone);
|
|
260
|
+
event[fields.endTime] = this.parent.tzModule.remove(<Date>event[fields.endTime], oldTimezone);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
public processTimezone(event: Record<string, any>, isReverse: boolean = false): Record<string, any> {
|
|
265
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
266
|
+
if (event[fields.isAllDay]) {
|
|
267
|
+
return event;
|
|
268
|
+
}
|
|
269
|
+
if (event[fields.startTimezone] || event[fields.endTimezone]) {
|
|
270
|
+
const startTimezone: string = <string>event[fields.startTimezone] || <string>event[fields.endTimezone];
|
|
271
|
+
const endTimezone: string = <string>event[fields.endTimezone] || <string>event[fields.startTimezone];
|
|
272
|
+
if (isReverse) {
|
|
273
|
+
if (this.parent.timezone) {
|
|
274
|
+
event[fields.startTime] = this.parent.tzModule.convert(<Date>event[fields.startTime], startTimezone, this.parent.timezone);
|
|
275
|
+
event[fields.endTime] = this.parent.tzModule.convert(<Date>event[fields.endTime], endTimezone, this.parent.timezone);
|
|
276
|
+
event[fields.startTime] = this.parent.tzModule.remove(<Date>event[fields.startTime], this.parent.timezone);
|
|
277
|
+
event[fields.endTime] = this.parent.tzModule.remove(<Date>event[fields.endTime], this.parent.timezone);
|
|
278
|
+
} else {
|
|
279
|
+
event[fields.startTime] = this.parent.tzModule.remove(<Date>event[fields.startTime], startTimezone);
|
|
280
|
+
event[fields.endTime] = this.parent.tzModule.remove(<Date>event[fields.endTime], endTimezone);
|
|
281
|
+
}
|
|
282
|
+
} else {
|
|
283
|
+
event[fields.startTime] = this.parent.tzModule.add(<Date>event[fields.startTime], startTimezone);
|
|
284
|
+
event[fields.endTime] = this.parent.tzModule.add(<Date>event[fields.endTime], endTimezone);
|
|
285
|
+
if (this.parent.timezone) {
|
|
286
|
+
event[fields.startTime] = this.parent.tzModule.convert(<Date>event[fields.startTime], startTimezone, this.parent.timezone);
|
|
287
|
+
event[fields.endTime] = this.parent.tzModule.convert(<Date>event[fields.endTime], endTimezone, this.parent.timezone);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
} else if (this.parent.timezone) {
|
|
291
|
+
if (isReverse) {
|
|
292
|
+
event[fields.startTime] = this.parent.tzModule.remove(<Date>event[fields.startTime], this.parent.timezone);
|
|
293
|
+
event[fields.endTime] = this.parent.tzModule.remove(<Date>event[fields.endTime], this.parent.timezone);
|
|
294
|
+
} else {
|
|
295
|
+
event[fields.startTime] = this.parent.tzModule.add(<Date>event[fields.startTime], this.parent.timezone);
|
|
296
|
+
event[fields.endTime] = this.parent.tzModule.add(<Date>event[fields.endTime], this.parent.timezone);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return event;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
public filterBlockEvents(eventObj: Record<string, any>): Record<string, any>[] {
|
|
303
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
304
|
+
const eStart: Date = eventObj[fields.startTime] as Date;
|
|
305
|
+
const eEnd: Date = eventObj[fields.endTime] as Date;
|
|
306
|
+
let resourceData: TdData;
|
|
307
|
+
if (this.parent.activeViewOptions.group.resources.length > 0) {
|
|
308
|
+
const data: number = this.getGroupIndexFromEvent(eventObj);
|
|
309
|
+
resourceData = this.parent.resourceBase.lastResourceLevel[parseInt(data.toString(), 10)];
|
|
310
|
+
}
|
|
311
|
+
const blockEvents: Record<string, any>[] = <Record<string, any>[]>extend([], this.parent.blockProcessed, null, true);
|
|
312
|
+
for (const eventObj of blockEvents) {
|
|
313
|
+
if (eventObj[fields.isAllDay]) {
|
|
314
|
+
const isDifferentTime: boolean = (eventObj[fields.endTime] as Date).getTime() >
|
|
315
|
+
util.resetTime(new Date((eventObj[fields.endTime] as Date).getTime())).getTime();
|
|
316
|
+
if (isDifferentTime) {
|
|
317
|
+
eventObj[fields.startTime] = util.resetTime(eventObj[fields.startTime] as Date);
|
|
318
|
+
eventObj[fields.endTime] = util.addDays(util.resetTime(eventObj[fields.endTime] as Date), 1);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return this.filterEvents(eStart, eEnd, blockEvents, resourceData);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
public filterEvents(startDate: Date, endDate: Date, appointments: Record<string, any>[] = this.parent.eventsProcessed, resourceTdData?: TdData): Record<string, any>[] {
|
|
326
|
+
const predicate: Predicate = this.parent.dataModule.getStartEndQuery(startDate, endDate);
|
|
327
|
+
let filter: Record<string, any>[] = new DataManager({ json: appointments }).executeLocal(new Query().where(predicate)) as Record<string, any>[];
|
|
328
|
+
if (resourceTdData) {
|
|
329
|
+
filter = this.filterEventsByResource(resourceTdData, filter);
|
|
330
|
+
}
|
|
331
|
+
return this.sortByTime(filter);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
public filterEventsByRange(eventCollection: Record<string, any>[], startDate?: Date, endDate?: Date): Record<string, any>[] {
|
|
335
|
+
let filteredEvents: Record<string, any>[] = [];
|
|
336
|
+
if (startDate && endDate) {
|
|
337
|
+
filteredEvents = this.filterEvents(startDate, endDate, eventCollection);
|
|
338
|
+
} else if (startDate && !endDate) {
|
|
339
|
+
filteredEvents = eventCollection.filter((e: Record<string, any>) => e[this.parent.eventFields.startTime] >= startDate);
|
|
340
|
+
} else if (!startDate && endDate) {
|
|
341
|
+
filteredEvents = eventCollection.filter((e: Record<string, any>) => e[this.parent.eventFields.endTime] <= endDate);
|
|
342
|
+
} else {
|
|
343
|
+
filteredEvents = eventCollection;
|
|
344
|
+
}
|
|
345
|
+
return this.sortByTime(filteredEvents);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
public filterEventsByResource(resourceTdData: TdData, appointments: Record<string, any>[] = this.parent.eventsProcessed): Record<string, any>[] {
|
|
349
|
+
const predicate: Record<string, number | string> = {};
|
|
350
|
+
const resourceCollection: ResourcesModel[] = this.parent.resourceBase.resourceCollection;
|
|
351
|
+
for (let level: number = 0; level < resourceCollection.length; level++) {
|
|
352
|
+
predicate[resourceCollection[parseInt(level.toString(), 10)].field] = resourceTdData.groupOrder[parseInt(level.toString(), 10)];
|
|
353
|
+
}
|
|
354
|
+
const keys: string[] = Object.keys(predicate);
|
|
355
|
+
const filteredCollection: Record<string, any>[] = appointments.filter((eventObj: Record<string, any>) => keys.every((key: string) => {
|
|
356
|
+
if (eventObj[`${key}`] instanceof Array) {
|
|
357
|
+
return (<(string | number)[]>eventObj[`${key}`]).indexOf(predicate[`${key}`]) > -1;
|
|
358
|
+
} else {
|
|
359
|
+
return eventObj[`${key}`] === predicate[`${key}`];
|
|
360
|
+
}
|
|
361
|
+
}));
|
|
362
|
+
return filteredCollection;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
public sortByTime(appointmentsCollection: Record<string, any>[]): Record<string, any>[] {
|
|
366
|
+
if (this.parent.eventSettings.sortComparer && (typeof(this.parent.eventSettings.sortComparer) === 'function' || typeof(this.parent.eventSettings.sortComparer) === 'string')) {
|
|
367
|
+
appointmentsCollection = this.customSorting(appointmentsCollection);
|
|
368
|
+
} else {
|
|
369
|
+
const fieldMappings: EventFieldsMapping = this.parent.eventFields;
|
|
370
|
+
appointmentsCollection.sort((a: Record<string, any>, b: Record<string, any>) => {
|
|
371
|
+
const d1: Date = a[fieldMappings.startTime] as Date;
|
|
372
|
+
const d2: Date = b[fieldMappings.startTime] as Date;
|
|
373
|
+
return d1.getTime() - d2.getTime();
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
return appointmentsCollection;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
public sortByDateTime(appointments: Record<string, any>[]): Record<string, any>[] {
|
|
380
|
+
if (this.parent.eventSettings.sortComparer && (typeof(this.parent.eventSettings.sortComparer) === 'function' || typeof(this.parent.eventSettings.sortComparer) === 'string')) {
|
|
381
|
+
appointments = this.customSorting(appointments);
|
|
382
|
+
} else {
|
|
383
|
+
const fieldMapping: EventFieldsMapping = this.parent.eventFields;
|
|
384
|
+
appointments.sort((object1: Record<string, any>, object2: Record<string, any>) => {
|
|
385
|
+
const d3: Date = object1[fieldMapping.startTime] as Date;
|
|
386
|
+
const d4: Date = object2[fieldMapping.startTime] as Date;
|
|
387
|
+
const d5: Date = object1[fieldMapping.endTime] as Date;
|
|
388
|
+
const d6: Date = object2[fieldMapping.endTime] as Date;
|
|
389
|
+
const d1: number = d5.getTime() - d3.getTime();
|
|
390
|
+
const d2: number = d6.getTime() - d4.getTime();
|
|
391
|
+
return (d3.getTime() - d4.getTime() || d2 - d1);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return appointments;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private customSorting(appointments: Record<string, any>[]): Record<string, any>[] {
|
|
398
|
+
if (typeof(this.parent.eventSettings.sortComparer) === 'function') {
|
|
399
|
+
return this.parent.eventSettings.sortComparer.call(this.parent, appointments);
|
|
400
|
+
} else if (typeof(this.parent.eventSettings.sortComparer) === 'string') {
|
|
401
|
+
const splits: string[] = (this.parent.eventSettings.sortComparer as string).split('.');
|
|
402
|
+
let sortFn: Function;
|
|
403
|
+
if (!isNullOrUndefined(window)) {
|
|
404
|
+
sortFn = (window as Record<string, any>)[splits[splits.length - 1]];
|
|
405
|
+
}
|
|
406
|
+
if (sortFn) {
|
|
407
|
+
return sortFn(appointments);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return appointments;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
public getSmallestMissingNumber(array: number[]): number {
|
|
414
|
+
const large: number = Math.max(...array);
|
|
415
|
+
for (let i: number = 0; i < large; i++) {
|
|
416
|
+
if (array.indexOf(i) === -1) { return i; }
|
|
417
|
+
}
|
|
418
|
+
return large + 1;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
public splitEventByDay(event: Record<string, any>): Record<string, any>[] {
|
|
422
|
+
const eventFields: EventFieldsMapping = this.parent.eventFields;
|
|
423
|
+
const data: Record<string, any>[] = [];
|
|
424
|
+
const eventStartTime: Date = event[eventFields.startTime] as Date;
|
|
425
|
+
const eventEndTime: Date = event[eventFields.endTime] as Date;
|
|
426
|
+
const isDifferentDate: boolean = util.resetTime(new Date(eventStartTime.getTime())) <
|
|
427
|
+
util.resetTime(new Date(eventEndTime.getTime()));
|
|
428
|
+
if (isDifferentDate) {
|
|
429
|
+
let start: Date = new Date(eventStartTime.getTime());
|
|
430
|
+
let end: Date = util.addDays(util.resetTime(new Date(eventStartTime.getTime())), 1);
|
|
431
|
+
const endDate: Date = (eventEndTime.getHours() === 0 && eventEndTime.getMinutes() === 0) ?
|
|
432
|
+
eventEndTime : util.addDays(eventEndTime, 1);
|
|
433
|
+
let index: number = 1;
|
|
434
|
+
const eventLength: number = util.getDaysCount(eventStartTime.getTime(), endDate.getTime());
|
|
435
|
+
while (end <= eventEndTime && start.getTime() !== end.getTime()) {
|
|
436
|
+
const app: Record<string, any> = <Record<string, any>>extend({}, event);
|
|
437
|
+
app[eventFields.startTime] = start;
|
|
438
|
+
app[eventFields.endTime] = end;
|
|
439
|
+
app.data = { index: index, count: eventLength };
|
|
440
|
+
app.Guid = this.generateGuid();
|
|
441
|
+
app.isSpanned = true;
|
|
442
|
+
data.push(app);
|
|
443
|
+
start = end;
|
|
444
|
+
if ((util.resetTime(new Date(start.getTime())).getTime() === util.resetTime(new Date(eventEndTime.getTime())).getTime())
|
|
445
|
+
&& !(end.getTime() === eventEndTime.getTime())) {
|
|
446
|
+
end = new Date(start.getTime());
|
|
447
|
+
end = new Date(end.setHours(eventEndTime.getHours(), eventEndTime.getMinutes(), eventEndTime.getSeconds()));
|
|
448
|
+
} else {
|
|
449
|
+
end = util.addDays(util.resetTime(new Date(start.getTime())), 1);
|
|
450
|
+
}
|
|
451
|
+
index++;
|
|
452
|
+
}
|
|
453
|
+
} else {
|
|
454
|
+
data.push(event);
|
|
455
|
+
}
|
|
456
|
+
return data;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
public splitEvent(event: Record<string, any>, dateRender: Date[]): Record<string, any>[] {
|
|
460
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
461
|
+
let start: number = util.resetTime(event[fields.startTime]).getTime();
|
|
462
|
+
let end: number = util.resetTime(event[fields.endTime]).getTime();
|
|
463
|
+
if (util.getDateInMs(event[fields.endTime] as Date) <= 0) {
|
|
464
|
+
const temp: number = util.addDays(util.resetTime(event[fields.endTime]), -1).getTime();
|
|
465
|
+
end = start > temp ? start : temp;
|
|
466
|
+
}
|
|
467
|
+
const orgStart: number = start;
|
|
468
|
+
const orgEnd: number = end;
|
|
469
|
+
const ranges: Record<string, any>[] = [];
|
|
470
|
+
if (start !== end) {
|
|
471
|
+
if (start < dateRender[0].getTime()) {
|
|
472
|
+
start = dateRender[0].getTime();
|
|
473
|
+
}
|
|
474
|
+
if (end > dateRender[dateRender.length - 1].getTime()) {
|
|
475
|
+
end = dateRender[dateRender.length - 1].getTime();
|
|
476
|
+
}
|
|
477
|
+
let cStart: number = start;
|
|
478
|
+
for (let level: number = 0; level < this.slots.length; level++) {
|
|
479
|
+
let slot: number[] = <[number]><unknown>this.slots[parseInt(level.toString(), 10)];
|
|
480
|
+
if (this.parent.currentView === 'WorkWeek' || this.parent.currentView === 'TimelineWorkWeek'
|
|
481
|
+
|| this.parent.activeViewOptions.group.byDate || this.parent.activeViewOptions.showWeekend) {
|
|
482
|
+
const slotDates: Date[] = [];
|
|
483
|
+
for (const s of slot) {
|
|
484
|
+
slotDates.push(new Date(s));
|
|
485
|
+
}
|
|
486
|
+
const renderedDates: Date[] = this.getRenderedDates(slotDates);
|
|
487
|
+
if (!isNullOrUndefined(renderedDates) && renderedDates.length > 0) {
|
|
488
|
+
slot = [];
|
|
489
|
+
for (const date of renderedDates) {
|
|
490
|
+
slot.push(date.getTime());
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (typeof (slot) === 'number') {
|
|
495
|
+
const temp: number = slot;
|
|
496
|
+
slot = [];
|
|
497
|
+
slot.push(temp);
|
|
498
|
+
}
|
|
499
|
+
const firstSlot: number = <number>slot[0];
|
|
500
|
+
cStart = (cStart <= firstSlot && end >= firstSlot) ? firstSlot : cStart;
|
|
501
|
+
if (cStart > end || firstSlot > end) {
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
if (!this.parent.activeViewOptions.group.byDate && this.parent.activeViewOptions.showWeekend &&
|
|
505
|
+
this.parent.currentView !== 'WorkWeek' && this.parent.currentView !== 'TimelineWorkWeek') {
|
|
506
|
+
const startIndex: number = slot.indexOf(cStart);
|
|
507
|
+
if (startIndex !== -1) {
|
|
508
|
+
let endIndex: number = slot.indexOf(end);
|
|
509
|
+
const hasBreak: boolean = endIndex !== -1;
|
|
510
|
+
endIndex = hasBreak ? endIndex : slot.length - 1;
|
|
511
|
+
const count: number = ((endIndex - startIndex) + 1);
|
|
512
|
+
const isLeft: boolean = (slot[parseInt(startIndex.toString(), 10)] !== orgStart);
|
|
513
|
+
const isRight: boolean = (slot[parseInt(endIndex.toString(), 10)] !== orgEnd);
|
|
514
|
+
ranges.push(this.cloneEventObject(event, slot[parseInt(startIndex.toString(), 10)], slot[parseInt(endIndex.toString(), 10)], count, isLeft, isRight));
|
|
515
|
+
if (hasBreak) {
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
} else {
|
|
520
|
+
if (this.dateInRange(cStart, slot[0], slot[slot.length - 1])) {
|
|
521
|
+
const availSlot: number[] = [];
|
|
522
|
+
for (let i: number = 0; i < slot.length; i++) {
|
|
523
|
+
if (this.dateInRange(<number>slot[parseInt(i.toString(), 10)], orgStart, orgEnd)) {
|
|
524
|
+
availSlot.push(slot[parseInt(i.toString(), 10)]);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (availSlot.length > 0) {
|
|
528
|
+
if (!this.parent.activeViewOptions.group.byDate) {
|
|
529
|
+
const isLeft: boolean = (availSlot[0] !== orgStart);
|
|
530
|
+
const isRight: boolean = (availSlot[availSlot.length - 1] !== orgEnd);
|
|
531
|
+
ranges.push(this.cloneEventObject(
|
|
532
|
+
event, availSlot[0], availSlot[availSlot.length - 1], availSlot.length, isLeft, isRight));
|
|
533
|
+
} else {
|
|
534
|
+
for (const slot of availSlot) {
|
|
535
|
+
ranges.push(this.cloneEventObject(event, slot, slot, 1, (slot !== orgStart), (slot !== orgEnd)));
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
} else {
|
|
543
|
+
ranges.push(this.cloneEventObject(event, start, end, 1, false, false));
|
|
544
|
+
}
|
|
545
|
+
return ranges;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
public cloneEventObject(event: Record<string, any>, start: number, end: number, count: number, isLeft: boolean, isRight: boolean): Record<string, any> {
|
|
549
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
550
|
+
const e: Record<string, any> = extend({}, event, null, true) as Record<string, any>;
|
|
551
|
+
const data: Record<string, any> = { count: count, isLeft: isLeft, isRight: isRight };
|
|
552
|
+
data[fields.startTime] = event[fields.startTime];
|
|
553
|
+
data[fields.endTime] = event[fields.endTime];
|
|
554
|
+
e.data = data;
|
|
555
|
+
e[fields.startTime] = new Date(start);
|
|
556
|
+
e[fields.endTime] = new Date(end);
|
|
557
|
+
return e;
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
private dateInRange(date: number, start: number, end: number): boolean {
|
|
561
|
+
return start <= date && date <= end;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
public getSelectedEventElements(target: Element): Element[] {
|
|
565
|
+
this.removeSelectedAppointmentClass();
|
|
566
|
+
if (this.parent.selectedElements.length <= 0) {
|
|
567
|
+
this.parent.selectedElements.push(target);
|
|
568
|
+
} else {
|
|
569
|
+
const isAlreadySelected: Element[] = this.parent.selectedElements.filter((element: HTMLElement) =>
|
|
570
|
+
element.getAttribute('data-guid') === target.getAttribute('data-guid'));
|
|
571
|
+
if (isAlreadySelected.length <= 0) {
|
|
572
|
+
const elementSelector: string = 'div[data-guid="' + target.getAttribute('data-guid') + '"]';
|
|
573
|
+
const focusElements: Element[] = [].slice.call(this.parent.element.querySelectorAll(elementSelector));
|
|
574
|
+
for (const element of focusElements) {
|
|
575
|
+
this.parent.selectedElements.push(element);
|
|
576
|
+
}
|
|
577
|
+
} else {
|
|
578
|
+
const selectedElements: Element[] = this.parent.selectedElements.filter((element: HTMLElement) =>
|
|
579
|
+
element.getAttribute('data-guid') !== target.getAttribute('data-guid'));
|
|
580
|
+
this.parent.selectedElements = selectedElements;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (target && this.parent.selectedElements.length > 0) {
|
|
584
|
+
this.addSelectedAppointments(this.parent.selectedElements, false);
|
|
585
|
+
}
|
|
586
|
+
return this.parent.selectedElements;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
public getSelectedEvents(): EventClickArgs {
|
|
590
|
+
const eventSelect: Record<string, any>[] = [];
|
|
591
|
+
const elementSelect: HTMLElement[] = [];
|
|
592
|
+
const selectAppointments: Element[] = [].slice.call(this.parent.element.querySelectorAll('.' + cls.APPOINTMENT_BORDER)) as Element[];
|
|
593
|
+
selectAppointments.filter((element: HTMLElement) => {
|
|
594
|
+
const isAlreadyAdded: Record<string, any>[] = eventSelect.filter((event: Record<string, any>) => {
|
|
595
|
+
return event.Guid === element.getAttribute('data-guid');
|
|
596
|
+
});
|
|
597
|
+
if (isAlreadyAdded.length === 0) {
|
|
598
|
+
eventSelect.push(this.getEventByGuid(element.getAttribute('data-guid')));
|
|
599
|
+
}
|
|
600
|
+
elementSelect.push(element);
|
|
601
|
+
});
|
|
602
|
+
return {
|
|
603
|
+
event: eventSelect.length > 1 ? eventSelect : eventSelect[0],
|
|
604
|
+
element: elementSelect.length > 1 ? elementSelect : elementSelect[0]
|
|
605
|
+
} as EventClickArgs;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
public removeSelectedAppointmentClass(): void {
|
|
609
|
+
const selectedAppointments: Element[] = this.getSelectedAppointments();
|
|
610
|
+
removeClass(selectedAppointments, cls.APPOINTMENT_BORDER);
|
|
611
|
+
if (this.parent.currentView === 'Agenda' || this.parent.currentView === 'MonthAgenda') {
|
|
612
|
+
removeClass(selectedAppointments, cls.AGENDA_SELECTED_CELL);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
public addSelectedAppointments(cells: Element[], preventFocus?: boolean): void {
|
|
617
|
+
if (this.parent.currentView !== 'MonthAgenda') {
|
|
618
|
+
this.parent.removeSelectedClass();
|
|
619
|
+
}
|
|
620
|
+
addClass(cells, cls.APPOINTMENT_BORDER);
|
|
621
|
+
if (cells.length > 0 && !preventFocus) {
|
|
622
|
+
(cells[cells.length - 1] as HTMLElement).focus();
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
public getSelectedAppointments(): Element[] {
|
|
627
|
+
return [].slice.call(this.parent.element.querySelectorAll('.' + cls.APPOINTMENT_BORDER + ',.' + cls.APPOINTMENT_CLASS + ':focus'));
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
public focusElement(isFocused?: boolean): void {
|
|
631
|
+
if (this.parent.eventWindow.dialogObject && this.parent.eventWindow.dialogObject.visible) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
const activeEle: Element = document.activeElement;
|
|
635
|
+
const selectedCell: Element[] = this.parent.getSelectedCells();
|
|
636
|
+
if (selectedCell.length > 0 && ((activeEle && (this.parent.element.contains(activeEle) ||
|
|
637
|
+
selectedCell.indexOf(activeEle) !== -1)) || isFocused)) {
|
|
638
|
+
if (this.parent.keyboardInteractionModule) {
|
|
639
|
+
const target: HTMLTableCellElement = ((!isNullOrUndefined(this.parent.activeCellsData) &&
|
|
640
|
+
this.parent.activeCellsData.element) || selectedCell[selectedCell.length - 1]) as HTMLTableCellElement;
|
|
641
|
+
this.parent.keyboardInteractionModule.selectCells(target instanceof Array, target);
|
|
642
|
+
}
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const selectedAppointments: Element[] = this.getSelectedAppointments();
|
|
646
|
+
if (selectedAppointments.length > 0) {
|
|
647
|
+
if (this.parent.activeEventData && this.parent.activeEventData.element && selectedAppointments.indexOf(this.parent.activeEventData.element as Element) > -1) {
|
|
648
|
+
(this.parent.activeEventData.element as HTMLElement).focus();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
(selectedAppointments[selectedAppointments.length - 1] as HTMLElement).focus();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
public selectWorkCellByTime(eventsData: Record<string, any>[]): Element {
|
|
657
|
+
let target: Element;
|
|
658
|
+
if (this.parent.currentView === 'Agenda' || this.parent.currentView === 'MonthAgenda') {
|
|
659
|
+
return target;
|
|
660
|
+
}
|
|
661
|
+
if (eventsData.length > 0) {
|
|
662
|
+
const selectedObject: Record<string, any> = eventsData[eventsData.length - 1];
|
|
663
|
+
const eventStartTime: Date = <Date>selectedObject[this.parent.eventFields.startTime];
|
|
664
|
+
let nearestTime: number;
|
|
665
|
+
const isAllDay: boolean = this.isAllDayAppointment(selectedObject);
|
|
666
|
+
if (this.parent.currentView === 'Month' || isAllDay || !this.parent.activeViewOptions.timeScale.enable) {
|
|
667
|
+
nearestTime = new Date(+eventStartTime).setHours(0, 0, 0, 0);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
nearestTime = this.findNearestSlot(eventStartTime);
|
|
671
|
+
}
|
|
672
|
+
let targetArea: Element;
|
|
673
|
+
if (isAllDay && ['Day', 'Week', 'WorkWeek'].indexOf(this.parent.currentView) !== -1) {
|
|
674
|
+
targetArea = this.parent.getAllDayRow();
|
|
675
|
+
} else {
|
|
676
|
+
targetArea = this.parent.getContentTable();
|
|
677
|
+
}
|
|
678
|
+
let queryString: string = '[data-date="' + new Date(nearestTime).getTime() + '"]';
|
|
679
|
+
if (!isNullOrUndefined(this.parent.activeViewOptions.group.resources) &&
|
|
680
|
+
this.parent.activeViewOptions.group.resources.length > 0) {
|
|
681
|
+
queryString += '[data-group-index="' + this.getGroupIndexFromEvent(selectedObject) + '"]';
|
|
682
|
+
}
|
|
683
|
+
target = targetArea.querySelector(queryString) as Element;
|
|
684
|
+
if (target) {
|
|
685
|
+
this.parent.activeCellsData = this.parent.getCellDetails(target);
|
|
686
|
+
if (this.parent.keyboardInteractionModule) {
|
|
687
|
+
this.parent.keyboardInteractionModule.selectCells(false, target as HTMLTableCellElement);
|
|
688
|
+
}
|
|
689
|
+
return target;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return target;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
private findNearestSlot(appointmentTime: Date): number {
|
|
696
|
+
const msMajorInterval: number = this.parent.activeViewOptions.timeScale.interval * util.MS_PER_MINUTE;
|
|
697
|
+
const msInterval: number = msMajorInterval / this.parent.activeViewOptions.timeScale.slotCount;
|
|
698
|
+
const numberOfSlots: number = Math.round(util.MS_PER_DAY / msInterval);
|
|
699
|
+
const startTime: Date = new Date(appointmentTime);
|
|
700
|
+
startTime.setHours(0, 0, 0, 0);
|
|
701
|
+
const slots: Date[] = Array.from({ length: numberOfSlots }, (_: any, i: number) => {
|
|
702
|
+
const slotTime: Date = new Date(startTime.getTime() + i * msInterval);
|
|
703
|
+
return slotTime;
|
|
704
|
+
});
|
|
705
|
+
const nearestSlot: Date = slots.reduce((nearest: Date, slot: Date) => {
|
|
706
|
+
const difference: number = Math.abs(appointmentTime.getTime() - slot.getTime());
|
|
707
|
+
if (!nearest || difference < Math.abs(appointmentTime.getTime() - nearest.getTime())) {
|
|
708
|
+
return slot;
|
|
709
|
+
}
|
|
710
|
+
return nearest;
|
|
711
|
+
}, null);
|
|
712
|
+
return Math.trunc(nearestSlot.getTime() / 1000) * 1000;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
|
|
716
|
+
public getGroupIndexFromEvent(eventData: Record<string, any>): number {
|
|
717
|
+
let levelIndex: number;
|
|
718
|
+
let resource: ResourcesModel;
|
|
719
|
+
let levelName: string;
|
|
720
|
+
let idField: string;
|
|
721
|
+
for (let i: number = this.parent.resourceBase.resourceCollection.length - 1; i >= 0; i--) {
|
|
722
|
+
const resourceData: Record<string, any> | string | number = eventData[this.parent.resourceBase.resourceCollection[parseInt(i.toString(), 10)].field] as Record<string, any>;
|
|
723
|
+
if (!isNullOrUndefined(resourceData)) {
|
|
724
|
+
resource = this.parent.resourceBase.resourceCollection[parseInt(i.toString(), 10)];
|
|
725
|
+
levelIndex = i;
|
|
726
|
+
levelName = resource.name;
|
|
727
|
+
idField = resource.field;
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
if (isNullOrUndefined(levelName) && isNullOrUndefined(levelIndex)) {
|
|
732
|
+
levelName = this.parent.resourceCollection.slice(-1)[0].name;
|
|
733
|
+
levelIndex = this.parent.resourceCollection.length - 1;
|
|
734
|
+
idField = this.parent.resourceCollection.slice(-1)[0].field;
|
|
735
|
+
resource = this.parent.resourceCollection.filter((e: ResourcesModel, index: number) => {
|
|
736
|
+
if (e.name === levelName) {
|
|
737
|
+
levelIndex = index;
|
|
738
|
+
return e;
|
|
739
|
+
}
|
|
740
|
+
return null;
|
|
741
|
+
})[0];
|
|
742
|
+
}
|
|
743
|
+
const id: number = ((eventData[`${idField}`] instanceof Array) ?
|
|
744
|
+
(eventData[`${idField}`] as Record<string, any>)[0] : eventData[`${idField}`]) as number;
|
|
745
|
+
if (levelIndex > 0) {
|
|
746
|
+
const parentField: string = this.parent.resourceCollection[levelIndex - 1].field;
|
|
747
|
+
return this.parent.resourceBase.getIndexFromResourceId(id, levelName, resource, eventData, parentField);
|
|
748
|
+
} else {
|
|
749
|
+
return this.parent.resourceBase.getIndexFromResourceId(id, levelName, resource);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
public isAllDayAppointment(event: Record<string, any>): boolean {
|
|
754
|
+
const fieldMapping: EventFieldsMapping = this.parent.eventFields;
|
|
755
|
+
const isAllDay: boolean = event[fieldMapping.isAllDay] as boolean;
|
|
756
|
+
const isFullDay: boolean = ((util.getUniversalTime(<Date>event[fieldMapping.endTime]) - util.getUniversalTime(<Date>event[fieldMapping.startTime]))
|
|
757
|
+
/ util.MS_PER_DAY) >= 1;
|
|
758
|
+
return (isAllDay || (this.parent.eventSettings.spannedEventPlacement !== 'TimeSlot' && isFullDay)) ? true : false;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
public addEventListener(): void {
|
|
762
|
+
this.parent.on(event.documentClick, this.appointmentBorderRemove, this);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
public removeEventListener(): void {
|
|
766
|
+
this.parent.off(event.documentClick, this.appointmentBorderRemove);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
private appointmentBorderRemove(event: Event & CellClickEventArgs): void {
|
|
770
|
+
const element: HTMLElement = event.event.target as HTMLElement;
|
|
771
|
+
if (closest(element as Element, '.' + cls.APPOINTMENT_CLASS)) {
|
|
772
|
+
if (this.parent.currentView !== 'MonthAgenda') {
|
|
773
|
+
this.parent.removeSelectedClass();
|
|
774
|
+
}
|
|
775
|
+
} else if (!closest(element as Element, '.' + cls.POPUP_OPEN)) {
|
|
776
|
+
if (this.parent.uiStateValues.isTapHold && closest(element, '.' + cls.WORK_CELLS_CLASS + ',.' + cls.ALLDAY_CELLS_CLASS)) {
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
this.parent.uiStateValues.isTapHold = false;
|
|
780
|
+
this.removeSelectedAppointmentClass();
|
|
781
|
+
this.parent.selectedElements = [];
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
public wireAppointmentEvents(element: HTMLElement, event?: Record<string, any>, isPreventCrud: boolean = false): void {
|
|
786
|
+
const isReadOnly: boolean = (!isNullOrUndefined(event)) ? event[this.parent.eventFields.isReadonly] as boolean : false;
|
|
787
|
+
EventHandler.add(element, 'click', this.eventClick, this);
|
|
788
|
+
if (!this.parent.isAdaptive && !this.parent.activeViewOptions.readonly && !isReadOnly) {
|
|
789
|
+
EventHandler.add(element, 'touchend', this.eventTouchClick, this);
|
|
790
|
+
EventHandler.add(element, 'dblclick', this.eventDoubleClick, this);
|
|
791
|
+
}
|
|
792
|
+
if (!this.parent.activeViewOptions.readonly && !isReadOnly && !isPreventCrud) {
|
|
793
|
+
if (this.parent.resizeModule) {
|
|
794
|
+
this.parent.resizeModule.wireResizeEvent(element);
|
|
795
|
+
}
|
|
796
|
+
if (this.parent.dragAndDropModule) {
|
|
797
|
+
this.parent.dragAndDropModule.wireDragEvent(element);
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
private eventTouchClick(e: Event): void {
|
|
803
|
+
if (this.parent.uiStateValues.isTouchScroll || this.parent.uiStateValues.isTapHold || this.parent.uiStateValues.action) {
|
|
804
|
+
this.parent.uiStateValues.isTouchScroll = this.parent.uiStateValues.isTapHold = false;
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
setTimeout(() => this.isDoubleTapped = false, 250);
|
|
808
|
+
e.preventDefault();
|
|
809
|
+
if (this.isDoubleTapped) {
|
|
810
|
+
this.eventDoubleClick(e);
|
|
811
|
+
} else if (!this.isDoubleTapped) {
|
|
812
|
+
this.isDoubleTapped = true;
|
|
813
|
+
this.eventClick(e as Event & MouseEvent);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
public renderResizeHandler(element: HTMLElement, spanEvent: Record<string, any>, isReadOnly: boolean): void {
|
|
818
|
+
if (!this.parent.resizeModule || !this.parent.allowResizing || this.parent.activeViewOptions.readonly || isReadOnly) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
for (const resizeEdge of Object.keys(spanEvent)) {
|
|
822
|
+
const resizeHandler: HTMLElement = createElement('div', { className: cls.EVENT_RESIZE_CLASS });
|
|
823
|
+
switch (resizeEdge) {
|
|
824
|
+
case 'isLeft':
|
|
825
|
+
if (!spanEvent.isLeft) {
|
|
826
|
+
resizeHandler.appendChild(createElement('div', { className: 'e-left-right-resize' }));
|
|
827
|
+
addClass([resizeHandler], this.parent.enableRtl ? cls.RIGHT_RESIZE_HANDLER : cls.LEFT_RESIZE_HANDLER);
|
|
828
|
+
prepend([resizeHandler], element);
|
|
829
|
+
}
|
|
830
|
+
break;
|
|
831
|
+
case 'isRight':
|
|
832
|
+
if (!spanEvent.isRight) {
|
|
833
|
+
resizeHandler.appendChild(createElement('div', { className: 'e-left-right-resize' }));
|
|
834
|
+
addClass([resizeHandler], this.parent.enableRtl ? cls.LEFT_RESIZE_HANDLER : cls.RIGHT_RESIZE_HANDLER);
|
|
835
|
+
append([resizeHandler], element);
|
|
836
|
+
}
|
|
837
|
+
break;
|
|
838
|
+
case 'isTop':
|
|
839
|
+
if (!spanEvent.isTop) {
|
|
840
|
+
resizeHandler.appendChild(createElement('div', { className: 'e-top-bottom-resize' }));
|
|
841
|
+
addClass([resizeHandler], cls.TOP_RESIZE_HANDLER);
|
|
842
|
+
prepend([resizeHandler], element);
|
|
843
|
+
}
|
|
844
|
+
break;
|
|
845
|
+
case 'isBottom':
|
|
846
|
+
if (!spanEvent.isBottom) {
|
|
847
|
+
resizeHandler.appendChild(createElement('div', { className: 'e-top-bottom-resize' }));
|
|
848
|
+
addClass([resizeHandler], cls.BOTTOM_RESIZE_HANDLER);
|
|
849
|
+
append([resizeHandler], element);
|
|
850
|
+
}
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
private eventClick(eventData: Event & MouseEvent): void {
|
|
857
|
+
const target: HTMLElement = eventData.target as HTMLElement;
|
|
858
|
+
if (target.classList.contains(cls.DRAG_CLONE_CLASS) || target.classList.contains(cls.RESIZE_CLONE_CLASS) ||
|
|
859
|
+
target.classList.contains(cls.INLINE_SUBJECT_CLASS)) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
if ((eventData.ctrlKey || eventData.metaKey) && eventData.which === 1 && this.parent.keyboardInteractionModule) {
|
|
863
|
+
this.parent.quickPopup.quickPopup.hide();
|
|
864
|
+
this.parent.selectedElements = [].slice.call(this.parent.element.querySelectorAll('.' + cls.APPOINTMENT_BORDER)) as Element[];
|
|
865
|
+
const target: Element = closest(<Element>eventData.target, '.' + cls.APPOINTMENT_CLASS) as Element;
|
|
866
|
+
this.getSelectedEventElements(target);
|
|
867
|
+
this.activeEventData(eventData, false);
|
|
868
|
+
const selectArgs: SelectEventArgs = {
|
|
869
|
+
data: this.parent.activeEventData.event,
|
|
870
|
+
element: this.parent.activeEventData.element,
|
|
871
|
+
event: eventData, requestType: 'eventSelect'
|
|
872
|
+
};
|
|
873
|
+
this.parent.trigger(event.select, selectArgs);
|
|
874
|
+
const args: EventClickArgs = <EventClickArgs>extend(this.parent.activeEventData, { cancel: false, originalEvent: eventData });
|
|
875
|
+
this.parent.trigger(event.eventClick, args);
|
|
876
|
+
} else {
|
|
877
|
+
this.removeSelectedAppointmentClass();
|
|
878
|
+
this.activeEventData(eventData, true);
|
|
879
|
+
const selectEventArgs: SelectEventArgs = {
|
|
880
|
+
data: this.parent.activeEventData.event,
|
|
881
|
+
element: this.parent.activeEventData.element,
|
|
882
|
+
event: eventData, requestType: 'eventSelect'
|
|
883
|
+
};
|
|
884
|
+
this.parent.trigger(event.select, selectEventArgs);
|
|
885
|
+
const args: EventClickArgs = <EventClickArgs>extend(this.parent.activeEventData, { cancel: false, originalEvent: eventData });
|
|
886
|
+
this.parent.trigger(event.eventClick, args, (eventClickArgs: EventClickArgs) => {
|
|
887
|
+
if (eventClickArgs.cancel) {
|
|
888
|
+
this.removeSelectedAppointmentClass();
|
|
889
|
+
this.parent.selectedElements = [];
|
|
890
|
+
if (this.parent.quickPopup) {
|
|
891
|
+
this.parent.quickPopup.quickPopupHide();
|
|
892
|
+
}
|
|
893
|
+
} else {
|
|
894
|
+
if (this.parent.currentView === 'Agenda' || this.parent.currentView === 'MonthAgenda') {
|
|
895
|
+
addClass([this.parent.activeEventData.element as Element], cls.AGENDA_SELECTED_CELL);
|
|
896
|
+
}
|
|
897
|
+
if (this.parent.allowInline) {
|
|
898
|
+
const inlineArgs: InlineClickArgs = {
|
|
899
|
+
data: eventClickArgs.event as Record<string, any>,
|
|
900
|
+
element: eventClickArgs.element as HTMLElement,
|
|
901
|
+
type: 'Event'
|
|
902
|
+
};
|
|
903
|
+
this.parent.notify(event.inlineClick, inlineArgs);
|
|
904
|
+
} else {
|
|
905
|
+
this.parent.notify(event.eventClick, eventClickArgs);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
private eventDoubleClick(eventData: Event): void {
|
|
913
|
+
if (this.parent.quickPopup) {
|
|
914
|
+
this.parent.quickPopup.quickPopupHide(true);
|
|
915
|
+
}
|
|
916
|
+
if (eventData.type === 'touchend') {
|
|
917
|
+
this.activeEventData(eventData, true);
|
|
918
|
+
}
|
|
919
|
+
this.removeSelectedAppointmentClass();
|
|
920
|
+
this.parent.selectedElements = [];
|
|
921
|
+
if ((this.parent.activeEventData.element as HTMLElement).classList.contains(cls.INLINE_APPOINTMENT_CLASS) ||
|
|
922
|
+
(this.parent.activeEventData.element as HTMLElement).querySelector('.' + cls.INLINE_SUBJECT_CLASS)) {
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
const args: EventClickArgs = <EventClickArgs>extend(this.parent.activeEventData, { cancel: false, originalEvent: eventData });
|
|
926
|
+
this.parent.trigger(event.eventDoubleClick, args, (eventDoubleClickArgs: EventClickArgs) => {
|
|
927
|
+
if (!eventDoubleClickArgs.cancel) {
|
|
928
|
+
if (!isNullOrUndefined(this.parent.activeEventData.event) &&
|
|
929
|
+
isNullOrUndefined((<Record<string, any>>this.parent.activeEventData.event)[this.parent.eventFields.recurrenceID])) {
|
|
930
|
+
this.parent.eventWindow.openEditor(this.parent.activeEventData.event as Record<string, any>, 'Save');
|
|
931
|
+
} else {
|
|
932
|
+
this.parent.currentAction = 'EditOccurrence';
|
|
933
|
+
this.parent.quickPopup.openRecurrenceAlert();
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
});
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
public getEventByGuid(guid: string): Record<string, any> {
|
|
940
|
+
return this.parent.eventsProcessed.filter((data: Record<string, any>) => data.Guid === guid)[0];
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
public getEventById(id: number | string): Record<string, any> {
|
|
944
|
+
return this.parent.eventsData.filter((data: Record<string, any>) =>
|
|
945
|
+
data[this.parent.eventFields.id] === id)[0] as Record<string, any>;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
public generateGuid(): string {
|
|
949
|
+
return 'xyxxxxyx-xxxy-yxxx-xyxx-xxyxxxxyyxxx'.replace(/[xy]/g, (c: string) => {
|
|
950
|
+
const r: number = Math.random() * 16 | 0;
|
|
951
|
+
const v: number = (c === 'x') ? r : (r & 0x3 | 0x8);
|
|
952
|
+
return v.toString(16);
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
public getEventIDType(): string {
|
|
957
|
+
if (this.parent.eventsData.length !== 0) {
|
|
958
|
+
return typeof ((<Record<string, any>>this.parent.eventsData[0])[this.parent.eventFields.id]);
|
|
959
|
+
}
|
|
960
|
+
if (this.parent.blockData.length !== 0) {
|
|
961
|
+
return typeof ((<Record<string, any>>this.parent.blockData[0])[this.parent.eventFields.id]);
|
|
962
|
+
}
|
|
963
|
+
return 'string';
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
public getEventMaxID(resourceId?: number): number | string {
|
|
967
|
+
if (this.parent.eventsData.length < 1 && this.parent.blockData.length < 1) {
|
|
968
|
+
return 1;
|
|
969
|
+
}
|
|
970
|
+
let eventId: string | number;
|
|
971
|
+
const idType: string = this.getEventIDType();
|
|
972
|
+
if (idType === 'string') {
|
|
973
|
+
eventId = this.generateGuid();
|
|
974
|
+
}
|
|
975
|
+
if (idType === 'number') {
|
|
976
|
+
const datas: Record<string, number>[] = this.parent.eventsData.concat(this.parent.blockData) as Record<string, number>[];
|
|
977
|
+
const appIds: number[] = datas.map((event: Record<string, number>) => event[this.parent.eventFields.id]);
|
|
978
|
+
let maxId: number = appIds.reduce((a: number, b: number) => Math.max(a, b));
|
|
979
|
+
maxId = isNullOrUndefined(resourceId) ? maxId : maxId + resourceId;
|
|
980
|
+
eventId = maxId + 1;
|
|
981
|
+
}
|
|
982
|
+
return eventId;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
private activeEventData(eventData: Event, isMultiple: boolean): void {
|
|
986
|
+
const target: Element = closest(<Element>eventData.target, '.' + cls.APPOINTMENT_CLASS);
|
|
987
|
+
const guid: string = target.getAttribute('data-guid');
|
|
988
|
+
if (isMultiple) {
|
|
989
|
+
this.addSelectedAppointments([].slice.call(this.parent.element.querySelectorAll('div[data-guid="' + guid + '"]')), true);
|
|
990
|
+
(target as HTMLElement).focus();
|
|
991
|
+
}
|
|
992
|
+
let eventObject: Record<string, any> = this.getEventByGuid(guid);
|
|
993
|
+
if (eventObject && eventObject.isSpanned) {
|
|
994
|
+
eventObject = this.parent.eventsData.filter((obj: Record<string, any>) =>
|
|
995
|
+
obj[this.parent.eventFields.id] === eventObject[this.parent.eventFields.id])[0];
|
|
996
|
+
}
|
|
997
|
+
this.parent.activeEventData = { event: eventObject, element: target } as EventClickArgs;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
public generateOccurrence(event: Record<string, any>, viewDate?: Date, isMaxCount?: boolean): Record<string, any>[] {
|
|
1001
|
+
let startDate: Date = event[this.parent.eventFields.startTime] as Date;
|
|
1002
|
+
const endDate: Date = event[this.parent.eventFields.endTime] as Date;
|
|
1003
|
+
const eventRule: string = event[this.parent.eventFields.recurrenceRule] as string;
|
|
1004
|
+
const timeZoneDiff: number = endDate.getTimezoneOffset() - startDate.getTimezoneOffset();
|
|
1005
|
+
const duration: number = (endDate.getTime() - startDate.getTime()) - (timeZoneDiff * 60000);
|
|
1006
|
+
viewDate = new Date((viewDate || this.parent.activeView.startDate()).getTime() - duration);
|
|
1007
|
+
const exception: string = event[this.parent.eventFields.recurrenceException] as string;
|
|
1008
|
+
let maxCount: number;
|
|
1009
|
+
if (this.parent.currentView !== 'Agenda' && isMaxCount) {
|
|
1010
|
+
maxCount = util.getDateCount(viewDate, this.parent.activeView.endDate()) + 1;
|
|
1011
|
+
}
|
|
1012
|
+
const newTimezone: string = this.parent.timezone || this.parent.tzModule.getLocalTimezoneName();
|
|
1013
|
+
const firstDay: number = this.parent.activeViewOptions.firstDayOfWeek;
|
|
1014
|
+
const calendarMode: CalendarType = this.parent.calendarMode;
|
|
1015
|
+
if (event[this.parent.eventFields.recurrenceRule] && this.isDayBasedRecurrence(event) &&
|
|
1016
|
+
this.parent.timezone && event[this.parent.eventFields.startTimezone] && event[this.parent.eventFields.endTimezone]) {
|
|
1017
|
+
startDate = this.parent.tzModule.convert(event[this.parent.eventFields.startTime],
|
|
1018
|
+
this.parent.timezone, event[this.parent.eventFields.startTimezone]);
|
|
1019
|
+
}
|
|
1020
|
+
const dates: number[] =
|
|
1021
|
+
generate(startDate, eventRule, exception, firstDay, maxCount, viewDate, calendarMode, newTimezone);
|
|
1022
|
+
if (this.parent.currentView === 'Agenda' && eventRule.indexOf('COUNT') === -1 && eventRule.indexOf('UNTIL') === -1) {
|
|
1023
|
+
if (isNullOrUndefined(event.generatedDates)) {
|
|
1024
|
+
event.generatedDates = { start: new Date(dates[0]), end: new Date(dates[dates.length - 1]) };
|
|
1025
|
+
} else {
|
|
1026
|
+
if (dates[0] < (<Date>(<Record<string, any>>event.generatedDates).start).getTime()) {
|
|
1027
|
+
(<Record<string, any>>event.generatedDates).start = new Date(dates[0]);
|
|
1028
|
+
}
|
|
1029
|
+
if (dates[dates.length - 1] > (<Date>(<Record<string, any>>event.generatedDates).end).getTime()) {
|
|
1030
|
+
(<Record<string, any>>event.generatedDates).end = new Date(dates[dates.length - 1]);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
let isDSTAdjusted: boolean = false;
|
|
1035
|
+
let convertedDates: number[] = [];
|
|
1036
|
+
if (event[this.parent.eventFields.recurrenceRule] && this.isDayBasedRecurrence(event) &&
|
|
1037
|
+
this.parent.timezone && event[this.parent.eventFields.startTimezone] && event[this.parent.eventFields.endTimezone]) {
|
|
1038
|
+
isDSTAdjusted = true;
|
|
1039
|
+
convertedDates.push(...dates.map((date: number) =>
|
|
1040
|
+
this.parent.tzModule.convert(new Date(date), event[this.parent.eventFields.startTimezone], this.parent.timezone).getTime()
|
|
1041
|
+
));
|
|
1042
|
+
}
|
|
1043
|
+
convertedDates = convertedDates.length > 0 ? convertedDates : dates;
|
|
1044
|
+
const occurrenceCollection: Record<string, any>[] = [];
|
|
1045
|
+
for (let date of convertedDates) {
|
|
1046
|
+
const clonedObject: Record<string, any> = extend({}, event, null, true) as Record<string, any>;
|
|
1047
|
+
date = !isDSTAdjusted ? this.getDSTAdjustedTime(date, clonedObject) : date;
|
|
1048
|
+
clonedObject[this.parent.eventFields.startTime] = new Date(date);
|
|
1049
|
+
clonedObject[this.parent.eventFields.endTime] = new Date(new Date(date).setMilliseconds(duration));
|
|
1050
|
+
clonedObject[this.parent.eventFields.recurrenceID] = clonedObject[this.parent.eventFields.id];
|
|
1051
|
+
delete clonedObject[this.parent.eventFields.recurrenceException];
|
|
1052
|
+
delete clonedObject[this.parent.eventFields.followingID];
|
|
1053
|
+
clonedObject.Guid = this.generateGuid();
|
|
1054
|
+
occurrenceCollection.push(clonedObject);
|
|
1055
|
+
}
|
|
1056
|
+
return occurrenceCollection;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
private isDayBasedRecurrence(event: Record<string, any>): boolean {
|
|
1060
|
+
return (event[this.parent.eventFields.recurrenceRule].includes('BYMONTHDAY')
|
|
1061
|
+
|| event[this.parent.eventFields.recurrenceRule].includes('BYDAY'));
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
private getDSTAdjustedTime(date: number, event: Record<string, any>): number {
|
|
1065
|
+
let occurDate: number = date;
|
|
1066
|
+
if (this.parent.timezone &&
|
|
1067
|
+
(event[this.parent.eventFields.startTimezone] || event[this.parent.eventFields.endTimezone])) {
|
|
1068
|
+
const eventOffset: number = this.getDSTDiff(event[this.parent.eventFields.startTime], new Date(date), event[this.parent.eventFields.startTimezone]);
|
|
1069
|
+
const schOffset: number = this.getDSTDiff(event[this.parent.eventFields.startTime], new Date(date), this.parent.timezone);
|
|
1070
|
+
occurDate = (new Date(date).getTime() - (eventOffset - schOffset) * 60000);
|
|
1071
|
+
}
|
|
1072
|
+
return occurDate;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
private getDSTDiff(startDate: Date, occurDate: Date, timezone: string): number {
|
|
1076
|
+
const startOffset: number = this.parent.tzModule.offset(new Date(startDate), timezone);
|
|
1077
|
+
const occurOffset: number = this.parent.tzModule.offset(new Date(occurDate), timezone);
|
|
1078
|
+
return startOffset - occurOffset;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
public getParentEvent(eventObj: Record<string, any>, isParent: boolean = false): Record<string, any> {
|
|
1082
|
+
let parentEvent: Record<string, any>;
|
|
1083
|
+
do {
|
|
1084
|
+
eventObj = this.getFollowingEvent(eventObj);
|
|
1085
|
+
if (eventObj) {
|
|
1086
|
+
parentEvent = extend({}, eventObj, null, true) as Record<string, any>;
|
|
1087
|
+
}
|
|
1088
|
+
} while (eventObj && isParent);
|
|
1089
|
+
if (isParent && parentEvent) {
|
|
1090
|
+
const collection: Record<string, unknown[]> = this.getEventCollections(parentEvent);
|
|
1091
|
+
let followObj: Record<string, any> = collection.follow.slice(-1)[0] as Record<string, any>;
|
|
1092
|
+
if (collection.occurrence.length > 0 && !parentEvent[this.parent.eventFields.recurrenceException]) {
|
|
1093
|
+
followObj = collection.occurrence.slice(-1)[0] as Record<string, any>;
|
|
1094
|
+
}
|
|
1095
|
+
if (followObj) {
|
|
1096
|
+
parentEvent[this.parent.eventFields.recurrenceRule] = followObj[this.parent.eventFields.recurrenceRule];
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return parentEvent;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
public getEventCollections(parentObj: Record<string, any>, childObj?: Record<string, any>): { [key: string]: Record<string, any>[] } {
|
|
1103
|
+
const followingCollection: Record<string, any>[] = [];
|
|
1104
|
+
let occurrenceCollection: Record<string, any>[] = [];
|
|
1105
|
+
let followingEvent: Record<string, any> = parentObj;
|
|
1106
|
+
do {
|
|
1107
|
+
followingEvent = this.getFollowingEvent(followingEvent, true);
|
|
1108
|
+
if (followingEvent) {
|
|
1109
|
+
followingCollection.push(followingEvent);
|
|
1110
|
+
}
|
|
1111
|
+
occurrenceCollection = occurrenceCollection.concat(this.getOccurrenceEvent(followingEvent || parentObj));
|
|
1112
|
+
} while (followingEvent);
|
|
1113
|
+
let collections: { [key: string]: Record<string, any>[] } = {};
|
|
1114
|
+
if (childObj) {
|
|
1115
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1116
|
+
collections = {
|
|
1117
|
+
follow: followingCollection.filter((eventData: Record<string, any>) =>
|
|
1118
|
+
eventData[fields.startTime] >= childObj[fields.startTime]),
|
|
1119
|
+
occurrence: occurrenceCollection.filter((eventData: Record<string, any>) =>
|
|
1120
|
+
eventData[fields.startTime] >= childObj[fields.startTime])
|
|
1121
|
+
};
|
|
1122
|
+
} else {
|
|
1123
|
+
collections = { follow: followingCollection, occurrence: occurrenceCollection };
|
|
1124
|
+
}
|
|
1125
|
+
return collections;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
public getFollowingEvent(parentObj: Record<string, any>, isReverse?: boolean): Record<string, any> {
|
|
1129
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1130
|
+
let fieldValue: string | number;
|
|
1131
|
+
if (isReverse) {
|
|
1132
|
+
fieldValue = parentObj[fields.id] as string | number;
|
|
1133
|
+
} else {
|
|
1134
|
+
fieldValue = (parentObj[fields.recurrenceID] || parentObj[fields.followingID]) as string | number;
|
|
1135
|
+
}
|
|
1136
|
+
const parentApp: Record<string, any>[] = this.parent.eventsData.filter((data: Record<string, any>) =>
|
|
1137
|
+
data[isReverse ? fields.followingID : fields.id] === fieldValue);
|
|
1138
|
+
return parentApp.shift() as Record<string, any>;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
public isFollowingEvent(parentObj: Record<string, any>, childObj: Record<string, any>): boolean {
|
|
1142
|
+
const parentStart: Date = parentObj[this.parent.eventFields.startTime] as Date;
|
|
1143
|
+
const childStart: Date = childObj[this.parent.eventFields.startTime] as Date;
|
|
1144
|
+
return parentStart.getHours() === childStart.getHours() && parentStart.getMinutes() === childStart.getMinutes() &&
|
|
1145
|
+
parentStart.getSeconds() === childStart.getSeconds();
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
public getOccurrenceEvent(eventObj: Record<string, any>, isGuid: boolean = false, isFollowing: boolean = false): Record<string, any>[] {
|
|
1149
|
+
const idField: string = isGuid ? 'Guid' : (isFollowing) ? this.parent.eventFields.followingID : this.parent.eventFields.recurrenceID;
|
|
1150
|
+
const fieldKey: string = isGuid ? 'Guid' : this.parent.eventFields.id;
|
|
1151
|
+
const dataSource: Record<string, any>[] = isGuid ? this.parent.eventsProcessed : this.parent.eventsData;
|
|
1152
|
+
return dataSource.filter((data: Record<string, any>) => data[`${idField}`] === eventObj[`${fieldKey}`]);
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
public getOccurrencesByID(id: number | string): Record<string, any>[] {
|
|
1156
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1157
|
+
let occurrenceCollection: Record<string, any>[] = [];
|
|
1158
|
+
const parentObject: Record<string, any>[] = this.parent.eventsData.filter((obj: Record<string, any>) => obj[fields.id] === id);
|
|
1159
|
+
for (const event of parentObject) {
|
|
1160
|
+
if (!isNullOrUndefined(event[fields.recurrenceRule])) {
|
|
1161
|
+
occurrenceCollection = occurrenceCollection.concat(this.generateOccurrence(event));
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return occurrenceCollection;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
public getOccurrencesByRange(startTime: Date, endTime: Date): Record<string, any>[] {
|
|
1168
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1169
|
+
let occurrenceCollection: Record<string, any>[] = [];
|
|
1170
|
+
for (const event of this.parent.eventsData) {
|
|
1171
|
+
if (!isNullOrUndefined(event[fields.recurrenceRule])) {
|
|
1172
|
+
occurrenceCollection = occurrenceCollection.concat(this.generateOccurrence(event));
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
const filter: Record<string, any>[] = occurrenceCollection.filter((obj: Record<string, any>) =>
|
|
1176
|
+
obj[fields.startTime] >= startTime && obj[fields.endTime] <= endTime && !isNullOrUndefined(obj[fields.recurrenceID]));
|
|
1177
|
+
return filter;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
public getDeletedOccurrences(recurrenceData: string | number | Record<string, any>): Record<string, any>[] {
|
|
1181
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1182
|
+
let parentObject: Record<string, any>;
|
|
1183
|
+
const deletedOccurrences: Record<string, any>[] = [];
|
|
1184
|
+
if (typeof recurrenceData === 'string' || typeof recurrenceData === 'number') {
|
|
1185
|
+
parentObject = this.parent.eventsData.filter((obj: Record<string, any>) =>
|
|
1186
|
+
obj[fields.id] === recurrenceData)[0] as Record<string, any>;
|
|
1187
|
+
} else {
|
|
1188
|
+
parentObject = extend({}, recurrenceData, null, true) as Record<string, any>;
|
|
1189
|
+
}
|
|
1190
|
+
if (parentObject[fields.recurrenceException]) {
|
|
1191
|
+
const exDateString: string[] = (<string>parentObject[fields.recurrenceException]).split(',');
|
|
1192
|
+
for (let i: number = 0, len: number = exDateString.length; i < len; i++) {
|
|
1193
|
+
const edited: Record<string, any>[] = this.parent.eventsData.filter((eventObj: Record<string, any>) =>
|
|
1194
|
+
eventObj[fields.recurrenceID] === parentObject[fields.id] && eventObj[fields.recurrenceException] === exDateString[parseInt(i.toString(), 10)]);
|
|
1195
|
+
if (edited.length === 0) {
|
|
1196
|
+
const exDate: Date = getDateFromRecurrenceDateString(exDateString[parseInt(i.toString(), 10)]);
|
|
1197
|
+
const childObject: Record<string, any> = extend({}, recurrenceData, null, true) as Record<string, any>;
|
|
1198
|
+
childObject[fields.recurrenceID] = parentObject[fields.id];
|
|
1199
|
+
delete childObject[fields.followingID];
|
|
1200
|
+
childObject[fields.recurrenceException] = exDateString[parseInt(i.toString(), 10)];
|
|
1201
|
+
const startDate: Date = new Date(exDate.getTime());
|
|
1202
|
+
const time: number = (<Date>parentObject[fields.endTime]).getTime() - (<Date>parentObject[fields.startTime]).getTime();
|
|
1203
|
+
const endDate: Date = new Date(startDate.getTime());
|
|
1204
|
+
endDate.setMilliseconds(time);
|
|
1205
|
+
childObject[fields.startTime] = new Date(startDate.getTime());
|
|
1206
|
+
childObject[fields.endTime] = new Date(endDate.getTime());
|
|
1207
|
+
deletedOccurrences.push(childObject);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return deletedOccurrences;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
public applyResourceColor(element: HTMLElement, data: Record<string, any>, type: string, index?: string[], alpha?: string): void {
|
|
1215
|
+
if (!this.parent.resourceBase) {
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
const alphaColor: CallbackFunction = (color: string, alpha: string): string => {
|
|
1219
|
+
color = color.replace('#', '');
|
|
1220
|
+
const r: number = parseInt(color.substring(0, color.length / 3), 16);
|
|
1221
|
+
const g: number = parseInt(color.substring(color.length / 3, 2 * color.length / 3), 16);
|
|
1222
|
+
const b: number = parseInt(color.substring(2 * color.length / 3, 3 * color.length / 3), 16);
|
|
1223
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
1224
|
+
};
|
|
1225
|
+
// index refers groupOrder
|
|
1226
|
+
const color: string = this.parent.resourceBase.getResourceColor(data, index);
|
|
1227
|
+
if (color) {
|
|
1228
|
+
element.style[<any>type] = !isNullOrUndefined(alpha) ? alphaColor(color, alpha) : color;
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
public createBlockAppointmentElement(record: Record<string, any>, resIndex: number, isResourceEventTemplate: boolean): HTMLElement {
|
|
1233
|
+
const eventSubject: string = (record[this.parent.eventFields.subject] || this.parent.eventSettings.fields.subject.default) as string;
|
|
1234
|
+
const appointmentWrapper: HTMLElement = createElement('div', {
|
|
1235
|
+
className: cls.BLOCK_APPOINTMENT_CLASS,
|
|
1236
|
+
attrs: {
|
|
1237
|
+
'data-id': 'Appointment_' + record[this.parent.eventFields.id],
|
|
1238
|
+
'aria-disabled': 'true'
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
let templateElement: HTMLElement[];
|
|
1242
|
+
if (!isNullOrUndefined(this.parent.activeViewOptions.eventTemplate)) {
|
|
1243
|
+
const scheduleId: string = this.parent.element.id + '_';
|
|
1244
|
+
const viewName: string = this.parent.activeViewOptions.eventTemplateName;
|
|
1245
|
+
const templateId: string = scheduleId + viewName + 'eventTemplate';
|
|
1246
|
+
const templateName: string = isResourceEventTemplate && this.parent.currentView.indexOf('Year') === -1 ?
|
|
1247
|
+
this.parent.getEventTemplateName(resIndex) : 'eventTemplate';
|
|
1248
|
+
templateElement = this.parent.getAppointmentTemplate()(record, this.parent, templateName, templateId, false,
|
|
1249
|
+
undefined, undefined, this.parent.root);
|
|
1250
|
+
} else {
|
|
1251
|
+
const appointmentSubject: HTMLElement = createElement('div', { className: cls.SUBJECT_CLASS });
|
|
1252
|
+
this.parent.sanitize(eventSubject, appointmentSubject);
|
|
1253
|
+
templateElement = [appointmentSubject];
|
|
1254
|
+
}
|
|
1255
|
+
append(templateElement, appointmentWrapper);
|
|
1256
|
+
this.setWrapperAttributes(appointmentWrapper, resIndex);
|
|
1257
|
+
return appointmentWrapper;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
public setWrapperAttributes(appointmentWrapper: HTMLElement, resIndex: number): void {
|
|
1261
|
+
if (!isNullOrUndefined(this.cssClass)) {
|
|
1262
|
+
addClass([appointmentWrapper], this.cssClass);
|
|
1263
|
+
}
|
|
1264
|
+
if (this.parent.activeViewOptions.group.resources.length > 0) {
|
|
1265
|
+
appointmentWrapper.setAttribute('data-group-index', resIndex.toString());
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
public getReadonlyAttribute(event: Record<string, any>): string {
|
|
1270
|
+
return (event[this.parent.eventFields.isReadonly] || this.parent.readonly).toString();
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
public isBlockRange(eventData: Record<string, any> | Record<string, any>[]): boolean {
|
|
1274
|
+
const eventCollection: Record<string, any>[] = (eventData instanceof Array) ? eventData : [eventData];
|
|
1275
|
+
let isBlockAlert: boolean = false;
|
|
1276
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1277
|
+
for (const event of eventCollection as Record<string, any>[]) {
|
|
1278
|
+
let dataCol: Record<string, any>[] = [];
|
|
1279
|
+
if (!isNullOrUndefined(event[fields.recurrenceRule]) &&
|
|
1280
|
+
(isNullOrUndefined(event[fields.recurrenceID]) || event[fields.id] === event[fields.recurrenceID])) {
|
|
1281
|
+
dataCol = this.generateOccurrence(event);
|
|
1282
|
+
} else {
|
|
1283
|
+
dataCol.push(event);
|
|
1284
|
+
}
|
|
1285
|
+
for (const data of dataCol) {
|
|
1286
|
+
const filterBlockEvents: Record<string, any>[] = this.filterBlockEvents(data);
|
|
1287
|
+
if (filterBlockEvents.length > 0) {
|
|
1288
|
+
isBlockAlert = true;
|
|
1289
|
+
break;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
this.parent.uiStateValues.isBlock = isBlockAlert;
|
|
1294
|
+
return isBlockAlert;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
public getFilterEventsList(dataSource: Record<string, any>[], query: Predicate): Record<string, any>[] {
|
|
1298
|
+
return new DataManager(dataSource).executeLocal(new Query().where(query)) as Record<string, any>[];
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
public getSeriesEvents(parentEvent: Record<string, any>, startTime?: string): Record<string, any>[] {
|
|
1302
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1303
|
+
startTime = isNullOrUndefined(startTime) ? parentEvent[fields.startTime] as string : startTime;
|
|
1304
|
+
let deleteFutureEditEvents: Record<string, any>;
|
|
1305
|
+
let futureEvents: Record<string, any>[];
|
|
1306
|
+
const deleteFutureEditEventList: Record<string, any>[] = [];
|
|
1307
|
+
let delId: string = parentEvent[fields.id] as string;
|
|
1308
|
+
let followingId: string = parentEvent[fields.followingID] as string;
|
|
1309
|
+
let deleteFutureEvent: Predicate;
|
|
1310
|
+
const startTimeQuery: string = this.parent.currentAction === 'EditSeries' ? 'greaterthan' : 'greaterthanorequal';
|
|
1311
|
+
do {
|
|
1312
|
+
deleteFutureEvent = ((new Predicate(fields.followingID, 'equal', delId))).
|
|
1313
|
+
and(new Predicate(fields.startTime, startTimeQuery, startTime));
|
|
1314
|
+
futureEvents = this.getFilterEventsList(this.parent.eventsData, deleteFutureEvent);
|
|
1315
|
+
deleteFutureEditEvents = futureEvents.slice(-1)[0];
|
|
1316
|
+
if (!isNullOrUndefined(deleteFutureEditEvents) && deleteFutureEditEvents[fields.id] !== followingId) {
|
|
1317
|
+
deleteFutureEditEventList.push(deleteFutureEditEvents);
|
|
1318
|
+
delId = deleteFutureEditEvents[fields.id] as string;
|
|
1319
|
+
followingId = deleteFutureEditEvents[fields.followingID] as string;
|
|
1320
|
+
} else { followingId = null; }
|
|
1321
|
+
} while (futureEvents.length === 1 && !isNullOrUndefined(deleteFutureEditEvents[fields.followingID]));
|
|
1322
|
+
return deleteFutureEditEventList;
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
public getEditedOccurrences(deleteFutureEditEventList: Record<string, any>[], startTime?: string): Record<string, any>[] {
|
|
1326
|
+
const fields: EventFieldsMapping = this.parent.eventFields;
|
|
1327
|
+
let deleteRecurrenceEventList: Record<string, any>[] = [];
|
|
1328
|
+
let delEditedEvents: Record<string, any>[];
|
|
1329
|
+
for (const event of deleteFutureEditEventList) {
|
|
1330
|
+
let delEventQuery: Predicate = new Predicate(fields.recurrenceID, 'equal', event[fields.id] as string).
|
|
1331
|
+
or(new Predicate(fields.recurrenceID, 'equal', event[fields.followingID] as string).
|
|
1332
|
+
and(new Predicate(fields.recurrenceID, 'notequal', undefined)).
|
|
1333
|
+
and(new Predicate(fields.recurrenceID, 'notequal', null)));
|
|
1334
|
+
if (this.parent.currentAction === 'EditFollowingEvents' || this.parent.currentAction === 'DeleteFollowingEvents') {
|
|
1335
|
+
delEventQuery = delEventQuery.and(new Predicate(fields.startTime, 'greaterthanorequal', startTime));
|
|
1336
|
+
}
|
|
1337
|
+
delEditedEvents = this.getFilterEventsList(this.parent.eventsData, delEventQuery);
|
|
1338
|
+
deleteRecurrenceEventList = deleteRecurrenceEventList.concat(delEditedEvents);
|
|
1339
|
+
}
|
|
1340
|
+
return deleteRecurrenceEventList;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
public getRenderedDates(dateRender: Date[]): Date[] {
|
|
1344
|
+
let firstDate: number = 0;
|
|
1345
|
+
let lastDate: number = dateRender.length;
|
|
1346
|
+
let filteredDates: Date[];
|
|
1347
|
+
const maxDate: Date = isNullOrUndefined(this.parent.maxDate) ? new Date(2099, 11, 31) : this.parent.maxDate;
|
|
1348
|
+
const minDate: Date = isNullOrUndefined(this.parent.minDate) ? new Date(1900, 0, 1) : this.parent.minDate;
|
|
1349
|
+
if (dateRender[0] < minDate && dateRender[dateRender.length - 1] > maxDate) {
|
|
1350
|
+
for (let i: number = 0; i < dateRender.length; i++) {
|
|
1351
|
+
if (util.resetTime(dateRender[parseInt(i.toString(), 10)]).getTime() === util.resetTime(new Date(minDate)).getTime()) {
|
|
1352
|
+
firstDate = i;
|
|
1353
|
+
}
|
|
1354
|
+
if (util.resetTime(dateRender[parseInt(i.toString(), 10)]).getTime() === util.resetTime(new Date(maxDate)).getTime()) {
|
|
1355
|
+
lastDate = i;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
filteredDates = dateRender.filter((date: Date) => date >= dateRender[parseInt(firstDate.toString(), 10)] && date <= dateRender[parseInt(lastDate.toString(), 10)]);
|
|
1359
|
+
}
|
|
1360
|
+
return filteredDates;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
public isValidEvent(eventObj: Record<string, any>, start: Date, end: Date, schedule: { [key: string]: Date }): boolean {
|
|
1364
|
+
const isHourRange: boolean = end.getTime() > schedule.startHour.getTime() && start.getTime() < schedule.endHour.getTime();
|
|
1365
|
+
const isSameRange: boolean = schedule.startHour.getTime() <= start.getTime() &&
|
|
1366
|
+
(<Date>eventObj[this.parent.eventFields.startTime]).getTime() >= schedule.startHour.getTime() &&
|
|
1367
|
+
(<Date>eventObj[this.parent.eventFields.endTime]).getTime() < schedule.endHour.getTime() && start.getTime() === end.getTime();
|
|
1368
|
+
return isHourRange || isSameRange;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
public allDayExpandScroll(dateHeader: HTMLElement): void {
|
|
1372
|
+
let indentHeight: number = 0;
|
|
1373
|
+
const headerRows: HTMLElement[] = [].slice.call(this.parent.element.querySelectorAll('.' + cls.HEADER_ROW_CLASS));
|
|
1374
|
+
headerRows.forEach((element: HTMLElement) => {
|
|
1375
|
+
const tdEle: HTMLElement[] = [].slice.call(element.children);
|
|
1376
|
+
tdEle.forEach((ele: HTMLElement) => { ele.style.top = indentHeight + 'px'; });
|
|
1377
|
+
indentHeight += element.offsetHeight;
|
|
1378
|
+
});
|
|
1379
|
+
indentHeight = dateHeader.offsetHeight - indentHeight;
|
|
1380
|
+
(this.parent.element.querySelector('.' + cls.ALLDAY_CELLS_CLASS) as HTMLElement).style.height = (indentHeight / 12) + 'em';
|
|
1381
|
+
if (this.parent.uiStateValues.expand) {
|
|
1382
|
+
addClass([dateHeader], cls.ALLDAY_APPOINTMENT_SCROLL);
|
|
1383
|
+
} else {
|
|
1384
|
+
removeClass([dateHeader], cls.ALLDAY_APPOINTMENT_SCROLL);
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
public updateEventMinimumDuration(startEndHours: Record<string, Date>, startTime: Date, endTime: Date): Record<string, Date> {
|
|
1389
|
+
if (startTime.getTime() < endTime.getTime() || (startTime.getTime() === endTime.getTime() &&
|
|
1390
|
+
(startEndHours.startHour.getTime() < endTime.getTime() && startEndHours.endHour.getTime() > startTime.getTime()) &&
|
|
1391
|
+
this.parent.currentView.indexOf('Timeline') === -1)) {
|
|
1392
|
+
const eventDuration: number = (util.getUniversalTime(endTime) - util.getUniversalTime(startTime)) / util.MS_PER_MINUTE;
|
|
1393
|
+
if (eventDuration < this.parent.eventSettings.minimumEventDuration) {
|
|
1394
|
+
const tempEnd: Date = new Date(startTime);
|
|
1395
|
+
tempEnd.setMinutes(tempEnd.getMinutes() + this.parent.eventSettings.minimumEventDuration);
|
|
1396
|
+
endTime = tempEnd;
|
|
1397
|
+
if (endTime.getTime() > startEndHours.endHour.getTime()) {
|
|
1398
|
+
const tempStart: Date = new Date(startEndHours.endHour.getTime());
|
|
1399
|
+
tempStart.setMinutes(tempStart.getMinutes() - this.parent.eventSettings.minimumEventDuration);
|
|
1400
|
+
startTime = tempStart;
|
|
1401
|
+
endTime = startEndHours.endHour;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return { startDate: startTime, endDate: endTime };
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
public createEventWrapper(type: string = '', index: number = 0): HTMLElement {
|
|
1409
|
+
const tr: HTMLElement = createElement('tr');
|
|
1410
|
+
const levels: TdData[] = this.parent.activeView.colLevels.slice(-1)[0];
|
|
1411
|
+
const className: string = (this.parent as any).isReact && this.parent.activeViewOptions.eventTemplate ?
|
|
1412
|
+
' ' + cls.APPOINTMENT_WRAPPER_HIDDEN_CLASS : '';
|
|
1413
|
+
for (let i: number = 0, len: number = levels.length; i < len; i++) {
|
|
1414
|
+
const col: TdData = levels[parseInt(i.toString(), 10)];
|
|
1415
|
+
const appointmentWrap: HTMLElement = createElement('td', {
|
|
1416
|
+
className: (type === 'allDay') ? cls.ALLDAY_APPOINTMENT_WRAPPER_CLASS + className : (type === 'timeIndicator') ?
|
|
1417
|
+
cls.TIMELINE_WRAPPER_CLASS : cls.DAY_WRAPPER_CLASS + className, attrs: { 'data-date': col.date.getTime().toString() }
|
|
1418
|
+
});
|
|
1419
|
+
if (!isNullOrUndefined(col.groupIndex)) {
|
|
1420
|
+
appointmentWrap.setAttribute('data-group-index', col.groupIndex.toString());
|
|
1421
|
+
}
|
|
1422
|
+
if (type === '') {
|
|
1423
|
+
const innerWrapper: HTMLElement = createElement('div', {
|
|
1424
|
+
id: cls.APPOINTMENT_WRAPPER_CLASS + '-' + index.toString(),
|
|
1425
|
+
className: cls.APPOINTMENT_WRAPPER_CLASS
|
|
1426
|
+
});
|
|
1427
|
+
appointmentWrap.appendChild(innerWrapper);
|
|
1428
|
+
}
|
|
1429
|
+
tr.appendChild(appointmentWrap);
|
|
1430
|
+
index = index + 1;
|
|
1431
|
+
}
|
|
1432
|
+
return tr;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
public getPageCoordinates(e: MouseEvent & TouchEvent): (MouseEvent & TouchEvent) | Touch {
|
|
1436
|
+
if (isNullOrUndefined(e)) {
|
|
1437
|
+
return e;
|
|
1438
|
+
}
|
|
1439
|
+
const eventArgs: TouchEvent = (e as Record<string, any> & MouseEvent & TouchEvent).event as TouchEvent;
|
|
1440
|
+
return eventArgs && eventArgs.changedTouches ? eventArgs.changedTouches[0] : e.changedTouches ? e.changedTouches[0] :
|
|
1441
|
+
(<MouseEvent & TouchEvent>eventArgs) || e;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
public renderSpannedIcon(element: HTMLElement, spanEvent: Record<string, any>): void {
|
|
1445
|
+
const iconElement: HTMLElement = createElement('div', { className: cls.EVENT_INDICATOR_CLASS + ' ' + cls.ICON });
|
|
1446
|
+
if (spanEvent.isLeft) {
|
|
1447
|
+
const iconLeft: HTMLElement = iconElement.cloneNode() as HTMLElement;
|
|
1448
|
+
addClass([iconLeft], cls.EVENT_ICON_LEFT_CLASS);
|
|
1449
|
+
prepend([iconLeft], element);
|
|
1450
|
+
}
|
|
1451
|
+
if (spanEvent.isRight) {
|
|
1452
|
+
const iconRight: HTMLElement = iconElement.cloneNode() as HTMLElement;
|
|
1453
|
+
addClass([iconRight], cls.EVENT_ICON_RIGHT_CLASS);
|
|
1454
|
+
append([iconRight], element);
|
|
1455
|
+
}
|
|
1456
|
+
if (spanEvent.isTop) {
|
|
1457
|
+
const iconTop: HTMLElement = iconElement.cloneNode() as HTMLElement;
|
|
1458
|
+
addClass([iconTop], cls.EVENT_ICON_UP_CLASS);
|
|
1459
|
+
prepend([iconTop], element);
|
|
1460
|
+
}
|
|
1461
|
+
if (spanEvent.isBottom) {
|
|
1462
|
+
const iconBottom: HTMLElement = iconElement.cloneNode() as HTMLElement;
|
|
1463
|
+
addClass([iconBottom], cls.EVENT_ICON_DOWN_CLASS);
|
|
1464
|
+
append([iconBottom], element);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
public addCellHeight(selector: string, eventHeight: number, eventGap: number, headerHeight: number, indHeight: number, isScrollUpdate: boolean = true): void {
|
|
1469
|
+
if (this.parent.activeViewOptions.maxEventsPerRow && !this.parent.rowAutoHeight) {
|
|
1470
|
+
const rows: HTMLElement[] = [].slice.call(this.parent.element.querySelectorAll(selector));
|
|
1471
|
+
const weekNumberRows: HTMLElement[] = this.parent.showWeekNumber
|
|
1472
|
+
? [].slice.call(this.parent.element.querySelectorAll('.' + cls.WEEK_NUMBER_WRAPPER_CLASS + ' tbody tr'))
|
|
1473
|
+
: [];
|
|
1474
|
+
for (const row of rows) {
|
|
1475
|
+
const height: number = (this.parent.activeViewOptions.maxEventsPerRow *
|
|
1476
|
+
((eventHeight + (this.parent.currentView === 'Month' ? eventGap : 2)))) + headerHeight + indHeight;
|
|
1477
|
+
if (weekNumberRows.length > 0) {
|
|
1478
|
+
setStyleAttribute(weekNumberRows[rows.indexOf(row)].firstElementChild as HTMLElement, { 'height': height + 'px' });
|
|
1479
|
+
}
|
|
1480
|
+
setStyleAttribute(row.firstElementChild as HTMLElement, { 'height': height + 'px' });
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
if (!this.parent.enablePersistence && !this.parent.activeViewOptions.allowVirtualScrolling && isScrollUpdate) {
|
|
1484
|
+
this.parent.notify(event.contentReady, {});
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
private unWireEvents(): void {
|
|
1490
|
+
const appElements: Element[] = [].slice.call(this.parent.element.querySelectorAll('.' + cls.APPOINTMENT_CLASS));
|
|
1491
|
+
for (const element of appElements) {
|
|
1492
|
+
EventHandler.clearEvents(element);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
public destroy(): void {
|
|
1497
|
+
this.unWireEvents();
|
|
1498
|
+
this.parent = null;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
}
|