Newer
Older
7001
7002
7003
7004
7005
7006
7007
7008
7009
7010
7011
7012
7013
7014
7015
7016
7017
7018
7019
7020
7021
7022
7023
7024
7025
7026
7027
// also, whatever is happening in constructor, have it happen in action queue too
var CalendarDataManager = /** @class */ (function () {
function CalendarDataManager(props) {
var _this = this;
this.computeOptionsData = memoize(this._computeOptionsData);
this.computeCurrentViewData = memoize(this._computeCurrentViewData);
this.organizeRawLocales = memoize(organizeRawLocales);
this.buildLocale = memoize(buildLocale);
this.buildPluginHooks = buildBuildPluginHooks();
this.buildDateEnv = memoize(buildDateEnv$1);
this.buildTheme = memoize(buildTheme);
this.parseToolbars = memoize(parseToolbars);
this.buildViewSpecs = memoize(buildViewSpecs);
this.buildDateProfileGenerator = memoizeObjArg(buildDateProfileGenerator);
this.buildViewApi = memoize(buildViewApi);
this.buildViewUiProps = memoizeObjArg(buildViewUiProps);
this.buildEventUiBySource = memoize(buildEventUiBySource, isPropsEqual);
this.buildEventUiBases = memoize(buildEventUiBases);
this.parseContextBusinessHours = memoizeObjArg(parseContextBusinessHours);
this.buildTitle = memoize(buildTitle);
this.emitter = new Emitter();
this.actionRunner = new TaskRunner(this._handleAction.bind(this), this.updateData.bind(this));
this.currentCalendarOptionsInput = {};
this.currentCalendarOptionsRefined = {};
this.currentViewOptionsInput = {};
this.currentViewOptionsRefined = {};
this.currentCalendarOptionsRefiners = {};
this.getCurrentData = function () { return _this.data; };
7029
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041
7042
7043
7044
7045
7046
7047
7048
7049
7050
7051
7052
7053
7054
this.dispatch = function (action) {
_this.actionRunner.request(action); // protects against recursive calls to _handleAction
};
this.props = props;
this.actionRunner.pause();
var dynamicOptionOverrides = {};
var optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
var currentViewType = optionsData.calendarOptions.initialView || optionsData.pluginHooks.initialView;
var currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
// wire things up
// TODO: not DRY
props.calendarApi.currentDataManager = this;
this.emitter.setThisContext(props.calendarApi);
this.emitter.setOptions(currentViewData.options);
var currentDate = getInitialDate(optionsData.calendarOptions, optionsData.dateEnv);
var dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
if (!rangeContainsMarker(dateProfile.activeRange, currentDate)) {
currentDate = dateProfile.currentRange.start;
}
var calendarContext = {
dateEnv: optionsData.dateEnv,
options: optionsData.calendarOptions,
pluginHooks: optionsData.pluginHooks,
calendarApi: props.calendarApi,
dispatch: this.dispatch,
emitter: this.emitter,
7056
7057
7058
7059
7060
7061
7062
7063
7064
7065
7066
7067
7068
7069
7070
7071
7072
7073
7074
7075
7076
7077
};
// needs to be after setThisContext
for (var _i = 0, _a = optionsData.pluginHooks.contextInit; _i < _a.length; _i++) {
var callback = _a[_i];
callback(calendarContext);
}
// NOT DRY
var eventSources = initEventSources(optionsData.calendarOptions, dateProfile, calendarContext);
var initialState = {
dynamicOptionOverrides: dynamicOptionOverrides,
currentViewType: currentViewType,
currentDate: currentDate,
dateProfile: dateProfile,
businessHours: this.parseContextBusinessHours(calendarContext),
eventSources: eventSources,
eventUiBases: {},
eventStore: createEmptyEventStore(),
renderableEventStore: createEmptyEventStore(),
dateSelection: null,
eventSelection: '',
eventDrag: null,
eventResize: null,
selectionConfig: this.buildViewUiProps(calendarContext).selectionConfig,
};
var contextAndState = __assign(__assign({}, calendarContext), initialState);
for (var _b = 0, _c = optionsData.pluginHooks.reducers; _b < _c.length; _b++) {
var reducer = _c[_b];
__assign(initialState, reducer(null, null, contextAndState));
}
if (computeIsLoading(initialState, calendarContext)) {
this.emitter.trigger('loading', true); // NOT DRY
}
this.state = initialState;
this.updateData();
this.actionRunner.resume();
}
CalendarDataManager.prototype.resetOptions = function (optionOverrides, append) {
var props = this.props;
props.optionOverrides = append
? __assign(__assign({}, props.optionOverrides), optionOverrides) : optionOverrides;
this.actionRunner.request({
});
};
CalendarDataManager.prototype._handleAction = function (action) {
var _a = this, props = _a.props, state = _a.state, emitter = _a.emitter;
var dynamicOptionOverrides = reduceDynamicOptionOverrides(state.dynamicOptionOverrides, action);
var optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
var currentViewType = reduceViewType(state.currentViewType, action);
var currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
// wire things up
// TODO: not DRY
props.calendarApi.currentDataManager = this;
emitter.setThisContext(props.calendarApi);
emitter.setOptions(currentViewData.options);
var calendarContext = {
dateEnv: optionsData.dateEnv,
options: optionsData.calendarOptions,
pluginHooks: optionsData.pluginHooks,
calendarApi: props.calendarApi,
dispatch: this.dispatch,
emitter: emitter,
var currentDate = state.currentDate, dateProfile = state.dateProfile;
if (this.data && this.data.dateProfileGenerator !== currentViewData.dateProfileGenerator) { // hack
dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
}
currentDate = reduceCurrentDate(currentDate, action);
dateProfile = reduceDateProfile(dateProfile, action, currentDate, currentViewData.dateProfileGenerator);
if (!rangeContainsMarker(dateProfile.currentRange, currentDate)) {
currentDate = dateProfile.currentRange.start;
}
var eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendarContext);
var eventStore = reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendarContext);
var isEventsLoading = computeEventSourcesLoading(eventSources); // BAD. also called in this func in computeIsLoading
var renderableEventStore = (isEventsLoading && !currentViewData.options.progressiveEventRendering) ?
(state.renderableEventStore || eventStore) : // try from previous state
eventStore;
var _b = this.buildViewUiProps(calendarContext), eventUiSingleBase = _b.eventUiSingleBase, selectionConfig = _b.selectionConfig; // will memoize obj
var eventUiBySource = this.buildEventUiBySource(eventSources);
var eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource);
var newState = {
dynamicOptionOverrides: dynamicOptionOverrides,
currentViewType: currentViewType,
currentDate: currentDate,
dateProfile: dateProfile,
eventSources: eventSources,
eventStore: eventStore,
renderableEventStore: renderableEventStore,
selectionConfig: selectionConfig,
eventUiBases: eventUiBases,
businessHours: this.parseContextBusinessHours(calendarContext),
dateSelection: reduceDateSelection(state.dateSelection, action),
eventSelection: reduceSelectedEvent(state.eventSelection, action),
eventDrag: reduceEventDrag(state.eventDrag, action),
eventResize: reduceEventResize(state.eventResize, action),
};
var contextAndState = __assign(__assign({}, calendarContext), newState);
for (var _i = 0, _c = optionsData.pluginHooks.reducers; _i < _c.length; _i++) {
var reducer = _c[_i];
__assign(newState, reducer(state, action, contextAndState)); // give the OLD state, for old value
}
var wasLoading = computeIsLoading(state, calendarContext);
var isLoading = computeIsLoading(newState, calendarContext);
// TODO: use propSetHandlers in plugin system
emitter.trigger('loading', true);
}
7166
7167
7168
7169
7170
7171
7172
7173
7174
7175
7176
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
emitter.trigger('loading', false);
}
this.state = newState;
if (props.onAction) {
props.onAction(action);
}
};
CalendarDataManager.prototype.updateData = function () {
var _a = this, props = _a.props, state = _a.state;
var oldData = this.data;
var optionsData = this.computeOptionsData(props.optionOverrides, state.dynamicOptionOverrides, props.calendarApi);
var currentViewData = this.computeCurrentViewData(state.currentViewType, optionsData, props.optionOverrides, state.dynamicOptionOverrides);
var data = this.data = __assign(__assign(__assign({ viewTitle: this.buildTitle(state.dateProfile, currentViewData.options, optionsData.dateEnv), calendarApi: props.calendarApi, dispatch: this.dispatch, emitter: this.emitter, getCurrentData: this.getCurrentData }, optionsData), currentViewData), state);
var changeHandlers = optionsData.pluginHooks.optionChangeHandlers;
var oldCalendarOptions = oldData && oldData.calendarOptions;
var newCalendarOptions = optionsData.calendarOptions;
if (oldCalendarOptions && oldCalendarOptions !== newCalendarOptions) {
if (oldCalendarOptions.timeZone !== newCalendarOptions.timeZone) {
// hack
state.eventSources = data.eventSources = reduceEventSourcesNewTimeZone(data.eventSources, state.dateProfile, data);
state.eventStore = data.eventStore = rezoneEventStoreDates(data.eventStore, oldData.dateEnv, data.dateEnv);
}
for (var optionName in changeHandlers) {
if (oldCalendarOptions[optionName] !== newCalendarOptions[optionName]) {
changeHandlers[optionName](newCalendarOptions[optionName], data);
}
}
}
if (props.onData) {
props.onData(data);
}
};
CalendarDataManager.prototype._computeOptionsData = function (optionOverrides, dynamicOptionOverrides, calendarApi) {
// TODO: blacklist options that are handled by optionChangeHandlers
var _a = this.processRawCalendarOptions(optionOverrides, dynamicOptionOverrides), refinedOptions = _a.refinedOptions, pluginHooks = _a.pluginHooks, localeDefaults = _a.localeDefaults, availableLocaleData = _a.availableLocaleData, extra = _a.extra;
warnUnknownOptions(extra);
var dateEnv = this.buildDateEnv(refinedOptions.timeZone, refinedOptions.locale, refinedOptions.weekNumberCalculation, refinedOptions.firstDay, refinedOptions.weekText, pluginHooks, availableLocaleData, refinedOptions.defaultRangeSeparator);
var viewSpecs = this.buildViewSpecs(pluginHooks.views, optionOverrides, dynamicOptionOverrides, localeDefaults);
var theme = this.buildTheme(refinedOptions, pluginHooks);
var toolbarConfig = this.parseToolbars(refinedOptions, optionOverrides, theme, viewSpecs, calendarApi);
return {
calendarOptions: refinedOptions,
pluginHooks: pluginHooks,
dateEnv: dateEnv,
viewSpecs: viewSpecs,
theme: theme,
toolbarConfig: toolbarConfig,
localeDefaults: localeDefaults,
availableRawLocales: availableLocaleData.map,
};
};
// always called from behind a memoizer
CalendarDataManager.prototype.processRawCalendarOptions = function (optionOverrides, dynamicOptionOverrides) {
var _a = mergeRawOptions([
BASE_OPTION_DEFAULTS,
optionOverrides,
]), locales = _a.locales, locale = _a.locale;
var availableLocaleData = this.organizeRawLocales(locales);
var availableRawLocales = availableLocaleData.map;
var localeDefaults = this.buildLocale(locale || availableLocaleData.defaultCode, availableRawLocales).options;
var pluginHooks = this.buildPluginHooks(optionOverrides.plugins || [], globalPlugins);
var refiners = this.currentCalendarOptionsRefiners = __assign(__assign(__assign(__assign(__assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
var extra = {};
var raw = mergeRawOptions([
BASE_OPTION_DEFAULTS,
localeDefaults,
optionOverrides,
]);
var refined = {};
var currentRaw = this.currentCalendarOptionsInput;
var currentRefined = this.currentCalendarOptionsRefined;
var anyChanges = false;
for (var optionName in raw) {
if (optionName !== 'plugins') { // because plugins is special-cased
if (raw[optionName] === currentRaw[optionName] ||
(COMPLEX_OPTION_COMPARATORS[optionName] &&
(optionName in currentRaw) &&
COMPLEX_OPTION_COMPARATORS[optionName](currentRaw[optionName], raw[optionName]))) {
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
refined[optionName] = currentRefined[optionName];
}
else if (refiners[optionName]) {
refined[optionName] = refiners[optionName](raw[optionName]);
anyChanges = true;
}
else {
extra[optionName] = currentRaw[optionName];
}
}
}
if (anyChanges) {
this.currentCalendarOptionsInput = raw;
this.currentCalendarOptionsRefined = refined;
}
return {
rawOptions: this.currentCalendarOptionsInput,
refinedOptions: this.currentCalendarOptionsRefined,
pluginHooks: pluginHooks,
availableLocaleData: availableLocaleData,
localeDefaults: localeDefaults,
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
};
};
CalendarDataManager.prototype._computeCurrentViewData = function (viewType, optionsData, optionOverrides, dynamicOptionOverrides) {
var viewSpec = optionsData.viewSpecs[viewType];
if (!viewSpec) {
throw new Error("viewType \"" + viewType + "\" is not available. Please make sure you've loaded all neccessary plugins");
}
var _a = this.processRawViewOptions(viewSpec, optionsData.pluginHooks, optionsData.localeDefaults, optionOverrides, dynamicOptionOverrides), refinedOptions = _a.refinedOptions, extra = _a.extra;
warnUnknownOptions(extra);
var dateProfileGenerator = this.buildDateProfileGenerator({
dateProfileGeneratorClass: viewSpec.optionDefaults.dateProfileGeneratorClass,
duration: viewSpec.duration,
durationUnit: viewSpec.durationUnit,
usesMinMaxTime: viewSpec.optionDefaults.usesMinMaxTime,
dateEnv: optionsData.dateEnv,
calendarApi: this.props.calendarApi,
slotMinTime: refinedOptions.slotMinTime,
slotMaxTime: refinedOptions.slotMaxTime,
showNonCurrentDates: refinedOptions.showNonCurrentDates,
dayCount: refinedOptions.dayCount,
dateAlignment: refinedOptions.dateAlignment,
dateIncrement: refinedOptions.dateIncrement,
hiddenDays: refinedOptions.hiddenDays,
weekends: refinedOptions.weekends,
nowInput: refinedOptions.now,
validRangeInput: refinedOptions.validRange,
visibleRangeInput: refinedOptions.visibleRange,
monthMode: refinedOptions.monthMode,
fixedWeekCount: refinedOptions.fixedWeekCount,
});
var viewApi = this.buildViewApi(viewType, this.getCurrentData, optionsData.dateEnv);
return { viewSpec: viewSpec, options: refinedOptions, dateProfileGenerator: dateProfileGenerator, viewApi: viewApi };
};
CalendarDataManager.prototype.processRawViewOptions = function (viewSpec, pluginHooks, localeDefaults, optionOverrides, dynamicOptionOverrides) {
var raw = mergeRawOptions([
BASE_OPTION_DEFAULTS,
viewSpec.optionDefaults,
localeDefaults,
optionOverrides,
viewSpec.optionOverrides,
7309
7310
7311
7312
7313
7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
]);
var refiners = __assign(__assign(__assign(__assign(__assign(__assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), VIEW_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
var refined = {};
var currentRaw = this.currentViewOptionsInput;
var currentRefined = this.currentViewOptionsRefined;
var anyChanges = false;
var extra = {};
for (var optionName in raw) {
if (raw[optionName] === currentRaw[optionName]) {
refined[optionName] = currentRefined[optionName];
}
else {
if (raw[optionName] === this.currentCalendarOptionsInput[optionName]) {
if (optionName in this.currentCalendarOptionsRefined) { // might be an "extra" prop
refined[optionName] = this.currentCalendarOptionsRefined[optionName];
}
}
else if (refiners[optionName]) {
refined[optionName] = refiners[optionName](raw[optionName]);
}
else {
extra[optionName] = raw[optionName];
}
anyChanges = true;
}
}
if (anyChanges) {
this.currentViewOptionsInput = raw;
this.currentViewOptionsRefined = refined;
}
return {
rawOptions: this.currentViewOptionsInput,
refinedOptions: this.currentViewOptionsRefined,
};
};
return CalendarDataManager;
}());
function buildDateEnv$1(timeZone, explicitLocale, weekNumberCalculation, firstDay, weekText, pluginHooks, availableLocaleData, defaultSeparator) {
var locale = buildLocale(explicitLocale || availableLocaleData.defaultCode, availableLocaleData.map);
return new DateEnv({
calendarSystem: 'gregory',
timeZone: timeZone,
namedTimeZoneImpl: pluginHooks.namedTimeZonedImpl,
locale: locale,
weekNumberCalculation: weekNumberCalculation,
firstDay: firstDay,
weekText: weekText,
cmdFormatter: pluginHooks.cmdFormatter,
});
}
function buildTheme(options, pluginHooks) {
var ThemeClass = pluginHooks.themeClasses[options.themeSystem] || StandardTheme;
return new ThemeClass(options);
}
function buildDateProfileGenerator(props) {
var DateProfileGeneratorClass = props.dateProfileGeneratorClass || DateProfileGenerator;
return new DateProfileGeneratorClass(props);
}
function buildViewApi(type, getCurrentData, dateEnv) {
return new ViewApi(type, getCurrentData, dateEnv);
}
function buildEventUiBySource(eventSources) {
return mapHash(eventSources, function (eventSource) { return eventSource.ui; });
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
7392
7393
7394
7395
7396
7397
7398
}
function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) {
var eventUiBases = { '': eventUiSingleBase };
for (var defId in eventDefs) {
var def = eventDefs[defId];
if (def.sourceId && eventUiBySource[def.sourceId]) {
eventUiBases[defId] = eventUiBySource[def.sourceId];
}
}
return eventUiBases;
}
function buildViewUiProps(calendarContext) {
var options = calendarContext.options;
return {
eventUiSingleBase: createEventUi({
display: options.eventDisplay,
editable: options.editable,
startEditable: options.eventStartEditable,
durationEditable: options.eventDurationEditable,
constraint: options.eventConstraint,
overlap: typeof options.eventOverlap === 'boolean' ? options.eventOverlap : undefined,
allow: options.eventAllow,
backgroundColor: options.eventBackgroundColor,
borderColor: options.eventBorderColor,
textColor: options.eventTextColor,
}, calendarContext),
selectionConfig: createEventUi({
constraint: options.selectConstraint,
overlap: typeof options.selectOverlap === 'boolean' ? options.selectOverlap : undefined,
allow: options.selectAllow,
}, calendarContext),
function computeIsLoading(state, context) {
for (var _i = 0, _a = context.pluginHooks.isLoadingFuncs; _i < _a.length; _i++) {
var isLoadingFunc = _a[_i];
if (isLoadingFunc(state)) {
return true;
}
}
return false;
}
7417
7418
7419
7420
7421
7422
7423
7424
7425
7426
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438
7439
7440
7441
7442
7443
function parseContextBusinessHours(calendarContext) {
return parseBusinessHours(calendarContext.options.businessHours, calendarContext);
}
function warnUnknownOptions(options, viewName) {
for (var optionName in options) {
console.warn("Unknown option '" + optionName + "'" +
(viewName ? " for view '" + viewName + "'" : ''));
}
}
// TODO: move this to react plugin?
var CalendarDataProvider = /** @class */ (function (_super) {
__extends(CalendarDataProvider, _super);
function CalendarDataProvider(props) {
var _this = _super.call(this, props) || this;
_this.handleData = function (data) {
if (!_this.dataManager) { // still within initial run, before assignment in constructor
// eslint-disable-next-line react/no-direct-mutation-state
_this.state = data; // can't use setState yet
}
else {
_this.setState(data);
}
};
_this.dataManager = new CalendarDataManager({
optionOverrides: props.optionOverrides,
calendarApi: props.calendarApi,
7445
7446
7447
7448
7449
7450
7451
7452
7453
7454
7455
7456
7457
7458
7459
7460
7461
7462
7463
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
});
return _this;
}
CalendarDataProvider.prototype.render = function () {
return this.props.children(this.state);
};
CalendarDataProvider.prototype.componentDidUpdate = function (prevProps) {
var newOptionOverrides = this.props.optionOverrides;
if (newOptionOverrides !== prevProps.optionOverrides) { // prevent recursive handleData
this.dataManager.resetOptions(newOptionOverrides);
}
};
return CalendarDataProvider;
}(Component));
// HELPERS
/*
if nextDayThreshold is specified, slicing is done in an all-day fashion.
you can get nextDayThreshold from context.nextDayThreshold
*/
function sliceEvents(props, allDay) {
return sliceEventStore(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg;
}
var NamedTimeZoneImpl = /** @class */ (function () {
function NamedTimeZoneImpl(timeZoneName) {
this.timeZoneName = timeZoneName;
}
return NamedTimeZoneImpl;
}());
var Interaction = /** @class */ (function () {
function Interaction(settings) {
this.component = settings.component;
}
Interaction.prototype.destroy = function () {
};
return Interaction;
}());
function parseInteractionSettings(component, input) {
return {
component: component,
el: input.el,
useEventCenter: input.useEventCenter != null ? input.useEventCenter : true,
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
};
}
function interactionSettingsToStore(settings) {
var _a;
return _a = {},
_a[settings.component.uid] = settings,
_a;
}
// global state
var interactionSettingsStore = {};
/*
An abstraction for a dragging interaction originating on an event.
Does higher-level things than PointerDragger, such as possibly:
- a "mirror" that moves with the pointer
- a minimum number of pixels or other criteria for a true drag to begin
subclasses must emit:
- pointerdown
- dragstart
- dragmove
- pointerup
- dragend
*/
var ElementDragging = /** @class */ (function () {
function ElementDragging(el, selector) {
this.emitter = new Emitter();
}
ElementDragging.prototype.destroy = function () {
};
ElementDragging.prototype.setMirrorIsVisible = function (bool) {
// optional if subclass doesn't want to support a mirror
};
ElementDragging.prototype.setMirrorNeedsRevert = function (bool) {
// optional if subclass doesn't want to support a mirror
};
ElementDragging.prototype.setAutoScrollEnabled = function (bool) {
// optional
};
return ElementDragging;
}());
// TODO: get rid of this in favor of options system,
// tho it's really easy to access this globally rather than pass thru options.
var config = {};
/*
Information about what will happen when an external element is dragged-and-dropped
onto a calendar. Contains information for creating an event.
*/
var DRAG_META_REFINERS = {
startTime: createDuration,
duration: createDuration,
create: Boolean,
};
function parseDragMeta(raw) {
var _a = refineProps(raw, DRAG_META_REFINERS), refined = _a.refined, extra = _a.extra;
return {
startTime: refined.startTime || null,
duration: refined.duration || null,
create: refined.create != null ? refined.create : true,
sourceId: refined.sourceId,
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
};
}
var ToolbarSection = /** @class */ (function (_super) {
__extends(ToolbarSection, _super);
function ToolbarSection() {
return _super !== null && _super.apply(this, arguments) || this;
}
ToolbarSection.prototype.render = function () {
var _this = this;
var children = this.props.widgetGroups.map(function (widgetGroup) { return _this.renderWidgetGroup(widgetGroup); });
return createElement.apply(void 0, __spreadArrays(['div', { className: 'fc-toolbar-chunk' }], children));
};
ToolbarSection.prototype.renderWidgetGroup = function (widgetGroup) {
var props = this.props;
var theme = this.context.theme;
var children = [];
var isOnlyButtons = true;
for (var _i = 0, widgetGroup_1 = widgetGroup; _i < widgetGroup_1.length; _i++) {
var widget = widgetGroup_1[_i];
var buttonName = widget.buttonName, buttonClick = widget.buttonClick, buttonText = widget.buttonText, buttonIcon = widget.buttonIcon;
if (buttonName === 'title') {
isOnlyButtons = false;
children.push(createElement("h2", { className: "fc-toolbar-title" }, props.title));
}
else {
var ariaAttrs = buttonIcon ? { 'aria-label': buttonName } : {};
var buttonClasses = ["fc-" + buttonName + "-button", theme.getClass('button')];
if (buttonName === props.activeButton) {
buttonClasses.push(theme.getClass('buttonActive'));
}
var isDisabled = (!props.isTodayEnabled && buttonName === 'today') ||
(!props.isPrevEnabled && buttonName === 'prev') ||
(!props.isNextEnabled && buttonName === 'next');
children.push(createElement("button", __assign({ disabled: isDisabled, className: buttonClasses.join(' '), onClick: buttonClick, type: "button" }, ariaAttrs), buttonText || (buttonIcon ? createElement("span", { className: buttonIcon }) : '')));
}
}
if (children.length > 1) {
var groupClassName = (isOnlyButtons && theme.getClass('buttonGroup')) || '';
return createElement.apply(void 0, __spreadArrays(['div', { className: groupClassName }], children));
}
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
return children[0];
};
return ToolbarSection;
}(BaseComponent));
var Toolbar = /** @class */ (function (_super) {
__extends(Toolbar, _super);
function Toolbar() {
return _super !== null && _super.apply(this, arguments) || this;
}
Toolbar.prototype.render = function () {
var _a = this.props, model = _a.model, extraClassName = _a.extraClassName;
var forceLtr = false;
var startContent;
var endContent;
var centerContent = model.center;
if (model.left) {
forceLtr = true;
startContent = model.left;
}
else {
startContent = model.start;
}
if (model.right) {
forceLtr = true;
endContent = model.right;
}
var classNames = [
extraClassName || '',
'fc-toolbar',
forceLtr ? 'fc-toolbar-ltr' : '',
];
return (createElement("div", { className: classNames.join(' ') },
this.renderSection('start', startContent || []),
this.renderSection('center', centerContent || []),
this.renderSection('end', endContent || [])));
Toolbar.prototype.renderSection = function (key, widgetGroups) {
var props = this.props;
return (createElement(ToolbarSection, { key: key, widgetGroups: widgetGroups, title: props.title, activeButton: props.activeButton, isTodayEnabled: props.isTodayEnabled, isPrevEnabled: props.isPrevEnabled, isNextEnabled: props.isNextEnabled }));
};
return Toolbar;
}(BaseComponent));
// TODO: do function component?
var ViewContainer = /** @class */ (function (_super) {
__extends(ViewContainer, _super);
function ViewContainer() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.state = {
availableWidth: null,
};
_this.handleEl = function (el) {
_this.el = el;
setRef(_this.props.elRef, el);
_this.updateAvailableWidth();
};
_this.handleResize = function () {
_this.updateAvailableWidth();
};
return _this;
}
ViewContainer.prototype.render = function () {
var _a = this, props = _a.props, state = _a.state;
var aspectRatio = props.aspectRatio;
var classNames = [
'fc-view-harness',
(aspectRatio || props.liquid || props.height)
? 'fc-view-harness-active' // harness controls the height
];
var height = '';
var paddingBottom = '';
if (aspectRatio) {
if (state.availableWidth !== null) {
height = state.availableWidth / aspectRatio;
}
else {
// while waiting to know availableWidth, we can't set height to *zero*
// because will cause lots of unnecessary scrollbars within scrollgrid.
// BETTER: don't start rendering ANYTHING yet until we know container width
// NOTE: why not always use paddingBottom? Causes height oscillation (issue 5606)
paddingBottom = (1 / aspectRatio) * 100 + "%";
}
}
else {
height = props.height || '';
}
return (createElement("div", { ref: this.handleEl, onClick: props.onClick, className: classNames.join(' '), style: { height: height, paddingBottom: paddingBottom } }, props.children));
};
ViewContainer.prototype.componentDidMount = function () {
this.context.addResizeHandler(this.handleResize);
};
ViewContainer.prototype.componentWillUnmount = function () {
this.context.removeResizeHandler(this.handleResize);
};
ViewContainer.prototype.updateAvailableWidth = function () {
if (this.el && // needed. but why?
this.props.aspectRatio // aspectRatio is the only height setting that needs availableWidth
) {
this.setState({ availableWidth: this.el.offsetWidth });
}
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
};
return ViewContainer;
}(BaseComponent));
/*
Detects when the user clicks on an event within a DateComponent
*/
var EventClicking = /** @class */ (function (_super) {
__extends(EventClicking, _super);
function EventClicking(settings) {
var _this = _super.call(this, settings) || this;
_this.handleSegClick = function (ev, segEl) {
var component = _this.component;
var context = component.context;
var seg = getElSeg(segEl);
if (seg && // might be the <div> surrounding the more link
component.isValidSegDownEl(ev.target)) {
// our way to simulate a link click for elements that can't be <a> tags
// grab before trigger fired in case trigger trashes DOM thru rerendering
var hasUrlContainer = elementClosest(ev.target, '.fc-event-forced-url');
var url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';
context.emitter.trigger('eventClick', {
el: segEl,
event: new EventApi(component.context, seg.eventRange.def, seg.eventRange.instance),
jsEvent: ev,
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
7779
});
if (url && !ev.defaultPrevented) {
window.location.href = url;
}
}
};
_this.destroy = listenBySelector(settings.el, 'click', '.fc-event', // on both fg and bg events
_this.handleSegClick);
return _this;
}
return EventClicking;
}(Interaction));
/*
Triggers events and adds/removes core classNames when the user's pointer
enters/leaves event-elements of a component.
*/
var EventHovering = /** @class */ (function (_super) {
__extends(EventHovering, _super);
function EventHovering(settings) {
var _this = _super.call(this, settings) || this;
// for simulating an eventMouseLeave when the event el is destroyed while mouse is over it
_this.handleEventElRemove = function (el) {
if (el === _this.currentSegEl) {
_this.handleSegLeave(null, _this.currentSegEl);
}
};
_this.handleSegEnter = function (ev, segEl) {
if (getElSeg(segEl)) { // TODO: better way to make sure not hovering over more+ link or its wrapper
_this.currentSegEl = segEl;
_this.triggerEvent('eventMouseEnter', ev, segEl);
}
};
_this.handleSegLeave = function (ev, segEl) {
if (_this.currentSegEl) {
_this.currentSegEl = null;
_this.triggerEvent('eventMouseLeave', ev, segEl);
}
};
_this.removeHoverListeners = listenToHoverBySelector(settings.el, '.fc-event', // on both fg and bg events
_this.handleSegEnter, _this.handleSegLeave);
return _this;
}
EventHovering.prototype.destroy = function () {
this.removeHoverListeners();
};
EventHovering.prototype.triggerEvent = function (publicEvName, ev, segEl) {
var component = this.component;
var context = component.context;
var seg = getElSeg(segEl);
if (!ev || component.isValidSegDownEl(ev.target)) {
context.emitter.trigger(publicEvName, {
el: segEl,
event: new EventApi(context, seg.eventRange.def, seg.eventRange.instance),
jsEvent: ev,
7781
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
});
}
};
return EventHovering;
}(Interaction));
var CalendarContent = /** @class */ (function (_super) {
__extends(CalendarContent, _super);
function CalendarContent() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.buildViewContext = memoize(buildViewContext);
_this.buildViewPropTransformers = memoize(buildViewPropTransformers);
_this.buildToolbarProps = memoize(buildToolbarProps);
_this.handleNavLinkClick = buildDelegationHandler('a[data-navlink]', _this._handleNavLinkClick.bind(_this));
_this.headerRef = createRef();
_this.footerRef = createRef();
_this.interactionsStore = {};
// Component Registration
// -----------------------------------------------------------------------------------------------------------------
_this.registerInteractiveComponent = function (component, settingsInput) {
var settings = parseInteractionSettings(component, settingsInput);
var DEFAULT_INTERACTIONS = [
EventClicking,
];
var interactionClasses = DEFAULT_INTERACTIONS.concat(_this.props.pluginHooks.componentInteractions);
var interactions = interactionClasses.map(function (TheInteractionClass) { return new TheInteractionClass(settings); });
7808
7809
7810
7811
7812
7813
7814
7815
7816
7817
7818
7819
7820
7821
7822
7823
7824
7825
7826
7827
7828
7829
7830
7831
7832
7833
7834
7835
7836
7837
7838
7839
7840
7841
7842
7843
7844
7845
7846
7847
7848
7849
7850
7851
7852
7853
7854
7855
7856
7857
7858
7859
_this.interactionsStore[component.uid] = interactions;
interactionSettingsStore[component.uid] = settings;
};
_this.unregisterInteractiveComponent = function (component) {
for (var _i = 0, _a = _this.interactionsStore[component.uid]; _i < _a.length; _i++) {
var listener = _a[_i];
listener.destroy();
}
delete _this.interactionsStore[component.uid];
delete interactionSettingsStore[component.uid];
};
// Resizing
// -----------------------------------------------------------------------------------------------------------------
_this.resizeRunner = new DelayedRunner(function () {
_this.props.emitter.trigger('_resize', true); // should window resizes be considered "forced" ?
_this.props.emitter.trigger('windowResize', { view: _this.props.viewApi });
});
_this.handleWindowResize = function (ev) {
var options = _this.props.options;
if (options.handleWindowResize &&
ev.target === window // avoid jqui events
) {
_this.resizeRunner.request(options.windowResizeDelay);
}
};
return _this;
}
/*
renders INSIDE of an outer div
*/
CalendarContent.prototype.render = function () {
var props = this.props;
var toolbarConfig = props.toolbarConfig, options = props.options;
var toolbarProps = this.buildToolbarProps(props.viewSpec, props.dateProfile, props.dateProfileGenerator, props.currentDate, getNow(props.options.now, props.dateEnv), // TODO: use NowTimer????
props.viewTitle);
var viewVGrow = false;
var viewHeight = '';
var viewAspectRatio;
if (props.isHeightAuto || props.forPrint) {
viewHeight = '';
}
else if (options.height != null) {
viewVGrow = true;
}
else if (options.contentHeight != null) {
viewHeight = options.contentHeight;
}
else {
viewAspectRatio = Math.max(options.aspectRatio, 0.5); // prevent from getting too tall
}
var viewContext = this.buildViewContext(props.viewSpec, props.viewApi, props.options, props.dateProfileGenerator, props.dateEnv, props.theme, props.pluginHooks, props.dispatch, props.getCurrentData, props.emitter, props.calendarApi, this.registerInteractiveComponent, this.unregisterInteractiveComponent);
return (createElement(ViewContextType.Provider, { value: viewContext },
toolbarConfig.headerToolbar && (createElement(Toolbar, __assign({ ref: this.headerRef, extraClassName: "fc-header-toolbar", model: toolbarConfig.headerToolbar }, toolbarProps))),
createElement(ViewContainer, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, onClick: this.handleNavLinkClick },
this.renderView(props),
this.buildAppendContent()),
toolbarConfig.footerToolbar && (createElement(Toolbar, __assign({ ref: this.footerRef, extraClassName: "fc-footer-toolbar", model: toolbarConfig.footerToolbar }, toolbarProps)))));
};
CalendarContent.prototype.componentDidMount = function () {
var props = this.props;
this.calendarInteractions = props.pluginHooks.calendarInteractions
.map(function (CalendarInteractionClass) { return new CalendarInteractionClass(props); });
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928
7929
window.addEventListener('resize', this.handleWindowResize);
var propSetHandlers = props.pluginHooks.propSetHandlers;
for (var propName in propSetHandlers) {
propSetHandlers[propName](props[propName], props);
}
};
CalendarContent.prototype.componentDidUpdate = function (prevProps) {
var props = this.props;
var propSetHandlers = props.pluginHooks.propSetHandlers;
for (var propName in propSetHandlers) {
if (props[propName] !== prevProps[propName]) {
propSetHandlers[propName](props[propName], props);
}
}
};
CalendarContent.prototype.componentWillUnmount = function () {
window.removeEventListener('resize', this.handleWindowResize);
this.resizeRunner.clear();
for (var _i = 0, _a = this.calendarInteractions; _i < _a.length; _i++) {
var interaction = _a[_i];
interaction.destroy();
}
this.props.emitter.trigger('_unmount');
};
CalendarContent.prototype._handleNavLinkClick = function (ev, anchorEl) {
var _a = this.props, dateEnv = _a.dateEnv, options = _a.options, calendarApi = _a.calendarApi;
var navLinkOptions = anchorEl.getAttribute('data-navlink');
navLinkOptions = navLinkOptions ? JSON.parse(navLinkOptions) : {};
var dateMarker = dateEnv.createMarker(navLinkOptions.date);
var viewType = navLinkOptions.type;
var customAction = viewType === 'day' ? options.navLinkDayClick :
viewType === 'week' ? options.navLinkWeekClick : null;
if (typeof customAction === 'function') {
customAction.call(calendarApi, dateEnv.toDate(dateMarker), ev);
}
else {
if (typeof customAction === 'string') {
viewType = customAction;
}
calendarApi.zoomTo(dateMarker, viewType);
}
};
CalendarContent.prototype.buildAppendContent = function () {
var props = this.props;
var children = props.pluginHooks.viewContainerAppends.map(function (buildAppendContent) { return buildAppendContent(props); });
return createElement.apply(void 0, __spreadArrays([Fragment, {}], children));
};
CalendarContent.prototype.renderView = function (props) {
var pluginHooks = props.pluginHooks;
var viewSpec = props.viewSpec;
var viewProps = {
dateProfile: props.dateProfile,
businessHours: props.businessHours,
eventStore: props.renderableEventStore,
eventUiBases: props.eventUiBases,
dateSelection: props.dateSelection,
eventSelection: props.eventSelection,
eventDrag: props.eventDrag,
eventResize: props.eventResize,
isHeightAuto: props.isHeightAuto,
7931
7932
7933
7934
7935
7936
7937
7938
7939
7940
7941
7942
7943
7944
7945
7946
7947
7948
7949
7950
7951
};
var transformers = this.buildViewPropTransformers(pluginHooks.viewPropsTransformers);
for (var _i = 0, transformers_1 = transformers; _i < transformers_1.length; _i++) {
var transformer = transformers_1[_i];
__assign(viewProps, transformer.transform(viewProps, props));
}
var ViewComponent = viewSpec.component;
return (createElement(ViewComponent, __assign({}, viewProps)));
};
return CalendarContent;
}(PureComponent));
function buildToolbarProps(viewSpec, dateProfile, dateProfileGenerator, currentDate, now, title) {
// don't force any date-profiles to valid date profiles (the `false`) so that we can tell if it's invalid
var todayInfo = dateProfileGenerator.build(now, undefined, false); // TODO: need `undefined` or else INFINITE LOOP for some reason
var prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate, false);
var nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate, false);
return {
title: title,
activeButton: viewSpec.type,
isTodayEnabled: todayInfo.isValid && !rangeContainsMarker(dateProfile.currentRange, now),
isPrevEnabled: prevInfo.isValid,
};
}
// Plugin
// -----------------------------------------------------------------------------------------------------------------
function buildViewPropTransformers(theClasses) {
return theClasses.map(function (TheClass) { return new TheClass(); });
}
var CalendarRoot = /** @class */ (function (_super) {
__extends(CalendarRoot, _super);
function CalendarRoot() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.state = {
};
_this.handleBeforePrint = function () {
_this.setState({ forPrint: true });
};
_this.handleAfterPrint = function () {
_this.setState({ forPrint: false });
};
return _this;
}
CalendarRoot.prototype.render = function () {
var props = this.props;
var options = props.options;
var forPrint = this.state.forPrint;
var isHeightAuto = forPrint || options.height === 'auto' || options.contentHeight === 'auto';
var height = (!isHeightAuto && options.height != null) ? options.height : '';
var classNames = [
'fc',
forPrint ? 'fc-media-print' : 'fc-media-screen',
"fc-direction-" + options.direction,
props.theme.getClass('root'),
];
if (!getCanVGrowWithinCell()) {
classNames.push('fc-liquid-hack');
}
return props.children(classNames, height, isHeightAuto, forPrint);
};
CalendarRoot.prototype.componentDidMount = function () {
var emitter = this.props.emitter;
emitter.on('_beforeprint', this.handleBeforePrint);
emitter.on('_afterprint', this.handleAfterPrint);
};
CalendarRoot.prototype.componentWillUnmount = function () {
var emitter = this.props.emitter;
emitter.off('_beforeprint', this.handleBeforePrint);