1 | import { m as mergeProps, g as guid, i as isArraysEqual, T as Theme, a as mapHash, B as BaseComponent, V as ViewContextType, C as ContentContainer, b as buildViewClassNames, c as greatestDurationDenominator, d as createDuration, e as BASE_OPTION_DEFAULTS, f as arrayToHash, h as filterHash, j as buildEventSourceRefiners, p as parseEventSource, k as formatWithOrdinals, u as unpromisify, l as buildRangeApiWithTimeZone, n as identity, r as requestJson, s as subtractDurations, o as intersectRanges, q as startOfDay, t as addDays, v as hashValuesToArray, w as buildEventApis, D as DelayedRunner, x as createFormatter, y as diffWholeDays, z as memoize, A as memoizeObjArg, E as isPropsEqual, F as Emitter, G as getInitialDate, H as rangeContainsMarker, I as createEmptyEventStore, J as reduceCurrentDate, K as reduceEventStore, L as rezoneEventStoreDates, M as mergeRawOptions, N as BASE_OPTION_REFINERS, O as CALENDAR_LISTENER_REFINERS, P as CALENDAR_OPTION_REFINERS, Q as COMPLEX_OPTION_COMPARATORS, R as VIEW_OPTION_REFINERS, S as DateEnv, U as DateProfileGenerator, W as createEventUi, X as parseBusinessHours, Y as setRef, Z as Interaction, _ as getElSeg, $ as elementClosest, a0 as EventImpl, a1 as listenBySelector, a2 as listenToHoverBySelector, a3 as PureComponent, a4 as buildViewContext, a5 as getUniqueDomId, a6 as parseInteractionSettings, a7 as interactionSettingsStore, a8 as getNow, a9 as CalendarImpl, aa as flushSync, ab as CalendarRoot, ac as RenderId, ad as ensureElHasStyles, ae as applyStyleProp, af as sliceEventStore } from './internal-common.js';
|
2 | export { ag as JsonRequestError } from './internal-common.js';
|
3 | import { createElement, createRef, Fragment, render } from 'preact';
|
4 | import 'preact/compat';
|
5 |
|
6 | const globalLocales = [];
|
7 |
|
8 | const MINIMAL_RAW_EN_LOCALE = {
|
9 | code: 'en',
|
10 | week: {
|
11 | dow: 0,
|
12 | doy: 4,
|
13 | },
|
14 | direction: 'ltr',
|
15 | buttonText: {
|
16 | prev: 'prev',
|
17 | next: 'next',
|
18 | prevYear: 'prev year',
|
19 | nextYear: 'next year',
|
20 | year: 'year',
|
21 | today: 'today',
|
22 | month: 'month',
|
23 | week: 'week',
|
24 | day: 'day',
|
25 | list: 'list',
|
26 | },
|
27 | weekText: 'W',
|
28 | weekTextLong: 'Week',
|
29 | closeHint: 'Close',
|
30 | timeHint: 'Time',
|
31 | eventHint: 'Event',
|
32 | allDayText: 'all-day',
|
33 | moreLinkText: 'more',
|
34 | noEventsText: 'No events to display',
|
35 | };
|
36 | const RAW_EN_LOCALE = Object.assign(Object.assign({}, MINIMAL_RAW_EN_LOCALE), {
|
37 |
|
38 |
|
39 | buttonHints: {
|
40 | prev: 'Previous $0',
|
41 | next: 'Next $0',
|
42 | today(buttonText, unit) {
|
43 | return (unit === 'day')
|
44 | ? 'Today'
|
45 | : `This ${buttonText}`;
|
46 | },
|
47 | }, viewHint: '$0 view', navLinkHint: 'Go to $0', moreLinkHint(eventCnt) {
|
48 | return `Show ${eventCnt} more event${eventCnt === 1 ? '' : 's'}`;
|
49 | } });
|
50 | function organizeRawLocales(explicitRawLocales) {
|
51 | let defaultCode = explicitRawLocales.length > 0 ? explicitRawLocales[0].code : 'en';
|
52 | let allRawLocales = globalLocales.concat(explicitRawLocales);
|
53 | let rawLocaleMap = {
|
54 | en: RAW_EN_LOCALE,
|
55 | };
|
56 | for (let rawLocale of allRawLocales) {
|
57 | rawLocaleMap[rawLocale.code] = rawLocale;
|
58 | }
|
59 | return {
|
60 | map: rawLocaleMap,
|
61 | defaultCode,
|
62 | };
|
63 | }
|
64 | function buildLocale(inputSingular, available) {
|
65 | if (typeof inputSingular === 'object' && !Array.isArray(inputSingular)) {
|
66 | return parseLocale(inputSingular.code, [inputSingular.code], inputSingular);
|
67 | }
|
68 | return queryLocale(inputSingular, available);
|
69 | }
|
70 | function queryLocale(codeArg, available) {
|
71 | let codes = [].concat(codeArg || []);
|
72 | let raw = queryRawLocale(codes, available) || RAW_EN_LOCALE;
|
73 | return parseLocale(codeArg, codes, raw);
|
74 | }
|
75 | function queryRawLocale(codes, available) {
|
76 | for (let i = 0; i < codes.length; i += 1) {
|
77 | let parts = codes[i].toLocaleLowerCase().split('-');
|
78 | for (let j = parts.length; j > 0; j -= 1) {
|
79 | let simpleId = parts.slice(0, j).join('-');
|
80 | if (available[simpleId]) {
|
81 | return available[simpleId];
|
82 | }
|
83 | }
|
84 | }
|
85 | return null;
|
86 | }
|
87 | function parseLocale(codeArg, codes, raw) {
|
88 | let merged = mergeProps([MINIMAL_RAW_EN_LOCALE, raw], ['buttonText']);
|
89 | delete merged.code;
|
90 | let { week } = merged;
|
91 | delete merged.week;
|
92 | return {
|
93 | codeArg,
|
94 | codes,
|
95 | week,
|
96 | simpleNumberFormat: new Intl.NumberFormat(codeArg),
|
97 | options: merged,
|
98 | };
|
99 | }
|
100 |
|
101 |
|
102 | function createPlugin(input) {
|
103 | return {
|
104 | id: guid(),
|
105 | name: input.name,
|
106 | premiumReleaseDate: input.premiumReleaseDate ? new Date(input.premiumReleaseDate) : undefined,
|
107 | deps: input.deps || [],
|
108 | reducers: input.reducers || [],
|
109 | isLoadingFuncs: input.isLoadingFuncs || [],
|
110 | contextInit: [].concat(input.contextInit || []),
|
111 | eventRefiners: input.eventRefiners || {},
|
112 | eventDefMemberAdders: input.eventDefMemberAdders || [],
|
113 | eventSourceRefiners: input.eventSourceRefiners || {},
|
114 | isDraggableTransformers: input.isDraggableTransformers || [],
|
115 | eventDragMutationMassagers: input.eventDragMutationMassagers || [],
|
116 | eventDefMutationAppliers: input.eventDefMutationAppliers || [],
|
117 | dateSelectionTransformers: input.dateSelectionTransformers || [],
|
118 | datePointTransforms: input.datePointTransforms || [],
|
119 | dateSpanTransforms: input.dateSpanTransforms || [],
|
120 | views: input.views || {},
|
121 | viewPropsTransformers: input.viewPropsTransformers || [],
|
122 | isPropsValid: input.isPropsValid || null,
|
123 | externalDefTransforms: input.externalDefTransforms || [],
|
124 | viewContainerAppends: input.viewContainerAppends || [],
|
125 | eventDropTransformers: input.eventDropTransformers || [],
|
126 | componentInteractions: input.componentInteractions || [],
|
127 | calendarInteractions: input.calendarInteractions || [],
|
128 | themeClasses: input.themeClasses || {},
|
129 | eventSourceDefs: input.eventSourceDefs || [],
|
130 | cmdFormatter: input.cmdFormatter,
|
131 | recurringTypes: input.recurringTypes || [],
|
132 | namedTimeZonedImpl: input.namedTimeZonedImpl,
|
133 | initialView: input.initialView || '',
|
134 | elementDraggingImpl: input.elementDraggingImpl,
|
135 | optionChangeHandlers: input.optionChangeHandlers || {},
|
136 | scrollGridImpl: input.scrollGridImpl || null,
|
137 | listenerRefiners: input.listenerRefiners || {},
|
138 | optionRefiners: input.optionRefiners || {},
|
139 | propSetHandlers: input.propSetHandlers || {},
|
140 | };
|
141 | }
|
142 | function buildPluginHooks(pluginDefs, globalDefs) {
|
143 | let currentPluginIds = {};
|
144 | let hooks = {
|
145 | premiumReleaseDate: undefined,
|
146 | reducers: [],
|
147 | isLoadingFuncs: [],
|
148 | contextInit: [],
|
149 | eventRefiners: {},
|
150 | eventDefMemberAdders: [],
|
151 | eventSourceRefiners: {},
|
152 | isDraggableTransformers: [],
|
153 | eventDragMutationMassagers: [],
|
154 | eventDefMutationAppliers: [],
|
155 | dateSelectionTransformers: [],
|
156 | datePointTransforms: [],
|
157 | dateSpanTransforms: [],
|
158 | views: {},
|
159 | viewPropsTransformers: [],
|
160 | isPropsValid: null,
|
161 | externalDefTransforms: [],
|
162 | viewContainerAppends: [],
|
163 | eventDropTransformers: [],
|
164 | componentInteractions: [],
|
165 | calendarInteractions: [],
|
166 | themeClasses: {},
|
167 | eventSourceDefs: [],
|
168 | cmdFormatter: null,
|
169 | recurringTypes: [],
|
170 | namedTimeZonedImpl: null,
|
171 | initialView: '',
|
172 | elementDraggingImpl: null,
|
173 | optionChangeHandlers: {},
|
174 | scrollGridImpl: null,
|
175 | listenerRefiners: {},
|
176 | optionRefiners: {},
|
177 | propSetHandlers: {},
|
178 | };
|
179 | function addDefs(defs) {
|
180 | for (let def of defs) {
|
181 | const pluginName = def.name;
|
182 | const currentId = currentPluginIds[pluginName];
|
183 | if (currentId === undefined) {
|
184 | currentPluginIds[pluginName] = def.id;
|
185 | addDefs(def.deps);
|
186 | hooks = combineHooks(hooks, def);
|
187 | }
|
188 | else if (currentId !== def.id) {
|
189 |
|
190 | console.warn(`Duplicate plugin '${pluginName}'`);
|
191 | }
|
192 | }
|
193 | }
|
194 | if (pluginDefs) {
|
195 | addDefs(pluginDefs);
|
196 | }
|
197 | addDefs(globalDefs);
|
198 | return hooks;
|
199 | }
|
200 | function buildBuildPluginHooks() {
|
201 | let currentOverrideDefs = [];
|
202 | let currentGlobalDefs = [];
|
203 | let currentHooks;
|
204 | return (overrideDefs, globalDefs) => {
|
205 | if (!currentHooks || !isArraysEqual(overrideDefs, currentOverrideDefs) || !isArraysEqual(globalDefs, currentGlobalDefs)) {
|
206 | currentHooks = buildPluginHooks(overrideDefs, globalDefs);
|
207 | }
|
208 | currentOverrideDefs = overrideDefs;
|
209 | currentGlobalDefs = globalDefs;
|
210 | return currentHooks;
|
211 | };
|
212 | }
|
213 | function combineHooks(hooks0, hooks1) {
|
214 | return {
|
215 | premiumReleaseDate: compareOptionalDates(hooks0.premiumReleaseDate, hooks1.premiumReleaseDate),
|
216 | reducers: hooks0.reducers.concat(hooks1.reducers),
|
217 | isLoadingFuncs: hooks0.isLoadingFuncs.concat(hooks1.isLoadingFuncs),
|
218 | contextInit: hooks0.contextInit.concat(hooks1.contextInit),
|
219 | eventRefiners: Object.assign(Object.assign({}, hooks0.eventRefiners), hooks1.eventRefiners),
|
220 | eventDefMemberAdders: hooks0.eventDefMemberAdders.concat(hooks1.eventDefMemberAdders),
|
221 | eventSourceRefiners: Object.assign(Object.assign({}, hooks0.eventSourceRefiners), hooks1.eventSourceRefiners),
|
222 | isDraggableTransformers: hooks0.isDraggableTransformers.concat(hooks1.isDraggableTransformers),
|
223 | eventDragMutationMassagers: hooks0.eventDragMutationMassagers.concat(hooks1.eventDragMutationMassagers),
|
224 | eventDefMutationAppliers: hooks0.eventDefMutationAppliers.concat(hooks1.eventDefMutationAppliers),
|
225 | dateSelectionTransformers: hooks0.dateSelectionTransformers.concat(hooks1.dateSelectionTransformers),
|
226 | datePointTransforms: hooks0.datePointTransforms.concat(hooks1.datePointTransforms),
|
227 | dateSpanTransforms: hooks0.dateSpanTransforms.concat(hooks1.dateSpanTransforms),
|
228 | views: Object.assign(Object.assign({}, hooks0.views), hooks1.views),
|
229 | viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers),
|
230 | isPropsValid: hooks1.isPropsValid || hooks0.isPropsValid,
|
231 | externalDefTransforms: hooks0.externalDefTransforms.concat(hooks1.externalDefTransforms),
|
232 | viewContainerAppends: hooks0.viewContainerAppends.concat(hooks1.viewContainerAppends),
|
233 | eventDropTransformers: hooks0.eventDropTransformers.concat(hooks1.eventDropTransformers),
|
234 | calendarInteractions: hooks0.calendarInteractions.concat(hooks1.calendarInteractions),
|
235 | componentInteractions: hooks0.componentInteractions.concat(hooks1.componentInteractions),
|
236 | themeClasses: Object.assign(Object.assign({}, hooks0.themeClasses), hooks1.themeClasses),
|
237 | eventSourceDefs: hooks0.eventSourceDefs.concat(hooks1.eventSourceDefs),
|
238 | cmdFormatter: hooks1.cmdFormatter || hooks0.cmdFormatter,
|
239 | recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes),
|
240 | namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl,
|
241 | initialView: hooks0.initialView || hooks1.initialView,
|
242 | elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl,
|
243 | optionChangeHandlers: Object.assign(Object.assign({}, hooks0.optionChangeHandlers), hooks1.optionChangeHandlers),
|
244 | scrollGridImpl: hooks1.scrollGridImpl || hooks0.scrollGridImpl,
|
245 | listenerRefiners: Object.assign(Object.assign({}, hooks0.listenerRefiners), hooks1.listenerRefiners),
|
246 | optionRefiners: Object.assign(Object.assign({}, hooks0.optionRefiners), hooks1.optionRefiners),
|
247 | propSetHandlers: Object.assign(Object.assign({}, hooks0.propSetHandlers), hooks1.propSetHandlers),
|
248 | };
|
249 | }
|
250 | function compareOptionalDates(date0, date1) {
|
251 | if (date0 === undefined) {
|
252 | return date1;
|
253 | }
|
254 | if (date1 === undefined) {
|
255 | return date0;
|
256 | }
|
257 | return new Date(Math.max(date0.valueOf(), date1.valueOf()));
|
258 | }
|
259 |
|
260 | class StandardTheme extends Theme {
|
261 | }
|
262 | StandardTheme.prototype.classes = {
|
263 | root: 'fc-theme-standard',
|
264 | tableCellShaded: 'fc-cell-shaded',
|
265 | buttonGroup: 'fc-button-group',
|
266 | button: 'fc-button fc-button-primary',
|
267 | buttonActive: 'fc-button-active',
|
268 | };
|
269 | StandardTheme.prototype.baseIconClass = 'fc-icon';
|
270 | StandardTheme.prototype.iconClasses = {
|
271 | close: 'fc-icon-x',
|
272 | prev: 'fc-icon-chevron-left',
|
273 | next: 'fc-icon-chevron-right',
|
274 | prevYear: 'fc-icon-chevrons-left',
|
275 | nextYear: 'fc-icon-chevrons-right',
|
276 | };
|
277 | StandardTheme.prototype.rtlIconClasses = {
|
278 | prev: 'fc-icon-chevron-right',
|
279 | next: 'fc-icon-chevron-left',
|
280 | prevYear: 'fc-icon-chevrons-right',
|
281 | nextYear: 'fc-icon-chevrons-left',
|
282 | };
|
283 | StandardTheme.prototype.iconOverrideOption = 'buttonIcons';
|
284 | StandardTheme.prototype.iconOverrideCustomButtonOption = 'icon';
|
285 | StandardTheme.prototype.iconOverridePrefix = 'fc-icon-';
|
286 |
|
287 | function compileViewDefs(defaultConfigs, overrideConfigs) {
|
288 | let hash = {};
|
289 | let viewType;
|
290 | for (viewType in defaultConfigs) {
|
291 | ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);
|
292 | }
|
293 | for (viewType in overrideConfigs) {
|
294 | ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs);
|
295 | }
|
296 | return hash;
|
297 | }
|
298 | function ensureViewDef(viewType, hash, defaultConfigs, overrideConfigs) {
|
299 | if (hash[viewType]) {
|
300 | return hash[viewType];
|
301 | }
|
302 | let viewDef = buildViewDef(viewType, hash, defaultConfigs, overrideConfigs);
|
303 | if (viewDef) {
|
304 | hash[viewType] = viewDef;
|
305 | }
|
306 | return viewDef;
|
307 | }
|
308 | function buildViewDef(viewType, hash, defaultConfigs, overrideConfigs) {
|
309 | let defaultConfig = defaultConfigs[viewType];
|
310 | let overrideConfig = overrideConfigs[viewType];
|
311 | let queryProp = (name) => ((defaultConfig && defaultConfig[name] !== null) ? defaultConfig[name] :
|
312 | ((overrideConfig && overrideConfig[name] !== null) ? overrideConfig[name] : null));
|
313 | let theComponent = queryProp('component');
|
314 | let superType = queryProp('superType');
|
315 | let superDef = null;
|
316 | if (superType) {
|
317 | if (superType === viewType) {
|
318 | throw new Error('Can\'t have a custom view type that references itself');
|
319 | }
|
320 | superDef = ensureViewDef(superType, hash, defaultConfigs, overrideConfigs);
|
321 | }
|
322 | if (!theComponent && superDef) {
|
323 | theComponent = superDef.component;
|
324 | }
|
325 | if (!theComponent) {
|
326 | return null;
|
327 | }
|
328 | return {
|
329 | type: viewType,
|
330 | component: theComponent,
|
331 | defaults: Object.assign(Object.assign({}, (superDef ? superDef.defaults : {})), (defaultConfig ? defaultConfig.rawOptions : {})),
|
332 | overrides: Object.assign(Object.assign({}, (superDef ? superDef.overrides : {})), (overrideConfig ? overrideConfig.rawOptions : {})),
|
333 | };
|
334 | }
|
335 |
|
336 | function parseViewConfigs(inputs) {
|
337 | return mapHash(inputs, parseViewConfig);
|
338 | }
|
339 | function parseViewConfig(input) {
|
340 | let rawOptions = typeof input === 'function' ?
|
341 | { component: input } :
|
342 | input;
|
343 | let { component } = rawOptions;
|
344 | if (rawOptions.content) {
|
345 |
|
346 | component = createViewHookComponent(rawOptions);
|
347 | }
|
348 | else if (component && !(component.prototype instanceof BaseComponent)) {
|
349 |
|
350 |
|
351 | component = createViewHookComponent(Object.assign(Object.assign({}, rawOptions), { content: component }));
|
352 | }
|
353 | return {
|
354 | superType: rawOptions.type,
|
355 | component: component,
|
356 | rawOptions,
|
357 | };
|
358 | }
|
359 | function createViewHookComponent(options) {
|
360 | return (viewProps) => (createElement(ViewContextType.Consumer, null, (context) => (createElement(ContentContainer, { elTag: "div", elClasses: buildViewClassNames(context.viewSpec), renderProps: Object.assign(Object.assign({}, viewProps), { nextDayThreshold: context.options.nextDayThreshold }), generatorName: undefined, customGenerator: options.content, classNameGenerator: options.classNames, didMount: options.didMount, willUnmount: options.willUnmount }))));
|
361 | }
|
362 |
|
363 | function buildViewSpecs(defaultInputs, optionOverrides, dynamicOptionOverrides, localeDefaults) {
|
364 | let defaultConfigs = parseViewConfigs(defaultInputs);
|
365 | let overrideConfigs = parseViewConfigs(optionOverrides.views);
|
366 | let viewDefs = compileViewDefs(defaultConfigs, overrideConfigs);
|
367 | return mapHash(viewDefs, (viewDef) => buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults));
|
368 | }
|
369 | function buildViewSpec(viewDef, overrideConfigs, optionOverrides, dynamicOptionOverrides, localeDefaults) {
|
370 | let durationInput = viewDef.overrides.duration ||
|
371 | viewDef.defaults.duration ||
|
372 | dynamicOptionOverrides.duration ||
|
373 | optionOverrides.duration;
|
374 | let duration = null;
|
375 | let durationUnit = '';
|
376 | let singleUnit = '';
|
377 | let singleUnitOverrides = {};
|
378 | if (durationInput) {
|
379 | duration = createDurationCached(durationInput);
|
380 | if (duration) {
|
381 | let denom = greatestDurationDenominator(duration);
|
382 | durationUnit = denom.unit;
|
383 | if (denom.value === 1) {
|
384 | singleUnit = durationUnit;
|
385 | singleUnitOverrides = overrideConfigs[durationUnit] ? overrideConfigs[durationUnit].rawOptions : {};
|
386 | }
|
387 | }
|
388 | }
|
389 | let queryButtonText = (optionsSubset) => {
|
390 | let buttonTextMap = optionsSubset.buttonText || {};
|
391 | let buttonTextKey = viewDef.defaults.buttonTextKey;
|
392 | if (buttonTextKey != null && buttonTextMap[buttonTextKey] != null) {
|
393 | return buttonTextMap[buttonTextKey];
|
394 | }
|
395 | if (buttonTextMap[viewDef.type] != null) {
|
396 | return buttonTextMap[viewDef.type];
|
397 | }
|
398 | if (buttonTextMap[singleUnit] != null) {
|
399 | return buttonTextMap[singleUnit];
|
400 | }
|
401 | return null;
|
402 | };
|
403 | let queryButtonTitle = (optionsSubset) => {
|
404 | let buttonHints = optionsSubset.buttonHints || {};
|
405 | let buttonKey = viewDef.defaults.buttonTextKey;
|
406 | if (buttonKey != null && buttonHints[buttonKey] != null) {
|
407 | return buttonHints[buttonKey];
|
408 | }
|
409 | if (buttonHints[viewDef.type] != null) {
|
410 | return buttonHints[viewDef.type];
|
411 | }
|
412 | if (buttonHints[singleUnit] != null) {
|
413 | return buttonHints[singleUnit];
|
414 | }
|
415 | return null;
|
416 | };
|
417 | return {
|
418 | type: viewDef.type,
|
419 | component: viewDef.component,
|
420 | duration,
|
421 | durationUnit,
|
422 | singleUnit,
|
423 | optionDefaults: viewDef.defaults,
|
424 | optionOverrides: Object.assign(Object.assign({}, singleUnitOverrides), viewDef.overrides),
|
425 | buttonTextOverride: queryButtonText(dynamicOptionOverrides) ||
|
426 | queryButtonText(optionOverrides) ||
|
427 | viewDef.overrides.buttonText,
|
428 | buttonTextDefault: queryButtonText(localeDefaults) ||
|
429 | viewDef.defaults.buttonText ||
|
430 | queryButtonText(BASE_OPTION_DEFAULTS) ||
|
431 | viewDef.type,
|
432 |
|
433 | buttonTitleOverride: queryButtonTitle(dynamicOptionOverrides) ||
|
434 | queryButtonTitle(optionOverrides) ||
|
435 | viewDef.overrides.buttonHint,
|
436 | buttonTitleDefault: queryButtonTitle(localeDefaults) ||
|
437 | viewDef.defaults.buttonHint ||
|
438 | queryButtonTitle(BASE_OPTION_DEFAULTS),
|
439 |
|
440 | };
|
441 | }
|
442 |
|
443 | let durationInputMap = {};
|
444 | function createDurationCached(durationInput) {
|
445 | let json = JSON.stringify(durationInput);
|
446 | let res = durationInputMap[json];
|
447 | if (res === undefined) {
|
448 | res = createDuration(durationInput);
|
449 | durationInputMap[json] = res;
|
450 | }
|
451 | return res;
|
452 | }
|
453 |
|
454 | function reduceViewType(viewType, action) {
|
455 | switch (action.type) {
|
456 | case 'CHANGE_VIEW_TYPE':
|
457 | viewType = action.viewType;
|
458 | }
|
459 | return viewType;
|
460 | }
|
461 |
|
462 | function reduceDynamicOptionOverrides(dynamicOptionOverrides, action) {
|
463 | switch (action.type) {
|
464 | case 'SET_OPTION':
|
465 | return Object.assign(Object.assign({}, dynamicOptionOverrides), { [action.optionName]: action.rawOptionValue });
|
466 | default:
|
467 | return dynamicOptionOverrides;
|
468 | }
|
469 | }
|
470 |
|
471 | function reduceDateProfile(currentDateProfile, action, currentDate, dateProfileGenerator) {
|
472 | let dp;
|
473 | switch (action.type) {
|
474 | case 'CHANGE_VIEW_TYPE':
|
475 | return dateProfileGenerator.build(action.dateMarker || currentDate);
|
476 | case 'CHANGE_DATE':
|
477 | return dateProfileGenerator.build(action.dateMarker);
|
478 | case 'PREV':
|
479 | dp = dateProfileGenerator.buildPrev(currentDateProfile, currentDate);
|
480 | if (dp.isValid) {
|
481 | return dp;
|
482 | }
|
483 | break;
|
484 | case 'NEXT':
|
485 | dp = dateProfileGenerator.buildNext(currentDateProfile, currentDate);
|
486 | if (dp.isValid) {
|
487 | return dp;
|
488 | }
|
489 | break;
|
490 | }
|
491 | return currentDateProfile;
|
492 | }
|
493 |
|
494 | function initEventSources(calendarOptions, dateProfile, context) {
|
495 | let activeRange = dateProfile ? dateProfile.activeRange : null;
|
496 | return addSources({}, parseInitialSources(calendarOptions, context), activeRange, context);
|
497 | }
|
498 | function reduceEventSources(eventSources, action, dateProfile, context) {
|
499 | let activeRange = dateProfile ? dateProfile.activeRange : null;
|
500 | switch (action.type) {
|
501 | case 'ADD_EVENT_SOURCES':
|
502 | return addSources(eventSources, action.sources, activeRange, context);
|
503 | case 'REMOVE_EVENT_SOURCE':
|
504 | return removeSource(eventSources, action.sourceId);
|
505 | case 'PREV':
|
506 | case 'NEXT':
|
507 | case 'CHANGE_DATE':
|
508 | case 'CHANGE_VIEW_TYPE':
|
509 | if (dateProfile) {
|
510 | return fetchDirtySources(eventSources, activeRange, context);
|
511 | }
|
512 | return eventSources;
|
513 | case 'FETCH_EVENT_SOURCES':
|
514 | return fetchSourcesByIds(eventSources, action.sourceIds ?
|
515 | arrayToHash(action.sourceIds) :
|
516 | excludeStaticSources(eventSources, context), activeRange, action.isRefetch || false, context);
|
517 | case 'RECEIVE_EVENTS':
|
518 | case 'RECEIVE_EVENT_ERROR':
|
519 | return receiveResponse(eventSources, action.sourceId, action.fetchId, action.fetchRange);
|
520 | case 'REMOVE_ALL_EVENT_SOURCES':
|
521 | return {};
|
522 | default:
|
523 | return eventSources;
|
524 | }
|
525 | }
|
526 | function reduceEventSourcesNewTimeZone(eventSources, dateProfile, context) {
|
527 | let activeRange = dateProfile ? dateProfile.activeRange : null;
|
528 | return fetchSourcesByIds(eventSources, excludeStaticSources(eventSources, context), activeRange, true, context);
|
529 | }
|
530 | function computeEventSourcesLoading(eventSources) {
|
531 | for (let sourceId in eventSources) {
|
532 | if (eventSources[sourceId].isFetching) {
|
533 | return true;
|
534 | }
|
535 | }
|
536 | return false;
|
537 | }
|
538 | function addSources(eventSourceHash, sources, fetchRange, context) {
|
539 | let hash = {};
|
540 | for (let source of sources) {
|
541 | hash[source.sourceId] = source;
|
542 | }
|
543 | if (fetchRange) {
|
544 | hash = fetchDirtySources(hash, fetchRange, context);
|
545 | }
|
546 | return Object.assign(Object.assign({}, eventSourceHash), hash);
|
547 | }
|
548 | function removeSource(eventSourceHash, sourceId) {
|
549 | return filterHash(eventSourceHash, (eventSource) => eventSource.sourceId !== sourceId);
|
550 | }
|
551 | function fetchDirtySources(sourceHash, fetchRange, context) {
|
552 | return fetchSourcesByIds(sourceHash, filterHash(sourceHash, (eventSource) => isSourceDirty(eventSource, fetchRange, context)), fetchRange, false, context);
|
553 | }
|
554 | function isSourceDirty(eventSource, fetchRange, context) {
|
555 | if (!doesSourceNeedRange(eventSource, context)) {
|
556 | return !eventSource.latestFetchId;
|
557 | }
|
558 | return !context.options.lazyFetching ||
|
559 | !eventSource.fetchRange ||
|
560 | eventSource.isFetching ||
|
561 | fetchRange.start < eventSource.fetchRange.start ||
|
562 | fetchRange.end > eventSource.fetchRange.end;
|
563 | }
|
564 | function fetchSourcesByIds(prevSources, sourceIdHash, fetchRange, isRefetch, context) {
|
565 | let nextSources = {};
|
566 | for (let sourceId in prevSources) {
|
567 | let source = prevSources[sourceId];
|
568 | if (sourceIdHash[sourceId]) {
|
569 | nextSources[sourceId] = fetchSource(source, fetchRange, isRefetch, context);
|
570 | }
|
571 | else {
|
572 | nextSources[sourceId] = source;
|
573 | }
|
574 | }
|
575 | return nextSources;
|
576 | }
|
577 | function fetchSource(eventSource, fetchRange, isRefetch, context) {
|
578 | let { options, calendarApi } = context;
|
579 | let sourceDef = context.pluginHooks.eventSourceDefs[eventSource.sourceDefId];
|
580 | let fetchId = guid();
|
581 | sourceDef.fetch({
|
582 | eventSource,
|
583 | range: fetchRange,
|
584 | isRefetch,
|
585 | context,
|
586 | }, (res) => {
|
587 | let { rawEvents } = res;
|
588 | if (options.eventSourceSuccess) {
|
589 | rawEvents = options.eventSourceSuccess.call(calendarApi, rawEvents, res.response) || rawEvents;
|
590 | }
|
591 | if (eventSource.success) {
|
592 | rawEvents = eventSource.success.call(calendarApi, rawEvents, res.response) || rawEvents;
|
593 | }
|
594 | context.dispatch({
|
595 | type: 'RECEIVE_EVENTS',
|
596 | sourceId: eventSource.sourceId,
|
597 | fetchId,
|
598 | fetchRange,
|
599 | rawEvents,
|
600 | });
|
601 | }, (error) => {
|
602 | let errorHandled = false;
|
603 | if (options.eventSourceFailure) {
|
604 | options.eventSourceFailure.call(calendarApi, error);
|
605 | errorHandled = true;
|
606 | }
|
607 | if (eventSource.failure) {
|
608 | eventSource.failure(error);
|
609 | errorHandled = true;
|
610 | }
|
611 | if (!errorHandled) {
|
612 | console.warn(error.message, error);
|
613 | }
|
614 | context.dispatch({
|
615 | type: 'RECEIVE_EVENT_ERROR',
|
616 | sourceId: eventSource.sourceId,
|
617 | fetchId,
|
618 | fetchRange,
|
619 | error,
|
620 | });
|
621 | });
|
622 | return Object.assign(Object.assign({}, eventSource), { isFetching: true, latestFetchId: fetchId });
|
623 | }
|
624 | function receiveResponse(sourceHash, sourceId, fetchId, fetchRange) {
|
625 | let eventSource = sourceHash[sourceId];
|
626 | if (eventSource &&
|
627 | fetchId === eventSource.latestFetchId) {
|
628 | return Object.assign(Object.assign({}, sourceHash), { [sourceId]: Object.assign(Object.assign({}, eventSource), { isFetching: false, fetchRange }) });
|
629 | }
|
630 | return sourceHash;
|
631 | }
|
632 | function excludeStaticSources(eventSources, context) {
|
633 | return filterHash(eventSources, (eventSource) => doesSourceNeedRange(eventSource, context));
|
634 | }
|
635 | function parseInitialSources(rawOptions, context) {
|
636 | let refiners = buildEventSourceRefiners(context);
|
637 | let rawSources = [].concat(rawOptions.eventSources || []);
|
638 | let sources = [];
|
639 | if (rawOptions.initialEvents) {
|
640 | rawSources.unshift(rawOptions.initialEvents);
|
641 | }
|
642 | if (rawOptions.events) {
|
643 | rawSources.unshift(rawOptions.events);
|
644 | }
|
645 | for (let rawSource of rawSources) {
|
646 | let source = parseEventSource(rawSource, context, refiners);
|
647 | if (source) {
|
648 | sources.push(source);
|
649 | }
|
650 | }
|
651 | return sources;
|
652 | }
|
653 | function doesSourceNeedRange(eventSource, context) {
|
654 | let defs = context.pluginHooks.eventSourceDefs;
|
655 | return !defs[eventSource.sourceDefId].ignoreRange;
|
656 | }
|
657 |
|
658 | function reduceDateSelection(currentSelection, action) {
|
659 | switch (action.type) {
|
660 | case 'UNSELECT_DATES':
|
661 | return null;
|
662 | case 'SELECT_DATES':
|
663 | return action.selection;
|
664 | default:
|
665 | return currentSelection;
|
666 | }
|
667 | }
|
668 |
|
669 | function reduceSelectedEvent(currentInstanceId, action) {
|
670 | switch (action.type) {
|
671 | case 'UNSELECT_EVENT':
|
672 | return '';
|
673 | case 'SELECT_EVENT':
|
674 | return action.eventInstanceId;
|
675 | default:
|
676 | return currentInstanceId;
|
677 | }
|
678 | }
|
679 |
|
680 | function reduceEventDrag(currentDrag, action) {
|
681 | let newDrag;
|
682 | switch (action.type) {
|
683 | case 'UNSET_EVENT_DRAG':
|
684 | return null;
|
685 | case 'SET_EVENT_DRAG':
|
686 | newDrag = action.state;
|
687 | return {
|
688 | affectedEvents: newDrag.affectedEvents,
|
689 | mutatedEvents: newDrag.mutatedEvents,
|
690 | isEvent: newDrag.isEvent,
|
691 | };
|
692 | default:
|
693 | return currentDrag;
|
694 | }
|
695 | }
|
696 |
|
697 | function reduceEventResize(currentResize, action) {
|
698 | let newResize;
|
699 | switch (action.type) {
|
700 | case 'UNSET_EVENT_RESIZE':
|
701 | return null;
|
702 | case 'SET_EVENT_RESIZE':
|
703 | newResize = action.state;
|
704 | return {
|
705 | affectedEvents: newResize.affectedEvents,
|
706 | mutatedEvents: newResize.mutatedEvents,
|
707 | isEvent: newResize.isEvent,
|
708 | };
|
709 | default:
|
710 | return currentResize;
|
711 | }
|
712 | }
|
713 |
|
714 | function parseToolbars(calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {
|
715 | let header = calendarOptions.headerToolbar ? parseToolbar(calendarOptions.headerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;
|
716 | let footer = calendarOptions.footerToolbar ? parseToolbar(calendarOptions.footerToolbar, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) : null;
|
717 | return { header, footer };
|
718 | }
|
719 | function parseToolbar(sectionStrHash, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi) {
|
720 | let sectionWidgets = {};
|
721 | let viewsWithButtons = [];
|
722 | let hasTitle = false;
|
723 | for (let sectionName in sectionStrHash) {
|
724 | let sectionStr = sectionStrHash[sectionName];
|
725 | let sectionRes = parseSection(sectionStr, calendarOptions, calendarOptionOverrides, theme, viewSpecs, calendarApi);
|
726 | sectionWidgets[sectionName] = sectionRes.widgets;
|
727 | viewsWithButtons.push(...sectionRes.viewsWithButtons);
|
728 | hasTitle = hasTitle || sectionRes.hasTitle;
|
729 | }
|
730 | return { sectionWidgets, viewsWithButtons, hasTitle };
|
731 | }
|
732 |
|
733 |
|
734 |
|
735 | function parseSection(sectionStr, calendarOptions, // defaults+overrides, then refined
|
736 | calendarOptionOverrides, // overrides only!, unrefined :(
|
737 | theme, viewSpecs, calendarApi) {
|
738 | let isRtl = calendarOptions.direction === 'rtl';
|
739 | let calendarCustomButtons = calendarOptions.customButtons || {};
|
740 | let calendarButtonTextOverrides = calendarOptionOverrides.buttonText || {};
|
741 | let calendarButtonText = calendarOptions.buttonText || {};
|
742 | let calendarButtonHintOverrides = calendarOptionOverrides.buttonHints || {};
|
743 | let calendarButtonHints = calendarOptions.buttonHints || {};
|
744 | let sectionSubstrs = sectionStr ? sectionStr.split(' ') : [];
|
745 | let viewsWithButtons = [];
|
746 | let hasTitle = false;
|
747 | let widgets = sectionSubstrs.map((buttonGroupStr) => (buttonGroupStr.split(',').map((buttonName) => {
|
748 | if (buttonName === 'title') {
|
749 | hasTitle = true;
|
750 | return { buttonName };
|
751 | }
|
752 | let customButtonProps;
|
753 | let viewSpec;
|
754 | let buttonClick;
|
755 | let buttonIcon;
|
756 | let buttonText;
|
757 | let buttonHint;
|
758 |
|
759 | if ((customButtonProps = calendarCustomButtons[buttonName])) {
|
760 | buttonClick = (ev) => {
|
761 | if (customButtonProps.click) {
|
762 | customButtonProps.click.call(ev.target, ev, ev.target);
|
763 | }
|
764 | };
|
765 | (buttonIcon = theme.getCustomButtonIconClass(customButtonProps)) ||
|
766 | (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
|
767 | (buttonText = customButtonProps.text);
|
768 | buttonHint = customButtonProps.hint || customButtonProps.text;
|
769 | }
|
770 | else if ((viewSpec = viewSpecs[buttonName])) {
|
771 | viewsWithButtons.push(buttonName);
|
772 | buttonClick = () => {
|
773 | calendarApi.changeView(buttonName);
|
774 | };
|
775 | (buttonText = viewSpec.buttonTextOverride) ||
|
776 | (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
|
777 | (buttonText = viewSpec.buttonTextDefault);
|
778 | let textFallback = viewSpec.buttonTextOverride ||
|
779 | viewSpec.buttonTextDefault;
|
780 | buttonHint = formatWithOrdinals(viewSpec.buttonTitleOverride ||
|
781 | viewSpec.buttonTitleDefault ||
|
782 | calendarOptions.viewHint, [textFallback, buttonName],
|
783 | textFallback);
|
784 | }
|
785 | else if (calendarApi[buttonName]) {
|
786 | buttonClick = () => {
|
787 | calendarApi[buttonName]();
|
788 | };
|
789 | (buttonText = calendarButtonTextOverrides[buttonName]) ||
|
790 | (buttonIcon = theme.getIconClass(buttonName, isRtl)) ||
|
791 | (buttonText = calendarButtonText[buttonName]);
|
792 | if (buttonName === 'prevYear' || buttonName === 'nextYear') {
|
793 | let prevOrNext = buttonName === 'prevYear' ? 'prev' : 'next';
|
794 | buttonHint = formatWithOrdinals(calendarButtonHintOverrides[prevOrNext] ||
|
795 | calendarButtonHints[prevOrNext], [
|
796 | calendarButtonText.year || 'year',
|
797 | 'year',
|
798 | ], calendarButtonText[buttonName]);
|
799 | }
|
800 | else {
|
801 | buttonHint = (navUnit) => formatWithOrdinals(calendarButtonHintOverrides[buttonName] ||
|
802 | calendarButtonHints[buttonName], [
|
803 | calendarButtonText[navUnit] || navUnit,
|
804 | navUnit,
|
805 | ], calendarButtonText[buttonName]);
|
806 | }
|
807 | }
|
808 | return { buttonName, buttonClick, buttonIcon, buttonText, buttonHint };
|
809 | })));
|
810 | return { widgets, viewsWithButtons, hasTitle };
|
811 | }
|
812 |
|
813 |
|
814 | class ViewImpl {
|
815 | constructor(type, getCurrentData, dateEnv) {
|
816 | this.type = type;
|
817 | this.getCurrentData = getCurrentData;
|
818 | this.dateEnv = dateEnv;
|
819 | }
|
820 | get calendar() {
|
821 | return this.getCurrentData().calendarApi;
|
822 | }
|
823 | get title() {
|
824 | return this.getCurrentData().viewTitle;
|
825 | }
|
826 | get activeStart() {
|
827 | return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.start);
|
828 | }
|
829 | get activeEnd() {
|
830 | return this.dateEnv.toDate(this.getCurrentData().dateProfile.activeRange.end);
|
831 | }
|
832 | get currentStart() {
|
833 | return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.start);
|
834 | }
|
835 | get currentEnd() {
|
836 | return this.dateEnv.toDate(this.getCurrentData().dateProfile.currentRange.end);
|
837 | }
|
838 | getOption(name) {
|
839 | return this.getCurrentData().options[name];
|
840 | }
|
841 | }
|
842 |
|
843 | let eventSourceDef$2 = {
|
844 | ignoreRange: true,
|
845 | parseMeta(refined) {
|
846 | if (Array.isArray(refined.events)) {
|
847 | return refined.events;
|
848 | }
|
849 | return null;
|
850 | },
|
851 | fetch(arg, successCallback) {
|
852 | successCallback({
|
853 | rawEvents: arg.eventSource.meta,
|
854 | });
|
855 | },
|
856 | };
|
857 | const arrayEventSourcePlugin = createPlugin({
|
858 | name: 'array-event-source',
|
859 | eventSourceDefs: [eventSourceDef$2],
|
860 | });
|
861 |
|
862 | let eventSourceDef$1 = {
|
863 | parseMeta(refined) {
|
864 | if (typeof refined.events === 'function') {
|
865 | return refined.events;
|
866 | }
|
867 | return null;
|
868 | },
|
869 | fetch(arg, successCallback, errorCallback) {
|
870 | const { dateEnv } = arg.context;
|
871 | const func = arg.eventSource.meta;
|
872 | unpromisify(func.bind(null, buildRangeApiWithTimeZone(arg.range, dateEnv)), (rawEvents) => successCallback({ rawEvents }), errorCallback);
|
873 | },
|
874 | };
|
875 | const funcEventSourcePlugin = createPlugin({
|
876 | name: 'func-event-source',
|
877 | eventSourceDefs: [eventSourceDef$1],
|
878 | });
|
879 |
|
880 | const JSON_FEED_EVENT_SOURCE_REFINERS = {
|
881 | method: String,
|
882 | extraParams: identity,
|
883 | startParam: String,
|
884 | endParam: String,
|
885 | timeZoneParam: String,
|
886 | };
|
887 |
|
888 | let eventSourceDef = {
|
889 | parseMeta(refined) {
|
890 | if (refined.url && (refined.format === 'json' || !refined.format)) {
|
891 | return {
|
892 | url: refined.url,
|
893 | format: 'json',
|
894 | method: (refined.method || 'GET').toUpperCase(),
|
895 | extraParams: refined.extraParams,
|
896 | startParam: refined.startParam,
|
897 | endParam: refined.endParam,
|
898 | timeZoneParam: refined.timeZoneParam,
|
899 | };
|
900 | }
|
901 | return null;
|
902 | },
|
903 | fetch(arg, successCallback, errorCallback) {
|
904 | const { meta } = arg.eventSource;
|
905 | const requestParams = buildRequestParams(meta, arg.range, arg.context);
|
906 | requestJson(meta.method, meta.url, requestParams).then(([rawEvents, response]) => {
|
907 | successCallback({ rawEvents, response });
|
908 | }, errorCallback);
|
909 | },
|
910 | };
|
911 | const jsonFeedEventSourcePlugin = createPlugin({
|
912 | name: 'json-event-source',
|
913 | eventSourceRefiners: JSON_FEED_EVENT_SOURCE_REFINERS,
|
914 | eventSourceDefs: [eventSourceDef],
|
915 | });
|
916 | function buildRequestParams(meta, range, context) {
|
917 | let { dateEnv, options } = context;
|
918 | let startParam;
|
919 | let endParam;
|
920 | let timeZoneParam;
|
921 | let customRequestParams;
|
922 | let params = {};
|
923 | startParam = meta.startParam;
|
924 | if (startParam == null) {
|
925 | startParam = options.startParam;
|
926 | }
|
927 | endParam = meta.endParam;
|
928 | if (endParam == null) {
|
929 | endParam = options.endParam;
|
930 | }
|
931 | timeZoneParam = meta.timeZoneParam;
|
932 | if (timeZoneParam == null) {
|
933 | timeZoneParam = options.timeZoneParam;
|
934 | }
|
935 |
|
936 | if (typeof meta.extraParams === 'function') {
|
937 |
|
938 | customRequestParams = meta.extraParams();
|
939 | }
|
940 | else {
|
941 |
|
942 | customRequestParams = meta.extraParams || {};
|
943 | }
|
944 | Object.assign(params, customRequestParams);
|
945 | params[startParam] = dateEnv.formatIso(range.start);
|
946 | params[endParam] = dateEnv.formatIso(range.end);
|
947 | if (dateEnv.timeZone !== 'local') {
|
948 | params[timeZoneParam] = dateEnv.timeZone;
|
949 | }
|
950 | return params;
|
951 | }
|
952 |
|
953 | const SIMPLE_RECURRING_REFINERS = {
|
954 | daysOfWeek: identity,
|
955 | startTime: createDuration,
|
956 | endTime: createDuration,
|
957 | duration: createDuration,
|
958 | startRecur: identity,
|
959 | endRecur: identity,
|
960 | };
|
961 |
|
962 | let recurring = {
|
963 | parse(refined, dateEnv) {
|
964 | if (refined.daysOfWeek || refined.startTime || refined.endTime || refined.startRecur || refined.endRecur) {
|
965 | let recurringData = {
|
966 | daysOfWeek: refined.daysOfWeek || null,
|
967 | startTime: refined.startTime || null,
|
968 | endTime: refined.endTime || null,
|
969 | startRecur: refined.startRecur ? dateEnv.createMarker(refined.startRecur) : null,
|
970 | endRecur: refined.endRecur ? dateEnv.createMarker(refined.endRecur) : null,
|
971 | };
|
972 | let duration;
|
973 | if (refined.duration) {
|
974 | duration = refined.duration;
|
975 | }
|
976 | if (!duration && refined.startTime && refined.endTime) {
|
977 | duration = subtractDurations(refined.endTime, refined.startTime);
|
978 | }
|
979 | return {
|
980 | allDayGuess: Boolean(!refined.startTime && !refined.endTime),
|
981 | duration,
|
982 | typeData: recurringData,
|
983 | };
|
984 | }
|
985 | return null;
|
986 | },
|
987 | expand(typeData, framingRange, dateEnv) {
|
988 | let clippedFramingRange = intersectRanges(framingRange, { start: typeData.startRecur, end: typeData.endRecur });
|
989 | if (clippedFramingRange) {
|
990 | return expandRanges(typeData.daysOfWeek, typeData.startTime, clippedFramingRange, dateEnv);
|
991 | }
|
992 | return [];
|
993 | },
|
994 | };
|
995 | const simpleRecurringEventsPlugin = createPlugin({
|
996 | name: 'simple-recurring-event',
|
997 | recurringTypes: [recurring],
|
998 | eventRefiners: SIMPLE_RECURRING_REFINERS,
|
999 | });
|
1000 | function expandRanges(daysOfWeek, startTime, framingRange, dateEnv) {
|
1001 | let dowHash = daysOfWeek ? arrayToHash(daysOfWeek) : null;
|
1002 | let dayMarker = startOfDay(framingRange.start);
|
1003 | let endMarker = framingRange.end;
|
1004 | let instanceStarts = [];
|
1005 | while (dayMarker < endMarker) {
|
1006 | let instanceStart;
|
1007 |
|
1008 | if (!dowHash || dowHash[dayMarker.getUTCDay()]) {
|
1009 | if (startTime) {
|
1010 | instanceStart = dateEnv.add(dayMarker, startTime);
|
1011 | }
|
1012 | else {
|
1013 | instanceStart = dayMarker;
|
1014 | }
|
1015 | instanceStarts.push(instanceStart);
|
1016 | }
|
1017 | dayMarker = addDays(dayMarker, 1);
|
1018 | }
|
1019 | return instanceStarts;
|
1020 | }
|
1021 |
|
1022 | const changeHandlerPlugin = createPlugin({
|
1023 | name: 'change-handler',
|
1024 | optionChangeHandlers: {
|
1025 | events(events, context) {
|
1026 | handleEventSources([events], context);
|
1027 | },
|
1028 | eventSources: handleEventSources,
|
1029 | },
|
1030 | });
|
1031 |
|
1032 |
|
1033 |
|
1034 | function handleEventSources(inputs, context) {
|
1035 | let unfoundSources = hashValuesToArray(context.getCurrentData().eventSources);
|
1036 | if (unfoundSources.length === 1 &&
|
1037 | inputs.length === 1 &&
|
1038 | Array.isArray(unfoundSources[0]._raw) &&
|
1039 | Array.isArray(inputs[0])) {
|
1040 | context.dispatch({
|
1041 | type: 'RESET_RAW_EVENTS',
|
1042 | sourceId: unfoundSources[0].sourceId,
|
1043 | rawEvents: inputs[0],
|
1044 | });
|
1045 | return;
|
1046 | }
|
1047 | let newInputs = [];
|
1048 | for (let input of inputs) {
|
1049 | let inputFound = false;
|
1050 | for (let i = 0; i < unfoundSources.length; i += 1) {
|
1051 | if (unfoundSources[i]._raw === input) {
|
1052 | unfoundSources.splice(i, 1);
|
1053 | inputFound = true;
|
1054 | break;
|
1055 | }
|
1056 | }
|
1057 | if (!inputFound) {
|
1058 | newInputs.push(input);
|
1059 | }
|
1060 | }
|
1061 | for (let unfoundSource of unfoundSources) {
|
1062 | context.dispatch({
|
1063 | type: 'REMOVE_EVENT_SOURCE',
|
1064 | sourceId: unfoundSource.sourceId,
|
1065 | });
|
1066 | }
|
1067 | for (let newInput of newInputs) {
|
1068 | context.calendarApi.addEventSource(newInput);
|
1069 | }
|
1070 | }
|
1071 |
|
1072 | function handleDateProfile(dateProfile, context) {
|
1073 | context.emitter.trigger('datesSet', Object.assign(Object.assign({}, buildRangeApiWithTimeZone(dateProfile.activeRange, context.dateEnv)), { view: context.viewApi }));
|
1074 | }
|
1075 |
|
1076 | function handleEventStore(eventStore, context) {
|
1077 | let { emitter } = context;
|
1078 | if (emitter.hasHandlers('eventsSet')) {
|
1079 | emitter.trigger('eventsSet', buildEventApis(eventStore, context));
|
1080 | }
|
1081 | }
|
1082 |
|
1083 |
|
1084 |
|
1085 |
|
1086 |
|
1087 | const globalPlugins = [
|
1088 | arrayEventSourcePlugin,
|
1089 | funcEventSourcePlugin,
|
1090 | jsonFeedEventSourcePlugin,
|
1091 | simpleRecurringEventsPlugin,
|
1092 | changeHandlerPlugin,
|
1093 | createPlugin({
|
1094 | name: 'misc',
|
1095 | isLoadingFuncs: [
|
1096 | (state) => computeEventSourcesLoading(state.eventSources),
|
1097 | ],
|
1098 | propSetHandlers: {
|
1099 | dateProfile: handleDateProfile,
|
1100 | eventStore: handleEventStore,
|
1101 | },
|
1102 | }),
|
1103 | ];
|
1104 |
|
1105 | class TaskRunner {
|
1106 | constructor(runTaskOption, drainedOption) {
|
1107 | this.runTaskOption = runTaskOption;
|
1108 | this.drainedOption = drainedOption;
|
1109 | this.queue = [];
|
1110 | this.delayedRunner = new DelayedRunner(this.drain.bind(this));
|
1111 | }
|
1112 | request(task, delay) {
|
1113 | this.queue.push(task);
|
1114 | this.delayedRunner.request(delay);
|
1115 | }
|
1116 | pause(scope) {
|
1117 | this.delayedRunner.pause(scope);
|
1118 | }
|
1119 | resume(scope, force) {
|
1120 | this.delayedRunner.resume(scope, force);
|
1121 | }
|
1122 | drain() {
|
1123 | let { queue } = this;
|
1124 | while (queue.length) {
|
1125 | let completedTasks = [];
|
1126 | let task;
|
1127 | while ((task = queue.shift())) {
|
1128 | this.runTask(task);
|
1129 | completedTasks.push(task);
|
1130 | }
|
1131 | this.drained(completedTasks);
|
1132 | }
|
1133 | }
|
1134 | runTask(task) {
|
1135 | if (this.runTaskOption) {
|
1136 | this.runTaskOption(task);
|
1137 | }
|
1138 | }
|
1139 | drained(completedTasks) {
|
1140 | if (this.drainedOption) {
|
1141 | this.drainedOption(completedTasks);
|
1142 | }
|
1143 | }
|
1144 | }
|
1145 |
|
1146 |
|
1147 | function buildTitle(dateProfile, viewOptions, dateEnv) {
|
1148 | let range;
|
1149 |
|
1150 | if (/^(year|month)$/.test(dateProfile.currentRangeUnit)) {
|
1151 | range = dateProfile.currentRange;
|
1152 | }
|
1153 | else {
|
1154 | range = dateProfile.activeRange;
|
1155 | }
|
1156 | return dateEnv.formatRange(range.start, range.end, createFormatter(viewOptions.titleFormat || buildTitleFormat(dateProfile)), {
|
1157 | isEndExclusive: dateProfile.isRangeAllDay,
|
1158 | defaultSeparator: viewOptions.titleRangeSeparator,
|
1159 | });
|
1160 | }
|
1161 |
|
1162 |
|
1163 | function buildTitleFormat(dateProfile) {
|
1164 | let { currentRangeUnit } = dateProfile;
|
1165 | if (currentRangeUnit === 'year') {
|
1166 | return { year: 'numeric' };
|
1167 | }
|
1168 | if (currentRangeUnit === 'month') {
|
1169 | return { year: 'numeric', month: 'long' };
|
1170 | }
|
1171 | let days = diffWholeDays(dateProfile.currentRange.start, dateProfile.currentRange.end);
|
1172 | if (days !== null && days > 1) {
|
1173 |
|
1174 | return { year: 'numeric', month: 'short', day: 'numeric' };
|
1175 | }
|
1176 |
|
1177 | return { year: 'numeric', month: 'long', day: 'numeric' };
|
1178 | }
|
1179 |
|
1180 |
|
1181 |
|
1182 | class CalendarDataManager {
|
1183 | constructor(props) {
|
1184 | this.computeCurrentViewData = memoize(this._computeCurrentViewData);
|
1185 | this.organizeRawLocales = memoize(organizeRawLocales);
|
1186 | this.buildLocale = memoize(buildLocale);
|
1187 | this.buildPluginHooks = buildBuildPluginHooks();
|
1188 | this.buildDateEnv = memoize(buildDateEnv$1);
|
1189 | this.buildTheme = memoize(buildTheme);
|
1190 | this.parseToolbars = memoize(parseToolbars);
|
1191 | this.buildViewSpecs = memoize(buildViewSpecs);
|
1192 | this.buildDateProfileGenerator = memoizeObjArg(buildDateProfileGenerator);
|
1193 | this.buildViewApi = memoize(buildViewApi);
|
1194 | this.buildViewUiProps = memoizeObjArg(buildViewUiProps);
|
1195 | this.buildEventUiBySource = memoize(buildEventUiBySource, isPropsEqual);
|
1196 | this.buildEventUiBases = memoize(buildEventUiBases);
|
1197 | this.parseContextBusinessHours = memoizeObjArg(parseContextBusinessHours);
|
1198 | this.buildTitle = memoize(buildTitle);
|
1199 | this.emitter = new Emitter();
|
1200 | this.actionRunner = new TaskRunner(this._handleAction.bind(this), this.updateData.bind(this));
|
1201 | this.currentCalendarOptionsInput = {};
|
1202 | this.currentCalendarOptionsRefined = {};
|
1203 | this.currentViewOptionsInput = {};
|
1204 | this.currentViewOptionsRefined = {};
|
1205 | this.currentCalendarOptionsRefiners = {};
|
1206 | this.optionsForRefining = [];
|
1207 | this.optionsForHandling = [];
|
1208 | this.getCurrentData = () => this.data;
|
1209 | this.dispatch = (action) => {
|
1210 | this.actionRunner.request(action);
|
1211 | };
|
1212 | this.props = props;
|
1213 | this.actionRunner.pause();
|
1214 | let dynamicOptionOverrides = {};
|
1215 | let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
|
1216 | let currentViewType = optionsData.calendarOptions.initialView || optionsData.pluginHooks.initialView;
|
1217 | let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
|
1218 |
|
1219 |
|
1220 | props.calendarApi.currentDataManager = this;
|
1221 | this.emitter.setThisContext(props.calendarApi);
|
1222 | this.emitter.setOptions(currentViewData.options);
|
1223 | let currentDate = getInitialDate(optionsData.calendarOptions, optionsData.dateEnv);
|
1224 | let dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
|
1225 | if (!rangeContainsMarker(dateProfile.activeRange, currentDate)) {
|
1226 | currentDate = dateProfile.currentRange.start;
|
1227 | }
|
1228 | let calendarContext = {
|
1229 | dateEnv: optionsData.dateEnv,
|
1230 | options: optionsData.calendarOptions,
|
1231 | pluginHooks: optionsData.pluginHooks,
|
1232 | calendarApi: props.calendarApi,
|
1233 | dispatch: this.dispatch,
|
1234 | emitter: this.emitter,
|
1235 | getCurrentData: this.getCurrentData,
|
1236 | };
|
1237 |
|
1238 | for (let callback of optionsData.pluginHooks.contextInit) {
|
1239 | callback(calendarContext);
|
1240 | }
|
1241 |
|
1242 | let eventSources = initEventSources(optionsData.calendarOptions, dateProfile, calendarContext);
|
1243 | let initialState = {
|
1244 | dynamicOptionOverrides,
|
1245 | currentViewType,
|
1246 | currentDate,
|
1247 | dateProfile,
|
1248 | businessHours: this.parseContextBusinessHours(calendarContext),
|
1249 | eventSources,
|
1250 | eventUiBases: {},
|
1251 | eventStore: createEmptyEventStore(),
|
1252 | renderableEventStore: createEmptyEventStore(),
|
1253 | dateSelection: null,
|
1254 | eventSelection: '',
|
1255 | eventDrag: null,
|
1256 | eventResize: null,
|
1257 | selectionConfig: this.buildViewUiProps(calendarContext).selectionConfig,
|
1258 | };
|
1259 | let contextAndState = Object.assign(Object.assign({}, calendarContext), initialState);
|
1260 | for (let reducer of optionsData.pluginHooks.reducers) {
|
1261 | Object.assign(initialState, reducer(null, null, contextAndState));
|
1262 | }
|
1263 | if (computeIsLoading(initialState, calendarContext)) {
|
1264 | this.emitter.trigger('loading', true);
|
1265 | }
|
1266 | this.state = initialState;
|
1267 | this.updateData();
|
1268 | this.actionRunner.resume();
|
1269 | }
|
1270 | resetOptions(optionOverrides, changedOptionNames) {
|
1271 | let { props } = this;
|
1272 | if (changedOptionNames === undefined) {
|
1273 | props.optionOverrides = optionOverrides;
|
1274 | }
|
1275 | else {
|
1276 | props.optionOverrides = Object.assign(Object.assign({}, (props.optionOverrides || {})), optionOverrides);
|
1277 | this.optionsForRefining.push(...changedOptionNames);
|
1278 | }
|
1279 | if (changedOptionNames === undefined || changedOptionNames.length) {
|
1280 | this.actionRunner.request({
|
1281 | type: 'NOTHING',
|
1282 | });
|
1283 | }
|
1284 | }
|
1285 | _handleAction(action) {
|
1286 | let { props, state, emitter } = this;
|
1287 | let dynamicOptionOverrides = reduceDynamicOptionOverrides(state.dynamicOptionOverrides, action);
|
1288 | let optionsData = this.computeOptionsData(props.optionOverrides, dynamicOptionOverrides, props.calendarApi);
|
1289 | let currentViewType = reduceViewType(state.currentViewType, action);
|
1290 | let currentViewData = this.computeCurrentViewData(currentViewType, optionsData, props.optionOverrides, dynamicOptionOverrides);
|
1291 |
|
1292 |
|
1293 | props.calendarApi.currentDataManager = this;
|
1294 | emitter.setThisContext(props.calendarApi);
|
1295 | emitter.setOptions(currentViewData.options);
|
1296 | let calendarContext = {
|
1297 | dateEnv: optionsData.dateEnv,
|
1298 | options: optionsData.calendarOptions,
|
1299 | pluginHooks: optionsData.pluginHooks,
|
1300 | calendarApi: props.calendarApi,
|
1301 | dispatch: this.dispatch,
|
1302 | emitter,
|
1303 | getCurrentData: this.getCurrentData,
|
1304 | };
|
1305 | let { currentDate, dateProfile } = state;
|
1306 | if (this.data && this.data.dateProfileGenerator !== currentViewData.dateProfileGenerator) {
|
1307 | dateProfile = currentViewData.dateProfileGenerator.build(currentDate);
|
1308 | }
|
1309 | currentDate = reduceCurrentDate(currentDate, action);
|
1310 | dateProfile = reduceDateProfile(dateProfile, action, currentDate, currentViewData.dateProfileGenerator);
|
1311 | if (action.type === 'PREV' ||
|
1312 | action.type === 'NEXT' ||
|
1313 | !rangeContainsMarker(dateProfile.currentRange, currentDate)) {
|
1314 | currentDate = dateProfile.currentRange.start;
|
1315 | }
|
1316 | let eventSources = reduceEventSources(state.eventSources, action, dateProfile, calendarContext);
|
1317 | let eventStore = reduceEventStore(state.eventStore, action, eventSources, dateProfile, calendarContext);
|
1318 | let isEventsLoading = computeEventSourcesLoading(eventSources);
|
1319 | let renderableEventStore = (isEventsLoading && !currentViewData.options.progressiveEventRendering) ?
|
1320 | (state.renderableEventStore || eventStore) :
|
1321 | eventStore;
|
1322 | let { eventUiSingleBase, selectionConfig } = this.buildViewUiProps(calendarContext);
|
1323 | let eventUiBySource = this.buildEventUiBySource(eventSources);
|
1324 | let eventUiBases = this.buildEventUiBases(renderableEventStore.defs, eventUiSingleBase, eventUiBySource);
|
1325 | let newState = {
|
1326 | dynamicOptionOverrides,
|
1327 | currentViewType,
|
1328 | currentDate,
|
1329 | dateProfile,
|
1330 | eventSources,
|
1331 | eventStore,
|
1332 | renderableEventStore,
|
1333 | selectionConfig,
|
1334 | eventUiBases,
|
1335 | businessHours: this.parseContextBusinessHours(calendarContext),
|
1336 | dateSelection: reduceDateSelection(state.dateSelection, action),
|
1337 | eventSelection: reduceSelectedEvent(state.eventSelection, action),
|
1338 | eventDrag: reduceEventDrag(state.eventDrag, action),
|
1339 | eventResize: reduceEventResize(state.eventResize, action),
|
1340 | };
|
1341 | let contextAndState = Object.assign(Object.assign({}, calendarContext), newState);
|
1342 | for (let reducer of optionsData.pluginHooks.reducers) {
|
1343 | Object.assign(newState, reducer(state, action, contextAndState));
|
1344 | }
|
1345 | let wasLoading = computeIsLoading(state, calendarContext);
|
1346 | let isLoading = computeIsLoading(newState, calendarContext);
|
1347 |
|
1348 | if (!wasLoading && isLoading) {
|
1349 | emitter.trigger('loading', true);
|
1350 | }
|
1351 | else if (wasLoading && !isLoading) {
|
1352 | emitter.trigger('loading', false);
|
1353 | }
|
1354 | this.state = newState;
|
1355 | if (props.onAction) {
|
1356 | props.onAction(action);
|
1357 | }
|
1358 | }
|
1359 | updateData() {
|
1360 | let { props, state } = this;
|
1361 | let oldData = this.data;
|
1362 | let optionsData = this.computeOptionsData(props.optionOverrides, state.dynamicOptionOverrides, props.calendarApi);
|
1363 | let currentViewData = this.computeCurrentViewData(state.currentViewType, optionsData, props.optionOverrides, state.dynamicOptionOverrides);
|
1364 | let data = this.data = Object.assign(Object.assign(Object.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);
|
1365 | let changeHandlers = optionsData.pluginHooks.optionChangeHandlers;
|
1366 | let oldCalendarOptions = oldData && oldData.calendarOptions;
|
1367 | let newCalendarOptions = optionsData.calendarOptions;
|
1368 | if (oldCalendarOptions && oldCalendarOptions !== newCalendarOptions) {
|
1369 | if (oldCalendarOptions.timeZone !== newCalendarOptions.timeZone) {
|
1370 |
|
1371 | state.eventSources = data.eventSources = reduceEventSourcesNewTimeZone(data.eventSources, state.dateProfile, data);
|
1372 | state.eventStore = data.eventStore = rezoneEventStoreDates(data.eventStore, oldData.dateEnv, data.dateEnv);
|
1373 | state.renderableEventStore = data.renderableEventStore = rezoneEventStoreDates(data.renderableEventStore, oldData.dateEnv, data.dateEnv);
|
1374 | }
|
1375 | for (let optionName in changeHandlers) {
|
1376 | if (this.optionsForHandling.indexOf(optionName) !== -1 ||
|
1377 | oldCalendarOptions[optionName] !== newCalendarOptions[optionName]) {
|
1378 | changeHandlers[optionName](newCalendarOptions[optionName], data);
|
1379 | }
|
1380 | }
|
1381 | }
|
1382 | this.optionsForHandling = [];
|
1383 | if (props.onData) {
|
1384 | props.onData(data);
|
1385 | }
|
1386 | }
|
1387 | computeOptionsData(optionOverrides, dynamicOptionOverrides, calendarApi) {
|
1388 |
|
1389 | if (!this.optionsForRefining.length &&
|
1390 | optionOverrides === this.stableOptionOverrides &&
|
1391 | dynamicOptionOverrides === this.stableDynamicOptionOverrides) {
|
1392 | return this.stableCalendarOptionsData;
|
1393 | }
|
1394 | let { refinedOptions, pluginHooks, localeDefaults, availableLocaleData, extra, } = this.processRawCalendarOptions(optionOverrides, dynamicOptionOverrides);
|
1395 | warnUnknownOptions(extra);
|
1396 | let dateEnv = this.buildDateEnv(refinedOptions.timeZone, refinedOptions.locale, refinedOptions.weekNumberCalculation, refinedOptions.firstDay, refinedOptions.weekText, pluginHooks, availableLocaleData, refinedOptions.defaultRangeSeparator);
|
1397 | let viewSpecs = this.buildViewSpecs(pluginHooks.views, this.stableOptionOverrides, this.stableDynamicOptionOverrides, localeDefaults);
|
1398 | let theme = this.buildTheme(refinedOptions, pluginHooks);
|
1399 | let toolbarConfig = this.parseToolbars(refinedOptions, this.stableOptionOverrides, theme, viewSpecs, calendarApi);
|
1400 | return this.stableCalendarOptionsData = {
|
1401 | calendarOptions: refinedOptions,
|
1402 | pluginHooks,
|
1403 | dateEnv,
|
1404 | viewSpecs,
|
1405 | theme,
|
1406 | toolbarConfig,
|
1407 | localeDefaults,
|
1408 | availableRawLocales: availableLocaleData.map,
|
1409 | };
|
1410 | }
|
1411 |
|
1412 | processRawCalendarOptions(optionOverrides, dynamicOptionOverrides) {
|
1413 | let { locales, locale } = mergeRawOptions([
|
1414 | BASE_OPTION_DEFAULTS,
|
1415 | optionOverrides,
|
1416 | dynamicOptionOverrides,
|
1417 | ]);
|
1418 | let availableLocaleData = this.organizeRawLocales(locales);
|
1419 | let availableRawLocales = availableLocaleData.map;
|
1420 | let localeDefaults = this.buildLocale(locale || availableLocaleData.defaultCode, availableRawLocales).options;
|
1421 | let pluginHooks = this.buildPluginHooks(optionOverrides.plugins || [], globalPlugins);
|
1422 | let refiners = this.currentCalendarOptionsRefiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
|
1423 | let extra = {};
|
1424 | let raw = mergeRawOptions([
|
1425 | BASE_OPTION_DEFAULTS,
|
1426 | localeDefaults,
|
1427 | optionOverrides,
|
1428 | dynamicOptionOverrides,
|
1429 | ]);
|
1430 | let refined = {};
|
1431 | let currentRaw = this.currentCalendarOptionsInput;
|
1432 | let currentRefined = this.currentCalendarOptionsRefined;
|
1433 | let anyChanges = false;
|
1434 | for (let optionName in raw) {
|
1435 | if (this.optionsForRefining.indexOf(optionName) === -1 && (raw[optionName] === currentRaw[optionName] || (COMPLEX_OPTION_COMPARATORS[optionName] &&
|
1436 | (optionName in currentRaw) &&
|
1437 | COMPLEX_OPTION_COMPARATORS[optionName](currentRaw[optionName], raw[optionName])))) {
|
1438 | refined[optionName] = currentRefined[optionName];
|
1439 | }
|
1440 | else if (refiners[optionName]) {
|
1441 | refined[optionName] = refiners[optionName](raw[optionName]);
|
1442 | anyChanges = true;
|
1443 | }
|
1444 | else {
|
1445 | extra[optionName] = currentRaw[optionName];
|
1446 | }
|
1447 | }
|
1448 | if (anyChanges) {
|
1449 | this.currentCalendarOptionsInput = raw;
|
1450 | this.currentCalendarOptionsRefined = refined;
|
1451 | this.stableOptionOverrides = optionOverrides;
|
1452 | this.stableDynamicOptionOverrides = dynamicOptionOverrides;
|
1453 | }
|
1454 | this.optionsForHandling.push(...this.optionsForRefining);
|
1455 | this.optionsForRefining = [];
|
1456 | return {
|
1457 | rawOptions: this.currentCalendarOptionsInput,
|
1458 | refinedOptions: this.currentCalendarOptionsRefined,
|
1459 | pluginHooks,
|
1460 | availableLocaleData,
|
1461 | localeDefaults,
|
1462 | extra,
|
1463 | };
|
1464 | }
|
1465 | _computeCurrentViewData(viewType, optionsData, optionOverrides, dynamicOptionOverrides) {
|
1466 | let viewSpec = optionsData.viewSpecs[viewType];
|
1467 | if (!viewSpec) {
|
1468 | throw new Error(`viewType "${viewType}" is not available. Please make sure you've loaded all neccessary plugins`);
|
1469 | }
|
1470 | let { refinedOptions, extra } = this.processRawViewOptions(viewSpec, optionsData.pluginHooks, optionsData.localeDefaults, optionOverrides, dynamicOptionOverrides);
|
1471 | warnUnknownOptions(extra);
|
1472 | let dateProfileGenerator = this.buildDateProfileGenerator({
|
1473 | dateProfileGeneratorClass: viewSpec.optionDefaults.dateProfileGeneratorClass,
|
1474 | duration: viewSpec.duration,
|
1475 | durationUnit: viewSpec.durationUnit,
|
1476 | usesMinMaxTime: viewSpec.optionDefaults.usesMinMaxTime,
|
1477 | dateEnv: optionsData.dateEnv,
|
1478 | calendarApi: this.props.calendarApi,
|
1479 | slotMinTime: refinedOptions.slotMinTime,
|
1480 | slotMaxTime: refinedOptions.slotMaxTime,
|
1481 | showNonCurrentDates: refinedOptions.showNonCurrentDates,
|
1482 | dayCount: refinedOptions.dayCount,
|
1483 | dateAlignment: refinedOptions.dateAlignment,
|
1484 | dateIncrement: refinedOptions.dateIncrement,
|
1485 | hiddenDays: refinedOptions.hiddenDays,
|
1486 | weekends: refinedOptions.weekends,
|
1487 | nowInput: refinedOptions.now,
|
1488 | validRangeInput: refinedOptions.validRange,
|
1489 | visibleRangeInput: refinedOptions.visibleRange,
|
1490 | fixedWeekCount: refinedOptions.fixedWeekCount,
|
1491 | });
|
1492 | let viewApi = this.buildViewApi(viewType, this.getCurrentData, optionsData.dateEnv);
|
1493 | return { viewSpec, options: refinedOptions, dateProfileGenerator, viewApi };
|
1494 | }
|
1495 | processRawViewOptions(viewSpec, pluginHooks, localeDefaults, optionOverrides, dynamicOptionOverrides) {
|
1496 | let raw = mergeRawOptions([
|
1497 | BASE_OPTION_DEFAULTS,
|
1498 | viewSpec.optionDefaults,
|
1499 | localeDefaults,
|
1500 | optionOverrides,
|
1501 | viewSpec.optionOverrides,
|
1502 | dynamicOptionOverrides,
|
1503 | ]);
|
1504 | let refiners = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, BASE_OPTION_REFINERS), CALENDAR_LISTENER_REFINERS), CALENDAR_OPTION_REFINERS), VIEW_OPTION_REFINERS), pluginHooks.listenerRefiners), pluginHooks.optionRefiners);
|
1505 | let refined = {};
|
1506 | let currentRaw = this.currentViewOptionsInput;
|
1507 | let currentRefined = this.currentViewOptionsRefined;
|
1508 | let anyChanges = false;
|
1509 | let extra = {};
|
1510 | for (let optionName in raw) {
|
1511 | if (raw[optionName] === currentRaw[optionName] ||
|
1512 | (COMPLEX_OPTION_COMPARATORS[optionName] &&
|
1513 | COMPLEX_OPTION_COMPARATORS[optionName](raw[optionName], currentRaw[optionName]))) {
|
1514 | refined[optionName] = currentRefined[optionName];
|
1515 | }
|
1516 | else {
|
1517 | if (raw[optionName] === this.currentCalendarOptionsInput[optionName] ||
|
1518 | (COMPLEX_OPTION_COMPARATORS[optionName] &&
|
1519 | COMPLEX_OPTION_COMPARATORS[optionName](raw[optionName], this.currentCalendarOptionsInput[optionName]))) {
|
1520 | if (optionName in this.currentCalendarOptionsRefined) {
|
1521 | refined[optionName] = this.currentCalendarOptionsRefined[optionName];
|
1522 | }
|
1523 | }
|
1524 | else if (refiners[optionName]) {
|
1525 | refined[optionName] = refiners[optionName](raw[optionName]);
|
1526 | }
|
1527 | else {
|
1528 | extra[optionName] = raw[optionName];
|
1529 | }
|
1530 | anyChanges = true;
|
1531 | }
|
1532 | }
|
1533 | if (anyChanges) {
|
1534 | this.currentViewOptionsInput = raw;
|
1535 | this.currentViewOptionsRefined = refined;
|
1536 | }
|
1537 | return {
|
1538 | rawOptions: this.currentViewOptionsInput,
|
1539 | refinedOptions: this.currentViewOptionsRefined,
|
1540 | extra,
|
1541 | };
|
1542 | }
|
1543 | }
|
1544 | function buildDateEnv$1(timeZone, explicitLocale, weekNumberCalculation, firstDay, weekText, pluginHooks, availableLocaleData, defaultSeparator) {
|
1545 | let locale = buildLocale(explicitLocale || availableLocaleData.defaultCode, availableLocaleData.map);
|
1546 | return new DateEnv({
|
1547 | calendarSystem: 'gregory',
|
1548 | timeZone,
|
1549 | namedTimeZoneImpl: pluginHooks.namedTimeZonedImpl,
|
1550 | locale,
|
1551 | weekNumberCalculation,
|
1552 | firstDay,
|
1553 | weekText,
|
1554 | cmdFormatter: pluginHooks.cmdFormatter,
|
1555 | defaultSeparator,
|
1556 | });
|
1557 | }
|
1558 | function buildTheme(options, pluginHooks) {
|
1559 | let ThemeClass = pluginHooks.themeClasses[options.themeSystem] || StandardTheme;
|
1560 | return new ThemeClass(options);
|
1561 | }
|
1562 | function buildDateProfileGenerator(props) {
|
1563 | let DateProfileGeneratorClass = props.dateProfileGeneratorClass || DateProfileGenerator;
|
1564 | return new DateProfileGeneratorClass(props);
|
1565 | }
|
1566 | function buildViewApi(type, getCurrentData, dateEnv) {
|
1567 | return new ViewImpl(type, getCurrentData, dateEnv);
|
1568 | }
|
1569 | function buildEventUiBySource(eventSources) {
|
1570 | return mapHash(eventSources, (eventSource) => eventSource.ui);
|
1571 | }
|
1572 | function buildEventUiBases(eventDefs, eventUiSingleBase, eventUiBySource) {
|
1573 | let eventUiBases = { '': eventUiSingleBase };
|
1574 | for (let defId in eventDefs) {
|
1575 | let def = eventDefs[defId];
|
1576 | if (def.sourceId && eventUiBySource[def.sourceId]) {
|
1577 | eventUiBases[defId] = eventUiBySource[def.sourceId];
|
1578 | }
|
1579 | }
|
1580 | return eventUiBases;
|
1581 | }
|
1582 | function buildViewUiProps(calendarContext) {
|
1583 | let { options } = calendarContext;
|
1584 | return {
|
1585 | eventUiSingleBase: createEventUi({
|
1586 | display: options.eventDisplay,
|
1587 | editable: options.editable,
|
1588 | startEditable: options.eventStartEditable,
|
1589 | durationEditable: options.eventDurationEditable,
|
1590 | constraint: options.eventConstraint,
|
1591 | overlap: typeof options.eventOverlap === 'boolean' ? options.eventOverlap : undefined,
|
1592 | allow: options.eventAllow,
|
1593 | backgroundColor: options.eventBackgroundColor,
|
1594 | borderColor: options.eventBorderColor,
|
1595 | textColor: options.eventTextColor,
|
1596 | color: options.eventColor,
|
1597 |
|
1598 | }, calendarContext),
|
1599 | selectionConfig: createEventUi({
|
1600 | constraint: options.selectConstraint,
|
1601 | overlap: typeof options.selectOverlap === 'boolean' ? options.selectOverlap : undefined,
|
1602 | allow: options.selectAllow,
|
1603 | }, calendarContext),
|
1604 | };
|
1605 | }
|
1606 | function computeIsLoading(state, context) {
|
1607 | for (let isLoadingFunc of context.pluginHooks.isLoadingFuncs) {
|
1608 | if (isLoadingFunc(state)) {
|
1609 | return true;
|
1610 | }
|
1611 | }
|
1612 | return false;
|
1613 | }
|
1614 | function parseContextBusinessHours(calendarContext) {
|
1615 | return parseBusinessHours(calendarContext.options.businessHours, calendarContext);
|
1616 | }
|
1617 | function warnUnknownOptions(options, viewName) {
|
1618 | for (let optionName in options) {
|
1619 | console.warn(`Unknown option '${optionName}'` +
|
1620 | (viewName ? ` for view '${viewName}'` : ''));
|
1621 | }
|
1622 | }
|
1623 |
|
1624 | class ToolbarSection extends BaseComponent {
|
1625 | render() {
|
1626 | let children = this.props.widgetGroups.map((widgetGroup) => this.renderWidgetGroup(widgetGroup));
|
1627 | return createElement('div', { className: 'fc-toolbar-chunk' }, ...children);
|
1628 | }
|
1629 | renderWidgetGroup(widgetGroup) {
|
1630 | let { props } = this;
|
1631 | let { theme } = this.context;
|
1632 | let children = [];
|
1633 | let isOnlyButtons = true;
|
1634 | for (let widget of widgetGroup) {
|
1635 | let { buttonName, buttonClick, buttonText, buttonIcon, buttonHint } = widget;
|
1636 | if (buttonName === 'title') {
|
1637 | isOnlyButtons = false;
|
1638 | children.push(createElement("h2", { className: "fc-toolbar-title", id: props.titleId }, props.title));
|
1639 | }
|
1640 | else {
|
1641 | let isPressed = buttonName === props.activeButton;
|
1642 | let isDisabled = (!props.isTodayEnabled && buttonName === 'today') ||
|
1643 | (!props.isPrevEnabled && buttonName === 'prev') ||
|
1644 | (!props.isNextEnabled && buttonName === 'next');
|
1645 | let buttonClasses = [`fc-${buttonName}-button`, theme.getClass('button')];
|
1646 | if (isPressed) {
|
1647 | buttonClasses.push(theme.getClass('buttonActive'));
|
1648 | }
|
1649 | children.push(createElement("button", { type: "button", title: typeof buttonHint === 'function' ? buttonHint(props.navUnit) : buttonHint, disabled: isDisabled, "aria-pressed": isPressed, className: buttonClasses.join(' '), onClick: buttonClick }, buttonText || (buttonIcon ? createElement("span", { className: buttonIcon, role: "img" }) : '')));
|
1650 | }
|
1651 | }
|
1652 | if (children.length > 1) {
|
1653 | let groupClassName = (isOnlyButtons && theme.getClass('buttonGroup')) || '';
|
1654 | return createElement('div', { className: groupClassName }, ...children);
|
1655 | }
|
1656 | return children[0];
|
1657 | }
|
1658 | }
|
1659 |
|
1660 | class Toolbar extends BaseComponent {
|
1661 | render() {
|
1662 | let { model, extraClassName } = this.props;
|
1663 | let forceLtr = false;
|
1664 | let startContent;
|
1665 | let endContent;
|
1666 | let sectionWidgets = model.sectionWidgets;
|
1667 | let centerContent = sectionWidgets.center;
|
1668 | if (sectionWidgets.left) {
|
1669 | forceLtr = true;
|
1670 | startContent = sectionWidgets.left;
|
1671 | }
|
1672 | else {
|
1673 | startContent = sectionWidgets.start;
|
1674 | }
|
1675 | if (sectionWidgets.right) {
|
1676 | forceLtr = true;
|
1677 | endContent = sectionWidgets.right;
|
1678 | }
|
1679 | else {
|
1680 | endContent = sectionWidgets.end;
|
1681 | }
|
1682 | let classNames = [
|
1683 | extraClassName || '',
|
1684 | 'fc-toolbar',
|
1685 | forceLtr ? 'fc-toolbar-ltr' : '',
|
1686 | ];
|
1687 | return (createElement("div", { className: classNames.join(' ') },
|
1688 | this.renderSection('start', startContent || []),
|
1689 | this.renderSection('center', centerContent || []),
|
1690 | this.renderSection('end', endContent || [])));
|
1691 | }
|
1692 | renderSection(key, widgetGroups) {
|
1693 | let { props } = this;
|
1694 | return (createElement(ToolbarSection, { key: key, widgetGroups: widgetGroups, title: props.title, navUnit: props.navUnit, activeButton: props.activeButton, isTodayEnabled: props.isTodayEnabled, isPrevEnabled: props.isPrevEnabled, isNextEnabled: props.isNextEnabled, titleId: props.titleId }));
|
1695 | }
|
1696 | }
|
1697 |
|
1698 | class ViewHarness extends BaseComponent {
|
1699 | constructor() {
|
1700 | super(...arguments);
|
1701 | this.state = {
|
1702 | availableWidth: null,
|
1703 | };
|
1704 | this.handleEl = (el) => {
|
1705 | this.el = el;
|
1706 | setRef(this.props.elRef, el);
|
1707 | this.updateAvailableWidth();
|
1708 | };
|
1709 | this.handleResize = () => {
|
1710 | this.updateAvailableWidth();
|
1711 | };
|
1712 | }
|
1713 | render() {
|
1714 | let { props, state } = this;
|
1715 | let { aspectRatio } = props;
|
1716 | let classNames = [
|
1717 | 'fc-view-harness',
|
1718 | (aspectRatio || props.liquid || props.height)
|
1719 | ? 'fc-view-harness-active'
|
1720 | : 'fc-view-harness-passive',
|
1721 | ];
|
1722 | let height = '';
|
1723 | let paddingBottom = '';
|
1724 | if (aspectRatio) {
|
1725 | if (state.availableWidth !== null) {
|
1726 | height = state.availableWidth / aspectRatio;
|
1727 | }
|
1728 | else {
|
1729 |
|
1730 |
|
1731 |
|
1732 |
|
1733 | paddingBottom = `${(1 / aspectRatio) * 100}%`;
|
1734 | }
|
1735 | }
|
1736 | else {
|
1737 | height = props.height || '';
|
1738 | }
|
1739 | return (createElement("div", { "aria-labelledby": props.labeledById, ref: this.handleEl, className: classNames.join(' '), style: { height, paddingBottom } }, props.children));
|
1740 | }
|
1741 | componentDidMount() {
|
1742 | this.context.addResizeHandler(this.handleResize);
|
1743 | }
|
1744 | componentWillUnmount() {
|
1745 | this.context.removeResizeHandler(this.handleResize);
|
1746 | }
|
1747 | updateAvailableWidth() {
|
1748 | if (this.el &&
|
1749 | this.props.aspectRatio
|
1750 | ) {
|
1751 | this.setState({ availableWidth: this.el.offsetWidth });
|
1752 | }
|
1753 | }
|
1754 | }
|
1755 |
|
1756 |
|
1757 |
|
1758 |
|
1759 | class EventClicking extends Interaction {
|
1760 | constructor(settings) {
|
1761 | super(settings);
|
1762 | this.handleSegClick = (ev, segEl) => {
|
1763 | let { component } = this;
|
1764 | let { context } = component;
|
1765 | let seg = getElSeg(segEl);
|
1766 | if (seg &&
|
1767 | component.isValidSegDownEl(ev.target)) {
|
1768 |
|
1769 |
|
1770 | let hasUrlContainer = elementClosest(ev.target, '.fc-event-forced-url');
|
1771 | let url = hasUrlContainer ? hasUrlContainer.querySelector('a[href]').href : '';
|
1772 | context.emitter.trigger('eventClick', {
|
1773 | el: segEl,
|
1774 | event: new EventImpl(component.context, seg.eventRange.def, seg.eventRange.instance),
|
1775 | jsEvent: ev,
|
1776 | view: context.viewApi,
|
1777 | });
|
1778 | if (url && !ev.defaultPrevented) {
|
1779 | window.location.href = url;
|
1780 | }
|
1781 | }
|
1782 | };
|
1783 | this.destroy = listenBySelector(settings.el, 'click', '.fc-event',
|
1784 | this.handleSegClick);
|
1785 | }
|
1786 | }
|
1787 |
|
1788 |
|
1789 |
|
1790 |
|
1791 |
|
1792 | class EventHovering extends Interaction {
|
1793 | constructor(settings) {
|
1794 | super(settings);
|
1795 |
|
1796 | this.handleEventElRemove = (el) => {
|
1797 | if (el === this.currentSegEl) {
|
1798 | this.handleSegLeave(null, this.currentSegEl);
|
1799 | }
|
1800 | };
|
1801 | this.handleSegEnter = (ev, segEl) => {
|
1802 | if (getElSeg(segEl)) {
|
1803 | this.currentSegEl = segEl;
|
1804 | this.triggerEvent('eventMouseEnter', ev, segEl);
|
1805 | }
|
1806 | };
|
1807 | this.handleSegLeave = (ev, segEl) => {
|
1808 | if (this.currentSegEl) {
|
1809 | this.currentSegEl = null;
|
1810 | this.triggerEvent('eventMouseLeave', ev, segEl);
|
1811 | }
|
1812 | };
|
1813 | this.removeHoverListeners = listenToHoverBySelector(settings.el, '.fc-event',
|
1814 | this.handleSegEnter, this.handleSegLeave);
|
1815 | }
|
1816 | destroy() {
|
1817 | this.removeHoverListeners();
|
1818 | }
|
1819 | triggerEvent(publicEvName, ev, segEl) {
|
1820 | let { component } = this;
|
1821 | let { context } = component;
|
1822 | let seg = getElSeg(segEl);
|
1823 | if (!ev || component.isValidSegDownEl(ev.target)) {
|
1824 | context.emitter.trigger(publicEvName, {
|
1825 | el: segEl,
|
1826 | event: new EventImpl(context, seg.eventRange.def, seg.eventRange.instance),
|
1827 | jsEvent: ev,
|
1828 | view: context.viewApi,
|
1829 | });
|
1830 | }
|
1831 | }
|
1832 | }
|
1833 |
|
1834 | class CalendarContent extends PureComponent {
|
1835 | constructor() {
|
1836 | super(...arguments);
|
1837 | this.buildViewContext = memoize(buildViewContext);
|
1838 | this.buildViewPropTransformers = memoize(buildViewPropTransformers);
|
1839 | this.buildToolbarProps = memoize(buildToolbarProps);
|
1840 | this.headerRef = createRef();
|
1841 | this.footerRef = createRef();
|
1842 | this.interactionsStore = {};
|
1843 |
|
1844 | this.state = {
|
1845 | viewLabelId: getUniqueDomId(),
|
1846 | };
|
1847 |
|
1848 |
|
1849 | this.registerInteractiveComponent = (component, settingsInput) => {
|
1850 | let settings = parseInteractionSettings(component, settingsInput);
|
1851 | let DEFAULT_INTERACTIONS = [
|
1852 | EventClicking,
|
1853 | EventHovering,
|
1854 | ];
|
1855 | let interactionClasses = DEFAULT_INTERACTIONS.concat(this.props.pluginHooks.componentInteractions);
|
1856 | let interactions = interactionClasses.map((TheInteractionClass) => new TheInteractionClass(settings));
|
1857 | this.interactionsStore[component.uid] = interactions;
|
1858 | interactionSettingsStore[component.uid] = settings;
|
1859 | };
|
1860 | this.unregisterInteractiveComponent = (component) => {
|
1861 | let listeners = this.interactionsStore[component.uid];
|
1862 | if (listeners) {
|
1863 | for (let listener of listeners) {
|
1864 | listener.destroy();
|
1865 | }
|
1866 | delete this.interactionsStore[component.uid];
|
1867 | }
|
1868 | delete interactionSettingsStore[component.uid];
|
1869 | };
|
1870 |
|
1871 |
|
1872 | this.resizeRunner = new DelayedRunner(() => {
|
1873 | this.props.emitter.trigger('_resize', true);
|
1874 | this.props.emitter.trigger('windowResize', { view: this.props.viewApi });
|
1875 | });
|
1876 | this.handleWindowResize = (ev) => {
|
1877 | let { options } = this.props;
|
1878 | if (options.handleWindowResize &&
|
1879 | ev.target === window
|
1880 | ) {
|
1881 | this.resizeRunner.request(options.windowResizeDelay);
|
1882 | }
|
1883 | };
|
1884 | }
|
1885 | |
1886 |
|
1887 |
|
1888 | render() {
|
1889 | let { props } = this;
|
1890 | let { toolbarConfig, options } = props;
|
1891 | let toolbarProps = this.buildToolbarProps(props.viewSpec, props.dateProfile, props.dateProfileGenerator, props.currentDate, getNow(props.options.now, props.dateEnv),
|
1892 | props.viewTitle);
|
1893 | let viewVGrow = false;
|
1894 | let viewHeight = '';
|
1895 | let viewAspectRatio;
|
1896 | if (props.isHeightAuto || props.forPrint) {
|
1897 | viewHeight = '';
|
1898 | }
|
1899 | else if (options.height != null) {
|
1900 | viewVGrow = true;
|
1901 | }
|
1902 | else if (options.contentHeight != null) {
|
1903 | viewHeight = options.contentHeight;
|
1904 | }
|
1905 | else {
|
1906 | viewAspectRatio = Math.max(options.aspectRatio, 0.5);
|
1907 | }
|
1908 | let 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);
|
1909 | let viewLabelId = (toolbarConfig.header && toolbarConfig.header.hasTitle)
|
1910 | ? this.state.viewLabelId
|
1911 | : undefined;
|
1912 | return (createElement(ViewContextType.Provider, { value: viewContext },
|
1913 | toolbarConfig.header && (createElement(Toolbar, Object.assign({ ref: this.headerRef, extraClassName: "fc-header-toolbar", model: toolbarConfig.header, titleId: viewLabelId }, toolbarProps))),
|
1914 | createElement(ViewHarness, { liquid: viewVGrow, height: viewHeight, aspectRatio: viewAspectRatio, labeledById: viewLabelId },
|
1915 | this.renderView(props),
|
1916 | this.buildAppendContent()),
|
1917 | toolbarConfig.footer && (createElement(Toolbar, Object.assign({ ref: this.footerRef, extraClassName: "fc-footer-toolbar", model: toolbarConfig.footer, titleId: "" }, toolbarProps)))));
|
1918 | }
|
1919 | componentDidMount() {
|
1920 | let { props } = this;
|
1921 | this.calendarInteractions = props.pluginHooks.calendarInteractions
|
1922 | .map((CalendarInteractionClass) => new CalendarInteractionClass(props));
|
1923 | window.addEventListener('resize', this.handleWindowResize);
|
1924 | let { propSetHandlers } = props.pluginHooks;
|
1925 | for (let propName in propSetHandlers) {
|
1926 | propSetHandlers[propName](props[propName], props);
|
1927 | }
|
1928 | }
|
1929 | componentDidUpdate(prevProps) {
|
1930 | let { props } = this;
|
1931 | let { propSetHandlers } = props.pluginHooks;
|
1932 | for (let propName in propSetHandlers) {
|
1933 | if (props[propName] !== prevProps[propName]) {
|
1934 | propSetHandlers[propName](props[propName], props);
|
1935 | }
|
1936 | }
|
1937 | }
|
1938 | componentWillUnmount() {
|
1939 | window.removeEventListener('resize', this.handleWindowResize);
|
1940 | this.resizeRunner.clear();
|
1941 | for (let interaction of this.calendarInteractions) {
|
1942 | interaction.destroy();
|
1943 | }
|
1944 | this.props.emitter.trigger('_unmount');
|
1945 | }
|
1946 | buildAppendContent() {
|
1947 | let { props } = this;
|
1948 | let children = props.pluginHooks.viewContainerAppends.map((buildAppendContent) => buildAppendContent(props));
|
1949 | return createElement(Fragment, {}, ...children);
|
1950 | }
|
1951 | renderView(props) {
|
1952 | let { pluginHooks } = props;
|
1953 | let { viewSpec } = props;
|
1954 | let viewProps = {
|
1955 | dateProfile: props.dateProfile,
|
1956 | businessHours: props.businessHours,
|
1957 | eventStore: props.renderableEventStore,
|
1958 | eventUiBases: props.eventUiBases,
|
1959 | dateSelection: props.dateSelection,
|
1960 | eventSelection: props.eventSelection,
|
1961 | eventDrag: props.eventDrag,
|
1962 | eventResize: props.eventResize,
|
1963 | isHeightAuto: props.isHeightAuto,
|
1964 | forPrint: props.forPrint,
|
1965 | };
|
1966 | let transformers = this.buildViewPropTransformers(pluginHooks.viewPropsTransformers);
|
1967 | for (let transformer of transformers) {
|
1968 | Object.assign(viewProps, transformer.transform(viewProps, props));
|
1969 | }
|
1970 | let ViewComponent = viewSpec.component;
|
1971 | return (createElement(ViewComponent, Object.assign({}, viewProps)));
|
1972 | }
|
1973 | }
|
1974 | function buildToolbarProps(viewSpec, dateProfile, dateProfileGenerator, currentDate, now, title) {
|
1975 |
|
1976 | let todayInfo = dateProfileGenerator.build(now, undefined, false);
|
1977 | let prevInfo = dateProfileGenerator.buildPrev(dateProfile, currentDate, false);
|
1978 | let nextInfo = dateProfileGenerator.buildNext(dateProfile, currentDate, false);
|
1979 | return {
|
1980 | title,
|
1981 | activeButton: viewSpec.type,
|
1982 | navUnit: viewSpec.singleUnit,
|
1983 | isTodayEnabled: todayInfo.isValid && !rangeContainsMarker(dateProfile.currentRange, now),
|
1984 | isPrevEnabled: prevInfo.isValid,
|
1985 | isNextEnabled: nextInfo.isValid,
|
1986 | };
|
1987 | }
|
1988 |
|
1989 |
|
1990 | function buildViewPropTransformers(theClasses) {
|
1991 | return theClasses.map((TheClass) => new TheClass());
|
1992 | }
|
1993 |
|
1994 | class Calendar extends CalendarImpl {
|
1995 | constructor(el, optionOverrides = {}) {
|
1996 | super();
|
1997 | this.isRendering = false;
|
1998 | this.isRendered = false;
|
1999 | this.currentClassNames = [];
|
2000 | this.customContentRenderId = 0;
|
2001 | this.handleAction = (action) => {
|
2002 |
|
2003 | switch (action.type) {
|
2004 | case 'SET_EVENT_DRAG':
|
2005 | case 'SET_EVENT_RESIZE':
|
2006 | this.renderRunner.tryDrain();
|
2007 | }
|
2008 | };
|
2009 | this.handleData = (data) => {
|
2010 | this.currentData = data;
|
2011 | this.renderRunner.request(data.calendarOptions.rerenderDelay);
|
2012 | };
|
2013 | this.handleRenderRequest = () => {
|
2014 | if (this.isRendering) {
|
2015 | this.isRendered = true;
|
2016 | let { currentData } = this;
|
2017 | flushSync(() => {
|
2018 | render(createElement(CalendarRoot, { options: currentData.calendarOptions, theme: currentData.theme, emitter: currentData.emitter }, (classNames, height, isHeightAuto, forPrint) => {
|
2019 | this.setClassNames(classNames);
|
2020 | this.setHeight(height);
|
2021 | return (createElement(RenderId.Provider, { value: this.customContentRenderId },
|
2022 | createElement(CalendarContent, Object.assign({ isHeightAuto: isHeightAuto, forPrint: forPrint }, currentData))));
|
2023 | }), this.el);
|
2024 | });
|
2025 | }
|
2026 | else if (this.isRendered) {
|
2027 | this.isRendered = false;
|
2028 | render(null, this.el);
|
2029 | this.setClassNames([]);
|
2030 | this.setHeight('');
|
2031 | }
|
2032 | };
|
2033 | ensureElHasStyles(el);
|
2034 | this.el = el;
|
2035 | this.renderRunner = new DelayedRunner(this.handleRenderRequest);
|
2036 | new CalendarDataManager({
|
2037 | optionOverrides,
|
2038 | calendarApi: this,
|
2039 | onAction: this.handleAction,
|
2040 | onData: this.handleData,
|
2041 | });
|
2042 | }
|
2043 | render() {
|
2044 | let wasRendering = this.isRendering;
|
2045 | if (!wasRendering) {
|
2046 | this.isRendering = true;
|
2047 | }
|
2048 | else {
|
2049 | this.customContentRenderId += 1;
|
2050 | }
|
2051 | this.renderRunner.request();
|
2052 | if (wasRendering) {
|
2053 | this.updateSize();
|
2054 | }
|
2055 | }
|
2056 | destroy() {
|
2057 | if (this.isRendering) {
|
2058 | this.isRendering = false;
|
2059 | this.renderRunner.request();
|
2060 | }
|
2061 | }
|
2062 | updateSize() {
|
2063 | flushSync(() => {
|
2064 | super.updateSize();
|
2065 | });
|
2066 | }
|
2067 | batchRendering(func) {
|
2068 | this.renderRunner.pause('batchRendering');
|
2069 | func();
|
2070 | this.renderRunner.resume('batchRendering');
|
2071 | }
|
2072 | pauseRendering() {
|
2073 | this.renderRunner.pause('pauseRendering');
|
2074 | }
|
2075 | resumeRendering() {
|
2076 | this.renderRunner.resume('pauseRendering', true);
|
2077 | }
|
2078 | resetOptions(optionOverrides, changedOptionNames) {
|
2079 | this.currentDataManager.resetOptions(optionOverrides, changedOptionNames);
|
2080 | }
|
2081 | setClassNames(classNames) {
|
2082 | if (!isArraysEqual(classNames, this.currentClassNames)) {
|
2083 | let { classList } = this.el;
|
2084 | for (let className of this.currentClassNames) {
|
2085 | classList.remove(className);
|
2086 | }
|
2087 | for (let className of classNames) {
|
2088 | classList.add(className);
|
2089 | }
|
2090 | this.currentClassNames = classNames;
|
2091 | }
|
2092 | }
|
2093 | setHeight(height) {
|
2094 | applyStyleProp(this.el, 'height', height);
|
2095 | }
|
2096 | }
|
2097 |
|
2098 | function formatDate(dateInput, options = {}) {
|
2099 | let dateEnv = buildDateEnv(options);
|
2100 | let formatter = createFormatter(options);
|
2101 | let dateMeta = dateEnv.createMarkerMeta(dateInput);
|
2102 | if (!dateMeta) {
|
2103 | return '';
|
2104 | }
|
2105 | return dateEnv.format(dateMeta.marker, formatter, {
|
2106 | forcedTzo: dateMeta.forcedTzo,
|
2107 | });
|
2108 | }
|
2109 | function formatRange(startInput, endInput, options) {
|
2110 | let dateEnv = buildDateEnv(typeof options === 'object' && options ? options : {});
|
2111 | let formatter = createFormatter(options);
|
2112 | let startMeta = dateEnv.createMarkerMeta(startInput);
|
2113 | let endMeta = dateEnv.createMarkerMeta(endInput);
|
2114 | if (!startMeta || !endMeta) {
|
2115 | return '';
|
2116 | }
|
2117 | return dateEnv.formatRange(startMeta.marker, endMeta.marker, formatter, {
|
2118 | forcedStartTzo: startMeta.forcedTzo,
|
2119 | forcedEndTzo: endMeta.forcedTzo,
|
2120 | isEndExclusive: options.isEndExclusive,
|
2121 | defaultSeparator: BASE_OPTION_DEFAULTS.defaultRangeSeparator,
|
2122 | });
|
2123 | }
|
2124 |
|
2125 | function buildDateEnv(settings) {
|
2126 | let locale = buildLocale(settings.locale || 'en', organizeRawLocales([]).map);
|
2127 | return new DateEnv(Object.assign(Object.assign({ timeZone: BASE_OPTION_DEFAULTS.timeZone, calendarSystem: 'gregory' }, settings), { locale }));
|
2128 | }
|
2129 |
|
2130 |
|
2131 |
|
2132 |
|
2133 |
|
2134 |
|
2135 | function sliceEvents(props, allDay) {
|
2136 | return sliceEventStore(props.eventStore, props.eventUiBases, props.dateProfile.activeRange, allDay ? props.nextDayThreshold : null).fg;
|
2137 | }
|
2138 |
|
2139 | const version = '6.1.15';
|
2140 |
|
2141 | export { Calendar, createPlugin, formatDate, formatRange, globalLocales, globalPlugins, sliceEvents, version };
|