@fullcalendar/core 4.1.0 → 4.4.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/main.js CHANGED
@@ -1,8 +1,9 @@
1
1
  /*!
2
- FullCalendar Core Package v4.1.0
2
+ FullCalendar Core Package v4.4.0
3
3
  Docs & License: https://fullcalendar.io/
4
4
  (c) 2019 Adam Shaw
5
5
  */
6
+
6
7
  (function (global, factory) {
7
8
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
8
9
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -276,6 +277,7 @@ Docs & License: https://fullcalendar.io/
276
277
  var borderRight = parseInt(computedStyle.borderRightWidth, 10) || 0;
277
278
  var borderTop = parseInt(computedStyle.borderTopWidth, 10) || 0;
278
279
  var borderBottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
280
+ // must use offset(Width|Height) because compatible with client(Width|Height)
279
281
  var scrollbarLeftRight = sanitizeScrollbarWidth(el.offsetWidth - el.clientWidth - borderLeft - borderRight);
280
282
  var scrollbarBottom = sanitizeScrollbarWidth(el.offsetHeight - el.clientHeight - borderTop - borderBottom);
281
283
  var res = {
@@ -337,9 +339,11 @@ Docs & License: https://fullcalendar.io/
337
339
  };
338
340
  }
339
341
  function computeHeightAndMargins(el) {
342
+ return el.getBoundingClientRect().height + computeVMargins(el);
343
+ }
344
+ function computeVMargins(el) {
340
345
  var computed = window.getComputedStyle(el);
341
- return el.getBoundingClientRect().height +
342
- parseInt(computed.marginTop, 10) +
346
+ return parseInt(computed.marginTop, 10) +
343
347
  parseInt(computed.marginBottom, 10);
344
348
  }
345
349
  // does not return window
@@ -800,11 +804,12 @@ Docs & License: https://fullcalendar.io/
800
804
  // important to query for heights in a single first pass (to avoid reflow oscillation).
801
805
  els.forEach(function (el, i) {
802
806
  var minOffset = i === els.length - 1 ? minOffset2 : minOffset1;
803
- var naturalOffset = computeHeightAndMargins(el);
807
+ var naturalHeight = el.getBoundingClientRect().height;
808
+ var naturalOffset = naturalHeight + computeVMargins(el);
804
809
  if (naturalOffset < minOffset) {
805
810
  flexEls.push(el);
806
811
  flexOffsets.push(naturalOffset);
807
- flexHeights.push(el.offsetHeight);
812
+ flexHeights.push(naturalHeight);
808
813
  }
809
814
  else {
810
815
  // this element stretches past recommended height (non-expandable). mark the space as occupied.
@@ -842,7 +847,7 @@ Docs & License: https://fullcalendar.io/
842
847
  els.forEach(function (el) {
843
848
  var innerEl = el.firstChild; // hopefully an element
844
849
  if (innerEl instanceof HTMLElement) {
845
- var innerWidth_1 = innerEl.offsetWidth;
850
+ var innerWidth_1 = innerEl.getBoundingClientRect().width;
846
851
  if (innerWidth_1 > maxInnerWidth) {
847
852
  maxInnerWidth = innerWidth_1;
848
853
  }
@@ -864,7 +869,9 @@ Docs & License: https://fullcalendar.io/
864
869
  };
865
870
  applyStyle(outerEl, reflowStyleProps);
866
871
  applyStyle(innerEl, reflowStyleProps);
867
- var diff = outerEl.offsetHeight - innerEl.offsetHeight; // grab the dimensions
872
+ var diff = // grab the dimensions
873
+ outerEl.getBoundingClientRect().height -
874
+ innerEl.getBoundingClientRect().height;
868
875
  // undo hack
869
876
  var resetStyleProps = { position: '', left: '' };
870
877
  applyStyle(outerEl, resetStyleProps);
@@ -1071,16 +1078,6 @@ Docs & License: https://fullcalendar.io/
1071
1078
  }
1072
1079
  return refined;
1073
1080
  }
1074
- /*
1075
- Get a snapshot of an object, so we can compare it to later revisions.
1076
- Intentionally only works with arrays, jaja
1077
- */
1078
- function freezeRaw(raw) {
1079
- if (Array.isArray(raw)) {
1080
- return Array.prototype.slice.call(raw);
1081
- }
1082
- return raw;
1083
- }
1084
1081
  /* Date stuff that doesn't belong in datelib core
1085
1082
  ----------------------------------------------------------------------------------------------------------------------*/
1086
1083
  // given a timed range, computes an all-day range that has the same exact duration,
@@ -1203,9 +1200,12 @@ Docs & License: https://fullcalendar.io/
1203
1200
  /*
1204
1201
  Event MUST have a recurringDef
1205
1202
  */
1206
- function expandRecurringRanges(eventDef, framingRange, dateEnv, recurringTypes) {
1203
+ function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) {
1207
1204
  var typeDef = recurringTypes[eventDef.recurringDef.typeId];
1208
- var markers = typeDef.expand(eventDef.recurringDef.typeData, framingRange, dateEnv);
1205
+ var markers = typeDef.expand(eventDef.recurringDef.typeData, {
1206
+ start: dateEnv.subtract(framingRange.start, duration),
1207
+ end: framingRange.end
1208
+ }, dateEnv);
1209
1209
  // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to
1210
1210
  if (eventDef.allDay) {
1211
1211
  markers = markers.map(startOfDay);
@@ -1213,6 +1213,7 @@ Docs & License: https://fullcalendar.io/
1213
1213
  return markers;
1214
1214
  }
1215
1215
 
1216
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
1216
1217
  // Merges an array of objects into a single object.
1217
1218
  // The second argument allows for an array of property names who's object values will be merged together.
1218
1219
  function mergeProps(propObjs, complexProps) {
@@ -1286,6 +1287,23 @@ Docs & License: https://fullcalendar.io/
1286
1287
  }
1287
1288
  return a;
1288
1289
  }
1290
+ function isPropsEqual(obj0, obj1) {
1291
+ for (var key in obj0) {
1292
+ if (hasOwnProperty.call(obj0, key)) {
1293
+ if (!(key in obj1)) {
1294
+ return false;
1295
+ }
1296
+ }
1297
+ }
1298
+ for (var key in obj1) {
1299
+ if (hasOwnProperty.call(obj1, key)) {
1300
+ if (obj0[key] !== obj1[key]) {
1301
+ return false;
1302
+ }
1303
+ }
1304
+ }
1305
+ return true;
1306
+ }
1289
1307
 
1290
1308
  function parseEvents(rawEvents, sourceId, calendar, allowOpenRange) {
1291
1309
  var eventStore = createEmptyEventStore();
@@ -1316,13 +1334,13 @@ Docs & License: https://fullcalendar.io/
1316
1334
  for (var defId in defs) {
1317
1335
  var def = defs[defId];
1318
1336
  if (def.recurringDef) {
1319
- var starts = expandRecurringRanges(def, framingRange, calendar.dateEnv, calendar.pluginSystem.hooks.recurringTypes);
1320
1337
  var duration = def.recurringDef.duration;
1321
1338
  if (!duration) {
1322
1339
  duration = def.allDay ?
1323
1340
  calendar.defaultAllDayEventDuration :
1324
1341
  calendar.defaultTimedEventDuration;
1325
1342
  }
1343
+ var starts = expandRecurringRanges(def, duration, framingRange, calendar.dateEnv, calendar.pluginSystem.hooks.recurringTypes);
1326
1344
  for (var _i = 0, starts_1 = starts; _i < starts_1.length; _i++) {
1327
1345
  var start = starts_1[_i];
1328
1346
  var instance = createEventInstance(defId, {
@@ -2035,13 +2053,12 @@ Docs & License: https://fullcalendar.io/
2035
2053
  if (start && this._instance) { // TODO: warning if parsed bad
2036
2054
  var instanceRange = this._instance.range;
2037
2055
  var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity); // what if parsed bad!?
2038
- var endDelta = null;
2039
2056
  if (options.maintainDuration) {
2040
- var origDuration = diffDates(instanceRange.start, instanceRange.end, dateEnv, options.granularity);
2041
- var newDuration = diffDates(start, instanceRange.end, dateEnv, options.granularity);
2042
- endDelta = subtractDurations(origDuration, newDuration);
2057
+ this.mutate({ datesDelta: startDelta });
2058
+ }
2059
+ else {
2060
+ this.mutate({ startDelta: startDelta });
2043
2061
  }
2044
- this.mutate({ startDelta: startDelta, endDelta: endDelta });
2045
2062
  }
2046
2063
  };
2047
2064
  EventApi.prototype.setEnd = function (endInput, options) {
@@ -2089,11 +2106,16 @@ Docs & License: https://fullcalendar.io/
2089
2106
  var startDelta = diffDates(instanceRange.start, start, dateEnv, options.granularity);
2090
2107
  if (end) {
2091
2108
  var endDelta = diffDates(instanceRange.end, end, dateEnv, options.granularity);
2092
- this.mutate({ startDelta: startDelta, endDelta: endDelta, standardProps: standardProps });
2109
+ if (durationsEqual(startDelta, endDelta)) {
2110
+ this.mutate({ datesDelta: startDelta, standardProps: standardProps });
2111
+ }
2112
+ else {
2113
+ this.mutate({ startDelta: startDelta, endDelta: endDelta, standardProps: standardProps });
2114
+ }
2093
2115
  }
2094
- else {
2116
+ else { // means "clear the end"
2095
2117
  standardProps.hasEnd = false;
2096
- this.mutate({ startDelta: startDelta, standardProps: standardProps });
2118
+ this.mutate({ datesDelta: startDelta, standardProps: standardProps });
2097
2119
  }
2098
2120
  }
2099
2121
  };
@@ -2112,7 +2134,7 @@ Docs & License: https://fullcalendar.io/
2112
2134
  EventApi.prototype.moveDates = function (deltaInput) {
2113
2135
  var delta = createDuration(deltaInput);
2114
2136
  if (delta) { // TODO: warning if parsed bad
2115
- this.mutate({ startDelta: delta, endDelta: delta });
2137
+ this.mutate({ datesDelta: delta });
2116
2138
  }
2117
2139
  };
2118
2140
  EventApi.prototype.setAllDay = function (allDay, options) {
@@ -2370,12 +2392,13 @@ Docs & License: https://fullcalendar.io/
2370
2392
  function hasBgRendering(def) {
2371
2393
  return def.rendering === 'background' || def.rendering === 'inverse-background';
2372
2394
  }
2373
- function filterSegsViaEls(view, segs, isMirror) {
2374
- if (view.hasPublicHandlers('eventRender')) {
2395
+ function filterSegsViaEls(context, segs, isMirror) {
2396
+ var calendar = context.calendar, view = context.view;
2397
+ if (calendar.hasPublicHandlers('eventRender')) {
2375
2398
  segs = segs.filter(function (seg) {
2376
- var custom = view.publiclyTrigger('eventRender', [
2399
+ var custom = calendar.publiclyTrigger('eventRender', [
2377
2400
  {
2378
- event: new EventApi(view.calendar, seg.eventRange.def, seg.eventRange.instance),
2401
+ event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance),
2379
2402
  isMirror: isMirror,
2380
2403
  isStart: seg.isStart,
2381
2404
  isEnd: seg.isEnd,
@@ -2422,6 +2445,65 @@ Docs & License: https://fullcalendar.io/
2422
2445
  uis.push(eventDef.ui);
2423
2446
  return combineEventUis(uis);
2424
2447
  }
2448
+ // triggers
2449
+ function triggerRenderedSegs(context, segs, isMirrors) {
2450
+ var calendar = context.calendar, view = context.view;
2451
+ if (calendar.hasPublicHandlers('eventPositioned')) {
2452
+ for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
2453
+ var seg = segs_2[_i];
2454
+ calendar.publiclyTriggerAfterSizing('eventPositioned', [
2455
+ {
2456
+ event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance),
2457
+ isMirror: isMirrors,
2458
+ isStart: seg.isStart,
2459
+ isEnd: seg.isEnd,
2460
+ el: seg.el,
2461
+ view: view
2462
+ }
2463
+ ]);
2464
+ }
2465
+ }
2466
+ if (!calendar.state.loadingLevel) { // avoid initial empty state while pending
2467
+ calendar.afterSizingTriggers._eventsPositioned = [null]; // fire once
2468
+ }
2469
+ }
2470
+ function triggerWillRemoveSegs(context, segs, isMirrors) {
2471
+ var calendar = context.calendar, view = context.view;
2472
+ for (var _i = 0, segs_3 = segs; _i < segs_3.length; _i++) {
2473
+ var seg = segs_3[_i];
2474
+ calendar.trigger('eventElRemove', seg.el);
2475
+ }
2476
+ if (calendar.hasPublicHandlers('eventDestroy')) {
2477
+ for (var _a = 0, segs_4 = segs; _a < segs_4.length; _a++) {
2478
+ var seg = segs_4[_a];
2479
+ calendar.publiclyTrigger('eventDestroy', [
2480
+ {
2481
+ event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance),
2482
+ isMirror: isMirrors,
2483
+ el: seg.el,
2484
+ view: view
2485
+ }
2486
+ ]);
2487
+ }
2488
+ }
2489
+ }
2490
+ // is-interactable
2491
+ function computeEventDraggable(context, eventDef, eventUi) {
2492
+ var calendar = context.calendar, view = context.view;
2493
+ var transformers = calendar.pluginSystem.hooks.isDraggableTransformers;
2494
+ var val = eventUi.startEditable;
2495
+ for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) {
2496
+ var transformer = transformers_1[_i];
2497
+ val = transformer(val, eventDef, eventUi, view);
2498
+ }
2499
+ return val;
2500
+ }
2501
+ function computeEventStartResizable(context, eventDef, eventUi) {
2502
+ return eventUi.durationEditable && context.options.eventResizableFromStart;
2503
+ }
2504
+ function computeEventEndResizable(context, eventDef, eventUi) {
2505
+ return eventUi.durationEditable;
2506
+ }
2425
2507
 
2426
2508
  // applies the mutation to ALL defs/instances within the event store
2427
2509
  function applyMutationToEventStore(eventStore, eventConfigBase, mutation, calendar) {
@@ -2445,7 +2527,7 @@ Docs & License: https://fullcalendar.io/
2445
2527
  // and thus, we need to mark the event as having a real end
2446
2528
  if (standardProps.hasEnd == null &&
2447
2529
  eventConfig.durationEditable &&
2448
- willDeltasAffectDuration(eventConfig.startEditable ? mutation.startDelta : null, mutation.endDelta || null)) {
2530
+ (mutation.startDelta || mutation.endDelta)) {
2449
2531
  standardProps.hasEnd = true; // TODO: is this mutation okay?
2450
2532
  }
2451
2533
  var copy = __assign({}, eventDef, standardProps, { ui: __assign({}, eventDef.ui, standardProps.ui) });
@@ -2461,21 +2543,6 @@ Docs & License: https://fullcalendar.io/
2461
2543
  }
2462
2544
  return copy;
2463
2545
  }
2464
- function willDeltasAffectDuration(startDelta, endDelta) {
2465
- if (startDelta && !asRoughMs(startDelta)) {
2466
- startDelta = null;
2467
- }
2468
- if (endDelta && !asRoughMs(endDelta)) {
2469
- endDelta = null;
2470
- }
2471
- if (!startDelta && !endDelta) {
2472
- return false;
2473
- }
2474
- if (Boolean(startDelta) !== Boolean(endDelta)) {
2475
- return true;
2476
- }
2477
- return !durationsEqual(startDelta, endDelta);
2478
- }
2479
2546
  function applyMutationToEventInstance(eventInstance, eventDef, // must first be modified by applyMutationToEventDef
2480
2547
  eventConfig, mutation, calendar) {
2481
2548
  var dateEnv = calendar.dateEnv;
@@ -2485,25 +2552,28 @@ Docs & License: https://fullcalendar.io/
2485
2552
  if (forceAllDay) {
2486
2553
  copy.range = computeAlignedDayRange(copy.range);
2487
2554
  }
2488
- if (mutation.startDelta && eventConfig.startEditable) {
2555
+ if (mutation.datesDelta && eventConfig.startEditable) {
2556
+ copy.range = {
2557
+ start: dateEnv.add(copy.range.start, mutation.datesDelta),
2558
+ end: dateEnv.add(copy.range.end, mutation.datesDelta)
2559
+ };
2560
+ }
2561
+ if (mutation.startDelta && eventConfig.durationEditable) {
2489
2562
  copy.range = {
2490
2563
  start: dateEnv.add(copy.range.start, mutation.startDelta),
2491
2564
  end: copy.range.end
2492
2565
  };
2493
2566
  }
2494
- if (clearEnd) {
2567
+ if (mutation.endDelta && eventConfig.durationEditable) {
2495
2568
  copy.range = {
2496
2569
  start: copy.range.start,
2497
- end: calendar.getDefaultEventEnd(eventDef.allDay, copy.range.start)
2570
+ end: dateEnv.add(copy.range.end, mutation.endDelta)
2498
2571
  };
2499
2572
  }
2500
- else if (mutation.endDelta &&
2501
- (eventConfig.durationEditable ||
2502
- !willDeltasAffectDuration(// TODO: nonDRY logic above
2503
- eventConfig.startEditable ? mutation.startDelta : null, mutation.endDelta))) {
2573
+ if (clearEnd) {
2504
2574
  copy.range = {
2505
2575
  start: copy.range.start,
2506
- end: dateEnv.add(copy.range.end, mutation.endDelta)
2576
+ end: calendar.getDefaultEventEnd(eventDef.allDay, copy.range.start)
2507
2577
  };
2508
2578
  }
2509
2579
  // in case event was all-day but the supplied deltas were not
@@ -2709,11 +2779,12 @@ Docs & License: https://fullcalendar.io/
2709
2779
  }
2710
2780
  }
2711
2781
  // allow (a function)
2782
+ var calendarEventStore = calendar.state.eventStore; // need global-to-calendar, not local to component (splittable)state
2712
2783
  for (var _i = 0, _a = subjectConfig.allows; _i < _a.length; _i++) {
2713
2784
  var subjectAllow = _a[_i];
2714
2785
  var subjectDateSpan = __assign({}, dateSpanMeta, { range: subjectInstance.range, allDay: subjectDef.allDay });
2715
- var origDef = state.eventStore.defs[subjectDef.defId];
2716
- var origInstance = state.eventStore.instances[subjectInstanceId];
2786
+ var origDef = calendarEventStore.defs[subjectDef.defId];
2787
+ var origInstance = calendarEventStore.instances[subjectInstanceId];
2717
2788
  var eventApi = void 0;
2718
2789
  if (origDef) { // was previously in the calendar
2719
2790
  eventApi = new EventApi(calendar, origDef, origInstance);
@@ -3187,90 +3258,6 @@ Docs & License: https://fullcalendar.io/
3187
3258
  return res;
3188
3259
  }
3189
3260
 
3190
- function isValuesSimilar(val0, val1, depth) {
3191
- if (depth === void 0) { depth = 1; }
3192
- if (val0 === val1) {
3193
- return true;
3194
- }
3195
- else if (Array.isArray(val0) && Array.isArray(val1)) {
3196
- return isArraysSimilar(val0, val1, depth);
3197
- }
3198
- else if (typeof val0 === 'object' && val0 && typeof val1 === 'object' && val1) { // non-null objects
3199
- return isObjectsSimilar(val0, val1, depth);
3200
- }
3201
- else {
3202
- return false;
3203
- }
3204
- }
3205
- function isArraysSimilar(a0, a1, depth) {
3206
- if (depth === void 0) { depth = 1; }
3207
- if (a0 === a1) {
3208
- return true;
3209
- }
3210
- else if (depth > 0) {
3211
- if (a0.length !== a1.length) {
3212
- return false;
3213
- }
3214
- else {
3215
- for (var i = 0; i < a0.length; i++) {
3216
- if (!isValuesSimilar(a0[i], a1[i], depth - 1)) {
3217
- return false;
3218
- }
3219
- }
3220
- return true;
3221
- }
3222
- }
3223
- else {
3224
- return false;
3225
- }
3226
- }
3227
- function isObjectsSimilar(obj0, obj1, depth) {
3228
- if (depth === void 0) { depth = 1; }
3229
- if (obj0 === obj1) {
3230
- return true;
3231
- }
3232
- else if (depth > 0) {
3233
- for (var prop in obj0) {
3234
- if (!(prop in obj1)) {
3235
- return false;
3236
- }
3237
- }
3238
- for (var prop in obj1) {
3239
- if (!(prop in obj0)) {
3240
- return false;
3241
- }
3242
- else {
3243
- if (!isValuesSimilar(obj0[prop], obj1[prop], depth - 1)) {
3244
- return false;
3245
- }
3246
- }
3247
- }
3248
- return true;
3249
- }
3250
- else {
3251
- return false;
3252
- }
3253
- }
3254
- function computeChangedProps(obj0, obj1, depth) {
3255
- if (depth === void 0) { depth = 1; }
3256
- var res = {};
3257
- for (var prop in obj1) {
3258
- if (!(prop in obj0) ||
3259
- !isValuesSimilar(obj0[prop], obj1[prop], depth - 1)) {
3260
- res[prop] = obj1[prop];
3261
- }
3262
- }
3263
- return res;
3264
- }
3265
- function anyKeysRemoved(obj0, obj1) {
3266
- for (var prop in obj0) {
3267
- if (!(prop in obj1)) {
3268
- return true;
3269
- }
3270
- }
3271
- return false;
3272
- }
3273
-
3274
3261
  var EMPTY_EVENT_STORE = createEmptyEventStore(); // for purecomponents. TODO: keep elsewhere
3275
3262
  var Splitter = /** @class */ (function () {
3276
3263
  function Splitter() {
@@ -3418,8 +3405,7 @@ Docs & License: https://fullcalendar.io/
3418
3405
  // { date, type, forceOff }
3419
3406
  // `type` is a view-type like "day" or "week". default value is "day".
3420
3407
  // `attrs` and `innerHtml` are use to generate the rest of the HTML tag.
3421
- function buildGotoAnchorHtml(component, gotoOptions, attrs, innerHtml) {
3422
- var dateEnv = component.dateEnv;
3408
+ function buildGotoAnchorHtml(allOptions, dateEnv, gotoOptions, attrs, innerHtml) {
3423
3409
  var date;
3424
3410
  var type;
3425
3411
  var forceOff;
@@ -3442,7 +3428,7 @@ Docs & License: https://fullcalendar.io/
3442
3428
  }
3443
3429
  attrs = attrs ? ' ' + attrsToStr(attrs) : ''; // will have a leading space
3444
3430
  innerHtml = innerHtml || '';
3445
- if (!forceOff && component.opt('navLinks')) {
3431
+ if (!forceOff && allOptions.navLinks) {
3446
3432
  return '<a' + attrs +
3447
3433
  ' data-goto="' + htmlEscape(JSON.stringify(finalOptions)) + '">' +
3448
3434
  innerHtml +
@@ -3454,12 +3440,12 @@ Docs & License: https://fullcalendar.io/
3454
3440
  '</span>';
3455
3441
  }
3456
3442
  }
3457
- function getAllDayHtml(component) {
3458
- return component.opt('allDayHtml') || htmlEscape(component.opt('allDayText'));
3443
+ function getAllDayHtml(allOptions) {
3444
+ return allOptions.allDayHtml || htmlEscape(allOptions.allDayText);
3459
3445
  }
3460
3446
  // Computes HTML classNames for a single-day element
3461
3447
  function getDayClasses(date, dateProfile, context, noThemeHighlight) {
3462
- var calendar = context.calendar, view = context.view, theme = context.theme, dateEnv = context.dateEnv;
3448
+ var calendar = context.calendar, options = context.options, theme = context.theme, dateEnv = context.dateEnv;
3463
3449
  var classes = [];
3464
3450
  var todayStart;
3465
3451
  var todayEnd;
@@ -3468,7 +3454,7 @@ Docs & License: https://fullcalendar.io/
3468
3454
  }
3469
3455
  else {
3470
3456
  classes.push('fc-' + DAY_IDS[date.getUTCDay()]);
3471
- if (view.opt('monthMode') &&
3457
+ if (options.monthMode &&
3472
3458
  dateEnv.getMonth(date) !== dateEnv.getMonth(dateProfile.currentRange.start)) {
3473
3459
  classes.push('fc-other-month');
3474
3460
  }
@@ -3933,34 +3919,54 @@ Docs & License: https://fullcalendar.io/
3933
3919
  Theme.prototype.iconOverridePrefix = '';
3934
3920
 
3935
3921
  var guid = 0;
3922
+ var ComponentContext = /** @class */ (function () {
3923
+ function ComponentContext(calendar, theme, dateEnv, options, view) {
3924
+ this.calendar = calendar;
3925
+ this.theme = theme;
3926
+ this.dateEnv = dateEnv;
3927
+ this.options = options;
3928
+ this.view = view;
3929
+ this.isRtl = options.dir === 'rtl';
3930
+ this.eventOrderSpecs = parseFieldSpecs(options.eventOrder);
3931
+ this.nextDayThreshold = createDuration(options.nextDayThreshold);
3932
+ }
3933
+ ComponentContext.prototype.extend = function (options, view) {
3934
+ return new ComponentContext(this.calendar, this.theme, this.dateEnv, options || this.options, view || this.view);
3935
+ };
3936
+ return ComponentContext;
3937
+ }());
3936
3938
  var Component = /** @class */ (function () {
3937
- function Component(context, isView) {
3938
- // HACK to populate view at top of component instantiation call chain
3939
- if (isView) {
3940
- context.view = this;
3941
- }
3939
+ function Component() {
3942
3940
  this.uid = String(guid++);
3943
- this.context = context;
3944
- this.dateEnv = context.dateEnv;
3945
- this.theme = context.theme;
3946
- this.view = context.view;
3947
- this.calendar = context.calendar;
3948
- this.isRtl = this.opt('dir') === 'rtl';
3949
3941
  }
3950
3942
  Component.addEqualityFuncs = function (newFuncs) {
3951
3943
  this.prototype.equalityFuncs = __assign({}, this.prototype.equalityFuncs, newFuncs);
3952
3944
  };
3953
- Component.prototype.opt = function (name) {
3954
- return this.context.options[name];
3955
- };
3956
- Component.prototype.receiveProps = function (props) {
3945
+ Component.prototype.receiveProps = function (props, context) {
3946
+ var oldContext = this.context;
3947
+ this.context = context;
3948
+ if (!oldContext) {
3949
+ this.firstContext(context);
3950
+ }
3957
3951
  var _a = recycleProps(this.props || {}, props, this.equalityFuncs), anyChanges = _a.anyChanges, comboProps = _a.comboProps;
3958
3952
  this.props = comboProps;
3959
3953
  if (anyChanges) {
3960
- this.render(comboProps);
3954
+ if (oldContext) {
3955
+ this.beforeUpdate();
3956
+ }
3957
+ this.render(comboProps, context);
3958
+ if (oldContext) {
3959
+ this.afterUpdate();
3960
+ }
3961
3961
  }
3962
3962
  };
3963
- Component.prototype.render = function (props) {
3963
+ Component.prototype.render = function (props, context) {
3964
+ };
3965
+ Component.prototype.firstContext = function (context) {
3966
+ };
3967
+ Component.prototype.beforeUpdate = function () {
3968
+ };
3969
+ Component.prototype.afterUpdate = function () {
3964
3970
  };
3965
3971
  // after destroy is called, this component won't ever be used again
3966
3972
  Component.prototype.destroy = function () {
@@ -4002,8 +4008,8 @@ Docs & License: https://fullcalendar.io/
4002
4008
  */
4003
4009
  var DateComponent = /** @class */ (function (_super) {
4004
4010
  __extends(DateComponent, _super);
4005
- function DateComponent(context, el, isView) {
4006
- var _this = _super.call(this, context, isView) || this;
4011
+ function DateComponent(el) {
4012
+ var _this = _super.call(this) || this;
4007
4013
  _this.el = el;
4008
4014
  return _this;
4009
4015
  }
@@ -4011,38 +4017,6 @@ Docs & License: https://fullcalendar.io/
4011
4017
  _super.prototype.destroy.call(this);
4012
4018
  removeElement(this.el);
4013
4019
  };
4014
- // TODO: WHAT ABOUT (sourceSeg && sourceSeg.component.doesDragMirror)
4015
- //
4016
- // Event Drag-n-Drop Rendering (for both events and external elements)
4017
- // ---------------------------------------------------------------------------------------------------------------
4018
- /*
4019
- renderEventDragSegs(state: EventSegUiInteractionState) {
4020
- if (state) {
4021
- let { isEvent, segs, sourceSeg } = state
4022
-
4023
- if (this.eventRenderer) {
4024
- this.eventRenderer.hideByHash(state.affectedInstances)
4025
- }
4026
-
4027
- // if the user is dragging something that is considered an event with real event data,
4028
- // and this component likes to do drag mirrors OR the component where the seg came from
4029
- // likes to do drag mirrors, then render a drag mirror.
4030
- if (isEvent && (this.doesDragMirror || sourceSeg && sourceSeg.component.doesDragMirror)) {
4031
- if (this.mirrorRenderer) {
4032
- this.mirrorRenderer.renderSegs(segs, { isDragging: true, sourceSeg })
4033
- }
4034
- }
4035
-
4036
- // if it would be impossible to render a drag mirror OR this component likes to render
4037
- // highlights, then render a highlight.
4038
- if (!isEvent || this.doesDragHighlight) {
4039
- if (this.fillRenderer) {
4040
- this.fillRenderer.renderSegs('highlight', segs)
4041
- }
4042
- }
4043
- }
4044
- }
4045
- */
4046
4020
  // Hit System
4047
4021
  // -----------------------------------------------------------------------------------------------------------------
4048
4022
  DateComponent.prototype.buildPositionCaches = function () {
@@ -4053,7 +4027,7 @@ Docs & License: https://fullcalendar.io/
4053
4027
  // Validation
4054
4028
  // -----------------------------------------------------------------------------------------------------------------
4055
4029
  DateComponent.prototype.isInteractionValid = function (interaction) {
4056
- var calendar = this.calendar;
4030
+ var calendar = this.context.calendar;
4057
4031
  var dateProfile = this.props.dateProfile; // HACK
4058
4032
  var instances = interaction.mutatedEvents.instances;
4059
4033
  if (dateProfile) { // HACK for DayTile
@@ -4066,68 +4040,13 @@ Docs & License: https://fullcalendar.io/
4066
4040
  return isInteractionValid(interaction, calendar);
4067
4041
  };
4068
4042
  DateComponent.prototype.isDateSelectionValid = function (selection) {
4043
+ var calendar = this.context.calendar;
4069
4044
  var dateProfile = this.props.dateProfile; // HACK
4070
4045
  if (dateProfile && // HACK for DayTile
4071
4046
  !rangeContainsRange(dateProfile.validRange, selection.range)) {
4072
4047
  return false;
4073
4048
  }
4074
- return isDateSelectionValid(selection, this.calendar);
4075
- };
4076
- // Triggering
4077
- // -----------------------------------------------------------------------------------------------------------------
4078
- // TODO: move to Calendar
4079
- DateComponent.prototype.publiclyTrigger = function (name, args) {
4080
- var calendar = this.calendar;
4081
- return calendar.publiclyTrigger(name, args);
4082
- };
4083
- DateComponent.prototype.publiclyTriggerAfterSizing = function (name, args) {
4084
- var calendar = this.calendar;
4085
- return calendar.publiclyTriggerAfterSizing(name, args);
4086
- };
4087
- DateComponent.prototype.hasPublicHandlers = function (name) {
4088
- var calendar = this.calendar;
4089
- return calendar.hasPublicHandlers(name);
4090
- };
4091
- DateComponent.prototype.triggerRenderedSegs = function (segs, isMirrors) {
4092
- var calendar = this.calendar;
4093
- if (this.hasPublicHandlers('eventPositioned')) {
4094
- for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
4095
- var seg = segs_1[_i];
4096
- this.publiclyTriggerAfterSizing('eventPositioned', [
4097
- {
4098
- event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance),
4099
- isMirror: isMirrors,
4100
- isStart: seg.isStart,
4101
- isEnd: seg.isEnd,
4102
- el: seg.el,
4103
- view: this // ?
4104
- }
4105
- ]);
4106
- }
4107
- }
4108
- if (!calendar.state.loadingLevel) { // avoid initial empty state while pending
4109
- calendar.afterSizingTriggers._eventsPositioned = [null]; // fire once
4110
- }
4111
- };
4112
- DateComponent.prototype.triggerWillRemoveSegs = function (segs, isMirrors) {
4113
- var calendar = this.calendar;
4114
- for (var _i = 0, segs_2 = segs; _i < segs_2.length; _i++) {
4115
- var seg = segs_2[_i];
4116
- calendar.trigger('eventElRemove', seg.el);
4117
- }
4118
- if (this.hasPublicHandlers('eventDestroy')) {
4119
- for (var _a = 0, segs_3 = segs; _a < segs_3.length; _a++) {
4120
- var seg = segs_3[_a];
4121
- this.publiclyTrigger('eventDestroy', [
4122
- {
4123
- event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance),
4124
- isMirror: isMirrors,
4125
- el: seg.el,
4126
- view: this // ?
4127
- }
4128
- ]);
4129
- }
4130
- }
4049
+ return isDateSelectionValid(selection, calendar);
4131
4050
  };
4132
4051
  // Pointer Interaction Utils
4133
4052
  // -----------------------------------------------------------------------------------------------------------------
@@ -4164,6 +4083,7 @@ Docs & License: https://fullcalendar.io/
4164
4083
  deps: input.deps || [],
4165
4084
  reducers: input.reducers || [],
4166
4085
  eventDefParsers: input.eventDefParsers || [],
4086
+ isDraggableTransformers: input.isDraggableTransformers || [],
4167
4087
  eventDragMutationMassagers: input.eventDragMutationMassagers || [],
4168
4088
  eventDefMutationAppliers: input.eventDefMutationAppliers || [],
4169
4089
  dateSelectionTransformers: input.dateSelectionTransformers || [],
@@ -4193,6 +4113,7 @@ Docs & License: https://fullcalendar.io/
4193
4113
  this.hooks = {
4194
4114
  reducers: [],
4195
4115
  eventDefParsers: [],
4116
+ isDraggableTransformers: [],
4196
4117
  eventDragMutationMassagers: [],
4197
4118
  eventDefMutationAppliers: [],
4198
4119
  dateSelectionTransformers: [],
@@ -4234,6 +4155,7 @@ Docs & License: https://fullcalendar.io/
4234
4155
  return {
4235
4156
  reducers: hooks0.reducers.concat(hooks1.reducers),
4236
4157
  eventDefParsers: hooks0.eventDefParsers.concat(hooks1.eventDefParsers),
4158
+ isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers),
4237
4159
  eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers),
4238
4160
  eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers),
4239
4161
  dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers),
@@ -4441,11 +4363,17 @@ Docs & License: https://fullcalendar.io/
4441
4363
  }
4442
4364
  }
4443
4365
  if (anyValid) {
4366
+ var duration = null;
4367
+ if ('duration' in leftoverProps) {
4368
+ duration = createDuration(leftoverProps.duration);
4369
+ delete leftoverProps.duration;
4370
+ }
4371
+ if (!duration && props.startTime && props.endTime) {
4372
+ duration = subtractDurations(props.endTime, props.startTime);
4373
+ }
4444
4374
  return {
4445
4375
  allDayGuess: Boolean(!props.startTime && !props.endTime),
4446
- duration: (props.startTime && props.endTime) ?
4447
- subtractDurations(props.endTime, props.startTime) :
4448
- null,
4376
+ duration: duration,
4449
4377
  typeData: props // doesn't need endTime anymore but oh well
4450
4378
  };
4451
4379
  }
@@ -4490,21 +4418,21 @@ Docs & License: https://fullcalendar.io/
4490
4418
 
4491
4419
  var DefaultOptionChangeHandlers = createPlugin({
4492
4420
  optionChangeHandlers: {
4493
- events: function (events, calendar) {
4494
- handleEventSources([events], calendar);
4421
+ events: function (events, calendar, deepEqual) {
4422
+ handleEventSources([events], calendar, deepEqual);
4495
4423
  },
4496
4424
  eventSources: handleEventSources,
4497
4425
  plugins: handlePlugins
4498
4426
  }
4499
4427
  });
4500
- function handleEventSources(inputs, calendar) {
4428
+ function handleEventSources(inputs, calendar, deepEqual) {
4501
4429
  var unfoundSources = hashValuesToArray(calendar.state.eventSources);
4502
4430
  var newInputs = [];
4503
4431
  for (var _i = 0, inputs_1 = inputs; _i < inputs_1.length; _i++) {
4504
4432
  var input = inputs_1[_i];
4505
4433
  var inputFound = false;
4506
4434
  for (var i = 0; i < unfoundSources.length; i++) {
4507
- if (isValuesSimilar(unfoundSources[i]._raw, input, 2)) {
4435
+ if (deepEqual(unfoundSources[i]._raw, input)) {
4508
4436
  unfoundSources.splice(i, 1); // delete
4509
4437
  inputFound = true;
4510
4438
  break;
@@ -4732,16 +4660,16 @@ Docs & License: https://fullcalendar.io/
4732
4660
  this.dynamicOverrides = {};
4733
4661
  this.compute();
4734
4662
  }
4735
- OptionsManager.prototype.add = function (props) {
4736
- __assign(this.overrides, props);
4737
- this.compute();
4738
- };
4739
- OptionsManager.prototype.addDynamic = function (props) {
4740
- __assign(this.dynamicOverrides, props);
4741
- this.compute();
4742
- };
4743
- OptionsManager.prototype.reset = function (props) {
4744
- this.overrides = props;
4663
+ OptionsManager.prototype.mutate = function (updates, removals, isDynamic) {
4664
+ if (!Object.keys(updates).length && !removals.length) {
4665
+ return;
4666
+ }
4667
+ var overrideHash = isDynamic ? this.dynamicOverrides : this.overrides;
4668
+ __assign(overrideHash, updates);
4669
+ for (var _i = 0, removals_1 = removals; _i < removals_1.length; _i++) {
4670
+ var propName = removals_1[_i];
4671
+ delete overrideHash[propName];
4672
+ }
4745
4673
  this.compute();
4746
4674
  };
4747
4675
  // Computes the flattened options hash for the calendar and assigns to `this.options`.
@@ -4836,7 +4764,7 @@ Docs & License: https://fullcalendar.io/
4836
4764
  this.weekDow = 1;
4837
4765
  this.weekDoy = 4;
4838
4766
  }
4839
- else if (typeof settings.firstDay === 'number') {
4767
+ if (typeof settings.firstDay === 'number') {
4840
4768
  this.weekDow = settings.firstDay;
4841
4769
  }
4842
4770
  if (typeof settings.weekNumberCalculation === 'function') {
@@ -5164,7 +5092,7 @@ Docs & License: https://fullcalendar.io/
5164
5092
  var meta = def.parseMeta(raw);
5165
5093
  if (meta) {
5166
5094
  var res = parseEventSourceProps(typeof raw === 'object' ? raw : {}, meta, i, calendar);
5167
- res._raw = freezeRaw(raw);
5095
+ res._raw = raw;
5168
5096
  return res;
5169
5097
  }
5170
5098
  }
@@ -5246,6 +5174,7 @@ Docs & License: https://fullcalendar.io/
5246
5174
  else {
5247
5175
  return !calendar.opt('lazyFetching') ||
5248
5176
  !eventSource.fetchRange ||
5177
+ eventSource.isFetching || // always cancel outdated in-progress fetches
5249
5178
  fetchRange.start < eventSource.fetchRange.start ||
5250
5179
  fetchRange.end > eventSource.fetchRange.end;
5251
5180
  }
@@ -5313,7 +5242,8 @@ Docs & License: https://fullcalendar.io/
5313
5242
  var eventSource = sourceHash[sourceId];
5314
5243
  if (eventSource && // not already removed
5315
5244
  fetchId === eventSource.latestFetchId) {
5316
- return __assign({}, sourceHash, (_a = {}, _a[sourceId] = __assign({}, eventSource, { isFetching: false, fetchRange: fetchRange }), _a));
5245
+ return __assign({}, sourceHash, (_a = {}, _a[sourceId] = __assign({}, eventSource, { isFetching: false, fetchRange: fetchRange // also serves as a marker that at least one fetch has completed
5246
+ }), _a));
5317
5247
  }
5318
5248
  return sourceHash;
5319
5249
  }
@@ -5650,10 +5580,19 @@ Docs & License: https://fullcalendar.io/
5650
5580
  }());
5651
5581
  // TODO: find a way to avoid comparing DateProfiles. it's tedious
5652
5582
  function isDateProfilesEqual(p0, p1) {
5653
- return rangesEqual(p0.activeRange, p1.activeRange) &&
5654
- rangesEqual(p0.validRange, p1.validRange) &&
5583
+ return rangesEqual(p0.validRange, p1.validRange) &&
5584
+ rangesEqual(p0.activeRange, p1.activeRange) &&
5585
+ rangesEqual(p0.renderRange, p1.renderRange) &&
5655
5586
  durationsEqual(p0.minTime, p1.minTime) &&
5656
5587
  durationsEqual(p0.maxTime, p1.maxTime);
5588
+ /*
5589
+ TODO: compare more?
5590
+ currentRange: DateRange
5591
+ currentRangeUnit: string
5592
+ isRangeAllDay: boolean
5593
+ isValid: boolean
5594
+ dateIncrement: Duration
5595
+ */
5657
5596
  }
5658
5597
 
5659
5598
  function reduce (state, action, calendar) {
@@ -5929,7 +5868,13 @@ Docs & License: https://fullcalendar.io/
5929
5868
  findViewNameBySubclass(theClass, overrideConfigs) ||
5930
5869
  findViewNameBySubclass(theClass, defaultConfigs);
5931
5870
  }
5932
- var superDef = superType ? ensureViewDef(superType, hash, defaultConfigs, overrideConfigs) : null;
5871
+ var superDef = null;
5872
+ if (superType) {
5873
+ if (superType === viewType) {
5874
+ throw new Error('Can\'t have a custom view type that references itself');
5875
+ }
5876
+ superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs);
5877
+ }
5933
5878
  if (!theClass && superDef) {
5934
5879
  theClass = superDef.class;
5935
5880
  }
@@ -6036,8 +5981,8 @@ Docs & License: https://fullcalendar.io/
6036
5981
 
6037
5982
  var Toolbar = /** @class */ (function (_super) {
6038
5983
  __extends(Toolbar, _super);
6039
- function Toolbar(context, extraClassName) {
6040
- var _this = _super.call(this, context) || this;
5984
+ function Toolbar(extraClassName) {
5985
+ var _this = _super.call(this) || this;
6041
5986
  _this._renderLayout = memoizeRendering(_this.renderLayout, _this.unrenderLayout);
6042
5987
  _this._updateTitle = memoizeRendering(_this.updateTitle, null, [_this._renderLayout]);
6043
5988
  _this._updateActiveButton = memoizeRendering(_this.updateActiveButton, null, [_this._renderLayout]);
@@ -6072,7 +6017,7 @@ Docs & License: https://fullcalendar.io/
6072
6017
  };
6073
6018
  Toolbar.prototype.renderSection = function (position, buttonStr) {
6074
6019
  var _this = this;
6075
- var _a = this, theme = _a.theme, calendar = _a.calendar;
6020
+ var _a = this.context, theme = _a.theme, calendar = _a.calendar;
6076
6021
  var optionsManager = calendar.optionsManager;
6077
6022
  var viewSpecs = calendar.viewSpecs;
6078
6023
  var sectionEl = createElement('div', { className: 'fc-' + position });
@@ -6180,7 +6125,8 @@ Docs & License: https://fullcalendar.io/
6180
6125
  });
6181
6126
  };
6182
6127
  Toolbar.prototype.updateActiveButton = function (buttonName) {
6183
- var className = this.theme.getClass('buttonActive');
6128
+ var theme = this.context.theme;
6129
+ var className = theme.getClass('buttonActive');
6184
6130
  findElements(this.el, 'button').forEach(function (buttonEl) {
6185
6131
  if (buttonName && buttonEl.classList.contains('fc-' + buttonName + '-button')) {
6186
6132
  buttonEl.classList.add(className);
@@ -6200,24 +6146,29 @@ Docs & License: https://fullcalendar.io/
6200
6146
 
6201
6147
  var CalendarComponent = /** @class */ (function (_super) {
6202
6148
  __extends(CalendarComponent, _super);
6203
- function CalendarComponent(context, el) {
6204
- var _this = _super.call(this, context) || this;
6205
- _this._renderToolbars = memoizeRendering(_this.renderToolbars);
6149
+ function CalendarComponent(el) {
6150
+ var _this = _super.call(this) || this;
6151
+ _this.elClassNames = [];
6152
+ _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton);
6153
+ _this.renderToolbars = memoizeRendering(_this._renderToolbars, _this._unrenderToolbars, [_this.renderSkeleton]);
6154
+ _this.buildComponentContext = memoize(buildComponentContext);
6206
6155
  _this.buildViewPropTransformers = memoize(buildViewPropTransformers);
6207
6156
  _this.el = el;
6208
- prependToElement(el, _this.contentEl = createElement('div', { className: 'fc-view-container' }));
6209
- var calendar = _this.calendar;
6210
- for (var _i = 0, _a = calendar.pluginSystem.hooks.viewContainerModifiers; _i < _a.length; _i++) {
6211
- var modifyViewContainer = _a[_i];
6212
- modifyViewContainer(_this.contentEl, calendar);
6213
- }
6214
- _this.toggleElClassNames(true);
6215
6157
  _this.computeTitle = memoize(computeTitle);
6216
6158
  _this.parseBusinessHours = memoize(function (input) {
6217
- return parseBusinessHours(input, _this.calendar);
6159
+ return parseBusinessHours(input, _this.context.calendar);
6218
6160
  });
6219
6161
  return _this;
6220
6162
  }
6163
+ CalendarComponent.prototype.render = function (props, context) {
6164
+ this.freezeHeight();
6165
+ var title = this.computeTitle(props.dateProfile, props.viewSpec.options);
6166
+ this.renderSkeleton(context);
6167
+ this.renderToolbars(props.viewSpec, props.dateProfile, props.currentDate, title);
6168
+ this.renderView(props, title);
6169
+ this.updateSize();
6170
+ this.thawHeight();
6171
+ };
6221
6172
  CalendarComponent.prototype.destroy = function () {
6222
6173
  if (this.header) {
6223
6174
  this.header.destroy();
@@ -6225,40 +6176,57 @@ Docs & License: https://fullcalendar.io/
6225
6176
  if (this.footer) {
6226
6177
  this.footer.destroy();
6227
6178
  }
6179
+ this.renderSkeleton.unrender(); // will call destroyView
6180
+ _super.prototype.destroy.call(this);
6181
+ };
6182
+ CalendarComponent.prototype._renderSkeleton = function (context) {
6183
+ this.updateElClassNames(context);
6184
+ prependToElement(this.el, this.contentEl = createElement('div', { className: 'fc-view-container' }));
6185
+ var calendar = context.calendar;
6186
+ for (var _i = 0, _a = calendar.pluginSystem.hooks.viewContainerModifiers; _i < _a.length; _i++) {
6187
+ var modifyViewContainer = _a[_i];
6188
+ modifyViewContainer(this.contentEl, calendar);
6189
+ }
6190
+ };
6191
+ CalendarComponent.prototype._unrenderSkeleton = function () {
6192
+ // weird to have this here
6228
6193
  if (this.view) {
6194
+ this.savedScroll = this.view.queryScroll();
6229
6195
  this.view.destroy();
6196
+ this.view = null;
6230
6197
  }
6231
6198
  removeElement(this.contentEl);
6232
- this.toggleElClassNames(false);
6233
- _super.prototype.destroy.call(this);
6199
+ this.removeElClassNames();
6234
6200
  };
6235
- CalendarComponent.prototype.toggleElClassNames = function (bool) {
6201
+ CalendarComponent.prototype.removeElClassNames = function () {
6236
6202
  var classList = this.el.classList;
6237
- var dirClassName = 'fc-' + this.opt('dir');
6238
- var themeClassName = this.theme.getClass('widget');
6239
- if (bool) {
6240
- classList.add('fc');
6241
- classList.add(dirClassName);
6242
- classList.add(themeClassName);
6243
- }
6244
- else {
6245
- classList.remove('fc');
6246
- classList.remove(dirClassName);
6247
- classList.remove(themeClassName);
6248
- }
6249
- };
6250
- CalendarComponent.prototype.render = function (props) {
6251
- this.freezeHeight();
6252
- var title = this.computeTitle(props.dateProfile, props.viewSpec.options);
6253
- this._renderToolbars(props.viewSpec, props.dateProfile, props.currentDate, props.dateProfileGenerator, title);
6254
- this.renderView(props, title);
6255
- this.updateSize();
6256
- this.thawHeight();
6257
- };
6258
- CalendarComponent.prototype.renderToolbars = function (viewSpec, dateProfile, currentDate, dateProfileGenerator, title) {
6259
- var headerLayout = this.opt('header');
6260
- var footerLayout = this.opt('footer');
6261
- var now = this.calendar.getNow();
6203
+ for (var _i = 0, _a = this.elClassNames; _i < _a.length; _i++) {
6204
+ var className = _a[_i];
6205
+ classList.remove(className);
6206
+ }
6207
+ this.elClassNames = [];
6208
+ };
6209
+ CalendarComponent.prototype.updateElClassNames = function (context) {
6210
+ this.removeElClassNames();
6211
+ var theme = context.theme, options = context.options;
6212
+ this.elClassNames = [
6213
+ 'fc',
6214
+ 'fc-' + options.dir,
6215
+ theme.getClass('widget')
6216
+ ];
6217
+ var classList = this.el.classList;
6218
+ for (var _i = 0, _a = this.elClassNames; _i < _a.length; _i++) {
6219
+ var className = _a[_i];
6220
+ classList.add(className);
6221
+ }
6222
+ };
6223
+ CalendarComponent.prototype._renderToolbars = function (viewSpec, dateProfile, currentDate, title) {
6224
+ var _a = this, context = _a.context, header = _a.header, footer = _a.footer;
6225
+ var options = context.options, calendar = context.calendar;
6226
+ var headerLayout = options.header;
6227
+ var footerLayout = options.footer;
6228
+ var dateProfileGenerator = this.props.dateProfileGenerator;
6229
+ var now = calendar.getNow();
6262
6230
  var todayInfo = dateProfileGenerator.build(now);
6263
6231
  var prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate);
6264
6232
  var nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate);
@@ -6270,48 +6238,55 @@ Docs & License: https://fullcalendar.io/
6270
6238
  isNextEnabled: nextInfo.isValid
6271
6239
  };
6272
6240
  if (headerLayout) {
6273
- if (!this.header) {
6274
- this.header = new Toolbar(this.context, 'fc-header-toolbar');
6275
- prependToElement(this.el, this.header.el);
6241
+ if (!header) {
6242
+ header = this.header = new Toolbar('fc-header-toolbar');
6243
+ prependToElement(this.el, header.el);
6276
6244
  }
6277
- this.header.receiveProps(__assign({ layout: headerLayout }, toolbarProps));
6245
+ header.receiveProps(__assign({ layout: headerLayout }, toolbarProps), context);
6278
6246
  }
6279
- else if (this.header) {
6280
- this.header.destroy();
6281
- this.header = null;
6247
+ else if (header) {
6248
+ header.destroy();
6249
+ header = this.header = null;
6282
6250
  }
6283
6251
  if (footerLayout) {
6284
- if (!this.footer) {
6285
- this.footer = new Toolbar(this.context, 'fc-footer-toolbar');
6286
- appendToElement(this.el, this.footer.el);
6252
+ if (!footer) {
6253
+ footer = this.footer = new Toolbar('fc-footer-toolbar');
6254
+ appendToElement(this.el, footer.el);
6287
6255
  }
6288
- this.footer.receiveProps(__assign({ layout: footerLayout }, toolbarProps));
6256
+ footer.receiveProps(__assign({ layout: footerLayout }, toolbarProps), context);
6257
+ }
6258
+ else if (footer) {
6259
+ footer.destroy();
6260
+ footer = this.footer = null;
6261
+ }
6262
+ };
6263
+ CalendarComponent.prototype._unrenderToolbars = function () {
6264
+ if (this.header) {
6265
+ this.header.destroy();
6266
+ this.header = null;
6289
6267
  }
6290
- else if (this.footer) {
6268
+ if (this.footer) {
6291
6269
  this.footer.destroy();
6292
6270
  this.footer = null;
6293
6271
  }
6294
6272
  };
6295
6273
  CalendarComponent.prototype.renderView = function (props, title) {
6296
6274
  var view = this.view;
6275
+ var _a = this.context, calendar = _a.calendar, options = _a.options;
6297
6276
  var viewSpec = props.viewSpec, dateProfileGenerator = props.dateProfileGenerator;
6298
6277
  if (!view || view.viewSpec !== viewSpec) {
6299
6278
  if (view) {
6300
6279
  view.destroy();
6301
6280
  }
6302
- view = this.view = new viewSpec['class']({
6303
- calendar: this.calendar,
6304
- view: null,
6305
- dateEnv: this.dateEnv,
6306
- theme: this.theme,
6307
- options: viewSpec.options
6308
- }, viewSpec, dateProfileGenerator, this.contentEl);
6309
- }
6310
- else {
6311
- view.addScroll(view.queryScroll());
6281
+ view = this.view = new viewSpec['class'](viewSpec, this.contentEl);
6282
+ if (this.savedScroll) {
6283
+ view.addScroll(this.savedScroll, true);
6284
+ this.savedScroll = null;
6285
+ }
6312
6286
  }
6313
6287
  view.title = title; // for the API
6314
6288
  var viewProps = {
6289
+ dateProfileGenerator: dateProfileGenerator,
6315
6290
  dateProfile: props.dateProfile,
6316
6291
  businessHours: this.parseBusinessHours(viewSpec.options.businessHours),
6317
6292
  eventStore: props.eventStore,
@@ -6321,20 +6296,20 @@ Docs & License: https://fullcalendar.io/
6321
6296
  eventDrag: props.eventDrag,
6322
6297
  eventResize: props.eventResize
6323
6298
  };
6324
- var transformers = this.buildViewPropTransformers(this.calendar.pluginSystem.hooks.viewPropsTransformers);
6299
+ var transformers = this.buildViewPropTransformers(calendar.pluginSystem.hooks.viewPropsTransformers);
6325
6300
  for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) {
6326
6301
  var transformer = transformers_1[_i];
6327
- __assign(viewProps, transformer.transform(viewProps, viewSpec, props, view));
6302
+ __assign(viewProps, transformer.transform(viewProps, viewSpec, props, options));
6328
6303
  }
6329
- view.receiveProps(viewProps);
6304
+ view.receiveProps(viewProps, this.buildComponentContext(this.context, viewSpec, view));
6330
6305
  };
6331
6306
  // Sizing
6332
6307
  // -----------------------------------------------------------------------------------------------------------------
6333
6308
  CalendarComponent.prototype.updateSize = function (isResize) {
6334
6309
  if (isResize === void 0) { isResize = false; }
6335
6310
  var view = this.view;
6336
- if (isResize) {
6337
- view.addScroll(view.queryScroll());
6311
+ if (!view) {
6312
+ return; // why?
6338
6313
  }
6339
6314
  if (isResize || this.isHeightAuto == null) {
6340
6315
  this.computeHeightVars();
@@ -6344,7 +6319,7 @@ Docs & License: https://fullcalendar.io/
6344
6319
  view.popScroll(isResize);
6345
6320
  };
6346
6321
  CalendarComponent.prototype.computeHeightVars = function () {
6347
- var calendar = this.calendar; // yuck. need to handle dynamic options
6322
+ var calendar = this.context.calendar; // yuck. need to handle dynamic options
6348
6323
  var heightInput = calendar.opt('height');
6349
6324
  var contentHeightInput = calendar.opt('contentHeight');
6350
6325
  this.isHeightAuto = heightInput === 'auto' || contentHeightInput === 'auto';
@@ -6361,10 +6336,11 @@ Docs & License: https://fullcalendar.io/
6361
6336
  this.viewHeight = heightInput() - this.queryToolbarsHeight();
6362
6337
  }
6363
6338
  else if (heightInput === 'parent') { // set to height of parent element
6364
- this.viewHeight = this.el.parentNode.offsetHeight - this.queryToolbarsHeight();
6339
+ var parentEl = this.el.parentNode;
6340
+ this.viewHeight = parentEl.getBoundingClientRect().height - this.queryToolbarsHeight();
6365
6341
  }
6366
6342
  else {
6367
- this.viewHeight = Math.round(this.contentEl.offsetWidth /
6343
+ this.viewHeight = Math.round(this.contentEl.getBoundingClientRect().width /
6368
6344
  Math.max(calendar.opt('aspectRatio'), .5));
6369
6345
  }
6370
6346
  };
@@ -6382,7 +6358,7 @@ Docs & License: https://fullcalendar.io/
6382
6358
  // -----------------------------------------------------------------------------------------------------------------
6383
6359
  CalendarComponent.prototype.freezeHeight = function () {
6384
6360
  applyStyle(this.el, {
6385
- height: this.el.offsetHeight,
6361
+ height: this.el.getBoundingClientRect().height,
6386
6362
  overflow: 'hidden'
6387
6363
  });
6388
6364
  };
@@ -6406,7 +6382,7 @@ Docs & License: https://fullcalendar.io/
6406
6382
  else { // for day units or smaller, use the actual day range
6407
6383
  range = dateProfile.activeRange;
6408
6384
  }
6409
- return this.dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || computeTitleFormat(dateProfile), viewOptions.titleRangeSeparator), { isEndExclusive: dateProfile.isRangeAllDay });
6385
+ return this.context.dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || computeTitleFormat(dateProfile), viewOptions.titleRangeSeparator), { isEndExclusive: dateProfile.isRangeAllDay });
6410
6386
  }
6411
6387
  // Generates the format string that should be used to generate the title for the current date range.
6412
6388
  // Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.
@@ -6430,6 +6406,10 @@ Docs & License: https://fullcalendar.io/
6430
6406
  }
6431
6407
  }
6432
6408
  }
6409
+ // build a context scoped to the view
6410
+ function buildComponentContext(context, viewSpec, view) {
6411
+ return context.extend(viewSpec.options, view);
6412
+ }
6433
6413
  // Plugin
6434
6414
  // -----------------------------------------------------------------------------------------------------------------
6435
6415
  function buildViewPropTransformers(theClasses) {
@@ -6471,6 +6451,7 @@ Docs & License: https://fullcalendar.io/
6471
6451
  var _this = _super.call(this, settings) || this;
6472
6452
  _this.handleSegClick = function (ev, segEl) {
6473
6453
  var component = _this.component;
6454
+ var _a = component.context, calendar = _a.calendar, view = _a.view;
6474
6455
  var seg = getElSeg(segEl);
6475
6456
  if (seg && // might be the <div> surrounding the more link
6476
6457
  component.isValidSegDownEl(ev.target)) {
@@ -6478,12 +6459,12 @@ Docs & License: https://fullcalendar.io/
6478
6459
  // grab before trigger fired in case trigger trashes DOM thru rerendering
6479
6460
  var hasUrlContainer = elementClosest(ev.target, '.fc-has-url');
6480
6461
  var url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';
6481
- component.publiclyTrigger('eventClick', [
6462
+ calendar.publiclyTrigger('eventClick', [
6482
6463
  {
6483
6464
  el: segEl,
6484
- event: new EventApi(component.calendar, seg.eventRange.def, seg.eventRange.instance),
6465
+ event: new EventApi(component.context.calendar, seg.eventRange.def, seg.eventRange.instance),
6485
6466
  jsEvent: ev,
6486
- view: component.view
6467
+ view: view
6487
6468
  }
6488
6469
  ]);
6489
6470
  if (url && !ev.defaultPrevented) {
@@ -6528,23 +6509,25 @@ Docs & License: https://fullcalendar.io/
6528
6509
  };
6529
6510
  var component = settings.component;
6530
6511
  _this.removeHoverListeners = listenToHoverBySelector(component.el, component.fgSegSelector + ',' + component.bgSegSelector, _this.handleSegEnter, _this.handleSegLeave);
6531
- component.calendar.on('eventElRemove', _this.handleEventElRemove);
6512
+ // how to make sure component already has context?
6513
+ component.context.calendar.on('eventElRemove', _this.handleEventElRemove);
6532
6514
  return _this;
6533
6515
  }
6534
6516
  EventHovering.prototype.destroy = function () {
6535
6517
  this.removeHoverListeners();
6536
- this.component.calendar.off('eventElRemove', this.handleEventElRemove);
6518
+ this.component.context.calendar.off('eventElRemove', this.handleEventElRemove);
6537
6519
  };
6538
6520
  EventHovering.prototype.triggerEvent = function (publicEvName, ev, segEl) {
6539
6521
  var component = this.component;
6522
+ var _a = component.context, calendar = _a.calendar, view = _a.view;
6540
6523
  var seg = getElSeg(segEl);
6541
6524
  if (!ev || component.isValidSegDownEl(ev.target)) {
6542
- component.publiclyTrigger(publicEvName, [
6525
+ calendar.publiclyTrigger(publicEvName, [
6543
6526
  {
6544
6527
  el: segEl,
6545
- event: new EventApi(this.component.calendar, seg.eventRange.def, seg.eventRange.instance),
6528
+ event: new EventApi(calendar, seg.eventRange.def, seg.eventRange.instance),
6546
6529
  jsEvent: ev,
6547
- view: component.view
6530
+ view: view
6548
6531
  }
6549
6532
  ]);
6550
6533
  }
@@ -6589,20 +6572,20 @@ Docs & License: https://fullcalendar.io/
6589
6572
  var Calendar = /** @class */ (function () {
6590
6573
  function Calendar(el, overrides) {
6591
6574
  var _this = this;
6575
+ this.buildComponentContext = memoize(buildComponentContext$1);
6592
6576
  this.parseRawLocales = memoize(parseRawLocales);
6593
6577
  this.buildLocale = memoize(buildLocale);
6594
6578
  this.buildDateEnv = memoize(buildDateEnv);
6595
6579
  this.buildTheme = memoize(buildTheme);
6596
6580
  this.buildEventUiSingleBase = memoize(this._buildEventUiSingleBase);
6597
6581
  this.buildSelectionConfig = memoize(this._buildSelectionConfig);
6598
- this.buildEventUiBySource = memoizeOutput(buildEventUiBySource, isObjectsSimilar);
6582
+ this.buildEventUiBySource = memoizeOutput(buildEventUiBySource, isPropsEqual);
6599
6583
  this.buildEventUiBases = memoize(buildEventUiBases);
6600
6584
  this.interactionsStore = {};
6601
6585
  this.actionQueue = [];
6602
6586
  this.isReducing = false;
6603
6587
  // isDisplaying: boolean = false // installed in DOM? accepting renders?
6604
6588
  this.needsRerender = false; // needs a render?
6605
- this.needsFullRerender = false;
6606
6589
  this.isRendering = false; // currently in the executeRender function?
6607
6590
  this.renderingPauseDepth = 0;
6608
6591
  this.buildDelayedRerender = memoize(buildDelayedRerender);
@@ -6642,12 +6625,13 @@ Docs & License: https://fullcalendar.io/
6642
6625
  // -----------------------------------------------------------------------------------------------------------------
6643
6626
  Calendar.prototype.render = function () {
6644
6627
  if (!this.component) {
6628
+ this.component = new CalendarComponent(this.el);
6645
6629
  this.renderableEventStore = createEmptyEventStore();
6646
6630
  this.bindHandlers();
6647
6631
  this.executeRender();
6648
6632
  }
6649
6633
  else {
6650
- this.requestRerender(true);
6634
+ this.requestRerender();
6651
6635
  }
6652
6636
  };
6653
6637
  Calendar.prototype.destroy = function () {
@@ -6756,12 +6740,12 @@ Docs & License: https://fullcalendar.io/
6756
6740
  this.publiclyTrigger('loading', [false]);
6757
6741
  }
6758
6742
  var view = this.component && this.component.view;
6759
- if (oldState.eventStore !== newState.eventStore || this.needsFullRerender) {
6743
+ if (oldState.eventStore !== newState.eventStore) {
6760
6744
  if (oldState.eventStore) {
6761
6745
  this.isEventsUpdated = true;
6762
6746
  }
6763
6747
  }
6764
- if (oldState.dateProfile !== newState.dateProfile || this.needsFullRerender) {
6748
+ if (oldState.dateProfile !== newState.dateProfile) {
6765
6749
  if (oldState.dateProfile && view) { // why would view be null!?
6766
6750
  this.publiclyTrigger('datesDestroy', [
6767
6751
  {
@@ -6772,7 +6756,7 @@ Docs & License: https://fullcalendar.io/
6772
6756
  }
6773
6757
  this.isDatesUpdated = true;
6774
6758
  }
6775
- if (oldState.viewType !== newState.viewType || this.needsFullRerender) {
6759
+ if (oldState.viewType !== newState.viewType) {
6776
6760
  if (oldState.viewType && view) { // why would view be null!?
6777
6761
  this.publiclyTrigger('viewSkeletonDestroy', [
6778
6762
  {
@@ -6791,10 +6775,8 @@ Docs & License: https://fullcalendar.io/
6791
6775
  };
6792
6776
  // Render Queue
6793
6777
  // -----------------------------------------------------------------------------------------------------------------
6794
- Calendar.prototype.requestRerender = function (needsFull) {
6795
- if (needsFull === void 0) { needsFull = false; }
6778
+ Calendar.prototype.requestRerender = function () {
6796
6779
  this.needsRerender = true;
6797
- this.needsFullRerender = this.needsFullRerender || needsFull;
6798
6780
  this.delayedRerender(); // will call a debounced-version of tryRerender
6799
6781
  };
6800
6782
  Calendar.prototype.tryRerender = function () {
@@ -6817,12 +6799,10 @@ Docs & License: https://fullcalendar.io/
6817
6799
  // Rendering
6818
6800
  // -----------------------------------------------------------------------------------------------------------------
6819
6801
  Calendar.prototype.executeRender = function () {
6820
- var needsFullRerender = this.needsFullRerender; // save before clearing
6821
6802
  // clear these BEFORE the render so that new values will accumulate during render
6822
6803
  this.needsRerender = false;
6823
- this.needsFullRerender = false;
6824
6804
  this.isRendering = true;
6825
- this.renderComponent(needsFullRerender);
6805
+ this.renderComponent();
6826
6806
  this.isRendering = false;
6827
6807
  // received a rerender request while rendering
6828
6808
  if (this.needsRerender) {
@@ -6832,11 +6812,10 @@ Docs & License: https://fullcalendar.io/
6832
6812
  /*
6833
6813
  don't call this directly. use executeRender instead
6834
6814
  */
6835
- Calendar.prototype.renderComponent = function (needsFull) {
6815
+ Calendar.prototype.renderComponent = function () {
6836
6816
  var _a = this, state = _a.state, component = _a.component;
6837
6817
  var viewType = state.viewType;
6838
6818
  var viewSpec = this.viewSpecs[viewType];
6839
- var savedScroll = (needsFull && component) ? component.view.queryScroll() : null;
6840
6819
  if (!viewSpec) {
6841
6820
  throw new Error("View type \"" + viewType + "\" is not valid");
6842
6821
  }
@@ -6849,23 +6828,7 @@ Docs & License: https://fullcalendar.io/
6849
6828
  var eventUiSingleBase = this.buildEventUiSingleBase(viewSpec.options);
6850
6829
  var eventUiBySource = this.buildEventUiBySource(state.eventSources);
6851
6830
  var eventUiBases = this.eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource);
6852
- if (needsFull || !component) {
6853
- if (component) {
6854
- component.freezeHeight(); // next component will unfreeze it
6855
- component.destroy();
6856
- }
6857
- component = this.component = new CalendarComponent({
6858
- calendar: this,
6859
- view: null,
6860
- dateEnv: this.dateEnv,
6861
- theme: this.theme,
6862
- options: this.optionsManager.computed
6863
- }, this.el);
6864
- }
6865
- component.receiveProps(__assign({}, state, { viewSpec: viewSpec, dateProfile: state.dateProfile, dateProfileGenerator: this.dateProfileGenerators[viewType], eventStore: renderableEventStore, eventUiBases: eventUiBases, dateSelection: state.dateSelection, eventSelection: state.eventSelection, eventDrag: state.eventDrag, eventResize: state.eventResize }));
6866
- if (savedScroll) {
6867
- component.view.applyScroll(savedScroll, false);
6868
- }
6831
+ component.receiveProps(__assign({}, state, { viewSpec: viewSpec, dateProfileGenerator: this.dateProfileGenerators[viewType], dateProfile: state.dateProfile, eventStore: renderableEventStore, eventUiBases: eventUiBases, dateSelection: state.dateSelection, eventSelection: state.eventSelection, eventDrag: state.eventDrag, eventResize: state.eventResize }), this.buildComponentContext(this.theme, this.dateEnv, this.optionsManager.computed));
6869
6832
  if (this.isViewUpdated) {
6870
6833
  this.isViewUpdated = false;
6871
6834
  this.publiclyTrigger('viewSkeletonRender', [
@@ -6891,98 +6854,60 @@ Docs & License: https://fullcalendar.io/
6891
6854
  };
6892
6855
  // Options
6893
6856
  // -----------------------------------------------------------------------------------------------------------------
6894
- /*
6895
- Not meant for public API
6896
- */
6897
- Calendar.prototype.resetOptions = function (options) {
6898
- var _this = this;
6899
- var changeHandlers = this.pluginSystem.hooks.optionChangeHandlers;
6900
- var oldOptions = this.optionsManager.overrides;
6901
- var oldNormalOptions = {};
6902
- var normalOptions = {};
6903
- var specialOptions = {};
6904
- for (var name_1 in oldOptions) {
6905
- if (!changeHandlers[name_1]) {
6906
- oldNormalOptions[name_1] = oldOptions[name_1];
6907
- }
6908
- }
6909
- for (var name_2 in options) {
6910
- if (changeHandlers[name_2]) {
6911
- specialOptions[name_2] = options[name_2];
6912
- }
6913
- else {
6914
- normalOptions[name_2] = options[name_2];
6915
- }
6916
- }
6917
- this.batchRendering(function () {
6918
- if (anyKeysRemoved(oldNormalOptions, normalOptions)) {
6919
- _this.processOptions(options, 'reset');
6920
- }
6921
- else {
6922
- _this.processOptions(computeChangedProps(oldNormalOptions, normalOptions));
6923
- }
6924
- // handle special options last
6925
- for (var name_3 in specialOptions) {
6926
- changeHandlers[name_3](specialOptions[name_3], _this);
6927
- }
6928
- });
6857
+ Calendar.prototype.setOption = function (name, val) {
6858
+ var _a;
6859
+ this.mutateOptions((_a = {}, _a[name] = val, _a), [], true);
6860
+ };
6861
+ Calendar.prototype.getOption = function (name) {
6862
+ return this.optionsManager.computed[name];
6863
+ };
6864
+ Calendar.prototype.opt = function (name) {
6865
+ return this.optionsManager.computed[name];
6866
+ };
6867
+ Calendar.prototype.viewOpt = function (name) {
6868
+ return this.viewOpts()[name];
6869
+ };
6870
+ Calendar.prototype.viewOpts = function () {
6871
+ return this.viewSpecs[this.state.viewType].options;
6929
6872
  };
6930
6873
  /*
6931
- Not meant for public API. Won't give the same precedence that setOption does
6874
+ handles option changes (like a diff)
6932
6875
  */
6933
- Calendar.prototype.setOptions = function (options) {
6876
+ Calendar.prototype.mutateOptions = function (updates, removals, isDynamic, deepEqual) {
6934
6877
  var _this = this;
6935
6878
  var changeHandlers = this.pluginSystem.hooks.optionChangeHandlers;
6936
- var normalOptions = {};
6937
- var specialOptions = {};
6938
- for (var name_4 in options) {
6939
- if (changeHandlers[name_4]) {
6940
- specialOptions[name_4] = options[name_4];
6879
+ var normalUpdates = {};
6880
+ var specialUpdates = {};
6881
+ var oldDateEnv = this.dateEnv; // do this before handleOptions
6882
+ var isTimeZoneDirty = false;
6883
+ var isSizeDirty = false;
6884
+ var anyDifficultOptions = Boolean(removals.length);
6885
+ for (var name_1 in updates) {
6886
+ if (changeHandlers[name_1]) {
6887
+ specialUpdates[name_1] = updates[name_1];
6941
6888
  }
6942
6889
  else {
6943
- normalOptions[name_4] = options[name_4];
6890
+ normalUpdates[name_1] = updates[name_1];
6944
6891
  }
6945
6892
  }
6946
- this.batchRendering(function () {
6947
- _this.processOptions(normalOptions);
6948
- // handle special options last
6949
- for (var name_5 in specialOptions) {
6950
- changeHandlers[name_5](specialOptions[name_5], _this);
6951
- }
6952
- });
6953
- };
6954
- Calendar.prototype.processOptions = function (options, mode) {
6955
- var _this = this;
6956
- var oldDateEnv = this.dateEnv; // do this before handleOptions
6957
- var isTimeZoneDirty = false;
6958
- var isSizeDirty = false;
6959
- var anyDifficultOptions = false;
6960
- for (var name_6 in options) {
6961
- if (/^(height|contentHeight|aspectRatio)$/.test(name_6)) {
6893
+ for (var name_2 in normalUpdates) {
6894
+ if (/^(height|contentHeight|aspectRatio)$/.test(name_2)) {
6962
6895
  isSizeDirty = true;
6963
6896
  }
6964
- else if (/^(defaultDate|defaultView)$/.test(name_6)) ;
6897
+ else if (/^(defaultDate|defaultView)$/.test(name_2)) ;
6965
6898
  else {
6966
6899
  anyDifficultOptions = true;
6967
- if (name_6 === 'timeZone') {
6900
+ if (name_2 === 'timeZone') {
6968
6901
  isTimeZoneDirty = true;
6969
6902
  }
6970
6903
  }
6971
6904
  }
6972
- if (mode === 'reset') {
6973
- anyDifficultOptions = true;
6974
- this.optionsManager.reset(options);
6975
- }
6976
- else if (mode === 'dynamic') {
6977
- this.optionsManager.addDynamic(options); // takes higher precedence
6978
- }
6979
- else {
6980
- this.optionsManager.add(options);
6981
- }
6905
+ this.optionsManager.mutate(normalUpdates, removals, isDynamic);
6982
6906
  if (anyDifficultOptions) {
6983
- this.handleOptions(this.optionsManager.computed); // only for "difficult" options
6984
- this.needsFullRerender = true;
6985
- this.batchRendering(function () {
6907
+ this.handleOptions(this.optionsManager.computed);
6908
+ }
6909
+ this.batchRendering(function () {
6910
+ if (anyDifficultOptions) {
6986
6911
  if (isTimeZoneDirty) {
6987
6912
  _this.dispatch({
6988
6913
  type: 'CHANGE_TIMEZONE',
@@ -6990,34 +6915,24 @@ Docs & License: https://fullcalendar.io/
6990
6915
  });
6991
6916
  }
6992
6917
  /* HACK
6993
- has the same effect as calling this.requestRerender(true)
6918
+ has the same effect as calling this.requestRerender()
6994
6919
  but recomputes the state's dateProfile
6995
6920
  */
6996
6921
  _this.dispatch({
6997
6922
  type: 'SET_VIEW_TYPE',
6998
6923
  viewType: _this.state.viewType
6999
6924
  });
7000
- });
7001
- }
7002
- if (isSizeDirty) {
7003
- this.updateSize();
7004
- }
7005
- };
7006
- Calendar.prototype.setOption = function (name, val) {
7007
- var _a;
7008
- this.processOptions((_a = {}, _a[name] = val, _a), 'dynamic');
7009
- };
7010
- Calendar.prototype.getOption = function (name) {
7011
- return this.optionsManager.computed[name];
7012
- };
7013
- Calendar.prototype.opt = function (name) {
7014
- return this.optionsManager.computed[name];
7015
- };
7016
- Calendar.prototype.viewOpt = function (name) {
7017
- return this.viewOpts()[name];
7018
- };
7019
- Calendar.prototype.viewOpts = function () {
7020
- return this.viewSpecs[this.state.viewType].options;
6925
+ }
6926
+ else if (isSizeDirty) {
6927
+ _this.updateSize();
6928
+ }
6929
+ // special updates
6930
+ if (deepEqual) {
6931
+ for (var name_3 in specialUpdates) {
6932
+ changeHandlers[name_3](specialUpdates[name_3], _this, deepEqual);
6933
+ }
6934
+ }
6935
+ });
7021
6936
  };
7022
6937
  /*
7023
6938
  rebuilds things based off of a complete set of refined options
@@ -7072,10 +6987,10 @@ Docs & License: https://fullcalendar.io/
7072
6987
  };
7073
6988
  Calendar.prototype.releaseAfterSizingTriggers = function () {
7074
6989
  var afterSizingTriggers = this.afterSizingTriggers;
7075
- for (var name_7 in afterSizingTriggers) {
7076
- for (var _i = 0, _a = afterSizingTriggers[name_7]; _i < _a.length; _i++) {
6990
+ for (var name_4 in afterSizingTriggers) {
6991
+ for (var _i = 0, _a = afterSizingTriggers[name_4]; _i < _a.length; _i++) {
7077
6992
  var args = _a[_i];
7078
- this.publiclyTrigger(name_7, args);
6993
+ this.publiclyTrigger(name_4, args);
7079
6994
  }
7080
6995
  }
7081
6996
  this.afterSizingTriggers = {};
@@ -7090,7 +7005,7 @@ Docs & License: https://fullcalendar.io/
7090
7005
  var dateMarker = null;
7091
7006
  if (dateOrRange) {
7092
7007
  if (dateOrRange.start && dateOrRange.end) { // a range
7093
- this.optionsManager.addDynamic({ visibleRange: dateOrRange }); // will not rerender
7008
+ this.optionsManager.mutate({ visibleRange: dateOrRange }, []); // will not rerender
7094
7009
  this.handleOptions(this.optionsManager.computed); // ...but yuck
7095
7010
  }
7096
7011
  else { // a date
@@ -7309,9 +7224,7 @@ Docs & License: https://fullcalendar.io/
7309
7224
  }
7310
7225
  };
7311
7226
  Calendar.prototype.triggerDateSelect = function (selection, pev) {
7312
- var arg = this.buildDateSpanApi(selection);
7313
- arg.jsEvent = pev ? pev.origEvent : null;
7314
- arg.view = this.view;
7227
+ var arg = __assign({}, this.buildDateSpanApi(selection), { jsEvent: pev ? pev.origEvent : null, view: this.view });
7315
7228
  this.publiclyTrigger('select', [arg]);
7316
7229
  };
7317
7230
  Calendar.prototype.triggerDateUnselect = function (pev) {
@@ -7324,10 +7237,8 @@ Docs & License: https://fullcalendar.io/
7324
7237
  };
7325
7238
  // TODO: receive pev?
7326
7239
  Calendar.prototype.triggerDateClick = function (dateSpan, dayEl, view, ev) {
7327
- var arg = this.buildDatePointApi(dateSpan);
7328
- arg.dayEl = dayEl;
7329
- arg.jsEvent = ev;
7330
- arg.view = view;
7240
+ var arg = __assign({}, this.buildDatePointApi(dateSpan), { dayEl: dayEl, jsEvent: ev, // Is this always a mouse event? See #4655
7241
+ view: view });
7331
7242
  this.publiclyTrigger('dateClick', [arg]);
7332
7243
  };
7333
7244
  Calendar.prototype.buildDatePointApi = function (dateSpan) {
@@ -7500,9 +7411,9 @@ Docs & License: https://fullcalendar.io/
7500
7411
  // Scroll
7501
7412
  // -----------------------------------------------------------------------------------------------------------------
7502
7413
  Calendar.prototype.scrollToTime = function (timeInput) {
7503
- var time = createDuration(timeInput);
7504
- if (time) {
7505
- this.component.view.scrollToTime(time);
7414
+ var duration = createDuration(timeInput);
7415
+ if (duration) {
7416
+ this.component.view.scrollToDuration(duration);
7506
7417
  }
7507
7418
  };
7508
7419
  return Calendar;
@@ -7510,6 +7421,9 @@ Docs & License: https://fullcalendar.io/
7510
7421
  EmitterMixin.mixInto(Calendar);
7511
7422
  // for memoizers
7512
7423
  // -----------------------------------------------------------------------------------------------------------------
7424
+ function buildComponentContext$1(theme, dateEnv, options) {
7425
+ return new ComponentContext(this, theme, dateEnv, options, null);
7426
+ }
7513
7427
  function buildDateEnv(locale, timeZone, namedTimeZoneImpl, firstDay, weekNumberCalculation, weekLabel, cmdFormatter) {
7514
7428
  return new DateEnv({
7515
7429
  calendarSystem: 'gregory',
@@ -7551,9 +7465,8 @@ Docs & License: https://fullcalendar.io/
7551
7465
 
7552
7466
  var View = /** @class */ (function (_super) {
7553
7467
  __extends(View, _super);
7554
- function View(context, viewSpec, dateProfileGenerator, parentEl) {
7555
- var _this = _super.call(this, context, createElement('div', { className: 'fc-view fc-' + viewSpec.type + '-view' }), true // isView (HACK)
7556
- ) || this;
7468
+ function View(viewSpec, parentEl) {
7469
+ var _this = _super.call(this, createElement('div', { className: 'fc-view fc-' + viewSpec.type + '-view' })) || this;
7557
7470
  _this.renderDatesMem = memoizeRendering(_this.renderDatesWrap, _this.unrenderDatesWrap);
7558
7471
  _this.renderBusinessHoursMem = memoizeRendering(_this.renderBusinessHours, _this.unrenderBusinessHours, [_this.renderDatesMem]);
7559
7472
  _this.renderDateSelectionMem = memoizeRendering(_this.renderDateSelectionWrap, _this.unrenderDateSelectionWrap, [_this.renderDatesMem]);
@@ -7562,10 +7475,7 @@ Docs & License: https://fullcalendar.io/
7562
7475
  _this.renderEventDragMem = memoizeRendering(_this.renderEventDragWrap, _this.unrenderEventDragWrap, [_this.renderDatesMem]);
7563
7476
  _this.renderEventResizeMem = memoizeRendering(_this.renderEventResizeWrap, _this.unrenderEventResizeWrap, [_this.renderDatesMem]);
7564
7477
  _this.viewSpec = viewSpec;
7565
- _this.dateProfileGenerator = dateProfileGenerator;
7566
7478
  _this.type = viewSpec.type;
7567
- _this.eventOrderSpecs = parseFieldSpecs(_this.opt('eventOrder'));
7568
- _this.nextDayThreshold = createDuration(_this.opt('nextDayThreshold'));
7569
7479
  parentEl.appendChild(_this.el);
7570
7480
  _this.initialize();
7571
7481
  return _this;
@@ -7576,35 +7486,35 @@ Docs & License: https://fullcalendar.io/
7576
7486
  // Date Setting/Unsetting
7577
7487
  // -----------------------------------------------------------------------------------------------------------------
7578
7488
  get: function () {
7579
- return this.dateEnv.toDate(this.props.dateProfile.activeRange.start);
7489
+ return this.context.dateEnv.toDate(this.props.dateProfile.activeRange.start);
7580
7490
  },
7581
7491
  enumerable: true,
7582
7492
  configurable: true
7583
7493
  });
7584
7494
  Object.defineProperty(View.prototype, "activeEnd", {
7585
7495
  get: function () {
7586
- return this.dateEnv.toDate(this.props.dateProfile.activeRange.end);
7496
+ return this.context.dateEnv.toDate(this.props.dateProfile.activeRange.end);
7587
7497
  },
7588
7498
  enumerable: true,
7589
7499
  configurable: true
7590
7500
  });
7591
7501
  Object.defineProperty(View.prototype, "currentStart", {
7592
7502
  get: function () {
7593
- return this.dateEnv.toDate(this.props.dateProfile.currentRange.start);
7503
+ return this.context.dateEnv.toDate(this.props.dateProfile.currentRange.start);
7594
7504
  },
7595
7505
  enumerable: true,
7596
7506
  configurable: true
7597
7507
  });
7598
7508
  Object.defineProperty(View.prototype, "currentEnd", {
7599
7509
  get: function () {
7600
- return this.dateEnv.toDate(this.props.dateProfile.currentRange.end);
7510
+ return this.context.dateEnv.toDate(this.props.dateProfile.currentRange.end);
7601
7511
  },
7602
7512
  enumerable: true,
7603
7513
  configurable: true
7604
7514
  });
7605
7515
  // General Rendering
7606
7516
  // -----------------------------------------------------------------------------------------------------------------
7607
- View.prototype.render = function (props) {
7517
+ View.prototype.render = function (props, context) {
7608
7518
  this.renderDatesMem(props.dateProfile);
7609
7519
  this.renderBusinessHoursMem(props.businessHours);
7610
7520
  this.renderDateSelectionMem(props.dateSelection);
@@ -7613,6 +7523,9 @@ Docs & License: https://fullcalendar.io/
7613
7523
  this.renderEventDragMem(props.eventDrag);
7614
7524
  this.renderEventResizeMem(props.eventResize);
7615
7525
  };
7526
+ View.prototype.beforeUpdate = function () {
7527
+ this.addScroll(this.queryScroll());
7528
+ };
7616
7529
  View.prototype.destroy = function () {
7617
7530
  _super.prototype.destroy.call(this);
7618
7531
  this.renderDatesMem.unrender(); // should unrender everything else
@@ -7620,12 +7533,19 @@ Docs & License: https://fullcalendar.io/
7620
7533
  // Sizing
7621
7534
  // -----------------------------------------------------------------------------------------------------------------
7622
7535
  View.prototype.updateSize = function (isResize, viewHeight, isAuto) {
7623
- var calendar = this.calendar;
7624
- if (isResize || calendar.isViewUpdated || calendar.isDatesUpdated || calendar.isEventsUpdated) {
7536
+ var calendar = this.context.calendar;
7537
+ if (isResize) {
7538
+ this.addScroll(this.queryScroll()); // NOTE: same code as in beforeUpdate
7539
+ }
7540
+ if (isResize || // HACKS...
7541
+ calendar.isViewUpdated ||
7542
+ calendar.isDatesUpdated ||
7543
+ calendar.isEventsUpdated) {
7625
7544
  // sort of the catch-all sizing
7626
7545
  // anything that might cause dimension changes
7627
7546
  this.updateBaseSize(isResize, viewHeight, isAuto);
7628
7547
  }
7548
+ // NOTE: popScroll is called by CalendarComponent
7629
7549
  };
7630
7550
  View.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) {
7631
7551
  };
@@ -7634,9 +7554,8 @@ Docs & License: https://fullcalendar.io/
7634
7554
  View.prototype.renderDatesWrap = function (dateProfile) {
7635
7555
  this.renderDates(dateProfile);
7636
7556
  this.addScroll({
7637
- timeMs: createDuration(this.opt('scrollTime')).milliseconds
7557
+ duration: createDuration(this.context.options.scrollTime)
7638
7558
  });
7639
- this.startNowIndicator(dateProfile); // shouldn't render yet because updateSize will be called soon
7640
7559
  };
7641
7560
  View.prototype.unrenderDatesWrap = function () {
7642
7561
  this.stopNowIndicator();
@@ -7669,7 +7588,7 @@ Docs & License: https://fullcalendar.io/
7669
7588
  // util for subclasses
7670
7589
  View.prototype.sliceEvents = function (eventStore, allDay) {
7671
7590
  var props = this.props;
7672
- return sliceEventStore(eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? this.nextDayThreshold : null).fg;
7591
+ return sliceEventStore(eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? this.context.nextDayThreshold : null).fg;
7673
7592
  };
7674
7593
  // Event Selection
7675
7594
  // -----------------------------------------------------------------------------------------------------------------
@@ -7718,17 +7637,18 @@ Docs & License: https://fullcalendar.io/
7718
7637
  // Immediately render the current time indicator and begins re-rendering it at an interval,
7719
7638
  // which is defined by this.getNowIndicatorUnit().
7720
7639
  // TODO: somehow do this for the current whole day's background too
7721
- View.prototype.startNowIndicator = function (dateProfile) {
7640
+ // USAGE: must be called manually from subclasses' render methods! don't need to call stopNowIndicator tho
7641
+ View.prototype.startNowIndicator = function (dateProfile, dateProfileGenerator) {
7722
7642
  var _this = this;
7723
- var dateEnv = this.dateEnv;
7643
+ var _a = this.context, calendar = _a.calendar, dateEnv = _a.dateEnv, options = _a.options;
7724
7644
  var unit;
7725
7645
  var update;
7726
7646
  var delay; // ms wait value
7727
- if (this.opt('nowIndicator')) {
7728
- unit = this.getNowIndicatorUnit(dateProfile);
7647
+ if (options.nowIndicator && !this.initialNowDate) {
7648
+ unit = this.getNowIndicatorUnit(dateProfile, dateProfileGenerator);
7729
7649
  if (unit) {
7730
7650
  update = this.updateNowIndicator.bind(this);
7731
- this.initialNowDate = this.calendar.getNow();
7651
+ this.initialNowDate = calendar.getNow();
7732
7652
  this.initialNowQueriedMs = new Date().valueOf();
7733
7653
  // wait until the beginning of the next interval
7734
7654
  delay = dateEnv.add(dateEnv.startOf(this.initialNowDate, unit), createDuration(1, unit)).valueOf() - this.initialNowDate.valueOf();
@@ -7762,20 +7682,20 @@ Docs & License: https://fullcalendar.io/
7762
7682
  // Immediately unrenders the view's current time indicator and stops any re-rendering timers.
7763
7683
  // Won't cause side effects if indicator isn't rendered.
7764
7684
  View.prototype.stopNowIndicator = function () {
7685
+ if (this.nowIndicatorTimeoutID) {
7686
+ clearTimeout(this.nowIndicatorTimeoutID);
7687
+ this.nowIndicatorTimeoutID = null;
7688
+ }
7689
+ if (this.nowIndicatorIntervalID) {
7690
+ clearInterval(this.nowIndicatorIntervalID);
7691
+ this.nowIndicatorIntervalID = null;
7692
+ }
7765
7693
  if (this.isNowIndicatorRendered) {
7766
- if (this.nowIndicatorTimeoutID) {
7767
- clearTimeout(this.nowIndicatorTimeoutID);
7768
- this.nowIndicatorTimeoutID = null;
7769
- }
7770
- if (this.nowIndicatorIntervalID) {
7771
- clearInterval(this.nowIndicatorIntervalID);
7772
- this.nowIndicatorIntervalID = null;
7773
- }
7774
7694
  this.unrenderNowIndicator();
7775
7695
  this.isNowIndicatorRendered = false;
7776
7696
  }
7777
7697
  };
7778
- View.prototype.getNowIndicatorUnit = function (dateProfile) {
7698
+ View.prototype.getNowIndicatorUnit = function (dateProfile, dateProfileGenerator) {
7779
7699
  // subclasses should implement
7780
7700
  };
7781
7701
  // Renders a current time indicator at the given datetime
@@ -7788,16 +7708,20 @@ Docs & License: https://fullcalendar.io/
7788
7708
  };
7789
7709
  /* Scroller
7790
7710
  ------------------------------------------------------------------------------------------------------------------*/
7791
- View.prototype.addScroll = function (scroll) {
7792
- var queuedScroll = this.queuedScroll || (this.queuedScroll = {});
7793
- __assign(queuedScroll, scroll);
7711
+ View.prototype.addScroll = function (scroll, isForced) {
7712
+ if (isForced) {
7713
+ scroll.isForced = isForced;
7714
+ }
7715
+ __assign(this.queuedScroll || (this.queuedScroll = {}), scroll);
7794
7716
  };
7795
7717
  View.prototype.popScroll = function (isResize) {
7796
7718
  this.applyQueuedScroll(isResize);
7797
7719
  this.queuedScroll = null;
7798
7720
  };
7799
7721
  View.prototype.applyQueuedScroll = function (isResize) {
7800
- this.applyScroll(this.queuedScroll || {}, isResize);
7722
+ if (this.queuedScroll) {
7723
+ this.applyScroll(this.queuedScroll, isResize);
7724
+ }
7801
7725
  };
7802
7726
  View.prototype.queryScroll = function () {
7803
7727
  var scroll = {};
@@ -7807,18 +7731,18 @@ Docs & License: https://fullcalendar.io/
7807
7731
  return scroll;
7808
7732
  };
7809
7733
  View.prototype.applyScroll = function (scroll, isResize) {
7810
- var timeMs = scroll.timeMs;
7811
- if (timeMs != null) {
7812
- delete scroll.timeMs;
7734
+ var duration = scroll.duration, isForced = scroll.isForced;
7735
+ if (duration != null && !isForced) {
7736
+ delete scroll.duration;
7813
7737
  if (this.props.dateProfile) { // dates rendered yet?
7814
- __assign(scroll, this.computeDateScroll(timeMs));
7738
+ __assign(scroll, this.computeDateScroll(duration));
7815
7739
  }
7816
7740
  }
7817
7741
  if (this.props.dateProfile) { // dates rendered yet?
7818
7742
  this.applyDateScroll(scroll);
7819
7743
  }
7820
7744
  };
7821
- View.prototype.computeDateScroll = function (timeMs) {
7745
+ View.prototype.computeDateScroll = function (duration) {
7822
7746
  return {}; // subclasses must implement
7823
7747
  };
7824
7748
  View.prototype.queryDateScroll = function () {
@@ -7828,10 +7752,8 @@ Docs & License: https://fullcalendar.io/
7828
7752
  // subclasses must implement
7829
7753
  };
7830
7754
  // for API
7831
- View.prototype.scrollToTime = function (time) {
7832
- this.applyScroll({
7833
- timeMs: time.milliseconds
7834
- }, false);
7755
+ View.prototype.scrollToDuration = function (duration) {
7756
+ this.applyScroll({ duration: duration }, false);
7835
7757
  };
7836
7758
  return View;
7837
7759
  }(DateComponent));
@@ -7840,12 +7762,12 @@ Docs & License: https://fullcalendar.io/
7840
7762
  View.prototype.dateProfileGeneratorClass = DateProfileGenerator;
7841
7763
 
7842
7764
  var FgEventRenderer = /** @class */ (function () {
7843
- function FgEventRenderer(context) {
7765
+ function FgEventRenderer() {
7844
7766
  this.segs = [];
7845
7767
  this.isSizeDirty = false;
7846
- this.context = context;
7847
7768
  }
7848
- FgEventRenderer.prototype.renderSegs = function (segs, mirrorInfo) {
7769
+ FgEventRenderer.prototype.renderSegs = function (context, segs, mirrorInfo) {
7770
+ this.context = context;
7849
7771
  this.rangeUpdated(); // called too frequently :(
7850
7772
  // render an `.el` on each seg
7851
7773
  // returns a subset of the segs. segs that were actually rendered
@@ -7853,10 +7775,10 @@ Docs & License: https://fullcalendar.io/
7853
7775
  this.segs = segs;
7854
7776
  this.attachSegs(segs, mirrorInfo);
7855
7777
  this.isSizeDirty = true;
7856
- this.context.view.triggerRenderedSegs(this.segs, Boolean(mirrorInfo));
7778
+ triggerRenderedSegs(this.context, this.segs, Boolean(mirrorInfo));
7857
7779
  };
7858
- FgEventRenderer.prototype.unrender = function (_segs, mirrorInfo) {
7859
- this.context.view.triggerWillRemoveSegs(this.segs, Boolean(mirrorInfo));
7780
+ FgEventRenderer.prototype.unrender = function (context, _segs, mirrorInfo) {
7781
+ triggerWillRemoveSegs(this.context, this.segs, Boolean(mirrorInfo));
7860
7782
  this.detachSegs(this.segs);
7861
7783
  this.segs = [];
7862
7784
  };
@@ -7895,7 +7817,7 @@ Docs & License: https://fullcalendar.io/
7895
7817
  seg.el = el;
7896
7818
  }
7897
7819
  });
7898
- segs = filterSegsViaEls(this.context.view, segs, Boolean(mirrorInfo));
7820
+ segs = filterSegsViaEls(this.context, segs, Boolean(mirrorInfo));
7899
7821
  }
7900
7822
  return segs;
7901
7823
  };
@@ -7977,7 +7899,7 @@ Docs & License: https://fullcalendar.io/
7977
7899
  };
7978
7900
  };
7979
7901
  FgEventRenderer.prototype.sortEventSegs = function (segs) {
7980
- var specs = this.context.view.eventOrderSpecs;
7902
+ var specs = this.context.eventOrderSpecs;
7981
7903
  var objs = segs.map(buildSegCompareObj);
7982
7904
  objs.sort(function (obj0, obj1) {
7983
7905
  return compareByFieldSpecs(obj0, obj1, specs);
@@ -8058,19 +7980,22 @@ Docs & License: https://fullcalendar.io/
8058
7980
  });
8059
7981
  }
8060
7982
 
7983
+ /*
7984
+ TODO: when refactoring this class, make a new FillRenderer instance for each `type`
7985
+ */
8061
7986
  var FillRenderer = /** @class */ (function () {
8062
- function FillRenderer(context) {
7987
+ function FillRenderer() {
8063
7988
  this.fillSegTag = 'div';
8064
7989
  this.dirtySizeFlags = {};
8065
- this.context = context;
8066
7990
  this.containerElsByType = {};
8067
7991
  this.segsByType = {};
8068
7992
  }
8069
7993
  FillRenderer.prototype.getSegsByType = function (type) {
8070
7994
  return this.segsByType[type] || [];
8071
7995
  };
8072
- FillRenderer.prototype.renderSegs = function (type, segs) {
7996
+ FillRenderer.prototype.renderSegs = function (type, context, segs) {
8073
7997
  var _a;
7998
+ this.context = context;
8074
7999
  var renderedSegs = this.renderSegEls(type, segs); // assignes `.el` to each seg. returns successfully rendered segs
8075
8000
  var containerEls = this.attachSegs(type, renderedSegs);
8076
8001
  if (containerEls) {
@@ -8078,16 +8003,16 @@ Docs & License: https://fullcalendar.io/
8078
8003
  }
8079
8004
  this.segsByType[type] = renderedSegs;
8080
8005
  if (type === 'bgEvent') {
8081
- this.context.view.triggerRenderedSegs(renderedSegs, false); // isMirror=false
8006
+ triggerRenderedSegs(context, renderedSegs, false); // isMirror=false
8082
8007
  }
8083
8008
  this.dirtySizeFlags[type] = true;
8084
8009
  };
8085
8010
  // Unrenders a specific type of fill that is currently rendered on the grid
8086
- FillRenderer.prototype.unrender = function (type) {
8011
+ FillRenderer.prototype.unrender = function (type, context) {
8087
8012
  var segs = this.segsByType[type];
8088
8013
  if (segs) {
8089
8014
  if (type === 'bgEvent') {
8090
- this.context.view.triggerWillRemoveSegs(segs, false); // isMirror=false
8015
+ triggerWillRemoveSegs(context, segs, false); // isMirror=false
8091
8016
  }
8092
8017
  this.detachSegs(type, segs);
8093
8018
  }
@@ -8112,7 +8037,7 @@ Docs & License: https://fullcalendar.io/
8112
8037
  }
8113
8038
  });
8114
8039
  if (type === 'bgEvent') {
8115
- segs = filterSegsViaEls(this.context.view, segs, false // isMirror. background events can never be mirror elements
8040
+ segs = filterSegsViaEls(this.context, segs, false // isMirror. background events can never be mirror elements
8116
8041
  );
8117
8042
  }
8118
8043
  // correct element type? (would be bad if a non-TD were inserted into a table for example)
@@ -8278,7 +8203,7 @@ Docs & License: https://fullcalendar.io/
8278
8203
  }
8279
8204
  }
8280
8205
  function renderDateCell(dateMarker, dateProfile, datesRepDistinctDays, colCnt, colHeadFormat, context, colspan, otherAttrs) {
8281
- var view = context.view, dateEnv = context.dateEnv, theme = context.theme, options = context.options;
8206
+ var dateEnv = context.dateEnv, theme = context.theme, options = context.options;
8282
8207
  var isDateValid = rangeContainsMarker(dateProfile.activeRange, dateMarker); // TODO: called too frequently. cache somehow.
8283
8208
  var classNames = [
8284
8209
  'fc-day-header',
@@ -8318,7 +8243,7 @@ Docs & License: https://fullcalendar.io/
8318
8243
  '>' +
8319
8244
  (isDateValid ?
8320
8245
  // don't make a link if the heading could represent multiple days, or if there's only one day (forceOff)
8321
- buildGotoAnchorHtml(view, { date: dateMarker, forceOff: !datesRepDistinctDays || colCnt === 1 }, innerHtml) :
8246
+ buildGotoAnchorHtml(options, dateEnv, { date: dateMarker, forceOff: !datesRepDistinctDays || colCnt === 1 }, innerHtml) :
8322
8247
  // if not valid, display text, but no link
8323
8248
  innerHtml) +
8324
8249
  '</th>';
@@ -8326,37 +8251,48 @@ Docs & License: https://fullcalendar.io/
8326
8251
 
8327
8252
  var DayHeader = /** @class */ (function (_super) {
8328
8253
  __extends(DayHeader, _super);
8329
- function DayHeader(context, parentEl) {
8330
- var _this = _super.call(this, context) || this;
8331
- parentEl.innerHTML = ''; // because might be nbsp
8332
- parentEl.appendChild(_this.el = htmlToElement('<div class="fc-row ' + _this.theme.getClass('headerRow') + '">' +
8333
- '<table class="' + _this.theme.getClass('tableGrid') + '">' +
8334
- '<thead></thead>' +
8335
- '</table>' +
8336
- '</div>'));
8337
- _this.thead = _this.el.querySelector('thead');
8254
+ function DayHeader(parentEl) {
8255
+ var _this = _super.call(this) || this;
8256
+ _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton);
8257
+ _this.parentEl = parentEl;
8338
8258
  return _this;
8339
8259
  }
8340
- DayHeader.prototype.destroy = function () {
8341
- removeElement(this.el);
8342
- };
8343
- DayHeader.prototype.render = function (props) {
8260
+ DayHeader.prototype.render = function (props, context) {
8344
8261
  var dates = props.dates, datesRepDistinctDays = props.datesRepDistinctDays;
8345
8262
  var parts = [];
8263
+ this.renderSkeleton(context);
8346
8264
  if (props.renderIntroHtml) {
8347
8265
  parts.push(props.renderIntroHtml());
8348
8266
  }
8349
- var colHeadFormat = createFormatter(this.opt('columnHeaderFormat') ||
8267
+ var colHeadFormat = createFormatter(context.options.columnHeaderFormat ||
8350
8268
  computeFallbackHeaderFormat(datesRepDistinctDays, dates.length));
8351
8269
  for (var _i = 0, dates_1 = dates; _i < dates_1.length; _i++) {
8352
8270
  var date = dates_1[_i];
8353
- parts.push(renderDateCell(date, props.dateProfile, datesRepDistinctDays, dates.length, colHeadFormat, this.context));
8271
+ parts.push(renderDateCell(date, props.dateProfile, datesRepDistinctDays, dates.length, colHeadFormat, context));
8354
8272
  }
8355
- if (this.isRtl) {
8273
+ if (context.isRtl) {
8356
8274
  parts.reverse();
8357
8275
  }
8358
8276
  this.thead.innerHTML = '<tr>' + parts.join('') + '</tr>';
8359
8277
  };
8278
+ DayHeader.prototype.destroy = function () {
8279
+ _super.prototype.destroy.call(this);
8280
+ this.renderSkeleton.unrender();
8281
+ };
8282
+ DayHeader.prototype._renderSkeleton = function (context) {
8283
+ var theme = context.theme;
8284
+ var parentEl = this.parentEl;
8285
+ parentEl.innerHTML = ''; // because might be nbsp
8286
+ parentEl.appendChild(this.el = htmlToElement('<div class="fc-row ' + theme.getClass('headerRow') + '">' +
8287
+ '<table class="' + theme.getClass('tableGrid') + '">' +
8288
+ '<thead></thead>' +
8289
+ '</table>' +
8290
+ '</div>'));
8291
+ this.thead = this.el.querySelector('thead');
8292
+ };
8293
+ DayHeader.prototype._unrenderSkeleton = function () {
8294
+ removeElement(this.el);
8295
+ };
8360
8296
  return DayHeader;
8361
8297
  }(Component));
8362
8298
 
@@ -8505,16 +8441,16 @@ Docs & License: https://fullcalendar.io/
8505
8441
  this.sliceEventDrag = memoize(this._sliceInteraction);
8506
8442
  this.sliceEventResize = memoize(this._sliceInteraction);
8507
8443
  }
8508
- Slicer.prototype.sliceProps = function (props, dateProfile, nextDayThreshold, component) {
8444
+ Slicer.prototype.sliceProps = function (props, dateProfile, nextDayThreshold, calendar, component) {
8509
8445
  var extraArgs = [];
8510
- for (var _i = 4; _i < arguments.length; _i++) {
8511
- extraArgs[_i - 4] = arguments[_i];
8446
+ for (var _i = 5; _i < arguments.length; _i++) {
8447
+ extraArgs[_i - 5] = arguments[_i];
8512
8448
  }
8513
8449
  var eventUiBases = props.eventUiBases;
8514
8450
  var eventSegs = this.sliceEventStore.apply(this, [props.eventStore, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs));
8515
8451
  return {
8516
8452
  dateSelectionSegs: this.sliceDateSelection.apply(this, [props.dateSelection, eventUiBases, component].concat(extraArgs)),
8517
- businessHourSegs: this.sliceBusinessHours.apply(this, [props.businessHours, dateProfile, nextDayThreshold, component].concat(extraArgs)),
8453
+ businessHourSegs: this.sliceBusinessHours.apply(this, [props.businessHours, dateProfile, nextDayThreshold, calendar, component].concat(extraArgs)),
8518
8454
  fgEventSegs: eventSegs.fg,
8519
8455
  bgEventSegs: eventSegs.bg,
8520
8456
  eventDrag: this.sliceEventDrag.apply(this, [props.eventDrag, eventUiBases, dateProfile, nextDayThreshold, component].concat(extraArgs)),
@@ -8532,15 +8468,15 @@ Docs & License: https://fullcalendar.io/
8532
8468
  {},
8533
8469
  component].concat(extraArgs));
8534
8470
  };
8535
- Slicer.prototype._sliceBusinessHours = function (businessHours, dateProfile, nextDayThreshold, component) {
8471
+ Slicer.prototype._sliceBusinessHours = function (businessHours, dateProfile, nextDayThreshold, calendar, component) {
8536
8472
  var extraArgs = [];
8537
- for (var _i = 4; _i < arguments.length; _i++) {
8538
- extraArgs[_i - 4] = arguments[_i];
8473
+ for (var _i = 5; _i < arguments.length; _i++) {
8474
+ extraArgs[_i - 5] = arguments[_i];
8539
8475
  }
8540
8476
  if (!businessHours) {
8541
8477
  return [];
8542
8478
  }
8543
- return this._sliceEventStore.apply(this, [expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), component.calendar),
8479
+ return this._sliceEventStore.apply(this, [expandRecurring(businessHours, computeActiveRange(dateProfile, Boolean(nextDayThreshold)), calendar),
8544
8480
  {},
8545
8481
  dateProfile,
8546
8482
  nextDayThreshold,
@@ -8586,7 +8522,7 @@ Docs & License: https://fullcalendar.io/
8586
8522
  if (!dateSpan) {
8587
8523
  return [];
8588
8524
  }
8589
- var eventRange = fabricateEventRange(dateSpan, eventUiBases, component.calendar);
8525
+ var eventRange = fabricateEventRange(dateSpan, eventUiBases, component.context.calendar);
8590
8526
  var segs = this.sliceRange.apply(this, [dateSpan.range].concat(extraArgs));
8591
8527
  for (var _a = 0, segs_1 = segs; _a < segs_1.length; _a++) {
8592
8528
  var seg = segs_1[_a];
@@ -8642,10 +8578,11 @@ Docs & License: https://fullcalendar.io/
8642
8578
 
8643
8579
  // exports
8644
8580
  // --------------------------------------------------------------------------------------------------
8645
- var version = '4.1.0';
8581
+ var version = '4.4.0';
8646
8582
 
8647
8583
  exports.Calendar = Calendar;
8648
8584
  exports.Component = Component;
8585
+ exports.ComponentContext = ComponentContext;
8649
8586
  exports.DateComponent = DateComponent;
8650
8587
  exports.DateEnv = DateEnv;
8651
8588
  exports.DateProfileGenerator = DateProfileGenerator;
@@ -8693,6 +8630,9 @@ Docs & License: https://fullcalendar.io/
8693
8630
  exports.compensateScroll = compensateScroll;
8694
8631
  exports.computeClippingRect = computeClippingRect;
8695
8632
  exports.computeEdges = computeEdges;
8633
+ exports.computeEventDraggable = computeEventDraggable;
8634
+ exports.computeEventEndResizable = computeEventEndResizable;
8635
+ exports.computeEventStartResizable = computeEventStartResizable;
8696
8636
  exports.computeFallbackHeaderFormat = computeFallbackHeaderFormat;
8697
8637
  exports.computeHeightAndMargins = computeHeightAndMargins;
8698
8638
  exports.computeInnerRect = computeInnerRect;
@@ -8730,7 +8670,6 @@ Docs & License: https://fullcalendar.io/
8730
8670
  exports.formatDate = formatDate;
8731
8671
  exports.formatIsoTimeString = formatIsoTimeString;
8732
8672
  exports.formatRange = formatRange;
8733
- exports.freezeRaw = freezeRaw;
8734
8673
  exports.getAllDayHtml = getAllDayHtml;
8735
8674
  exports.getClippingParents = getClippingParents;
8736
8675
  exports.getDayClasses = getDayClasses;
@@ -8752,11 +8691,10 @@ Docs & License: https://fullcalendar.io/
8752
8691
  exports.isInt = isInt;
8753
8692
  exports.isInteractionValid = isInteractionValid;
8754
8693
  exports.isMultiDayRange = isMultiDayRange;
8755
- exports.isObjectsSimilar = isObjectsSimilar;
8694
+ exports.isPropsEqual = isPropsEqual;
8756
8695
  exports.isPropsValid = isPropsValid;
8757
8696
  exports.isSingleDay = isSingleDay;
8758
8697
  exports.isValidDate = isValidDate;
8759
- exports.isValuesSimilar = isValuesSimilar;
8760
8698
  exports.listenBySelector = listenBySelector;
8761
8699
  exports.mapHash = mapHash;
8762
8700
  exports.matchCellWidths = matchCellWidths;