@fullcalendar/timeline 6.0.1 → 6.0.3
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/{index.cjs → index.esm.js} +12 -20
- package/index.global.js +2 -2
- package/index.global.min.js +2 -2
- package/index.js +20 -12
- package/{internal.cjs → internal.esm.js} +135 -150
- package/internal.js +150 -135
- package/package.json +10 -14
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var internal_cjs = require('@fullcalendar/core/internal.cjs');
|
|
6
|
-
var preact_cjs = require('@fullcalendar/core/preact.cjs');
|
|
7
|
-
var internal_cjs$1 = require('@fullcalendar/scrollgrid/internal.cjs');
|
|
1
|
+
import { config, createFormatter, greatestDurationDenominator, asCleanDays, createDuration, wholeDivideDurations, asRoughMs, addDays, startOfDay, asRoughSeconds, asRoughMinutes, diffWholeDays, isInt, computeVisibleDayRange, padStart, BaseComponent, memoizeObjArg, memoize, getDateMeta, ContentContainer, getSlotClassNames, getDayClassNames, buildNavLinkAttrs, PositionCache, findDirectChildren, rangeContainsMarker, NowTimer, NowIndicatorContainer, findElements, RefMap, multiplyDuration, SegHierarchy, groupIntersectingEntries, buildIsoString, computeEarliestSegStart, buildEventRangeKey, BgEvent, getSegMeta, renderFill, Slicer, intersectRanges, addMs, StandardEvent, MoreLinkContainer, sortEventSegs, mapHash, isPropsEqual, DateComponent, getStickyHeaderDates, getStickyFooterScrollbar, ViewContainer, renderScrollShim } from '@fullcalendar/core/internal';
|
|
2
|
+
import { createElement, Fragment, createRef } from '@fullcalendar/core/preact';
|
|
3
|
+
import { ScrollGrid } from '@fullcalendar/scrollgrid/internal';
|
|
8
4
|
|
|
9
5
|
const MIN_AUTO_LABELS = 18; // more than `12` months but less that `24` hours
|
|
10
6
|
const MAX_AUTO_SLOTS_PER_LABEL = 6; // allows 6 10-min slots in an hour
|
|
11
7
|
const MAX_AUTO_CELLS = 200; // allows 4-days to have a :30 slot duration
|
|
12
|
-
|
|
8
|
+
config.MAX_TIMELINE_SLOTS = 1000;
|
|
13
9
|
// potential nice values for slot-duration and interval-duration
|
|
14
10
|
const STOCK_SUB_DURATIONS = [
|
|
15
11
|
{ years: 1 },
|
|
@@ -43,18 +39,18 @@ function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileG
|
|
|
43
39
|
let rawFormats = Array.isArray(input) ? input :
|
|
44
40
|
(input != null) ? [input] :
|
|
45
41
|
computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions);
|
|
46
|
-
tDateProfile.headerFormats = rawFormats.map((rawFormat) =>
|
|
42
|
+
tDateProfile.headerFormats = rawFormats.map((rawFormat) => createFormatter(rawFormat));
|
|
47
43
|
tDateProfile.isTimeScale = Boolean(tDateProfile.slotDuration.milliseconds);
|
|
48
44
|
let largeUnit = null;
|
|
49
45
|
if (!tDateProfile.isTimeScale) {
|
|
50
|
-
const slotUnit =
|
|
46
|
+
const slotUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit;
|
|
51
47
|
if (/year|month|week/.test(slotUnit)) {
|
|
52
48
|
largeUnit = slotUnit;
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
tDateProfile.largeUnit = largeUnit;
|
|
56
52
|
tDateProfile.emphasizeWeeks =
|
|
57
|
-
|
|
53
|
+
asCleanDays(tDateProfile.slotDuration) === 1 &&
|
|
58
54
|
currentRangeAs('weeks', dateProfile, dateEnv) >= 2 &&
|
|
59
55
|
!allOptions.businessHours;
|
|
60
56
|
/*
|
|
@@ -68,8 +64,8 @@ function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileG
|
|
|
68
64
|
let snapDuration;
|
|
69
65
|
let snapsPerSlot;
|
|
70
66
|
if (rawSnapDuration) {
|
|
71
|
-
snapDuration =
|
|
72
|
-
snapsPerSlot =
|
|
67
|
+
snapDuration = createDuration(rawSnapDuration);
|
|
68
|
+
snapsPerSlot = wholeDivideDurations(tDateProfile.slotDuration, snapDuration);
|
|
73
69
|
// ^ TODO: warning if not whole?
|
|
74
70
|
}
|
|
75
71
|
if (snapsPerSlot == null) {
|
|
@@ -79,7 +75,7 @@ function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileG
|
|
|
79
75
|
tDateProfile.snapDuration = snapDuration;
|
|
80
76
|
tDateProfile.snapsPerSlot = snapsPerSlot;
|
|
81
77
|
// more...
|
|
82
|
-
let timeWindowMs =
|
|
78
|
+
let timeWindowMs = asRoughMs(dateProfile.slotMaxTime) - asRoughMs(dateProfile.slotMinTime);
|
|
83
79
|
// TODO: why not use normalizeRange!?
|
|
84
80
|
let normalizedStart = normalizeDate(dateProfile.renderRange.start, tDateProfile, dateEnv);
|
|
85
81
|
let normalizedEnd = normalizeDate(dateProfile.renderRange.end, tDateProfile, dateEnv);
|
|
@@ -87,7 +83,7 @@ function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileG
|
|
|
87
83
|
// TODO: View should be responsible.
|
|
88
84
|
if (tDateProfile.isTimeScale) {
|
|
89
85
|
normalizedStart = dateEnv.add(normalizedStart, dateProfile.slotMinTime);
|
|
90
|
-
normalizedEnd = dateEnv.add(
|
|
86
|
+
normalizedEnd = dateEnv.add(addDays(normalizedEnd, -1), dateProfile.slotMaxTime);
|
|
91
87
|
}
|
|
92
88
|
tDateProfile.timeWindowMs = timeWindowMs;
|
|
93
89
|
tDateProfile.normalizedRange = { start: normalizedStart, end: normalizedEnd };
|
|
@@ -125,7 +121,7 @@ function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileG
|
|
|
125
121
|
// more...
|
|
126
122
|
tDateProfile.isWeekStarts = buildIsWeekStarts(tDateProfile, dateEnv);
|
|
127
123
|
tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv);
|
|
128
|
-
tDateProfile.slotsPerLabel =
|
|
124
|
+
tDateProfile.slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
|
|
129
125
|
return tDateProfile;
|
|
130
126
|
}
|
|
131
127
|
/*
|
|
@@ -134,7 +130,7 @@ snaps to appropriate unit
|
|
|
134
130
|
function normalizeDate(date, tDateProfile, dateEnv) {
|
|
135
131
|
let normalDate = date;
|
|
136
132
|
if (!tDateProfile.isTimeScale) {
|
|
137
|
-
normalDate =
|
|
133
|
+
normalDate = startOfDay(normalDate);
|
|
138
134
|
if (tDateProfile.largeUnit) {
|
|
139
135
|
normalDate = dateEnv.startOf(normalDate, tDateProfile.largeUnit);
|
|
140
136
|
}
|
|
@@ -146,7 +142,7 @@ snaps to appropriate unit
|
|
|
146
142
|
*/
|
|
147
143
|
function normalizeRange(range, tDateProfile, dateEnv) {
|
|
148
144
|
if (!tDateProfile.isTimeScale) {
|
|
149
|
-
range =
|
|
145
|
+
range = computeVisibleDayRange(range);
|
|
150
146
|
if (tDateProfile.largeUnit) {
|
|
151
147
|
let dayRange = range; // preserve original result
|
|
152
148
|
range = {
|
|
@@ -171,9 +167,9 @@ function isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator) {
|
|
|
171
167
|
}
|
|
172
168
|
if (tDateProfile.isTimeScale) {
|
|
173
169
|
// determine if the time is within slotMinTime/slotMaxTime, which may have wacky values
|
|
174
|
-
let day =
|
|
170
|
+
let day = startOfDay(date);
|
|
175
171
|
let timeMs = date.valueOf() - day.valueOf();
|
|
176
|
-
let ms = timeMs -
|
|
172
|
+
let ms = timeMs - asRoughMs(dateProfile.slotMinTime); // milliseconds since slotMinTime
|
|
177
173
|
ms = ((ms % 86400000) + 86400000) % 86400000; // make negative values wrap to 24hr clock
|
|
178
174
|
return ms < tDateProfile.timeWindowMs; // before the slotMaxTime?
|
|
179
175
|
}
|
|
@@ -184,7 +180,7 @@ function validateLabelAndSlot(tDateProfile, dateProfile, dateEnv) {
|
|
|
184
180
|
// make sure labelInterval doesn't exceed the max number of cells
|
|
185
181
|
if (tDateProfile.labelInterval) {
|
|
186
182
|
const labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.labelInterval);
|
|
187
|
-
if (labelCnt >
|
|
183
|
+
if (labelCnt > config.MAX_TIMELINE_SLOTS) {
|
|
188
184
|
console.warn('slotLabelInterval results in too many cells');
|
|
189
185
|
tDateProfile.labelInterval = null;
|
|
190
186
|
}
|
|
@@ -192,14 +188,14 @@ function validateLabelAndSlot(tDateProfile, dateProfile, dateEnv) {
|
|
|
192
188
|
// make sure slotDuration doesn't exceed the maximum number of cells
|
|
193
189
|
if (tDateProfile.slotDuration) {
|
|
194
190
|
const slotCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.slotDuration);
|
|
195
|
-
if (slotCnt >
|
|
191
|
+
if (slotCnt > config.MAX_TIMELINE_SLOTS) {
|
|
196
192
|
console.warn('slotDuration results in too many cells');
|
|
197
193
|
tDateProfile.slotDuration = null;
|
|
198
194
|
}
|
|
199
195
|
}
|
|
200
196
|
// make sure labelInterval is a multiple of slotDuration
|
|
201
197
|
if (tDateProfile.labelInterval && tDateProfile.slotDuration) {
|
|
202
|
-
const slotsPerLabel =
|
|
198
|
+
const slotsPerLabel = wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
|
|
203
199
|
if (slotsPerLabel === null || slotsPerLabel < 1) {
|
|
204
200
|
console.warn('slotLabelInterval must be a multiple of slotDuration');
|
|
205
201
|
tDateProfile.slotDuration = null;
|
|
@@ -215,8 +211,8 @@ function ensureLabelInterval(tDateProfile, dateProfile, dateEnv) {
|
|
|
215
211
|
let input;
|
|
216
212
|
if (tDateProfile.slotDuration) {
|
|
217
213
|
for (input of STOCK_SUB_DURATIONS) {
|
|
218
|
-
const tryLabelInterval =
|
|
219
|
-
const slotsPerLabel =
|
|
214
|
+
const tryLabelInterval = createDuration(input);
|
|
215
|
+
const slotsPerLabel = wholeDivideDurations(tryLabelInterval, tDateProfile.slotDuration);
|
|
220
216
|
if (slotsPerLabel !== null && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
|
|
221
217
|
labelInterval = tryLabelInterval;
|
|
222
218
|
break;
|
|
@@ -231,7 +227,7 @@ function ensureLabelInterval(tDateProfile, dateProfile, dateEnv) {
|
|
|
231
227
|
}
|
|
232
228
|
else {
|
|
233
229
|
for (input of STOCK_SUB_DURATIONS) {
|
|
234
|
-
labelInterval =
|
|
230
|
+
labelInterval = createDuration(input);
|
|
235
231
|
const labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, labelInterval);
|
|
236
232
|
if (labelCnt >= MIN_AUTO_LABELS) {
|
|
237
233
|
break;
|
|
@@ -250,8 +246,8 @@ function ensureSlotDuration(tDateProfile, dateProfile, dateEnv) {
|
|
|
250
246
|
// compute based off the label interval
|
|
251
247
|
// find the largest slot duration that is different from labelInterval, but still acceptable
|
|
252
248
|
for (let input of STOCK_SUB_DURATIONS) {
|
|
253
|
-
const trySlotDuration =
|
|
254
|
-
const slotsPerLabel =
|
|
249
|
+
const trySlotDuration = createDuration(input);
|
|
250
|
+
const slotsPerLabel = wholeDivideDurations(labelInterval, trySlotDuration);
|
|
255
251
|
if (slotsPerLabel !== null && slotsPerLabel > 1 && slotsPerLabel <= MAX_AUTO_SLOTS_PER_LABEL) {
|
|
256
252
|
slotDuration = trySlotDuration;
|
|
257
253
|
break;
|
|
@@ -276,7 +272,7 @@ function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions) {
|
|
|
276
272
|
let format1;
|
|
277
273
|
let format2;
|
|
278
274
|
const { labelInterval } = tDateProfile;
|
|
279
|
-
let unit =
|
|
275
|
+
let unit = greatestDurationDenominator(labelInterval).unit;
|
|
280
276
|
const weekNumbersVisible = allOptions.weekNumbers;
|
|
281
277
|
let format0 = (format1 = (format2 = null));
|
|
282
278
|
// NOTE: weekNumber computation function wont work
|
|
@@ -327,12 +323,12 @@ function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions) {
|
|
|
327
323
|
break;
|
|
328
324
|
case 'minute':
|
|
329
325
|
// sufficiently large number of different minute cells?
|
|
330
|
-
if ((
|
|
326
|
+
if ((asRoughMinutes(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
|
|
331
327
|
format0 = {
|
|
332
328
|
hour: 'numeric',
|
|
333
329
|
meridiem: 'short',
|
|
334
330
|
};
|
|
335
|
-
format1 = (params) => (':' +
|
|
331
|
+
format1 = (params) => (':' + padStart(params.date.minute, 2) // ':30'
|
|
336
332
|
);
|
|
337
333
|
}
|
|
338
334
|
else {
|
|
@@ -345,9 +341,9 @@ function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions) {
|
|
|
345
341
|
break;
|
|
346
342
|
case 'second':
|
|
347
343
|
// sufficiently large number of different second cells?
|
|
348
|
-
if ((
|
|
344
|
+
if ((asRoughSeconds(labelInterval) / 60) >= MAX_AUTO_SLOTS_PER_LABEL) {
|
|
349
345
|
format0 = { hour: 'numeric', minute: '2-digit', meridiem: 'lowercase' }; // '8:30 PM'
|
|
350
|
-
format1 = (params) => (':' +
|
|
346
|
+
format1 = (params) => (':' + padStart(params.date.second, 2) // ':30'
|
|
351
347
|
);
|
|
352
348
|
}
|
|
353
349
|
else {
|
|
@@ -356,7 +352,7 @@ function computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions) {
|
|
|
356
352
|
break;
|
|
357
353
|
case 'millisecond':
|
|
358
354
|
format0 = { hour: 'numeric', minute: '2-digit', second: '2-digit', meridiem: 'lowercase' }; // '8:30:45 PM'
|
|
359
|
-
format1 = (params) => ('.' +
|
|
355
|
+
format1 = (params) => ('.' + padStart(params.millisecond, 3));
|
|
360
356
|
break;
|
|
361
357
|
}
|
|
362
358
|
return [].concat(format0 || [], format1 || [], format2 || []);
|
|
@@ -377,7 +373,7 @@ function currentRangeAs(unit, dateProfile, dateEnv) {
|
|
|
377
373
|
res = dateEnv.diffWholeMonths(range.start, range.end);
|
|
378
374
|
}
|
|
379
375
|
else if (unit === 'days') {
|
|
380
|
-
res =
|
|
376
|
+
res = diffWholeDays(range.start, range.end);
|
|
381
377
|
}
|
|
382
378
|
return res || 0;
|
|
383
379
|
}
|
|
@@ -397,7 +393,7 @@ function buildCellRows(tDateProfile, dateEnv) {
|
|
|
397
393
|
let slotDates = tDateProfile.slotDates;
|
|
398
394
|
let formats = tDateProfile.headerFormats;
|
|
399
395
|
let cellRows = formats.map(() => []); // indexed by row,col
|
|
400
|
-
let slotAsDays =
|
|
396
|
+
let slotAsDays = asCleanDays(tDateProfile.slotDuration);
|
|
401
397
|
let guessedSlotUnit = slotAsDays === 7 ? 'week' :
|
|
402
398
|
slotAsDays === 1 ? 'day' :
|
|
403
399
|
null;
|
|
@@ -425,7 +421,7 @@ function buildCellRows(tDateProfile, dateEnv) {
|
|
|
425
421
|
}
|
|
426
422
|
}
|
|
427
423
|
else if (!leadingCell ||
|
|
428
|
-
|
|
424
|
+
isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval))) {
|
|
429
425
|
let text = dateEnv.format(date, format);
|
|
430
426
|
newCell = buildCellObject(date, text, rowUnit);
|
|
431
427
|
}
|
|
@@ -444,11 +440,11 @@ function buildCellObject(date, text, rowUnit) {
|
|
|
444
440
|
return { date, text, rowUnit, colspan: 1, isWeekStart: false };
|
|
445
441
|
}
|
|
446
442
|
|
|
447
|
-
class TimelineHeaderTh extends
|
|
443
|
+
class TimelineHeaderTh extends BaseComponent {
|
|
448
444
|
constructor() {
|
|
449
445
|
super(...arguments);
|
|
450
|
-
this.refineRenderProps =
|
|
451
|
-
this.buildCellNavLinkAttrs =
|
|
446
|
+
this.refineRenderProps = memoizeObjArg(refineRenderProps);
|
|
447
|
+
this.buildCellNavLinkAttrs = memoize(buildCellNavLinkAttrs);
|
|
452
448
|
}
|
|
453
449
|
render() {
|
|
454
450
|
let { props, context } = this;
|
|
@@ -457,7 +453,7 @@ class TimelineHeaderTh extends internal_cjs.BaseComponent {
|
|
|
457
453
|
// the cell.rowUnit is f'd
|
|
458
454
|
// giving 'month' for a 3-day view
|
|
459
455
|
// workaround: to infer day, do NOT time
|
|
460
|
-
let dateMeta =
|
|
456
|
+
let dateMeta = getDateMeta(cell.date, props.todayRange, props.nowDate, dateProfile);
|
|
461
457
|
let renderProps = this.refineRenderProps({
|
|
462
458
|
level: props.rowLevel,
|
|
463
459
|
dateMarker: cell.date,
|
|
@@ -465,22 +461,22 @@ class TimelineHeaderTh extends internal_cjs.BaseComponent {
|
|
|
465
461
|
dateEnv: context.dateEnv,
|
|
466
462
|
viewApi: context.viewApi,
|
|
467
463
|
});
|
|
468
|
-
return (
|
|
464
|
+
return (createElement(ContentContainer, { elTag: "th", elClasses: [
|
|
469
465
|
'fc-timeline-slot',
|
|
470
466
|
'fc-timeline-slot-label',
|
|
471
467
|
cell.isWeekStart && 'fc-timeline-slot-em',
|
|
472
468
|
...( // TODO: so slot classnames for week/month/bigger. see note above about rowUnit
|
|
473
469
|
cell.rowUnit === 'time' ?
|
|
474
|
-
|
|
475
|
-
|
|
470
|
+
getSlotClassNames(dateMeta, context.theme) :
|
|
471
|
+
getDayClassNames(dateMeta, context.theme)),
|
|
476
472
|
], elAttrs: {
|
|
477
473
|
colSpan: cell.colspan,
|
|
478
474
|
'data-date': dateEnv.formatIso(cell.date, {
|
|
479
475
|
omitTime: !tDateProfile.isTimeScale,
|
|
480
476
|
omitTimeZoneOffset: true,
|
|
481
477
|
}),
|
|
482
|
-
}, renderProps: renderProps, generatorName: "slotLabelContent", generator: options.slotLabelContent || renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => (
|
|
483
|
-
|
|
478
|
+
}, renderProps: renderProps, generatorName: "slotLabelContent", generator: options.slotLabelContent || renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => (createElement("div", { className: "fc-timeline-slot-frame", style: { height: props.rowInnerHeight } },
|
|
479
|
+
createElement(InnerContent, { elTag: "a", elClasses: [
|
|
484
480
|
'fc-timeline-slot-cushion',
|
|
485
481
|
'fc-scrollgrid-sync-inner',
|
|
486
482
|
props.isSticky && 'fc-sticky',
|
|
@@ -489,7 +485,7 @@ class TimelineHeaderTh extends internal_cjs.BaseComponent {
|
|
|
489
485
|
}
|
|
490
486
|
function buildCellNavLinkAttrs(context, cellDate, rowUnit) {
|
|
491
487
|
return (rowUnit && rowUnit !== 'time')
|
|
492
|
-
?
|
|
488
|
+
? buildNavLinkAttrs(context, cellDate, rowUnit)
|
|
493
489
|
: {};
|
|
494
490
|
}
|
|
495
491
|
function renderInnerContent(renderProps) {
|
|
@@ -504,11 +500,11 @@ function refineRenderProps(input) {
|
|
|
504
500
|
};
|
|
505
501
|
}
|
|
506
502
|
|
|
507
|
-
class TimelineHeaderRows extends
|
|
503
|
+
class TimelineHeaderRows extends BaseComponent {
|
|
508
504
|
render() {
|
|
509
505
|
let { dateProfile, tDateProfile, rowInnerHeights, todayRange, nowDate } = this.props;
|
|
510
506
|
let { cellRows } = tDateProfile;
|
|
511
|
-
return (
|
|
507
|
+
return (createElement(Fragment, null, cellRows.map((rowCells, rowLevel) => {
|
|
512
508
|
let isLast = rowLevel === cellRows.length - 1;
|
|
513
509
|
let isChrono = tDateProfile.isTimeScale && isLast; // the final row, with times?
|
|
514
510
|
let classNames = [
|
|
@@ -516,7 +512,7 @@ class TimelineHeaderRows extends internal_cjs.BaseComponent {
|
|
|
516
512
|
isChrono ? 'fc-timeline-header-row-chrono' : '',
|
|
517
513
|
];
|
|
518
514
|
return ( // eslint-disable-next-line react/no-array-index-key
|
|
519
|
-
|
|
515
|
+
createElement("tr", { key: rowLevel, className: classNames.join(' ') }, rowCells.map((cell) => (createElement(TimelineHeaderTh, { key: cell.date.toISOString(), cell: cell, rowLevel: rowLevel, dateProfile: dateProfile, tDateProfile: tDateProfile, todayRange: todayRange, nowDate: nowDate, rowInnerHeight: rowInnerHeights && rowInnerHeights[rowLevel], isSticky: !isLast })))));
|
|
520
516
|
})));
|
|
521
517
|
}
|
|
522
518
|
}
|
|
@@ -529,15 +525,15 @@ class TimelineCoords {
|
|
|
529
525
|
this.tDateProfile = tDateProfile;
|
|
530
526
|
this.dateEnv = dateEnv;
|
|
531
527
|
this.isRtl = isRtl;
|
|
532
|
-
this.outerCoordCache = new
|
|
528
|
+
this.outerCoordCache = new PositionCache(slatRootEl, slatEls, true, // isHorizontal
|
|
533
529
|
false);
|
|
534
530
|
// for the inner divs within the slats
|
|
535
531
|
// used for event rendering and scrollTime, to disregard slat border
|
|
536
|
-
this.innerCoordCache = new
|
|
532
|
+
this.innerCoordCache = new PositionCache(slatRootEl, findDirectChildren(slatEls, 'div'), true, // isHorizontal
|
|
537
533
|
false);
|
|
538
534
|
}
|
|
539
535
|
isDateInRange(date) {
|
|
540
|
-
return
|
|
536
|
+
return rangeContainsMarker(this.dateProfile.currentRange, date);
|
|
541
537
|
}
|
|
542
538
|
// results range from negative width of area to 0
|
|
543
539
|
dateToCoord(date) {
|
|
@@ -567,7 +563,7 @@ class TimelineCoords {
|
|
|
567
563
|
if (dateProfile) {
|
|
568
564
|
let date = dateEnv.add(dateProfile.activeRange.start, duration);
|
|
569
565
|
if (!tDateProfile.isTimeScale) {
|
|
570
|
-
date =
|
|
566
|
+
date = startOfDay(date);
|
|
571
567
|
}
|
|
572
568
|
coord = this.dateToCoord(date);
|
|
573
569
|
// hack to overcome the left borders of non-first slat
|
|
@@ -599,7 +595,7 @@ function computeDateSnapCoverage(date, tDateProfile, dateEnv) {
|
|
|
599
595
|
}
|
|
600
596
|
let snapDiffInt = Math.floor(snapDiff);
|
|
601
597
|
let snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
|
|
602
|
-
if (
|
|
598
|
+
if (isInt(snapCoverage)) { // not an in-between value
|
|
603
599
|
snapCoverage += snapDiff - snapDiffInt; // add the remainder
|
|
604
600
|
}
|
|
605
601
|
else {
|
|
@@ -628,28 +624,28 @@ function coordsToCss(hcoords, isRtl) {
|
|
|
628
624
|
return { left: hcoords.start, right: -hcoords.end };
|
|
629
625
|
}
|
|
630
626
|
|
|
631
|
-
class TimelineHeader extends
|
|
627
|
+
class TimelineHeader extends BaseComponent {
|
|
632
628
|
constructor() {
|
|
633
629
|
super(...arguments);
|
|
634
|
-
this.rootElRef =
|
|
630
|
+
this.rootElRef = createRef();
|
|
635
631
|
}
|
|
636
632
|
render() {
|
|
637
633
|
let { props, context } = this;
|
|
638
634
|
// TODO: very repetitive
|
|
639
635
|
// TODO: make part of tDateProfile?
|
|
640
|
-
let timerUnit =
|
|
636
|
+
let timerUnit = greatestDurationDenominator(props.tDateProfile.slotDuration).unit;
|
|
641
637
|
// WORKAROUND: make ignore slatCoords when out of sync with dateProfile
|
|
642
638
|
let slatCoords = props.slatCoords && props.slatCoords.dateProfile === props.dateProfile ? props.slatCoords : null;
|
|
643
|
-
return (
|
|
644
|
-
|
|
639
|
+
return (createElement(NowTimer, { unit: timerUnit }, (nowDate, todayRange) => (createElement("div", { className: "fc-timeline-header", ref: this.rootElRef },
|
|
640
|
+
createElement("table", { "aria-hidden": true, className: "fc-scrollgrid-sync-table", style: { minWidth: props.tableMinWidth, width: props.clientWidth } },
|
|
645
641
|
props.tableColGroupNode,
|
|
646
|
-
|
|
647
|
-
|
|
642
|
+
createElement("tbody", null,
|
|
643
|
+
createElement(TimelineHeaderRows, { dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, rowInnerHeights: props.rowInnerHeights }))),
|
|
648
644
|
context.options.nowIndicator && (
|
|
649
645
|
// need to have a container regardless of whether the current view has a visible now indicator
|
|
650
646
|
// because apparently removal of the element resets the scroll for some reasons (issue #5351).
|
|
651
647
|
// this issue doesn't happen for the timeline body however (
|
|
652
|
-
|
|
648
|
+
createElement("div", { className: "fc-timeline-now-indicator-container" }, (slatCoords && slatCoords.isDateInRange(nowDate)) && (createElement(NowIndicatorContainer, { elClasses: ['fc-timeline-now-indicator-arrow'], elStyle: coordToCss(slatCoords.dateToCoord(nowDate), context.isRtl), isAxis: true, date: nowDate }))))))));
|
|
653
649
|
}
|
|
654
650
|
componentDidMount() {
|
|
655
651
|
this.updateSize();
|
|
@@ -663,55 +659,55 @@ class TimelineHeader extends internal_cjs.BaseComponent {
|
|
|
663
659
|
}
|
|
664
660
|
}
|
|
665
661
|
computeMaxCushionWidth() {
|
|
666
|
-
return Math.max(...
|
|
662
|
+
return Math.max(...findElements(this.rootElRef.current, '.fc-timeline-header-row:last-child .fc-timeline-slot-cushion').map((el) => el.getBoundingClientRect().width));
|
|
667
663
|
}
|
|
668
664
|
}
|
|
669
665
|
|
|
670
|
-
class TimelineSlatCell extends
|
|
666
|
+
class TimelineSlatCell extends BaseComponent {
|
|
671
667
|
render() {
|
|
672
668
|
let { props, context } = this;
|
|
673
669
|
let { dateEnv, options, theme } = context;
|
|
674
670
|
let { date, tDateProfile, isEm } = props;
|
|
675
|
-
let dateMeta =
|
|
671
|
+
let dateMeta = getDateMeta(props.date, props.todayRange, props.nowDate, props.dateProfile);
|
|
676
672
|
let renderProps = Object.assign(Object.assign({ date: dateEnv.toDate(props.date) }, dateMeta), { view: context.viewApi });
|
|
677
|
-
return (
|
|
673
|
+
return (createElement(ContentContainer, { elTag: "td", elRef: props.elRef, elClasses: [
|
|
678
674
|
'fc-timeline-slot',
|
|
679
675
|
'fc-timeline-slot-lane',
|
|
680
676
|
isEm && 'fc-timeline-slot-em',
|
|
681
|
-
tDateProfile.isTimeScale ? (
|
|
677
|
+
tDateProfile.isTimeScale ? (isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, props.date, tDateProfile.labelInterval)) ?
|
|
682
678
|
'fc-timeline-slot-major' :
|
|
683
679
|
'fc-timeline-slot-minor') : '',
|
|
684
680
|
...(props.isDay ?
|
|
685
|
-
|
|
686
|
-
|
|
681
|
+
getDayClassNames(dateMeta, theme) :
|
|
682
|
+
getSlotClassNames(dateMeta, theme)),
|
|
687
683
|
], elAttrs: {
|
|
688
684
|
'data-date': dateEnv.formatIso(date, {
|
|
689
685
|
omitTimeZoneOffset: true,
|
|
690
686
|
omitTime: !tDateProfile.isTimeScale,
|
|
691
687
|
}),
|
|
692
|
-
}, renderProps: renderProps, generatorName: "slotLaneContent", generator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }, (InnerContent) => (
|
|
688
|
+
}, renderProps: renderProps, generatorName: "slotLaneContent", generator: options.slotLaneContent, classNameGenerator: options.slotLaneClassNames, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }, (InnerContent) => (createElement(InnerContent, { elTag: "div" }))));
|
|
693
689
|
}
|
|
694
690
|
}
|
|
695
691
|
|
|
696
|
-
class TimelineSlatsBody extends
|
|
692
|
+
class TimelineSlatsBody extends BaseComponent {
|
|
697
693
|
render() {
|
|
698
694
|
let { props } = this;
|
|
699
695
|
let { tDateProfile, cellElRefs } = props;
|
|
700
696
|
let { slotDates, isWeekStarts } = tDateProfile;
|
|
701
697
|
let isDay = !tDateProfile.isTimeScale && !tDateProfile.largeUnit;
|
|
702
|
-
return (
|
|
703
|
-
|
|
698
|
+
return (createElement("tbody", null,
|
|
699
|
+
createElement("tr", null, slotDates.map((slotDate, i) => {
|
|
704
700
|
let key = slotDate.toISOString();
|
|
705
|
-
return (
|
|
701
|
+
return (createElement(TimelineSlatCell, { key: key, elRef: cellElRefs.createRef(key), date: slotDate, dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isEm: isWeekStarts[i], isDay: isDay }));
|
|
706
702
|
}))));
|
|
707
703
|
}
|
|
708
704
|
}
|
|
709
705
|
|
|
710
|
-
class TimelineSlats extends
|
|
706
|
+
class TimelineSlats extends BaseComponent {
|
|
711
707
|
constructor() {
|
|
712
708
|
super(...arguments);
|
|
713
|
-
this.rootElRef =
|
|
714
|
-
this.cellElRefs = new
|
|
709
|
+
this.rootElRef = createRef();
|
|
710
|
+
this.cellElRefs = new RefMap();
|
|
715
711
|
this.handleScrollRequest = (request) => {
|
|
716
712
|
let { onScrollLeftRequest } = this.props;
|
|
717
713
|
let { coords } = this;
|
|
@@ -727,13 +723,13 @@ class TimelineSlats extends internal_cjs.BaseComponent {
|
|
|
727
723
|
}
|
|
728
724
|
render() {
|
|
729
725
|
let { props, context } = this;
|
|
730
|
-
return (
|
|
731
|
-
|
|
726
|
+
return (createElement("div", { className: "fc-timeline-slots", ref: this.rootElRef },
|
|
727
|
+
createElement("table", { "aria-hidden": true, className: context.theme.getClass('table'), style: {
|
|
732
728
|
minWidth: props.tableMinWidth,
|
|
733
729
|
width: props.clientWidth,
|
|
734
730
|
} },
|
|
735
731
|
props.tableColGroupNode,
|
|
736
|
-
|
|
732
|
+
createElement(TimelineSlatsBody, { cellElRefs: this.cellElRefs, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange }))));
|
|
737
733
|
}
|
|
738
734
|
componentDidMount() {
|
|
739
735
|
this.updateSizing();
|
|
@@ -777,7 +773,7 @@ class TimelineSlats extends internal_cjs.BaseComponent {
|
|
|
777
773
|
(outerCoordCache.rights[slatIndex] - leftPosition) / slatWidth :
|
|
778
774
|
(leftPosition - outerCoordCache.lefts[slatIndex]) / slatWidth;
|
|
779
775
|
let localSnapIndex = Math.floor(partial * tDateProfile.snapsPerSlot);
|
|
780
|
-
let start = dateEnv.add(tDateProfile.slotDates[slatIndex],
|
|
776
|
+
let start = dateEnv.add(tDateProfile.slotDates[slatIndex], multiplyDuration(tDateProfile.snapDuration, localSnapIndex));
|
|
781
777
|
let end = dateEnv.add(start, tDateProfile.snapDuration);
|
|
782
778
|
return {
|
|
783
779
|
dateSpan: {
|
|
@@ -840,7 +836,7 @@ strictOrder, maxStackCnt) {
|
|
|
840
836
|
});
|
|
841
837
|
}
|
|
842
838
|
}
|
|
843
|
-
let hierarchy = new
|
|
839
|
+
let hierarchy = new SegHierarchy();
|
|
844
840
|
if (strictOrder != null) {
|
|
845
841
|
hierarchy.strictOrder = strictOrder;
|
|
846
842
|
}
|
|
@@ -853,14 +849,14 @@ strictOrder, maxStackCnt) {
|
|
|
853
849
|
hcoords: entry.span,
|
|
854
850
|
top: null,
|
|
855
851
|
}));
|
|
856
|
-
let hiddenGroups =
|
|
852
|
+
let hiddenGroups = groupIntersectingEntries(hiddenEntries);
|
|
857
853
|
let moreLinkInputs = [];
|
|
858
854
|
let moreLinkCrudePlacements = [];
|
|
859
855
|
const extractSeg = (entry) => segs[entry.index];
|
|
860
856
|
for (let i = 0; i < hiddenGroups.length; i += 1) {
|
|
861
857
|
let hiddenGroup = hiddenGroups[i];
|
|
862
858
|
let sortedSegs = hiddenGroup.entries.map(extractSeg);
|
|
863
|
-
let height = moreLinkHeights[
|
|
859
|
+
let height = moreLinkHeights[buildIsoString(computeEarliestSegStart(sortedSegs))]; // not optimal :(
|
|
864
860
|
if (height != null) {
|
|
865
861
|
// NOTE: the hiddenGroup's spanStart/spanEnd are already computed by rangeToCoords. computed during input.
|
|
866
862
|
moreLinkInputs.push({
|
|
@@ -900,11 +896,11 @@ strictOrder, maxStackCnt) {
|
|
|
900
896
|
];
|
|
901
897
|
}
|
|
902
898
|
|
|
903
|
-
class TimelineLaneBg extends
|
|
899
|
+
class TimelineLaneBg extends BaseComponent {
|
|
904
900
|
render() {
|
|
905
901
|
let { props } = this;
|
|
906
902
|
let highlightSeg = [].concat(props.eventResizeSegs, props.dateSelectionSegs);
|
|
907
|
-
return props.timelineCoords && (
|
|
903
|
+
return props.timelineCoords && (createElement("div", { className: "fc-timeline-bg" },
|
|
908
904
|
this.renderSegs(props.businessHourSegs || [], props.timelineCoords, 'non-business'),
|
|
909
905
|
this.renderSegs(props.bgEventSegs || [], props.timelineCoords, 'bg-event'),
|
|
910
906
|
this.renderSegs(highlightSeg, props.timelineCoords, 'highlight')));
|
|
@@ -916,15 +912,15 @@ class TimelineLaneBg extends internal_cjs.BaseComponent {
|
|
|
916
912
|
let children = segs.map((seg, i) => {
|
|
917
913
|
let hcoords = segHCoords[i];
|
|
918
914
|
let hStyle = coordsToCss(hcoords, isRtl);
|
|
919
|
-
return (
|
|
920
|
-
|
|
921
|
-
|
|
915
|
+
return (createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-timeline-bg-harness", style: hStyle }, fillType === 'bg-event' ?
|
|
916
|
+
createElement(BgEvent, Object.assign({ seg: seg }, getSegMeta(seg, todayRange, nowDate))) :
|
|
917
|
+
renderFill(fillType)));
|
|
922
918
|
});
|
|
923
|
-
return
|
|
919
|
+
return createElement(Fragment, null, children);
|
|
924
920
|
}
|
|
925
921
|
}
|
|
926
922
|
|
|
927
|
-
class TimelineLaneSlicer extends
|
|
923
|
+
class TimelineLaneSlicer extends Slicer {
|
|
928
924
|
sliceRange(origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) {
|
|
929
925
|
let normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
|
|
930
926
|
let segs = [];
|
|
@@ -932,7 +928,7 @@ class TimelineLaneSlicer extends internal_cjs.Slicer {
|
|
|
932
928
|
if (computeDateSnapCoverage(normalRange.start, tDateProfile, dateEnv)
|
|
933
929
|
< computeDateSnapCoverage(normalRange.end, tDateProfile, dateEnv)) {
|
|
934
930
|
// intersect the footprint's range with the grid's range
|
|
935
|
-
let slicedRange =
|
|
931
|
+
let slicedRange = intersectRanges(normalRange, tDateProfile.normalizedRange);
|
|
936
932
|
if (slicedRange) {
|
|
937
933
|
segs.push({
|
|
938
934
|
start: slicedRange.start,
|
|
@@ -940,7 +936,7 @@ class TimelineLaneSlicer extends internal_cjs.Slicer {
|
|
|
940
936
|
isStart: slicedRange.start.valueOf() === normalRange.start.valueOf()
|
|
941
937
|
&& isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
|
|
942
938
|
isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf()
|
|
943
|
-
&& isValidDate(
|
|
939
|
+
&& isValidDate(addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator),
|
|
944
940
|
});
|
|
945
941
|
}
|
|
946
942
|
}
|
|
@@ -948,20 +944,20 @@ class TimelineLaneSlicer extends internal_cjs.Slicer {
|
|
|
948
944
|
}
|
|
949
945
|
}
|
|
950
946
|
|
|
951
|
-
const DEFAULT_TIME_FORMAT =
|
|
947
|
+
const DEFAULT_TIME_FORMAT = createFormatter({
|
|
952
948
|
hour: 'numeric',
|
|
953
949
|
minute: '2-digit',
|
|
954
950
|
omitZeroMinute: true,
|
|
955
951
|
meridiem: 'narrow',
|
|
956
952
|
});
|
|
957
|
-
class TimelineEvent extends
|
|
953
|
+
class TimelineEvent extends BaseComponent {
|
|
958
954
|
render() {
|
|
959
955
|
let { props } = this;
|
|
960
|
-
return (
|
|
956
|
+
return (createElement(StandardEvent, Object.assign({}, props, { elClasses: ['fc-timeline-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale })));
|
|
961
957
|
}
|
|
962
958
|
}
|
|
963
959
|
|
|
964
|
-
class TimelineLaneMoreLink extends
|
|
960
|
+
class TimelineLaneMoreLink extends BaseComponent {
|
|
965
961
|
render() {
|
|
966
962
|
let { props, context } = this;
|
|
967
963
|
let { hiddenSegs, placement, resourceId } = props;
|
|
@@ -969,22 +965,22 @@ class TimelineLaneMoreLink extends internal_cjs.BaseComponent {
|
|
|
969
965
|
let isVisible = hcoords && top !== null;
|
|
970
966
|
let hStyle = coordsToCss(hcoords, context.isRtl);
|
|
971
967
|
let extraDateSpan = resourceId ? { resourceId } : {};
|
|
972
|
-
return (
|
|
968
|
+
return (createElement(MoreLinkContainer, { elRef: props.elRef, elClasses: ['fc-timeline-more-link'], elStyle: Object.assign({ visibility: isVisible ? '' : 'hidden', top: top || 0 }, hStyle), allDayDate: null, moreCnt: hiddenSegs.length, allSegs: hiddenSegs, hiddenSegs: hiddenSegs, dateProfile: props.dateProfile, todayRange: props.todayRange, extraDateSpan: extraDateSpan, popoverContent: () => (createElement(Fragment, null, hiddenSegs.map((seg) => {
|
|
973
969
|
let instanceId = seg.eventRange.instance.instanceId;
|
|
974
|
-
return (
|
|
975
|
-
|
|
976
|
-
}))) }, (InnerContent) => (
|
|
970
|
+
return (createElement("div", { key: instanceId, style: { visibility: props.isForcedInvisible[instanceId] ? 'hidden' : '' } },
|
|
971
|
+
createElement(TimelineEvent, Object.assign({ isTimeScale: props.isTimeScale, seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection }, getSegMeta(seg, props.todayRange, props.nowDate)))));
|
|
972
|
+
}))) }, (InnerContent) => (createElement(InnerContent, { elTag: "div", elClasses: ['fc-timeline-more-link-inner', 'fc-sticky'] }))));
|
|
977
973
|
}
|
|
978
974
|
}
|
|
979
975
|
|
|
980
|
-
class TimelineLane extends
|
|
976
|
+
class TimelineLane extends BaseComponent {
|
|
981
977
|
constructor() {
|
|
982
978
|
super(...arguments);
|
|
983
979
|
this.slicer = new TimelineLaneSlicer();
|
|
984
|
-
this.sortEventSegs =
|
|
985
|
-
this.harnessElRefs = new
|
|
986
|
-
this.moreElRefs = new
|
|
987
|
-
this.innerElRef =
|
|
980
|
+
this.sortEventSegs = memoize(sortEventSegs);
|
|
981
|
+
this.harnessElRefs = new RefMap();
|
|
982
|
+
this.moreElRefs = new RefMap();
|
|
983
|
+
this.innerElRef = createRef();
|
|
988
984
|
// TODO: memoize event positioning
|
|
989
985
|
this.state = {
|
|
990
986
|
eventInstanceHeights: {},
|
|
@@ -1012,9 +1008,9 @@ class TimelineLane extends internal_cjs.BaseComponent {
|
|
|
1012
1008
|
(slicedProps.eventDrag ? slicedProps.eventDrag.affectedInstances : null) ||
|
|
1013
1009
|
(slicedProps.eventResize ? slicedProps.eventResize.affectedInstances : null) ||
|
|
1014
1010
|
{};
|
|
1015
|
-
return (
|
|
1016
|
-
|
|
1017
|
-
|
|
1011
|
+
return (createElement(Fragment, null,
|
|
1012
|
+
createElement(TimelineLaneBg, { businessHourSegs: slicedProps.businessHourSegs, bgEventSegs: slicedProps.bgEventSegs, timelineCoords: props.timelineCoords, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : [] /* bad new empty array? */, dateSelectionSegs: slicedProps.dateSelectionSegs, nowDate: props.nowDate, todayRange: props.todayRange }),
|
|
1013
|
+
createElement("div", { className: "fc-timeline-events fc-scrollgrid-sync-inner", ref: this.innerElRef, style: { height: fgHeight } },
|
|
1018
1014
|
this.renderFgSegs(fgPlacements, isForcedInvisible, false, false, false),
|
|
1019
1015
|
this.renderFgSegs(buildMirrorPlacements(mirrorSegs, props.timelineCoords, fgPlacements), {}, Boolean(slicedProps.eventDrag), Boolean(slicedProps.eventResize), false))));
|
|
1020
1016
|
}
|
|
@@ -1042,8 +1038,8 @@ class TimelineLane extends internal_cjs.BaseComponent {
|
|
|
1042
1038
|
}
|
|
1043
1039
|
if (timelineCoords) {
|
|
1044
1040
|
this.setState({
|
|
1045
|
-
eventInstanceHeights:
|
|
1046
|
-
moreLinkHeights:
|
|
1041
|
+
eventInstanceHeights: mapHash(this.harnessElRefs.currentMap, (harnessEl) => (Math.round(harnessEl.getBoundingClientRect().height))),
|
|
1042
|
+
moreLinkHeights: mapHash(this.moreElRefs.currentMap, (moreEl) => (Math.round(moreEl.getBoundingClientRect().height))),
|
|
1047
1043
|
}, () => {
|
|
1048
1044
|
if (props.onHeightChange) {
|
|
1049
1045
|
props.onHeightChange(innerEl, true);
|
|
@@ -1058,23 +1054,23 @@ class TimelineLane extends internal_cjs.BaseComponent {
|
|
|
1058
1054
|
renderFgSegs(segPlacements, isForcedInvisible, isDragging, isResizing, isDateSelecting) {
|
|
1059
1055
|
let { harnessElRefs, moreElRefs, props, context } = this;
|
|
1060
1056
|
let isMirror = isDragging || isResizing || isDateSelecting;
|
|
1061
|
-
return (
|
|
1057
|
+
return (createElement(Fragment, null, segPlacements.map((segPlacement) => {
|
|
1062
1058
|
let { seg, hcoords, top } = segPlacement;
|
|
1063
1059
|
if (Array.isArray(seg)) { // a more-link
|
|
1064
|
-
let isoStr =
|
|
1065
|
-
return (
|
|
1060
|
+
let isoStr = buildIsoString(computeEarliestSegStart(seg));
|
|
1061
|
+
return (createElement(TimelineLaneMoreLink, { key: 'm:' + isoStr /* "m" for "more" */, elRef: moreElRefs.createRef(isoStr), hiddenSegs: seg, placement: segPlacement, dateProfile: props.dateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isTimeScale: props.tDateProfile.isTimeScale, eventSelection: props.eventSelection, resourceId: props.resourceId, isForcedInvisible: isForcedInvisible }));
|
|
1066
1062
|
}
|
|
1067
1063
|
let instanceId = seg.eventRange.instance.instanceId;
|
|
1068
1064
|
let isVisible = isMirror || Boolean(!isForcedInvisible[instanceId] && hcoords && top !== null);
|
|
1069
1065
|
let hStyle = coordsToCss(hcoords, context.isRtl);
|
|
1070
|
-
return (
|
|
1071
|
-
|
|
1066
|
+
return (createElement("div", { key: 'e:' + instanceId /* "e" for "event" */, ref: isMirror ? null : harnessElRefs.createRef(instanceId), className: "fc-timeline-event-harness", style: Object.assign({ visibility: isVisible ? '' : 'hidden', top: top || 0 }, hStyle) },
|
|
1067
|
+
createElement(TimelineEvent, Object.assign({ isTimeScale: props.tDateProfile.isTimeScale, seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === props.eventSelection /* TODO: bad for mirror? */ }, getSegMeta(seg, props.todayRange, props.nowDate)))));
|
|
1072
1068
|
})));
|
|
1073
1069
|
}
|
|
1074
1070
|
}
|
|
1075
1071
|
TimelineLane.addStateEquality({
|
|
1076
|
-
eventInstanceHeights:
|
|
1077
|
-
moreLinkHeights:
|
|
1072
|
+
eventInstanceHeights: isPropsEqual,
|
|
1073
|
+
moreLinkHeights: isPropsEqual,
|
|
1078
1074
|
});
|
|
1079
1075
|
function buildMirrorPlacements(mirrorSegs, timelineCoords, fgPlacements) {
|
|
1080
1076
|
if (!mirrorSegs.length || !timelineCoords) {
|
|
@@ -1098,10 +1094,10 @@ function buildAbsoluteTopHash(placements) {
|
|
|
1098
1094
|
return topsByInstanceId;
|
|
1099
1095
|
}
|
|
1100
1096
|
|
|
1101
|
-
class TimelineGrid extends
|
|
1097
|
+
class TimelineGrid extends DateComponent {
|
|
1102
1098
|
constructor() {
|
|
1103
1099
|
super(...arguments);
|
|
1104
|
-
this.slatsRef =
|
|
1100
|
+
this.slatsRef = createRef();
|
|
1105
1101
|
this.state = {
|
|
1106
1102
|
coords: null,
|
|
1107
1103
|
};
|
|
@@ -1124,17 +1120,17 @@ class TimelineGrid extends internal_cjs.DateComponent {
|
|
|
1124
1120
|
let { props, state, context } = this;
|
|
1125
1121
|
let { options } = context;
|
|
1126
1122
|
let { dateProfile, tDateProfile } = props;
|
|
1127
|
-
let timerUnit =
|
|
1128
|
-
return (
|
|
1123
|
+
let timerUnit = greatestDurationDenominator(tDateProfile.slotDuration).unit;
|
|
1124
|
+
return (createElement("div", { className: "fc-timeline-body", ref: this.handeEl, style: {
|
|
1129
1125
|
minWidth: props.tableMinWidth,
|
|
1130
1126
|
height: props.clientHeight,
|
|
1131
1127
|
width: props.clientWidth,
|
|
1132
1128
|
} },
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
(options.nowIndicator && state.coords && state.coords.isDateInRange(nowDate)) && (
|
|
1137
|
-
|
|
1129
|
+
createElement(NowTimer, { unit: timerUnit }, (nowDate, todayRange) => (createElement(Fragment, null,
|
|
1130
|
+
createElement(TimelineSlats, { ref: this.slatsRef, dateProfile: dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, clientWidth: props.clientWidth, tableColGroupNode: props.tableColGroupNode, tableMinWidth: props.tableMinWidth, onCoords: this.handleCoords, onScrollLeftRequest: props.onScrollLeftRequest }),
|
|
1131
|
+
createElement(TimelineLane, { dateProfile: dateProfile, tDateProfile: props.tDateProfile, nowDate: nowDate, todayRange: todayRange, nextDayThreshold: options.nextDayThreshold, businessHours: props.businessHours, eventStore: props.eventStore, eventUiBases: props.eventUiBases, dateSelection: props.dateSelection, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, timelineCoords: state.coords, syncParentMinHeight: true }),
|
|
1132
|
+
(options.nowIndicator && state.coords && state.coords.isDateInRange(nowDate)) && (createElement("div", { className: "fc-timeline-now-indicator-container" },
|
|
1133
|
+
createElement(NowIndicatorContainer, { elClasses: ['fc-timeline-now-indicator-line'], elStyle: coordToCss(state.coords.dateToCoord(nowDate), context.isRtl), isAxis: false, date: nowDate }))))))));
|
|
1138
1134
|
}
|
|
1139
1135
|
// Hit System
|
|
1140
1136
|
// ------------------------------------------------------------------------------------------
|
|
@@ -1159,11 +1155,11 @@ class TimelineGrid extends internal_cjs.DateComponent {
|
|
|
1159
1155
|
}
|
|
1160
1156
|
}
|
|
1161
1157
|
|
|
1162
|
-
class TimelineView extends
|
|
1158
|
+
class TimelineView extends DateComponent {
|
|
1163
1159
|
constructor() {
|
|
1164
1160
|
super(...arguments);
|
|
1165
|
-
this.buildTimelineDateProfile =
|
|
1166
|
-
this.scrollGridRef =
|
|
1161
|
+
this.buildTimelineDateProfile = memoize(buildTimelineDateProfile);
|
|
1162
|
+
this.scrollGridRef = createRef();
|
|
1167
1163
|
this.state = {
|
|
1168
1164
|
slatCoords: null,
|
|
1169
1165
|
slotCushionMaxWidth: null,
|
|
@@ -1184,8 +1180,8 @@ class TimelineView extends internal_cjs.DateComponent {
|
|
|
1184
1180
|
render() {
|
|
1185
1181
|
let { props, state, context } = this;
|
|
1186
1182
|
let { options } = context;
|
|
1187
|
-
let stickyHeaderDates = !props.forPrint &&
|
|
1188
|
-
let stickyFooterScrollbar = !props.forPrint &&
|
|
1183
|
+
let stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options);
|
|
1184
|
+
let stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(options);
|
|
1189
1185
|
let tDateProfile = this.buildTimelineDateProfile(props.dateProfile, context.dateEnv, options, context.dateProfileGenerator);
|
|
1190
1186
|
let { slotMinWidth } = options;
|
|
1191
1187
|
let slatCols = buildSlatCols(tDateProfile, slotMinWidth || this.computeFallbackSlotMinWidth(tDateProfile));
|
|
@@ -1196,7 +1192,7 @@ class TimelineView extends internal_cjs.DateComponent {
|
|
|
1196
1192
|
isSticky: stickyHeaderDates,
|
|
1197
1193
|
chunks: [{
|
|
1198
1194
|
key: 'timeline',
|
|
1199
|
-
content: (contentArg) => (
|
|
1195
|
+
content: (contentArg) => (createElement(TimelineHeader, { dateProfile: props.dateProfile, clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, tableMinWidth: contentArg.tableMinWidth, tableColGroupNode: contentArg.tableColGroupNode, tDateProfile: tDateProfile, slatCoords: state.slatCoords, onMaxCushionWidth: slotMinWidth ? null : this.handleMaxCushionWidth })),
|
|
1200
1196
|
}],
|
|
1201
1197
|
},
|
|
1202
1198
|
{
|
|
@@ -1205,7 +1201,7 @@ class TimelineView extends internal_cjs.DateComponent {
|
|
|
1205
1201
|
liquid: true,
|
|
1206
1202
|
chunks: [{
|
|
1207
1203
|
key: 'timeline',
|
|
1208
|
-
content: (contentArg) => (
|
|
1204
|
+
content: (contentArg) => (createElement(TimelineGrid, Object.assign({}, props, { clientWidth: contentArg.clientWidth, clientHeight: contentArg.clientHeight, tableMinWidth: contentArg.tableMinWidth, tableColGroupNode: contentArg.tableColGroupNode, tDateProfile: tDateProfile, onSlatCoords: this.handleSlatCoords, onScrollLeftRequest: this.handleScrollLeftRequest }))),
|
|
1209
1205
|
}],
|
|
1210
1206
|
},
|
|
1211
1207
|
];
|
|
@@ -1216,17 +1212,17 @@ class TimelineView extends internal_cjs.DateComponent {
|
|
|
1216
1212
|
isSticky: true,
|
|
1217
1213
|
chunks: [{
|
|
1218
1214
|
key: 'timeline',
|
|
1219
|
-
content:
|
|
1215
|
+
content: renderScrollShim,
|
|
1220
1216
|
}],
|
|
1221
1217
|
});
|
|
1222
1218
|
}
|
|
1223
|
-
return (
|
|
1219
|
+
return (createElement(ViewContainer, { elClasses: [
|
|
1224
1220
|
'fc-timeline',
|
|
1225
1221
|
options.eventOverlap === false ?
|
|
1226
1222
|
'fc-timeline-overlap-disabled' :
|
|
1227
1223
|
'',
|
|
1228
1224
|
], viewSpec: context.viewSpec },
|
|
1229
|
-
|
|
1225
|
+
createElement(ScrollGrid, { ref: this.scrollGridRef, liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: false, colGroups: [
|
|
1230
1226
|
{ cols: slatCols },
|
|
1231
1227
|
], sections: sections })));
|
|
1232
1228
|
}
|
|
@@ -1241,15 +1237,4 @@ function buildSlatCols(tDateProfile, slotMinWidth) {
|
|
|
1241
1237
|
}];
|
|
1242
1238
|
}
|
|
1243
1239
|
|
|
1244
|
-
|
|
1245
|
-
exports.TimelineHeader = TimelineHeader;
|
|
1246
|
-
exports.TimelineHeaderRows = TimelineHeaderRows;
|
|
1247
|
-
exports.TimelineLane = TimelineLane;
|
|
1248
|
-
exports.TimelineLaneBg = TimelineLaneBg;
|
|
1249
|
-
exports.TimelineLaneSlicer = TimelineLaneSlicer;
|
|
1250
|
-
exports.TimelineSlats = TimelineSlats;
|
|
1251
|
-
exports.TimelineView = TimelineView;
|
|
1252
|
-
exports.buildSlatCols = buildSlatCols;
|
|
1253
|
-
exports.buildTimelineDateProfile = buildTimelineDateProfile;
|
|
1254
|
-
exports.coordToCss = coordToCss;
|
|
1255
|
-
exports.coordsToCss = coordsToCss;
|
|
1240
|
+
export { TimelineCoords, TimelineHeader, TimelineHeaderRows, TimelineLane, TimelineLaneBg, TimelineLaneSlicer, TimelineSlats, TimelineView, buildSlatCols, buildTimelineDateProfile, coordToCss, coordsToCss };
|