react-big-schedule 8.1.0 → 9.0.1
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/README.md +24 -1129
- package/dist/calendar/Calendar.d.ts +28 -0
- package/dist/calendar/Calendar.js +95 -0
- package/dist/calendar/Toolbar.d.ts +18 -0
- package/dist/calendar/Toolbar.js +6 -0
- package/dist/calendar/recurrence.check.d.ts +1 -0
- package/dist/calendar/recurrence.check.js +49 -0
- package/dist/calendar/recurrence.d.ts +8 -0
- package/dist/calendar/recurrence.js +90 -0
- package/dist/calendar/timezone.d.ts +6 -0
- package/dist/calendar/timezone.js +14 -0
- package/dist/calendar/types.d.ts +187 -0
- package/dist/calendar/types.js +1 -0
- package/dist/calendar/useEventSources.d.ts +11 -0
- package/dist/calendar/useEventSources.js +89 -0
- package/dist/calendar/useRecurrence.d.ts +4 -0
- package/dist/calendar/useRecurrence.js +15 -0
- package/dist/calendar/utils.d.ts +38 -0
- package/dist/calendar/utils.js +143 -0
- package/dist/calendar/views/DayGridView.d.ts +3 -0
- package/dist/calendar/views/DayGridView.js +375 -0
- package/dist/calendar/views/ListView.d.ts +4 -0
- package/dist/calendar/views/ListView.js +56 -0
- package/dist/calendar/views/MultiMonthView.d.ts +4 -0
- package/dist/calendar/views/MultiMonthView.js +36 -0
- package/dist/calendar/views/TimeGridView.d.ts +3 -0
- package/dist/calendar/views/TimeGridView.js +334 -0
- package/dist/calendar/views/daygrid/DayCell.d.ts +19 -0
- package/dist/calendar/views/daygrid/DayCell.js +17 -0
- package/dist/calendar/views/daygrid/EventChip.d.ts +19 -0
- package/dist/calendar/views/daygrid/EventChip.js +40 -0
- package/dist/calendar/views/daygrid/layout.d.ts +30 -0
- package/dist/calendar/views/daygrid/layout.js +63 -0
- package/dist/calendar/views/list/bucket.d.ts +8 -0
- package/dist/calendar/views/list/bucket.js +37 -0
- package/dist/calendar/views/multimonth/Cell.d.ts +12 -0
- package/dist/calendar/views/multimonth/Cell.js +44 -0
- package/dist/calendar/views/multimonth/Continuous.d.ts +8 -0
- package/dist/calendar/views/multimonth/Continuous.js +28 -0
- package/dist/calendar/views/multimonth/MonthGrid.d.ts +10 -0
- package/dist/calendar/views/multimonth/MonthGrid.js +36 -0
- package/dist/calendar/views/multimonth/shared.d.ts +27 -0
- package/dist/calendar/views/multimonth/shared.js +40 -0
- package/dist/calendar/views/timegrid/DayColumn.d.ts +49 -0
- package/dist/calendar/views/timegrid/DayColumn.js +86 -0
- package/dist/calendar/views/timegrid/model.d.ts +55 -0
- package/dist/calendar/views/timegrid/model.js +102 -0
- package/dist/components/AddMore.d.ts +13 -0
- package/dist/components/AddMore.js +9 -42
- package/dist/components/AddMorePopover.d.ts +13 -0
- package/dist/components/AddMorePopover.js +24 -95
- package/dist/components/AgendaEventItem.d.ts +10 -0
- package/dist/components/AgendaEventItem.js +33 -81
- package/dist/components/AgendaResourceEvents.d.ts +10 -0
- package/dist/components/AgendaResourceEvents.js +37 -91
- package/dist/components/AgendaView.d.ts +9 -0
- package/dist/components/AgendaView.js +10 -69
- package/dist/components/BodyView.d.ts +11 -0
- package/dist/components/BodyView.js +36 -67
- package/dist/components/DnDContext.d.ts +48 -0
- package/dist/components/DnDContext.js +200 -221
- package/dist/components/DnDSource.d.ts +49 -0
- package/dist/components/DnDSource.js +125 -120
- package/dist/components/EventItem.d.ts +41 -0
- package/dist/components/EventItem.js +585 -787
- package/dist/components/EventItemPopover.d.ts +12 -0
- package/dist/components/EventItemPopover.js +19 -143
- package/dist/components/HeaderView.d.ts +14 -0
- package/dist/components/HeaderView.js +123 -186
- package/dist/components/ResourceEvents.d.ts +54 -0
- package/dist/components/ResourceEvents.js +534 -703
- package/dist/components/ResourceView.d.ts +26 -0
- package/dist/components/ResourceView.js +64 -184
- package/dist/components/SchedulerData.d.ts +136 -0
- package/dist/components/SchedulerData.js +1296 -1226
- package/dist/components/SchedulerHeader.d.ts +25 -0
- package/dist/components/SchedulerHeader.js +50 -150
- package/dist/components/SelectedArea.d.ts +8 -0
- package/dist/components/SelectedArea.js +11 -26
- package/dist/components/Summary.d.ts +11 -0
- package/dist/components/Summary.js +21 -50
- package/dist/components/WrapperFun.d.ts +2 -0
- package/dist/components/WrapperFun.js +5 -10
- package/dist/components/index.d.ts +44 -0
- package/dist/components/index.js +428 -654
- package/dist/components/ui/Icons.d.ts +8 -0
- package/dist/components/ui/Icons.js +7 -0
- package/dist/components/ui/MiniCalendar.d.ts +9 -0
- package/dist/components/ui/MiniCalendar.js +17 -0
- package/dist/components/ui/Popover.d.ts +13 -0
- package/dist/components/ui/Popover.js +80 -0
- package/dist/config/default.d.ts +36 -0
- package/dist/config/default.js +17 -26
- package/dist/config/i18n.d.ts +27 -0
- package/dist/config/i18n.js +21 -37
- package/dist/config/scheduler.d.ts +12 -0
- package/dist/config/scheduler.js +126 -119
- package/dist/css/style.css +2 -316
- package/dist/helper/behaviors.d.ts +14 -0
- package/dist/helper/behaviors.js +75 -75
- package/dist/helper/utility.d.ts +26 -0
- package/dist/helper/utility.js +23 -30
- package/dist/index.d.ts +6 -477
- package/dist/index.js +4 -2
- package/dist/sample-data/sample1.d.ts +11 -0
- package/dist/sample-data/sample1.js +427 -372
- package/dist/types.d.ts +267 -0
- package/dist/types.js +1 -0
- package/package.json +30 -27
|
@@ -1,1271 +1,1341 @@
|
|
|
1
1
|
import dayjs from 'dayjs';
|
|
2
2
|
import isoWeek from 'dayjs/plugin/isoWeek';
|
|
3
3
|
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
|
|
4
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
4
5
|
import utc from 'dayjs/plugin/utc';
|
|
5
6
|
import weekday from 'dayjs/plugin/weekday';
|
|
6
7
|
import { RRuleSet, rrulestr } from 'rrule';
|
|
7
8
|
import { CellUnit, DATE_FORMAT, DATETIME_FORMAT, ViewType } from '../config/default';
|
|
8
9
|
import { getDefaultLabels, getLabel } from '../config/i18n';
|
|
9
10
|
import config from '../config/scheduler';
|
|
10
|
-
import behaviors from '../helper/behaviors';
|
|
11
|
+
import behaviors, { toDate } from '../helper/behaviors';
|
|
11
12
|
import { normalizeEventEnd, normalizeEventStart } from '../helper/utility';
|
|
13
|
+
// dayjs's quarterOfYear plugin adds 'quarters' to add() but not to the ManipulateType the base overload accepts.
|
|
14
|
+
const addUnit = (d, amount, unit) => d.add(amount, unit);
|
|
15
|
+
const isPercent = (value) => typeof value === 'string' && value.endsWith('%');
|
|
16
|
+
const percentOf = (base, percent) => Math.trunc((base * Number(String(percent).slice(0, -1))) / 100);
|
|
17
|
+
// Non-percent widths are pixel numbers by contract.
|
|
18
|
+
const asPx = (value) => value;
|
|
12
19
|
export default class SchedulerData {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
...newBehaviors
|
|
46
|
-
};
|
|
47
|
-
this._resolveDate(0, date);
|
|
48
|
-
this._createHeaders();
|
|
49
|
-
this._createRenderData();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Per-instance dayjs: the locale is applied to each created date instead of the global dayjs
|
|
53
|
-
// singleton, so schedulers (and the host app) don't overwrite each other's locale (#146).
|
|
54
|
-
_createLocaleDayjs() {
|
|
55
|
-
let locale;
|
|
56
|
-
const localeDayjs = (...args) => {
|
|
57
|
-
const d = dayjs(...args);
|
|
58
|
-
return locale ? d.locale(locale) : d;
|
|
59
|
-
};
|
|
60
|
-
localeDayjs.locale = preset => {
|
|
61
|
-
if (preset === undefined) return locale || dayjs.locale();
|
|
62
|
-
// dayjs accepts a locale name or a locale object; resolve (and register) it once to a name
|
|
63
|
-
locale = dayjs().locale(preset).locale();
|
|
64
|
-
return localeDayjs;
|
|
65
|
-
};
|
|
66
|
-
return localeDayjs;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Update user-facing labels from the i18n provider
|
|
71
|
-
* This allows apps to provide localized labels via setLabelsProvider()
|
|
72
|
-
* @private
|
|
73
|
-
*/
|
|
74
|
-
_updateLabelsFromI18n(locale) {
|
|
75
|
-
// Get labels from the i18n provider if available
|
|
76
|
-
const defaults = getDefaultLabels();
|
|
77
|
-
const applyIfProvided = (key, current) => {
|
|
78
|
-
const value = getLabel(key, locale);
|
|
79
|
-
if (value === undefined || value === null) return current;
|
|
80
|
-
return value !== defaults[key] ? value : current;
|
|
81
|
-
};
|
|
82
|
-
this.config.resourceName = applyIfProvided('resourceName', this.config.resourceName);
|
|
83
|
-
this.config.taskName = applyIfProvided('taskName', this.config.taskName);
|
|
84
|
-
this.config.agendaViewHeader = applyIfProvided('agendaViewHeader', this.config.agendaViewHeader);
|
|
85
|
-
this.config.weekNumberLabel = applyIfProvided('weekNumberLabel', this.config.weekNumberLabel);
|
|
86
|
-
}
|
|
87
|
-
setVersionChangeNotifier(callback) {
|
|
88
|
-
this._versionChangeCallback = typeof callback === 'function' ? callback : null;
|
|
89
|
-
}
|
|
90
|
-
beginBatch() {
|
|
91
|
-
this._batchCount = (this._batchCount || 0) + 1;
|
|
92
|
-
}
|
|
93
|
-
endBatch() {
|
|
94
|
-
if (this._batchCount === undefined || this._batchCount <= 0) {
|
|
95
|
-
this._batchCount = 0;
|
|
96
|
-
console.warn('SchedulerData.endBatch called without a matching beginBatch');
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
if (this._batchCount > 0) {
|
|
100
|
-
this._batchCount -= 1;
|
|
101
|
-
if (this._batchCount === 0 && this._pendingVersion !== undefined) {
|
|
102
|
-
const pendingVersion = this._pendingVersion;
|
|
103
|
-
this._pendingVersion = undefined;
|
|
104
|
-
if (typeof this._versionChangeCallback === 'function') {
|
|
105
|
-
this._versionChangeCallback(pendingVersion);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
bumpVersion() {
|
|
111
|
-
this.version += 1;
|
|
112
|
-
if (this._batchCount > 0) {
|
|
113
|
-
// Defer callback until batch ends
|
|
114
|
-
this._pendingVersion = this.version;
|
|
115
|
-
} else if (typeof this._versionChangeCallback === 'function') {
|
|
116
|
-
this._versionChangeCallback(this.version);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
getVersion() {
|
|
120
|
-
return this.version;
|
|
121
|
-
}
|
|
122
|
-
isVerticalResourceView() {
|
|
123
|
-
return this.viewType === ViewType.VerticalResource;
|
|
124
|
-
}
|
|
125
|
-
setSchedulerLocale(preset) {
|
|
126
|
-
if (!preset) return;
|
|
127
|
-
this.localeDayjs.locale(preset);
|
|
128
|
-
this._updateLabelsFromI18n(preset);
|
|
129
|
-
this._shouldReloadViewType = true;
|
|
130
|
-
this.setViewType(this.viewType, this.showAgenda, this.isEventPerspective);
|
|
131
|
-
}
|
|
132
|
-
setCalendarPopoverLocale(lang) {
|
|
133
|
-
if (lang) {
|
|
134
|
-
this.calendarPopoverLocale = lang;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
setResources(resources) {
|
|
138
|
-
this._validateResource(resources);
|
|
139
|
-
this.resources = Array.from(new Set(resources));
|
|
140
|
-
// vertical view builds its headers from the resources
|
|
141
|
-
if (this.isVerticalResourceView()) {
|
|
142
|
-
this._createHeaders();
|
|
143
|
-
}
|
|
144
|
-
this._createRenderData();
|
|
145
|
-
this.setScrollToSpecialDayjs(true);
|
|
146
|
-
this.bumpVersion();
|
|
147
|
-
}
|
|
148
|
-
setEventGroupsAutoGenerated(autoGenerated) {
|
|
149
|
-
this.eventGroupsAutoGenerated = autoGenerated;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// optional
|
|
153
|
-
setEventGroups(eventGroups) {
|
|
154
|
-
this._validateEventGroups(eventGroups);
|
|
155
|
-
this.eventGroups = Array.from(new Set(eventGroups));
|
|
156
|
-
this.eventGroupsAutoGenerated = false;
|
|
157
|
-
this._createRenderData();
|
|
158
|
-
this.setScrollToSpecialDayjs(true);
|
|
159
|
-
this.bumpVersion();
|
|
160
|
-
}
|
|
161
|
-
setMinuteStep(minuteStep) {
|
|
162
|
-
if (this.config.minuteStep !== minuteStep) {
|
|
163
|
-
this._validateMinuteStep(minuteStep);
|
|
164
|
-
this.config.minuteStep = minuteStep;
|
|
165
|
-
this._createHeaders();
|
|
166
|
-
this._createRenderData();
|
|
167
|
-
this.bumpVersion();
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
setUnderneathHeight(underneathHeight) {
|
|
171
|
-
if (underneathHeight >= 0 && this.config.underneathHeight !== underneathHeight) {
|
|
172
|
-
this.config.underneathHeight = underneathHeight;
|
|
173
|
-
this.bumpVersion();
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
getMinuteStepsInHour() {
|
|
177
|
-
return 60 / this.config.minuteStep;
|
|
178
|
-
}
|
|
179
|
-
addResource(resource) {
|
|
180
|
-
const existedResources = this.resources.filter(x => x.id === resource.id);
|
|
181
|
-
if (existedResources.length === 0) {
|
|
182
|
-
this.resources.push(resource);
|
|
183
|
-
if (this.isVerticalResourceView()) {
|
|
184
|
-
this._createHeaders();
|
|
185
|
-
}
|
|
186
|
-
this._createRenderData();
|
|
187
|
-
this.bumpVersion();
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
addEventGroup(eventGroup) {
|
|
191
|
-
const existedEventGroups = this.eventGroups.filter(x => x.id === eventGroup.id);
|
|
192
|
-
if (existedEventGroups.length === 0) {
|
|
193
|
-
this.eventGroups.push(eventGroup);
|
|
194
|
-
this._createRenderData();
|
|
195
|
-
this.bumpVersion();
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
removeEventGroupById(eventGroupId) {
|
|
199
|
-
let index = -1;
|
|
200
|
-
this.eventGroups.forEach((item, idx) => {
|
|
201
|
-
if (item.id === eventGroupId) index = idx;
|
|
202
|
-
});
|
|
203
|
-
if (index !== -1) {
|
|
204
|
-
this.eventGroups.splice(index, 1);
|
|
205
|
-
this._createRenderData();
|
|
206
|
-
this.bumpVersion();
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
containsEventGroupId(eventGroupId) {
|
|
210
|
-
let index = -1;
|
|
211
|
-
this.eventGroups.forEach((item, idx) => {
|
|
212
|
-
if (item.id === eventGroupId) index = idx;
|
|
213
|
-
});
|
|
214
|
-
return index !== -1;
|
|
215
|
-
}
|
|
216
|
-
setEvents(events) {
|
|
217
|
-
this._validateEvents(events);
|
|
218
|
-
this.events = Array.from(events);
|
|
219
|
-
if (this.eventGroupsAutoGenerated) this._generateEventGroups();
|
|
220
|
-
if (this.config.recurringEventsEnabled) this._handleRecurringEvents();
|
|
221
|
-
this._createRenderData();
|
|
222
|
-
this.bumpVersion();
|
|
223
|
-
}
|
|
224
|
-
setScrollToSpecialDayjs(scrollToSpecialDayjs) {
|
|
225
|
-
if (this.config.scrollToSpecialDayjsEnabled) this.scrollToSpecialDayjs = scrollToSpecialDayjs;
|
|
226
|
-
}
|
|
227
|
-
prev() {
|
|
228
|
-
this._resolveDate(-1);
|
|
229
|
-
this.events = [];
|
|
230
|
-
this._createHeaders();
|
|
231
|
-
this._createRenderData();
|
|
232
|
-
this.bumpVersion();
|
|
233
|
-
}
|
|
234
|
-
next() {
|
|
235
|
-
this._resolveDate(1);
|
|
236
|
-
this.events = [];
|
|
237
|
-
this._createHeaders();
|
|
238
|
-
this._createRenderData();
|
|
239
|
-
this.bumpVersion();
|
|
240
|
-
}
|
|
241
|
-
setDate(date = dayjs(new Date())) {
|
|
242
|
-
this._resolveDate(0, date);
|
|
243
|
-
this.events = [];
|
|
244
|
-
this._createHeaders();
|
|
245
|
-
this._createRenderData();
|
|
246
|
-
this.bumpVersion();
|
|
247
|
-
}
|
|
248
|
-
setViewType(viewType = ViewType.Week, showAgenda = false, isEventPerspective = false) {
|
|
249
|
-
const previousShowAgenda = this.showAgenda;
|
|
250
|
-
const previousIsEventPerspective = this.isEventPerspective;
|
|
251
|
-
this.showAgenda = showAgenda;
|
|
252
|
-
this.isEventPerspective = isEventPerspective;
|
|
253
|
-
const isCustomView = viewType === ViewType.Custom || viewType === ViewType.Custom1 || viewType === ViewType.Custom2;
|
|
254
|
-
const isVerticalView = viewType === ViewType.VerticalResource;
|
|
255
|
-
if (!isCustomView && viewType !== ViewType.Day && !isVerticalView) {
|
|
256
|
-
this.cellUnit = CellUnit.Day;
|
|
257
|
-
} else if (viewType === ViewType.Day || isVerticalView) {
|
|
258
|
-
this.cellUnit = CellUnit.Hour;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// If showAgenda or isEventPerspective changed, force reload
|
|
262
|
-
if (previousShowAgenda !== showAgenda || previousIsEventPerspective !== isEventPerspective) {
|
|
263
|
-
this._shouldReloadViewType = true;
|
|
264
|
-
}
|
|
265
|
-
if (this.viewType !== viewType || this._shouldReloadViewType) {
|
|
266
|
-
let date = this.startDate;
|
|
267
|
-
if (viewType === ViewType.Custom || viewType === ViewType.Custom1 || viewType === ViewType.Custom2) {
|
|
20
|
+
resources;
|
|
21
|
+
events;
|
|
22
|
+
eventGroups;
|
|
23
|
+
eventGroupsAutoGenerated;
|
|
24
|
+
viewType;
|
|
25
|
+
cellUnit;
|
|
26
|
+
showAgenda;
|
|
27
|
+
isEventPerspective;
|
|
28
|
+
resizing;
|
|
29
|
+
scrollToSpecialDayjs;
|
|
30
|
+
documentWidth;
|
|
31
|
+
documentHeight;
|
|
32
|
+
schedulerHeaderHeight;
|
|
33
|
+
version;
|
|
34
|
+
localeDayjs;
|
|
35
|
+
config;
|
|
36
|
+
behaviors;
|
|
37
|
+
selectDate;
|
|
38
|
+
startDate;
|
|
39
|
+
endDate;
|
|
40
|
+
timeSlots;
|
|
41
|
+
headers;
|
|
42
|
+
renderData;
|
|
43
|
+
_shouldReloadViewType;
|
|
44
|
+
_batchCount;
|
|
45
|
+
_versionChangeCallback;
|
|
46
|
+
_pendingVersion;
|
|
47
|
+
constructor(date = dayjs(), viewType = ViewType.Week, showAgenda = false, isEventPerspective = false, newConfig = undefined, newBehaviors = undefined) {
|
|
48
|
+
this.resources = [];
|
|
49
|
+
this.events = [];
|
|
50
|
+
this.eventGroups = [];
|
|
51
|
+
this.eventGroupsAutoGenerated = true;
|
|
268
52
|
this.viewType = viewType;
|
|
53
|
+
this.cellUnit = viewType === ViewType.Day || viewType === ViewType.VerticalResource ? CellUnit.Hour : CellUnit.Day;
|
|
54
|
+
this.showAgenda = showAgenda;
|
|
55
|
+
this.isEventPerspective = isEventPerspective;
|
|
56
|
+
this.resizing = false;
|
|
57
|
+
this.scrollToSpecialDayjs = false;
|
|
58
|
+
this.documentWidth = 0;
|
|
59
|
+
this.documentHeight = 0;
|
|
60
|
+
this.schedulerHeaderHeight = 0;
|
|
61
|
+
this._shouldReloadViewType = false;
|
|
62
|
+
this.version = 0;
|
|
63
|
+
this._batchCount = 0;
|
|
64
|
+
this._versionChangeCallback = null;
|
|
65
|
+
dayjs.extend(quarterOfYear);
|
|
66
|
+
dayjs.extend(weekday);
|
|
67
|
+
dayjs.extend(utc);
|
|
68
|
+
dayjs.extend(timezone);
|
|
69
|
+
dayjs.extend(isoWeek);
|
|
70
|
+
this.localeDayjs = this._createLocaleDayjs();
|
|
71
|
+
this.config = newConfig === undefined ? config : { ...config, ...newConfig };
|
|
72
|
+
this._updateLabelsFromI18n();
|
|
73
|
+
this._validateMinuteStep(this.config.minuteStep);
|
|
74
|
+
this.behaviors = newBehaviors === undefined ? behaviors : { ...behaviors, ...newBehaviors };
|
|
269
75
|
this._resolveDate(0, date);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
76
|
+
this._createHeaders();
|
|
77
|
+
this._createRenderData();
|
|
78
|
+
}
|
|
79
|
+
// Per-instance dayjs: the locale is applied to each created date instead of the global dayjs
|
|
80
|
+
// singleton, so schedulers (and the host app) don't overwrite each other's locale (#146).
|
|
81
|
+
_createLocaleDayjs() {
|
|
82
|
+
let locale;
|
|
83
|
+
const create = (date, format, strict) => {
|
|
84
|
+
const d = dayjs(date, format, strict);
|
|
85
|
+
return locale ? d.locale(locale) : d;
|
|
86
|
+
};
|
|
87
|
+
function setLocale(preset) {
|
|
88
|
+
if (preset === undefined)
|
|
89
|
+
return locale || dayjs.locale();
|
|
90
|
+
// dayjs accepts a locale name or a locale object; resolve (and register) it once to a name
|
|
91
|
+
locale = dayjs().locale(preset).locale();
|
|
92
|
+
return localeDayjs;
|
|
93
|
+
}
|
|
94
|
+
// wall-clock `date` interpreted in IANA zone `zone` (instants / Dates / Dayjs are converted instead)
|
|
95
|
+
const tz = (date, zone) => {
|
|
96
|
+
const d = dayjs.tz(date, zone);
|
|
97
|
+
return locale ? d.locale(locale) : d;
|
|
98
|
+
};
|
|
99
|
+
const localeDayjs = Object.assign(create, { locale: setLocale, utc: dayjs.utc, tz });
|
|
100
|
+
return localeDayjs;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Update user-facing labels from the i18n provider
|
|
104
|
+
* This allows apps to provide localized labels via setLabelsProvider()
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
_updateLabelsFromI18n(locale) {
|
|
108
|
+
// Get labels from the i18n provider if available
|
|
109
|
+
const defaults = getDefaultLabels();
|
|
110
|
+
const applyIfProvided = (key, current) => {
|
|
111
|
+
const value = getLabel(key, locale);
|
|
112
|
+
if (value === undefined || value === null)
|
|
113
|
+
return current;
|
|
114
|
+
return value !== defaults[key] ? value : current;
|
|
115
|
+
};
|
|
116
|
+
this.config.resourceName = applyIfProvided('resourceName', this.config.resourceName);
|
|
117
|
+
this.config.taskName = applyIfProvided('taskName', this.config.taskName);
|
|
118
|
+
this.config.agendaViewHeader = applyIfProvided('agendaViewHeader', this.config.agendaViewHeader);
|
|
119
|
+
this.config.weekNumberLabel = applyIfProvided('weekNumberLabel', this.config.weekNumberLabel);
|
|
120
|
+
}
|
|
121
|
+
setVersionChangeNotifier(callback) {
|
|
122
|
+
this._versionChangeCallback = typeof callback === 'function' ? callback : null;
|
|
123
|
+
}
|
|
124
|
+
beginBatch() {
|
|
125
|
+
this._batchCount = (this._batchCount || 0) + 1;
|
|
126
|
+
}
|
|
127
|
+
endBatch() {
|
|
128
|
+
if (this._batchCount === undefined || this._batchCount <= 0) {
|
|
129
|
+
this._batchCount = 0;
|
|
130
|
+
console.warn('SchedulerData.endBatch called without a matching beginBatch');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (this._batchCount > 0) {
|
|
134
|
+
this._batchCount -= 1;
|
|
135
|
+
if (this._batchCount === 0 && this._pendingVersion !== undefined) {
|
|
136
|
+
const pendingVersion = this._pendingVersion;
|
|
137
|
+
this._pendingVersion = undefined;
|
|
138
|
+
if (typeof this._versionChangeCallback === 'function') {
|
|
139
|
+
this._versionChangeCallback(pendingVersion);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
bumpVersion() {
|
|
145
|
+
this.version += 1;
|
|
146
|
+
if (this._batchCount > 0) {
|
|
147
|
+
// Defer callback until batch ends
|
|
148
|
+
this._pendingVersion = this.version;
|
|
149
|
+
}
|
|
150
|
+
else if (typeof this._versionChangeCallback === 'function') {
|
|
151
|
+
this._versionChangeCallback(this.version);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
getVersion() {
|
|
155
|
+
return this.version;
|
|
156
|
+
}
|
|
157
|
+
isVerticalResourceView() {
|
|
158
|
+
return this.viewType === ViewType.VerticalResource;
|
|
159
|
+
}
|
|
160
|
+
setSchedulerLocale(preset) {
|
|
161
|
+
if (!preset)
|
|
162
|
+
return;
|
|
163
|
+
this.localeDayjs.locale(preset);
|
|
164
|
+
this._updateLabelsFromI18n(preset);
|
|
165
|
+
this._shouldReloadViewType = true;
|
|
166
|
+
this.setViewType(this.viewType, this.showAgenda, this.isEventPerspective);
|
|
167
|
+
}
|
|
168
|
+
setResources(resources) {
|
|
169
|
+
this._validateResource(resources);
|
|
170
|
+
this.resources = Array.from(new Set(resources));
|
|
171
|
+
// vertical view builds its headers from the resources
|
|
172
|
+
if (this.isVerticalResourceView()) {
|
|
173
|
+
this._createHeaders();
|
|
174
|
+
}
|
|
175
|
+
this._createRenderData();
|
|
176
|
+
this.setScrollToSpecialDayjs(true);
|
|
177
|
+
this.bumpVersion();
|
|
178
|
+
}
|
|
179
|
+
setEventGroupsAutoGenerated(autoGenerated) {
|
|
180
|
+
this.eventGroupsAutoGenerated = autoGenerated;
|
|
181
|
+
}
|
|
182
|
+
// optional
|
|
183
|
+
setEventGroups(eventGroups) {
|
|
184
|
+
this._validateEventGroups(eventGroups);
|
|
185
|
+
this.eventGroups = Array.from(new Set(eventGroups));
|
|
186
|
+
this.eventGroupsAutoGenerated = false;
|
|
187
|
+
this._createRenderData();
|
|
188
|
+
this.setScrollToSpecialDayjs(true);
|
|
189
|
+
this.bumpVersion();
|
|
190
|
+
}
|
|
191
|
+
setMinuteStep(minuteStep) {
|
|
192
|
+
if (this.config.minuteStep !== minuteStep) {
|
|
193
|
+
this._validateMinuteStep(minuteStep);
|
|
194
|
+
this.config.minuteStep = minuteStep;
|
|
195
|
+
this._createHeaders();
|
|
196
|
+
this._createRenderData();
|
|
197
|
+
this.bumpVersion();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
setUnderneathHeight(underneathHeight) {
|
|
201
|
+
if (underneathHeight >= 0 && this.config.underneathHeight !== underneathHeight) {
|
|
202
|
+
this.config.underneathHeight = underneathHeight;
|
|
203
|
+
this.bumpVersion();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
getMinuteStepsInHour() {
|
|
207
|
+
return 60 / this.config.minuteStep;
|
|
208
|
+
}
|
|
209
|
+
addResource(resource) {
|
|
210
|
+
const existedResources = this.resources.filter(x => x.id === resource.id);
|
|
211
|
+
if (existedResources.length === 0) {
|
|
212
|
+
this.resources.push(resource);
|
|
213
|
+
if (this.isVerticalResourceView()) {
|
|
214
|
+
this._createHeaders();
|
|
292
215
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.
|
|
216
|
+
this._createRenderData();
|
|
217
|
+
this.bumpVersion();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
addEventGroup(eventGroup) {
|
|
221
|
+
const existedEventGroups = this.eventGroups.filter(x => x.id === eventGroup.id);
|
|
222
|
+
if (existedEventGroups.length === 0) {
|
|
223
|
+
this.eventGroups.push(eventGroup);
|
|
224
|
+
this._createRenderData();
|
|
225
|
+
this.bumpVersion();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
removeEventGroupById(eventGroupId) {
|
|
229
|
+
let index = -1;
|
|
230
|
+
this.eventGroups.forEach((item, idx) => {
|
|
231
|
+
if (item.id === eventGroupId)
|
|
232
|
+
index = idx;
|
|
233
|
+
});
|
|
234
|
+
if (index !== -1) {
|
|
235
|
+
this.eventGroups.splice(index, 1);
|
|
236
|
+
this._createRenderData();
|
|
237
|
+
this.bumpVersion();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
containsEventGroupId(eventGroupId) {
|
|
241
|
+
let index = -1;
|
|
242
|
+
this.eventGroups.forEach((item, idx) => {
|
|
243
|
+
if (item.id === eventGroupId)
|
|
244
|
+
index = idx;
|
|
245
|
+
});
|
|
246
|
+
return index !== -1;
|
|
247
|
+
}
|
|
248
|
+
setEvents(events) {
|
|
249
|
+
this._validateEvents(events);
|
|
250
|
+
this.events = Array.from(events);
|
|
251
|
+
if (this.eventGroupsAutoGenerated)
|
|
252
|
+
this._generateEventGroups();
|
|
253
|
+
if (this.config.recurringEventsEnabled)
|
|
254
|
+
this._handleRecurringEvents();
|
|
255
|
+
this._createRenderData();
|
|
256
|
+
this.bumpVersion();
|
|
257
|
+
}
|
|
258
|
+
setScrollToSpecialDayjs(scrollToSpecialDayjs) {
|
|
259
|
+
if (this.config.scrollToSpecialDayjsEnabled)
|
|
260
|
+
this.scrollToSpecialDayjs = scrollToSpecialDayjs;
|
|
261
|
+
}
|
|
262
|
+
prev() {
|
|
263
|
+
this._resolveDate(-1);
|
|
264
|
+
this.events = [];
|
|
265
|
+
this._createHeaders();
|
|
266
|
+
this._createRenderData();
|
|
267
|
+
this.bumpVersion();
|
|
268
|
+
}
|
|
269
|
+
next() {
|
|
270
|
+
this._resolveDate(1);
|
|
271
|
+
this.events = [];
|
|
272
|
+
this._createHeaders();
|
|
273
|
+
this._createRenderData();
|
|
274
|
+
this.bumpVersion();
|
|
275
|
+
}
|
|
276
|
+
setDate(date = dayjs(new Date())) {
|
|
277
|
+
this._resolveDate(0, date);
|
|
278
|
+
this.events = [];
|
|
279
|
+
this._createHeaders();
|
|
280
|
+
this._createRenderData();
|
|
281
|
+
this.bumpVersion();
|
|
282
|
+
}
|
|
283
|
+
setViewType(viewType = ViewType.Week, showAgenda = false, isEventPerspective = false) {
|
|
284
|
+
const previousShowAgenda = this.showAgenda;
|
|
285
|
+
const previousIsEventPerspective = this.isEventPerspective;
|
|
286
|
+
this.showAgenda = showAgenda;
|
|
287
|
+
this.isEventPerspective = isEventPerspective;
|
|
288
|
+
const isCustomView = viewType === ViewType.Custom || viewType === ViewType.Custom1 || viewType === ViewType.Custom2;
|
|
289
|
+
const isVerticalView = viewType === ViewType.VerticalResource;
|
|
290
|
+
if (!isCustomView && viewType !== ViewType.Day && !isVerticalView) {
|
|
291
|
+
this.cellUnit = CellUnit.Day;
|
|
292
|
+
}
|
|
293
|
+
else if (viewType === ViewType.Day || isVerticalView) {
|
|
301
294
|
this.cellUnit = CellUnit.Hour;
|
|
302
|
-
} else if (viewType === ViewType.Week) {
|
|
303
|
-
this.startDate = this.localeDayjs(new Date(date)).startOf('isoWeek');
|
|
304
|
-
this.endDate = this.localeDayjs(new Date(this.startDate)).endOf('isoWeek');
|
|
305
|
-
} else if (viewType === ViewType.Month) {
|
|
306
|
-
this.startDate = this.localeDayjs(new Date(date)).startOf('month');
|
|
307
|
-
this.endDate = this.localeDayjs(new Date(this.startDate)).endOf('month');
|
|
308
|
-
} else if (viewType === ViewType.Quarter) {
|
|
309
|
-
this.startDate = this.localeDayjs(new Date(date)).startOf('quarter');
|
|
310
|
-
this.endDate = this.localeDayjs(new Date(this.startDate)).endOf('quarter');
|
|
311
|
-
}
|
|
312
295
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
296
|
+
// If showAgenda or isEventPerspective changed, force reload
|
|
297
|
+
if (previousShowAgenda !== showAgenda || previousIsEventPerspective !== isEventPerspective) {
|
|
298
|
+
this._shouldReloadViewType = true;
|
|
299
|
+
}
|
|
300
|
+
if (this.viewType !== viewType || this._shouldReloadViewType) {
|
|
301
|
+
let date = this.startDate;
|
|
302
|
+
if (viewType === ViewType.Custom || viewType === ViewType.Custom1 || viewType === ViewType.Custom2) {
|
|
303
|
+
this.viewType = viewType;
|
|
304
|
+
this._resolveDate(0, date);
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
if (this.viewType < viewType) {
|
|
308
|
+
if (viewType === ViewType.Week) {
|
|
309
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('isoWeek');
|
|
310
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('isoWeek');
|
|
311
|
+
}
|
|
312
|
+
else if (viewType === ViewType.Month) {
|
|
313
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('month');
|
|
314
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('month');
|
|
315
|
+
}
|
|
316
|
+
else if (viewType === ViewType.Quarter) {
|
|
317
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('quarter');
|
|
318
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('quarter');
|
|
319
|
+
}
|
|
320
|
+
else if (viewType === ViewType.Year) {
|
|
321
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('year');
|
|
322
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('year');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const start = this.localeDayjs(toDate(this.startDate));
|
|
327
|
+
const end = this.localeDayjs(toDate(this.endDate)).add(1, 'days');
|
|
328
|
+
if (this.selectDate !== undefined) {
|
|
329
|
+
const selectDate = this.localeDayjs(toDate(this.selectDate));
|
|
330
|
+
if (selectDate >= start && selectDate < end) {
|
|
331
|
+
date = this.selectDate;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const now = this.localeDayjs();
|
|
335
|
+
if (now >= start && now < end) {
|
|
336
|
+
date = now.startOf('day');
|
|
337
|
+
}
|
|
338
|
+
if (viewType === ViewType.Day || viewType === ViewType.VerticalResource) {
|
|
339
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('day');
|
|
340
|
+
this.endDate = this.startDate;
|
|
341
|
+
this.cellUnit = CellUnit.Hour;
|
|
342
|
+
}
|
|
343
|
+
else if (viewType === ViewType.Week) {
|
|
344
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('isoWeek');
|
|
345
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('isoWeek');
|
|
346
|
+
}
|
|
347
|
+
else if (viewType === ViewType.Month) {
|
|
348
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('month');
|
|
349
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('month');
|
|
350
|
+
}
|
|
351
|
+
else if (viewType === ViewType.Quarter) {
|
|
352
|
+
this.startDate = this.localeDayjs(toDate(date)).startOf('quarter');
|
|
353
|
+
this.endDate = this.localeDayjs(toDate(this.startDate)).endOf('quarter');
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
this.viewType = viewType;
|
|
357
|
+
}
|
|
358
|
+
this._shouldReloadViewType = false;
|
|
359
|
+
this.events = [];
|
|
360
|
+
this._createHeaders();
|
|
361
|
+
this._createRenderData();
|
|
362
|
+
this.setScrollToSpecialDayjs(true);
|
|
363
|
+
this.bumpVersion();
|
|
353
364
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
item.render = newRender;
|
|
359
|
-
changed = true;
|
|
365
|
+
}
|
|
366
|
+
setSchedulerMaxHeight(newSchedulerMaxHeight) {
|
|
367
|
+
if (newSchedulerMaxHeight < 0) {
|
|
368
|
+
return;
|
|
360
369
|
}
|
|
361
|
-
if (
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
render: item.render
|
|
365
|
-
});
|
|
370
|
+
if (this.config.schedulerMaxHeight !== newSchedulerMaxHeight) {
|
|
371
|
+
this.config.schedulerMaxHeight = newSchedulerMaxHeight;
|
|
372
|
+
this.bumpVersion();
|
|
366
373
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
getContentCellWidth() {
|
|
413
|
-
const contentCellConfigWidth = this.getContentCellConfigWidth();
|
|
414
|
-
const schedulerWidth = this.getSchedulerWidth();
|
|
415
|
-
const cellWidth = this.isContentViewResponsive() ? parseInt(schedulerWidth * Number(contentCellConfigWidth.slice(0, -1)) / 100, 10) : contentCellConfigWidth;
|
|
416
|
-
|
|
417
|
-
// stretch the cells to fill the container instead of widening the resource column
|
|
418
|
-
if (this.isSchedulerResponsive() && !this.showAgenda && this.headers?.length) {
|
|
419
|
-
const resourceWidth = this.config.resourceViewEnabled === false ? 0 : this._getConfiguredResourceTableWidth();
|
|
420
|
-
const fillWidth = Math.floor((schedulerWidth - resourceWidth) / this.headers.length);
|
|
421
|
-
return Math.max(cellWidth, fillWidth);
|
|
422
|
-
}
|
|
423
|
-
return cellWidth;
|
|
424
|
-
}
|
|
425
|
-
getContentTableWidth() {
|
|
426
|
-
return this.headers.length * this.getContentCellWidth();
|
|
427
|
-
}
|
|
428
|
-
getScrollToSpecialDayjs() {
|
|
429
|
-
if (this.config.scrollToSpecialDayjsEnabled) return this.scrollToSpecialDayjs;
|
|
430
|
-
return false;
|
|
431
|
-
}
|
|
432
|
-
getSlots() {
|
|
433
|
-
return this.isEventPerspective ? this.eventGroups : this.resources;
|
|
434
|
-
}
|
|
435
|
-
getSlotById(slotId) {
|
|
436
|
-
const slots = this.getSlots();
|
|
437
|
-
let slot;
|
|
438
|
-
slots.forEach(item => {
|
|
439
|
-
if (item.id === slotId) slot = item;
|
|
440
|
-
});
|
|
441
|
-
return slot;
|
|
442
|
-
}
|
|
443
|
-
getResourceById(resourceId) {
|
|
444
|
-
let resource;
|
|
445
|
-
this.resources.forEach(item => {
|
|
446
|
-
if (item.id === resourceId) resource = item;
|
|
447
|
-
});
|
|
448
|
-
return resource;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// height of the optional group rows (month / week number) rendered above the main header row
|
|
452
|
-
getHeaderGroupRowsHeight() {
|
|
453
|
-
const {
|
|
454
|
-
showMonthRow,
|
|
455
|
-
monthRowHeight = 24,
|
|
456
|
-
showWeekNumber,
|
|
457
|
-
weekNumberRowHeight = 24
|
|
458
|
-
} = this.config;
|
|
459
|
-
return (showMonthRow ? monthRowHeight : 0) + (showWeekNumber ? weekNumberRowHeight : 0);
|
|
460
|
-
}
|
|
461
|
-
getTableHeaderHeight() {
|
|
462
|
-
return this.config.tableHeaderHeight;
|
|
463
|
-
}
|
|
464
|
-
getSchedulerContentDesiredHeight() {
|
|
465
|
-
let height = 0;
|
|
466
|
-
this.renderData.forEach(item => {
|
|
467
|
-
if (item.render) height += item.rowHeight;
|
|
468
|
-
});
|
|
469
|
-
return height;
|
|
470
|
-
}
|
|
471
|
-
getCellMaxEvents() {
|
|
472
|
-
const viewConfigMap = {
|
|
473
|
-
[ViewType.Week]: 'weekMaxEvents',
|
|
474
|
-
[ViewType.Day]: 'dayMaxEvents',
|
|
475
|
-
[ViewType.Month]: 'monthMaxEvents',
|
|
476
|
-
[ViewType.Year]: 'yearMaxEvents',
|
|
477
|
-
[ViewType.Quarter]: 'quarterMaxEvents'
|
|
478
|
-
};
|
|
479
|
-
const configProperty = viewConfigMap[this.viewType] || 'customMaxEvents';
|
|
480
|
-
return this.config[configProperty];
|
|
481
|
-
}
|
|
482
|
-
getCalendarPopoverLocale() {
|
|
483
|
-
return this.calendarPopoverLocale;
|
|
484
|
-
}
|
|
485
|
-
getSelectedDate() {
|
|
486
|
-
return this.selectDate.format(DATE_FORMAT);
|
|
487
|
-
}
|
|
488
|
-
getViewStartDate() {
|
|
489
|
-
return this.startDate;
|
|
490
|
-
}
|
|
491
|
-
getViewEndDate() {
|
|
492
|
-
return this.endDate;
|
|
493
|
-
}
|
|
494
|
-
getViewDates() {
|
|
495
|
-
return {
|
|
496
|
-
startDate: this.startDate,
|
|
497
|
-
endDate: this.endDate
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
getDateLabel() {
|
|
501
|
-
const start = this.localeDayjs(new Date(this.startDate));
|
|
502
|
-
const end = this.localeDayjs(new Date(this.endDate));
|
|
503
|
-
let dateLabel = start.format('LL');
|
|
504
|
-
if (start !== end) dateLabel = `${start.format('LL')}-${end.format('LL')}`;
|
|
505
|
-
if (this.behaviors.getDateLabelFunc) dateLabel = this.behaviors.getDateLabelFunc(this, this.viewType, this.startDate, this.endDate);
|
|
506
|
-
return dateLabel;
|
|
507
|
-
}
|
|
508
|
-
addEvent(newEvent) {
|
|
509
|
-
this._attachEvent(newEvent);
|
|
510
|
-
if (this.eventGroupsAutoGenerated) this._generateEventGroups();
|
|
511
|
-
this._createRenderData();
|
|
512
|
-
this.bumpVersion();
|
|
513
|
-
}
|
|
514
|
-
updateEventStart(event, newStart) {
|
|
515
|
-
this._detachEvent(event);
|
|
516
|
-
event.start = newStart;
|
|
517
|
-
this._attachEvent(event);
|
|
518
|
-
this._createRenderData();
|
|
519
|
-
this.bumpVersion();
|
|
520
|
-
}
|
|
521
|
-
updateEventEnd(event, newEnd) {
|
|
522
|
-
event.end = newEnd;
|
|
523
|
-
this._createRenderData();
|
|
524
|
-
this.bumpVersion();
|
|
525
|
-
}
|
|
526
|
-
swapEvent(eventSource, eventDest) {
|
|
527
|
-
// Swap group or resource IDs
|
|
528
|
-
if (this.isEventPerspective) {
|
|
529
|
-
[eventSource.groupId, eventDest.groupId] = [eventDest.groupId, eventSource.groupId];
|
|
530
|
-
[eventSource.groupName, eventDest.groupName] = [eventDest.groupName, eventSource.groupName];
|
|
531
|
-
} else {
|
|
532
|
-
[eventSource.resourceId, eventDest.resourceId] = [eventDest.resourceId, eventSource.resourceId];
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
// Swap start and end times
|
|
536
|
-
[eventSource.start, eventDest.start] = [eventDest.start, eventSource.start];
|
|
537
|
-
[eventSource.end, eventDest.end] = [eventDest.end, eventSource.end];
|
|
538
|
-
|
|
539
|
-
// Update the events
|
|
540
|
-
this._detachEvent(eventSource);
|
|
541
|
-
this._detachEvent(eventDest);
|
|
542
|
-
this._attachEvent(eventSource);
|
|
543
|
-
this._attachEvent(eventDest);
|
|
544
|
-
this._createRenderData();
|
|
545
|
-
this.bumpVersion();
|
|
546
|
-
}
|
|
547
|
-
swapEvent2(eventSource, eventDest) {
|
|
548
|
-
const tempEventSource = {
|
|
549
|
-
...eventSource
|
|
550
|
-
};
|
|
551
|
-
const tempEventDest = {
|
|
552
|
-
...eventDest
|
|
553
|
-
};
|
|
554
|
-
this._detachEvent(eventSource);
|
|
555
|
-
this._detachEvent(eventDest);
|
|
556
|
-
if (this.isEventPerspective) {
|
|
557
|
-
tempEventSource.groupId = eventDest.groupId;
|
|
558
|
-
tempEventSource.groupName = eventDest.groupName;
|
|
559
|
-
tempEventDest.groupId = eventSource.groupId;
|
|
560
|
-
tempEventDest.groupName = eventSource.groupName;
|
|
561
|
-
} else {
|
|
562
|
-
tempEventSource.resourceId = eventDest.resourceId;
|
|
563
|
-
tempEventDest.resourceId = eventSource.resourceId;
|
|
564
|
-
}
|
|
565
|
-
tempEventSource.end = eventDest.end;
|
|
566
|
-
tempEventSource.start = eventDest.start;
|
|
567
|
-
tempEventDest.end = eventSource.end;
|
|
568
|
-
tempEventDest.start = eventSource.start;
|
|
569
|
-
this._attachEvent(tempEventSource);
|
|
570
|
-
this._attachEvent(tempEventDest);
|
|
571
|
-
this._createRenderData();
|
|
572
|
-
this.bumpVersion();
|
|
573
|
-
}
|
|
574
|
-
moveEvent(event, newSlotId, newSlotName, newStart, newEnd) {
|
|
575
|
-
this._detachEvent(event);
|
|
576
|
-
if (this.isEventPerspective) {
|
|
577
|
-
event.groupId = newSlotId;
|
|
578
|
-
event.groupName = newSlotName;
|
|
579
|
-
} else event.resourceId = newSlotId;
|
|
580
|
-
event.end = newEnd;
|
|
581
|
-
event.start = newStart;
|
|
582
|
-
this._attachEvent(event);
|
|
583
|
-
this._createRenderData();
|
|
584
|
-
this.bumpVersion();
|
|
585
|
-
}
|
|
586
|
-
isEventInTimeWindow(eventStart, eventEnd, windowStart, windowEnd) {
|
|
587
|
-
return eventStart < windowEnd && eventEnd > windowStart;
|
|
588
|
-
}
|
|
589
|
-
removeEvent(event) {
|
|
590
|
-
const index = this.events.indexOf(event);
|
|
591
|
-
if (index !== -1) {
|
|
592
|
-
this.events.splice(index, 1);
|
|
593
|
-
this._createRenderData();
|
|
594
|
-
this.bumpVersion();
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
removeEventById(eventId) {
|
|
598
|
-
let index = -1;
|
|
599
|
-
this.events.forEach((item, idx) => {
|
|
600
|
-
if (item.id === eventId) index = idx;
|
|
601
|
-
});
|
|
602
|
-
if (index !== -1) {
|
|
603
|
-
this.events.splice(index, 1);
|
|
604
|
-
this._createRenderData();
|
|
605
|
-
this.bumpVersion();
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
getResourceTableConfigWidth() {
|
|
609
|
-
if (this.showAgenda) {
|
|
610
|
-
return this.config.agendaResourceTableWidth;
|
|
611
|
-
}
|
|
612
|
-
const viewConfigMap = {
|
|
613
|
-
[ViewType.Week]: 'weekResourceTableWidth',
|
|
614
|
-
[ViewType.Day]: 'dayResourceTableWidth',
|
|
615
|
-
[ViewType.Month]: 'monthResourceTableWidth',
|
|
616
|
-
[ViewType.Year]: 'yearResourceTableWidth',
|
|
617
|
-
[ViewType.Quarter]: 'quarterResourceTableWidth',
|
|
618
|
-
[ViewType.VerticalResource]: 'customResourceTableWidth'
|
|
619
|
-
};
|
|
620
|
-
const configProperty = viewConfigMap[this.viewType] || 'customResourceTableWidth';
|
|
621
|
-
return this.config[configProperty];
|
|
622
|
-
}
|
|
623
|
-
getContentCellConfigWidth() {
|
|
624
|
-
const viewConfigMap = {
|
|
625
|
-
[ViewType.Week]: 'weekCellWidth',
|
|
626
|
-
[ViewType.Day]: 'dayCellWidth',
|
|
627
|
-
[ViewType.Month]: 'monthCellWidth',
|
|
628
|
-
[ViewType.Year]: 'yearCellWidth',
|
|
629
|
-
[ViewType.Quarter]: 'quarterCellWidth',
|
|
630
|
-
[ViewType.VerticalResource]: 'customCellWidth'
|
|
631
|
-
};
|
|
632
|
-
const configProperty = viewConfigMap[this.viewType] || 'customCellWidth';
|
|
633
|
-
return this.config[configProperty];
|
|
634
|
-
}
|
|
635
|
-
_setDocumentWidth(documentWidth) {
|
|
636
|
-
if (documentWidth >= 0 && documentWidth !== this.documentWidth) {
|
|
637
|
-
this.documentWidth = documentWidth;
|
|
638
|
-
this.bumpVersion();
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
_setDocumentHeight(documentHeight) {
|
|
642
|
-
if (documentHeight >= 0 && documentHeight !== this.documentHeight) {
|
|
643
|
-
this.documentHeight = documentHeight;
|
|
644
|
-
this.bumpVersion();
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
_setSchedulerHeaderHeight(schedulerHeaderHeight) {
|
|
648
|
-
if (schedulerHeaderHeight >= 0 && schedulerHeaderHeight !== this.schedulerHeaderHeight) {
|
|
649
|
-
this.schedulerHeaderHeight = schedulerHeaderHeight;
|
|
650
|
-
this.bumpVersion();
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
_detachEvent(event) {
|
|
654
|
-
const index = this.events.indexOf(event);
|
|
655
|
-
if (index !== -1) this.events.splice(index, 1);
|
|
656
|
-
}
|
|
657
|
-
_attachEvent(event) {
|
|
658
|
-
let pos = 0;
|
|
659
|
-
const eventStart = this.localeDayjs(new Date(event.start));
|
|
660
|
-
this.events.forEach((item, index) => {
|
|
661
|
-
const start = this.localeDayjs(new Date(item.start));
|
|
662
|
-
if (eventStart >= start) pos = index + 1;
|
|
663
|
-
});
|
|
664
|
-
this.events.splice(pos, 0, event);
|
|
665
|
-
}
|
|
666
|
-
_handleRecurringEvents() {
|
|
667
|
-
const recurringEvents = this.events.filter(x => !!x.rrule);
|
|
668
|
-
recurringEvents.forEach(item => {
|
|
669
|
-
this._detachEvent(item);
|
|
670
|
-
});
|
|
671
|
-
recurringEvents.forEach(item => {
|
|
672
|
-
const windowStart = this.startDate;
|
|
673
|
-
const windowEnd = this.endDate.add(1, 'days');
|
|
674
|
-
const oldStart = this.localeDayjs(new Date(item.start));
|
|
675
|
-
const oldEnd = this.localeDayjs(new Date(item.end));
|
|
676
|
-
let rule = rrulestr(item.rrule);
|
|
677
|
-
let oldDtstart;
|
|
678
|
-
const oldUntil = rule.origOptions.until || windowEnd.toDate();
|
|
679
|
-
if (rule.origOptions.dtstart) {
|
|
680
|
-
oldDtstart = this.localeDayjs(new Date(rule.origOptions.dtstart));
|
|
681
|
-
}
|
|
682
|
-
// rule.origOptions.dtstart = oldStart.toDate();
|
|
683
|
-
if (windowEnd < oldUntil) {
|
|
684
|
-
rule.origOptions.until = windowEnd.toDate();
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// reload
|
|
688
|
-
rule = rrulestr(rule.toString());
|
|
689
|
-
if (item.exdates || item.exrule) {
|
|
690
|
-
const rruleSet = new RRuleSet();
|
|
691
|
-
rruleSet.rrule(rule);
|
|
692
|
-
if (item.exrule) {
|
|
693
|
-
rruleSet.exrule(rrulestr(item.exrule));
|
|
374
|
+
}
|
|
375
|
+
isSchedulerResponsive() {
|
|
376
|
+
return isPercent(this.config.schedulerWidth);
|
|
377
|
+
}
|
|
378
|
+
toggleExpandStatus(slotId) {
|
|
379
|
+
let slotEntered = false;
|
|
380
|
+
let slotIndent = -1;
|
|
381
|
+
let isExpanded = false;
|
|
382
|
+
let changed = false;
|
|
383
|
+
const expandedMap = new Map();
|
|
384
|
+
this.renderData.forEach(item => {
|
|
385
|
+
if (slotEntered === false) {
|
|
386
|
+
if (item.slotId === slotId && item.hasChildren) {
|
|
387
|
+
slotEntered = true;
|
|
388
|
+
isExpanded = !item.expanded;
|
|
389
|
+
item.expanded = isExpanded;
|
|
390
|
+
changed = true;
|
|
391
|
+
slotIndent = item.indent;
|
|
392
|
+
expandedMap.set(item.indent, {
|
|
393
|
+
expanded: item.expanded,
|
|
394
|
+
render: item.render,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
else if (item.indent > slotIndent) {
|
|
399
|
+
const expandStatus = expandedMap.get(item.indent - 1);
|
|
400
|
+
const newRender = expandStatus.expanded && expandStatus.render;
|
|
401
|
+
if (item.render !== newRender) {
|
|
402
|
+
item.render = newRender;
|
|
403
|
+
changed = true;
|
|
404
|
+
}
|
|
405
|
+
if (item.hasChildren) {
|
|
406
|
+
expandedMap.set(item.indent, {
|
|
407
|
+
expanded: item.expanded,
|
|
408
|
+
render: item.render,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
slotEntered = false;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
if (changed) {
|
|
417
|
+
this.bumpVersion();
|
|
694
418
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
419
|
+
}
|
|
420
|
+
isResourceViewResponsive() {
|
|
421
|
+
return isPercent(this.getResourceTableConfigWidth());
|
|
422
|
+
}
|
|
423
|
+
isContentViewResponsive() {
|
|
424
|
+
return isPercent(this.getContentCellConfigWidth());
|
|
425
|
+
}
|
|
426
|
+
getSchedulerWidth() {
|
|
427
|
+
const baseWidth = this.documentWidth > 0 ? this.documentWidth : 0;
|
|
428
|
+
return this.isSchedulerResponsive()
|
|
429
|
+
? percentOf(baseWidth, this.config.schedulerWidth)
|
|
430
|
+
: asPx(this.config.schedulerWidth);
|
|
431
|
+
}
|
|
432
|
+
getSchedulerHeight() {
|
|
433
|
+
// Use the header height tracked in SchedulerData (set via _setSchedulerHeaderHeight)
|
|
434
|
+
const headerHeight = this.schedulerHeaderHeight || 0;
|
|
435
|
+
const underneathHeight = this.config.underneathHeight || 0;
|
|
436
|
+
const baseHeight = this.documentHeight - headerHeight - this.config.tableHeaderHeight - underneathHeight;
|
|
437
|
+
const validBaseHeight = baseHeight > 0 ? baseHeight : 0;
|
|
438
|
+
const { schedulerHeight } = this.config;
|
|
439
|
+
if (this.isSchedulerResponsive() && schedulerHeight !== undefined && isPercent(schedulerHeight)) {
|
|
440
|
+
return percentOf(validBaseHeight, schedulerHeight);
|
|
699
441
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
442
|
+
// fallback to max height if set, else just use base height
|
|
443
|
+
return this.config.schedulerMaxHeight || validBaseHeight;
|
|
444
|
+
}
|
|
445
|
+
// configured resource column width in px (config may be a percentage of the scheduler width)
|
|
446
|
+
_getConfiguredResourceTableWidth() {
|
|
447
|
+
const resourceTableConfigWidth = this.getResourceTableConfigWidth();
|
|
448
|
+
return this.isResourceViewResponsive()
|
|
449
|
+
? percentOf(this.getSchedulerWidth(), resourceTableConfigWidth)
|
|
450
|
+
: asPx(resourceTableConfigWidth);
|
|
451
|
+
}
|
|
452
|
+
getResourceTableWidth() {
|
|
453
|
+
const schedulerWidth = this.getSchedulerWidth();
|
|
454
|
+
let resourceTableWidth = this._getConfiguredResourceTableWidth();
|
|
455
|
+
// only the few px left after the cells are stretched go to the resource column
|
|
456
|
+
if (this.isSchedulerResponsive() && this.getContentTableWidth() + resourceTableWidth < schedulerWidth)
|
|
457
|
+
resourceTableWidth = schedulerWidth - this.getContentTableWidth();
|
|
458
|
+
return resourceTableWidth;
|
|
459
|
+
}
|
|
460
|
+
getContentCellWidth() {
|
|
461
|
+
const contentCellConfigWidth = this.getContentCellConfigWidth();
|
|
462
|
+
const schedulerWidth = this.getSchedulerWidth();
|
|
463
|
+
const cellWidth = this.isContentViewResponsive()
|
|
464
|
+
? percentOf(schedulerWidth, contentCellConfigWidth)
|
|
465
|
+
: asPx(contentCellConfigWidth);
|
|
466
|
+
// stretch the cells to fill the container instead of widening the resource column
|
|
467
|
+
if (this.isSchedulerResponsive() && !this.showAgenda && this.headers?.length) {
|
|
468
|
+
const resourceWidth = this.config.resourceViewEnabled === false ? 0 : this._getConfiguredResourceTableWidth();
|
|
469
|
+
const fillWidth = Math.floor((schedulerWidth - resourceWidth) / this.headers.length);
|
|
470
|
+
return Math.max(cellWidth, fillWidth);
|
|
471
|
+
}
|
|
472
|
+
return cellWidth;
|
|
473
|
+
}
|
|
474
|
+
getContentTableWidth() {
|
|
475
|
+
return this.headers.length * this.getContentCellWidth();
|
|
476
|
+
}
|
|
477
|
+
getScrollToSpecialDayjs() {
|
|
478
|
+
if (this.config.scrollToSpecialDayjsEnabled)
|
|
479
|
+
return this.scrollToSpecialDayjs;
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
getSlots() {
|
|
483
|
+
return this.isEventPerspective ? this.eventGroups : this.resources;
|
|
484
|
+
}
|
|
485
|
+
getSlotById(slotId) {
|
|
486
|
+
const slots = this.getSlots();
|
|
487
|
+
let slot = undefined;
|
|
488
|
+
slots.forEach(item => {
|
|
489
|
+
if (item.id === slotId)
|
|
490
|
+
slot = item;
|
|
491
|
+
});
|
|
492
|
+
return slot;
|
|
493
|
+
}
|
|
494
|
+
getResourceById(resourceId) {
|
|
495
|
+
let resource = undefined;
|
|
496
|
+
this.resources.forEach(item => {
|
|
497
|
+
if (item.id === resourceId)
|
|
498
|
+
resource = item;
|
|
499
|
+
});
|
|
500
|
+
return resource;
|
|
501
|
+
}
|
|
502
|
+
// height of the optional group rows (month / week number) rendered above the main header row
|
|
503
|
+
getHeaderGroupRowsHeight() {
|
|
504
|
+
const { showMonthRow, monthRowHeight = 24, showWeekNumber, weekNumberRowHeight = 24 } = this.config;
|
|
505
|
+
return (showMonthRow ? monthRowHeight : 0) + (showWeekNumber ? weekNumberRowHeight : 0);
|
|
506
|
+
}
|
|
507
|
+
getTableHeaderHeight() {
|
|
508
|
+
return this.config.tableHeaderHeight;
|
|
509
|
+
}
|
|
510
|
+
getSchedulerContentDesiredHeight() {
|
|
511
|
+
let height = 0;
|
|
512
|
+
this.renderData.forEach(item => {
|
|
513
|
+
if (item.render)
|
|
514
|
+
height += item.rowHeight;
|
|
515
|
+
});
|
|
516
|
+
return height;
|
|
517
|
+
}
|
|
518
|
+
getCellMaxEvents() {
|
|
519
|
+
const viewConfigMap = {
|
|
520
|
+
[ViewType.Week]: 'weekMaxEvents',
|
|
521
|
+
[ViewType.Day]: 'dayMaxEvents',
|
|
522
|
+
[ViewType.Month]: 'monthMaxEvents',
|
|
523
|
+
[ViewType.Year]: 'yearMaxEvents',
|
|
524
|
+
[ViewType.Quarter]: 'quarterMaxEvents',
|
|
712
525
|
};
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
526
|
+
const configProperty = viewConfigMap[this.viewType] || 'customMaxEvents';
|
|
527
|
+
return this.config[configProperty];
|
|
528
|
+
}
|
|
529
|
+
getSelectedDate() {
|
|
530
|
+
return this.selectDate.format(DATE_FORMAT);
|
|
531
|
+
}
|
|
532
|
+
getViewStartDate() {
|
|
533
|
+
return this.startDate;
|
|
534
|
+
}
|
|
535
|
+
getViewEndDate() {
|
|
536
|
+
return this.endDate;
|
|
537
|
+
}
|
|
538
|
+
getViewDates() {
|
|
539
|
+
return {
|
|
540
|
+
startDate: this.startDate,
|
|
541
|
+
endDate: this.endDate,
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
getDateLabel() {
|
|
545
|
+
const start = this.localeDayjs(toDate(this.startDate));
|
|
546
|
+
const end = this.localeDayjs(toDate(this.endDate));
|
|
547
|
+
let dateLabel = start.format('LL');
|
|
548
|
+
if (start !== end)
|
|
549
|
+
dateLabel = `${start.format('LL')}-${end.format('LL')}`;
|
|
550
|
+
if (this.behaviors.getDateLabelFunc)
|
|
551
|
+
dateLabel = this.behaviors.getDateLabelFunc(this, this.viewType, this.startDate, this.endDate);
|
|
552
|
+
return dateLabel;
|
|
553
|
+
}
|
|
554
|
+
addEvent(newEvent) {
|
|
555
|
+
this._attachEvent(newEvent);
|
|
556
|
+
if (this.eventGroupsAutoGenerated)
|
|
557
|
+
this._generateEventGroups();
|
|
558
|
+
this._createRenderData();
|
|
559
|
+
this.bumpVersion();
|
|
560
|
+
}
|
|
561
|
+
updateEventStart(event, newStart) {
|
|
562
|
+
this._detachEvent(event);
|
|
563
|
+
event.start = newStart;
|
|
564
|
+
this._attachEvent(event);
|
|
565
|
+
this._createRenderData();
|
|
566
|
+
this.bumpVersion();
|
|
567
|
+
}
|
|
568
|
+
updateEventEnd(event, newEnd) {
|
|
569
|
+
event.end = newEnd;
|
|
570
|
+
this._createRenderData();
|
|
571
|
+
this.bumpVersion();
|
|
572
|
+
}
|
|
573
|
+
swapEvent(eventSource, eventDest) {
|
|
574
|
+
// Swap group or resource IDs
|
|
575
|
+
if (this.isEventPerspective) {
|
|
576
|
+
[eventSource.groupId, eventDest.groupId] = [eventDest.groupId, eventSource.groupId];
|
|
577
|
+
[eventSource.groupName, eventDest.groupName] = [eventDest.groupName, eventSource.groupName];
|
|
717
578
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
_resolveDate(num, date = undefined) {
|
|
722
|
-
if (date !== undefined) {
|
|
723
|
-
this.selectDate = this.localeDayjs(date);
|
|
724
|
-
}
|
|
725
|
-
const setStartAndEndDates = unit => {
|
|
726
|
-
this.startDate = date !== undefined ? this.selectDate.startOf(unit) : this.startDate.add(num, `${unit}s`);
|
|
727
|
-
this.endDate = this.startDate.endOf(unit);
|
|
728
|
-
};
|
|
729
|
-
switch (this.viewType) {
|
|
730
|
-
case ViewType.Week:
|
|
731
|
-
if (date !== undefined) {
|
|
732
|
-
this.startDate = this.selectDate.startOf('isoWeek');
|
|
733
|
-
} else {
|
|
734
|
-
this.startDate = this.startDate.add(num, 'weeks');
|
|
579
|
+
else {
|
|
580
|
+
[eventSource.resourceId, eventDest.resourceId] = [eventDest.resourceId, eventSource.resourceId];
|
|
735
581
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
this.
|
|
741
|
-
this.
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
this.startDate = this.localeDayjs(customDate.startDate);
|
|
758
|
-
this.endDate = this.localeDayjs(customDate.endDate);
|
|
759
|
-
if (customDate.cellUnit) {
|
|
760
|
-
this.cellUnit = customDate.cellUnit;
|
|
761
|
-
}
|
|
762
|
-
} else {
|
|
763
|
-
throw new Error('This is a custom view type, set behaviors.getCustomDateFunc func ' + 'to resolve the time window (startDate and endDate) yourself');
|
|
582
|
+
// Swap start and end times
|
|
583
|
+
[eventSource.start, eventDest.start] = [eventDest.start, eventSource.start];
|
|
584
|
+
[eventSource.end, eventDest.end] = [eventDest.end, eventSource.end];
|
|
585
|
+
// Update the events
|
|
586
|
+
this._detachEvent(eventSource);
|
|
587
|
+
this._detachEvent(eventDest);
|
|
588
|
+
this._attachEvent(eventSource);
|
|
589
|
+
this._attachEvent(eventDest);
|
|
590
|
+
this._createRenderData();
|
|
591
|
+
this.bumpVersion();
|
|
592
|
+
}
|
|
593
|
+
swapEvent2(eventSource, eventDest) {
|
|
594
|
+
const tempEventSource = { ...eventSource };
|
|
595
|
+
const tempEventDest = { ...eventDest };
|
|
596
|
+
this._detachEvent(eventSource);
|
|
597
|
+
this._detachEvent(eventDest);
|
|
598
|
+
if (this.isEventPerspective) {
|
|
599
|
+
tempEventSource.groupId = eventDest.groupId;
|
|
600
|
+
tempEventSource.groupName = eventDest.groupName;
|
|
601
|
+
tempEventDest.groupId = eventSource.groupId;
|
|
602
|
+
tempEventDest.groupName = eventSource.groupName;
|
|
764
603
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
_createHeaders() {
|
|
771
|
-
const timeSlots = [];
|
|
772
|
-
let start = this.localeDayjs(new Date(this.startDate));
|
|
773
|
-
let end = this.localeDayjs(new Date(this.endDate));
|
|
774
|
-
let header = start;
|
|
775
|
-
const width = this.getContentCellWidth();
|
|
776
|
-
if (this.showAgenda) {
|
|
777
|
-
timeSlots.push({
|
|
778
|
-
time: header.format(DATETIME_FORMAT),
|
|
779
|
-
nonWorkingTime: false
|
|
780
|
-
});
|
|
781
|
-
} else if (this.cellUnit === CellUnit.Hour) {
|
|
782
|
-
if (start.hour() === 0) {
|
|
783
|
-
start = start.hour(this.config.dayStartFrom);
|
|
784
|
-
}
|
|
785
|
-
if (end.hour() === 0) {
|
|
786
|
-
end = end.hour(this.config.dayStopTo);
|
|
787
|
-
}
|
|
788
|
-
header = start;
|
|
789
|
-
let prevHour = -1;
|
|
790
|
-
while (header >= start && header <= end) {
|
|
791
|
-
// prevent doubled hours on time change
|
|
792
|
-
if (header.hour() === prevHour) {
|
|
793
|
-
header = header.add(1, 'hours');
|
|
794
|
-
continue;
|
|
604
|
+
else {
|
|
605
|
+
tempEventSource.resourceId = eventDest.resourceId;
|
|
606
|
+
tempEventDest.resourceId = eventSource.resourceId;
|
|
795
607
|
}
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
608
|
+
tempEventSource.end = eventDest.end;
|
|
609
|
+
tempEventSource.start = eventDest.start;
|
|
610
|
+
tempEventDest.end = eventSource.end;
|
|
611
|
+
tempEventDest.start = eventSource.start;
|
|
612
|
+
this._attachEvent(tempEventSource);
|
|
613
|
+
this._attachEvent(tempEventDest);
|
|
614
|
+
this._createRenderData();
|
|
615
|
+
this.bumpVersion();
|
|
616
|
+
}
|
|
617
|
+
moveEvent(event, newSlotId, newSlotName, newStart, newEnd) {
|
|
618
|
+
this._detachEvent(event);
|
|
619
|
+
if (this.isEventPerspective) {
|
|
620
|
+
event.groupId = newSlotId;
|
|
621
|
+
event.groupName = newSlotName;
|
|
622
|
+
}
|
|
623
|
+
else
|
|
624
|
+
event.resourceId = newSlotId;
|
|
625
|
+
event.end = newEnd;
|
|
626
|
+
event.start = newStart;
|
|
627
|
+
this._attachEvent(event);
|
|
628
|
+
this._createRenderData();
|
|
629
|
+
this.bumpVersion();
|
|
630
|
+
}
|
|
631
|
+
isEventInTimeWindow(eventStart, eventEnd, windowStart, windowEnd) {
|
|
632
|
+
return eventStart < windowEnd && eventEnd > windowStart;
|
|
633
|
+
}
|
|
634
|
+
removeEvent(event) {
|
|
635
|
+
const index = this.events.indexOf(event);
|
|
636
|
+
if (index !== -1) {
|
|
637
|
+
this.events.splice(index, 1);
|
|
638
|
+
this._createRenderData();
|
|
639
|
+
this.bumpVersion();
|
|
809
640
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
641
|
+
}
|
|
642
|
+
removeEventById(eventId) {
|
|
643
|
+
let index = -1;
|
|
644
|
+
this.events.forEach((item, idx) => {
|
|
645
|
+
if (item.id === eventId)
|
|
646
|
+
index = idx;
|
|
647
|
+
});
|
|
648
|
+
if (index !== -1) {
|
|
649
|
+
this.events.splice(index, 1);
|
|
650
|
+
this._createRenderData();
|
|
651
|
+
this.bumpVersion();
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
getResourceTableConfigWidth() {
|
|
655
|
+
if (this.showAgenda) {
|
|
656
|
+
return this.config.agendaResourceTableWidth;
|
|
657
|
+
}
|
|
658
|
+
const viewConfigMap = {
|
|
659
|
+
[ViewType.Week]: 'weekResourceTableWidth',
|
|
660
|
+
[ViewType.Day]: 'dayResourceTableWidth',
|
|
661
|
+
[ViewType.Month]: 'monthResourceTableWidth',
|
|
662
|
+
[ViewType.Year]: 'yearResourceTableWidth',
|
|
663
|
+
[ViewType.Quarter]: 'quarterResourceTableWidth',
|
|
664
|
+
[ViewType.VerticalResource]: 'customResourceTableWidth',
|
|
817
665
|
};
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
666
|
+
const configProperty = viewConfigMap[this.viewType] || 'customResourceTableWidth';
|
|
667
|
+
return this.config[configProperty];
|
|
668
|
+
}
|
|
669
|
+
getContentCellConfigWidth() {
|
|
670
|
+
const viewConfigMap = {
|
|
671
|
+
[ViewType.Week]: 'weekCellWidth',
|
|
672
|
+
[ViewType.Day]: 'dayCellWidth',
|
|
673
|
+
[ViewType.Month]: 'monthCellWidth',
|
|
674
|
+
[ViewType.Year]: 'yearCellWidth',
|
|
675
|
+
[ViewType.Quarter]: 'quarterCellWidth',
|
|
676
|
+
[ViewType.VerticalResource]: 'customCellWidth',
|
|
677
|
+
};
|
|
678
|
+
const configProperty = viewConfigMap[this.viewType] || 'customCellWidth';
|
|
679
|
+
return this.config[configProperty];
|
|
680
|
+
}
|
|
681
|
+
_setDocumentWidth(documentWidth) {
|
|
682
|
+
if (documentWidth >= 0 && documentWidth !== this.documentWidth) {
|
|
683
|
+
this.documentWidth = documentWidth;
|
|
684
|
+
this.bumpVersion();
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
_setDocumentHeight(documentHeight) {
|
|
688
|
+
if (documentHeight >= 0 && documentHeight !== this.documentHeight) {
|
|
689
|
+
this.documentHeight = documentHeight;
|
|
690
|
+
this.bumpVersion();
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
_setSchedulerHeaderHeight(schedulerHeaderHeight) {
|
|
694
|
+
if (schedulerHeaderHeight >= 0 && schedulerHeaderHeight !== this.schedulerHeaderHeight) {
|
|
695
|
+
this.schedulerHeaderHeight = schedulerHeaderHeight;
|
|
696
|
+
this.bumpVersion();
|
|
826
697
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
698
|
+
}
|
|
699
|
+
_detachEvent(event) {
|
|
700
|
+
const index = this.events.indexOf(event);
|
|
701
|
+
if (index !== -1)
|
|
702
|
+
this.events.splice(index, 1);
|
|
703
|
+
}
|
|
704
|
+
_attachEvent(event) {
|
|
705
|
+
let pos = 0;
|
|
706
|
+
const eventStart = this.localeDayjs(new Date(event.start));
|
|
707
|
+
this.events.forEach((item, index) => {
|
|
708
|
+
const start = this.localeDayjs(new Date(item.start));
|
|
709
|
+
if (eventStart >= start)
|
|
710
|
+
pos = index + 1;
|
|
834
711
|
});
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
time
|
|
712
|
+
this.events.splice(pos, 0, event);
|
|
713
|
+
}
|
|
714
|
+
_handleRecurringEvents() {
|
|
715
|
+
const recurringEvents = this.events.filter((x) => !!x.rrule);
|
|
716
|
+
recurringEvents.forEach(item => {
|
|
717
|
+
this._detachEvent(item);
|
|
842
718
|
});
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
719
|
+
recurringEvents.forEach(item => {
|
|
720
|
+
const windowStart = this.startDate;
|
|
721
|
+
const windowEnd = this.endDate.add(1, 'days');
|
|
722
|
+
const oldStart = this.localeDayjs(new Date(item.start));
|
|
723
|
+
const oldEnd = this.localeDayjs(new Date(item.end));
|
|
724
|
+
let rule = rrulestr(item.rrule);
|
|
725
|
+
let oldDtstart;
|
|
726
|
+
const oldUntil = rule.origOptions.until || windowEnd.toDate();
|
|
727
|
+
if (rule.origOptions.dtstart) {
|
|
728
|
+
oldDtstart = this.localeDayjs(new Date(rule.origOptions.dtstart));
|
|
729
|
+
}
|
|
730
|
+
// rule.origOptions.dtstart = oldStart.toDate();
|
|
731
|
+
if (windowEnd.valueOf() < oldUntil.valueOf()) {
|
|
732
|
+
rule.origOptions.until = windowEnd.toDate();
|
|
733
|
+
}
|
|
734
|
+
// reload
|
|
735
|
+
rule = rrulestr(rule.toString());
|
|
736
|
+
if (item.exdates || item.exrule) {
|
|
737
|
+
const rruleSet = new RRuleSet();
|
|
738
|
+
rruleSet.rrule(rule);
|
|
739
|
+
if (item.exrule) {
|
|
740
|
+
rruleSet.exrule(rrulestr(item.exrule));
|
|
741
|
+
}
|
|
742
|
+
if (item.exdates) {
|
|
743
|
+
item.exdates.forEach(exdate => {
|
|
744
|
+
rruleSet.exdate(this.localeDayjs(exdate).toDate());
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
rule = rruleSet;
|
|
748
|
+
}
|
|
749
|
+
const all = rule.between(toDate(windowStart), toDate(windowEnd));
|
|
750
|
+
all.forEach((time, index) => {
|
|
751
|
+
const newEvent = {
|
|
752
|
+
...item,
|
|
753
|
+
recurringEventId: item.id,
|
|
754
|
+
recurringEventStart: item.start,
|
|
755
|
+
recurringEventEnd: item.end,
|
|
756
|
+
id: `${item.id}-${index}`,
|
|
757
|
+
start: rule.origOptions.tzid
|
|
758
|
+
? this.localeDayjs
|
|
759
|
+
.utc(time)
|
|
760
|
+
.utcOffset(this.localeDayjs(new Date()).utcOffset(), true)
|
|
761
|
+
.format(DATETIME_FORMAT)
|
|
762
|
+
: this.localeDayjs(new Date(time)).format(DATETIME_FORMAT),
|
|
763
|
+
end: rule.origOptions.tzid
|
|
764
|
+
? this.localeDayjs
|
|
765
|
+
.utc(time)
|
|
766
|
+
.utcOffset(this.localeDayjs(new Date()).utcOffset(), true)
|
|
767
|
+
.add(oldEnd.diff(oldStart), 'ms')
|
|
768
|
+
.add(this.localeDayjs(new Date(oldUntil)).utcOffset() - this.localeDayjs(new Date(item.start)).utcOffset(), 'm')
|
|
769
|
+
.format(DATETIME_FORMAT)
|
|
770
|
+
: this.localeDayjs(new Date(time)).add(oldEnd.diff(oldStart), 'ms').format(DATETIME_FORMAT),
|
|
771
|
+
};
|
|
772
|
+
const eventStart = normalizeEventStart(newEvent.start);
|
|
773
|
+
const eventEnd = normalizeEventEnd(newEvent.end);
|
|
774
|
+
if (this.isEventInTimeWindow(eventStart, eventEnd, windowStart, windowEnd) &&
|
|
775
|
+
(!oldDtstart || eventStart >= oldDtstart)) {
|
|
776
|
+
this._attachEvent(newEvent);
|
|
777
|
+
}
|
|
778
|
+
});
|
|
850
779
|
});
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
780
|
+
}
|
|
781
|
+
_resolveDate(num, date = undefined) {
|
|
782
|
+
if (date !== undefined) {
|
|
783
|
+
this.selectDate = this.localeDayjs(date);
|
|
784
|
+
}
|
|
785
|
+
const setStartAndEndDates = (unit) => {
|
|
786
|
+
this.startDate = date !== undefined ? this.selectDate.startOf(unit) : this.startDate.add(num, `${unit}s`);
|
|
787
|
+
this.endDate = this.startDate.endOf(unit);
|
|
788
|
+
};
|
|
789
|
+
switch (this.viewType) {
|
|
790
|
+
case ViewType.Week:
|
|
791
|
+
if (date !== undefined) {
|
|
792
|
+
this.startDate = this.selectDate.startOf('isoWeek');
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
this.startDate = this.startDate.add(num, 'weeks');
|
|
796
|
+
}
|
|
797
|
+
this.endDate = this.startDate.endOf('isoWeek');
|
|
798
|
+
break;
|
|
799
|
+
case ViewType.Day:
|
|
800
|
+
case ViewType.VerticalResource:
|
|
801
|
+
this.startDate = (date !== undefined ? this.selectDate : this.startDate.add(num, 'days')).startOf('day');
|
|
802
|
+
this.endDate = this.startDate;
|
|
803
|
+
break;
|
|
804
|
+
case ViewType.Month:
|
|
805
|
+
setStartAndEndDates('month');
|
|
806
|
+
break;
|
|
807
|
+
case ViewType.Quarter:
|
|
808
|
+
setStartAndEndDates('quarter');
|
|
809
|
+
break;
|
|
810
|
+
case ViewType.Year:
|
|
811
|
+
setStartAndEndDates('year');
|
|
812
|
+
break;
|
|
813
|
+
case ViewType.Custom:
|
|
814
|
+
case ViewType.Custom1:
|
|
815
|
+
case ViewType.Custom2:
|
|
816
|
+
if (this.behaviors.getCustomDateFunc !== undefined) {
|
|
817
|
+
const customDate = this.behaviors.getCustomDateFunc(this, num, date);
|
|
818
|
+
this.startDate = this.localeDayjs(customDate.startDate);
|
|
819
|
+
this.endDate = this.localeDayjs(customDate.endDate);
|
|
820
|
+
if (customDate.cellUnit) {
|
|
821
|
+
this.cellUnit = customDate.cellUnit;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
throw new Error('This is a custom view type, set behaviors.getCustomDateFunc func ' +
|
|
826
|
+
'to resolve the time window (startDate and endDate) yourself');
|
|
827
|
+
}
|
|
828
|
+
break;
|
|
829
|
+
default:
|
|
830
|
+
break;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
_createHeaders() {
|
|
834
|
+
const timeSlots = [];
|
|
835
|
+
let start = this.localeDayjs(toDate(this.startDate));
|
|
836
|
+
let end = this.localeDayjs(toDate(this.endDate));
|
|
837
|
+
let header = start;
|
|
838
|
+
const width = this.getContentCellWidth();
|
|
839
|
+
if (this.showAgenda) {
|
|
840
|
+
timeSlots.push({
|
|
841
|
+
time: header.format(DATETIME_FORMAT),
|
|
842
|
+
nonWorkingTime: false,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
else if (this.cellUnit === CellUnit.Hour) {
|
|
846
|
+
if (start.hour() === 0) {
|
|
847
|
+
start = start.hour(this.config.dayStartFrom);
|
|
848
|
+
}
|
|
849
|
+
if (end.hour() === 0) {
|
|
850
|
+
end = end.hour(this.config.dayStopTo);
|
|
851
|
+
}
|
|
852
|
+
header = start;
|
|
853
|
+
let prevHour = -1;
|
|
854
|
+
while (header >= start && header <= end) {
|
|
855
|
+
// prevent doubled hours on time change
|
|
856
|
+
if (header.hour() === prevHour) {
|
|
857
|
+
header = header.add(1, 'hours');
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
prevHour = header.hour();
|
|
861
|
+
const minuteSteps = this.getMinuteStepsInHour();
|
|
862
|
+
for (let i = 0; i < minuteSteps; i += 1) {
|
|
863
|
+
const hour = header.hour();
|
|
864
|
+
if (hour >= this.config.dayStartFrom && hour <= this.config.dayStopTo) {
|
|
865
|
+
const time = header.format(DATETIME_FORMAT);
|
|
866
|
+
const nonWorkingTime = this.behaviors.isNonWorkingTimeFunc(this, time);
|
|
867
|
+
timeSlots.push({ time, nonWorkingTime });
|
|
868
|
+
}
|
|
869
|
+
header = header.add(this.config.minuteStep, 'minutes');
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
else if (this.cellUnit === CellUnit.Day) {
|
|
874
|
+
while (header >= start && header <= end) {
|
|
875
|
+
const time = header.format(DATETIME_FORMAT);
|
|
876
|
+
const style = { width, minWidth: width };
|
|
877
|
+
const dayOfWeek = header.day();
|
|
878
|
+
if (this.config.displayWeekend || (dayOfWeek !== 0 && dayOfWeek !== 6)) {
|
|
879
|
+
const nonWorkingTime = this.behaviors.isNonWorkingTimeFunc(this, time);
|
|
880
|
+
timeSlots.push({ time, nonWorkingTime, style });
|
|
881
|
+
}
|
|
882
|
+
header = header.add(1, 'days');
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
else if (this.cellUnit === CellUnit.Week) {
|
|
886
|
+
while (header >= start && header <= end) {
|
|
887
|
+
const time = header.format(DATE_FORMAT);
|
|
888
|
+
timeSlots.push({ time });
|
|
889
|
+
header = header.add(1, 'weeks').startOf('isoWeek');
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
else if (this.cellUnit === CellUnit.Month) {
|
|
893
|
+
while (header >= start && header <= end) {
|
|
894
|
+
const time = header.format(DATE_FORMAT);
|
|
895
|
+
timeSlots.push({ time });
|
|
896
|
+
header = header.add(1, 'months').startOf('month');
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
else if (this.cellUnit === CellUnit.Quarter) {
|
|
900
|
+
while (header >= start && header <= end) {
|
|
901
|
+
const time = header.format(DATE_FORMAT);
|
|
902
|
+
timeSlots.push({ time });
|
|
903
|
+
header = header.add(1, 'quarters').startOf('quarter');
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
else if (this.cellUnit === CellUnit.Year) {
|
|
907
|
+
while (header >= start && header <= end) {
|
|
908
|
+
const time = header.format(DATE_FORMAT);
|
|
909
|
+
timeSlots.push({ time });
|
|
910
|
+
header = header.add(1, 'years').startOf('year');
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
this.timeSlots = timeSlots;
|
|
914
|
+
if (this.isVerticalResourceView()) {
|
|
915
|
+
const currentViewDate = this.localeDayjs(toDate(this.startDate)).format(DATETIME_FORMAT);
|
|
916
|
+
this.headers = this.resources.map(r => ({
|
|
917
|
+
...r,
|
|
918
|
+
time: currentViewDate,
|
|
919
|
+
nonWorkingTime: false,
|
|
920
|
+
}));
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
this.headers = timeSlots;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
_createInitHeaderEvents(header) {
|
|
927
|
+
const start = this.localeDayjs(new Date(header.time));
|
|
928
|
+
const startValue = start.format(DATETIME_FORMAT);
|
|
929
|
+
let endValue;
|
|
930
|
+
if (this.showAgenda) {
|
|
931
|
+
const incrementUnits = {
|
|
932
|
+
[ViewType.Day]: 'days',
|
|
933
|
+
[ViewType.Week]: 'weeks',
|
|
934
|
+
[ViewType.Month]: 'months',
|
|
935
|
+
[ViewType.Year]: 'years',
|
|
936
|
+
[ViewType.Quarter]: 'quarters',
|
|
937
|
+
};
|
|
938
|
+
const incrementUnit = incrementUnits[this.viewType] || 'days';
|
|
939
|
+
if (incrementUnit === 'days') {
|
|
940
|
+
endValue = this.localeDayjs(toDate(this.endDate)).add(1, 'days').format(DATETIME_FORMAT);
|
|
941
|
+
}
|
|
942
|
+
else {
|
|
943
|
+
endValue = addUnit(start, 1, incrementUnit).format(DATETIME_FORMAT);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
else if (this.isVerticalResourceView()) {
|
|
947
|
+
// In vertical view, headers are resources. They don't have a time span.
|
|
948
|
+
// But we need a start/end for the headerEvent structure.
|
|
949
|
+
endValue = startValue;
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
const { amount, unit } = this._getCellStep();
|
|
953
|
+
// Keep the full timestamp so cell bounds match _getSpan/normalizeEventEnd in every time zone.
|
|
954
|
+
endValue = addUnit(start, amount, unit).format(DATETIME_FORMAT);
|
|
955
|
+
}
|
|
956
|
+
return {
|
|
957
|
+
time: header.time,
|
|
958
|
+
nonWorkingTime: header.nonWorkingTime,
|
|
959
|
+
start: startValue,
|
|
960
|
+
end: endValue,
|
|
961
|
+
count: 0,
|
|
962
|
+
addMore: 0,
|
|
963
|
+
addMoreIndex: 0,
|
|
964
|
+
events: [],
|
|
965
|
+
id: header.id || header.time,
|
|
966
|
+
style: header.style || { width: this.getContentCellWidth(), minWidth: this.getContentCellWidth() },
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
_createHeaderEvent(render, span, eventItem) {
|
|
970
|
+
return { render, span, eventItem };
|
|
971
|
+
}
|
|
972
|
+
_getEventSlotId(event) {
|
|
973
|
+
if (this.isEventPerspective) {
|
|
974
|
+
return this._getEventGroupId(event);
|
|
975
|
+
}
|
|
976
|
+
// Support for multi-resource events
|
|
977
|
+
if (event.resourceIds && event.resourceIds.length > 0) {
|
|
978
|
+
// For multi-resource events, return the first resourceId for backward compatibility
|
|
979
|
+
// The rendering logic will handle showing on multiple rows
|
|
980
|
+
return event.resourceIds[0];
|
|
981
|
+
}
|
|
982
|
+
// Fallback to single resourceId
|
|
983
|
+
return event.resourceId;
|
|
984
|
+
}
|
|
985
|
+
_getEventGroupId(event) {
|
|
986
|
+
return event.groupId ? event.groupId.toString() : event.id.toString();
|
|
987
|
+
}
|
|
988
|
+
_getEventGroupName(event) {
|
|
989
|
+
return event.groupName ? event.groupName : event.title;
|
|
990
|
+
}
|
|
991
|
+
_generateEventGroups() {
|
|
992
|
+
const eventGroups = [];
|
|
993
|
+
const set = new Set();
|
|
994
|
+
this.events.forEach(item => {
|
|
995
|
+
const groupId = this._getEventGroupId(item);
|
|
996
|
+
const groupName = this._getEventGroupName(item);
|
|
997
|
+
if (!set.has(groupId)) {
|
|
998
|
+
eventGroups.push({
|
|
999
|
+
id: groupId,
|
|
1000
|
+
name: groupName,
|
|
1001
|
+
state: item,
|
|
1002
|
+
});
|
|
1003
|
+
set.add(groupId);
|
|
1004
|
+
}
|
|
858
1005
|
});
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
}
|
|
927
|
-
_getEventSlotId(event) {
|
|
928
|
-
if (this.isEventPerspective) {
|
|
929
|
-
return this._getEventGroupId(event);
|
|
930
|
-
}
|
|
931
|
-
// Support for multi-resource events
|
|
932
|
-
if (event.resourceIds && event.resourceIds.length > 0) {
|
|
933
|
-
// For multi-resource events, return the first resourceId for backward compatibility
|
|
934
|
-
// The rendering logic will handle showing on multiple rows
|
|
935
|
-
return event.resourceIds[0];
|
|
936
|
-
}
|
|
937
|
-
// Fallback to single resourceId
|
|
938
|
-
return event.resourceId;
|
|
939
|
-
}
|
|
940
|
-
_getEventGroupId(event) {
|
|
941
|
-
return event.groupId ? event.groupId.toString() : event.id.toString();
|
|
942
|
-
}
|
|
943
|
-
_getEventGroupName(event) {
|
|
944
|
-
return event.groupName ? event.groupName : event.title;
|
|
945
|
-
}
|
|
946
|
-
_generateEventGroups() {
|
|
947
|
-
const eventGroups = [];
|
|
948
|
-
const set = new Set();
|
|
949
|
-
this.events.forEach(item => {
|
|
950
|
-
const groupId = this._getEventGroupId(item);
|
|
951
|
-
const groupName = this._getEventGroupName(item);
|
|
952
|
-
if (!set.has(groupId)) {
|
|
953
|
-
eventGroups.push({
|
|
954
|
-
id: groupId,
|
|
955
|
-
name: groupName,
|
|
956
|
-
state: item
|
|
1006
|
+
this.eventGroups = eventGroups;
|
|
1007
|
+
}
|
|
1008
|
+
_createInitRenderData(isEventPerspective, eventGroups, resources, headers) {
|
|
1009
|
+
const slots = this.isVerticalResourceView()
|
|
1010
|
+
? this.timeSlots.map(ts => ({
|
|
1011
|
+
...ts,
|
|
1012
|
+
id: ts.time,
|
|
1013
|
+
name: ts.time,
|
|
1014
|
+
slotId: ts.time,
|
|
1015
|
+
slotName: ts.time,
|
|
1016
|
+
}))
|
|
1017
|
+
: isEventPerspective
|
|
1018
|
+
? eventGroups
|
|
1019
|
+
: resources;
|
|
1020
|
+
const slotTree = [];
|
|
1021
|
+
const slotMap = new Map();
|
|
1022
|
+
slots.forEach(slot => {
|
|
1023
|
+
const headerEvents = headers.map(header => this._createInitHeaderEvents(header));
|
|
1024
|
+
const slotRenderData = {
|
|
1025
|
+
...slot,
|
|
1026
|
+
slotId: slot.id,
|
|
1027
|
+
slotName: slot.name,
|
|
1028
|
+
slotTitle: slot.title,
|
|
1029
|
+
parentId: slot.parentId,
|
|
1030
|
+
groupOnly: slot.groupOnly,
|
|
1031
|
+
hasSummary: false,
|
|
1032
|
+
rowMaxCount: 0,
|
|
1033
|
+
rowHeight: this.config.nonAgendaSlotMinHeight !== 0
|
|
1034
|
+
? this.config.nonAgendaSlotMinHeight
|
|
1035
|
+
: this.config.eventItemLineHeight + 2,
|
|
1036
|
+
headerItems: headerEvents,
|
|
1037
|
+
indent: 0,
|
|
1038
|
+
hasChildren: false,
|
|
1039
|
+
expanded: true,
|
|
1040
|
+
render: true,
|
|
1041
|
+
};
|
|
1042
|
+
const { id } = slot;
|
|
1043
|
+
let value;
|
|
1044
|
+
if (slotMap.has(id)) {
|
|
1045
|
+
value = slotMap.get(id);
|
|
1046
|
+
value.data = slotRenderData;
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
value = {
|
|
1050
|
+
data: slotRenderData,
|
|
1051
|
+
children: [],
|
|
1052
|
+
};
|
|
1053
|
+
slotMap.set(id, value);
|
|
1054
|
+
}
|
|
1055
|
+
const { parentId } = slot;
|
|
1056
|
+
if (!parentId || parentId === id) {
|
|
1057
|
+
slotTree.push(value);
|
|
1058
|
+
}
|
|
1059
|
+
else {
|
|
1060
|
+
let parentValue;
|
|
1061
|
+
if (slotMap.has(parentId)) {
|
|
1062
|
+
parentValue = slotMap.get(parentId);
|
|
1063
|
+
}
|
|
1064
|
+
else {
|
|
1065
|
+
parentValue = {
|
|
1066
|
+
data: undefined,
|
|
1067
|
+
children: [],
|
|
1068
|
+
};
|
|
1069
|
+
slotMap.set(parentId, parentValue);
|
|
1070
|
+
}
|
|
1071
|
+
parentValue.children.push(value);
|
|
1072
|
+
}
|
|
957
1073
|
});
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
};
|
|
991
|
-
const {
|
|
992
|
-
id
|
|
993
|
-
} = slot;
|
|
994
|
-
let value;
|
|
995
|
-
if (slotMap.has(id)) {
|
|
996
|
-
value = slotMap.get(id);
|
|
997
|
-
value.data = slotRenderData;
|
|
998
|
-
} else {
|
|
999
|
-
value = {
|
|
1000
|
-
data: slotRenderData,
|
|
1001
|
-
children: []
|
|
1074
|
+
const slotStack = [];
|
|
1075
|
+
let i;
|
|
1076
|
+
for (i = slotTree.length - 1; i >= 0; i -= 1) {
|
|
1077
|
+
slotStack.push(slotTree[i]);
|
|
1078
|
+
}
|
|
1079
|
+
const initRenderData = [];
|
|
1080
|
+
while (slotStack.length > 0) {
|
|
1081
|
+
const currentNode = slotStack.pop();
|
|
1082
|
+
// every node reached from the tree roots has its data set (placeholders only exist for missing parents)
|
|
1083
|
+
const data = currentNode.data;
|
|
1084
|
+
if (data.indent > 0) {
|
|
1085
|
+
data.render = this.config.defaultExpanded;
|
|
1086
|
+
}
|
|
1087
|
+
if (currentNode.children.length > 0) {
|
|
1088
|
+
data.hasChildren = true;
|
|
1089
|
+
data.expanded = this.config.defaultExpanded;
|
|
1090
|
+
}
|
|
1091
|
+
initRenderData.push(data);
|
|
1092
|
+
for (i = currentNode.children.length - 1; i >= 0; i -= 1) {
|
|
1093
|
+
currentNode.children[i].data.indent = data.indent + 1;
|
|
1094
|
+
slotStack.push(currentNode.children[i]);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
return initRenderData;
|
|
1098
|
+
}
|
|
1099
|
+
_getCellStep() {
|
|
1100
|
+
const units = {
|
|
1101
|
+
[CellUnit.Hour]: 'minutes',
|
|
1102
|
+
[CellUnit.Week]: 'weeks',
|
|
1103
|
+
[CellUnit.Month]: 'months',
|
|
1104
|
+
[CellUnit.Year]: 'years',
|
|
1105
|
+
[CellUnit.Quarter]: 'quarters',
|
|
1002
1106
|
};
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1107
|
+
const unit = units[this.cellUnit] || 'days';
|
|
1108
|
+
return { amount: unit === 'minutes' ? this.config.minuteStep : 1, unit };
|
|
1109
|
+
}
|
|
1110
|
+
// Span = number of visible header cells the event overlaps, using the same overlap rule as
|
|
1111
|
+
// _createRenderData. Headers only cover the visible window (and visible days), so the event is
|
|
1112
|
+
// clamped consistently across views, and calendar-aware dayjs math keeps DST days at one cell.
|
|
1113
|
+
_getSpan(startTime, endTime, headers) {
|
|
1114
|
+
if (this.showAgenda || this.isVerticalResourceView())
|
|
1115
|
+
return 1;
|
|
1116
|
+
const eventStart = normalizeEventStart(startTime);
|
|
1117
|
+
const eventEnd = normalizeEventEnd(endTime);
|
|
1118
|
+
const { amount, unit } = this._getCellStep();
|
|
1119
|
+
return headers.filter(header => {
|
|
1120
|
+
const cellStart = this.localeDayjs(new Date(header.time));
|
|
1121
|
+
return cellStart.isBefore(eventEnd) && addUnit(cellStart, amount, unit).isAfter(eventStart);
|
|
1122
|
+
}).length;
|
|
1123
|
+
}
|
|
1124
|
+
_validateResource(resources) {
|
|
1125
|
+
if (Object.prototype.toString.call(resources) !== '[object Array]') {
|
|
1126
|
+
throw new Error('Resources should be Array object');
|
|
1020
1127
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
let currentNode;
|
|
1031
|
-
while (slotStack.length > 0) {
|
|
1032
|
-
currentNode = slotStack.pop();
|
|
1033
|
-
if (currentNode.data.indent > 0) {
|
|
1034
|
-
currentNode.data.render = this.config.defaultExpanded;
|
|
1035
|
-
}
|
|
1036
|
-
if (currentNode.children.length > 0) {
|
|
1037
|
-
currentNode.data.hasChildren = true;
|
|
1038
|
-
currentNode.data.expanded = this.config.defaultExpanded;
|
|
1039
|
-
}
|
|
1040
|
-
initRenderData.push(currentNode.data);
|
|
1041
|
-
for (i = currentNode.children.length - 1; i >= 0; i -= 1) {
|
|
1042
|
-
currentNode.children[i].data.indent = currentNode.data.indent + 1;
|
|
1043
|
-
slotStack.push(currentNode.children[i]);
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
return initRenderData;
|
|
1047
|
-
}
|
|
1048
|
-
_getCellStep() {
|
|
1049
|
-
const unit = {
|
|
1050
|
-
[CellUnit.Hour]: 'minutes',
|
|
1051
|
-
[CellUnit.Week]: 'weeks',
|
|
1052
|
-
[CellUnit.Month]: 'months',
|
|
1053
|
-
[CellUnit.Year]: 'years',
|
|
1054
|
-
[CellUnit.Quarter]: 'quarters'
|
|
1055
|
-
}[this.cellUnit] || 'days';
|
|
1056
|
-
return {
|
|
1057
|
-
amount: unit === 'minutes' ? this.config.minuteStep : 1,
|
|
1058
|
-
unit
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
// Span = number of visible header cells the event overlaps, using the same overlap rule as
|
|
1063
|
-
// _createRenderData. Headers only cover the visible window (and visible days), so the event is
|
|
1064
|
-
// clamped consistently across views, and calendar-aware dayjs math keeps DST days at one cell.
|
|
1065
|
-
_getSpan(startTime, endTime, headers) {
|
|
1066
|
-
if (this.showAgenda || this.isVerticalResourceView()) return 1;
|
|
1067
|
-
const eventStart = normalizeEventStart(startTime);
|
|
1068
|
-
const eventEnd = normalizeEventEnd(endTime);
|
|
1069
|
-
const {
|
|
1070
|
-
amount,
|
|
1071
|
-
unit
|
|
1072
|
-
} = this._getCellStep();
|
|
1073
|
-
return headers.filter(header => {
|
|
1074
|
-
const cellStart = this.localeDayjs(new Date(header.time));
|
|
1075
|
-
return cellStart.isBefore(eventEnd) && cellStart.add(amount, unit).isAfter(eventStart);
|
|
1076
|
-
}).length;
|
|
1077
|
-
}
|
|
1078
|
-
_validateResource(resources) {
|
|
1079
|
-
if (Object.prototype.toString.call(resources) !== '[object Array]') {
|
|
1080
|
-
throw new Error('Resources should be Array object');
|
|
1081
|
-
}
|
|
1082
|
-
resources.forEach((item, index) => {
|
|
1083
|
-
if (item === undefined) {
|
|
1084
|
-
console.error(`Resource undefined: ${index}`);
|
|
1085
|
-
throw new Error(`Resource undefined: ${index}`);
|
|
1086
|
-
}
|
|
1087
|
-
if (item.id === undefined || item.name === undefined) {
|
|
1088
|
-
console.error('Resource property missed', index, item);
|
|
1089
|
-
throw new Error(`Resource property undefined: ${index}`);
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
}
|
|
1093
|
-
_validateEventGroups(eventGroups) {
|
|
1094
|
-
if (Object.prototype.toString.call(eventGroups) !== '[object Array]') {
|
|
1095
|
-
throw new Error('Event groups should be Array object');
|
|
1096
|
-
}
|
|
1097
|
-
eventGroups.forEach((item, index) => {
|
|
1098
|
-
if (item === undefined) {
|
|
1099
|
-
console.error(`Event group undefined: ${index}`);
|
|
1100
|
-
throw new Error(`Event group undefined: ${index}`);
|
|
1101
|
-
}
|
|
1102
|
-
if (item.id === undefined || item.name === undefined) {
|
|
1103
|
-
console.error('Event group property missed', index, item);
|
|
1104
|
-
throw new Error(`Event group property undefined: ${index}`);
|
|
1105
|
-
}
|
|
1106
|
-
});
|
|
1107
|
-
}
|
|
1108
|
-
_validateEvents(events) {
|
|
1109
|
-
if (Object.prototype.toString.call(events) !== '[object Array]') {
|
|
1110
|
-
throw new Error('Events should be Array object');
|
|
1111
|
-
}
|
|
1112
|
-
events.forEach((e, index) => {
|
|
1113
|
-
if (e === undefined) {
|
|
1114
|
-
console.error(`Event undefined: ${index}`);
|
|
1115
|
-
throw new Error(`Event undefined: ${index}`);
|
|
1116
|
-
}
|
|
1117
|
-
const hasResourceTarget = e.resourceId !== undefined || Array.isArray(e.resourceIds) && e.resourceIds.length > 0;
|
|
1118
|
-
if (e.id === undefined || !hasResourceTarget || e.title === undefined || e.start === undefined || e.end === undefined) {
|
|
1119
|
-
console.error('Event property missed (id, resourceId/resourceIds, title, start, end)', index, e);
|
|
1120
|
-
throw new Error(`Event property undefined (id/resourceId|resourceIds/title/start/end): ${index}`);
|
|
1121
|
-
}
|
|
1122
|
-
});
|
|
1123
|
-
}
|
|
1124
|
-
_validateMinuteStep(minuteStep) {
|
|
1125
|
-
if (60 % minuteStep !== 0) {
|
|
1126
|
-
console.error('Minute step is not set properly - 60 minutes must be divisible without remainder by this number');
|
|
1127
|
-
throw new Error('Minute step is not set properly - 60 minutes must be divisible without remainder by this number');
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
_compare(event1, event2) {
|
|
1131
|
-
const start1 = this.localeDayjs(event1.start);
|
|
1132
|
-
const start2 = this.localeDayjs(event2.start);
|
|
1133
|
-
if (start1 !== start2) return start1 < start2 ? -1 : 1;
|
|
1134
|
-
const end1 = this.localeDayjs(event1.end);
|
|
1135
|
-
const end2 = this.localeDayjs(event2.end);
|
|
1136
|
-
if (end1 !== end2) return end1 < end2 ? -1 : 1;
|
|
1137
|
-
return event1.id < event2.id ? -1 : 1;
|
|
1138
|
-
}
|
|
1139
|
-
_createRenderData() {
|
|
1140
|
-
const initRenderData = this._createInitRenderData(this.isEventPerspective, this.eventGroups, this.resources, this.headers);
|
|
1141
|
-
// this.events.sort(this._compare);
|
|
1142
|
-
const cellMaxEventsCount = this.getCellMaxEvents();
|
|
1143
|
-
const cellMaxEventsCountValue = 30;
|
|
1144
|
-
this.events.forEach(item => {
|
|
1145
|
-
let targetSlotIds = [];
|
|
1146
|
-
if (this.isVerticalResourceView()) {
|
|
1147
|
-
const eventStart = new Date(item.start);
|
|
1148
|
-
const eventEnd = new Date(item.end);
|
|
1149
|
-
this.timeSlots.forEach(ts => {
|
|
1150
|
-
// Check if the time slot overlaps with the event's time
|
|
1151
|
-
const tsStart = new Date(ts.time);
|
|
1152
|
-
const tsEnd = this.localeDayjs(ts.time).add(this.config.minuteStep, 'minutes').toDate();
|
|
1153
|
-
if (tsEnd > eventStart && tsStart < eventEnd) {
|
|
1154
|
-
targetSlotIds.push(ts.time);
|
|
1155
|
-
}
|
|
1128
|
+
resources.forEach((item, index) => {
|
|
1129
|
+
if (item === undefined) {
|
|
1130
|
+
console.error(`Resource undefined: ${index}`);
|
|
1131
|
+
throw new Error(`Resource undefined: ${index}`);
|
|
1132
|
+
}
|
|
1133
|
+
if (item.id === undefined || item.name === undefined) {
|
|
1134
|
+
console.error('Resource property missed', index, item);
|
|
1135
|
+
throw new Error(`Resource property undefined: ${index}`);
|
|
1136
|
+
}
|
|
1156
1137
|
});
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
targetSlotIds.forEach(slotId => {
|
|
1167
|
-
const resourceEventsList = initRenderData.filter(x => x.slotId === slotId);
|
|
1168
|
-
if (resourceEventsList.length > 0) {
|
|
1169
|
-
const resourceEvents = resourceEventsList[0];
|
|
1170
|
-
const span = this._getSpan(item.start, item.end, this.headers);
|
|
1171
|
-
const eventStart = normalizeEventStart(item.start).toDate();
|
|
1172
|
-
const eventEnd = normalizeEventEnd(item.end).toDate();
|
|
1173
|
-
let pos = -1;
|
|
1174
|
-
resourceEvents.headerItems.forEach((header, index) => {
|
|
1175
|
-
let isOverlapping = false;
|
|
1176
|
-
if (this.isVerticalResourceView()) {
|
|
1177
|
-
// In vertical view, headers are resources. Check if event belongs to this resource.
|
|
1178
|
-
const itemResourceIds = item.resourceIds || [item.resourceId];
|
|
1179
|
-
const targetId = header.id;
|
|
1180
|
-
isOverlapping = itemResourceIds.includes(targetId);
|
|
1181
|
-
} else {
|
|
1182
|
-
const headerStart = new Date(header.start);
|
|
1183
|
-
const headerEnd = new Date(header.end);
|
|
1184
|
-
isOverlapping = headerEnd > eventStart && headerStart < eventEnd;
|
|
1138
|
+
}
|
|
1139
|
+
_validateEventGroups(eventGroups) {
|
|
1140
|
+
if (Object.prototype.toString.call(eventGroups) !== '[object Array]') {
|
|
1141
|
+
throw new Error('Event groups should be Array object');
|
|
1142
|
+
}
|
|
1143
|
+
eventGroups.forEach((item, index) => {
|
|
1144
|
+
if (item === undefined) {
|
|
1145
|
+
console.error(`Event group undefined: ${index}`);
|
|
1146
|
+
throw new Error(`Event group undefined: ${index}`);
|
|
1185
1147
|
}
|
|
1186
|
-
if (
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
resourceEvents.rowMaxCount = header.count;
|
|
1190
|
-
const rowsCount = cellMaxEventsCount <= cellMaxEventsCountValue && resourceEvents.rowMaxCount > cellMaxEventsCount ? cellMaxEventsCount : resourceEvents.rowMaxCount;
|
|
1191
|
-
const newRowHeight = rowsCount * this.config.eventItemLineHeight + (this.config.creatable && this.config.checkConflict === false ? 20 : 2);
|
|
1192
|
-
if (newRowHeight > resourceEvents.rowHeight) resourceEvents.rowHeight = newRowHeight;
|
|
1193
|
-
}
|
|
1194
|
-
if (pos === -1) {
|
|
1195
|
-
let tmp = 0;
|
|
1196
|
-
while (header.events[tmp] !== undefined) tmp += 1;
|
|
1197
|
-
pos = tmp;
|
|
1198
|
-
}
|
|
1199
|
-
let render = false;
|
|
1200
|
-
if (this.isVerticalResourceView()) {
|
|
1201
|
-
render = true;
|
|
1202
|
-
} else {
|
|
1203
|
-
const headerStart = new Date(header.start);
|
|
1204
|
-
render = headerStart <= eventStart || index === 0;
|
|
1205
|
-
if (render === false) {
|
|
1206
|
-
const previousHeader = resourceEvents.headerItems[index - 1];
|
|
1207
|
-
const previousHeaderStart = new Date(previousHeader.start);
|
|
1208
|
-
const previousHeaderEnd = new Date(previousHeader.end);
|
|
1209
|
-
if (previousHeaderEnd <= eventStart || previousHeaderStart >= eventEnd) render = true;
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
header.events[pos] = this._createHeaderEvent(render, span, item);
|
|
1148
|
+
if (item.id === undefined || item.name === undefined) {
|
|
1149
|
+
console.error('Event group property missed', index, item);
|
|
1150
|
+
throw new Error(`Event group property undefined: ${index}`);
|
|
1213
1151
|
}
|
|
1214
|
-
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
_validateEvents(events) {
|
|
1155
|
+
if (Object.prototype.toString.call(events) !== '[object Array]') {
|
|
1156
|
+
throw new Error('Events should be Array object');
|
|
1157
|
+
}
|
|
1158
|
+
events.forEach((e, index) => {
|
|
1159
|
+
if (e === undefined) {
|
|
1160
|
+
console.error(`Event undefined: ${index}`);
|
|
1161
|
+
throw new Error(`Event undefined: ${index}`);
|
|
1162
|
+
}
|
|
1163
|
+
const hasResourceTarget = e.resourceId !== undefined || (Array.isArray(e.resourceIds) && e.resourceIds.length > 0);
|
|
1164
|
+
if (e.id === undefined ||
|
|
1165
|
+
!hasResourceTarget ||
|
|
1166
|
+
e.title === undefined ||
|
|
1167
|
+
e.start === undefined ||
|
|
1168
|
+
e.end === undefined) {
|
|
1169
|
+
console.error('Event property missed (id, resourceId/resourceIds, title, start, end)', index, e);
|
|
1170
|
+
throw new Error(`Event property undefined (id/resourceId|resourceIds/title/start/end): ${index}`);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
_validateMinuteStep(minuteStep) {
|
|
1175
|
+
if (60 % minuteStep !== 0) {
|
|
1176
|
+
console.error('Minute step is not set properly - 60 minutes must be divisible without remainder by this number');
|
|
1177
|
+
throw new Error('Minute step is not set properly - 60 minutes must be divisible without remainder by this number');
|
|
1215
1178
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1179
|
+
}
|
|
1180
|
+
_compare(event1, event2) {
|
|
1181
|
+
const start1 = this.localeDayjs(event1.start);
|
|
1182
|
+
const start2 = this.localeDayjs(event2.start);
|
|
1183
|
+
if (start1 !== start2)
|
|
1184
|
+
return start1 < start2 ? -1 : 1;
|
|
1185
|
+
const end1 = this.localeDayjs(event1.end);
|
|
1186
|
+
const end2 = this.localeDayjs(event2.end);
|
|
1187
|
+
if (end1 !== end2)
|
|
1188
|
+
return end1 < end2 ? -1 : 1;
|
|
1189
|
+
return event1.id < event2.id ? -1 : 1;
|
|
1190
|
+
}
|
|
1191
|
+
_createRenderData() {
|
|
1192
|
+
const initRenderData = this._createInitRenderData(this.isEventPerspective, this.eventGroups, this.resources, this.headers);
|
|
1193
|
+
// this.events.sort(this._compare);
|
|
1194
|
+
const cellMaxEventsCount = this.getCellMaxEvents();
|
|
1195
|
+
const cellMaxEventsCountValue = 30;
|
|
1196
|
+
this.events.forEach(item => {
|
|
1197
|
+
let targetSlotIds = [];
|
|
1198
|
+
if (this.isVerticalResourceView()) {
|
|
1199
|
+
const eventStart = new Date(item.start);
|
|
1200
|
+
const eventEnd = new Date(item.end);
|
|
1201
|
+
this.timeSlots.forEach(ts => {
|
|
1202
|
+
// Check if the time slot overlaps with the event's time
|
|
1203
|
+
const tsStart = new Date(ts.time);
|
|
1204
|
+
const tsEnd = this.localeDayjs(ts.time).add(this.config.minuteStep, 'minutes').toDate();
|
|
1205
|
+
if (tsEnd > eventStart && tsStart < eventEnd) {
|
|
1206
|
+
targetSlotIds.push(ts.time);
|
|
1207
|
+
}
|
|
1208
|
+
});
|
|
1232
1209
|
}
|
|
1233
|
-
if (
|
|
1234
|
-
|
|
1235
|
-
headerItem.addMore = headerItem.count - renderItemsCount;
|
|
1236
|
-
headerItem.addMoreIndex = addMoreIndex;
|
|
1237
|
-
}
|
|
1238
|
-
} else if (renderItemsCount < headerItem.count) {
|
|
1239
|
-
headerItem.addMore = headerItem.count - renderItemsCount;
|
|
1240
|
-
headerItem.addMoreIndex = addMoreIndex;
|
|
1210
|
+
else if (this.isEventPerspective) {
|
|
1211
|
+
targetSlotIds = [this._getEventSlotId(item)];
|
|
1241
1212
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1213
|
+
else if (item.resourceIds && item.resourceIds.length > 0) {
|
|
1214
|
+
// Multi-resource event
|
|
1215
|
+
targetSlotIds = item.resourceIds;
|
|
1216
|
+
}
|
|
1217
|
+
else if (item.resourceId) {
|
|
1218
|
+
// Single resource event (backward compatibility)
|
|
1219
|
+
targetSlotIds = [item.resourceId];
|
|
1220
|
+
}
|
|
1221
|
+
targetSlotIds.forEach(slotId => {
|
|
1222
|
+
const resourceEventsList = initRenderData.filter(x => x.slotId === slotId);
|
|
1223
|
+
if (resourceEventsList.length > 0) {
|
|
1224
|
+
const resourceEvents = resourceEventsList[0];
|
|
1225
|
+
const span = this._getSpan(item.start, item.end, this.headers);
|
|
1226
|
+
const eventStart = normalizeEventStart(item.start).toDate();
|
|
1227
|
+
const eventEnd = normalizeEventEnd(item.end).toDate();
|
|
1228
|
+
let pos = -1;
|
|
1229
|
+
resourceEvents.headerItems.forEach((header, index) => {
|
|
1230
|
+
let isOverlapping = false;
|
|
1231
|
+
if (this.isVerticalResourceView()) {
|
|
1232
|
+
// In vertical view, headers are resources. Check if event belongs to this resource.
|
|
1233
|
+
const itemResourceIds = item.resourceIds || [item.resourceId];
|
|
1234
|
+
const targetId = header.id;
|
|
1235
|
+
isOverlapping = itemResourceIds.includes(targetId);
|
|
1236
|
+
}
|
|
1237
|
+
else {
|
|
1238
|
+
const headerStart = new Date(header.start);
|
|
1239
|
+
const headerEnd = new Date(header.end);
|
|
1240
|
+
isOverlapping = headerEnd > eventStart && headerStart < eventEnd;
|
|
1241
|
+
}
|
|
1242
|
+
if (isOverlapping) {
|
|
1243
|
+
header.count += 1;
|
|
1244
|
+
if (header.count > resourceEvents.rowMaxCount) {
|
|
1245
|
+
resourceEvents.rowMaxCount = header.count;
|
|
1246
|
+
const rowsCount = cellMaxEventsCount <= cellMaxEventsCountValue && resourceEvents.rowMaxCount > cellMaxEventsCount
|
|
1247
|
+
? cellMaxEventsCount
|
|
1248
|
+
: resourceEvents.rowMaxCount;
|
|
1249
|
+
const newRowHeight = rowsCount * this.config.eventItemLineHeight +
|
|
1250
|
+
(this.config.creatable && this.config.checkConflict === false ? 20 : 2);
|
|
1251
|
+
if (newRowHeight > resourceEvents.rowHeight)
|
|
1252
|
+
resourceEvents.rowHeight = newRowHeight;
|
|
1253
|
+
}
|
|
1254
|
+
if (pos === -1) {
|
|
1255
|
+
let tmp = 0;
|
|
1256
|
+
while (header.events[tmp] !== undefined)
|
|
1257
|
+
tmp += 1;
|
|
1258
|
+
pos = tmp;
|
|
1259
|
+
}
|
|
1260
|
+
let render = false;
|
|
1261
|
+
if (this.isVerticalResourceView()) {
|
|
1262
|
+
render = true;
|
|
1263
|
+
}
|
|
1264
|
+
else {
|
|
1265
|
+
const headerStart = new Date(header.start);
|
|
1266
|
+
render = headerStart <= eventStart || index === 0;
|
|
1267
|
+
if (render === false) {
|
|
1268
|
+
const previousHeader = resourceEvents.headerItems[index - 1];
|
|
1269
|
+
const previousHeaderStart = new Date(previousHeader.start);
|
|
1270
|
+
const previousHeaderEnd = new Date(previousHeader.end);
|
|
1271
|
+
if (previousHeaderEnd <= eventStart || previousHeaderStart >= eventEnd)
|
|
1272
|
+
render = true;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
header.events[pos] = this._createHeaderEvent(render, span, item);
|
|
1276
|
+
}
|
|
1277
|
+
});
|
|
1278
|
+
}
|
|
1247
1279
|
});
|
|
1248
|
-
headerItem.summary = this.behaviors.getSummaryFunc(this, events, resourceEvents.slotId, resourceEvents.slotName, headerItem.start, headerItem.end);
|
|
1249
|
-
if (headerItem.summary && headerItem.summary.text !== undefined) hasSummary = true;
|
|
1250
|
-
}
|
|
1251
1280
|
});
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1281
|
+
if (cellMaxEventsCount <= cellMaxEventsCountValue || this.behaviors.getSummaryFunc !== undefined) {
|
|
1282
|
+
initRenderData.forEach(resourceEvents => {
|
|
1283
|
+
let hasSummary = false;
|
|
1284
|
+
resourceEvents.headerItems.forEach(headerItem => {
|
|
1285
|
+
if (cellMaxEventsCount <= cellMaxEventsCountValue) {
|
|
1286
|
+
let renderItemsCount = 0;
|
|
1287
|
+
let addMoreIndex = 0;
|
|
1288
|
+
let index = 0;
|
|
1289
|
+
while (index < cellMaxEventsCount - 1) {
|
|
1290
|
+
if (headerItem.events[index] !== undefined) {
|
|
1291
|
+
renderItemsCount += 1;
|
|
1292
|
+
addMoreIndex = index + 1;
|
|
1293
|
+
}
|
|
1294
|
+
index += 1;
|
|
1295
|
+
}
|
|
1296
|
+
if (headerItem.events[index] !== undefined) {
|
|
1297
|
+
if (renderItemsCount + 1 < headerItem.count) {
|
|
1298
|
+
headerItem.addMore = headerItem.count - renderItemsCount;
|
|
1299
|
+
headerItem.addMoreIndex = addMoreIndex;
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
else if (renderItemsCount < headerItem.count) {
|
|
1303
|
+
headerItem.addMore = headerItem.count - renderItemsCount;
|
|
1304
|
+
headerItem.addMoreIndex = addMoreIndex;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
if (this.behaviors.getSummaryFunc !== undefined) {
|
|
1308
|
+
const events = [];
|
|
1309
|
+
headerItem.events.forEach(e => {
|
|
1310
|
+
if (e?.eventItem)
|
|
1311
|
+
events.push(e.eventItem);
|
|
1312
|
+
});
|
|
1313
|
+
headerItem.summary = this.behaviors.getSummaryFunc(this, events, resourceEvents.slotId, resourceEvents.slotName, headerItem.start, headerItem.end);
|
|
1314
|
+
if (headerItem.summary && headerItem.summary.text !== undefined)
|
|
1315
|
+
hasSummary = true;
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1318
|
+
resourceEvents.hasSummary = hasSummary;
|
|
1319
|
+
if (hasSummary) {
|
|
1320
|
+
const rowsCount = cellMaxEventsCount <= cellMaxEventsCountValue && resourceEvents.rowMaxCount > cellMaxEventsCount
|
|
1321
|
+
? cellMaxEventsCount
|
|
1322
|
+
: resourceEvents.rowMaxCount;
|
|
1323
|
+
const newRowHeight = (rowsCount + 1) * this.config.eventItemLineHeight +
|
|
1324
|
+
(this.config.creatable && this.config.checkConflict === false ? 20 : 2);
|
|
1325
|
+
if (newRowHeight > resourceEvents.rowHeight)
|
|
1326
|
+
resourceEvents.rowHeight = newRowHeight;
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1257
1329
|
}
|
|
1258
|
-
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
}
|
|
1271
|
-
}
|
|
1330
|
+
this.renderData = initRenderData;
|
|
1331
|
+
}
|
|
1332
|
+
_startResizing() {
|
|
1333
|
+
this.resizing = true;
|
|
1334
|
+
}
|
|
1335
|
+
_stopResizing() {
|
|
1336
|
+
this.resizing = false;
|
|
1337
|
+
}
|
|
1338
|
+
_isResizing() {
|
|
1339
|
+
return this.resizing;
|
|
1340
|
+
}
|
|
1341
|
+
}
|