@fullcalendar/daygrid 6.1.14 → 7.0.0-beta.0
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.global.js +867 -679
- package/index.global.min.js +2 -2
- package/index.js +2 -2
- package/internal.cjs +901 -713
- package/internal.d.ts +206 -80
- package/internal.js +890 -711
- package/package.json +2 -2
package/internal.js
CHANGED
|
@@ -1,128 +1,251 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createRef, createElement, Fragment } from '@fullcalendar/core/preact.js';
|
|
1
|
+
import { injectStyles, Slicer, DateProfileGenerator, addWeeks, addDays, diffWeeks, DaySeriesModel, DayTableModel, fracToCssDim, BaseComponent, getDateMeta, buildNavLinkAttrs, ContentContainer, getDayClassNames, formatDayString, watchHeight, setRef, createFormatter, StandardEvent, buildSegTimeText, EventContainer, getSegAnchorAttrs, MoreLinkContainer, getSegMeta, DateComponent, DayCellContainer, hasCustomDayCellContent, addMs, SegHierarchy, buildEntryKey, intersectSpans, RefMap, afterSize, sortEventSegs, WeekNumberContainer, buildEventRangeKey, BgEvent, renderFill, memoize, getIsHeightAuto, watchWidth, getStickyHeaderDates, Scroller, getStickyFooterScrollbar, getScrollerSyncerClass, ScrollResponder, ViewContainer, NowTimer } from '@fullcalendar/core/internal.js';
|
|
2
|
+
import { createRef, createElement, Fragment, Component } from '@fullcalendar/core/preact.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TableView extends DateComponent {
|
|
4
|
+
var css_248z = ":root{--fc-daygrid-event-dot-width:8px}.fc-daygrid-week-number{background-color:var(--fc-neutral-bg-color);color:var(--fc-neutral-text-color);min-width:1.5em;padding:2px;position:absolute;text-align:center;top:0;z-index:5}.fc-daygrid-cell.fc-day-today{background-color:var(--fc-today-bg-color)}.fc-daygrid-row-spacious .fc-daygrid-cell-inner{min-height:3em}.fc-daygrid-cell-header{display:flex;flex-direction:row-reverse}.fc-day-other .fc-daygrid-cell-header{opacity:.3}.fc-daygrid-cell-number{padding:4px;position:relative;z-index:4}.fc-daygrid-month-start{font-size:1.1em;font-weight:700}.fc-daygrid-cell-footer{align-items:flex-start;display:flex;flex-direction:column;font-size:.85em;margin:0 2px}.fc-daygrid-row-spacious .fc-daygrid-cell-footer{margin-bottom:1em!important}.fc-daygrid-row-compact .fc-daygrid-cell-footer{align-items:stretch}.fc-daygrid-more-link{border-radius:3px;cursor:pointer;line-height:1;margin-top:1px;max-width:100%;overflow:hidden;padding:2px;position:relative;white-space:nowrap;z-index:4}.fc-daygrid-more-link:hover{background-color:rgba(0,0,0,.1)}.fc-daygrid-row-compact .fc-daygrid-more-link{border:1px solid var(--fc-event-border-color);padding:1px}.fc-daygrid-cell .fc-non-business{z-index:1}.fc-daygrid-cell .fc-bg-event{z-index:2}.fc-daygrid-cell .fc-highlight{z-index:3}.fc-more-popover .fc-popover-body{min-width:220px;padding:10px}.fc-daygrid-event{border-radius:3px;font-size:var(--fc-small-font-size);margin-top:1px;z-index:6}.fc-daygrid-event.fc-event-mirror{z-index:7}.fc-direction-ltr .fc-daygrid-event.fc-event-start,.fc-direction-rtl .fc-daygrid-event.fc-event-end{margin-left:2px}.fc-direction-ltr .fc-daygrid-event.fc-event-end,.fc-direction-rtl .fc-daygrid-event.fc-event-start{margin-right:2px}.fc-direction-ltr .fc-daygrid-event .fc-event-time{margin-right:3px}.fc-direction-rtl .fc-daygrid-event .fc-event-time{margin-left:3px}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-start),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-end){border-bottom-left-radius:0;border-left-width:0;border-top-left-radius:0}.fc-direction-ltr .fc-daygrid-block-event:not(.fc-event-end),.fc-direction-rtl .fc-daygrid-block-event:not(.fc-event-start){border-bottom-right-radius:0;border-right-width:0;border-top-right-radius:0}.fc-daygrid-block-event .fc-event-time{font-weight:700}.fc-daygrid-block-event .fc-event-time,.fc-daygrid-block-event .fc-event-title{padding:1px}.fc-daygrid-dot-event{align-items:center;direction:row;display:flex;padding:2px 0;position:relative}.fc-daygrid-dot-event.fc-event-mirror,.fc-daygrid-dot-event:hover{background:rgba(0,0,0,.1)}.fc-daygrid-event-dot{border:calc(var(--fc-daygrid-event-dot-width)/2) solid var(--fc-event-border-color);border-radius:calc(var(--fc-daygrid-event-dot-width)/2);box-sizing:content-box;height:0;margin:0 4px;width:0}.fc-daygrid-dot-event .fc-event-time,.fc-daygrid-dot-event .fc-event-title{overflow:hidden;white-space:nowrap}.fc-daygrid-dot-event .fc-event-title{flex-basis:0;flex-grow:1;font-weight:700;min-width:0}";
|
|
5
|
+
injectStyles(css_248z);
|
|
6
|
+
|
|
7
|
+
class DayTableSlicer extends Slicer {
|
|
9
8
|
constructor() {
|
|
10
9
|
super(...arguments);
|
|
11
|
-
this.
|
|
10
|
+
this.forceDayIfListItem = true;
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
sections.push({
|
|
30
|
-
type: 'body',
|
|
31
|
-
key: 'body',
|
|
32
|
-
liquid: true,
|
|
33
|
-
chunk: { content: bodyContent },
|
|
12
|
+
sliceRange(dateRange, dayTableModel) {
|
|
13
|
+
return dayTableModel.sliceRange(dateRange);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class TableDateProfileGenerator extends DateProfileGenerator {
|
|
18
|
+
// Computes the date range that will be rendered
|
|
19
|
+
buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay) {
|
|
20
|
+
let renderRange = super.buildRenderRange(currentRange, currentRangeUnit, isRangeAllDay);
|
|
21
|
+
let { props } = this;
|
|
22
|
+
return buildDayTableRenderRange({
|
|
23
|
+
currentRange: renderRange,
|
|
24
|
+
snapToWeek: /^(year|month)$/.test(currentRangeUnit),
|
|
25
|
+
fixedWeekCount: props.fixedWeekCount,
|
|
26
|
+
dateEnv: props.dateEnv,
|
|
34
27
|
});
|
|
35
|
-
return (createElement(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
|
|
36
|
-
createElement(SimpleScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, collapsibleWidth: props.forPrint, cols: [] /* TODO: make optional? */, sections: sections })));
|
|
37
28
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
29
|
+
}
|
|
30
|
+
function buildDayTableRenderRange(props) {
|
|
31
|
+
let { dateEnv, currentRange } = props;
|
|
32
|
+
let { start, end } = currentRange;
|
|
33
|
+
let endOfWeek;
|
|
34
|
+
// year and month views should be aligned with weeks. this is already done for week
|
|
35
|
+
if (props.snapToWeek) {
|
|
36
|
+
start = dateEnv.startOfWeek(start);
|
|
37
|
+
// make end-of-week if not already
|
|
38
|
+
endOfWeek = dateEnv.startOfWeek(end);
|
|
39
|
+
if (endOfWeek.valueOf() !== end.valueOf()) {
|
|
40
|
+
end = addWeeks(endOfWeek, 1);
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
}
|
|
43
|
+
// ensure 6 weeks
|
|
44
|
+
if (props.fixedWeekCount) {
|
|
45
|
+
// TODO: instead of these date-math gymnastics (for multimonth view),
|
|
46
|
+
// compute dateprofiles of all months, then use start of first and end of last.
|
|
47
|
+
let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(addDays(currentRange.end, -1)));
|
|
48
|
+
let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
|
|
49
|
+
diffWeeks(lastMonthRenderStart, end));
|
|
50
|
+
end = addWeeks(end, 6 - rowCnt);
|
|
51
|
+
}
|
|
52
|
+
return { start, end };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function renderInner(renderProps) {
|
|
56
|
+
return renderProps.text;
|
|
57
|
+
}
|
|
58
|
+
function buildDayTableModel(dateProfile, dateProfileGenerator) {
|
|
59
|
+
let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
|
|
60
|
+
return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
|
|
61
|
+
}
|
|
62
|
+
function computeColWidth(colCnt, colMinWidth, viewportWidth) {
|
|
63
|
+
if (viewportWidth == null) {
|
|
64
|
+
return [undefined, undefined];
|
|
65
|
+
}
|
|
66
|
+
const colTempWidth = viewportWidth / colCnt;
|
|
67
|
+
if (colTempWidth < colMinWidth) {
|
|
68
|
+
return [colMinWidth * colCnt, colMinWidth];
|
|
69
|
+
}
|
|
70
|
+
return [viewportWidth, undefined];
|
|
71
|
+
}
|
|
72
|
+
function buildHeaderTiers(dates, datesRepDistinctDays) {
|
|
73
|
+
return [
|
|
74
|
+
datesRepDistinctDays
|
|
75
|
+
? dates.map((date) => ({ colSpan: 1, date }))
|
|
76
|
+
: dates.map((date) => ({ colSpan: 1, dow: date.getUTCDay() }))
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
// Positioning
|
|
80
|
+
// -------------------------------------------------------------------------------------------------
|
|
81
|
+
function computeTopFromDate(date, cellRows, rowHeightMap) {
|
|
82
|
+
let top = 0;
|
|
83
|
+
for (const cells of cellRows) {
|
|
84
|
+
const start = cells[0].date;
|
|
85
|
+
const end = cells[cells.length - 1].date;
|
|
86
|
+
const key = start.toISOString();
|
|
87
|
+
if (date >= start && date <= end) {
|
|
88
|
+
return top;
|
|
59
89
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
90
|
+
const rowHeight = rowHeightMap.get(key);
|
|
91
|
+
if (rowHeight == null) {
|
|
92
|
+
return; // denote unknown
|
|
93
|
+
}
|
|
94
|
+
top += rowHeight;
|
|
95
|
+
}
|
|
96
|
+
return top;
|
|
97
|
+
}
|
|
98
|
+
function computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl) {
|
|
99
|
+
let left;
|
|
100
|
+
let right;
|
|
101
|
+
let width;
|
|
102
|
+
if (colWidth != null) {
|
|
103
|
+
width = (seg.lastCol - seg.firstCol + 1) * colWidth;
|
|
104
|
+
if (isRtl) {
|
|
105
|
+
right = seg.firstCol * colWidth;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
left = seg.firstCol * colWidth;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const colWidthFrac = 1 / colCnt;
|
|
113
|
+
width = fracToCssDim((seg.lastCol - seg.firstCol + 1) * colWidthFrac);
|
|
114
|
+
if (isRtl) {
|
|
115
|
+
right = fracToCssDim(seg.firstCol * colWidthFrac);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
left = fracToCssDim(seg.firstCol * colWidthFrac);
|
|
79
119
|
}
|
|
80
|
-
return (createElement(ViewContainer, { elClasses: ['fc-daygrid'], viewSpec: context.viewSpec },
|
|
81
|
-
createElement(ScrollGrid, { liquid: !props.isHeightAuto && !props.forPrint, forPrint: props.forPrint, collapsibleWidth: props.forPrint, colGroups: [{ cols: [{ span: colCnt, minWidth: dayMinWidth }] }], sections: sections })));
|
|
82
120
|
}
|
|
121
|
+
return { left, right, width };
|
|
122
|
+
}
|
|
123
|
+
function computeColFromPosition(positionLeft, elWidth, colWidth, colCnt, isRtl) {
|
|
124
|
+
const realColWidth = colWidth != null ? colWidth : elWidth / colCnt;
|
|
125
|
+
const colFromLeft = Math.floor(positionLeft / realColWidth);
|
|
126
|
+
const col = isRtl ? (colCnt - colFromLeft - 1) : colFromLeft;
|
|
127
|
+
const left = colFromLeft * realColWidth;
|
|
128
|
+
const right = left + realColWidth;
|
|
129
|
+
return { col, left, right };
|
|
130
|
+
}
|
|
131
|
+
function computeRowFromPosition(positionTop, cellRows, rowHeightMap) {
|
|
132
|
+
let row = 0;
|
|
133
|
+
let top = 0;
|
|
134
|
+
let bottom = 0;
|
|
135
|
+
for (const cells of cellRows) {
|
|
136
|
+
const key = cells[0].key;
|
|
137
|
+
top = bottom;
|
|
138
|
+
bottom = top + rowHeightMap.get(key);
|
|
139
|
+
if (positionTop < bottom) {
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
row++;
|
|
143
|
+
}
|
|
144
|
+
return { row, top, bottom };
|
|
145
|
+
}
|
|
146
|
+
// Hit Element
|
|
147
|
+
// -------------------------------------------------------------------------------------------------
|
|
148
|
+
function getRowEl(rootEl, row) {
|
|
149
|
+
return rootEl.querySelectorAll(':scope > [role=row]')[row];
|
|
150
|
+
}
|
|
151
|
+
function getCellEl(rowEl, col) {
|
|
152
|
+
return rowEl.querySelectorAll(':scope > [role=gridcell]')[col];
|
|
83
153
|
}
|
|
84
154
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
155
|
+
class DateHeaderCell extends BaseComponent {
|
|
156
|
+
constructor() {
|
|
157
|
+
super(...arguments);
|
|
158
|
+
// ref
|
|
159
|
+
this.innerElRef = createRef();
|
|
89
160
|
}
|
|
90
|
-
|
|
91
|
-
|
|
161
|
+
render() {
|
|
162
|
+
let { props, context } = this;
|
|
163
|
+
let { dateProfile, date, extraRenderProps, extraDataAttrs } = props;
|
|
164
|
+
let { dateEnv, options, theme, viewApi } = context;
|
|
165
|
+
let dayMeta = getDateMeta(date, props.todayRange, null, dateProfile);
|
|
166
|
+
let text = dateEnv.format(date, props.dayHeaderFormat);
|
|
167
|
+
let navLinkAttrs = (!dayMeta.isDisabled && props.navLink)
|
|
168
|
+
? buildNavLinkAttrs(context, date)
|
|
169
|
+
: {};
|
|
170
|
+
let renderProps = Object.assign(Object.assign(Object.assign({ date: dateEnv.toDate(date), view: viewApi }, extraRenderProps), { text }), dayMeta);
|
|
171
|
+
return (createElement(ContentContainer, { elTag: 'div', elClasses: [
|
|
172
|
+
...getDayClassNames(dayMeta, theme),
|
|
173
|
+
...(props.extraClassNames || []),
|
|
174
|
+
'fc-header-cell',
|
|
175
|
+
'fc-cell',
|
|
176
|
+
props.colWidth != null ? '' : 'fc-liquid',
|
|
177
|
+
'fc-flex-column',
|
|
178
|
+
'fc-align-center',
|
|
179
|
+
], elAttrs: Object.assign({ 'data-date': !dayMeta.isDisabled ? formatDayString(date) : undefined }, extraDataAttrs), elStyle: {
|
|
180
|
+
width: props.colWidth != null // TODO: DRY
|
|
181
|
+
? props.colWidth * (props.colSpan || 1)
|
|
182
|
+
: undefined,
|
|
183
|
+
}, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContainer) => (createElement("div", { ref: this.innerElRef, className: [
|
|
184
|
+
'fc-flex-column',
|
|
185
|
+
props.isSticky ? 'fc-sticky-x' : '',
|
|
186
|
+
].join(' ') }, !dayMeta.isDisabled && (createElement(InnerContainer, { elTag: "a", elAttrs: navLinkAttrs, elClasses: [
|
|
187
|
+
'fc-cell-inner',
|
|
188
|
+
'fc-padding-sm',
|
|
189
|
+
] }))))));
|
|
190
|
+
}
|
|
191
|
+
componentDidMount() {
|
|
192
|
+
const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
|
|
193
|
+
// TODO: only attach this if refs props present
|
|
194
|
+
this.disconectInnerHeight = watchHeight(innerEl, (height) => {
|
|
195
|
+
setRef(this.props.innerHeightRef, height);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
componentWillUnmount() {
|
|
199
|
+
this.disconectInnerHeight();
|
|
92
200
|
}
|
|
93
|
-
return byRow;
|
|
94
201
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
202
|
+
|
|
203
|
+
function splitSegsByRow(segs, rowCnt) {
|
|
204
|
+
const byRow = [];
|
|
205
|
+
for (let row = 0; row < rowCnt; row++) {
|
|
206
|
+
byRow[row] = [];
|
|
99
207
|
}
|
|
100
|
-
for (
|
|
101
|
-
|
|
208
|
+
for (const seg of segs) {
|
|
209
|
+
byRow[seg.row].push(seg);
|
|
102
210
|
}
|
|
103
|
-
return
|
|
211
|
+
return byRow;
|
|
104
212
|
}
|
|
105
213
|
function splitInteractionByRow(ui, rowCnt) {
|
|
106
|
-
|
|
214
|
+
const byRow = [];
|
|
107
215
|
if (!ui) {
|
|
108
|
-
for (let
|
|
109
|
-
byRow[
|
|
216
|
+
for (let row = 0; row < rowCnt; row++) {
|
|
217
|
+
byRow[row] = null;
|
|
110
218
|
}
|
|
111
219
|
}
|
|
112
220
|
else {
|
|
113
|
-
for (let
|
|
114
|
-
byRow[
|
|
221
|
+
for (let row = 0; row < rowCnt; row++) {
|
|
222
|
+
byRow[row] = {
|
|
115
223
|
affectedInstances: ui.affectedInstances,
|
|
116
224
|
isEvent: ui.isEvent,
|
|
117
225
|
segs: [],
|
|
118
226
|
};
|
|
119
227
|
}
|
|
120
|
-
for (
|
|
228
|
+
for (const seg of ui.segs) {
|
|
121
229
|
byRow[seg.row].segs.push(seg);
|
|
122
230
|
}
|
|
123
231
|
}
|
|
124
232
|
return byRow;
|
|
125
233
|
}
|
|
234
|
+
function splitSegsByCol(segs, colCnt) {
|
|
235
|
+
let byCol = [];
|
|
236
|
+
for (let col = 0; col < colCnt; col++) {
|
|
237
|
+
byCol.push([]);
|
|
238
|
+
}
|
|
239
|
+
for (let seg of segs) {
|
|
240
|
+
for (let col = seg.firstCol; col <= seg.lastCol; col++) {
|
|
241
|
+
if (seg.firstCol !== col) {
|
|
242
|
+
seg = Object.assign(Object.assign({}, seg), { firstCol: col, lastCol: col, isStart: false, isEnd: seg.isEnd && seg.lastCol === col, isStandin: true });
|
|
243
|
+
}
|
|
244
|
+
byCol[col].push(seg);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return byCol;
|
|
248
|
+
}
|
|
126
249
|
|
|
127
250
|
const DEFAULT_TABLE_EVENT_TIME_FORMAT = createFormatter({
|
|
128
251
|
hour: 'numeric',
|
|
@@ -140,14 +263,14 @@ function hasListItemDisplay(seg) {
|
|
|
140
263
|
);
|
|
141
264
|
}
|
|
142
265
|
|
|
143
|
-
class
|
|
266
|
+
class DayGridBlockEvent extends BaseComponent {
|
|
144
267
|
render() {
|
|
145
268
|
let { props } = this;
|
|
146
269
|
return (createElement(StandardEvent, Object.assign({}, props, { elClasses: ['fc-daygrid-event', 'fc-daygrid-block-event', 'fc-h-event'], defaultTimeFormat: DEFAULT_TABLE_EVENT_TIME_FORMAT, defaultDisplayEventEnd: props.defaultDisplayEventEnd, disableResizing: !props.seg.eventRange.def.allDay })));
|
|
147
270
|
}
|
|
148
271
|
}
|
|
149
272
|
|
|
150
|
-
class
|
|
273
|
+
class DayGridListEvent extends BaseComponent {
|
|
151
274
|
render() {
|
|
152
275
|
let { props, context } = this;
|
|
153
276
|
let { options } = context;
|
|
@@ -164,80 +287,83 @@ function renderInnerContent(renderProps) {
|
|
|
164
287
|
createElement("div", { className: "fc-event-title" }, renderProps.event.title || createElement(Fragment, null, "\u00A0"))));
|
|
165
288
|
}
|
|
166
289
|
|
|
167
|
-
class
|
|
168
|
-
constructor() {
|
|
169
|
-
super(...arguments);
|
|
170
|
-
this.compileSegs = memoize(compileSegs);
|
|
171
|
-
}
|
|
290
|
+
class DayGridMoreLink extends BaseComponent {
|
|
172
291
|
render() {
|
|
173
292
|
let { props } = this;
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
293
|
+
return (createElement(MoreLinkContainer, { elClasses: ['fc-daygrid-more-link'], dateProfile: props.dateProfile, todayRange: props.todayRange, allDayDate: props.allDayDate, segs: props.segs, hiddenSegs: props.hiddenSegs, alignmentElRef: props.alignmentElRef, alignGridTop: props.alignGridTop, extraDateSpan: props.extraDateSpan, popoverContent: () => {
|
|
294
|
+
let forcedInvisibleMap = // TODO: more convenient/DRY
|
|
295
|
+
(props.eventDrag ? props.eventDrag.affectedInstances : null) ||
|
|
177
296
|
(props.eventResize ? props.eventResize.affectedInstances : null) ||
|
|
178
297
|
{};
|
|
179
|
-
return (createElement(Fragment, null,
|
|
298
|
+
return (createElement(Fragment, null, props.segs.map((seg) => {
|
|
180
299
|
let instanceId = seg.eventRange.instance.instanceId;
|
|
181
|
-
return (createElement("div", {
|
|
182
|
-
visibility:
|
|
183
|
-
} }, hasListItemDisplay(seg) ? (createElement(
|
|
300
|
+
return (createElement("div", { key: instanceId, style: {
|
|
301
|
+
visibility: forcedInvisibleMap[instanceId] ? 'hidden' : '',
|
|
302
|
+
} }, hasListItemDisplay(seg) ? (createElement(DayGridListEvent, Object.assign({ seg: seg, isDragging: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getSegMeta(seg, props.todayRange)))) : (createElement(DayGridBlockEvent, Object.assign({ seg: seg, isDragging: false, isResizing: false, isDateSelecting: false, isSelected: instanceId === props.eventSelection, defaultDisplayEventEnd: false }, getSegMeta(seg, props.todayRange))))));
|
|
184
303
|
})));
|
|
185
304
|
} }));
|
|
186
305
|
}
|
|
187
306
|
}
|
|
188
|
-
function compileSegs(singlePlacements) {
|
|
189
|
-
let allSegs = [];
|
|
190
|
-
let invisibleSegs = [];
|
|
191
|
-
for (let placement of singlePlacements) {
|
|
192
|
-
allSegs.push(placement.seg);
|
|
193
|
-
if (!placement.isVisible) {
|
|
194
|
-
invisibleSegs.push(placement.seg);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
return { allSegs, invisibleSegs };
|
|
198
|
-
}
|
|
199
307
|
|
|
200
|
-
|
|
201
|
-
class TableCell extends DateComponent {
|
|
308
|
+
class DayGridCell extends DateComponent {
|
|
202
309
|
constructor() {
|
|
203
310
|
super(...arguments);
|
|
204
|
-
|
|
205
|
-
this.
|
|
206
|
-
|
|
207
|
-
};
|
|
208
|
-
this.handleRootEl = (el) => {
|
|
209
|
-
setRef(this.rootElRef, el);
|
|
210
|
-
setRef(this.props.elRef, el);
|
|
211
|
-
};
|
|
311
|
+
// ref
|
|
312
|
+
this.innerElRef = createRef();
|
|
313
|
+
this.headerWrapElRef = createRef();
|
|
212
314
|
}
|
|
213
315
|
render() {
|
|
214
|
-
let {
|
|
316
|
+
let { props, context } = this;
|
|
215
317
|
let { options, dateEnv } = context;
|
|
216
|
-
|
|
217
|
-
// TODO: memoize this?
|
|
318
|
+
// TODO: memoize this
|
|
218
319
|
const isMonthStart = props.showDayNumber &&
|
|
219
|
-
shouldDisplayMonthStart(date, dateProfile.currentRange, dateEnv);
|
|
220
|
-
return (createElement(DayCellContainer, { elTag: "
|
|
221
|
-
'fc-daygrid-
|
|
320
|
+
shouldDisplayMonthStart(props.date, props.dateProfile.currentRange, dateEnv);
|
|
321
|
+
return (createElement(DayCellContainer, { elTag: "div", elClasses: [
|
|
322
|
+
'fc-daygrid-cell',
|
|
323
|
+
'fc-cell',
|
|
324
|
+
props.width != null ? '' : 'fc-liquid',
|
|
325
|
+
'fc-flex-column',
|
|
222
326
|
...(props.extraClassNames || []),
|
|
223
|
-
], elAttrs: Object.assign(Object.assign(
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
327
|
+
], elAttrs: Object.assign(Object.assign({}, props.extraDataAttrs), { role: 'gridcell' }), elStyle: {
|
|
328
|
+
width: props.width
|
|
329
|
+
}, extraRenderProps: props.extraRenderProps, defaultGenerator: renderTopInner, date: props.date, dateProfile: props.dateProfile, todayRange: props.todayRange, showDayNumber: props.showDayNumber, isMonthStart: isMonthStart }, (InnerContent, renderProps) => (createElement("div", { ref: this.innerElRef, className: [
|
|
330
|
+
'fc-daygrid-cell-inner',
|
|
331
|
+
props.fgLiquidHeight ? 'fc-liquid' : ''
|
|
332
|
+
].join(' ') },
|
|
333
|
+
createElement("div", { ref: this.headerWrapElRef, className: "fc-flex-column" }, !renderProps.isDisabled && (props.showDayNumber || hasCustomDayCellContent(options)) && (createElement("div", { className: "fc-daygrid-cell-header" },
|
|
227
334
|
createElement(InnerContent, { elTag: "a", elClasses: [
|
|
228
|
-
'fc-daygrid-
|
|
335
|
+
'fc-daygrid-cell-number',
|
|
229
336
|
isMonthStart && 'fc-daygrid-month-start',
|
|
230
|
-
], elAttrs:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
createElement("div", { className: "fc-daygrid-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
337
|
+
], elAttrs: buildNavLinkAttrs(context, props.date) })))),
|
|
338
|
+
createElement("div", { className: "fc-daygrid-cell-main", style: {
|
|
339
|
+
height: props.fgLiquidHeight ? '' : props.fgHeight
|
|
340
|
+
} }, props.fg),
|
|
341
|
+
createElement("div", { className: "fc-daygrid-cell-footer", style: props.fgLiquidHeight
|
|
342
|
+
? { position: 'relative', top: props.fgHeight }
|
|
343
|
+
: {} },
|
|
344
|
+
createElement(DayGridMoreLink, { allDayDate: props.date, segs: props.segs, hiddenSegs: props.hiddenSegs, alignmentElRef: this.innerElRef, alignGridTop: !props.showDayNumber, extraDateSpan: props.extraDateSpan, dateProfile: props.dateProfile, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, todayRange: props.todayRange })),
|
|
345
|
+
props.bg))));
|
|
346
|
+
}
|
|
347
|
+
componentDidMount() {
|
|
348
|
+
const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
|
|
349
|
+
const headerWrapEl = this.headerWrapElRef.current; // "
|
|
350
|
+
// TODO: only attach this if refs props present
|
|
351
|
+
this.detachInnerHeight = watchHeight(innerEl, (height) => {
|
|
352
|
+
setRef(this.props.innerHeightRef, height);
|
|
353
|
+
});
|
|
354
|
+
this.detachHeaderHeight = watchHeight(headerWrapEl, (height) => {
|
|
355
|
+
setRef(this.props.headerHeightRef, height);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
componentWillUnmount() {
|
|
359
|
+
this.detachInnerHeight();
|
|
360
|
+
this.detachHeaderHeight();
|
|
361
|
+
setRef(this.props.innerHeightRef, null);
|
|
362
|
+
setRef(this.props.headerHeightRef, null);
|
|
239
363
|
}
|
|
240
364
|
}
|
|
365
|
+
// Utils
|
|
366
|
+
// -------------------------------------------------------------------------------------------------
|
|
241
367
|
function renderTopInner(props) {
|
|
242
368
|
return props.dayNumberText || createElement(Fragment, null, "\u00A0");
|
|
243
369
|
}
|
|
@@ -257,26 +383,43 @@ function shouldDisplayMonthStart(date, currentRange, dateEnv) {
|
|
|
257
383
|
(dateEnv.getDay(date) === 1 && date.valueOf() < currentEnd.valueOf()));
|
|
258
384
|
}
|
|
259
385
|
|
|
260
|
-
|
|
386
|
+
/*
|
|
387
|
+
Unique per-START-column, good for cataloging by top
|
|
388
|
+
*/
|
|
389
|
+
function getSegStartId(seg) {
|
|
261
390
|
return seg.eventRange.instance.instanceId + ':' + seg.firstCol;
|
|
262
391
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
function
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
392
|
+
/*
|
|
393
|
+
Unique per-START-and-END-column, good for cataloging by width/height
|
|
394
|
+
*/
|
|
395
|
+
function getSegSpanId(seg) {
|
|
396
|
+
return getSegStartId(seg) + ':' + seg.lastCol;
|
|
397
|
+
}
|
|
398
|
+
function computeFgSegVerticals(segs, segHeightMap, // keyed by segSpanId
|
|
399
|
+
cells, topOrigin, maxHeight, strictOrder, dayMaxEvents, dayMaxEventRows) {
|
|
400
|
+
// initialize column-based arrays
|
|
401
|
+
const colCnt = cells.length;
|
|
402
|
+
const hiddenSegsByCol = [];
|
|
403
|
+
const heightsByCol = [];
|
|
404
|
+
for (let col = 0; col < colCnt; col++) {
|
|
405
|
+
hiddenSegsByCol.push([]);
|
|
406
|
+
heightsByCol.push(0);
|
|
407
|
+
}
|
|
408
|
+
// create entries to be given to DayGridSegHierarchy
|
|
409
|
+
const segEntries = segs.map((seg, index) => ({
|
|
410
|
+
index: index,
|
|
411
|
+
seg,
|
|
412
|
+
span: {
|
|
413
|
+
start: seg.firstCol,
|
|
414
|
+
end: seg.lastCol + 1,
|
|
415
|
+
},
|
|
416
|
+
}));
|
|
417
|
+
// configure hierarchy position-generator
|
|
418
|
+
let hierarchy = new DayGridSegHierarchy((segEntry) => (segHeightMap.get(getSegSpanId(segs[segEntry.index]))));
|
|
419
|
+
hierarchy.allowReslicing = false;
|
|
277
420
|
hierarchy.strictOrder = strictOrder;
|
|
278
421
|
if (dayMaxEvents === true || dayMaxEventRows === true) {
|
|
279
|
-
hierarchy.maxCoord =
|
|
422
|
+
hierarchy.maxCoord = maxHeight;
|
|
280
423
|
hierarchy.hiddenConsumes = true;
|
|
281
424
|
}
|
|
282
425
|
else if (typeof dayMaxEvents === 'number') {
|
|
@@ -286,172 +429,30 @@ dayMaxEvents, dayMaxEventRows, strictOrder, segHeights, maxContentHeight, cells)
|
|
|
286
429
|
hierarchy.maxStackCnt = dayMaxEventRows;
|
|
287
430
|
hierarchy.hiddenConsumes = true;
|
|
288
431
|
}
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
span: {
|
|
300
|
-
start: seg.firstCol,
|
|
301
|
-
end: seg.lastCol + 1,
|
|
302
|
-
},
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
else {
|
|
306
|
-
unknownHeightSegs.push(seg);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
let hiddenEntries = hierarchy.addSegs(segInputs);
|
|
310
|
-
let segRects = hierarchy.toRects();
|
|
311
|
-
let { singleColPlacements, multiColPlacements, leftoverMargins } = placeRects(segRects, segs, cells);
|
|
312
|
-
let moreCnts = [];
|
|
313
|
-
let moreMarginTops = [];
|
|
314
|
-
// add segs with unknown heights
|
|
315
|
-
for (let seg of unknownHeightSegs) {
|
|
316
|
-
multiColPlacements[seg.firstCol].push({
|
|
317
|
-
seg,
|
|
318
|
-
isVisible: false,
|
|
319
|
-
isAbsolute: true,
|
|
320
|
-
absoluteTop: 0,
|
|
321
|
-
marginTop: 0,
|
|
322
|
-
});
|
|
323
|
-
for (let col = seg.firstCol; col <= seg.lastCol; col += 1) {
|
|
324
|
-
singleColPlacements[col].push({
|
|
325
|
-
seg: resliceSeg(seg, col, col + 1, cells),
|
|
326
|
-
isVisible: false,
|
|
327
|
-
isAbsolute: false,
|
|
328
|
-
absoluteTop: 0,
|
|
329
|
-
marginTop: 0,
|
|
330
|
-
});
|
|
432
|
+
// compile segTops & heightsByCol
|
|
433
|
+
const hiddenSegEntries = hierarchy.addSegs(segEntries);
|
|
434
|
+
const segRects = hierarchy.toRects();
|
|
435
|
+
const segTops = {};
|
|
436
|
+
for (const segRect of segRects) {
|
|
437
|
+
const seg = segs[segRect.index];
|
|
438
|
+
segTops[getSegStartId(seg)] = topOrigin + segRect.levelCoord;
|
|
439
|
+
let { start: col, end: endCol } = segRect.span;
|
|
440
|
+
for (; col < endCol; col++) {
|
|
441
|
+
heightsByCol[col] = Math.max(heightsByCol[col], segRect.levelCoord + segRect.thickness);
|
|
331
442
|
}
|
|
332
443
|
}
|
|
333
|
-
//
|
|
334
|
-
for (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
let hiddenSpan = hiddenEntry.span;
|
|
340
|
-
multiColPlacements[hiddenSpan.start].push({
|
|
341
|
-
seg: resliceSeg(seg, hiddenSpan.start, hiddenSpan.end, cells),
|
|
342
|
-
isVisible: false,
|
|
343
|
-
isAbsolute: true,
|
|
344
|
-
absoluteTop: 0,
|
|
345
|
-
marginTop: 0,
|
|
346
|
-
});
|
|
347
|
-
for (let col = hiddenSpan.start; col < hiddenSpan.end; col += 1) {
|
|
348
|
-
moreCnts[col] += 1;
|
|
349
|
-
singleColPlacements[col].push({
|
|
350
|
-
seg: resliceSeg(seg, col, col + 1, cells),
|
|
351
|
-
isVisible: false,
|
|
352
|
-
isAbsolute: false,
|
|
353
|
-
absoluteTop: 0,
|
|
354
|
-
marginTop: 0,
|
|
355
|
-
});
|
|
444
|
+
// compile # of invisible segs per-column
|
|
445
|
+
for (const hiddenSegEntry of hiddenSegEntries) {
|
|
446
|
+
const { span } = hiddenSegEntry;
|
|
447
|
+
const hiddenSeg = segs[hiddenSegEntry.index];
|
|
448
|
+
for (let col = span.start; col < span.end; col++) {
|
|
449
|
+
hiddenSegsByCol[col].push(hiddenSeg);
|
|
356
450
|
}
|
|
357
451
|
}
|
|
358
|
-
|
|
359
|
-
for (let col = 0; col < cells.length; col += 1) {
|
|
360
|
-
moreMarginTops.push(leftoverMargins[col]);
|
|
361
|
-
}
|
|
362
|
-
return { singleColPlacements, multiColPlacements, moreCnts, moreMarginTops };
|
|
363
|
-
}
|
|
364
|
-
// rects ordered by top coord, then left
|
|
365
|
-
function placeRects(allRects, segs, cells) {
|
|
366
|
-
let rectsByEachCol = groupRectsByEachCol(allRects, cells.length);
|
|
367
|
-
let singleColPlacements = [];
|
|
368
|
-
let multiColPlacements = [];
|
|
369
|
-
let leftoverMargins = [];
|
|
370
|
-
for (let col = 0; col < cells.length; col += 1) {
|
|
371
|
-
let rects = rectsByEachCol[col];
|
|
372
|
-
// compute all static segs in singlePlacements
|
|
373
|
-
let singlePlacements = [];
|
|
374
|
-
let currentHeight = 0;
|
|
375
|
-
let currentMarginTop = 0;
|
|
376
|
-
for (let rect of rects) {
|
|
377
|
-
let seg = segs[rect.index];
|
|
378
|
-
singlePlacements.push({
|
|
379
|
-
seg: resliceSeg(seg, col, col + 1, cells),
|
|
380
|
-
isVisible: true,
|
|
381
|
-
isAbsolute: false,
|
|
382
|
-
absoluteTop: rect.levelCoord,
|
|
383
|
-
marginTop: rect.levelCoord - currentHeight,
|
|
384
|
-
});
|
|
385
|
-
currentHeight = rect.levelCoord + rect.thickness;
|
|
386
|
-
}
|
|
387
|
-
// compute mixed static/absolute segs in multiPlacements
|
|
388
|
-
let multiPlacements = [];
|
|
389
|
-
currentHeight = 0;
|
|
390
|
-
currentMarginTop = 0;
|
|
391
|
-
for (let rect of rects) {
|
|
392
|
-
let seg = segs[rect.index];
|
|
393
|
-
let isAbsolute = rect.span.end - rect.span.start > 1; // multi-column?
|
|
394
|
-
let isFirstCol = rect.span.start === col;
|
|
395
|
-
currentMarginTop += rect.levelCoord - currentHeight; // amount of space since bottom of previous seg
|
|
396
|
-
currentHeight = rect.levelCoord + rect.thickness; // height will now be bottom of current seg
|
|
397
|
-
if (isAbsolute) {
|
|
398
|
-
currentMarginTop += rect.thickness;
|
|
399
|
-
if (isFirstCol) {
|
|
400
|
-
multiPlacements.push({
|
|
401
|
-
seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
|
|
402
|
-
isVisible: true,
|
|
403
|
-
isAbsolute: true,
|
|
404
|
-
absoluteTop: rect.levelCoord,
|
|
405
|
-
marginTop: 0,
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
else if (isFirstCol) {
|
|
410
|
-
multiPlacements.push({
|
|
411
|
-
seg: resliceSeg(seg, rect.span.start, rect.span.end, cells),
|
|
412
|
-
isVisible: true,
|
|
413
|
-
isAbsolute: false,
|
|
414
|
-
absoluteTop: rect.levelCoord,
|
|
415
|
-
marginTop: currentMarginTop, // claim the margin
|
|
416
|
-
});
|
|
417
|
-
currentMarginTop = 0;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
singleColPlacements.push(singlePlacements);
|
|
421
|
-
multiColPlacements.push(multiPlacements);
|
|
422
|
-
leftoverMargins.push(currentMarginTop);
|
|
423
|
-
}
|
|
424
|
-
return { singleColPlacements, multiColPlacements, leftoverMargins };
|
|
425
|
-
}
|
|
426
|
-
function groupRectsByEachCol(rects, colCnt) {
|
|
427
|
-
let rectsByEachCol = [];
|
|
428
|
-
for (let col = 0; col < colCnt; col += 1) {
|
|
429
|
-
rectsByEachCol.push([]);
|
|
430
|
-
}
|
|
431
|
-
for (let rect of rects) {
|
|
432
|
-
for (let col = rect.span.start; col < rect.span.end; col += 1) {
|
|
433
|
-
rectsByEachCol[col].push(rect);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
return rectsByEachCol;
|
|
437
|
-
}
|
|
438
|
-
function resliceSeg(seg, spanStart, spanEnd, cells) {
|
|
439
|
-
if (seg.firstCol === spanStart && seg.lastCol === spanEnd - 1) {
|
|
440
|
-
return seg;
|
|
441
|
-
}
|
|
442
|
-
let eventRange = seg.eventRange;
|
|
443
|
-
let origRange = eventRange.range;
|
|
444
|
-
let slicedRange = intersectRanges(origRange, {
|
|
445
|
-
start: cells[spanStart].date,
|
|
446
|
-
end: addDays(cells[spanEnd - 1].date, 1),
|
|
447
|
-
});
|
|
448
|
-
return Object.assign(Object.assign({}, seg), { firstCol: spanStart, lastCol: spanEnd - 1, eventRange: {
|
|
449
|
-
def: eventRange.def,
|
|
450
|
-
ui: Object.assign(Object.assign({}, eventRange.ui), { durationEditable: false }),
|
|
451
|
-
instance: eventRange.instance,
|
|
452
|
-
range: slicedRange,
|
|
453
|
-
}, isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(), isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf() });
|
|
452
|
+
return [segTops, heightsByCol, hiddenSegsByCol];
|
|
454
453
|
}
|
|
454
|
+
// DayGridSegHierarchy
|
|
455
|
+
// -------------------------------------------------------------------------------------------------
|
|
455
456
|
class DayGridSegHierarchy extends SegHierarchy {
|
|
456
457
|
constructor() {
|
|
457
458
|
super(...arguments);
|
|
@@ -499,74 +500,205 @@ class DayGridSegHierarchy extends SegHierarchy {
|
|
|
499
500
|
}
|
|
500
501
|
}
|
|
501
502
|
|
|
502
|
-
class
|
|
503
|
+
class DayGridEventHarness extends Component {
|
|
503
504
|
constructor() {
|
|
504
505
|
super(...arguments);
|
|
505
|
-
|
|
506
|
-
this.frameElRefs = new RefMap(); // the fc-daygrid-day-frame
|
|
507
|
-
this.fgElRefs = new RefMap(); // the fc-daygrid-day-events
|
|
508
|
-
this.segHarnessRefs = new RefMap(); // indexed by "instanceId:firstCol"
|
|
506
|
+
// ref
|
|
509
507
|
this.rootElRef = createRef();
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
508
|
+
}
|
|
509
|
+
render() {
|
|
510
|
+
const { props } = this;
|
|
511
|
+
return (createElement("div", { className: "fc-abs", style: props.style, ref: this.rootElRef }, props.children));
|
|
512
|
+
}
|
|
513
|
+
componentDidMount() {
|
|
514
|
+
const rootEl = this.rootElRef.current; // TODO: make dynamic with useEffect
|
|
515
|
+
this.detachHeight = watchHeight(rootEl, (height) => {
|
|
516
|
+
setRef(this.props.heightRef, height);
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
componentWillUnmount() {
|
|
520
|
+
this.detachHeight();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const DEFAULT_WEEK_NUM_FORMAT = createFormatter({ week: 'narrow' });
|
|
525
|
+
const COMPACT_CELL_WIDTH = 80;
|
|
526
|
+
class DayGridRow extends BaseComponent {
|
|
527
|
+
constructor() {
|
|
528
|
+
super(...arguments);
|
|
529
|
+
this.cellInnerHeightRefMap = new RefMap(() => {
|
|
530
|
+
afterSize(this.handleInnerHeights);
|
|
531
|
+
});
|
|
532
|
+
this.cellHeaderHeightRefMap = new RefMap(() => {
|
|
533
|
+
afterSize(this.handleHeaderHeights);
|
|
534
|
+
});
|
|
535
|
+
this.segHeightRefMap = new RefMap(() => {
|
|
536
|
+
afterSize(this.handleSegHeights);
|
|
537
|
+
});
|
|
538
|
+
this.handleRootEl = (rootEl) => {
|
|
539
|
+
this.rootEl = rootEl;
|
|
540
|
+
setRef(this.props.rootElRef, rootEl);
|
|
541
|
+
};
|
|
542
|
+
// Sizing
|
|
543
|
+
// -----------------------------------------------------------------------------------------------
|
|
544
|
+
this.handleHeaderHeights = () => {
|
|
545
|
+
const cellHeaderHeightMap = this.cellHeaderHeightRefMap.current;
|
|
546
|
+
let max = 0;
|
|
547
|
+
for (const height of cellHeaderHeightMap.values()) {
|
|
548
|
+
max = Math.max(max, height);
|
|
549
|
+
}
|
|
550
|
+
if (this.state.headerHeight !== max) {
|
|
551
|
+
this.setState({ headerHeight: max });
|
|
552
|
+
}
|
|
514
553
|
};
|
|
515
|
-
this.
|
|
516
|
-
|
|
517
|
-
|
|
554
|
+
this.handleInnerHeights = () => {
|
|
555
|
+
const { props } = this;
|
|
556
|
+
const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
|
|
557
|
+
const cellInnerHeightMap = this.cellInnerHeightRefMap.current;
|
|
558
|
+
let max = 0;
|
|
559
|
+
for (const height of cellInnerHeightMap.values()) {
|
|
560
|
+
max = Math.max(max, height);
|
|
561
|
+
}
|
|
562
|
+
if (fgLiquidHeight) {
|
|
563
|
+
if (this.state.innerHeight !== max) {
|
|
564
|
+
this.setState({ innerHeight: max }); // will trigger event rerender
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
setRef(props.innerHeightRef, max);
|
|
518
569
|
}
|
|
519
570
|
};
|
|
571
|
+
this.handleSegHeights = () => {
|
|
572
|
+
this.setState({ segHeightRev: this.segHeightRefMap.rev }); // will trigger event rerender
|
|
573
|
+
};
|
|
520
574
|
}
|
|
521
575
|
render() {
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
576
|
+
const { props, state, context, cellInnerHeightRefMap, cellHeaderHeightRefMap } = this;
|
|
577
|
+
const { cells } = props;
|
|
578
|
+
const { options } = context;
|
|
579
|
+
const weekDate = props.cells[0].date;
|
|
580
|
+
const colCnt = props.cells.length;
|
|
581
|
+
const fgLiquidHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
|
|
582
|
+
// TODO: memoize? sort all types of segs?
|
|
583
|
+
const fgEventSegs = sortEventSegs(props.fgEventSegs, options.eventOrder);
|
|
584
|
+
// TODO: memoize?
|
|
585
|
+
const fgEventSegsByCol = splitSegsByCol(fgEventSegs, colCnt);
|
|
586
|
+
const bgEventSegsByCol = splitSegsByCol(props.bgEventSegs, colCnt);
|
|
587
|
+
const businessHoursByCol = splitSegsByCol(props.businessHourSegs, colCnt);
|
|
588
|
+
const highlightSegsByCol = splitSegsByCol(this.getHighlightSegs(), colCnt); // TODO: doesn't need standins
|
|
589
|
+
const mirrorSegsByCol = splitSegsByCol(this.getMirrorSegs(), colCnt); // TODO: doesn't need standins
|
|
590
|
+
// TODO: memoize?
|
|
591
|
+
const [segTops, heightsByCol, hiddenSegsByCol] = computeFgSegVerticals(fgEventSegs, this.segHeightRefMap.current, cells, state.headerHeight, (fgLiquidHeight && state.innerHeight != null && state.headerHeight != null)
|
|
592
|
+
? state.innerHeight - state.headerHeight
|
|
593
|
+
: undefined, options.eventOrderStrict, props.dayMaxEvents, props.dayMaxEventRows);
|
|
594
|
+
const forcedInvisibleMap = // TODO: more convenient/DRY
|
|
531
595
|
(props.eventDrag && props.eventDrag.affectedInstances) ||
|
|
532
596
|
(props.eventResize && props.eventResize.affectedInstances) ||
|
|
533
597
|
{};
|
|
534
|
-
return (createElement("
|
|
535
|
-
|
|
598
|
+
return (createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
|
|
599
|
+
'fc-daygrid-row',
|
|
600
|
+
props.forceVSpacing
|
|
601
|
+
? 'fc-daygrid-row-spacious'
|
|
602
|
+
: props.compact
|
|
603
|
+
? 'fc-daygrid-row-compact'
|
|
604
|
+
: '',
|
|
605
|
+
props.cellGroup ? 'fc-flex-row' : 'fc-row',
|
|
606
|
+
'fc-rel',
|
|
607
|
+
props.className || '',
|
|
608
|
+
].join(' '), style: {
|
|
609
|
+
minHeight: props.minHeight,
|
|
610
|
+
}, ref: this.handleRootEl },
|
|
536
611
|
props.cells.map((cell, col) => {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
612
|
+
const normalFgNodes = this.renderFgSegs(fgEventSegsByCol[col], segTops, props.todayRange, forcedInvisibleMap);
|
|
613
|
+
const mirrorFgNodes = this.renderFgSegs(mirrorSegsByCol[col], segTops, props.todayRange, {}, // forcedInvisibleMap
|
|
614
|
+
Boolean(props.eventDrag), Boolean(props.eventResize), false);
|
|
615
|
+
return (createElement(DayGridCell, { key: cell.key, dateProfile: props.dateProfile, todayRange: props.todayRange, date: cell.date, showDayNumber: props.showDayNumbers,
|
|
616
|
+
// content
|
|
617
|
+
segs: fgEventSegsByCol[col], hiddenSegs: hiddenSegsByCol[col], fgLiquidHeight: fgLiquidHeight, fg: (createElement(Fragment, null,
|
|
541
618
|
createElement(Fragment, null, normalFgNodes),
|
|
542
|
-
createElement(Fragment, null, mirrorFgNodes))),
|
|
543
|
-
createElement(Fragment, null,
|
|
619
|
+
createElement(Fragment, null, mirrorFgNodes))), bg: (createElement(Fragment, null,
|
|
544
620
|
this.renderFillSegs(highlightSegsByCol[col], 'highlight'),
|
|
545
621
|
this.renderFillSegs(businessHoursByCol[col], 'non-business'),
|
|
546
|
-
this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))),
|
|
547
|
-
|
|
622
|
+
this.renderFillSegs(bgEventSegsByCol[col], 'bg-event'))), eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
|
|
623
|
+
// render hooks
|
|
624
|
+
extraRenderProps: cell.extraRenderProps, extraDateSpan: cell.extraDateSpan, extraDataAttrs: cell.extraDataAttrs, extraClassNames: cell.extraClassNames,
|
|
625
|
+
// dimensions
|
|
626
|
+
fgHeight: heightsByCol[col], width: props.colWidth,
|
|
627
|
+
// refs
|
|
628
|
+
innerHeightRef: cellInnerHeightRefMap.createRef(cell.key), headerHeightRef: cellHeaderHeightRefMap.createRef(cell.key) }));
|
|
629
|
+
}),
|
|
630
|
+
props.showWeekNumbers && (createElement(WeekNumberContainer, { elTag: "a", elClasses: ['fc-daygrid-week-number'], elAttrs: buildNavLinkAttrs(context, weekDate, 'week'), date: weekDate, defaultFormat: DEFAULT_WEEK_NUM_FORMAT }))));
|
|
631
|
+
}
|
|
632
|
+
renderFgSegs(segs, segTops, todayRange, forcedInvisibleMap, isDragging, isResizing, isDateSelecting) {
|
|
633
|
+
const { props, context, segHeightRefMap } = this;
|
|
634
|
+
const { isRtl } = context;
|
|
635
|
+
const { colWidth, eventSelection } = props;
|
|
636
|
+
const colCnt = props.cells.length;
|
|
637
|
+
const defaultDisplayEventEnd = props.cells.length === 1;
|
|
638
|
+
const isMirror = isDragging || isResizing || isDateSelecting;
|
|
639
|
+
const nodes = [];
|
|
640
|
+
for (const seg of segs) {
|
|
641
|
+
const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
|
|
642
|
+
// TODO: optimize ID creation? all related
|
|
643
|
+
const { instanceId } = seg.eventRange.instance;
|
|
644
|
+
const segSpanId = getSegSpanId(seg);
|
|
645
|
+
const segStartId = getSegStartId(seg);
|
|
646
|
+
const top = segTops[segStartId];
|
|
647
|
+
const isVisible = !seg.isStandin &&
|
|
648
|
+
top != null &&
|
|
649
|
+
!forcedInvisibleMap[instanceId];
|
|
650
|
+
/*
|
|
651
|
+
TODO: is this comment still relevant? vvvvvvvv
|
|
652
|
+
known bug: events that are force to be list-item but span multiple days still take up space in later columns
|
|
653
|
+
todo: in print view, for multi-day events, don't display title within non-start/end segs
|
|
654
|
+
*/
|
|
655
|
+
nodes.push(createElement(DayGridEventHarness, { key: segSpanId, style: {
|
|
656
|
+
visibility: isVisible ? '' : 'hidden',
|
|
657
|
+
top,
|
|
658
|
+
left,
|
|
659
|
+
right,
|
|
660
|
+
width,
|
|
661
|
+
}, heightRef: (isMirror || seg.isStandin)
|
|
662
|
+
? null
|
|
663
|
+
: segHeightRefMap.createRef(segSpanId) }, hasListItemDisplay(seg) ? (createElement(DayGridListEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange)))) : (createElement(DayGridBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange))))));
|
|
664
|
+
}
|
|
665
|
+
return nodes;
|
|
548
666
|
}
|
|
549
|
-
|
|
550
|
-
this
|
|
551
|
-
|
|
667
|
+
renderFillSegs(segs, fillType) {
|
|
668
|
+
const { props, context } = this;
|
|
669
|
+
const { isRtl } = context;
|
|
670
|
+
const { todayRange, colWidth } = props;
|
|
671
|
+
const colCnt = props.cells.length;
|
|
672
|
+
const nodes = [];
|
|
673
|
+
for (const seg of segs) {
|
|
674
|
+
const { left, right, width } = computeHorizontalsFromSeg(seg, colWidth, colCnt, isRtl);
|
|
675
|
+
const isVisible = !seg.isStandin;
|
|
676
|
+
nodes.push(createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-fill-y", style: {
|
|
677
|
+
visibility: isVisible ? '' : 'hidden',
|
|
678
|
+
left,
|
|
679
|
+
right,
|
|
680
|
+
width,
|
|
681
|
+
} }, fillType === 'bg-event' ?
|
|
682
|
+
createElement(BgEvent, Object.assign({ seg: seg }, getSegMeta(seg, todayRange))) :
|
|
683
|
+
renderFill(fillType)));
|
|
684
|
+
}
|
|
685
|
+
return createElement(Fragment, {}, ...nodes);
|
|
552
686
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
687
|
+
// Sizing
|
|
688
|
+
// -----------------------------------------------------------------------------------------------
|
|
689
|
+
componentDidMount() {
|
|
690
|
+
const { rootEl } = this; // TODO: make dynamic with useEffect
|
|
691
|
+
this.disconnectHeight = watchHeight(rootEl, (contentHeight) => {
|
|
692
|
+
setRef(this.props.heightRef, contentHeight);
|
|
693
|
+
});
|
|
556
694
|
}
|
|
557
695
|
componentWillUnmount() {
|
|
558
|
-
this.
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
let { props } = this;
|
|
562
|
-
if (props.eventDrag && props.eventDrag.segs.length) { // messy check
|
|
563
|
-
return props.eventDrag.segs;
|
|
564
|
-
}
|
|
565
|
-
if (props.eventResize && props.eventResize.segs.length) { // messy check
|
|
566
|
-
return props.eventResize.segs;
|
|
567
|
-
}
|
|
568
|
-
return props.dateSelectionSegs;
|
|
696
|
+
this.disconnectHeight();
|
|
697
|
+
setRef(this.props.heightRef, null);
|
|
698
|
+
setRef(this.props.innerHeightRef, null);
|
|
569
699
|
}
|
|
700
|
+
// Utils
|
|
701
|
+
// -----------------------------------------------------------------------------------------------
|
|
570
702
|
getMirrorSegs() {
|
|
571
703
|
let { props } = this;
|
|
572
704
|
if (props.eventResize && props.eventResize.segs.length) { // messy check
|
|
@@ -574,412 +706,459 @@ class TableRow extends DateComponent {
|
|
|
574
706
|
}
|
|
575
707
|
return [];
|
|
576
708
|
}
|
|
577
|
-
|
|
578
|
-
let {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
let defaultDisplayEventEnd = this.props.cells.length === 1; // colCnt === 1
|
|
582
|
-
let isMirror = isDragging || isResizing || isDateSelecting;
|
|
583
|
-
let nodes = [];
|
|
584
|
-
if (framePositions) {
|
|
585
|
-
for (let placement of segPlacements) {
|
|
586
|
-
let { seg } = placement;
|
|
587
|
-
let { instanceId } = seg.eventRange.instance;
|
|
588
|
-
let isVisible = placement.isVisible && !isForcedInvisible[instanceId];
|
|
589
|
-
let isAbsolute = placement.isAbsolute;
|
|
590
|
-
let left = '';
|
|
591
|
-
let right = '';
|
|
592
|
-
if (isAbsolute) {
|
|
593
|
-
if (context.isRtl) {
|
|
594
|
-
right = 0;
|
|
595
|
-
left = framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol];
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
left = 0;
|
|
599
|
-
right = framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol];
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
/*
|
|
603
|
-
known bug: events that are force to be list-item but span multiple days still take up space in later columns
|
|
604
|
-
todo: in print view, for multi-day events, don't display title within non-start/end segs
|
|
605
|
-
*/
|
|
606
|
-
nodes.push(createElement("div", { className: 'fc-daygrid-event-harness' + (isAbsolute ? ' fc-daygrid-event-harness-abs' : ''), key: generateSegKey(seg), ref: isMirror ? null : this.segHarnessRefs.createRef(generateSegUid(seg)), style: {
|
|
607
|
-
visibility: isVisible ? '' : 'hidden',
|
|
608
|
-
marginTop: isAbsolute ? '' : placement.marginTop,
|
|
609
|
-
top: isAbsolute ? placement.absoluteTop : '',
|
|
610
|
-
left,
|
|
611
|
-
right,
|
|
612
|
-
} }, hasListItemDisplay(seg) ? (createElement(TableListItemEvent, Object.assign({ seg: seg, isDragging: isDragging, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange)))) : (createElement(TableBlockEvent, Object.assign({ seg: seg, isDragging: isDragging, isResizing: isResizing, isDateSelecting: isDateSelecting, isSelected: instanceId === eventSelection, defaultDisplayEventEnd: defaultDisplayEventEnd }, getSegMeta(seg, todayRange))))));
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
return nodes;
|
|
616
|
-
}
|
|
617
|
-
renderFillSegs(segs, fillType) {
|
|
618
|
-
let { isRtl } = this.context;
|
|
619
|
-
let { todayRange } = this.props;
|
|
620
|
-
let { framePositions } = this.state;
|
|
621
|
-
let nodes = [];
|
|
622
|
-
if (framePositions) {
|
|
623
|
-
for (let seg of segs) {
|
|
624
|
-
let leftRightCss = isRtl ? {
|
|
625
|
-
right: 0,
|
|
626
|
-
left: framePositions.lefts[seg.lastCol] - framePositions.lefts[seg.firstCol],
|
|
627
|
-
} : {
|
|
628
|
-
left: 0,
|
|
629
|
-
right: framePositions.rights[seg.firstCol] - framePositions.rights[seg.lastCol],
|
|
630
|
-
};
|
|
631
|
-
nodes.push(createElement("div", { key: buildEventRangeKey(seg.eventRange), className: "fc-daygrid-bg-harness", style: leftRightCss }, fillType === 'bg-event' ?
|
|
632
|
-
createElement(BgEvent, Object.assign({ seg: seg }, getSegMeta(seg, todayRange))) :
|
|
633
|
-
renderFill(fillType)));
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
return createElement(Fragment, {}, ...nodes);
|
|
637
|
-
}
|
|
638
|
-
updateSizing(isExternalSizingChange) {
|
|
639
|
-
let { props, state, frameElRefs } = this;
|
|
640
|
-
if (!props.forPrint &&
|
|
641
|
-
props.clientWidth !== null // positioning ready?
|
|
642
|
-
) {
|
|
643
|
-
if (isExternalSizingChange) {
|
|
644
|
-
let frameEls = props.cells.map((cell) => frameElRefs.currentMap[cell.key]);
|
|
645
|
-
if (frameEls.length) {
|
|
646
|
-
let originEl = this.rootElRef.current;
|
|
647
|
-
let newPositionCache = new PositionCache(originEl, frameEls, true, // isHorizontal
|
|
648
|
-
false);
|
|
649
|
-
if (!state.framePositions || !state.framePositions.similarTo(newPositionCache)) {
|
|
650
|
-
this.setState({
|
|
651
|
-
framePositions: new PositionCache(originEl, frameEls, true, // isHorizontal
|
|
652
|
-
false),
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
const oldSegHeights = this.state.segHeights;
|
|
658
|
-
const newSegHeights = this.querySegHeights();
|
|
659
|
-
const limitByContentHeight = props.dayMaxEvents === true || props.dayMaxEventRows === true;
|
|
660
|
-
this.safeSetState({
|
|
661
|
-
// HACK to prevent oscillations of events being shown/hidden from max-event-rows
|
|
662
|
-
// Essentially, once you compute an element's height, never null-out.
|
|
663
|
-
// TODO: always display all events, as visibility:hidden?
|
|
664
|
-
segHeights: Object.assign(Object.assign({}, oldSegHeights), newSegHeights),
|
|
665
|
-
maxContentHeight: limitByContentHeight ? this.computeMaxContentHeight() : null,
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
querySegHeights() {
|
|
670
|
-
let segElMap = this.segHarnessRefs.currentMap;
|
|
671
|
-
let segHeights = {};
|
|
672
|
-
// get the max height amongst instance segs
|
|
673
|
-
for (let segUid in segElMap) {
|
|
674
|
-
let height = Math.round(segElMap[segUid].getBoundingClientRect().height);
|
|
675
|
-
segHeights[segUid] = Math.max(segHeights[segUid] || 0, height);
|
|
709
|
+
getHighlightSegs() {
|
|
710
|
+
let { props } = this;
|
|
711
|
+
if (props.eventDrag && props.eventDrag.segs.length) { // messy check
|
|
712
|
+
return props.eventDrag.segs;
|
|
676
713
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
computeMaxContentHeight() {
|
|
680
|
-
let firstKey = this.props.cells[0].key;
|
|
681
|
-
let cellEl = this.cellElRefs.currentMap[firstKey];
|
|
682
|
-
let fcContainerEl = this.fgElRefs.currentMap[firstKey];
|
|
683
|
-
return cellEl.getBoundingClientRect().bottom - fcContainerEl.getBoundingClientRect().top;
|
|
684
|
-
}
|
|
685
|
-
getCellEls() {
|
|
686
|
-
let elMap = this.cellElRefs.currentMap;
|
|
687
|
-
return this.props.cells.map((cell) => elMap[cell.key]);
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
TableRow.addStateEquality({
|
|
691
|
-
segHeights: isPropsEqual,
|
|
692
|
-
});
|
|
693
|
-
function buildMirrorPlacements(mirrorSegs, colPlacements) {
|
|
694
|
-
if (!mirrorSegs.length) {
|
|
695
|
-
return [];
|
|
696
|
-
}
|
|
697
|
-
let topsByInstanceId = buildAbsoluteTopHash(colPlacements); // TODO: cache this at first render?
|
|
698
|
-
return mirrorSegs.map((seg) => ({
|
|
699
|
-
seg,
|
|
700
|
-
isVisible: true,
|
|
701
|
-
isAbsolute: true,
|
|
702
|
-
absoluteTop: topsByInstanceId[seg.eventRange.instance.instanceId],
|
|
703
|
-
marginTop: 0,
|
|
704
|
-
}));
|
|
705
|
-
}
|
|
706
|
-
function buildAbsoluteTopHash(colPlacements) {
|
|
707
|
-
let topsByInstanceId = {};
|
|
708
|
-
for (let placements of colPlacements) {
|
|
709
|
-
for (let placement of placements) {
|
|
710
|
-
topsByInstanceId[placement.seg.eventRange.instance.instanceId] = placement.absoluteTop;
|
|
714
|
+
if (props.eventResize && props.eventResize.segs.length) { // messy check
|
|
715
|
+
return props.eventResize.segs;
|
|
711
716
|
}
|
|
717
|
+
return props.dateSelectionSegs;
|
|
712
718
|
}
|
|
713
|
-
return topsByInstanceId;
|
|
714
719
|
}
|
|
715
720
|
|
|
716
|
-
class
|
|
721
|
+
class DayGridRows extends DateComponent {
|
|
717
722
|
constructor() {
|
|
718
723
|
super(...arguments);
|
|
724
|
+
// memo
|
|
719
725
|
this.splitBusinessHourSegs = memoize(splitSegsByRow);
|
|
720
726
|
this.splitBgEventSegs = memoize(splitSegsByRow);
|
|
721
727
|
this.splitFgEventSegs = memoize(splitSegsByRow);
|
|
722
728
|
this.splitDateSelectionSegs = memoize(splitSegsByRow);
|
|
723
729
|
this.splitEventDrag = memoize(splitInteractionByRow);
|
|
724
730
|
this.splitEventResize = memoize(splitInteractionByRow);
|
|
725
|
-
|
|
731
|
+
// internal
|
|
732
|
+
this.rowHeightRefMap = new RefMap((height, key) => {
|
|
733
|
+
// HACKy way of syncing RefMap results with prop
|
|
734
|
+
const { rowHeightRefMap } = this.props;
|
|
735
|
+
if (rowHeightRefMap) {
|
|
736
|
+
rowHeightRefMap.handleValue(height, key);
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
this.handleRootEl = (rootEl) => {
|
|
740
|
+
this.rootEl = rootEl;
|
|
741
|
+
if (rootEl) {
|
|
742
|
+
this.context.registerInteractiveComponent(this, {
|
|
743
|
+
el: rootEl,
|
|
744
|
+
isHitComboAllowed: this.props.isHitComboAllowed,
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
this.context.unregisterInteractiveComponent(this);
|
|
749
|
+
}
|
|
750
|
+
};
|
|
726
751
|
}
|
|
727
752
|
render() {
|
|
728
|
-
let { props, context } = this;
|
|
729
|
-
let
|
|
730
|
-
let
|
|
731
|
-
let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
|
|
753
|
+
let { props, state, context, rowHeightRefMap } = this;
|
|
754
|
+
let { options } = context;
|
|
755
|
+
let rowCnt = props.cellRows.length;
|
|
732
756
|
let fgEventSegsByRow = this.splitFgEventSegs(props.fgEventSegs, rowCnt);
|
|
757
|
+
let bgEventSegsByRow = this.splitBgEventSegs(props.bgEventSegs, rowCnt);
|
|
758
|
+
let businessHourSegsByRow = this.splitBusinessHourSegs(props.businessHourSegs, rowCnt);
|
|
733
759
|
let dateSelectionSegsByRow = this.splitDateSelectionSegs(props.dateSelectionSegs, rowCnt);
|
|
734
760
|
let eventDragByRow = this.splitEventDrag(props.eventDrag, rowCnt);
|
|
735
761
|
let eventResizeByRow = this.splitEventResize(props.eventResize, rowCnt);
|
|
736
|
-
//
|
|
737
|
-
//
|
|
738
|
-
let
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
762
|
+
// whether the ROW should expand in height
|
|
763
|
+
// (not to be confused with whether the fg events within the row should be molded by height of row)
|
|
764
|
+
let isHeightAuto = getIsHeightAuto(options);
|
|
765
|
+
// maintain at least aspectRatio for cells?
|
|
766
|
+
let rowMinHeight = (state.width != null && (rowCnt >= 7 || // TODO: better way to infer if across single-month boundary
|
|
767
|
+
isHeightAuto)) ? state.width / context.options.aspectRatio / 6 // okay to hardcode 6 (weeks) ?
|
|
768
|
+
: null;
|
|
769
|
+
return (createElement("div", { className: 'fc-grow fc-flex-column', style: { width: props.width }, ref: this.handleRootEl }, props.cellRows.map((cells, row) => (createElement(DayGridRow, { key: cells[0].key, dateProfile: props.dateProfile, todayRange: props.todayRange, cells: cells, showDayNumbers: rowCnt > 1, showWeekNumbers: options.weekNumbers, forPrint: props.forPrint, compact: state.width != null && (state.width / cells.length) < COMPACT_CELL_WIDTH,
|
|
770
|
+
// if not auto-height, distribute height of container somewhat evently to rows
|
|
771
|
+
// (treat all as zero, distribute height, then ensure min-heights -- the inner content height)
|
|
772
|
+
className: isHeightAuto ? '' : 'fc-grow fc-basis0',
|
|
773
|
+
// content
|
|
774
|
+
fgEventSegs: fgEventSegsByRow[row], bgEventSegs: bgEventSegsByRow[row].filter(isSegAllDay) /* HACK */, businessHourSegs: businessHourSegsByRow[row], dateSelectionSegs: dateSelectionSegsByRow[row], eventSelection: props.eventSelection, eventDrag: eventDragByRow[row], eventResize: eventResizeByRow[row], dayMaxEvents: options.dayMaxEvents, dayMaxEventRows: options.dayMaxEventRows,
|
|
775
|
+
// dimensions
|
|
776
|
+
colWidth: props.colWidth, minHeight: rowMinHeight,
|
|
777
|
+
// refs
|
|
778
|
+
heightRef: rowHeightRefMap.createRef(cells[0].key) })))));
|
|
745
779
|
}
|
|
746
780
|
componentDidMount() {
|
|
747
|
-
this.
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
// for if started with zero cells
|
|
751
|
-
this.registerInteractiveComponent();
|
|
752
|
-
}
|
|
753
|
-
registerInteractiveComponent() {
|
|
754
|
-
if (!this.rootEl) {
|
|
755
|
-
// HACK: need a daygrid wrapper parent to do positioning
|
|
756
|
-
// NOTE: a daygrid resource view w/o resources can have zero cells
|
|
757
|
-
const firstCellEl = this.rowRefs.currentMap[0].getCellEls()[0];
|
|
758
|
-
const rootEl = firstCellEl ? firstCellEl.closest('.fc-daygrid-body') : null;
|
|
759
|
-
if (rootEl) {
|
|
760
|
-
this.rootEl = rootEl;
|
|
761
|
-
this.context.registerInteractiveComponent(this, {
|
|
762
|
-
el: rootEl,
|
|
763
|
-
isHitComboAllowed: this.props.isHitComboAllowed,
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
}
|
|
781
|
+
this.unwatchWidth = watchWidth(this.rootEl, (width) => {
|
|
782
|
+
this.setState({ width });
|
|
783
|
+
});
|
|
767
784
|
}
|
|
768
785
|
componentWillUnmount() {
|
|
769
|
-
|
|
770
|
-
this.context.unregisterInteractiveComponent(this);
|
|
771
|
-
this.rootEl = null;
|
|
772
|
-
}
|
|
786
|
+
this.unwatchWidth();
|
|
773
787
|
}
|
|
774
788
|
// Hit System
|
|
775
|
-
//
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
return null;
|
|
803
|
-
}
|
|
804
|
-
getCellEl(row, col) {
|
|
805
|
-
return this.rowRefs.currentMap[row].getCellEls()[col]; // TODO: not optimal
|
|
806
|
-
}
|
|
807
|
-
getCellRange(row, col) {
|
|
808
|
-
let start = this.props.cells[row][col].date;
|
|
809
|
-
let end = addDays(start, 1);
|
|
810
|
-
return { start, end };
|
|
789
|
+
// -----------------------------------------------------------------------------------------------
|
|
790
|
+
queryHit(positionLeft, positionTop, elWidth) {
|
|
791
|
+
const { props, context } = this;
|
|
792
|
+
const colCnt = props.cellRows[0].length;
|
|
793
|
+
const { col, left, right } = computeColFromPosition(positionLeft, elWidth, props.colWidth, colCnt, context.isRtl);
|
|
794
|
+
const { row, top, bottom } = computeRowFromPosition(positionTop, props.cellRows, this.rowHeightRefMap.current);
|
|
795
|
+
const cell = props.cellRows[row][col];
|
|
796
|
+
const cellStartDate = cell.date;
|
|
797
|
+
const cellEndDate = addDays(cellStartDate, 1);
|
|
798
|
+
return {
|
|
799
|
+
dateProfile: props.dateProfile,
|
|
800
|
+
dateSpan: Object.assign({ range: {
|
|
801
|
+
start: cellStartDate,
|
|
802
|
+
end: cellEndDate,
|
|
803
|
+
}, allDay: true }, cell.extraDateSpan),
|
|
804
|
+
// HACK. TODO: This is expensive to do every hit-query
|
|
805
|
+
dayEl: getCellEl(getRowEl(this.rootEl, row), col),
|
|
806
|
+
rect: {
|
|
807
|
+
left,
|
|
808
|
+
right,
|
|
809
|
+
top,
|
|
810
|
+
bottom,
|
|
811
|
+
},
|
|
812
|
+
layer: 0,
|
|
813
|
+
};
|
|
811
814
|
}
|
|
812
815
|
}
|
|
816
|
+
// Utils
|
|
817
|
+
// -------------------------------------------------------------------------------------------------
|
|
813
818
|
function isSegAllDay(seg) {
|
|
814
819
|
return seg.eventRange.def.allDay;
|
|
815
820
|
}
|
|
816
821
|
|
|
817
|
-
class
|
|
822
|
+
class HeaderRow extends BaseComponent {
|
|
823
|
+
render() {
|
|
824
|
+
const { props } = this;
|
|
825
|
+
return (createElement("div", { role: props.cellGroup ? undefined : 'row', className: [
|
|
826
|
+
props.cellGroup ? 'fc-flex-row' : 'fc-row',
|
|
827
|
+
props.className || '',
|
|
828
|
+
].join(' ') }, props.cells.map((cell) => (createElement(Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, undefined, // innerHeightRef
|
|
829
|
+
props.colWidth))))));
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function DayGridHeader(props) {
|
|
834
|
+
return (createElement("div", { className: [
|
|
835
|
+
'fc-rowgroup',
|
|
836
|
+
'fc-content-box',
|
|
837
|
+
...(props.extraClassNames || []),
|
|
838
|
+
].join(' '), style: {
|
|
839
|
+
width: props.width,
|
|
840
|
+
paddingLeft: props.paddingLeft,
|
|
841
|
+
paddingRight: props.paddingRight,
|
|
842
|
+
} }, props.headerTiers.map((cells, tierNum) => (createElement(HeaderRow, { key: tierNum, tierNum: tierNum, cells: cells, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey, colWidth: props.colWidth })))));
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
class DayGridLayoutNormal extends BaseComponent {
|
|
818
846
|
constructor() {
|
|
819
847
|
super(...arguments);
|
|
820
|
-
this.
|
|
821
|
-
|
|
848
|
+
this.handleScroller = (scroller) => {
|
|
849
|
+
setRef(this.props.scrollerRef, scroller);
|
|
850
|
+
};
|
|
851
|
+
this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
|
|
852
|
+
this.setState({ leftScrollbarWidth });
|
|
853
|
+
};
|
|
854
|
+
this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
|
|
855
|
+
this.setState({ rightScrollbarWidth });
|
|
856
|
+
};
|
|
822
857
|
}
|
|
823
858
|
render() {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
} },
|
|
850
|
-
props.colGroupNode,
|
|
851
|
-
createElement("tbody", { role: "presentation" },
|
|
852
|
-
createElement(TableRows, { dateProfile: props.dateProfile, cells: props.cells, renderRowIntro: props.renderRowIntro, showWeekNumbers: props.showWeekNumbers, clientWidth: props.clientWidth, clientHeight: props.clientHeight, businessHourSegs: props.businessHourSegs, bgEventSegs: props.bgEventSegs, fgEventSegs: props.fgEventSegs, dateSelectionSegs: props.dateSelectionSegs, eventSelection: props.eventSelection, eventDrag: props.eventDrag, eventResize: props.eventResize, dayMaxEvents: dayMaxEvents, dayMaxEventRows: dayMaxEventRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed })))));
|
|
859
|
+
const { props, state, context } = this;
|
|
860
|
+
const { options } = context;
|
|
861
|
+
const verticalScrollbars = !props.forPrint && !getIsHeightAuto(options);
|
|
862
|
+
const stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options);
|
|
863
|
+
return (createElement(Fragment, null,
|
|
864
|
+
options.dayHeaders && (createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
|
|
865
|
+
// render hooks
|
|
866
|
+
extraClassNames: [
|
|
867
|
+
'fc-daygrid-header',
|
|
868
|
+
stickyHeaderDates ? 'fc-sticky-header' : '',
|
|
869
|
+
],
|
|
870
|
+
// dimensions
|
|
871
|
+
paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth })),
|
|
872
|
+
createElement(Scroller, { vertical: verticalScrollbars, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
|
|
873
|
+
'fc-daygrid-body',
|
|
874
|
+
'fc-rowgroup',
|
|
875
|
+
'fc-flex-column',
|
|
876
|
+
verticalScrollbars ? 'fc-liquid' : '',
|
|
877
|
+
], ref: this.handleScroller },
|
|
878
|
+
createElement(DayGridRows // .fc-grow
|
|
879
|
+
, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
|
|
880
|
+
// content
|
|
881
|
+
fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
|
|
882
|
+
// refs
|
|
883
|
+
rowHeightRefMap: props.rowHeightRefMap }))));
|
|
853
884
|
}
|
|
854
|
-
|
|
855
|
-
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
class DayGridLayoutPannable extends BaseComponent {
|
|
888
|
+
constructor() {
|
|
889
|
+
super(...arguments);
|
|
890
|
+
this.headerScrollerRef = createRef();
|
|
891
|
+
this.bodyScrollerRef = createRef();
|
|
892
|
+
this.footerScrollerRef = createRef();
|
|
893
|
+
// Sizing
|
|
894
|
+
// -----------------------------------------------------------------------------------------------
|
|
895
|
+
this.handleWidth = (width) => {
|
|
896
|
+
this.setState({ width });
|
|
897
|
+
};
|
|
898
|
+
this.handleLeftScrollbarWidth = (leftScrollbarWidth) => {
|
|
899
|
+
this.setState({ leftScrollbarWidth });
|
|
900
|
+
};
|
|
901
|
+
this.handleRightScrollbarWidth = (rightScrollbarWidth) => {
|
|
902
|
+
this.setState({ rightScrollbarWidth });
|
|
903
|
+
};
|
|
856
904
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
905
|
+
render() {
|
|
906
|
+
const { props, state, context } = this;
|
|
907
|
+
const { options } = context;
|
|
908
|
+
const verticalScrollbars = !props.forPrint && !getIsHeightAuto(options);
|
|
909
|
+
const stickyHeaderDates = !props.forPrint && getStickyHeaderDates(options);
|
|
910
|
+
const stickyFooterScrollbar = !props.forPrint && getStickyFooterScrollbar(options);
|
|
911
|
+
const colCnt = props.cellRows[0].length;
|
|
912
|
+
const [canvasWidth, colWidth] = computeColWidth(colCnt, props.dayMinWidth, state.width);
|
|
913
|
+
return (createElement(Fragment, null,
|
|
914
|
+
options.dayHeaders && (createElement(Scroller, { horizontal: true, hideScrollbars: true, elClassNames: [
|
|
915
|
+
'fc-daygrid-header',
|
|
916
|
+
'fc-rowgroup',
|
|
917
|
+
stickyHeaderDates ? 'fc-sticky-header' : ''
|
|
918
|
+
], ref: this.headerScrollerRef },
|
|
919
|
+
createElement(DayGridHeader, { headerTiers: props.headerTiers, renderHeaderContent: props.renderHeaderContent, getHeaderModelKey: props.getHeaderModelKey,
|
|
920
|
+
// dimensions
|
|
921
|
+
colWidth: colWidth, width: canvasWidth, paddingLeft: state.leftScrollbarWidth, paddingRight: state.rightScrollbarWidth }))),
|
|
922
|
+
createElement(Scroller, { vertical: verticalScrollbars, horizontal: true, hideScrollbars: stickyFooterScrollbar, widthRef: this.handleWidth, leftScrollbarWidthRef: this.handleLeftScrollbarWidth, rightScrollbarWidthRef: this.handleRightScrollbarWidth, elClassNames: [
|
|
923
|
+
'fc-daygrid-body',
|
|
924
|
+
'fc-rowgroup',
|
|
925
|
+
'fc-flex-column',
|
|
926
|
+
verticalScrollbars ? 'fc-liquid' : '',
|
|
927
|
+
], ref: this.bodyScrollerRef },
|
|
928
|
+
createElement(DayGridRows // .fc-grow
|
|
929
|
+
, { dateProfile: props.dateProfile, todayRange: props.todayRange, cellRows: props.cellRows, forPrint: props.forPrint, isHitComboAllowed: props.isHitComboAllowed,
|
|
930
|
+
// content
|
|
931
|
+
fgEventSegs: props.fgEventSegs, bgEventSegs: props.bgEventSegs, businessHourSegs: props.businessHourSegs, dateSelectionSegs: props.dateSelectionSegs, eventDrag: props.eventDrag, eventResize: props.eventResize, eventSelection: props.eventSelection,
|
|
932
|
+
// dimensions
|
|
933
|
+
colWidth: colWidth, width: canvasWidth,
|
|
934
|
+
// refs
|
|
935
|
+
rowHeightRefMap: props.rowHeightRefMap })),
|
|
936
|
+
Boolean(stickyFooterScrollbar) && (createElement(Scroller, { ref: this.footerScrollerRef, horizontal: true, elClassNames: ['fc-sticky-footer'], elStyle: {
|
|
937
|
+
marginTop: '-1px', // HACK
|
|
938
|
+
} },
|
|
939
|
+
createElement("div", { style: {
|
|
940
|
+
width: canvasWidth,
|
|
941
|
+
height: '1px', // HACK
|
|
942
|
+
} })))));
|
|
864
943
|
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
)
|
|
873
|
-
const subjectEl = getScrollSubjectEl(this.elRef.current, this.props.dateProfile);
|
|
874
|
-
if (subjectEl) {
|
|
875
|
-
const originEl = subjectEl.closest('.fc-daygrid-body');
|
|
876
|
-
const scrollEl = originEl.closest('.fc-scroller');
|
|
877
|
-
const scrollTop = subjectEl.getBoundingClientRect().top -
|
|
878
|
-
originEl.getBoundingClientRect().top;
|
|
879
|
-
scrollEl.scrollTop = scrollTop ? (scrollTop + 1) : 0; // overcome border
|
|
880
|
-
}
|
|
881
|
-
this.needsScrollReset = false;
|
|
882
|
-
}
|
|
944
|
+
// Lifecycle
|
|
945
|
+
// -----------------------------------------------------------------------------------------------
|
|
946
|
+
componentDidMount() {
|
|
947
|
+
// scroller
|
|
948
|
+
const ScrollerSyncer = getScrollerSyncerClass(this.context.pluginHooks);
|
|
949
|
+
this.syncedScroller = new ScrollerSyncer(true); // horizontal=true
|
|
950
|
+
setRef(this.props.scrollerRef, this.syncedScroller);
|
|
951
|
+
this.updateSyncedScroller();
|
|
883
952
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
if (dateProfile.currentRangeUnit.match(/year|month/)) {
|
|
888
|
-
el = containerEl.querySelector(`[data-date="${formatIsoMonthStr(dateProfile.currentDate)}-01"]`);
|
|
889
|
-
// even if view is month-based, first-of-month might be hidden...
|
|
953
|
+
componentDidUpdate() {
|
|
954
|
+
// scroller
|
|
955
|
+
this.updateSyncedScroller();
|
|
890
956
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
957
|
+
componentWillUnmount() {
|
|
958
|
+
// scroller
|
|
959
|
+
this.syncedScroller.destroy();
|
|
960
|
+
}
|
|
961
|
+
// Scrolling
|
|
962
|
+
// -----------------------------------------------------------------------------------------------
|
|
963
|
+
updateSyncedScroller() {
|
|
964
|
+
const { isRtl } = this.context;
|
|
965
|
+
this.syncedScroller.handleChildren([
|
|
966
|
+
this.headerScrollerRef.current,
|
|
967
|
+
this.bodyScrollerRef.current,
|
|
968
|
+
this.footerScrollerRef.current,
|
|
969
|
+
], isRtl);
|
|
894
970
|
}
|
|
895
|
-
return el;
|
|
896
971
|
}
|
|
897
972
|
|
|
898
|
-
class
|
|
973
|
+
class DayGridLayout extends BaseComponent {
|
|
899
974
|
constructor() {
|
|
900
975
|
super(...arguments);
|
|
901
|
-
|
|
976
|
+
// ref
|
|
977
|
+
this.scrollerRef = createRef();
|
|
978
|
+
this.rowHeightRefMap = new RefMap();
|
|
979
|
+
// Scrolling
|
|
980
|
+
// -----------------------------------------------------------------------------------------------
|
|
981
|
+
this.timeScrollResponder = new ScrollResponder((_time) => {
|
|
982
|
+
// HACK to scroll to day
|
|
983
|
+
const rowHeightMap = this.rowHeightRefMap.current;
|
|
984
|
+
const scroller = this.scrollerRef.current;
|
|
985
|
+
const scrollTop = computeTopFromDate(this.props.dateProfile.currentDate, this.props.cellRows, rowHeightMap);
|
|
986
|
+
if (scrollTop != null) {
|
|
987
|
+
scroller.scrollTo({ y: scrollTop });
|
|
988
|
+
return true;
|
|
989
|
+
}
|
|
990
|
+
return false;
|
|
991
|
+
});
|
|
902
992
|
}
|
|
903
|
-
|
|
904
|
-
|
|
993
|
+
render() {
|
|
994
|
+
const { props, context } = this;
|
|
995
|
+
const { options } = context;
|
|
996
|
+
const commonLayoutProps = Object.assign(Object.assign({}, props), { scrollerRef: this.scrollerRef, rowHeightRefMap: this.rowHeightRefMap });
|
|
997
|
+
return (createElement(ViewContainer, { viewSpec: context.viewSpec, elClasses: [props.className, 'fc-flex-column', 'fc-border'] }, options.dayMinWidth ? (createElement(DayGridLayoutPannable, Object.assign({}, commonLayoutProps, { dayMinWidth: options.dayMinWidth }))) : (createElement(DayGridLayoutNormal, Object.assign({}, commonLayoutProps)))));
|
|
998
|
+
}
|
|
999
|
+
// Lifecycle
|
|
1000
|
+
// -----------------------------------------------------------------------------------------------
|
|
1001
|
+
componentDidMount() {
|
|
1002
|
+
const { context } = this;
|
|
1003
|
+
const { options } = context;
|
|
1004
|
+
context.emitter.on('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
|
1005
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
|
1006
|
+
}
|
|
1007
|
+
componentDidUpdate(prevProps) {
|
|
1008
|
+
const { options } = this.context;
|
|
1009
|
+
if (prevProps.dateProfile !== this.props.dateProfile && options.scrollTimeReset) {
|
|
1010
|
+
this.timeScrollResponder.handleScroll(options.scrollTime);
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
this.timeScrollResponder.drain();
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
componentWillUnmount() {
|
|
1017
|
+
this.context.emitter.off('_timeScrollRequest', this.timeScrollResponder.handleScroll);
|
|
905
1018
|
}
|
|
906
1019
|
}
|
|
907
1020
|
|
|
908
|
-
|
|
1021
|
+
const WEEKDAY_FORMAT = createFormatter({ weekday: 'long' });
|
|
1022
|
+
class DayOfWeekHeaderCell extends BaseComponent {
|
|
909
1023
|
constructor() {
|
|
910
1024
|
super(...arguments);
|
|
911
|
-
|
|
912
|
-
this.
|
|
1025
|
+
// ref
|
|
1026
|
+
this.innerElRef = createRef();
|
|
913
1027
|
}
|
|
914
1028
|
render() {
|
|
915
1029
|
let { props, context } = this;
|
|
916
|
-
|
|
1030
|
+
let { dateEnv, theme, viewApi, options } = context;
|
|
1031
|
+
let date = addDays(new Date(259200000), props.dow); // start with Sun, 04 Jan 1970 00:00:00 GMT
|
|
1032
|
+
let dateMeta = {
|
|
1033
|
+
dow: props.dow,
|
|
1034
|
+
isDisabled: false,
|
|
1035
|
+
isFuture: false,
|
|
1036
|
+
isPast: false,
|
|
1037
|
+
isToday: false,
|
|
1038
|
+
isOther: false,
|
|
1039
|
+
};
|
|
1040
|
+
let text = dateEnv.format(date, props.dayHeaderFormat);
|
|
1041
|
+
let renderProps = Object.assign(Object.assign(Object.assign(Object.assign({ date }, dateMeta), { view: viewApi }), props.extraRenderProps), { text });
|
|
1042
|
+
return (createElement(ContentContainer, { elTag: 'div', elClasses: [
|
|
1043
|
+
...getDayClassNames(dateMeta, theme),
|
|
1044
|
+
...(props.extraClassNames || []),
|
|
1045
|
+
'fc-header-cell',
|
|
1046
|
+
'fc-cell',
|
|
1047
|
+
props.colWidth != null ? '' : 'fc-liquid',
|
|
1048
|
+
'fc-flex-column',
|
|
1049
|
+
'fc-align-center',
|
|
1050
|
+
], elAttrs: props.extraDataAttrs, elStyle: {
|
|
1051
|
+
width: props.colWidth != null // TODO: DRY
|
|
1052
|
+
? props.colWidth * (props.colSpan || 1)
|
|
1053
|
+
: undefined,
|
|
1054
|
+
}, renderProps: renderProps, generatorName: "dayHeaderContent", customGenerator: options.dayHeaderContent, defaultGenerator: renderInner, classNameGenerator: options.dayHeaderClassNames, didMount: options.dayHeaderDidMount, willUnmount: options.dayHeaderWillUnmount }, (InnerContent) => (createElement("div", { ref: this.innerElRef, className: [
|
|
1055
|
+
'fc-flex-column',
|
|
1056
|
+
props.isSticky ? 'fc-sticky-x' : '',
|
|
1057
|
+
].join(' ') },
|
|
1058
|
+
createElement(InnerContent, { elTag: "a", elClasses: [
|
|
1059
|
+
'fc-cell-inner',
|
|
1060
|
+
'fc-padding-sm',
|
|
1061
|
+
], elAttrs: {
|
|
1062
|
+
'aria-label': dateEnv.format(date, WEEKDAY_FORMAT),
|
|
1063
|
+
} })))));
|
|
1064
|
+
}
|
|
1065
|
+
componentDidMount() {
|
|
1066
|
+
const innerEl = this.innerElRef.current; // TODO: make dynamic with useEffect
|
|
1067
|
+
// TODO: only attach this if refs props present
|
|
1068
|
+
this.disconectInnerHeight = watchHeight(innerEl, (height) => {
|
|
1069
|
+
setRef(this.props.innerHeightRef, height);
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
componentWillUnmount() {
|
|
1073
|
+
this.disconectInnerHeight();
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
function createDayHeaderFormatter(explicitFormat, datesRepDistinctDays, dateCnt) {
|
|
1078
|
+
return explicitFormat || computeFallbackHeaderFormat(datesRepDistinctDays, dateCnt);
|
|
1079
|
+
}
|
|
1080
|
+
// Computes a default column header formatting string if `colFormat` is not explicitly defined
|
|
1081
|
+
function computeFallbackHeaderFormat(datesRepDistinctDays, dayCnt) {
|
|
1082
|
+
// if more than one week row, or if there are a lot of columns with not much space,
|
|
1083
|
+
// put just the day numbers will be in each cell
|
|
1084
|
+
if (!datesRepDistinctDays || dayCnt > 10) {
|
|
1085
|
+
return createFormatter({ weekday: 'short' }); // "Sat"
|
|
917
1086
|
}
|
|
1087
|
+
if (dayCnt > 1) {
|
|
1088
|
+
return createFormatter({ weekday: 'short', month: 'numeric', day: 'numeric', omitCommas: true }); // "Sat 11/12"
|
|
1089
|
+
}
|
|
1090
|
+
return createFormatter({ weekday: 'long' }); // "Saturday"
|
|
918
1091
|
}
|
|
919
1092
|
|
|
920
|
-
class
|
|
1093
|
+
class DayGridView extends BaseComponent {
|
|
921
1094
|
constructor() {
|
|
922
1095
|
super(...arguments);
|
|
1096
|
+
// memo
|
|
923
1097
|
this.buildDayTableModel = memoize(buildDayTableModel);
|
|
924
|
-
this.
|
|
925
|
-
this.
|
|
926
|
-
//
|
|
1098
|
+
this.buildHeaderTiers = memoize(buildHeaderTiers);
|
|
1099
|
+
this.createDayHeaderFormatter = memoize(createDayHeaderFormatter);
|
|
1100
|
+
// internal
|
|
1101
|
+
this.slicer = new DayTableSlicer();
|
|
927
1102
|
}
|
|
928
1103
|
render() {
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1104
|
+
const { props, context } = this;
|
|
1105
|
+
const { options } = context;
|
|
1106
|
+
const dayTableModel = this.buildDayTableModel(props.dateProfile, context.dateProfileGenerator);
|
|
1107
|
+
const datesRepDistinctDays = dayTableModel.rowCnt === 1;
|
|
1108
|
+
const headerTiers = this.buildHeaderTiers(dayTableModel.headerDates, datesRepDistinctDays);
|
|
1109
|
+
const slicedProps = this.slicer.sliceProps(props, props.dateProfile, options.nextDayThreshold, context, dayTableModel);
|
|
1110
|
+
const dayHeaderFormat = this.createDayHeaderFormatter(context.options.dayHeaderFormat, datesRepDistinctDays, dayTableModel.colCnt);
|
|
1111
|
+
return (createElement(NowTimer, { unit: "day" }, (nowDate, todayRange) => (createElement(DayGridLayout, { dateProfile: props.dateProfile, todayRange: todayRange, cellRows: dayTableModel.cellRows, forPrint: props.forPrint, className: 'fc-daygrid-view',
|
|
1112
|
+
// header content
|
|
1113
|
+
headerTiers: headerTiers, renderHeaderContent: (model, tier, innerHeightRef, colWidth) => {
|
|
1114
|
+
if (model.date) {
|
|
1115
|
+
return (createElement(DateHeaderCell, Object.assign({}, model, { dateProfile: props.dateProfile, todayRange: todayRange, navLink: dayTableModel.colCnt > 1, dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
return (createElement(DayOfWeekHeaderCell, Object.assign({}, model, { dayHeaderFormat: dayHeaderFormat, colSpan: model.colSpan, colWidth: colWidth })));
|
|
1119
|
+
}
|
|
1120
|
+
}, getHeaderModelKey: (model) => {
|
|
1121
|
+
// can use model.key???
|
|
1122
|
+
if (model.date) {
|
|
1123
|
+
return model.date.toUTCString();
|
|
1124
|
+
}
|
|
1125
|
+
return model.dow;
|
|
1126
|
+
},
|
|
1127
|
+
// body content
|
|
1128
|
+
fgEventSegs: slicedProps.fgEventSegs, bgEventSegs: slicedProps.bgEventSegs, businessHourSegs: slicedProps.businessHourSegs, dateSelectionSegs: slicedProps.dateSelectionSegs, eventDrag: slicedProps.eventDrag, eventResize: slicedProps.eventResize, eventSelection: slicedProps.eventSelection }))));
|
|
937
1129
|
}
|
|
938
1130
|
}
|
|
939
|
-
function buildDayTableModel(dateProfile, dateProfileGenerator) {
|
|
940
|
-
let daySeries = new DaySeriesModel(dateProfile.renderRange, dateProfileGenerator);
|
|
941
|
-
return new DayTableModel(daySeries, /year|month|week/.test(dateProfile.currentRangeUnit));
|
|
942
|
-
}
|
|
943
1131
|
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
dateEnv: props.dateEnv,
|
|
1132
|
+
/*
|
|
1133
|
+
TODO: is it even worth doing this "advanced" version?
|
|
1134
|
+
*/
|
|
1135
|
+
class HeaderRowAdvanced extends BaseComponent {
|
|
1136
|
+
constructor() {
|
|
1137
|
+
super(...arguments);
|
|
1138
|
+
// ref
|
|
1139
|
+
this.innerHeightRefMap = new RefMap(() => {
|
|
1140
|
+
afterSize(this.handleInnerHeights);
|
|
954
1141
|
});
|
|
1142
|
+
this.handleInnerHeights = () => {
|
|
1143
|
+
const innerHeightMap = this.innerHeightRefMap.current;
|
|
1144
|
+
let max = 0;
|
|
1145
|
+
for (const innerHeight of innerHeightMap.values()) {
|
|
1146
|
+
max = Math.max(max, innerHeight);
|
|
1147
|
+
}
|
|
1148
|
+
if (this.currentInnerHeight !== max) {
|
|
1149
|
+
this.currentInnerHeight = max;
|
|
1150
|
+
setRef(this.props.innerHeightRef, max);
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
955
1153
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
start = dateEnv.startOfWeek(start);
|
|
964
|
-
// make end-of-week if not already
|
|
965
|
-
endOfWeek = dateEnv.startOfWeek(end);
|
|
966
|
-
if (endOfWeek.valueOf() !== end.valueOf()) {
|
|
967
|
-
end = addWeeks(endOfWeek, 1);
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
// ensure 6 weeks
|
|
971
|
-
if (props.fixedWeekCount) {
|
|
972
|
-
// TODO: instead of these date-math gymnastics (for multimonth view),
|
|
973
|
-
// compute dateprofiles of all months, then use start of first and end of last.
|
|
974
|
-
let lastMonthRenderStart = dateEnv.startOfWeek(dateEnv.startOfMonth(addDays(currentRange.end, -1)));
|
|
975
|
-
let rowCnt = Math.ceil(// could be partial weeks due to hiddenDays
|
|
976
|
-
diffWeeks(lastMonthRenderStart, end));
|
|
977
|
-
end = addWeeks(end, 6 - rowCnt);
|
|
1154
|
+
render() {
|
|
1155
|
+
const { props } = this;
|
|
1156
|
+
return (createElement("div", { role: 'row', className: 'fc-row', style: { height: props.height } }, props.cells.map((cell) => {
|
|
1157
|
+
const key = props.getHeaderModelKey(cell);
|
|
1158
|
+
return (createElement(Fragment, { key: props.getHeaderModelKey(cell) }, props.renderHeaderContent(cell, props.tierNum, this.innerHeightRefMap.createRef(key), // innerHeightRef
|
|
1159
|
+
props.colWidth)));
|
|
1160
|
+
})));
|
|
978
1161
|
}
|
|
979
|
-
return { start, end };
|
|
980
1162
|
}
|
|
981
1163
|
|
|
982
|
-
|
|
983
|
-
injectStyles(css_248z);
|
|
984
|
-
|
|
985
|
-
export { DayTableView as DayGridView, DayTable, DayTableSlicer, Table, TableDateProfileGenerator, TableRows, TableView, buildDayTableModel, buildDayTableRenderRange };
|
|
1164
|
+
export { COMPACT_CELL_WIDTH, DateHeaderCell, DayGridLayout, DayGridRow, DayGridRows, DayGridView, DayOfWeekHeaderCell, DayTableSlicer, HeaderRow, HeaderRowAdvanced, TableDateProfileGenerator, buildDayTableModel, buildDayTableRenderRange, computeColFromPosition, computeColWidth, createDayHeaderFormatter, getCellEl, getRowEl };
|