@fullcalendar/scrollgrid 6.1.15 → 7.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs +2 -3
- package/index.global.js +68 -817
- package/index.global.min.js +2 -2
- package/index.js +3 -4
- package/internal.cjs +61 -813
- package/internal.d.ts +22 -71
- package/internal.js +62 -814
- package/package.json +3 -3
package/index.global.js
CHANGED
|
@@ -1,360 +1,83 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
FullCalendar ScrollGrid Plugin
|
|
2
|
+
FullCalendar ScrollGrid Plugin v7.0.0-beta.1
|
|
3
3
|
Docs & License: https://fullcalendar.io/docs/premium
|
|
4
4
|
(c) 2024 Adam Shaw
|
|
5
5
|
*/
|
|
6
|
-
FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, internal$1
|
|
6
|
+
FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, internal$1) {
|
|
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
12
|
|
|
13
|
-
// TODO: assume the el has no borders?
|
|
14
|
-
function getScrollCanvasOrigin(scrollEl) {
|
|
15
|
-
let rect = scrollEl.getBoundingClientRect();
|
|
16
|
-
let edges = internal$1.computeEdges(scrollEl); // TODO: pass in isRtl?
|
|
17
|
-
return {
|
|
18
|
-
left: rect.left + edges.borderLeft + edges.scrollbarLeft - getScrollFromLeftEdge(scrollEl),
|
|
19
|
-
top: rect.top + edges.borderTop - scrollEl.scrollTop,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function getScrollFromLeftEdge(el) {
|
|
23
|
-
let scrollLeft = el.scrollLeft;
|
|
24
|
-
let computedStyles = window.getComputedStyle(el); // TODO: pass in isRtl instead?
|
|
25
|
-
if (computedStyles.direction === 'rtl') {
|
|
26
|
-
switch (getRtlScrollSystem()) {
|
|
27
|
-
case 'negative':
|
|
28
|
-
scrollLeft *= -1; // convert to 'reverse'. fall through...
|
|
29
|
-
case 'reverse': // scrollLeft is distance between scrollframe's right edge scrollcanvas's right edge
|
|
30
|
-
scrollLeft = el.scrollWidth - scrollLeft - el.clientWidth;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return scrollLeft;
|
|
34
|
-
}
|
|
35
|
-
function setScrollFromLeftEdge(el, scrollLeft) {
|
|
36
|
-
let computedStyles = window.getComputedStyle(el); // TODO: pass in isRtl instead?
|
|
37
|
-
if (computedStyles.direction === 'rtl') {
|
|
38
|
-
switch (getRtlScrollSystem()) {
|
|
39
|
-
case 'reverse':
|
|
40
|
-
scrollLeft = el.scrollWidth - scrollLeft;
|
|
41
|
-
break;
|
|
42
|
-
case 'negative':
|
|
43
|
-
scrollLeft = -(el.scrollWidth - scrollLeft);
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
el.scrollLeft = scrollLeft;
|
|
48
|
-
}
|
|
49
|
-
// Horizontal Scroll System Detection
|
|
50
|
-
// ----------------------------------------------------------------------------------------------
|
|
51
|
-
let _rtlScrollSystem;
|
|
52
|
-
function getRtlScrollSystem() {
|
|
53
|
-
return _rtlScrollSystem || (_rtlScrollSystem = detectRtlScrollSystem());
|
|
54
|
-
}
|
|
55
|
-
function detectRtlScrollSystem() {
|
|
56
|
-
let el = document.createElement('div');
|
|
57
|
-
el.style.position = 'absolute';
|
|
58
|
-
el.style.top = '-1000px';
|
|
59
|
-
el.style.width = '100px'; // must be at least the side of scrollbars or you get inaccurate values (#7335)
|
|
60
|
-
el.style.height = '100px'; // "
|
|
61
|
-
el.style.overflow = 'scroll';
|
|
62
|
-
el.style.direction = 'rtl';
|
|
63
|
-
let innerEl = document.createElement('div');
|
|
64
|
-
innerEl.style.width = '200px';
|
|
65
|
-
innerEl.style.height = '200px';
|
|
66
|
-
el.appendChild(innerEl);
|
|
67
|
-
document.body.appendChild(el);
|
|
68
|
-
let system;
|
|
69
|
-
if (el.scrollLeft > 0) {
|
|
70
|
-
system = 'positive'; // scroll is a positive number from the left edge
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
el.scrollLeft = 1;
|
|
74
|
-
if (el.scrollLeft > 0) {
|
|
75
|
-
system = 'reverse'; // scroll is a positive number from the right edge
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
system = 'negative'; // scroll is a negative number from the right edge
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
internal$1.removeElement(el);
|
|
82
|
-
return system;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const STICKY_SELECTOR = '.fc-sticky';
|
|
86
13
|
/*
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
REQUIREMENT: fc-sticky elements, if the fc-sticky className is taken away, should NOT have relative or absolute positioning.
|
|
90
|
-
This is because we attach the coords with JS, and the VDOM might take away the fc-sticky class but doesn't know kill the positioning.
|
|
91
|
-
|
|
92
|
-
TODO: don't query text-align:center. isn't compatible with flexbox centering. instead, check natural X coord within parent container
|
|
14
|
+
Fires:
|
|
15
|
+
- scrollEnd: (x, y) => void
|
|
93
16
|
*/
|
|
94
|
-
class
|
|
95
|
-
constructor(
|
|
96
|
-
this.
|
|
97
|
-
this.
|
|
98
|
-
this.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
let elGeoms = this.queryElGeoms(els);
|
|
102
|
-
let viewportWidth = scrollEl.clientWidth;
|
|
103
|
-
assignStickyPositions(els, elGeoms, viewportWidth);
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
queryElGeoms(els) {
|
|
107
|
-
let { scrollEl, isRtl } = this;
|
|
108
|
-
let canvasOrigin = getScrollCanvasOrigin(scrollEl);
|
|
109
|
-
let elGeoms = [];
|
|
110
|
-
for (let el of els) {
|
|
111
|
-
let parentBound = internal$1.translateRect(internal$1.computeInnerRect(el.parentNode, true, true), // weird way to call this!!!
|
|
112
|
-
-canvasOrigin.left, -canvasOrigin.top);
|
|
113
|
-
let elRect = el.getBoundingClientRect();
|
|
114
|
-
let computedStyles = window.getComputedStyle(el);
|
|
115
|
-
let textAlign = window.getComputedStyle(el.parentNode).textAlign; // ask the parent
|
|
116
|
-
let naturalBound = null;
|
|
117
|
-
if (textAlign === 'start') {
|
|
118
|
-
textAlign = isRtl ? 'right' : 'left';
|
|
119
|
-
}
|
|
120
|
-
else if (textAlign === 'end') {
|
|
121
|
-
textAlign = isRtl ? 'left' : 'right';
|
|
122
|
-
}
|
|
123
|
-
if (computedStyles.position !== 'sticky') {
|
|
124
|
-
naturalBound = internal$1.translateRect(elRect, -canvasOrigin.left - (parseFloat(computedStyles.left) || 0), // could be 'auto'
|
|
125
|
-
-canvasOrigin.top - (parseFloat(computedStyles.top) || 0));
|
|
126
|
-
}
|
|
127
|
-
elGeoms.push({
|
|
128
|
-
parentBound,
|
|
129
|
-
naturalBound,
|
|
130
|
-
elWidth: elRect.width,
|
|
131
|
-
elHeight: elRect.height,
|
|
132
|
-
textAlign,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
return elGeoms;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function assignStickyPositions(els, elGeoms, viewportWidth) {
|
|
139
|
-
els.forEach((el, i) => {
|
|
140
|
-
let { textAlign, elWidth, parentBound } = elGeoms[i];
|
|
141
|
-
let parentWidth = parentBound.right - parentBound.left;
|
|
142
|
-
let left;
|
|
143
|
-
if (textAlign === 'center' &&
|
|
144
|
-
parentWidth > viewportWidth) {
|
|
145
|
-
left = (viewportWidth - elWidth) / 2;
|
|
146
|
-
}
|
|
147
|
-
else { // if parent container can be completely in view, we don't need stickiness
|
|
148
|
-
left = '';
|
|
149
|
-
}
|
|
150
|
-
internal$1.applyStyle(el, {
|
|
151
|
-
left,
|
|
152
|
-
right: left,
|
|
153
|
-
top: 0,
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
class ClippedScroller extends internal$1.BaseComponent {
|
|
159
|
-
constructor() {
|
|
160
|
-
super(...arguments);
|
|
161
|
-
this.elRef = preact.createRef();
|
|
162
|
-
this.state = {
|
|
163
|
-
xScrollbarWidth: 0,
|
|
164
|
-
yScrollbarWidth: 0,
|
|
165
|
-
};
|
|
166
|
-
this.handleScroller = (scroller) => {
|
|
167
|
-
this.scroller = scroller;
|
|
168
|
-
internal$1.setRef(this.props.scrollerRef, scroller);
|
|
169
|
-
};
|
|
170
|
-
this.handleSizing = () => {
|
|
171
|
-
let { props } = this;
|
|
172
|
-
if (props.overflowY === 'scroll-hidden') {
|
|
173
|
-
this.setState({ yScrollbarWidth: this.scroller.getYScrollbarWidth() });
|
|
174
|
-
}
|
|
175
|
-
if (props.overflowX === 'scroll-hidden') {
|
|
176
|
-
this.setState({ xScrollbarWidth: this.scroller.getXScrollbarWidth() });
|
|
177
|
-
}
|
|
178
|
-
};
|
|
17
|
+
class ScrollerSyncer {
|
|
18
|
+
constructor(isHorizontal = false) {
|
|
19
|
+
this.isHorizontal = isHorizontal;
|
|
20
|
+
this.emitter = new internal$1.Emitter();
|
|
21
|
+
this.scrollers = [];
|
|
22
|
+
this.destroyFuncs = [];
|
|
23
|
+
this.isPaused = false;
|
|
179
24
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (props.forPrint) {
|
|
188
|
-
overflowX = 'visible';
|
|
189
|
-
overflowY = 'visible';
|
|
190
|
-
}
|
|
191
|
-
if (overflowX === 'scroll-hidden') {
|
|
192
|
-
overcomeBottom = state.xScrollbarWidth;
|
|
193
|
-
}
|
|
194
|
-
if (overflowY === 'scroll-hidden') {
|
|
195
|
-
if (state.yScrollbarWidth != null) {
|
|
196
|
-
if (isScrollbarOnLeft) {
|
|
197
|
-
overcomeLeft = state.yScrollbarWidth;
|
|
25
|
+
handleChildren(scrollers) {
|
|
26
|
+
if (!internal$1.isArraysEqual(this.scrollers, scrollers)) {
|
|
27
|
+
this.destroy();
|
|
28
|
+
for (const scroller of scrollers) {
|
|
29
|
+
if (scroller) { // could be null
|
|
30
|
+
this.destroyFuncs.push(this.bindScroller(scroller));
|
|
31
|
+
this.scrollers.push(scroller);
|
|
198
32
|
}
|
|
199
|
-
else {
|
|
200
|
-
overcomeRight = state.yScrollbarWidth;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return (preact.createElement("div", { ref: this.elRef, className: 'fc-scroller-harness' + (props.liquid ? ' fc-scroller-harness-liquid' : '') },
|
|
205
|
-
preact.createElement(internal$1.Scroller, { ref: this.handleScroller, elRef: this.props.scrollerElRef, overflowX: overflowX === 'scroll-hidden' ? 'scroll' : overflowX, overflowY: overflowY === 'scroll-hidden' ? 'scroll' : overflowY, overcomeLeft: overcomeLeft, overcomeRight: overcomeRight, overcomeBottom: overcomeBottom, maxHeight: typeof props.maxHeight === 'number'
|
|
206
|
-
? (props.maxHeight + (overflowX === 'scroll-hidden' ? state.xScrollbarWidth : 0))
|
|
207
|
-
: '', liquid: props.liquid, liquidIsAbsolute: true }, props.children)));
|
|
208
|
-
}
|
|
209
|
-
componentDidMount() {
|
|
210
|
-
this.handleSizing();
|
|
211
|
-
this.context.addResizeHandler(this.handleSizing);
|
|
212
|
-
}
|
|
213
|
-
getSnapshotBeforeUpdate(prevProps) {
|
|
214
|
-
if (this.props.forPrint && !prevProps.forPrint) {
|
|
215
|
-
return { simulateScrollLeft: this.scroller.el.scrollLeft };
|
|
216
|
-
}
|
|
217
|
-
return {};
|
|
218
|
-
}
|
|
219
|
-
componentDidUpdate(prevProps, prevState, snapshot) {
|
|
220
|
-
const { props, scroller: { el: scrollerEl } } = this;
|
|
221
|
-
if (!internal$1.isPropsEqual(prevProps, props)) { // an external change?
|
|
222
|
-
this.handleSizing();
|
|
223
|
-
}
|
|
224
|
-
if (snapshot.simulateScrollLeft !== undefined) {
|
|
225
|
-
scrollerEl.style.left = -snapshot.simulateScrollLeft + 'px';
|
|
226
|
-
}
|
|
227
|
-
else if (!props.forPrint && prevProps.forPrint) {
|
|
228
|
-
const restoredScrollLeft = -parseInt(scrollerEl.style.left);
|
|
229
|
-
scrollerEl.style.left = '';
|
|
230
|
-
scrollerEl.scrollLeft = restoredScrollLeft;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
componentWillUnmount() {
|
|
234
|
-
this.context.removeResizeHandler(this.handleSizing);
|
|
235
|
-
}
|
|
236
|
-
needsXScrolling() {
|
|
237
|
-
return this.scroller.needsXScrolling();
|
|
238
|
-
}
|
|
239
|
-
needsYScrolling() {
|
|
240
|
-
return this.scroller.needsYScrolling();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const WHEEL_EVENT_NAMES = 'wheel mousewheel DomMouseScroll MozMousePixelScroll'.split(' ');
|
|
245
|
-
/*
|
|
246
|
-
ALSO, with the ability to disable touch
|
|
247
|
-
*/
|
|
248
|
-
class ScrollListener {
|
|
249
|
-
constructor(el) {
|
|
250
|
-
this.el = el;
|
|
251
|
-
this.emitter = new internal$1.Emitter();
|
|
252
|
-
this.isScrolling = false;
|
|
253
|
-
this.isTouching = false; // user currently has finger down?
|
|
254
|
-
this.isRecentlyWheeled = false;
|
|
255
|
-
this.isRecentlyScrolled = false;
|
|
256
|
-
this.wheelWaiter = new internal$1.DelayedRunner(this._handleWheelWaited.bind(this));
|
|
257
|
-
this.scrollWaiter = new internal$1.DelayedRunner(this._handleScrollWaited.bind(this));
|
|
258
|
-
// Handlers
|
|
259
|
-
// ----------------------------------------------------------------------------------------------
|
|
260
|
-
this.handleScroll = () => {
|
|
261
|
-
this.startScroll();
|
|
262
|
-
this.emitter.trigger('scroll', this.isRecentlyWheeled, this.isTouching);
|
|
263
|
-
this.isRecentlyScrolled = true;
|
|
264
|
-
this.scrollWaiter.request(500);
|
|
265
|
-
};
|
|
266
|
-
// will fire *before* the scroll event is fired (might not cause a scroll)
|
|
267
|
-
this.handleWheel = () => {
|
|
268
|
-
this.isRecentlyWheeled = true;
|
|
269
|
-
this.wheelWaiter.request(500);
|
|
270
|
-
};
|
|
271
|
-
// will fire *before* the scroll event is fired (might not cause a scroll)
|
|
272
|
-
this.handleTouchStart = () => {
|
|
273
|
-
this.isTouching = true;
|
|
274
|
-
};
|
|
275
|
-
this.handleTouchEnd = () => {
|
|
276
|
-
this.isTouching = false;
|
|
277
|
-
// if the user ended their touch, and the scroll area wasn't moving,
|
|
278
|
-
// we consider this to be the end of the scroll.
|
|
279
|
-
if (!this.isRecentlyScrolled) {
|
|
280
|
-
this.endScroll(); // won't fire if already ended
|
|
281
33
|
}
|
|
282
|
-
};
|
|
283
|
-
el.addEventListener('scroll', this.handleScroll);
|
|
284
|
-
el.addEventListener('touchstart', this.handleTouchStart, { passive: true });
|
|
285
|
-
el.addEventListener('touchend', this.handleTouchEnd);
|
|
286
|
-
for (let eventName of WHEEL_EVENT_NAMES) {
|
|
287
|
-
el.addEventListener(eventName, this.handleWheel);
|
|
288
34
|
}
|
|
289
35
|
}
|
|
290
36
|
destroy() {
|
|
291
|
-
let
|
|
292
|
-
|
|
293
|
-
el.removeEventListener('touchstart', this.handleTouchStart, { passive: true });
|
|
294
|
-
el.removeEventListener('touchend', this.handleTouchEnd);
|
|
295
|
-
for (let eventName of WHEEL_EVENT_NAMES) {
|
|
296
|
-
el.removeEventListener(eventName, this.handleWheel);
|
|
37
|
+
for (let destroyFunc of this.destroyFuncs) {
|
|
38
|
+
destroyFunc();
|
|
297
39
|
}
|
|
40
|
+
this.destroyFuncs = [];
|
|
41
|
+
this.scrollers = [];
|
|
298
42
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (!this.isScrolling) {
|
|
303
|
-
this.isScrolling = true;
|
|
304
|
-
this.emitter.trigger('scrollStart', this.isRecentlyWheeled, this.isTouching);
|
|
305
|
-
}
|
|
43
|
+
get x() {
|
|
44
|
+
const { scrollers, masterScroller } = this;
|
|
45
|
+
return (masterScroller || scrollers[0]).x;
|
|
306
46
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
this.isScrolling = false;
|
|
311
|
-
this.isRecentlyScrolled = true;
|
|
312
|
-
this.isRecentlyWheeled = false;
|
|
313
|
-
this.scrollWaiter.clear();
|
|
314
|
-
this.wheelWaiter.clear();
|
|
315
|
-
}
|
|
47
|
+
get y() {
|
|
48
|
+
const { scrollers, masterScroller } = this;
|
|
49
|
+
return (masterScroller || scrollers[0]).y;
|
|
316
50
|
}
|
|
317
|
-
|
|
318
|
-
this.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
this.endScroll(); // won't fire if already ended
|
|
51
|
+
scrollTo(scrollArg) {
|
|
52
|
+
this.isPaused = true;
|
|
53
|
+
const { scrollers } = this;
|
|
54
|
+
for (let scroller of scrollers) {
|
|
55
|
+
scroller.scrollTo(scrollArg);
|
|
323
56
|
}
|
|
324
|
-
}
|
|
325
|
-
_handleWheelWaited() {
|
|
326
|
-
this.isRecentlyWheeled = false;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
class ScrollSyncer {
|
|
331
|
-
constructor(isVertical, scrollEls) {
|
|
332
|
-
this.isVertical = isVertical;
|
|
333
|
-
this.scrollEls = scrollEls;
|
|
334
57
|
this.isPaused = false;
|
|
335
|
-
this.scrollListeners = scrollEls.map((el) => this.bindScroller(el));
|
|
336
58
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
scrollListener.destroy();
|
|
340
|
-
}
|
|
59
|
+
addScrollEndListener(handler) {
|
|
60
|
+
this.emitter.on('scrollEnd', handler);
|
|
341
61
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
62
|
+
removeScrollEndListener(handler) {
|
|
63
|
+
this.emitter.off('scrollEnd', handler);
|
|
64
|
+
}
|
|
65
|
+
bindScroller(scroller) {
|
|
66
|
+
let { isHorizontal } = this;
|
|
345
67
|
const onScroll = (isWheel, isTouch) => {
|
|
346
68
|
if (!this.isPaused) {
|
|
347
|
-
if (!this.
|
|
348
|
-
this.assignMaster(
|
|
69
|
+
if (!this.masterScroller || (this.masterScroller !== scroller && (isWheel || isTouch))) {
|
|
70
|
+
this.assignMaster(scroller);
|
|
349
71
|
}
|
|
350
|
-
if (this.
|
|
351
|
-
for (let
|
|
352
|
-
if (
|
|
353
|
-
if (
|
|
354
|
-
|
|
72
|
+
if (this.masterScroller === scroller) { // dealing with current
|
|
73
|
+
for (let otherScroller of this.scrollers) {
|
|
74
|
+
if (otherScroller !== scroller) {
|
|
75
|
+
if (isHorizontal) {
|
|
76
|
+
// TODO: user raw scrollLeft for better performance. No normalization necessary
|
|
77
|
+
otherScroller.scrollTo({ x: scroller.x });
|
|
355
78
|
}
|
|
356
79
|
else {
|
|
357
|
-
|
|
80
|
+
otherScroller.scrollTo({ y: scroller.y });
|
|
358
81
|
}
|
|
359
82
|
}
|
|
360
83
|
}
|
|
@@ -362,512 +85,40 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
|
|
|
362
85
|
}
|
|
363
86
|
};
|
|
364
87
|
const onScrollEnd = () => {
|
|
365
|
-
if (this.
|
|
366
|
-
this.
|
|
367
|
-
|
|
368
|
-
};
|
|
369
|
-
scrollListener.emitter.on('scroll', onScroll);
|
|
370
|
-
scrollListener.emitter.on('scrollEnd', onScrollEnd);
|
|
371
|
-
return scrollListener;
|
|
372
|
-
}
|
|
373
|
-
assignMaster(el) {
|
|
374
|
-
this.masterEl = el;
|
|
375
|
-
for (let scrollListener of this.scrollListeners) {
|
|
376
|
-
if (scrollListener.el !== el) {
|
|
377
|
-
scrollListener.endScroll(); // to prevent residual scrolls from reclaiming master
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
/*
|
|
382
|
-
will normalize the scrollLeft value
|
|
383
|
-
*/
|
|
384
|
-
forceScrollLeft(scrollLeft) {
|
|
385
|
-
this.isPaused = true;
|
|
386
|
-
for (let listener of this.scrollListeners) {
|
|
387
|
-
setScrollFromLeftEdge(listener.el, scrollLeft);
|
|
388
|
-
}
|
|
389
|
-
this.isPaused = false;
|
|
390
|
-
}
|
|
391
|
-
forceScrollTop(top) {
|
|
392
|
-
this.isPaused = true;
|
|
393
|
-
for (let listener of this.scrollListeners) {
|
|
394
|
-
listener.el.scrollTop = top;
|
|
395
|
-
}
|
|
396
|
-
this.isPaused = false;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
internal$1.config.SCROLLGRID_RESIZE_INTERVAL = 500;
|
|
401
|
-
/*
|
|
402
|
-
TODO: make <ScrollGridSection> subcomponent
|
|
403
|
-
NOTE: doesn't support collapsibleWidth (which is sortof a hack anyway)
|
|
404
|
-
*/
|
|
405
|
-
class ScrollGrid extends internal$1.BaseComponent {
|
|
406
|
-
constructor() {
|
|
407
|
-
super(...arguments);
|
|
408
|
-
this.compileColGroupStats = internal$1.memoizeArraylike(compileColGroupStat, isColGroupStatsEqual);
|
|
409
|
-
this.renderMicroColGroups = internal$1.memoizeArraylike(internal$1.renderMicroColGroup); // yucky to memoize VNodes, but much more efficient for consumers
|
|
410
|
-
this.clippedScrollerRefs = new internal$1.RefMap();
|
|
411
|
-
// doesn't hold non-scrolling els used just for padding
|
|
412
|
-
this.scrollerElRefs = new internal$1.RefMap(this._handleScrollerEl.bind(this));
|
|
413
|
-
this.chunkElRefs = new internal$1.RefMap(this._handleChunkEl.bind(this));
|
|
414
|
-
this.scrollSyncersBySection = {};
|
|
415
|
-
this.scrollSyncersByColumn = {};
|
|
416
|
-
// for row-height-syncing
|
|
417
|
-
this.rowUnstableMap = new Map(); // no need to groom. always self-cancels
|
|
418
|
-
this.rowInnerMaxHeightMap = new Map();
|
|
419
|
-
this.anyRowHeightsChanged = false;
|
|
420
|
-
this.recentSizingCnt = 0;
|
|
421
|
-
this.state = {
|
|
422
|
-
shrinkWidths: [],
|
|
423
|
-
forceYScrollbars: false,
|
|
424
|
-
forceXScrollbars: false,
|
|
425
|
-
scrollerClientWidths: {},
|
|
426
|
-
scrollerClientHeights: {},
|
|
427
|
-
sectionRowMaxHeights: [],
|
|
428
|
-
};
|
|
429
|
-
this.handleSizing = (isForcedResize, sectionRowMaxHeightsChanged) => {
|
|
430
|
-
if (!this.allowSizing()) {
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
if (!sectionRowMaxHeightsChanged) { // something else changed, probably external
|
|
434
|
-
this.anyRowHeightsChanged = true;
|
|
88
|
+
if (this.masterScroller === scroller) {
|
|
89
|
+
this.masterScroller = null;
|
|
90
|
+
this.emitter.trigger('scrollEnd', this.x, this.y);
|
|
435
91
|
}
|
|
436
|
-
let otherState = {};
|
|
437
|
-
// if reacting to self-change of sectionRowMaxHeightsChanged, or not stable, don't do anything
|
|
438
|
-
if (isForcedResize || (!sectionRowMaxHeightsChanged && !this.rowUnstableMap.size)) {
|
|
439
|
-
otherState.sectionRowMaxHeights = this.computeSectionRowMaxHeights();
|
|
440
|
-
}
|
|
441
|
-
this.setState(Object.assign(Object.assign({ shrinkWidths: this.computeShrinkWidths() }, this.computeScrollerDims()), otherState), () => {
|
|
442
|
-
if (!this.rowUnstableMap.size) {
|
|
443
|
-
this.updateStickyScrolling(); // needs to happen AFTER final positioning committed to DOM
|
|
444
|
-
}
|
|
445
|
-
});
|
|
446
92
|
};
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
else {
|
|
453
|
-
rowUnstableMap.delete(rowEl);
|
|
454
|
-
let innerMaxHeight = getRowInnerMaxHeight(rowEl);
|
|
455
|
-
if (!rowInnerMaxHeightMap.has(rowEl) || rowInnerMaxHeightMap.get(rowEl) !== innerMaxHeight) {
|
|
456
|
-
rowInnerMaxHeightMap.set(rowEl, innerMaxHeight);
|
|
457
|
-
this.anyRowHeightsChanged = true;
|
|
458
|
-
}
|
|
459
|
-
if (!rowUnstableMap.size && this.anyRowHeightsChanged) {
|
|
460
|
-
this.anyRowHeightsChanged = false;
|
|
461
|
-
this.setState({
|
|
462
|
-
sectionRowMaxHeights: this.computeSectionRowMaxHeights(),
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
}
|
|
93
|
+
scroller.listener.emitter.on('scroll', onScroll);
|
|
94
|
+
scroller.listener.emitter.on('scrollEnd', onScrollEnd);
|
|
95
|
+
return () => {
|
|
96
|
+
scroller.listener.emitter.off('scroll', onScroll);
|
|
97
|
+
scroller.listener.emitter.off('scrollEnd', onScrollEnd);
|
|
466
98
|
};
|
|
467
99
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
let
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
let classNames = internal$1.getScrollGridClassNames(props.liquid, context);
|
|
474
|
-
this.getDims();
|
|
475
|
-
// TODO: make DRY
|
|
476
|
-
let sectionConfigs = props.sections;
|
|
477
|
-
let configCnt = sectionConfigs.length;
|
|
478
|
-
let configI = 0;
|
|
479
|
-
let currentConfig;
|
|
480
|
-
let headSectionNodes = [];
|
|
481
|
-
let bodySectionNodes = [];
|
|
482
|
-
let footSectionNodes = [];
|
|
483
|
-
while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'header') {
|
|
484
|
-
headSectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights, true));
|
|
485
|
-
configI += 1;
|
|
486
|
-
}
|
|
487
|
-
while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'body') {
|
|
488
|
-
bodySectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights, false));
|
|
489
|
-
configI += 1;
|
|
490
|
-
}
|
|
491
|
-
while (configI < configCnt && (currentConfig = sectionConfigs[configI]).type === 'footer') {
|
|
492
|
-
footSectionNodes.push(this.renderSection(currentConfig, configI, colGroupStats, microColGroupNodes, state.sectionRowMaxHeights, true));
|
|
493
|
-
configI += 1;
|
|
494
|
-
}
|
|
495
|
-
const isBuggy = !internal$1.getCanVGrowWithinCell(); // see NOTE in SimpleScrollGrid
|
|
496
|
-
const roleAttrs = { role: 'rowgroup' };
|
|
497
|
-
return preact.createElement('table', {
|
|
498
|
-
ref: props.elRef,
|
|
499
|
-
role: 'grid',
|
|
500
|
-
className: classNames.join(' '),
|
|
501
|
-
}, renderMacroColGroup(colGroupStats, shrinkWidths), Boolean(!isBuggy && headSectionNodes.length) && preact.createElement('thead', roleAttrs, ...headSectionNodes), Boolean(!isBuggy && bodySectionNodes.length) && preact.createElement('tbody', roleAttrs, ...bodySectionNodes), Boolean(!isBuggy && footSectionNodes.length) && preact.createElement('tfoot', roleAttrs, ...footSectionNodes), isBuggy && preact.createElement('tbody', roleAttrs, ...headSectionNodes, ...bodySectionNodes, ...footSectionNodes));
|
|
502
|
-
}
|
|
503
|
-
renderSection(sectionConfig, sectionIndex, colGroupStats, microColGroupNodes, sectionRowMaxHeights, isHeader) {
|
|
504
|
-
if ('outerContent' in sectionConfig) {
|
|
505
|
-
return (preact.createElement(preact.Fragment, { key: sectionConfig.key }, sectionConfig.outerContent));
|
|
506
|
-
}
|
|
507
|
-
return (preact.createElement("tr", { key: sectionConfig.key, role: "presentation", className: internal$1.getSectionClassNames(sectionConfig, this.props.liquid).join(' ') }, sectionConfig.chunks.map((chunkConfig, i) => this.renderChunk(sectionConfig, sectionIndex, colGroupStats[i], microColGroupNodes[i], chunkConfig, i, (sectionRowMaxHeights[sectionIndex] || [])[i] || [], isHeader))));
|
|
508
|
-
}
|
|
509
|
-
renderChunk(sectionConfig, sectionIndex, colGroupStat, microColGroupNode, chunkConfig, chunkIndex, rowHeights, isHeader) {
|
|
510
|
-
if ('outerContent' in chunkConfig) {
|
|
511
|
-
return (preact.createElement(preact.Fragment, { key: chunkConfig.key }, chunkConfig.outerContent));
|
|
512
|
-
}
|
|
513
|
-
let { state } = this;
|
|
514
|
-
let { scrollerClientWidths, scrollerClientHeights } = state;
|
|
515
|
-
let [sectionCnt, chunksPerSection] = this.getDims();
|
|
516
|
-
let index = sectionIndex * chunksPerSection + chunkIndex;
|
|
517
|
-
let sideScrollIndex = (!this.context.isRtl || internal$1.getIsRtlScrollbarOnLeft()) ? chunksPerSection - 1 : 0;
|
|
518
|
-
let isVScrollSide = chunkIndex === sideScrollIndex;
|
|
519
|
-
let isLastSection = sectionIndex === sectionCnt - 1;
|
|
520
|
-
let forceXScrollbars = isLastSection && state.forceXScrollbars; // NOOOO can result in `null`
|
|
521
|
-
let forceYScrollbars = isVScrollSide && state.forceYScrollbars; // NOOOO can result in `null`
|
|
522
|
-
let allowXScrolling = colGroupStat && colGroupStat.allowXScrolling; // rename?
|
|
523
|
-
let allowYScrolling = internal$1.getAllowYScrolling(this.props, sectionConfig); // rename? do in section func?
|
|
524
|
-
let chunkVGrow = internal$1.getSectionHasLiquidHeight(this.props, sectionConfig); // do in section func?
|
|
525
|
-
let expandRows = sectionConfig.expandRows && chunkVGrow;
|
|
526
|
-
let tableMinWidth = (colGroupStat && colGroupStat.totalColMinWidth) || '';
|
|
527
|
-
let content = internal$1.renderChunkContent(sectionConfig, chunkConfig, {
|
|
528
|
-
tableColGroupNode: microColGroupNode,
|
|
529
|
-
tableMinWidth,
|
|
530
|
-
clientWidth: scrollerClientWidths[index] !== undefined ? scrollerClientWidths[index] : null,
|
|
531
|
-
clientHeight: scrollerClientHeights[index] !== undefined ? scrollerClientHeights[index] : null,
|
|
532
|
-
expandRows,
|
|
533
|
-
syncRowHeights: Boolean(sectionConfig.syncRowHeights),
|
|
534
|
-
rowSyncHeights: rowHeights,
|
|
535
|
-
reportRowHeightChange: this.handleRowHeightChange,
|
|
536
|
-
}, isHeader);
|
|
537
|
-
let overflowX = forceXScrollbars ? (isLastSection ? 'scroll' : 'scroll-hidden') :
|
|
538
|
-
!allowXScrolling ? 'hidden' :
|
|
539
|
-
(isLastSection ? 'auto' : 'scroll-hidden');
|
|
540
|
-
let overflowY = forceYScrollbars ? (isVScrollSide ? 'scroll' : 'scroll-hidden') :
|
|
541
|
-
!allowYScrolling ? 'hidden' :
|
|
542
|
-
(isVScrollSide ? 'auto' : 'scroll-hidden');
|
|
543
|
-
// it *could* be possible to reduce DOM wrappers by only doing a ClippedScroller when allowXScrolling or allowYScrolling,
|
|
544
|
-
// but if these values were to change, the inner components would be unmounted/remounted because of the parent change.
|
|
545
|
-
content = (preact.createElement(ClippedScroller, { ref: this.clippedScrollerRefs.createRef(index), scrollerElRef: this.scrollerElRefs.createRef(index), overflowX: overflowX, overflowY: overflowY, forPrint: this.props.forPrint, liquid: chunkVGrow, maxHeight: sectionConfig.maxHeight }, content));
|
|
546
|
-
return preact.createElement(isHeader ? 'th' : 'td', {
|
|
547
|
-
key: chunkConfig.key,
|
|
548
|
-
ref: this.chunkElRefs.createRef(index),
|
|
549
|
-
role: 'presentation',
|
|
550
|
-
}, content);
|
|
551
|
-
}
|
|
552
|
-
componentDidMount() {
|
|
553
|
-
this.getStickyScrolling = internal$1.memoizeArraylike(initStickyScrolling);
|
|
554
|
-
this.getScrollSyncersBySection = internal$1.memoizeHashlike(initScrollSyncer.bind(this, true), null, destroyScrollSyncer);
|
|
555
|
-
this.getScrollSyncersByColumn = internal$1.memoizeHashlike(initScrollSyncer.bind(this, false), null, destroyScrollSyncer);
|
|
556
|
-
this.updateScrollSyncers();
|
|
557
|
-
this.handleSizing(false);
|
|
558
|
-
this.context.addResizeHandler(this.handleSizing);
|
|
559
|
-
}
|
|
560
|
-
componentDidUpdate(prevProps, prevState) {
|
|
561
|
-
this.updateScrollSyncers();
|
|
562
|
-
// TODO: need better solution when state contains non-sizing things
|
|
563
|
-
this.handleSizing(false, prevState.sectionRowMaxHeights !== this.state.sectionRowMaxHeights);
|
|
564
|
-
}
|
|
565
|
-
componentWillUnmount() {
|
|
566
|
-
this.context.removeResizeHandler(this.handleSizing);
|
|
567
|
-
this.destroyScrollSyncers();
|
|
568
|
-
}
|
|
569
|
-
allowSizing() {
|
|
570
|
-
let now = new Date();
|
|
571
|
-
if (!this.lastSizingDate ||
|
|
572
|
-
now.valueOf() > this.lastSizingDate.valueOf() + internal$1.config.SCROLLGRID_RESIZE_INTERVAL) {
|
|
573
|
-
this.lastSizingDate = now;
|
|
574
|
-
this.recentSizingCnt = 0;
|
|
575
|
-
return true;
|
|
576
|
-
}
|
|
577
|
-
return (this.recentSizingCnt += 1) <= 10;
|
|
578
|
-
}
|
|
579
|
-
computeShrinkWidths() {
|
|
580
|
-
let colGroupStats = this.compileColGroupStats(this.props.colGroups.map((colGroup) => [colGroup]));
|
|
581
|
-
let [sectionCnt, chunksPerSection] = this.getDims();
|
|
582
|
-
let cnt = sectionCnt * chunksPerSection;
|
|
583
|
-
let shrinkWidths = [];
|
|
584
|
-
colGroupStats.forEach((colGroupStat, i) => {
|
|
585
|
-
if (colGroupStat.hasShrinkCol) {
|
|
586
|
-
let chunkEls = this.chunkElRefs.collect(i, cnt, chunksPerSection); // in one col
|
|
587
|
-
shrinkWidths[i] = internal$1.computeShrinkWidth(chunkEls);
|
|
588
|
-
}
|
|
589
|
-
});
|
|
590
|
-
return shrinkWidths;
|
|
591
|
-
}
|
|
592
|
-
// has the side effect of grooming rowInnerMaxHeightMap
|
|
593
|
-
// TODO: somehow short-circuit if there are no new height changes
|
|
594
|
-
computeSectionRowMaxHeights() {
|
|
595
|
-
let newHeightMap = new Map();
|
|
596
|
-
let [sectionCnt, chunksPerSection] = this.getDims();
|
|
597
|
-
let sectionRowMaxHeights = [];
|
|
598
|
-
for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) {
|
|
599
|
-
let sectionConfig = this.props.sections[sectionI];
|
|
600
|
-
let assignableHeights = []; // chunk, row
|
|
601
|
-
if (sectionConfig && sectionConfig.syncRowHeights) {
|
|
602
|
-
let rowHeightsByChunk = [];
|
|
603
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
604
|
-
let index = sectionI * chunksPerSection + chunkI;
|
|
605
|
-
let rowHeights = [];
|
|
606
|
-
let chunkEl = this.chunkElRefs.currentMap[index];
|
|
607
|
-
if (chunkEl) {
|
|
608
|
-
rowHeights = internal$1.findElements(chunkEl, '.fc-scrollgrid-sync-table tr').map((rowEl) => {
|
|
609
|
-
let max = getRowInnerMaxHeight(rowEl);
|
|
610
|
-
newHeightMap.set(rowEl, max);
|
|
611
|
-
return max;
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
else {
|
|
615
|
-
rowHeights = [];
|
|
616
|
-
}
|
|
617
|
-
rowHeightsByChunk.push(rowHeights);
|
|
618
|
-
}
|
|
619
|
-
let rowCnt = rowHeightsByChunk[0].length;
|
|
620
|
-
let isEqualRowCnt = true;
|
|
621
|
-
for (let chunkI = 1; chunkI < chunksPerSection; chunkI += 1) {
|
|
622
|
-
let isOuterContent = sectionConfig.chunks[chunkI] && sectionConfig.chunks[chunkI].outerContent !== undefined; // can be null
|
|
623
|
-
if (!isOuterContent && rowHeightsByChunk[chunkI].length !== rowCnt) { // skip outer content
|
|
624
|
-
isEqualRowCnt = false;
|
|
625
|
-
break;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
if (!isEqualRowCnt) {
|
|
629
|
-
let chunkHeightSums = [];
|
|
630
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
631
|
-
chunkHeightSums.push(sumNumbers(rowHeightsByChunk[chunkI]) + rowHeightsByChunk[chunkI].length);
|
|
632
|
-
}
|
|
633
|
-
let maxTotalSum = Math.max(...chunkHeightSums);
|
|
634
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
635
|
-
let rowInChunkCnt = rowHeightsByChunk[chunkI].length;
|
|
636
|
-
let rowInChunkTotalHeight = maxTotalSum - rowInChunkCnt; // subtract border
|
|
637
|
-
// height of non-first row. we do this to avoid rounding, because it's unreliable within a table
|
|
638
|
-
let rowInChunkHeightOthers = Math.floor(rowInChunkTotalHeight / rowInChunkCnt);
|
|
639
|
-
// whatever is leftover goes to the first row
|
|
640
|
-
let rowInChunkHeightFirst = rowInChunkTotalHeight - rowInChunkHeightOthers * (rowInChunkCnt - 1);
|
|
641
|
-
let rowInChunkHeights = [];
|
|
642
|
-
let row = 0;
|
|
643
|
-
if (row < rowInChunkCnt) {
|
|
644
|
-
rowInChunkHeights.push(rowInChunkHeightFirst);
|
|
645
|
-
row += 1;
|
|
646
|
-
}
|
|
647
|
-
while (row < rowInChunkCnt) {
|
|
648
|
-
rowInChunkHeights.push(rowInChunkHeightOthers);
|
|
649
|
-
row += 1;
|
|
650
|
-
}
|
|
651
|
-
assignableHeights.push(rowInChunkHeights);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
else {
|
|
655
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
656
|
-
assignableHeights.push([]);
|
|
657
|
-
}
|
|
658
|
-
for (let row = 0; row < rowCnt; row += 1) {
|
|
659
|
-
let rowHeightsAcrossChunks = [];
|
|
660
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
661
|
-
let h = rowHeightsByChunk[chunkI][row];
|
|
662
|
-
if (h != null) { // protect against outerContent
|
|
663
|
-
rowHeightsAcrossChunks.push(h);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
let maxHeight = Math.max(...rowHeightsAcrossChunks);
|
|
667
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
668
|
-
assignableHeights[chunkI].push(maxHeight);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
sectionRowMaxHeights.push(assignableHeights);
|
|
674
|
-
}
|
|
675
|
-
this.rowInnerMaxHeightMap = newHeightMap;
|
|
676
|
-
return sectionRowMaxHeights;
|
|
677
|
-
}
|
|
678
|
-
computeScrollerDims() {
|
|
679
|
-
let scrollbarWidth = internal$1.getScrollbarWidths();
|
|
680
|
-
let [sectionCnt, chunksPerSection] = this.getDims();
|
|
681
|
-
let sideScrollI = (!this.context.isRtl || internal$1.getIsRtlScrollbarOnLeft()) ? chunksPerSection - 1 : 0;
|
|
682
|
-
let lastSectionI = sectionCnt - 1;
|
|
683
|
-
let currentScrollers = this.clippedScrollerRefs.currentMap;
|
|
684
|
-
let scrollerEls = this.scrollerElRefs.currentMap;
|
|
685
|
-
let forceYScrollbars = false;
|
|
686
|
-
let forceXScrollbars = false;
|
|
687
|
-
let scrollerClientWidths = {};
|
|
688
|
-
let scrollerClientHeights = {};
|
|
689
|
-
for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) { // along edge
|
|
690
|
-
let index = sectionI * chunksPerSection + sideScrollI;
|
|
691
|
-
let scroller = currentScrollers[index];
|
|
692
|
-
if (scroller && scroller.needsYScrolling()) {
|
|
693
|
-
forceYScrollbars = true;
|
|
694
|
-
break;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) { // along last row
|
|
698
|
-
let index = lastSectionI * chunksPerSection + chunkI;
|
|
699
|
-
let scroller = currentScrollers[index];
|
|
700
|
-
if (scroller && scroller.needsXScrolling()) {
|
|
701
|
-
forceXScrollbars = true;
|
|
702
|
-
break;
|
|
100
|
+
assignMaster(masterScroller) {
|
|
101
|
+
this.masterScroller = masterScroller;
|
|
102
|
+
for (let scroller of this.scrollers) {
|
|
103
|
+
if (scroller !== masterScroller) {
|
|
104
|
+
scroller.endScroll(); // to prevent residual scrolls from reclaiming master
|
|
703
105
|
}
|
|
704
106
|
}
|
|
705
|
-
for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) {
|
|
706
|
-
for (let chunkI = 0; chunkI < chunksPerSection; chunkI += 1) {
|
|
707
|
-
let index = sectionI * chunksPerSection + chunkI;
|
|
708
|
-
let scrollerEl = scrollerEls[index];
|
|
709
|
-
if (scrollerEl) {
|
|
710
|
-
// TODO: weird way to get this. need harness b/c doesn't include table borders
|
|
711
|
-
let harnessEl = scrollerEl.parentNode;
|
|
712
|
-
scrollerClientWidths[index] = Math.floor(harnessEl.getBoundingClientRect().width - ((chunkI === sideScrollI && forceYScrollbars)
|
|
713
|
-
? scrollbarWidth.y // use global because scroller might not have scrollbars yet but will need them in future
|
|
714
|
-
: 0));
|
|
715
|
-
scrollerClientHeights[index] = Math.floor(harnessEl.getBoundingClientRect().height - ((sectionI === lastSectionI && forceXScrollbars)
|
|
716
|
-
? scrollbarWidth.x // use global because scroller might not have scrollbars yet but will need them in future
|
|
717
|
-
: 0));
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
return { forceYScrollbars, forceXScrollbars, scrollerClientWidths, scrollerClientHeights };
|
|
722
|
-
}
|
|
723
|
-
updateStickyScrolling() {
|
|
724
|
-
let { isRtl } = this.context;
|
|
725
|
-
let argsByKey = this.scrollerElRefs.getAll().map((scrollEl) => [scrollEl, isRtl]);
|
|
726
|
-
this.getStickyScrolling(argsByKey)
|
|
727
|
-
.forEach((stickyScrolling) => stickyScrolling.updateSize());
|
|
728
|
-
}
|
|
729
|
-
updateScrollSyncers() {
|
|
730
|
-
let [sectionCnt, chunksPerSection] = this.getDims();
|
|
731
|
-
let cnt = sectionCnt * chunksPerSection;
|
|
732
|
-
let scrollElsBySection = {};
|
|
733
|
-
let scrollElsByColumn = {};
|
|
734
|
-
let scrollElMap = this.scrollerElRefs.currentMap;
|
|
735
|
-
for (let sectionI = 0; sectionI < sectionCnt; sectionI += 1) {
|
|
736
|
-
let startIndex = sectionI * chunksPerSection;
|
|
737
|
-
let endIndex = startIndex + chunksPerSection;
|
|
738
|
-
scrollElsBySection[sectionI] = internal$1.collectFromHash(scrollElMap, startIndex, endIndex, 1); // use the filtered
|
|
739
|
-
}
|
|
740
|
-
for (let col = 0; col < chunksPerSection; col += 1) {
|
|
741
|
-
scrollElsByColumn[col] = this.scrollerElRefs.collect(col, cnt, chunksPerSection); // DON'T use the filtered
|
|
742
|
-
}
|
|
743
|
-
this.scrollSyncersBySection = this.getScrollSyncersBySection(scrollElsBySection);
|
|
744
|
-
this.scrollSyncersByColumn = this.getScrollSyncersByColumn(scrollElsByColumn);
|
|
745
|
-
}
|
|
746
|
-
destroyScrollSyncers() {
|
|
747
|
-
internal$1.mapHash(this.scrollSyncersBySection, destroyScrollSyncer);
|
|
748
|
-
internal$1.mapHash(this.scrollSyncersByColumn, destroyScrollSyncer);
|
|
749
|
-
}
|
|
750
|
-
getChunkConfigByIndex(index) {
|
|
751
|
-
let chunksPerSection = this.getDims()[1];
|
|
752
|
-
let sectionI = Math.floor(index / chunksPerSection);
|
|
753
|
-
let chunkI = index % chunksPerSection;
|
|
754
|
-
let sectionConfig = this.props.sections[sectionI];
|
|
755
|
-
return sectionConfig && sectionConfig.chunks[chunkI];
|
|
756
|
-
}
|
|
757
|
-
forceScrollLeft(col, scrollLeft) {
|
|
758
|
-
let scrollSyncer = this.scrollSyncersByColumn[col];
|
|
759
|
-
if (scrollSyncer) {
|
|
760
|
-
scrollSyncer.forceScrollLeft(scrollLeft);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
forceScrollTop(sectionI, scrollTop) {
|
|
764
|
-
let scrollSyncer = this.scrollSyncersBySection[sectionI];
|
|
765
|
-
if (scrollSyncer) {
|
|
766
|
-
scrollSyncer.forceScrollTop(scrollTop);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
_handleChunkEl(chunkEl, key) {
|
|
770
|
-
let chunkConfig = this.getChunkConfigByIndex(parseInt(key, 10));
|
|
771
|
-
if (chunkConfig) { // null if section disappeared. bad, b/c won't null-set the elRef
|
|
772
|
-
internal$1.setRef(chunkConfig.elRef, chunkEl);
|
|
773
|
-
}
|
|
774
107
|
}
|
|
775
|
-
_handleScrollerEl(scrollerEl, key) {
|
|
776
|
-
let chunkConfig = this.getChunkConfigByIndex(parseInt(key, 10));
|
|
777
|
-
if (chunkConfig) { // null if section disappeared. bad, b/c won't null-set the elRef
|
|
778
|
-
internal$1.setRef(chunkConfig.scrollerElRef, scrollerEl);
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
getDims() {
|
|
782
|
-
let sectionCnt = this.props.sections.length;
|
|
783
|
-
let chunksPerSection = sectionCnt ? this.props.sections[0].chunks.length : 0;
|
|
784
|
-
return [sectionCnt, chunksPerSection];
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
ScrollGrid.addStateEquality({
|
|
788
|
-
shrinkWidths: internal$1.isArraysEqual,
|
|
789
|
-
scrollerClientWidths: internal$1.isPropsEqual,
|
|
790
|
-
scrollerClientHeights: internal$1.isPropsEqual,
|
|
791
|
-
});
|
|
792
|
-
function sumNumbers(numbers) {
|
|
793
|
-
let sum = 0;
|
|
794
|
-
for (let n of numbers) {
|
|
795
|
-
sum += n;
|
|
796
|
-
}
|
|
797
|
-
return sum;
|
|
798
|
-
}
|
|
799
|
-
function getRowInnerMaxHeight(rowEl) {
|
|
800
|
-
let innerHeights = internal$1.findElements(rowEl, '.fc-scrollgrid-sync-inner').map(getElHeight);
|
|
801
|
-
if (innerHeights.length) {
|
|
802
|
-
return Math.max(...innerHeights);
|
|
803
|
-
}
|
|
804
|
-
return 0;
|
|
805
|
-
}
|
|
806
|
-
function getElHeight(el) {
|
|
807
|
-
return el.offsetHeight; // better to deal with integers, for rounding, for PureComponent
|
|
808
|
-
}
|
|
809
|
-
function renderMacroColGroup(colGroupStats, shrinkWidths) {
|
|
810
|
-
let children = colGroupStats.map((colGroupStat, i) => {
|
|
811
|
-
let width = colGroupStat.width;
|
|
812
|
-
if (width === 'shrink') {
|
|
813
|
-
width = colGroupStat.totalColWidth + internal$1.sanitizeShrinkWidth(shrinkWidths[i]) + 1; // +1 for border :(
|
|
814
|
-
}
|
|
815
|
-
return ( // eslint-disable-next-line react/jsx-key
|
|
816
|
-
preact.createElement("col", { style: { width } }));
|
|
817
|
-
});
|
|
818
|
-
return preact.createElement('colgroup', {}, ...children);
|
|
819
|
-
}
|
|
820
|
-
function compileColGroupStat(colGroupConfig) {
|
|
821
|
-
let totalColWidth = sumColProp(colGroupConfig.cols, 'width'); // excludes "shrink"
|
|
822
|
-
let totalColMinWidth = sumColProp(colGroupConfig.cols, 'minWidth');
|
|
823
|
-
let hasShrinkCol = internal$1.hasShrinkWidth(colGroupConfig.cols);
|
|
824
|
-
let allowXScrolling = colGroupConfig.width !== 'shrink' && Boolean(totalColWidth || totalColMinWidth || hasShrinkCol);
|
|
825
|
-
return {
|
|
826
|
-
hasShrinkCol,
|
|
827
|
-
totalColWidth,
|
|
828
|
-
totalColMinWidth,
|
|
829
|
-
allowXScrolling,
|
|
830
|
-
cols: colGroupConfig.cols,
|
|
831
|
-
width: colGroupConfig.width,
|
|
832
|
-
};
|
|
833
|
-
}
|
|
834
|
-
function sumColProp(cols, propName) {
|
|
835
|
-
let total = 0;
|
|
836
|
-
for (let col of cols) {
|
|
837
|
-
let val = col[propName];
|
|
838
|
-
if (typeof val === 'number') {
|
|
839
|
-
total += val * (col.span || 1);
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
return total;
|
|
843
|
-
}
|
|
844
|
-
const COL_GROUP_STAT_EQUALITY = {
|
|
845
|
-
cols: internal$1.isColPropsEqual,
|
|
846
|
-
};
|
|
847
|
-
function isColGroupStatsEqual(stat0, stat1) {
|
|
848
|
-
return internal$1.compareObjs(stat0, stat1, COL_GROUP_STAT_EQUALITY);
|
|
849
|
-
}
|
|
850
|
-
// for memoizers...
|
|
851
|
-
function initScrollSyncer(isVertical, ...scrollEls) {
|
|
852
|
-
return new ScrollSyncer(isVertical, scrollEls);
|
|
853
|
-
}
|
|
854
|
-
function destroyScrollSyncer(scrollSyncer) {
|
|
855
|
-
scrollSyncer.destroy();
|
|
856
|
-
}
|
|
857
|
-
function initStickyScrolling(scrollEl, isRtl) {
|
|
858
|
-
return new StickyScrolling(scrollEl, isRtl);
|
|
859
108
|
}
|
|
860
109
|
|
|
861
110
|
var plugin = core.createPlugin({
|
|
862
111
|
name: '@fullcalendar/scrollgrid',
|
|
863
|
-
premiumReleaseDate: '2024-
|
|
112
|
+
premiumReleaseDate: '2024-10-09',
|
|
864
113
|
deps: [premiumCommonPlugin__default["default"]],
|
|
865
|
-
|
|
114
|
+
scrollerSyncerClass: ScrollerSyncer
|
|
866
115
|
});
|
|
867
116
|
|
|
117
|
+
// new
|
|
118
|
+
|
|
868
119
|
var internal = {
|
|
869
120
|
__proto__: null,
|
|
870
|
-
|
|
121
|
+
ScrollerSyncer: ScrollerSyncer
|
|
871
122
|
};
|
|
872
123
|
|
|
873
124
|
core.globalPlugins.push(plugin);
|
|
@@ -879,4 +130,4 @@ FullCalendar.ScrollGrid = (function (exports, core, premiumCommonPlugin, interna
|
|
|
879
130
|
|
|
880
131
|
return exports;
|
|
881
132
|
|
|
882
|
-
})({}, FullCalendar, FullCalendar.PremiumCommon, FullCalendar.Internal
|
|
133
|
+
})({}, FullCalendar, FullCalendar.PremiumCommon, FullCalendar.Internal);
|