Skip to content
Snippets Groups Projects
main.js 918 KiB
Newer Older
  • Learn to ignore specific revisions
  •     // 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; };
    
                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,
    
                    getCurrentData: this.getCurrentData,
    
                };
                // 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({
    
                    type: 'NOTHING',
    
                });
            };
            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,
    
                    getCurrentData: this.getCurrentData,
    
                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
    
                if (!wasLoading && isLoading) {
    
                    emitter.trigger('loading', true);
                }
    
                else if (wasLoading && !isLoading) {
    
                    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,
    
                    dynamicOptionOverrides,
    
                ]), 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,
    
                    dynamicOptionOverrides,
    
                ]);
                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]))) {
    
                            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,
    
                    extra: extra,
    
                };
            };
            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,
    
                    dynamicOptionOverrides,
    
                ]);
                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,
    
                    extra: extra,
    
                };
            };
            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,
    
                defaultSeparator: defaultSeparator,
    
            });
        }
        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; });
    
        }
        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,
    
                    color: options.eventColor,
    
                }, 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;
        }
    
        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,
    
                    onData: _this.handleData,
    
                });
                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,
    
            };
        }
        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,
    
            sourceId: String,
    
        };
        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,
    
                leftoverProps: extra,
    
            };
        }
    
        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));
                }
    
                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;
                }
    
                    endContent = model.end;
    
                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
    
                        : 'fc-view-harness-passive',
    
                ];
                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 });
                }
    
            };
            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,
    
                            view: context.viewApi,
    
                        });
                        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,
    
                        view: context.viewApi,
    
                    });
                }
            };
            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,
    
                        EventHovering,
    
                    ];
                    var interactionClasses = DEFAULT_INTERACTIONS.concat(_this.props.pluginHooks.componentInteractions);
    
                    var interactions = interactionClasses.map(function (TheInteractionClass) { return new TheInteractionClass(settings); });
    
                    _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); });
    
                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,
    
                    forPrint: props.forPrint,
    
                };
                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,
    
                isNextEnabled: nextInfo.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 = {
    
                    forPrint: false,
    
                };
                _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);