@fullcalendar/timeline 7.0.0-beta.3 → 7.0.0-beta.5
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/LICENSE.md +2 -2
- package/{index.cjs → cjs/index.cjs} +14 -7
- package/cjs/internal.cjs +1224 -0
- package/esm/index.d.ts +25 -0
- package/{index.js → esm/index.js} +13 -6
- package/{internal.d.ts → esm/internal.d.ts} +33 -48
- package/{internal.js → esm/internal.js} +455 -495
- package/{index.global.js → global.js} +464 -500
- package/global.min.js +6 -0
- package/package.json +24 -21
- package/index.d.ts +0 -8
- package/index.global.min.js +0 -6
- package/internal.cjs +0 -1261
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
FullCalendar Timeline Plugin v7.0.0-beta.
|
|
2
|
+
FullCalendar Timeline Plugin v7.0.0-beta.5
|
|
3
3
|
Docs & License: https://fullcalendar.io/docs/timeline-view-no-resources
|
|
4
|
-
(c)
|
|
4
|
+
(c) 2025 Adam Shaw
|
|
5
5
|
*/
|
|
6
|
-
FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$1, preact, internal$2) {
|
|
6
|
+
FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$1, classNames, preact, internal$2) {
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
10
10
|
|
|
11
11
|
var premiumCommonPlugin__default = /*#__PURE__*/_interopDefault(premiumCommonPlugin);
|
|
12
|
+
var classNames__default = /*#__PURE__*/_interopDefault(classNames);
|
|
12
13
|
|
|
13
14
|
const MIN_AUTO_LABELS = 18; // more than `12` months but less that `24` hours
|
|
14
15
|
const MAX_AUTO_SLOTS_PER_LABEL = 6; // allows 6 10-min slots in an hour
|
|
@@ -37,13 +38,13 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
37
38
|
];
|
|
38
39
|
function buildTimelineDateProfile(dateProfile, dateEnv, allOptions, dateProfileGenerator) {
|
|
39
40
|
let tDateProfile = {
|
|
40
|
-
labelInterval: allOptions.
|
|
41
|
+
labelInterval: allOptions.slotHeaderInterval,
|
|
41
42
|
slotDuration: allOptions.slotDuration,
|
|
42
43
|
};
|
|
43
44
|
validateLabelAndSlot(tDateProfile, dateProfile, dateEnv); // validate after computed grid duration
|
|
44
45
|
ensureLabelInterval(tDateProfile, dateProfile, dateEnv);
|
|
45
46
|
ensureSlotDuration(tDateProfile, dateProfile, dateEnv);
|
|
46
|
-
let input = allOptions.
|
|
47
|
+
let input = allOptions.slotHeaderFormat;
|
|
47
48
|
let rawFormats = Array.isArray(input) ? input :
|
|
48
49
|
(input != null) ? [input] :
|
|
49
50
|
computeHeaderFormats(tDateProfile, dateProfile, dateEnv, allOptions);
|
|
@@ -57,10 +58,6 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
tDateProfile.largeUnit = largeUnit;
|
|
60
|
-
tDateProfile.emphasizeWeeks =
|
|
61
|
-
internal$1.asCleanDays(tDateProfile.slotDuration) === 1 &&
|
|
62
|
-
currentRangeAs('weeks', dateProfile, dateEnv) >= 2 &&
|
|
63
|
-
!allOptions.businessHours;
|
|
64
61
|
/*
|
|
65
62
|
console.log('label interval =', timelineView.labelInterval.humanize())
|
|
66
63
|
console.log('slot duration =', timelineView.slotDuration.humanize())
|
|
@@ -96,14 +93,18 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
96
93
|
tDateProfile.timeWindowMs = timeWindowMs;
|
|
97
94
|
tDateProfile.normalizedRange = { start: normalizedStart, end: normalizedEnd };
|
|
98
95
|
let slotDates = [];
|
|
96
|
+
let slotDatesMajor = [];
|
|
99
97
|
let date = normalizedStart;
|
|
98
|
+
let majorUnit = internal$1.computeMajorUnit(dateProfile, dateEnv);
|
|
100
99
|
while (date < normalizedEnd) {
|
|
101
100
|
if (isValidDate(date, tDateProfile, dateProfile, dateProfileGenerator)) {
|
|
102
101
|
slotDates.push(date);
|
|
102
|
+
slotDatesMajor.push(internal$1.isMajorUnit(date, majorUnit, dateEnv));
|
|
103
103
|
}
|
|
104
104
|
date = dateEnv.add(date, tDateProfile.slotDuration);
|
|
105
105
|
}
|
|
106
106
|
tDateProfile.slotDates = slotDates;
|
|
107
|
+
tDateProfile.slotDatesMajor = slotDatesMajor;
|
|
107
108
|
// more...
|
|
108
109
|
let snapIndex = -1;
|
|
109
110
|
let snapDiff = 0; // index of the diff :(
|
|
@@ -127,8 +128,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
127
128
|
tDateProfile.snapCnt = snapIndex + 1; // is always one behind
|
|
128
129
|
tDateProfile.slotCnt = tDateProfile.snapCnt / tDateProfile.snapsPerSlot;
|
|
129
130
|
// more...
|
|
130
|
-
tDateProfile.
|
|
131
|
-
tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv);
|
|
131
|
+
tDateProfile.cellRows = buildCellRows(tDateProfile, dateEnv, majorUnit);
|
|
132
132
|
tDateProfile.slotsPerLabel = internal$1.wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
|
|
133
133
|
return tDateProfile;
|
|
134
134
|
}
|
|
@@ -189,7 +189,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
189
189
|
if (tDateProfile.labelInterval) {
|
|
190
190
|
const labelCnt = dateEnv.countDurationsBetween(currentRange.start, currentRange.end, tDateProfile.labelInterval);
|
|
191
191
|
if (labelCnt > internal$1.config.MAX_TIMELINE_SLOTS) {
|
|
192
|
-
console.warn('
|
|
192
|
+
console.warn('slotHeaderInterval results in too many cells');
|
|
193
193
|
tDateProfile.labelInterval = null;
|
|
194
194
|
}
|
|
195
195
|
}
|
|
@@ -205,7 +205,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
205
205
|
if (tDateProfile.labelInterval && tDateProfile.slotDuration) {
|
|
206
206
|
const slotsPerLabel = internal$1.wholeDivideDurations(tDateProfile.labelInterval, tDateProfile.slotDuration);
|
|
207
207
|
if (slotsPerLabel === null || slotsPerLabel < 1) {
|
|
208
|
-
console.warn('
|
|
208
|
+
console.warn('slotHeaderInterval must be a multiple of slotDuration');
|
|
209
209
|
tDateProfile.slotDuration = null;
|
|
210
210
|
}
|
|
211
211
|
}
|
|
@@ -280,6 +280,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
280
280
|
let format1;
|
|
281
281
|
let format2;
|
|
282
282
|
const { labelInterval } = tDateProfile;
|
|
283
|
+
const { currentRange } = dateProfile;
|
|
283
284
|
let unit = internal$1.greatestDurationDenominator(labelInterval).unit;
|
|
284
285
|
const weekNumbersVisible = allOptions.weekNumbers;
|
|
285
286
|
let format0 = (format1 = (format2 = null));
|
|
@@ -292,22 +293,22 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
292
293
|
format0 = { year: 'numeric' }; // '2015'
|
|
293
294
|
break;
|
|
294
295
|
case 'month':
|
|
295
|
-
if (
|
|
296
|
+
if (dateEnv.diffWholeYears(currentRange.start, currentRange.end) > 1) {
|
|
296
297
|
format0 = { year: 'numeric' }; // '2015'
|
|
297
298
|
}
|
|
298
299
|
format1 = { month: 'short' }; // 'Jan'
|
|
299
300
|
break;
|
|
300
301
|
case 'week':
|
|
301
|
-
if (
|
|
302
|
+
if (dateEnv.diffWholeYears(currentRange.start, currentRange.end) > 1) {
|
|
302
303
|
format0 = { year: 'numeric' }; // '2015'
|
|
303
304
|
}
|
|
304
305
|
format1 = { week: 'narrow' }; // 'Wk4'
|
|
305
306
|
break;
|
|
306
307
|
case 'day':
|
|
307
|
-
if (
|
|
308
|
+
if (dateEnv.diffWholeYears(currentRange.start, currentRange.end) > 1) {
|
|
308
309
|
format0 = { year: 'numeric', month: 'long' }; // 'January 2014'
|
|
309
310
|
}
|
|
310
|
-
else if (
|
|
311
|
+
else if (dateEnv.diffWholeMonths(currentRange.start, currentRange.end) > 1) {
|
|
311
312
|
format0 = { month: 'long' }; // 'January'
|
|
312
313
|
}
|
|
313
314
|
if (weekNumbersVisible) {
|
|
@@ -319,7 +320,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
319
320
|
if (weekNumbersVisible) {
|
|
320
321
|
format0 = { week: 'short' }; // 'Wk 4'
|
|
321
322
|
}
|
|
322
|
-
if (
|
|
323
|
+
if (internal$1.diffWholeDays(currentRange.start, currentRange.end) > 1) {
|
|
323
324
|
format1 = { weekday: 'short', day: 'numeric', month: 'numeric', omitCommas: true }; // Sat 4/7
|
|
324
325
|
}
|
|
325
326
|
format2 = {
|
|
@@ -365,39 +366,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
365
366
|
}
|
|
366
367
|
return [].concat(format0 || [], format1 || [], format2 || []);
|
|
367
368
|
}
|
|
368
|
-
|
|
369
|
-
// Won't go more precise than days.
|
|
370
|
-
// Will return `0` if there's not a clean whole interval.
|
|
371
|
-
function currentRangeAs(unit, dateProfile, dateEnv) {
|
|
372
|
-
let range = dateProfile.currentRange;
|
|
373
|
-
let res = null;
|
|
374
|
-
if (unit === 'years') {
|
|
375
|
-
res = dateEnv.diffWholeYears(range.start, range.end);
|
|
376
|
-
}
|
|
377
|
-
else if (unit === 'months') {
|
|
378
|
-
res = dateEnv.diffWholeMonths(range.start, range.end);
|
|
379
|
-
}
|
|
380
|
-
else if (unit === 'weeks') {
|
|
381
|
-
res = dateEnv.diffWholeMonths(range.start, range.end);
|
|
382
|
-
}
|
|
383
|
-
else if (unit === 'days') {
|
|
384
|
-
res = internal$1.diffWholeDays(range.start, range.end);
|
|
385
|
-
}
|
|
386
|
-
return res || 0;
|
|
387
|
-
}
|
|
388
|
-
function buildIsWeekStarts(tDateProfile, dateEnv) {
|
|
389
|
-
let { slotDates, emphasizeWeeks } = tDateProfile;
|
|
390
|
-
let prevWeekNumber = null;
|
|
391
|
-
let isWeekStarts = [];
|
|
392
|
-
for (let slotDate of slotDates) {
|
|
393
|
-
let weekNumber = dateEnv.computeWeekNumber(slotDate);
|
|
394
|
-
let isWeekStart = emphasizeWeeks && (prevWeekNumber !== null) && (prevWeekNumber !== weekNumber);
|
|
395
|
-
prevWeekNumber = weekNumber;
|
|
396
|
-
isWeekStarts.push(isWeekStart);
|
|
397
|
-
}
|
|
398
|
-
return isWeekStarts;
|
|
399
|
-
}
|
|
400
|
-
function buildCellRows(tDateProfile, dateEnv) {
|
|
369
|
+
function buildCellRows(tDateProfile, dateEnv, majorUnit) {
|
|
401
370
|
let slotDates = tDateProfile.slotDates;
|
|
402
371
|
let formats = tDateProfile.headerFormats;
|
|
403
372
|
let cellRows = formats.map(() => []); // indexed by row,col
|
|
@@ -406,23 +375,23 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
406
375
|
slotAsDays === 1 ? 'day' :
|
|
407
376
|
null;
|
|
408
377
|
// specifically for navclicks
|
|
409
|
-
let rowUnitsFromFormats = formats.map((format) => (format.
|
|
378
|
+
let rowUnitsFromFormats = formats.map((format) => (format.getSmallestUnit ? format.getSmallestUnit() : null));
|
|
410
379
|
// builds cellRows and slotCells
|
|
411
380
|
for (let i = 0; i < slotDates.length; i += 1) {
|
|
412
381
|
let date = slotDates[i];
|
|
413
|
-
let isWeekStart = tDateProfile.isWeekStarts[i];
|
|
414
382
|
for (let row = 0; row < formats.length; row += 1) {
|
|
415
383
|
let format = formats[row];
|
|
416
384
|
let rowCells = cellRows[row];
|
|
417
385
|
let leadingCell = rowCells[rowCells.length - 1];
|
|
418
386
|
let isLastRow = row === formats.length - 1;
|
|
419
387
|
let isSuperRow = formats.length > 1 && !isLastRow; // more than one row and not the last
|
|
388
|
+
let isMajor = internal$1.isMajorUnit(date, majorUnit, dateEnv);
|
|
420
389
|
let newCell = null;
|
|
421
390
|
let rowUnit = rowUnitsFromFormats[row] || (isLastRow ? guessedSlotUnit : null);
|
|
422
391
|
if (isSuperRow) {
|
|
423
|
-
let text = dateEnv.format(date, format);
|
|
392
|
+
let [text] = dateEnv.format(date, format);
|
|
424
393
|
if (!leadingCell || (leadingCell.text !== text)) {
|
|
425
|
-
newCell = buildCellObject(date, text, rowUnit);
|
|
394
|
+
newCell = buildCellObject(date, isMajor, text, rowUnit);
|
|
426
395
|
}
|
|
427
396
|
else {
|
|
428
397
|
leadingCell.colspan += 1;
|
|
@@ -430,161 +399,202 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
430
399
|
}
|
|
431
400
|
else if (!leadingCell ||
|
|
432
401
|
internal$1.isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.labelInterval))) {
|
|
433
|
-
let text = dateEnv.format(date, format);
|
|
434
|
-
newCell = buildCellObject(date, text, rowUnit);
|
|
402
|
+
let [text] = dateEnv.format(date, format);
|
|
403
|
+
newCell = buildCellObject(date, isMajor, text, rowUnit);
|
|
435
404
|
}
|
|
436
405
|
else {
|
|
437
406
|
leadingCell.colspan += 1;
|
|
438
407
|
}
|
|
439
408
|
if (newCell) {
|
|
440
|
-
newCell.weekStart = isWeekStart;
|
|
441
409
|
rowCells.push(newCell);
|
|
442
410
|
}
|
|
443
411
|
}
|
|
444
412
|
}
|
|
445
413
|
return cellRows;
|
|
446
414
|
}
|
|
447
|
-
function buildCellObject(date, text, rowUnit) {
|
|
448
|
-
return { date, text, rowUnit, colspan: 1
|
|
415
|
+
function buildCellObject(date, isMajor, text, rowUnit) {
|
|
416
|
+
return { date, isMajor, text, rowUnit, colspan: 1 }; // colspan mutated later
|
|
449
417
|
}
|
|
450
418
|
|
|
451
419
|
class TimelineSlatCell extends internal$1.BaseComponent {
|
|
452
420
|
constructor() {
|
|
453
421
|
super(...arguments);
|
|
454
|
-
//
|
|
455
|
-
this.
|
|
422
|
+
// memo
|
|
423
|
+
this.getDateMeta = internal$1.memoize(internal$1.getDateMeta);
|
|
456
424
|
}
|
|
457
425
|
render() {
|
|
458
426
|
let { props, context } = this;
|
|
459
427
|
let { dateEnv, options } = context;
|
|
460
|
-
let { date, tDateProfile,
|
|
461
|
-
let dateMeta =
|
|
462
|
-
let
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
'fc-timeline-slot-major' :
|
|
469
|
-
'fc-timeline-slot-minor'), 'fc-timeline-slot-lane fc-cell fc-flex-col fc-align-start', props.borderStart && 'fc-border-s', props.isDay ?
|
|
470
|
-
internal$1.getDayClassName(dateMeta) :
|
|
471
|
-
internal$1.getSlotClassName(dateMeta)), attrs: {
|
|
472
|
-
'data-date': dateEnv.formatIso(date, {
|
|
428
|
+
let { date, tDateProfile, isMajor } = props;
|
|
429
|
+
let dateMeta = this.getDateMeta(props.date, dateEnv, props.dateProfile, props.todayRange, props.nowDate);
|
|
430
|
+
let isMinor = tDateProfile.isTimeScale &&
|
|
431
|
+
!internal$1.isInt(dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, props.date, tDateProfile.labelInterval));
|
|
432
|
+
let renderProps = Object.assign(Object.assign({}, dateMeta), { isMajor,
|
|
433
|
+
isMinor, view: context.viewApi });
|
|
434
|
+
return (preact.createElement(internal$1.ContentContainer, { tag: "div", className: core.joinClassNames(classNames__default["default"].tight, classNames__default["default"].alignStart, // shrinks width of InnerContent
|
|
435
|
+
props.borderStart ? classNames__default["default"].borderOnlyS : classNames__default["default"].borderNone, classNames__default["default"].internalTimelineSlot), attrs: Object.assign({ 'data-date': dateEnv.formatIso(date, {
|
|
473
436
|
omitTimeZoneOffset: true,
|
|
474
437
|
omitTime: !tDateProfile.isTimeScale,
|
|
475
|
-
}),
|
|
476
|
-
}, style: {
|
|
438
|
+
}) }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), style: {
|
|
477
439
|
width: props.width,
|
|
478
|
-
}, renderProps: renderProps, generatorName:
|
|
440
|
+
}, renderProps: renderProps, generatorName: undefined, classNameGenerator: options.slotLaneClass, didMount: options.slotLaneDidMount, willUnmount: options.slotLaneWillUnmount }));
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
class TimelineSlats extends internal$1.BaseComponent {
|
|
445
|
+
render() {
|
|
446
|
+
let { props } = this;
|
|
447
|
+
let { tDateProfile, slotWidth } = props;
|
|
448
|
+
let { slotDates, slotDatesMajor } = tDateProfile;
|
|
449
|
+
return (preact.createElement("div", { "aria-hidden": true, className: core.joinClassNames(classNames__default["default"].flexRow, classNames__default["default"].fill), style: { height: props.height } }, slotDates.map((slotDate, i) => {
|
|
450
|
+
let key = slotDate.toISOString();
|
|
451
|
+
return (preact.createElement(TimelineSlatCell, { key: key, date: slotDate, dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isMajor: slotDatesMajor[i], borderStart: Boolean(i),
|
|
452
|
+
// dimensions
|
|
453
|
+
width: slotWidth }));
|
|
454
|
+
})));
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
class TimelineHeaderCell extends internal$1.BaseComponent {
|
|
459
|
+
constructor() {
|
|
460
|
+
super(...arguments);
|
|
461
|
+
// memo
|
|
462
|
+
this.getDateMeta = internal$1.memoize(internal$1.getDateMeta);
|
|
463
|
+
// ref
|
|
464
|
+
this.innerWrapperElRef = preact.createRef();
|
|
465
|
+
}
|
|
466
|
+
render() {
|
|
467
|
+
let { props, state, context } = this;
|
|
468
|
+
let { dateEnv, options } = context;
|
|
469
|
+
let { cell, dateProfile, tDateProfile } = props;
|
|
470
|
+
// the cell.rowUnit is f'd
|
|
471
|
+
// giving 'month' for a 3-day view
|
|
472
|
+
// workaround: to infer day, do NOT time
|
|
473
|
+
let dateMeta = this.getDateMeta(cell.date, dateEnv, dateProfile, props.todayRange, props.nowDate);
|
|
474
|
+
let hasNavLink = options.navLinks && !dateMeta.isDisabled && (cell.rowUnit && cell.rowUnit !== 'time');
|
|
475
|
+
let isTime = tDateProfile.isTimeScale && !props.rowLevel; // HACK: faulty way of determining this
|
|
476
|
+
let renderProps = Object.assign(Object.assign({}, dateMeta), { level: props.rowLevel, isMajor: cell.isMajor, isMinor: false, isNarrow: false, isTime,
|
|
477
|
+
hasNavLink, text: cell.text, isFirst: props.isFirst, view: context.viewApi });
|
|
478
|
+
const { slotHeaderAlign } = options;
|
|
479
|
+
const align = this.align =
|
|
480
|
+
typeof slotHeaderAlign === 'function'
|
|
481
|
+
? slotHeaderAlign({ level: props.rowLevel, isTime })
|
|
482
|
+
: slotHeaderAlign;
|
|
483
|
+
const isSticky = this.isSticky =
|
|
484
|
+
props.rowLevel && options.slotHeaderSticky !== false;
|
|
485
|
+
let edgeCoord;
|
|
486
|
+
if (isSticky) {
|
|
487
|
+
if (align === 'center') {
|
|
488
|
+
if (state.innerWidth != null) {
|
|
489
|
+
edgeCoord = `calc(50% - ${state.innerWidth / 2}px)`;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
edgeCoord = (typeof options.slotHeaderSticky === 'number' ||
|
|
494
|
+
typeof options.slotHeaderSticky === 'string') ? options.slotHeaderSticky : 0;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return (preact.createElement(internal$1.ContentContainer, { tag: "div", className: internal$1.joinArrayishClassNames(classNames__default["default"].tight, classNames__default["default"].flexCol, props.isFirst ? classNames__default["default"].borderNone : classNames__default["default"].borderOnlyS, align === 'center' ? classNames__default["default"].alignCenter :
|
|
498
|
+
align === 'end' ? classNames__default["default"].alignEnd :
|
|
499
|
+
classNames__default["default"].alignStart, classNames__default["default"].internalTimelineSlot), attrs: Object.assign({ 'data-date': dateEnv.formatIso(cell.date, {
|
|
500
|
+
omitTime: !tDateProfile.isTimeScale,
|
|
501
|
+
omitTimeZoneOffset: true,
|
|
502
|
+
}) }, (dateMeta.isToday ? { 'aria-current': 'date' } : {})), style: {
|
|
503
|
+
width: props.slotWidth != null
|
|
504
|
+
? props.slotWidth * cell.colspan
|
|
505
|
+
: undefined,
|
|
506
|
+
}, renderProps: renderProps, generatorName: "slotHeaderContent", customGenerator: options.slotHeaderContent, defaultGenerator: renderInnerContent, classNameGenerator: options.slotHeaderClass, didMount: options.slotHeaderDidMount, willUnmount: options.slotHeaderWillUnmount }, (InnerContent) => (preact.createElement("div", { ref: this.innerWrapperElRef, className: core.joinClassNames(classNames__default["default"].flexCol, classNames__default["default"].rigid, isSticky && classNames__default["default"].sticky), style: {
|
|
507
|
+
left: edgeCoord,
|
|
508
|
+
right: edgeCoord,
|
|
509
|
+
} },
|
|
510
|
+
preact.createElement(InnerContent, { tag: 'div', attrs: hasNavLink
|
|
511
|
+
// not tabbable because parent is aria-hidden
|
|
512
|
+
? internal$1.buildNavLinkAttrs(context, cell.date, cell.rowUnit, undefined, /* isTabbable = */ false)
|
|
513
|
+
: {} // don't bother with aria-hidden because parent already hidden
|
|
514
|
+
, className: internal$1.generateClassName(options.slotHeaderInnerClass, renderProps) })))));
|
|
479
515
|
}
|
|
480
516
|
componentDidMount() {
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
517
|
+
const { props } = this;
|
|
518
|
+
const innerWrapperEl = this.innerWrapperElRef.current; // TODO: make dynamic with useEffect
|
|
519
|
+
this.disconnectSize = internal$1.watchSize(innerWrapperEl, (width, height) => {
|
|
520
|
+
internal$1.setRef(props.innerWidthRef, width);
|
|
521
|
+
internal$1.setRef(props.innerHeightRef, height);
|
|
522
|
+
if (this.align === 'center' && this.isSticky) {
|
|
523
|
+
this.setState({ innerWidth: width });
|
|
524
|
+
}
|
|
484
525
|
});
|
|
485
526
|
}
|
|
486
527
|
componentWillUnmount() {
|
|
487
|
-
this
|
|
488
|
-
|
|
528
|
+
const { props } = this;
|
|
529
|
+
this.disconnectSize();
|
|
530
|
+
internal$1.setRef(props.innerWidthRef, null);
|
|
531
|
+
internal$1.setRef(props.innerHeightRef, null);
|
|
489
532
|
}
|
|
490
533
|
}
|
|
534
|
+
// Utils
|
|
535
|
+
// -------------------------------------------------------------------------------------------------
|
|
536
|
+
function renderInnerContent(renderProps) {
|
|
537
|
+
return renderProps.text;
|
|
538
|
+
}
|
|
491
539
|
|
|
492
|
-
class
|
|
540
|
+
class TimelineHeaderRow extends internal$1.BaseComponent {
|
|
493
541
|
constructor() {
|
|
494
542
|
super(...arguments);
|
|
543
|
+
// refs
|
|
495
544
|
this.innerWidthRefMap = new internal$1.RefMap(() => {
|
|
496
545
|
internal$1.afterSize(this.handleInnerWidths);
|
|
497
546
|
});
|
|
547
|
+
this.innerHeightRefMap = new internal$1.RefMap(() => {
|
|
548
|
+
internal$1.afterSize(this.handleInnerHeights);
|
|
549
|
+
});
|
|
498
550
|
this.handleInnerWidths = () => {
|
|
499
551
|
const innerWidthMap = this.innerWidthRefMap.current;
|
|
500
552
|
let max = 0;
|
|
501
553
|
for (const innerWidth of innerWidthMap.values()) {
|
|
502
554
|
max = Math.max(max, innerWidth);
|
|
503
555
|
}
|
|
504
|
-
// TODO:
|
|
556
|
+
// TODO: ensure not equal?
|
|
505
557
|
internal$1.setRef(this.props.innerWidthRef, max);
|
|
506
558
|
};
|
|
559
|
+
this.handleInnerHeights = () => {
|
|
560
|
+
const innerHeightMap = this.innerHeightRefMap.current;
|
|
561
|
+
let max = 0;
|
|
562
|
+
for (const innerHeight of innerHeightMap.values()) {
|
|
563
|
+
max = Math.max(max, innerHeight);
|
|
564
|
+
}
|
|
565
|
+
// TODO: ensure not equal?
|
|
566
|
+
internal$1.setRef(this.props.innerHeighRef, max);
|
|
567
|
+
this.setState({ innerHeight: max });
|
|
568
|
+
};
|
|
507
569
|
}
|
|
508
570
|
render() {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
571
|
+
const { props, innerWidthRefMap, innerHeightRefMap, state, context } = this;
|
|
572
|
+
const { options } = context;
|
|
573
|
+
return (preact.createElement("div", { className: internal$1.joinArrayishClassNames(options.slotHeaderRowClass, classNames__default["default"].flexRow, classNames__default["default"].grow, props.rowLevel // not the last row?
|
|
574
|
+
? classNames__default["default"].borderOnlyB
|
|
575
|
+
: classNames__default["default"].borderNone), style: {
|
|
576
|
+
// we assign height because we allow cells to have distorted heights for visual effect
|
|
577
|
+
// but we still want to keep the overall extrenal mass
|
|
578
|
+
height: state.innerHeight,
|
|
579
|
+
} }, props.cells.map((cell, cellI) => {
|
|
580
|
+
// TODO: make this part of the cell obj?
|
|
581
|
+
// TODO: rowUnit seems wrong sometimes. says 'month' when it should be day
|
|
582
|
+
// TODO: rowUnit is relevant to whole row. put it on a row object, not the cells
|
|
583
|
+
// TODO: use rowUnit to key the Row itself?
|
|
584
|
+
const key = cell.rowUnit + ':' + cell.date.toISOString();
|
|
585
|
+
return (preact.createElement(TimelineHeaderCell, { key: key, cell: cell, rowLevel: props.rowLevel, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, todayRange: props.todayRange, nowDate: props.nowDate, isFirst: cellI === 0,
|
|
586
|
+
// refs
|
|
587
|
+
innerWidthRef: innerWidthRefMap.createRef(key), innerHeightRef: innerHeightRefMap.createRef(key),
|
|
518
588
|
// dimensions
|
|
519
|
-
|
|
589
|
+
slotWidth: props.slotWidth }));
|
|
520
590
|
})));
|
|
521
591
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
TODO: rename this file!
|
|
526
|
-
*/
|
|
527
|
-
// returned value is between 0 and the number of snaps
|
|
528
|
-
function computeDateSnapCoverage$1(date, tDateProfile, dateEnv) {
|
|
529
|
-
let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
|
|
530
|
-
if (snapDiff < 0) {
|
|
531
|
-
return 0;
|
|
532
|
-
}
|
|
533
|
-
if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
|
|
534
|
-
return tDateProfile.snapCnt;
|
|
535
|
-
}
|
|
536
|
-
let snapDiffInt = Math.floor(snapDiff);
|
|
537
|
-
let snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
|
|
538
|
-
if (internal$1.isInt(snapCoverage)) { // not an in-between value
|
|
539
|
-
snapCoverage += snapDiff - snapDiffInt; // add the remainder
|
|
540
|
-
}
|
|
541
|
-
else {
|
|
542
|
-
// a fractional value, meaning the date is not visible
|
|
543
|
-
// always round up in this case. works for start AND end dates in a range.
|
|
544
|
-
snapCoverage = Math.ceil(snapCoverage);
|
|
545
|
-
}
|
|
546
|
-
return snapCoverage;
|
|
547
|
-
}
|
|
548
|
-
/*
|
|
549
|
-
TODO: DRY up with elsewhere?
|
|
550
|
-
*/
|
|
551
|
-
function horizontalsToCss(hcoord, isRtl) {
|
|
552
|
-
if (!hcoord) {
|
|
553
|
-
return {};
|
|
554
|
-
}
|
|
555
|
-
if (isRtl) {
|
|
556
|
-
return { right: hcoord.start, width: hcoord.size };
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
return { left: hcoord.start, width: hcoord.size };
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
function horizontalCoordToCss(start, isRtl) {
|
|
563
|
-
if (isRtl) {
|
|
564
|
-
return { right: start };
|
|
565
|
-
}
|
|
566
|
-
else {
|
|
567
|
-
return { left: start };
|
|
592
|
+
componentWillUnmount() {
|
|
593
|
+
internal$1.setRef(this.props.innerWidthRef, null);
|
|
594
|
+
internal$1.setRef(this.props.innerHeighRef, null);
|
|
568
595
|
}
|
|
569
596
|
}
|
|
570
597
|
|
|
571
|
-
function createVerticalStyle(props) {
|
|
572
|
-
if (props) {
|
|
573
|
-
return {
|
|
574
|
-
top: props.start,
|
|
575
|
-
height: props.size,
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
function createHorizontalStyle(// TODO: DRY up?
|
|
580
|
-
props, isRtl) {
|
|
581
|
-
if (props) {
|
|
582
|
-
return {
|
|
583
|
-
[isRtl ? 'right' : 'left']: props.start,
|
|
584
|
-
width: props.size,
|
|
585
|
-
};
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
598
|
// Timeline-specific
|
|
589
599
|
// -------------------------------------------------------------------------------------------------
|
|
590
600
|
const MIN_SLOT_WIDTH = 30; // for real
|
|
@@ -597,17 +607,17 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
597
607
|
}
|
|
598
608
|
slatMinWidth = Math.max(slatMinWidth || 0, (labelInnerWidth + 1) / slatsPerLabel, MIN_SLOT_WIDTH);
|
|
599
609
|
const slatTryWidth = viewportWidth / slatCnt;
|
|
600
|
-
let
|
|
610
|
+
let slotLiquid;
|
|
601
611
|
let slatWidth;
|
|
602
612
|
if (slatTryWidth >= slatMinWidth) {
|
|
603
|
-
|
|
613
|
+
slotLiquid = true;
|
|
604
614
|
slatWidth = slatTryWidth;
|
|
605
615
|
}
|
|
606
616
|
else {
|
|
607
|
-
|
|
617
|
+
slotLiquid = false;
|
|
608
618
|
slatWidth = Math.max(slatMinWidth, slatTryWidth);
|
|
609
619
|
}
|
|
610
|
-
return [slatWidth * slatCnt, slatWidth,
|
|
620
|
+
return [slatWidth * slatCnt, slatWidth, slotLiquid];
|
|
611
621
|
}
|
|
612
622
|
function timeToCoord(// pixels
|
|
613
623
|
time, dateEnv, dateProfile, tDateProfile, slowWidth) {
|
|
@@ -619,13 +629,86 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
619
629
|
}
|
|
620
630
|
function dateToCoord(// pixels
|
|
621
631
|
date, dateEnv, tDateProfile, slotWidth) {
|
|
622
|
-
let snapCoverage = computeDateSnapCoverage(date, tDateProfile, dateEnv);
|
|
632
|
+
let snapCoverage = computeDateSnapCoverage$1(date, tDateProfile, dateEnv);
|
|
623
633
|
let slotCoverage = snapCoverage / tDateProfile.snapsPerSlot;
|
|
624
634
|
return slotCoverage * slotWidth;
|
|
625
635
|
}
|
|
626
636
|
/*
|
|
627
637
|
returned value is between 0 and the number of snaps
|
|
628
638
|
*/
|
|
639
|
+
function computeDateSnapCoverage$1(date, tDateProfile, dateEnv) {
|
|
640
|
+
let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
|
|
641
|
+
if (snapDiff < 0) {
|
|
642
|
+
return 0;
|
|
643
|
+
}
|
|
644
|
+
if (snapDiff >= tDateProfile.snapDiffToIndex.length) {
|
|
645
|
+
return tDateProfile.snapCnt;
|
|
646
|
+
}
|
|
647
|
+
let snapDiffInt = Math.floor(snapDiff);
|
|
648
|
+
let snapCoverage = tDateProfile.snapDiffToIndex[snapDiffInt];
|
|
649
|
+
if (internal$1.isInt(snapCoverage)) { // not an in-between value
|
|
650
|
+
snapCoverage += snapDiff - snapDiffInt; // add the remainder
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
// a fractional value, meaning the date is not visible
|
|
654
|
+
// always round up in this case. works for start AND end dates in a range.
|
|
655
|
+
snapCoverage = Math.ceil(snapCoverage);
|
|
656
|
+
}
|
|
657
|
+
return snapCoverage;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
class TimelineNowIndicatorLine extends internal$1.BaseComponent {
|
|
661
|
+
render() {
|
|
662
|
+
const { props, context } = this;
|
|
663
|
+
const xStyle = props.slotWidth == null
|
|
664
|
+
? {}
|
|
665
|
+
: {
|
|
666
|
+
insetInlineStart: dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth)
|
|
667
|
+
};
|
|
668
|
+
return (preact.createElement("div", { className: classNames__default["default"].fill, style: {
|
|
669
|
+
zIndex: 2,
|
|
670
|
+
pointerEvents: 'none', // TODO: className
|
|
671
|
+
} },
|
|
672
|
+
preact.createElement(internal$1.NowIndicatorLineContainer, { className: core.joinClassNames(classNames__default["default"].fillY, classNames__default["default"].noMarginY, classNames__default["default"].borderlessY), style: xStyle, date: props.nowDate }),
|
|
673
|
+
preact.createElement("div", { className: core.joinClassNames(classNames__default["default"].flexCol, // better for negative margins
|
|
674
|
+
classNames__default["default"].fillY), style: xStyle },
|
|
675
|
+
preact.createElement("div", {
|
|
676
|
+
// stickiness on NowIndicatorDot misbehaves b/c of negative marginss
|
|
677
|
+
className: classNames__default["default"].stickyT },
|
|
678
|
+
preact.createElement(internal$1.NowIndicatorDot, null)))));
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/*
|
|
683
|
+
TODO: DRY with other NowIndicator components
|
|
684
|
+
*/
|
|
685
|
+
class TimelineNowIndicatorArrow extends internal$1.BaseComponent {
|
|
686
|
+
render() {
|
|
687
|
+
const { props, context } = this;
|
|
688
|
+
const xStyle = props.slotWidth == null
|
|
689
|
+
? {}
|
|
690
|
+
: {
|
|
691
|
+
insetInlineStart: dateToCoord(props.nowDate, context.dateEnv, props.tDateProfile, props.slotWidth)
|
|
692
|
+
};
|
|
693
|
+
return (preact.createElement("div", {
|
|
694
|
+
// crop any overflow that the arrow/line might cause
|
|
695
|
+
// TODO: just do this on the entire canvas within the scroller
|
|
696
|
+
className: core.joinClassNames(classNames__default["default"].fill, classNames__default["default"].crop), style: {
|
|
697
|
+
zIndex: 2,
|
|
698
|
+
pointerEvents: 'none', // TODO: className
|
|
699
|
+
} },
|
|
700
|
+
preact.createElement(internal$1.NowIndicatorHeaderContainer, { className: classNames__default["default"].abs, style: xStyle, date: props.nowDate })));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function getTimelineSlotEl(parentEl, index) {
|
|
705
|
+
return parentEl.querySelectorAll(`.${classNames__default["default"].internalTimelineSlot}`)[index];
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/*
|
|
709
|
+
TODO: rename this file!
|
|
710
|
+
*/
|
|
711
|
+
// returned value is between 0 and the number of snaps
|
|
629
712
|
function computeDateSnapCoverage(date, tDateProfile, dateEnv) {
|
|
630
713
|
let snapDiff = dateEnv.countDurationsBetween(tDateProfile.normalizedRange.start, date, tDateProfile.snapDuration);
|
|
631
714
|
if (snapDiff < 0) {
|
|
@@ -647,6 +730,60 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
647
730
|
return snapCoverage;
|
|
648
731
|
}
|
|
649
732
|
|
|
733
|
+
class TimelineLaneSlicer extends internal$1.Slicer {
|
|
734
|
+
sliceRange(origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) {
|
|
735
|
+
let normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
|
|
736
|
+
let segs = [];
|
|
737
|
+
// protect against when the span is entirely in an invalid date region
|
|
738
|
+
if (computeDateSnapCoverage(normalRange.start, tDateProfile, dateEnv)
|
|
739
|
+
< computeDateSnapCoverage(normalRange.end, tDateProfile, dateEnv)) {
|
|
740
|
+
// intersect the footprint's range with the grid's range
|
|
741
|
+
let slicedRange = internal$1.intersectRanges(normalRange, tDateProfile.normalizedRange);
|
|
742
|
+
if (slicedRange) {
|
|
743
|
+
segs.push({
|
|
744
|
+
startDate: slicedRange.start,
|
|
745
|
+
endDate: slicedRange.end,
|
|
746
|
+
isStart: slicedRange.start.valueOf() === normalRange.start.valueOf()
|
|
747
|
+
&& isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
|
|
748
|
+
isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf()
|
|
749
|
+
&& isValidDate(internal$1.addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator),
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return segs;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
const DEFAULT_TIME_FORMAT = internal$1.createFormatter({
|
|
758
|
+
hour: 'numeric',
|
|
759
|
+
minute: '2-digit',
|
|
760
|
+
omitZeroMinute: true,
|
|
761
|
+
meridiem: 'narrow',
|
|
762
|
+
});
|
|
763
|
+
class TimelineEvent extends internal$1.BaseComponent {
|
|
764
|
+
render() {
|
|
765
|
+
let { props } = this;
|
|
766
|
+
return (preact.createElement(internal$1.StandardEvent, Object.assign({}, props, { display: 'row', defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale })));
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
class TimelineLaneMoreLink extends internal$1.BaseComponent {
|
|
771
|
+
render() {
|
|
772
|
+
let { props } = this;
|
|
773
|
+
let { hiddenSegs, resourceId } = props;
|
|
774
|
+
let dateSpanProps = resourceId ? { resourceId } : {};
|
|
775
|
+
return (preact.createElement(internal$1.MoreLinkContainer, { display: 'row', allDayDate: null, segs: hiddenSegs, hiddenSegs: hiddenSegs, dateProfile: props.dateProfile, todayRange: props.todayRange, dateSpanProps: dateSpanProps, isNarrow: false, isMicro: false, popoverContent: () => (preact.createElement(preact.Fragment, null, hiddenSegs.map((seg) => {
|
|
776
|
+
let { eventRange } = seg;
|
|
777
|
+
let { instanceId } = eventRange.instance;
|
|
778
|
+
let isDragging = Boolean(props.eventDrag && props.eventDrag.affectedInstances[instanceId]);
|
|
779
|
+
let isResizing = Boolean(props.eventResize && props.eventResize.affectedInstances[instanceId]);
|
|
780
|
+
let isInvisible = isDragging || isResizing;
|
|
781
|
+
return (preact.createElement("div", { key: instanceId, style: { visibility: isInvisible ? 'hidden' : undefined } },
|
|
782
|
+
preact.createElement(TimelineEvent, Object.assign({ isTimeScale: props.isTimeScale, eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isMirror: false, isSelected: instanceId === props.eventSelection }, internal$1.getEventRangeMeta(eventRange, props.todayRange, props.nowDate)))));
|
|
783
|
+
}))) }));
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
650
787
|
function computeManySegHorizontals(segs, segMinWidth, dateEnv, tDateProfile, slotWidth) {
|
|
651
788
|
const res = {};
|
|
652
789
|
for (const seg of segs) {
|
|
@@ -711,83 +848,6 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
711
848
|
];
|
|
712
849
|
}
|
|
713
850
|
|
|
714
|
-
class TimelineLaneBg extends internal$1.BaseComponent {
|
|
715
|
-
render() {
|
|
716
|
-
let { props } = this;
|
|
717
|
-
let highlightSeg = [].concat(props.eventResizeSegs, props.dateSelectionSegs);
|
|
718
|
-
return (preact.createElement(preact.Fragment, null,
|
|
719
|
-
this.renderSegs(props.businessHourSegs || [], 'non-business'),
|
|
720
|
-
this.renderSegs(props.bgEventSegs || [], 'bg-event'),
|
|
721
|
-
this.renderSegs(highlightSeg, 'highlight')));
|
|
722
|
-
}
|
|
723
|
-
renderSegs(segs, fillType) {
|
|
724
|
-
let { tDateProfile, todayRange, nowDate, slotWidth } = this.props;
|
|
725
|
-
let { dateEnv, isRtl } = this.context;
|
|
726
|
-
return (preact.createElement(preact.Fragment, null, segs.map((seg) => {
|
|
727
|
-
let hStyle; // TODO
|
|
728
|
-
if (slotWidth != null) {
|
|
729
|
-
let segHorizontal = computeSegHorizontals(seg, undefined, dateEnv, tDateProfile, slotWidth);
|
|
730
|
-
hStyle = horizontalsToCss(segHorizontal, isRtl);
|
|
731
|
-
}
|
|
732
|
-
return (preact.createElement("div", { key: internal$1.buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: hStyle }, fillType === 'bg-event' ?
|
|
733
|
-
preact.createElement(internal$1.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd }, internal$1.getEventRangeMeta(seg.eventRange, todayRange, nowDate))) : (internal$1.renderFill(fillType))));
|
|
734
|
-
})));
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
class TimelineLaneSlicer extends internal$1.Slicer {
|
|
739
|
-
sliceRange(origRange, dateProfile, dateProfileGenerator, tDateProfile, dateEnv) {
|
|
740
|
-
let normalRange = normalizeRange(origRange, tDateProfile, dateEnv);
|
|
741
|
-
let segs = [];
|
|
742
|
-
// protect against when the span is entirely in an invalid date region
|
|
743
|
-
if (computeDateSnapCoverage$1(normalRange.start, tDateProfile, dateEnv)
|
|
744
|
-
< computeDateSnapCoverage$1(normalRange.end, tDateProfile, dateEnv)) {
|
|
745
|
-
// intersect the footprint's range with the grid's range
|
|
746
|
-
let slicedRange = internal$1.intersectRanges(normalRange, tDateProfile.normalizedRange);
|
|
747
|
-
if (slicedRange) {
|
|
748
|
-
segs.push({
|
|
749
|
-
startDate: slicedRange.start,
|
|
750
|
-
endDate: slicedRange.end,
|
|
751
|
-
isStart: slicedRange.start.valueOf() === normalRange.start.valueOf()
|
|
752
|
-
&& isValidDate(slicedRange.start, tDateProfile, dateProfile, dateProfileGenerator),
|
|
753
|
-
isEnd: slicedRange.end.valueOf() === normalRange.end.valueOf()
|
|
754
|
-
&& isValidDate(internal$1.addMs(slicedRange.end, -1), tDateProfile, dateProfile, dateProfileGenerator),
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
return segs;
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
const DEFAULT_TIME_FORMAT = internal$1.createFormatter({
|
|
763
|
-
hour: 'numeric',
|
|
764
|
-
minute: '2-digit',
|
|
765
|
-
omitZeroMinute: true,
|
|
766
|
-
meridiem: 'narrow',
|
|
767
|
-
});
|
|
768
|
-
class TimelineEvent extends internal$1.BaseComponent {
|
|
769
|
-
render() {
|
|
770
|
-
let { props, context } = this;
|
|
771
|
-
let { options } = context;
|
|
772
|
-
return (preact.createElement(internal$1.StandardEvent, Object.assign({}, props, { className: internal$1.joinClassNames('fc-timeline-event', options.eventOverlap === false // TODO: fix bad default
|
|
773
|
-
&& 'fc-timeline-event-spacious', 'fc-h-event'), defaultTimeFormat: DEFAULT_TIME_FORMAT, defaultDisplayEventTime: !props.isTimeScale })));
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
class TimelineLaneMoreLink extends internal$1.BaseComponent {
|
|
778
|
-
render() {
|
|
779
|
-
let { props } = this;
|
|
780
|
-
let { hiddenSegs, resourceId, forcedInvisibleMap } = props;
|
|
781
|
-
let dateSpanProps = resourceId ? { resourceId } : {};
|
|
782
|
-
return (preact.createElement(internal$1.MoreLinkContainer, { className: 'fc-timeline-more-link', allDayDate: null, segs: hiddenSegs, hiddenSegs: hiddenSegs, dateProfile: props.dateProfile, todayRange: props.todayRange, dateSpanProps: dateSpanProps, popoverContent: () => (preact.createElement(preact.Fragment, null, hiddenSegs.map((seg) => {
|
|
783
|
-
let { eventRange } = seg;
|
|
784
|
-
let instanceId = eventRange.instance.instanceId;
|
|
785
|
-
return (preact.createElement("div", { key: instanceId, style: { visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '' } },
|
|
786
|
-
preact.createElement(TimelineEvent, Object.assign({ isTimeScale: props.isTimeScale, eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection }, internal$1.getEventRangeMeta(eventRange, props.todayRange, props.nowDate)))));
|
|
787
|
-
}))) }, (InnerContent) => (preact.createElement(InnerContent, { tag: "div", className: 'fc-timeline-more-link-inner fc-sticky-s' }))));
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
851
|
/*
|
|
792
852
|
TODO: make DRY with other Event Harnesses
|
|
793
853
|
*/
|
|
@@ -799,7 +859,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
799
859
|
}
|
|
800
860
|
render() {
|
|
801
861
|
const { props } = this;
|
|
802
|
-
return (preact.createElement("div", { className: "
|
|
862
|
+
return (preact.createElement("div", { className: classNames__default["default"].abs, style: props.style, ref: this.rootElRef }, props.children));
|
|
803
863
|
}
|
|
804
864
|
componentDidMount() {
|
|
805
865
|
const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
|
|
@@ -813,10 +873,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
813
873
|
}
|
|
814
874
|
}
|
|
815
875
|
|
|
816
|
-
|
|
817
|
-
TODO: split TimelineLaneBg and TimelineLaneFg?
|
|
818
|
-
*/
|
|
819
|
-
class TimelineLane extends internal$1.BaseComponent {
|
|
876
|
+
class TimelineFg extends internal$1.BaseComponent {
|
|
820
877
|
constructor() {
|
|
821
878
|
super(...arguments);
|
|
822
879
|
// memo
|
|
@@ -828,8 +885,6 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
828
885
|
this.moreLinkHeightRefMap = new internal$1.RefMap(() => {
|
|
829
886
|
internal$1.afterSize(this.handleMoreLinkHeights);
|
|
830
887
|
});
|
|
831
|
-
// internal
|
|
832
|
-
this.slicer = new TimelineLaneSlicer();
|
|
833
888
|
this.handleMoreLinkHeights = () => {
|
|
834
889
|
this.setState({ moreLinkHeightRev: this.moreLinkHeightRefMap.rev }); // will trigger rerender
|
|
835
890
|
};
|
|
@@ -843,212 +898,92 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
843
898
|
render() {
|
|
844
899
|
let { props, context, segHeightRefMap, moreLinkHeightRefMap } = this;
|
|
845
900
|
let { options } = context;
|
|
846
|
-
let {
|
|
847
|
-
let
|
|
848
|
-
|
|
849
|
-
let mirrorSegs = (slicedProps.eventDrag ? slicedProps.eventDrag.segs : null) ||
|
|
850
|
-
(slicedProps.eventResize ? slicedProps.eventResize.segs : null) ||
|
|
901
|
+
let { tDateProfile } = props;
|
|
902
|
+
let mirrorSegs = (props.eventDrag ? props.eventDrag.segs : null) ||
|
|
903
|
+
(props.eventResize ? props.eventResize.segs : null) ||
|
|
851
904
|
[];
|
|
852
|
-
let fgSegs = this.sortEventSegs(
|
|
905
|
+
let fgSegs = this.sortEventSegs(props.fgEventSegs, options.eventOrder);
|
|
853
906
|
let fgSegHorizontals = props.slotWidth != null
|
|
854
907
|
? computeManySegHorizontals(fgSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
|
|
855
908
|
: {};
|
|
856
909
|
let [fgSegTops, hiddenGroups, hiddenGroupTops, totalHeight] = computeFgSegPlacements(fgSegs, fgSegHorizontals, segHeightRefMap.current, moreLinkHeightRefMap.current, options.eventOrderStrict, options.eventMaxStack);
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
false),
|
|
873
|
-
this.renderFgSegs(mirrorSegs, props.slotWidth // TODO: memoize
|
|
874
|
-
? computeManySegHorizontals(mirrorSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
|
|
875
|
-
: {}, fgSegTops, {}, // forcedInvisibleMap
|
|
876
|
-
[], // hiddenGroups
|
|
877
|
-
new Map(), // hiddenGroupTops
|
|
878
|
-
Boolean(slicedProps.eventDrag), Boolean(slicedProps.eventResize), false))));
|
|
879
|
-
}
|
|
880
|
-
renderFgSegs(segs, segHorizontals, segTops, forcedInvisibleMap, hiddenGroups, hiddenGroupTops, isDragging, isResizing, isDateSelecting) {
|
|
881
|
-
let { props, context, segHeightRefMap, moreLinkHeightRefMap } = this;
|
|
882
|
-
let isMirror = isDragging || isResizing || isDateSelecting;
|
|
910
|
+
this.totalHeight = totalHeight;
|
|
911
|
+
return (preact.createElement("div", { className: core.joinClassNames(classNames__default["default"].rel, classNames__default["default"].noShrink), style: {
|
|
912
|
+
height: totalHeight,
|
|
913
|
+
} },
|
|
914
|
+
this.renderFgSegs(fgSegs, fgSegHorizontals, fgSegTops, hiddenGroups, hiddenGroupTops,
|
|
915
|
+
/* isMirror = */ false),
|
|
916
|
+
this.renderFgSegs(mirrorSegs, props.slotWidth // TODO: memoize
|
|
917
|
+
? computeManySegHorizontals(mirrorSegs, options.eventMinWidth, context.dateEnv, tDateProfile, props.slotWidth)
|
|
918
|
+
: {}, fgSegTops,
|
|
919
|
+
/* hiddenGroups = */ [],
|
|
920
|
+
/* hiddenGroupTops = */ new Map(),
|
|
921
|
+
/* isMirror = */ true)));
|
|
922
|
+
}
|
|
923
|
+
renderFgSegs(segs, segHorizontals, segTops, hiddenGroups, hiddenGroupTops, isMirror) {
|
|
924
|
+
let { props, segHeightRefMap, moreLinkHeightRefMap } = this;
|
|
883
925
|
return (preact.createElement(preact.Fragment, null,
|
|
884
926
|
segs.map((seg) => {
|
|
885
927
|
const { eventRange } = seg;
|
|
886
928
|
const { instanceId } = eventRange.instance;
|
|
887
929
|
const segTop = segTops.get(instanceId);
|
|
888
|
-
const
|
|
889
|
-
const
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
930
|
+
const segHorizontalMaybe = segHorizontals[instanceId];
|
|
931
|
+
const segHorizontal = segHorizontalMaybe || {};
|
|
932
|
+
const isDragging = Boolean(props.eventDrag && props.eventDrag.affectedInstances[instanceId]);
|
|
933
|
+
const isResizing = Boolean(props.eventResize && props.eventResize.affectedInstances[instanceId]);
|
|
934
|
+
const isInvisible = !isMirror && (isDragging || isResizing || !segHorizontalMaybe || segTop == null);
|
|
935
|
+
return (preact.createElement(TimelineEventHarness, { key: instanceId, style: {
|
|
936
|
+
visibility: isInvisible ? 'hidden' : undefined,
|
|
937
|
+
zIndex: 1,
|
|
938
|
+
top: segTop || 0,
|
|
939
|
+
insetInlineStart: segHorizontal.start,
|
|
940
|
+
width: segHorizontal.size,
|
|
941
|
+
}, heightRef: isMirror ? undefined : segHeightRefMap.createRef(instanceId) },
|
|
942
|
+
preact.createElement(TimelineEvent, Object.assign({ isTimeScale: props.tDateProfile.isTimeScale, eventRange: eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isDragging: isDragging, isResizing: isResizing, isMirror: isMirror, isSelected: instanceId === props.eventSelection }, internal$1.getEventRangeMeta(eventRange, props.todayRange, props.nowDate)))));
|
|
893
943
|
}),
|
|
894
|
-
hiddenGroups.map((hiddenGroup) => (preact.createElement(TimelineEventHarness, { key: hiddenGroup.key, style:
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
class TimelineHeaderCell extends internal$1.BaseComponent {
|
|
903
|
-
constructor() {
|
|
904
|
-
super(...arguments);
|
|
905
|
-
// memo
|
|
906
|
-
this.refineRenderProps = internal$1.memoizeObjArg(refineRenderProps);
|
|
907
|
-
this.buildCellNavLinkAttrs = internal$1.memoize(buildCellNavLinkAttrs);
|
|
908
|
-
// ref
|
|
909
|
-
this.innerElRef = preact.createRef();
|
|
910
|
-
}
|
|
911
|
-
render() {
|
|
912
|
-
let { props, context } = this;
|
|
913
|
-
let { dateEnv, options } = context;
|
|
914
|
-
let { cell, dateProfile, tDateProfile } = props;
|
|
915
|
-
// the cell.rowUnit is f'd
|
|
916
|
-
// giving 'month' for a 3-day view
|
|
917
|
-
// workaround: to infer day, do NOT time
|
|
918
|
-
let dateMeta = internal$1.getDateMeta(cell.date, props.todayRange, props.nowDate, dateProfile);
|
|
919
|
-
let renderProps = this.refineRenderProps({
|
|
920
|
-
level: props.rowLevel,
|
|
921
|
-
dateMarker: cell.date,
|
|
922
|
-
text: cell.text,
|
|
923
|
-
dateEnv: context.dateEnv,
|
|
924
|
-
viewApi: context.viewApi,
|
|
925
|
-
});
|
|
926
|
-
return (preact.createElement(internal$1.ContentContainer, { tag: "div", className: internal$1.joinClassNames('fc-timeline-slot-label fc-timeline-slot', cell.isWeekStart && 'fc-timeline-slot-em', // TODO: document this semantic className
|
|
927
|
-
'fc-header-cell fc-cell fc-flex-col fc-justify-center', props.borderStart && 'fc-border-s', props.isCentered ? 'fc-align-center' : 'fc-align-start',
|
|
928
|
-
// TODO: so slot classnames for week/month/bigger. see note above about rowUnit
|
|
929
|
-
cell.rowUnit === 'time' ?
|
|
930
|
-
internal$1.getSlotClassName(dateMeta) :
|
|
931
|
-
internal$1.getDayClassName(dateMeta)), attrs: {
|
|
932
|
-
'data-date': dateEnv.formatIso(cell.date, {
|
|
933
|
-
omitTime: !tDateProfile.isTimeScale,
|
|
934
|
-
omitTimeZoneOffset: true,
|
|
935
|
-
}),
|
|
936
|
-
}, style: {
|
|
937
|
-
width: props.slotWidth != null
|
|
938
|
-
? props.slotWidth * cell.colspan
|
|
939
|
-
: undefined,
|
|
940
|
-
}, renderProps: renderProps, generatorName: "slotLabelContent", customGenerator: options.slotLabelContent, defaultGenerator: renderInnerContent, classNameGenerator: options.slotLabelClassNames, didMount: options.slotLabelDidMount, willUnmount: options.slotLabelWillUnmount }, (InnerContent) => (preact.createElement(InnerContent, { tag: "a", attrs: this.buildCellNavLinkAttrs(context, cell.date, cell.rowUnit), className: internal$1.joinClassNames('fc-cell-inner fc-padding-md', props.isSticky && 'fc-sticky-s'), elRef: this.innerElRef }))));
|
|
944
|
+
hiddenGroups.map((hiddenGroup) => (preact.createElement(TimelineEventHarness, { key: hiddenGroup.key, style: {
|
|
945
|
+
top: hiddenGroupTops.get(hiddenGroup.key) || 0,
|
|
946
|
+
insetInlineStart: hiddenGroup.start,
|
|
947
|
+
width: hiddenGroup.end - hiddenGroup.start,
|
|
948
|
+
}, heightRef: moreLinkHeightRefMap.createRef(hiddenGroup.key) },
|
|
949
|
+
preact.createElement(TimelineLaneMoreLink, { hiddenSegs: hiddenGroup.segs, dateProfile: props.dateProfile, nowDate: props.nowDate, todayRange: props.todayRange, isTimeScale: props.tDateProfile.isTimeScale, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection, resourceId: props.resourceId }))))));
|
|
941
950
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
this.detachSize = internal$1.watchSize(innerEl, (width, height) => {
|
|
946
|
-
internal$1.setRef(props.innerWidthRef, width);
|
|
947
|
-
internal$1.setRef(props.innerHeightRef, height);
|
|
948
|
-
// HACK for sticky-centering
|
|
949
|
-
innerEl.style.left = innerEl.style.right =
|
|
950
|
-
(props.isCentered && props.isSticky)
|
|
951
|
-
? `calc(50% - ${width / 2}px)`
|
|
952
|
-
: '';
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
componentWillUnmount() {
|
|
956
|
-
const { props } = this;
|
|
957
|
-
this.detachSize();
|
|
958
|
-
internal$1.setRef(props.innerWidthRef, null);
|
|
959
|
-
internal$1.setRef(props.innerHeightRef, null);
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
// Utils
|
|
963
|
-
// -------------------------------------------------------------------------------------------------
|
|
964
|
-
function buildCellNavLinkAttrs(context, cellDate, rowUnit) {
|
|
965
|
-
return (rowUnit && rowUnit !== 'time')
|
|
966
|
-
? internal$1.buildNavLinkAttrs(context, cellDate, rowUnit)
|
|
967
|
-
: {};
|
|
968
|
-
}
|
|
969
|
-
function renderInnerContent(renderProps) {
|
|
970
|
-
return renderProps.text;
|
|
971
|
-
}
|
|
972
|
-
function refineRenderProps(input) {
|
|
973
|
-
return {
|
|
974
|
-
level: input.level,
|
|
975
|
-
date: input.dateEnv.toDate(input.dateMarker),
|
|
976
|
-
view: input.viewApi,
|
|
977
|
-
text: input.text,
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
class TimelineHeaderRow extends internal$1.BaseComponent {
|
|
982
|
-
constructor() {
|
|
983
|
-
super(...arguments);
|
|
984
|
-
// refs
|
|
985
|
-
this.innerWidthRefMap = new internal$1.RefMap(() => {
|
|
986
|
-
internal$1.afterSize(this.handleInnerWidths);
|
|
987
|
-
});
|
|
988
|
-
this.innerHeightRefMap = new internal$1.RefMap(() => {
|
|
989
|
-
internal$1.afterSize(this.handleInnerHeights);
|
|
990
|
-
});
|
|
991
|
-
this.handleInnerWidths = () => {
|
|
992
|
-
const innerWidthMap = this.innerWidthRefMap.current;
|
|
993
|
-
let max = 0;
|
|
994
|
-
for (const innerWidth of innerWidthMap.values()) {
|
|
995
|
-
max = Math.max(max, innerWidth);
|
|
996
|
-
}
|
|
997
|
-
// TODO: ensure not equal?
|
|
998
|
-
internal$1.setRef(this.props.innerWidthRef, max);
|
|
999
|
-
};
|
|
1000
|
-
this.handleInnerHeights = () => {
|
|
1001
|
-
const innerHeightMap = this.innerHeightRefMap.current;
|
|
1002
|
-
let max = 0;
|
|
1003
|
-
for (const innerHeight of innerHeightMap.values()) {
|
|
1004
|
-
max = Math.max(max, innerHeight);
|
|
1005
|
-
}
|
|
1006
|
-
// TODO: ensure not equal?
|
|
1007
|
-
internal$1.setRef(this.props.innerHeighRef, max);
|
|
1008
|
-
};
|
|
951
|
+
/*
|
|
952
|
+
componentDidMount(): void {
|
|
953
|
+
// might want to do firedTotalHeight, but won't be ready on first render
|
|
1009
954
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
// TODO: make this part of the cell obj?
|
|
1017
|
-
// TODO: rowUnit seems wrong sometimes. says 'month' when it should be day
|
|
1018
|
-
// TODO: rowUnit is relevant to whole row. put it on a row object, not the cells
|
|
1019
|
-
// TODO: use rowUnit to key the Row itself?
|
|
1020
|
-
const key = cell.rowUnit + ':' + cell.date.toISOString();
|
|
1021
|
-
return (preact.createElement(TimelineHeaderCell, { key: key, cell: cell, rowLevel: props.rowLevel, dateProfile: props.dateProfile, tDateProfile: props.tDateProfile, todayRange: props.todayRange, nowDate: props.nowDate, isCentered: isCentered, isSticky: isSticky, borderStart: Boolean(cellI),
|
|
1022
|
-
// refs
|
|
1023
|
-
innerWidthRef: innerWidthRefMap.createRef(key), innerHeightRef: innerHeightRefMap.createRef(key),
|
|
1024
|
-
// dimensions
|
|
1025
|
-
slotWidth: props.slotWidth }));
|
|
1026
|
-
})));
|
|
955
|
+
*/
|
|
956
|
+
componentDidUpdate() {
|
|
957
|
+
if (this.totalHeight !== this.firedTotalHeight) {
|
|
958
|
+
this.firedTotalHeight = this.totalHeight;
|
|
959
|
+
internal$1.setRef(this.props.heightRef, this.totalHeight);
|
|
960
|
+
}
|
|
1027
961
|
}
|
|
1028
962
|
componentWillUnmount() {
|
|
1029
|
-
internal$1.setRef(this.props.
|
|
1030
|
-
internal$1.setRef(this.props.innerHeighRef, null);
|
|
963
|
+
internal$1.setRef(this.props.heightRef, null);
|
|
1031
964
|
}
|
|
1032
965
|
}
|
|
1033
966
|
|
|
1034
|
-
class
|
|
967
|
+
class TimelineBg extends internal$1.BaseComponent {
|
|
1035
968
|
render() {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
969
|
+
let { props } = this;
|
|
970
|
+
let highlightSeg = [].concat(props.eventResizeSegs || [], props.dateSelectionSegs);
|
|
971
|
+
return (preact.createElement(preact.Fragment, null,
|
|
972
|
+
this.renderSegs(props.businessHourSegs || [], 'non-business'),
|
|
973
|
+
this.renderSegs(props.bgEventSegs || [], 'bg-event'),
|
|
974
|
+
this.renderSegs(highlightSeg, 'highlight')));
|
|
1042
975
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
976
|
+
renderSegs(segs, fillType) {
|
|
977
|
+
let { tDateProfile, todayRange, nowDate, slotWidth } = this.props;
|
|
978
|
+
let { dateEnv, options } = this.context;
|
|
979
|
+
return (preact.createElement(preact.Fragment, null, segs.map((seg) => {
|
|
980
|
+
let hStyle = {};
|
|
981
|
+
if (slotWidth != null) {
|
|
982
|
+
let segHorizontal = computeSegHorizontals(seg, undefined, dateEnv, tDateProfile, slotWidth);
|
|
983
|
+
hStyle = { insetInlineStart: segHorizontal.start, width: segHorizontal.size };
|
|
984
|
+
}
|
|
985
|
+
return (preact.createElement("div", { key: internal$1.buildEventRangeKey(seg.eventRange), className: classNames__default["default"].fillY, style: hStyle }, fillType === 'bg-event' ? (preact.createElement(internal$1.BgEvent, Object.assign({ eventRange: seg.eventRange, isStart: seg.isStart, isEnd: seg.isEnd, isVertical: false }, internal$1.getEventRangeMeta(seg.eventRange, todayRange, nowDate)))) : (internal$1.renderFill(fillType, options))));
|
|
986
|
+
})));
|
|
1052
987
|
}
|
|
1053
988
|
}
|
|
1054
989
|
|
|
@@ -1066,46 +1001,34 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1066
1001
|
internal$1.afterSize(this.handleSlotInnerWidths);
|
|
1067
1002
|
});
|
|
1068
1003
|
this.scrollTime = null;
|
|
1004
|
+
this.slicer = new TimelineLaneSlicer();
|
|
1069
1005
|
// Sizing
|
|
1070
1006
|
// -----------------------------------------------------------------------------------------------
|
|
1071
|
-
this.handleBodySlotInnerWidth = (innerWidth) => {
|
|
1072
|
-
this.bodySlotInnerWidth = innerWidth;
|
|
1073
|
-
internal$1.afterSize(this.handleSlotInnerWidths);
|
|
1074
|
-
};
|
|
1075
1007
|
this.handleSlotInnerWidths = () => {
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
this.setState({ slotInnerWidth });
|
|
1008
|
+
const headerSlotInnerWidth = this.headerRowInnerWidthMap.current.get(this.tDateProfile.cellRows.length - 1);
|
|
1009
|
+
if (headerSlotInnerWidth != null && headerSlotInnerWidth !== this.state.slotInnerWidth) {
|
|
1010
|
+
this.setState({ slotInnerWidth: headerSlotInnerWidth });
|
|
1080
1011
|
}
|
|
1081
1012
|
};
|
|
1082
|
-
this.
|
|
1013
|
+
this.handleTotalWidth = (totalWidth) => {
|
|
1083
1014
|
this.setState({
|
|
1084
|
-
|
|
1015
|
+
totalWidth,
|
|
1085
1016
|
});
|
|
1086
1017
|
};
|
|
1087
|
-
this.
|
|
1018
|
+
this.handleClientWidth = (clientWidth) => {
|
|
1088
1019
|
this.setState({
|
|
1089
|
-
|
|
1020
|
+
clientWidth,
|
|
1090
1021
|
});
|
|
1091
1022
|
};
|
|
1092
|
-
this.
|
|
1023
|
+
this.handleTimeScrollRequest = (scrollTime) => {
|
|
1093
1024
|
this.scrollTime = scrollTime;
|
|
1094
|
-
this.
|
|
1025
|
+
this.applyTimeScroll();
|
|
1095
1026
|
};
|
|
1096
|
-
this.
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
let x = timeToCoord(scrollTime, context.dateEnv, props.dateProfile, tDateProfile, slotWidth);
|
|
1100
|
-
if (x) {
|
|
1101
|
-
x += 1; // overcome border. TODO: DRY this up
|
|
1102
|
-
}
|
|
1103
|
-
this.syncedScroller.scrollTo({ x });
|
|
1027
|
+
this.handleTimeScrollEnd = (isUser) => {
|
|
1028
|
+
if (isUser) {
|
|
1029
|
+
this.scrollTime = null;
|
|
1104
1030
|
}
|
|
1105
1031
|
};
|
|
1106
|
-
this.clearScroll = () => {
|
|
1107
|
-
this.scrollTime = null;
|
|
1108
|
-
};
|
|
1109
1032
|
// Hit System
|
|
1110
1033
|
// -----------------------------------------------------------------------------------------------
|
|
1111
1034
|
this.handeBodyEl = (el) => {
|
|
@@ -1121,6 +1044,10 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1121
1044
|
render() {
|
|
1122
1045
|
const { props, state, context } = this;
|
|
1123
1046
|
const { options } = context;
|
|
1047
|
+
const { totalWidth, clientWidth } = state;
|
|
1048
|
+
const endScrollbarWidth = (totalWidth != null && clientWidth != null)
|
|
1049
|
+
? totalWidth - clientWidth
|
|
1050
|
+
: undefined;
|
|
1124
1051
|
/* date */
|
|
1125
1052
|
const tDateProfile = this.tDateProfile = this.buildTimelineDateProfile(props.dateProfile, context.dateEnv, options, context.dateProfileGenerator);
|
|
1126
1053
|
const { cellRows } = tDateProfile;
|
|
@@ -1131,39 +1058,65 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1131
1058
|
const stickyFooterScrollbar = !props.forPrint && internal$1.getStickyFooterScrollbar(options);
|
|
1132
1059
|
/* table positions */
|
|
1133
1060
|
const [canvasWidth, slotWidth] = this.computeSlotWidth(tDateProfile.slotCnt, tDateProfile.slotsPerLabel, options.slotMinWidth, state.slotInnerWidth, // is ACTUALLY the label width. rename?
|
|
1134
|
-
|
|
1061
|
+
clientWidth);
|
|
1135
1062
|
this.slotWidth = slotWidth;
|
|
1063
|
+
/* sliced */
|
|
1064
|
+
let slicedProps = this.slicer.sliceProps(props, props.dateProfile, tDateProfile.isTimeScale ? null : options.nextDayThreshold, context, // wish we didn't have to pass in the rest of the args...
|
|
1065
|
+
props.dateProfile, context.dateProfileGenerator, tDateProfile, context.dateEnv);
|
|
1136
1066
|
return (preact.createElement(internal$1.NowTimer, { unit: timerUnit }, (nowDate, todayRange) => {
|
|
1137
1067
|
const enableNowIndicator = // TODO: DRY
|
|
1138
1068
|
options.nowIndicator &&
|
|
1139
1069
|
slotWidth != null &&
|
|
1140
1070
|
internal$1.rangeContainsMarker(props.dateProfile.currentRange, nowDate);
|
|
1141
|
-
return (preact.createElement(internal$1.ViewContainer, { viewSpec: context.viewSpec, className: internal$1.
|
|
1142
|
-
// HACK for Safari print-mode, where
|
|
1071
|
+
return (preact.createElement(internal$1.ViewContainer, { viewSpec: context.viewSpec, className: internal$1.joinArrayishClassNames(
|
|
1072
|
+
// HACK for Safari print-mode, where noScrollbars won't take effect for
|
|
1143
1073
|
// the below Scrollers if they have liquid flex height
|
|
1144
|
-
!props.forPrint &&
|
|
1145
|
-
preact.createElement(
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1074
|
+
!props.forPrint && classNames__default["default"].flexCol, props.className, options.tableClass, classNames__default["default"].isolate), borderlessX: props.borderlessX, borderlessTop: props.borderlessTop, borderlessBottom: props.borderlessBottom, noEdgeEffects: props.noEdgeEffects },
|
|
1075
|
+
preact.createElement("div", { className: core.joinClassNames(internal$1.generateClassName(options.tableHeaderClass, {
|
|
1076
|
+
isSticky: stickyHeaderDates,
|
|
1077
|
+
}), props.borderlessX && classNames__default["default"].borderlessX, classNames__default["default"].flexCol, stickyHeaderDates && classNames__default["default"].tableHeaderSticky), style: {
|
|
1078
|
+
zIndex: 1,
|
|
1079
|
+
} },
|
|
1080
|
+
preact.createElement(internal$1.Scroller, { horizontal: true, hideScrollbars: true, className: classNames__default["default"].flexRow, ref: this.headerScrollerRef },
|
|
1081
|
+
preact.createElement("div", {
|
|
1082
|
+
// TODO: DRY
|
|
1083
|
+
className: core.joinClassNames(classNames__default["default"].rel, // origin for now-indicator
|
|
1084
|
+
canvasWidth == null && classNames__default["default"].liquid), style: { width: canvasWidth } },
|
|
1085
|
+
cellRows.map((cells, rowIndex) => {
|
|
1086
|
+
const rowLevel = cellRows.length - rowIndex - 1;
|
|
1087
|
+
return (preact.createElement(TimelineHeaderRow, { key: rowIndex, dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange, rowLevel: rowLevel, cells: cells, slotWidth: slotWidth, innerWidthRef: this.headerRowInnerWidthMap.createRef(rowIndex) }));
|
|
1088
|
+
}),
|
|
1089
|
+
enableNowIndicator && (preact.createElement(TimelineNowIndicatorArrow, { tDateProfile: tDateProfile, nowDate: nowDate, slotWidth: slotWidth }))),
|
|
1090
|
+
Boolean(endScrollbarWidth) && (preact.createElement("div", { className: internal$1.joinArrayishClassNames(internal$1.generateClassName(options.fillerClass, { isHeader: true }), classNames__default["default"].borderOnlyS), style: { minWidth: endScrollbarWidth } }))),
|
|
1091
|
+
preact.createElement("div", { className: internal$1.generateClassName(options.slotHeaderDividerClass, {
|
|
1092
|
+
isHeader: true,
|
|
1093
|
+
options: { dayMinWidth: options.dayMinWidth },
|
|
1094
|
+
}) })),
|
|
1095
|
+
preact.createElement(internal$1.Scroller, { vertical: verticalScrolling, horizontal: true, hideScrollbars: stickyFooterScrollbar ||
|
|
1096
|
+
props.forPrint // prevents blank space in print-view on Safari
|
|
1097
|
+
, className: internal$1.joinArrayishClassNames(options.tableBodyClass, props.borderlessX && classNames__default["default"].borderlessX, stickyHeaderDates && classNames__default["default"].borderlessTop, (stickyHeaderDates || props.noEdgeEffects) && classNames__default["default"].noEdgeEffects, classNames__default["default"].flexCol, verticalScrolling && classNames__default["default"].liquid), style: {
|
|
1098
|
+
zIndex: 0,
|
|
1099
|
+
}, ref: this.bodyScrollerRef, clientWidthRef: this.handleClientWidth },
|
|
1100
|
+
preact.createElement("div", { "aria-label": options.eventsHint, className: core.joinClassNames(classNames__default["default"].rel, // for canvas origin?
|
|
1101
|
+
classNames__default["default"].grow), style: { width: canvasWidth }, ref: this.handeBodyEl },
|
|
1158
1102
|
preact.createElement(TimelineSlats, { dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
|
|
1159
|
-
// ref
|
|
1160
|
-
innerWidthRef: this.handleBodySlotInnerWidth,
|
|
1161
1103
|
// dimensions
|
|
1162
1104
|
slotWidth: slotWidth }),
|
|
1163
|
-
preact.createElement(
|
|
1105
|
+
preact.createElement(TimelineBg, { tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
|
|
1106
|
+
// content
|
|
1107
|
+
bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventResizeSegs: slicedProps.eventResize ? slicedProps.eventResize.segs : null,
|
|
1108
|
+
// dimensions
|
|
1109
|
+
slotWidth: slotWidth }),
|
|
1110
|
+
preact.createElement("div", { className: internal$1.joinArrayishClassNames(options.timelineTopClass) }),
|
|
1111
|
+
preact.createElement(TimelineFg, { dateProfile: props.dateProfile, tDateProfile: tDateProfile, nowDate: nowDate, todayRange: todayRange,
|
|
1112
|
+
// content
|
|
1113
|
+
fgEventSegs: slicedProps.fgEventSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection,
|
|
1114
|
+
// dimensions
|
|
1115
|
+
slotWidth: slotWidth }),
|
|
1116
|
+
preact.createElement("div", { className: internal$1.joinArrayishClassNames(options.timelineBottomClass) }),
|
|
1164
1117
|
enableNowIndicator && (preact.createElement(TimelineNowIndicatorLine, { tDateProfile: tDateProfile, nowDate: nowDate, slotWidth: slotWidth })))),
|
|
1165
|
-
stickyFooterScrollbar && (preact.createElement(internal$1.
|
|
1166
|
-
|
|
1118
|
+
Boolean(stickyFooterScrollbar) && (preact.createElement(internal$1.FooterScrollbar, { isSticky: true, canvasWidth: canvasWidth, scrollerRef: this.footerScrollerRef })),
|
|
1119
|
+
preact.createElement(internal$1.Ruler, { widthRef: this.handleTotalWidth })));
|
|
1167
1120
|
}));
|
|
1168
1121
|
}
|
|
1169
1122
|
// Lifecycle
|
|
@@ -1172,8 +1125,8 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1172
1125
|
this.syncedScroller = new internal$2.ScrollerSyncer(true); // horizontal=true
|
|
1173
1126
|
this.updateSyncedScroller();
|
|
1174
1127
|
this.resetScroll();
|
|
1175
|
-
this.context.emitter.on('_timeScrollRequest', this.
|
|
1176
|
-
this.syncedScroller.addScrollEndListener(this.
|
|
1128
|
+
this.context.emitter.on('_timeScrollRequest', this.handleTimeScrollRequest);
|
|
1129
|
+
this.syncedScroller.addScrollEndListener(this.handleTimeScrollEnd);
|
|
1177
1130
|
}
|
|
1178
1131
|
componentDidUpdate(prevProps) {
|
|
1179
1132
|
this.updateSyncedScroller();
|
|
@@ -1182,13 +1135,13 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1182
1135
|
}
|
|
1183
1136
|
else {
|
|
1184
1137
|
// TODO: inefficient to update so often
|
|
1185
|
-
this.
|
|
1138
|
+
this.applyTimeScroll();
|
|
1186
1139
|
}
|
|
1187
1140
|
}
|
|
1188
1141
|
componentWillUnmount() {
|
|
1189
1142
|
this.syncedScroller.destroy();
|
|
1190
|
-
this.context.emitter.off('_timeScrollRequest', this.
|
|
1191
|
-
this.syncedScroller.removeScrollEndListener(this.
|
|
1143
|
+
this.context.emitter.off('_timeScrollRequest', this.handleTimeScrollRequest);
|
|
1144
|
+
this.syncedScroller.removeScrollEndListener(this.handleTimeScrollEnd);
|
|
1192
1145
|
}
|
|
1193
1146
|
// Scrolling
|
|
1194
1147
|
// -----------------------------------------------------------------------------------------------
|
|
@@ -1200,13 +1153,23 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1200
1153
|
]);
|
|
1201
1154
|
}
|
|
1202
1155
|
resetScroll() {
|
|
1203
|
-
this.
|
|
1156
|
+
this.handleTimeScrollRequest(this.context.options.scrollTime);
|
|
1157
|
+
}
|
|
1158
|
+
applyTimeScroll() {
|
|
1159
|
+
const { props, context, tDateProfile, scrollTime, slotWidth } = this;
|
|
1160
|
+
if (scrollTime != null && slotWidth != null) {
|
|
1161
|
+
let x = timeToCoord(scrollTime, context.dateEnv, props.dateProfile, tDateProfile, slotWidth);
|
|
1162
|
+
if (x) {
|
|
1163
|
+
x += 1; // overcome border. TODO: DRY this up
|
|
1164
|
+
}
|
|
1165
|
+
this.syncedScroller.scrollTo({ x });
|
|
1166
|
+
}
|
|
1204
1167
|
}
|
|
1205
|
-
queryHit(positionLeft, positionTop, elWidth, elHeight) {
|
|
1168
|
+
queryHit(isRtl, positionLeft, positionTop, elWidth, elHeight) {
|
|
1206
1169
|
const { props, context, tDateProfile, slotWidth } = this;
|
|
1207
1170
|
const { dateEnv } = context;
|
|
1208
1171
|
if (slotWidth) {
|
|
1209
|
-
const x =
|
|
1172
|
+
const x = isRtl ? elWidth - positionLeft : positionLeft;
|
|
1210
1173
|
const slatIndex = Math.floor(x / slotWidth);
|
|
1211
1174
|
const slatX = slatIndex * slotWidth;
|
|
1212
1175
|
const partial = (x - slatX) / slotWidth; // floating point number between 0 and 1
|
|
@@ -1218,7 +1181,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1218
1181
|
let startCoord = slatIndex * slotWidth + (snapWidth * localSnapIndex);
|
|
1219
1182
|
let endCoord = startCoord + snapWidth;
|
|
1220
1183
|
let left, right;
|
|
1221
|
-
if (
|
|
1184
|
+
if (isRtl) {
|
|
1222
1185
|
left = elWidth - endCoord;
|
|
1223
1186
|
right = elWidth - startCoord;
|
|
1224
1187
|
}
|
|
@@ -1238,8 +1201,7 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1238
1201
|
top: 0,
|
|
1239
1202
|
bottom: elHeight,
|
|
1240
1203
|
},
|
|
1241
|
-
|
|
1242
|
-
dayEl: this.bodyEl.querySelectorAll('.fc-timeline-slot')[slatIndex],
|
|
1204
|
+
getDayEl: () => getTimelineSlotEl(this.bodyEl, slatIndex),
|
|
1243
1205
|
layer: 0,
|
|
1244
1206
|
};
|
|
1245
1207
|
}
|
|
@@ -1247,14 +1209,17 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1247
1209
|
}
|
|
1248
1210
|
}
|
|
1249
1211
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1212
|
+
const OPTION_REFINERS = {
|
|
1213
|
+
timelineTopClass: internal$1.identity,
|
|
1214
|
+
timelineBottomClass: internal$1.identity,
|
|
1215
|
+
};
|
|
1252
1216
|
|
|
1253
1217
|
var plugin = core.createPlugin({
|
|
1254
1218
|
name: '@fullcalendar/timeline',
|
|
1255
|
-
premiumReleaseDate: '
|
|
1219
|
+
premiumReleaseDate: '2025-12-20',
|
|
1256
1220
|
deps: [premiumCommonPlugin__default["default"]],
|
|
1257
1221
|
initialView: 'timelineDay',
|
|
1222
|
+
optionRefiners: OPTION_REFINERS,
|
|
1258
1223
|
views: {
|
|
1259
1224
|
timeline: {
|
|
1260
1225
|
component: TimelineView,
|
|
@@ -1283,18 +1248,17 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1283
1248
|
var internal = {
|
|
1284
1249
|
__proto__: null,
|
|
1285
1250
|
TimelineView: TimelineView,
|
|
1286
|
-
|
|
1287
|
-
|
|
1251
|
+
TimelineFg: TimelineFg,
|
|
1252
|
+
TimelineBg: TimelineBg,
|
|
1288
1253
|
TimelineSlats: TimelineSlats,
|
|
1289
1254
|
buildTimelineDateProfile: buildTimelineDateProfile,
|
|
1290
|
-
createVerticalStyle: createVerticalStyle,
|
|
1291
|
-
createHorizontalStyle: createHorizontalStyle,
|
|
1292
1255
|
computeSlotWidth: computeSlotWidth,
|
|
1293
1256
|
timeToCoord: timeToCoord,
|
|
1294
1257
|
TimelineLaneSlicer: TimelineLaneSlicer,
|
|
1295
1258
|
TimelineHeaderRow: TimelineHeaderRow,
|
|
1296
1259
|
TimelineNowIndicatorArrow: TimelineNowIndicatorArrow,
|
|
1297
|
-
TimelineNowIndicatorLine: TimelineNowIndicatorLine
|
|
1260
|
+
TimelineNowIndicatorLine: TimelineNowIndicatorLine,
|
|
1261
|
+
getTimelineSlotEl: getTimelineSlotEl
|
|
1298
1262
|
};
|
|
1299
1263
|
|
|
1300
1264
|
core.globalPlugins.push(plugin);
|
|
@@ -1306,4 +1270,4 @@ FullCalendar.Timeline = (function (exports, core, premiumCommonPlugin, internal$
|
|
|
1306
1270
|
|
|
1307
1271
|
return exports;
|
|
1308
1272
|
|
|
1309
|
-
})({}, FullCalendar, FullCalendar.PremiumCommon, FullCalendar.Internal, FullCalendar.Preact, FullCalendar.ScrollGrid.Internal);
|
|
1273
|
+
})({}, FullCalendar, FullCalendar.PremiumCommon, FullCalendar.Internal, FullCalendar.InternalClassNames, FullCalendar.Preact, FullCalendar.ScrollGrid.Internal);
|