UNPKG

@fullcalendar/common

Version:
1,499 lines (1,479 loc) 393 kB
/*! FullCalendar v5.11.4 Docs & License: https://fullcalendar.io/ (c) 2022 Adam Shaw */ import './main.css'; import { __assign, __spreadArray, __extends } from 'tslib'; import { createContext, Component, createRef, createElement, Fragment, createPortal } from './vdom.js'; export * from './vdom.js'; // no public types yet. when there are, export from: // import {} from './api-type-deps' var EventSourceApi = /** @class */ (function () { function EventSourceApi(context, internalEventSource) { this.context = context; this.internalEventSource = internalEventSource; } EventSourceApi.prototype.remove = function () { this.context.dispatch({ type: 'REMOVE_EVENT_SOURCE', sourceId: this.internalEventSource.sourceId, }); }; EventSourceApi.prototype.refetch = function () { this.context.dispatch({ type: 'FETCH_EVENT_SOURCES', sourceIds: [this.internalEventSource.sourceId], isRefetch: true, }); }; Object.defineProperty(EventSourceApi.prototype, "id", { get: function () { return this.internalEventSource.publicId; }, enumerable: false, configurable: true }); Object.defineProperty(EventSourceApi.prototype, "url", { get: function () { return this.internalEventSource.meta.url; }, enumerable: false, configurable: true }); Object.defineProperty(EventSourceApi.prototype, "format", { get: function () { return this.internalEventSource.meta.format; // TODO: bad. not guaranteed }, enumerable: false, configurable: true }); return EventSourceApi; }()); function removeElement(el) { if (el.parentNode) { el.parentNode.removeChild(el); } } // Querying // ---------------------------------------------------------------------------------------------------------------- function elementClosest(el, selector) { if (el.closest) { return el.closest(selector); // really bad fallback for IE // from https://developer.mozilla.org/en-US/docs/Web/API/Element/closest } if (!document.documentElement.contains(el)) { return null; } do { if (elementMatches(el, selector)) { return el; } el = (el.parentElement || el.parentNode); } while (el !== null && el.nodeType === 1); return null; } function elementMatches(el, selector) { var method = el.matches || el.matchesSelector || el.msMatchesSelector; return method.call(el, selector); } // accepts multiple subject els // returns a real array. good for methods like forEach // TODO: accept the document function findElements(container, selector) { var containers = container instanceof HTMLElement ? [container] : container; var allMatches = []; for (var i = 0; i < containers.length; i += 1) { var matches = containers[i].querySelectorAll(selector); for (var j = 0; j < matches.length; j += 1) { allMatches.push(matches[j]); } } return allMatches; } // accepts multiple subject els // only queries direct child elements // TODO: rename to findDirectChildren! function findDirectChildren(parent, selector) { var parents = parent instanceof HTMLElement ? [parent] : parent; var allMatches = []; for (var i = 0; i < parents.length; i += 1) { var childNodes = parents[i].children; // only ever elements for (var j = 0; j < childNodes.length; j += 1) { var childNode = childNodes[j]; if (!selector || elementMatches(childNode, selector)) { allMatches.push(childNode); } } } return allMatches; } // Style // ---------------------------------------------------------------------------------------------------------------- var PIXEL_PROP_RE = /(top|left|right|bottom|width|height)$/i; function applyStyle(el, props) { for (var propName in props) { applyStyleProp(el, propName, props[propName]); } } function applyStyleProp(el, name, val) { if (val == null) { el.style[name] = ''; } else if (typeof val === 'number' && PIXEL_PROP_RE.test(name)) { el.style[name] = val + "px"; } else { el.style[name] = val; } } // Event Handling // ---------------------------------------------------------------------------------------------------------------- // if intercepting bubbled events at the document/window/body level, // and want to see originating element (the 'target'), use this util instead // of `ev.target` because it goes within web-component boundaries. function getEventTargetViaRoot(ev) { var _a, _b; return (_b = (_a = ev.composedPath) === null || _a === void 0 ? void 0 : _a.call(ev)[0]) !== null && _b !== void 0 ? _b : ev.target; } // Shadow DOM consuderations // ---------------------------------------------------------------------------------------------------------------- function getElRoot(el) { return el.getRootNode ? el.getRootNode() : document; } // Unique ID for DOM attribute var guid$1 = 0; function getUniqueDomId() { guid$1 += 1; return 'fc-dom-' + guid$1; } // Stops a mouse/touch event from doing it's native browser action function preventDefault(ev) { ev.preventDefault(); } // Event Delegation // ---------------------------------------------------------------------------------------------------------------- function buildDelegationHandler(selector, handler) { return function (ev) { var matchedChild = elementClosest(ev.target, selector); if (matchedChild) { handler.call(matchedChild, ev, matchedChild); } }; } function listenBySelector(container, eventType, selector, handler) { var attachedHandler = buildDelegationHandler(selector, handler); container.addEventListener(eventType, attachedHandler); return function () { container.removeEventListener(eventType, attachedHandler); }; } function listenToHoverBySelector(container, selector, onMouseEnter, onMouseLeave) { var currentMatchedChild; return listenBySelector(container, 'mouseover', selector, function (mouseOverEv, matchedChild) { if (matchedChild !== currentMatchedChild) { currentMatchedChild = matchedChild; onMouseEnter(mouseOverEv, matchedChild); var realOnMouseLeave_1 = function (mouseLeaveEv) { currentMatchedChild = null; onMouseLeave(mouseLeaveEv, matchedChild); matchedChild.removeEventListener('mouseleave', realOnMouseLeave_1); }; // listen to the next mouseleave, and then unattach matchedChild.addEventListener('mouseleave', realOnMouseLeave_1); } }); } // Animation // ---------------------------------------------------------------------------------------------------------------- var transitionEventNames = [ 'webkitTransitionEnd', 'otransitionend', 'oTransitionEnd', 'msTransitionEnd', 'transitionend', ]; // triggered only when the next single subsequent transition finishes function whenTransitionDone(el, callback) { var realCallback = function (ev) { callback(ev); transitionEventNames.forEach(function (eventName) { el.removeEventListener(eventName, realCallback); }); }; transitionEventNames.forEach(function (eventName) { el.addEventListener(eventName, realCallback); // cross-browser way to determine when the transition finishes }); } // ARIA workarounds // ---------------------------------------------------------------------------------------------------------------- function createAriaClickAttrs(handler) { return __assign({ onClick: handler }, createAriaKeyboardAttrs(handler)); } function createAriaKeyboardAttrs(handler) { return { tabIndex: 0, onKeyDown: function (ev) { if (ev.key === 'Enter' || ev.key === ' ') { handler(ev); ev.preventDefault(); // if space, don't scroll down page } }, }; } var guidNumber = 0; function guid() { guidNumber += 1; return String(guidNumber); } /* FullCalendar-specific DOM Utilities ----------------------------------------------------------------------------------------------------------------------*/ // Make the mouse cursor express that an event is not allowed in the current area function disableCursor() { document.body.classList.add('fc-not-allowed'); } // Returns the mouse cursor to its original look function enableCursor() { document.body.classList.remove('fc-not-allowed'); } /* Selection ----------------------------------------------------------------------------------------------------------------------*/ function preventSelection(el) { el.classList.add('fc-unselectable'); el.addEventListener('selectstart', preventDefault); } function allowSelection(el) { el.classList.remove('fc-unselectable'); el.removeEventListener('selectstart', preventDefault); } /* Context Menu ----------------------------------------------------------------------------------------------------------------------*/ function preventContextMenu(el) { el.addEventListener('contextmenu', preventDefault); } function allowContextMenu(el) { el.removeEventListener('contextmenu', preventDefault); } function parseFieldSpecs(input) { var specs = []; var tokens = []; var i; var token; if (typeof input === 'string') { tokens = input.split(/\s*,\s*/); } else if (typeof input === 'function') { tokens = [input]; } else if (Array.isArray(input)) { tokens = input; } for (i = 0; i < tokens.length; i += 1) { token = tokens[i]; if (typeof token === 'string') { specs.push(token.charAt(0) === '-' ? { field: token.substring(1), order: -1 } : { field: token, order: 1 }); } else if (typeof token === 'function') { specs.push({ func: token }); } } return specs; } function compareByFieldSpecs(obj0, obj1, fieldSpecs) { var i; var cmp; for (i = 0; i < fieldSpecs.length; i += 1) { cmp = compareByFieldSpec(obj0, obj1, fieldSpecs[i]); if (cmp) { return cmp; } } return 0; } function compareByFieldSpec(obj0, obj1, fieldSpec) { if (fieldSpec.func) { return fieldSpec.func(obj0, obj1); } return flexibleCompare(obj0[fieldSpec.field], obj1[fieldSpec.field]) * (fieldSpec.order || 1); } function flexibleCompare(a, b) { if (!a && !b) { return 0; } if (b == null) { return -1; } if (a == null) { return 1; } if (typeof a === 'string' || typeof b === 'string') { return String(a).localeCompare(String(b)); } return a - b; } /* String Utilities ----------------------------------------------------------------------------------------------------------------------*/ function padStart(val, len) { var s = String(val); return '000'.substr(0, len - s.length) + s; } function formatWithOrdinals(formatter, args, fallbackText) { if (typeof formatter === 'function') { return formatter.apply(void 0, args); } if (typeof formatter === 'string') { // non-blank string return args.reduce(function (str, arg, index) { return (str.replace('$' + index, arg || '')); }, formatter); } return fallbackText; } /* Number Utilities ----------------------------------------------------------------------------------------------------------------------*/ function compareNumbers(a, b) { return a - b; } function isInt(n) { return n % 1 === 0; } /* FC-specific DOM dimension stuff ----------------------------------------------------------------------------------------------------------------------*/ function computeSmallestCellWidth(cellEl) { var allWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-frame'); var contentWidthEl = cellEl.querySelector('.fc-scrollgrid-shrink-cushion'); if (!allWidthEl) { throw new Error('needs fc-scrollgrid-shrink-frame className'); // TODO: use const } if (!contentWidthEl) { throw new Error('needs fc-scrollgrid-shrink-cushion className'); } return cellEl.getBoundingClientRect().width - allWidthEl.getBoundingClientRect().width + // the cell padding+border contentWidthEl.getBoundingClientRect().width; } var DAY_IDS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']; // Adding function addWeeks(m, n) { var a = dateToUtcArray(m); a[2] += n * 7; return arrayToUtcDate(a); } function addDays(m, n) { var a = dateToUtcArray(m); a[2] += n; return arrayToUtcDate(a); } function addMs(m, n) { var a = dateToUtcArray(m); a[6] += n; return arrayToUtcDate(a); } // Diffing (all return floats) // TODO: why not use ranges? function diffWeeks(m0, m1) { return diffDays(m0, m1) / 7; } function diffDays(m0, m1) { return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60 * 24); } function diffHours(m0, m1) { return (m1.valueOf() - m0.valueOf()) / (1000 * 60 * 60); } function diffMinutes(m0, m1) { return (m1.valueOf() - m0.valueOf()) / (1000 * 60); } function diffSeconds(m0, m1) { return (m1.valueOf() - m0.valueOf()) / 1000; } function diffDayAndTime(m0, m1) { var m0day = startOfDay(m0); var m1day = startOfDay(m1); return { years: 0, months: 0, days: Math.round(diffDays(m0day, m1day)), milliseconds: (m1.valueOf() - m1day.valueOf()) - (m0.valueOf() - m0day.valueOf()), }; } // Diffing Whole Units function diffWholeWeeks(m0, m1) { var d = diffWholeDays(m0, m1); if (d !== null && d % 7 === 0) { return d / 7; } return null; } function diffWholeDays(m0, m1) { if (timeAsMs(m0) === timeAsMs(m1)) { return Math.round(diffDays(m0, m1)); } return null; } // Start-Of function startOfDay(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), ]); } function startOfHour(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), m.getUTCHours(), ]); } function startOfMinute(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), m.getUTCHours(), m.getUTCMinutes(), ]); } function startOfSecond(m) { return arrayToUtcDate([ m.getUTCFullYear(), m.getUTCMonth(), m.getUTCDate(), m.getUTCHours(), m.getUTCMinutes(), m.getUTCSeconds(), ]); } // Week Computation function weekOfYear(marker, dow, doy) { var y = marker.getUTCFullYear(); var w = weekOfGivenYear(marker, y, dow, doy); if (w < 1) { return weekOfGivenYear(marker, y - 1, dow, doy); } var nextW = weekOfGivenYear(marker, y + 1, dow, doy); if (nextW >= 1) { return Math.min(w, nextW); } return w; } function weekOfGivenYear(marker, year, dow, doy) { var firstWeekStart = arrayToUtcDate([year, 0, 1 + firstWeekOffset(year, dow, doy)]); var dayStart = startOfDay(marker); var days = Math.round(diffDays(firstWeekStart, dayStart)); return Math.floor(days / 7) + 1; // zero-indexed } // start-of-first-week - start-of-year function firstWeekOffset(year, dow, doy) { // first-week day -- which january is always in the first week (4 for iso, 1 for other) var fwd = 7 + dow - doy; // first-week day local weekday -- which local weekday is fwd var fwdlw = (7 + arrayToUtcDate([year, 0, fwd]).getUTCDay() - dow) % 7; return -fwdlw + fwd - 1; } // Array Conversion function dateToLocalArray(date) { return [ date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds(), ]; } function arrayToLocalDate(a) { return new Date(a[0], a[1] || 0, a[2] == null ? 1 : a[2], // day of month a[3] || 0, a[4] || 0, a[5] || 0); } function dateToUtcArray(date) { return [ date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds(), ]; } function arrayToUtcDate(a) { // according to web standards (and Safari), a month index is required. // massage if only given a year. if (a.length === 1) { a = a.concat([0]); } return new Date(Date.UTC.apply(Date, a)); } // Other Utils function isValidDate(m) { return !isNaN(m.valueOf()); } function timeAsMs(m) { return m.getUTCHours() * 1000 * 60 * 60 + m.getUTCMinutes() * 1000 * 60 + m.getUTCSeconds() * 1000 + m.getUTCMilliseconds(); } function createEventInstance(defId, range, forcedStartTzo, forcedEndTzo) { return { instanceId: guid(), defId: defId, range: range, forcedStartTzo: forcedStartTzo == null ? null : forcedStartTzo, forcedEndTzo: forcedEndTzo == null ? null : forcedEndTzo, }; } var hasOwnProperty = Object.prototype.hasOwnProperty; // Merges an array of objects into a single object. // The second argument allows for an array of property names who's object values will be merged together. function mergeProps(propObjs, complexPropsMap) { var dest = {}; if (complexPropsMap) { for (var name_1 in complexPropsMap) { var complexObjs = []; // collect the trailing object values, stopping when a non-object is discovered for (var i = propObjs.length - 1; i >= 0; i -= 1) { var val = propObjs[i][name_1]; if (typeof val === 'object' && val) { // non-null object complexObjs.unshift(val); } else if (val !== undefined) { dest[name_1] = val; // if there were no objects, this value will be used break; } } // if the trailing values were objects, use the merged value if (complexObjs.length) { dest[name_1] = mergeProps(complexObjs); } } } // copy values into the destination, going from last to first for (var i = propObjs.length - 1; i >= 0; i -= 1) { var props = propObjs[i]; for (var name_2 in props) { if (!(name_2 in dest)) { // if already assigned by previous props or complex props, don't reassign dest[name_2] = props[name_2]; } } } return dest; } function filterHash(hash, func) { var filtered = {}; for (var key in hash) { if (func(hash[key], key)) { filtered[key] = hash[key]; } } return filtered; } function mapHash(hash, func) { var newHash = {}; for (var key in hash) { newHash[key] = func(hash[key], key); } return newHash; } function arrayToHash(a) { var hash = {}; for (var _i = 0, a_1 = a; _i < a_1.length; _i++) { var item = a_1[_i]; hash[item] = true; } return hash; } function buildHashFromArray(a, func) { var hash = {}; for (var i = 0; i < a.length; i += 1) { var tuple = func(a[i], i); hash[tuple[0]] = tuple[1]; } return hash; } function hashValuesToArray(obj) { var a = []; for (var key in obj) { a.push(obj[key]); } return a; } function isPropsEqual(obj0, obj1) { if (obj0 === obj1) { return true; } for (var key in obj0) { if (hasOwnProperty.call(obj0, key)) { if (!(key in obj1)) { return false; } } } for (var key in obj1) { if (hasOwnProperty.call(obj1, key)) { if (obj0[key] !== obj1[key]) { return false; } } } return true; } function getUnequalProps(obj0, obj1) { var keys = []; for (var key in obj0) { if (hasOwnProperty.call(obj0, key)) { if (!(key in obj1)) { keys.push(key); } } } for (var key in obj1) { if (hasOwnProperty.call(obj1, key)) { if (obj0[key] !== obj1[key]) { keys.push(key); } } } return keys; } function compareObjs(oldProps, newProps, equalityFuncs) { if (equalityFuncs === void 0) { equalityFuncs = {}; } if (oldProps === newProps) { return true; } for (var key in newProps) { if (key in oldProps && isObjValsEqual(oldProps[key], newProps[key], equalityFuncs[key])) ; else { return false; } } // check for props that were omitted in the new for (var key in oldProps) { if (!(key in newProps)) { return false; } } return true; } /* assumed "true" equality for handler names like "onReceiveSomething" */ function isObjValsEqual(val0, val1, comparator) { if (val0 === val1 || comparator === true) { return true; } if (comparator) { return comparator(val0, val1); } return false; } function collectFromHash(hash, startIndex, endIndex, step) { if (startIndex === void 0) { startIndex = 0; } if (step === void 0) { step = 1; } var res = []; if (endIndex == null) { endIndex = Object.keys(hash).length; } for (var i = startIndex; i < endIndex; i += step) { var val = hash[i]; if (val !== undefined) { // will disregard undefined for sparse arrays res.push(val); } } return res; } function parseRecurring(refined, defaultAllDay, dateEnv, recurringTypes) { for (var i = 0; i < recurringTypes.length; i += 1) { var parsed = recurringTypes[i].parse(refined, dateEnv); if (parsed) { var allDay = refined.allDay; if (allDay == null) { allDay = defaultAllDay; if (allDay == null) { allDay = parsed.allDayGuess; if (allDay == null) { allDay = false; } } } return { allDay: allDay, duration: parsed.duration, typeData: parsed.typeData, typeId: i, }; } } return null; } function expandRecurring(eventStore, framingRange, context) { var dateEnv = context.dateEnv, pluginHooks = context.pluginHooks, options = context.options; var defs = eventStore.defs, instances = eventStore.instances; // remove existing recurring instances // TODO: bad. always expand events as a second step instances = filterHash(instances, function (instance) { return !defs[instance.defId].recurringDef; }); for (var defId in defs) { var def = defs[defId]; if (def.recurringDef) { var duration = def.recurringDef.duration; if (!duration) { duration = def.allDay ? options.defaultAllDayEventDuration : options.defaultTimedEventDuration; } var starts = expandRecurringRanges(def, duration, framingRange, dateEnv, pluginHooks.recurringTypes); for (var _i = 0, starts_1 = starts; _i < starts_1.length; _i++) { var start = starts_1[_i]; var instance = createEventInstance(defId, { start: start, end: dateEnv.add(start, duration), }); instances[instance.instanceId] = instance; } } } return { defs: defs, instances: instances }; } /* Event MUST have a recurringDef */ function expandRecurringRanges(eventDef, duration, framingRange, dateEnv, recurringTypes) { var typeDef = recurringTypes[eventDef.recurringDef.typeId]; var markers = typeDef.expand(eventDef.recurringDef.typeData, { start: dateEnv.subtract(framingRange.start, duration), end: framingRange.end, }, dateEnv); // the recurrence plugins don't guarantee that all-day events are start-of-day, so we have to if (eventDef.allDay) { markers = markers.map(startOfDay); } return markers; } var INTERNAL_UNITS = ['years', 'months', 'days', 'milliseconds']; var PARSE_RE = /^(-?)(?:(\d+)\.)?(\d+):(\d\d)(?::(\d\d)(?:\.(\d\d\d))?)?/; // Parsing and Creation function createDuration(input, unit) { var _a; if (typeof input === 'string') { return parseString(input); } if (typeof input === 'object' && input) { // non-null object return parseObject(input); } if (typeof input === 'number') { return parseObject((_a = {}, _a[unit || 'milliseconds'] = input, _a)); } return null; } function parseString(s) { var m = PARSE_RE.exec(s); if (m) { var sign = m[1] ? -1 : 1; return { years: 0, months: 0, days: sign * (m[2] ? parseInt(m[2], 10) : 0), milliseconds: sign * ((m[3] ? parseInt(m[3], 10) : 0) * 60 * 60 * 1000 + // hours (m[4] ? parseInt(m[4], 10) : 0) * 60 * 1000 + // minutes (m[5] ? parseInt(m[5], 10) : 0) * 1000 + // seconds (m[6] ? parseInt(m[6], 10) : 0) // ms ), }; } return null; } function parseObject(obj) { var duration = { years: obj.years || obj.year || 0, months: obj.months || obj.month || 0, days: obj.days || obj.day || 0, milliseconds: (obj.hours || obj.hour || 0) * 60 * 60 * 1000 + // hours (obj.minutes || obj.minute || 0) * 60 * 1000 + // minutes (obj.seconds || obj.second || 0) * 1000 + // seconds (obj.milliseconds || obj.millisecond || obj.ms || 0), // ms }; var weeks = obj.weeks || obj.week; if (weeks) { duration.days += weeks * 7; duration.specifiedWeeks = true; } return duration; } // Equality function durationsEqual(d0, d1) { return d0.years === d1.years && d0.months === d1.months && d0.days === d1.days && d0.milliseconds === d1.milliseconds; } function asCleanDays(dur) { if (!dur.years && !dur.months && !dur.milliseconds) { return dur.days; } return 0; } // Simple Math function addDurations(d0, d1) { return { years: d0.years + d1.years, months: d0.months + d1.months, days: d0.days + d1.days, milliseconds: d0.milliseconds + d1.milliseconds, }; } function subtractDurations(d1, d0) { return { years: d1.years - d0.years, months: d1.months - d0.months, days: d1.days - d0.days, milliseconds: d1.milliseconds - d0.milliseconds, }; } function multiplyDuration(d, n) { return { years: d.years * n, months: d.months * n, days: d.days * n, milliseconds: d.milliseconds * n, }; } // Conversions // "Rough" because they are based on average-case Gregorian months/years function asRoughYears(dur) { return asRoughDays(dur) / 365; } function asRoughMonths(dur) { return asRoughDays(dur) / 30; } function asRoughDays(dur) { return asRoughMs(dur) / 864e5; } function asRoughMinutes(dur) { return asRoughMs(dur) / (1000 * 60); } function asRoughSeconds(dur) { return asRoughMs(dur) / 1000; } function asRoughMs(dur) { return dur.years * (365 * 864e5) + dur.months * (30 * 864e5) + dur.days * 864e5 + dur.milliseconds; } // Advanced Math function wholeDivideDurations(numerator, denominator) { var res = null; for (var i = 0; i < INTERNAL_UNITS.length; i += 1) { var unit = INTERNAL_UNITS[i]; if (denominator[unit]) { var localRes = numerator[unit] / denominator[unit]; if (!isInt(localRes) || (res !== null && res !== localRes)) { return null; } res = localRes; } else if (numerator[unit]) { // needs to divide by something but can't! return null; } } return res; } function greatestDurationDenominator(dur) { var ms = dur.milliseconds; if (ms) { if (ms % 1000 !== 0) { return { unit: 'millisecond', value: ms }; } if (ms % (1000 * 60) !== 0) { return { unit: 'second', value: ms / 1000 }; } if (ms % (1000 * 60 * 60) !== 0) { return { unit: 'minute', value: ms / (1000 * 60) }; } if (ms) { return { unit: 'hour', value: ms / (1000 * 60 * 60) }; } } if (dur.days) { if (dur.specifiedWeeks && dur.days % 7 === 0) { return { unit: 'week', value: dur.days / 7 }; } return { unit: 'day', value: dur.days }; } if (dur.months) { return { unit: 'month', value: dur.months }; } if (dur.years) { return { unit: 'year', value: dur.years }; } return { unit: 'millisecond', value: 0 }; } // timeZoneOffset is in minutes function buildIsoString(marker, timeZoneOffset, stripZeroTime) { if (stripZeroTime === void 0) { stripZeroTime = false; } var s = marker.toISOString(); s = s.replace('.000', ''); if (stripZeroTime) { s = s.replace('T00:00:00Z', ''); } if (s.length > 10) { // time part wasn't stripped, can add timezone info if (timeZoneOffset == null) { s = s.replace('Z', ''); } else if (timeZoneOffset !== 0) { s = s.replace('Z', formatTimeZoneOffset(timeZoneOffset, true)); } // otherwise, its UTC-0 and we want to keep the Z } return s; } // formats the date, but with no time part // TODO: somehow merge with buildIsoString and stripZeroTime // TODO: rename. omit "string" function formatDayString(marker) { return marker.toISOString().replace(/T.*$/, ''); } // TODO: use Date::toISOString and use everything after the T? function formatIsoTimeString(marker) { return padStart(marker.getUTCHours(), 2) + ':' + padStart(marker.getUTCMinutes(), 2) + ':' + padStart(marker.getUTCSeconds(), 2); } function formatTimeZoneOffset(minutes, doIso) { if (doIso === void 0) { doIso = false; } var sign = minutes < 0 ? '-' : '+'; var abs = Math.abs(minutes); var hours = Math.floor(abs / 60); var mins = Math.round(abs % 60); if (doIso) { return sign + padStart(hours, 2) + ":" + padStart(mins, 2); } return "GMT" + sign + hours + (mins ? ":" + padStart(mins, 2) : ''); } // TODO: new util arrayify? function removeExact(array, exactVal) { var removeCnt = 0; var i = 0; while (i < array.length) { if (array[i] === exactVal) { array.splice(i, 1); removeCnt += 1; } else { i += 1; } } return removeCnt; } function isArraysEqual(a0, a1, equalityFunc) { if (a0 === a1) { return true; } var len = a0.length; var i; if (len !== a1.length) { // not array? or not same length? return false; } for (i = 0; i < len; i += 1) { if (!(equalityFunc ? equalityFunc(a0[i], a1[i]) : a0[i] === a1[i])) { return false; } } return true; } function memoize(workerFunc, resEquality, teardownFunc) { var currentArgs; var currentRes; return function () { var newArgs = []; for (var _i = 0; _i < arguments.length; _i++) { newArgs[_i] = arguments[_i]; } if (!currentArgs) { currentRes = workerFunc.apply(this, newArgs); } else if (!isArraysEqual(currentArgs, newArgs)) { if (teardownFunc) { teardownFunc(currentRes); } var res = workerFunc.apply(this, newArgs); if (!resEquality || !resEquality(res, currentRes)) { currentRes = res; } } currentArgs = newArgs; return currentRes; }; } function memoizeObjArg(workerFunc, resEquality, teardownFunc) { var _this = this; var currentArg; var currentRes; return function (newArg) { if (!currentArg) { currentRes = workerFunc.call(_this, newArg); } else if (!isPropsEqual(currentArg, newArg)) { if (teardownFunc) { teardownFunc(currentRes); } var res = workerFunc.call(_this, newArg); if (!resEquality || !resEquality(res, currentRes)) { currentRes = res; } } currentArg = newArg; return currentRes; }; } function memoizeArraylike(// used at all? workerFunc, resEquality, teardownFunc) { var _this = this; var currentArgSets = []; var currentResults = []; return function (newArgSets) { var currentLen = currentArgSets.length; var newLen = newArgSets.length; var i = 0; for (; i < currentLen; i += 1) { if (!newArgSets[i]) { // one of the old sets no longer exists if (teardownFunc) { teardownFunc(currentResults[i]); } } else if (!isArraysEqual(currentArgSets[i], newArgSets[i])) { if (teardownFunc) { teardownFunc(currentResults[i]); } var res = workerFunc.apply(_this, newArgSets[i]); if (!resEquality || !resEquality(res, currentResults[i])) { currentResults[i] = res; } } } for (; i < newLen; i += 1) { currentResults[i] = workerFunc.apply(_this, newArgSets[i]); } currentArgSets = newArgSets; currentResults.splice(newLen); // remove excess return currentResults; }; } function memoizeHashlike(workerFunc, resEquality, teardownFunc) { var _this = this; var currentArgHash = {}; var currentResHash = {}; return function (newArgHash) { var newResHash = {}; for (var key in newArgHash) { if (!currentResHash[key]) { newResHash[key] = workerFunc.apply(_this, newArgHash[key]); } else if (!isArraysEqual(currentArgHash[key], newArgHash[key])) { if (teardownFunc) { teardownFunc(currentResHash[key]); } var res = workerFunc.apply(_this, newArgHash[key]); newResHash[key] = (resEquality && resEquality(res, currentResHash[key])) ? currentResHash[key] : res; } else { newResHash[key] = currentResHash[key]; } } currentArgHash = newArgHash; currentResHash = newResHash; return newResHash; }; } var EXTENDED_SETTINGS_AND_SEVERITIES = { week: 3, separator: 0, omitZeroMinute: 0, meridiem: 0, omitCommas: 0, }; var STANDARD_DATE_PROP_SEVERITIES = { timeZoneName: 7, era: 6, year: 5, month: 4, day: 2, weekday: 2, hour: 1, minute: 1, second: 1, }; var MERIDIEM_RE = /\s*([ap])\.?m\.?/i; // eats up leading spaces too var COMMA_RE = /,/g; // we need re for globalness var MULTI_SPACE_RE = /\s+/g; var LTR_RE = /\u200e/g; // control character var UTC_RE = /UTC|GMT/; var NativeFormatter = /** @class */ (function () { function NativeFormatter(formatSettings) { var standardDateProps = {}; var extendedSettings = {}; var severity = 0; for (var name_1 in formatSettings) { if (name_1 in EXTENDED_SETTINGS_AND_SEVERITIES) { extendedSettings[name_1] = formatSettings[name_1]; severity = Math.max(EXTENDED_SETTINGS_AND_SEVERITIES[name_1], severity); } else { standardDateProps[name_1] = formatSettings[name_1]; if (name_1 in STANDARD_DATE_PROP_SEVERITIES) { // TODO: what about hour12? no severity severity = Math.max(STANDARD_DATE_PROP_SEVERITIES[name_1], severity); } } } this.standardDateProps = standardDateProps; this.extendedSettings = extendedSettings; this.severity = severity; this.buildFormattingFunc = memoize(buildFormattingFunc); } NativeFormatter.prototype.format = function (date, context) { return this.buildFormattingFunc(this.standardDateProps, this.extendedSettings, context)(date); }; NativeFormatter.prototype.formatRange = function (start, end, context, betterDefaultSeparator) { var _a = this, standardDateProps = _a.standardDateProps, extendedSettings = _a.extendedSettings; var diffSeverity = computeMarkerDiffSeverity(start.marker, end.marker, context.calendarSystem); if (!diffSeverity) { return this.format(start, context); } var biggestUnitForPartial = diffSeverity; if (biggestUnitForPartial > 1 && // the two dates are different in a way that's larger scale than time (standardDateProps.year === 'numeric' || standardDateProps.year === '2-digit') && (standardDateProps.month === 'numeric' || standardDateProps.month === '2-digit') && (standardDateProps.day === 'numeric' || standardDateProps.day === '2-digit')) { biggestUnitForPartial = 1; // make it look like the dates are only different in terms of time } var full0 = this.format(start, context); var full1 = this.format(end, context); if (full0 === full1) { return full0; } var partialDateProps = computePartialFormattingOptions(standardDateProps, biggestUnitForPartial); var partialFormattingFunc = buildFormattingFunc(partialDateProps, extendedSettings, context); var partial0 = partialFormattingFunc(start); var partial1 = partialFormattingFunc(end); var insertion = findCommonInsertion(full0, partial0, full1, partial1); var separator = extendedSettings.separator || betterDefaultSeparator || context.defaultSeparator || ''; if (insertion) { return insertion.before + partial0 + separator + partial1 + insertion.after; } return full0 + separator + full1; }; NativeFormatter.prototype.getLargestUnit = function () { switch (this.severity) { case 7: case 6: case 5: return 'year'; case 4: return 'month'; case 3: return 'week'; case 2: return 'day'; default: return 'time'; // really? } }; return NativeFormatter; }()); function buildFormattingFunc(standardDateProps, extendedSettings, context) { var standardDatePropCnt = Object.keys(standardDateProps).length; if (standardDatePropCnt === 1 && standardDateProps.timeZoneName === 'short') { return function (date) { return (formatTimeZoneOffset(date.timeZoneOffset)); }; } if (standardDatePropCnt === 0 && extendedSettings.week) { return function (date) { return (formatWeekNumber(context.computeWeekNumber(date.marker), context.weekText, context.weekTextLong, context.locale, extendedSettings.week)); }; } return buildNativeFormattingFunc(standardDateProps, extendedSettings, context); } function buildNativeFormattingFunc(standardDateProps, extendedSettings, context) { standardDateProps = __assign({}, standardDateProps); // copy extendedSettings = __assign({}, extendedSettings); // copy sanitizeSettings(standardDateProps, extendedSettings); standardDateProps.timeZone = 'UTC'; // we leverage the only guaranteed timeZone for our UTC markers var normalFormat = new Intl.DateTimeFormat(context.locale.codes, standardDateProps); var zeroFormat; // needed? if (extendedSettings.omitZeroMinute) { var zeroProps = __assign({}, standardDateProps); delete zeroProps.minute; // seconds and ms were already considered in sanitizeSettings zeroFormat = new Intl.DateTimeFormat(context.locale.codes, zeroProps); } return function (date) { var marker = date.marker; var format; if (zeroFormat && !marker.getUTCMinutes()) { format = zeroFormat; } else { format = normalFormat; } var s = format.format(marker); return postProcess(s, date, standardDateProps, extendedSettings, context); }; } function sanitizeSettings(standardDateProps, extendedSettings) { // deal with a browser inconsistency where formatting the timezone // requires that the hour/minute be present. if (standardDateProps.timeZoneName) { if (!standardDateProps.hour) { standardDateProps.hour = '2-digit'; } if (!standardDateProps.minute) { standardDateProps.minute = '2-digit'; } } // only support short timezone names if (standardDateProps.timeZoneName === 'long') { standardDateProps.timeZoneName = 'short'; } // if requesting to display seconds, MUST display minutes if (extendedSettings.omitZeroMinute && (standardDateProps.second || standardDateProps.millisecond)) { delete extendedSettings.omitZeroMinute; } } function postProcess(s, date, standardDateProps, extendedSettings, context) { s = s.replace(LTR_RE, ''); // remove left-to-right control chars. do first. good for other regexes if (standardDateProps.timeZoneName === 'short') { s = injectTzoStr(s, (context.timeZone === 'UTC' || date.timeZoneOffset == null) ? 'UTC' : // important to normalize for IE, which does "GMT" formatTimeZoneOffset(date.timeZoneOffset)); } if (extendedSettings.omitCommas) { s = s.replace(COMMA_RE, '').trim(); } if (extendedSettings.omitZeroMinute) { s = s.replace(':00', ''); // zeroFormat doesn't always achieve this } // ^ do anything that might create adjacent spaces before this point, // because MERIDIEM_RE likes to eat up loading spaces if (extendedSettings.meridiem === false) { s = s.replace(MERIDIEM_RE, '').trim(); } else if (extendedSettings.meridiem === 'narrow') { // a/p s = s.replace(MERIDIEM_RE, function (m0, m1) { return m1.toLocaleLowerCase(); }); } else if (extendedSettings.meridiem === 'short') { // am/pm s = s.replace(MERIDIEM_RE, function (m0, m1) { return m1.toLocaleLowerCase() + "m"; }); } else if (extendedSettings.meridiem === 'lowercase') { // other meridiem transformers already converted to lowercase s = s.replace(MERIDIEM_RE, function (m0) { return m0.toLocaleLowerCase(); }); } s = s.replace(MULTI_SPACE_RE, ' '); s = s.trim(); return s; } function injectTzoStr(s, tzoStr) { var replaced = false; s = s.replace(UTC_RE, function () { replaced = true; return tzoStr; }); // IE11 doesn't include UTC/GMT in the original string, so append to end if (!replaced) { s += " " + tzoStr; } return s; } function formatWeekNumber(num, weekText, weekTextLong, locale, display) { var parts = []; if (display === 'long') { parts.push(weekTextLong); } else if (display === 'short' || display === 'narrow') { parts.push(weekText); } if (display === 'long' || display === 'short') { parts.push(' '); } parts.push(locale.simpleNumberFormat.format(num)); if (locale.options.direction === 'rtl') { // TODO: use control characters instead? parts.reverse(); } return parts.join(''); } // Range Formatting Utils // 0 = exactly the same // 1 = different by time // and bigger function computeMarkerDiffSeverity(d0, d1, ca) { if (ca.getMarkerYear(d0) !== ca.getMarkerYear(d1)) { return 5; } if (ca.getMarkerMonth(d0) !== ca.getMarkerMonth(d1)) { return 4; } if (ca.getMarkerDay(d0) !== ca.getMarkerDay(d1)) { return 2; } if (timeAsMs(d0) !== timeAsMs(d1)) { return 1; } return 0; } function computePartialFormattingOptions(options, biggestUnit) { var partialOptions = {}; for (var name_2 in options) { if (!(name_2 in STANDARD_DATE_PROP_SEVERITIES) || // not a date part prop (like timeZone) STANDARD_DATE_PROP_SEVERITIES[name_2] <= biggestUnit) { partialOptions[name_2] = options[name_2]; } } return partialOptions; } function findCommonInsertion(full0, partial0, full1, partial1) { var i0 = 0; while (i0 < full0.length) { var found0 = full0.indexOf(partial0, i0); if (found0 === -1) { break; } var before0 = full0.substr(0, found0); i0 = found0 + partial0.length; var after0 = full0.substr(i0); var i1 = 0; while (i1 < full1.length) { var found1 = full1.indexOf(partial1, i1); if (found1 === -1) { break; } var before1 = full1.substr(0, found1); i1 = found1 + partial1.length; var after1 = full1.substr(i1); if (before0 === before1 && after0 === after1) { return { before: before0, after: after0, }; } } } return null; } function expandZonedMarker(dateInfo, calendarSystem) { var a = calendarSystem.markerToArray(dateInfo.marker); return { marker: dateInfo.marker, timeZoneOffset: dateInfo.timeZoneOffset, array: a, year: a[0], month: a[1], day: a[2], hour: a[3], minute: a[4], second: a[5], millisecond: a[6], }; } function createVerboseFormattingArg(start, end, context, betterDefaultSeparator) { var startInfo = expandZonedMarker(start, context.calendarSystem); var endInfo = end ? expandZonedMarker(end, context.calendarSystem) : null; return { date: startInfo, start: startInfo, end: endInfo, timeZone: context.timeZone, localeCodes: context.locale.codes, defaultSeparator: betterDefaultSeparator || context.defaultSeparator, }; } /* TODO: fix the terminology of "formatter" vs "formatting func" */ /* At the time of instantiation, this object does not know which cmd-formatting system it will use. It receives this at the time of formatting, as a setting. */ var CmdFormatter = /** @class */ (function () { function CmdFormatter(cmdStr) { this.cmdStr = cmdStr; } CmdFormatter.prototype.format = function (date, context, betterDefaultSeparator) { return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(date, null, context, betterDefaultSeparator)); }; CmdFormatter.prototype.formatRange = function (start, end, context, betterDefaultSeparator) { return context.cmdFormatter(this.cmdStr, createVerboseFormattingArg(start, end, context, betterDefaultSeparator)); }; return CmdFormatter; }()); var FuncFormatter = /** @class */ (function () { function FuncFormatter(func) { this.func = func; } FuncFormatter.prototype.format = function (date, context, betterDefaultSeparator) { return this.func(createVerboseFormattingArg(date, null, context, betterDefaultSeparator)); }; FuncFormatter.prototype.formatRange = function (start, end, context, betterDefaultSeparator) { return this.func(createVerboseFormattingArg(start, end, context, betterDefaultSeparator)); }; return FuncFormatter; }()); function createFormatter(input) { if (typeof input === 'object' && input) { // non-null object return new NativeFormatter(input); } if (typeof input === 'string') { return new CmdFormatter(input); } if (typeof input === 'function') { return new FuncFormatter(input); } return null; } // base options // ------------ var BASE_OPTION_REFINERS = { navLinkDayClick: identity, navLinkWeekClick: identity, duration: createDuration, bootstrapFontAwesome: identity, buttonIcons: identity, customButtons: identity, defaultAllDayEventDuration: createDuration, defaultTimedEventDuration: createDuration, nextDayThreshold: createDuration, scrollTime: createDuration, scrollTimeReset: Boolean, slotMinTime: createDuration, slotMaxTime: createDuration, dayPopoverFormat: createFormatter, slotDuration: createDuration, snapDuration: createDuration, headerToolbar: identity, footerToolbar: identity, defaultRangeSeparator: String, titleRangeSeparator: String, forceEventDuration: Boolean, dayHeaders: Boolean, dayHeaderFormat: createFormatter, dayHeaderClassNames: identity, dayHeaderContent: identity, dayHeaderDidMount: identity, dayHeaderWillUnmount: identity, dayCellClassNames: identity, dayCellContent: identity, dayCellDidMount: identity, dayCellWillUnmount: identity, initialView: String, aspectRatio: Number, weekends: Boolean, weekNumberCalculation: identity, weekNumbers: Boolean, weekNumberClassNames: identity, weekNumberContent: identity, weekNumberDidMount: identity, weekNumberWillUnmount: identity, editable: Boolean, viewClassNames: identity, viewDidMount: identity, viewWillUnmount: identity, nowIndicator: Boolean, nowIndicatorClassNames: ident