diff options
Diffstat (limited to 'library/fullcalendar/packages/icalendar/index.global.js')
-rw-r--r-- | library/fullcalendar/packages/icalendar/index.global.js | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/library/fullcalendar/packages/icalendar/index.global.js b/library/fullcalendar/packages/icalendar/index.global.js new file mode 100644 index 000000000..c92e09e54 --- /dev/null +++ b/library/fullcalendar/packages/icalendar/index.global.js @@ -0,0 +1,225 @@ +/*! +FullCalendar iCalendar Plugin v6.0.3 +Docs & License: https://fullcalendar.io/docs/icalendar +(c) 2022 Adam Shaw +*/ +FullCalendar.ICalendar = (function (exports, core, internal, ICAL) { + 'use strict'; + + function _interopNamespace(e) { + if (e && e.__esModule) return e; + var n = Object.create(null); + if (e) { + Object.keys(e).forEach(function (k) { + if (k !== 'default') { + var d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: function () { return e[k]; } + }); + } + }); + } + n["default"] = e; + return n; + } + + var ICAL__namespace = /*#__PURE__*/_interopNamespace(ICAL); + + /* eslint-disable */ + class IcalExpander { + constructor(opts) { + this.maxIterations = opts.maxIterations != null ? opts.maxIterations : 1000; + this.skipInvalidDates = opts.skipInvalidDates != null ? opts.skipInvalidDates : false; + this.jCalData = ICAL__namespace.parse(opts.ics); + this.component = new ICAL__namespace.Component(this.jCalData); + this.events = this.component.getAllSubcomponents('vevent').map(vevent => new ICAL__namespace.Event(vevent)); + if (this.skipInvalidDates) { + this.events = this.events.filter((evt) => { + try { + evt.startDate.toJSDate(); + evt.endDate.toJSDate(); + return true; + } + catch (err) { + // skipping events with invalid time + return false; + } + }); + } + } + between(after, before) { + function isEventWithinRange(startTime, endTime) { + return (!after || endTime >= after.getTime()) && + (!before || startTime <= before.getTime()); + } + function getTimes(eventOrOccurrence) { + const startTime = eventOrOccurrence.startDate.toJSDate().getTime(); + let endTime = eventOrOccurrence.endDate.toJSDate().getTime(); + // If it is an all day event, the end date is set to 00:00 of the next day + // So we need to make it be 23:59:59 to compare correctly with the given range + if (eventOrOccurrence.endDate.isDate && (endTime > startTime)) { + endTime -= 1; + } + return { startTime, endTime }; + } + const exceptions = []; + this.events.forEach((event) => { + if (event.isRecurrenceException()) + exceptions.push(event); + }); + const ret = { + events: [], + occurrences: [], + }; + this.events.filter(e => !e.isRecurrenceException()).forEach((event) => { + const exdates = []; + event.component.getAllProperties('exdate').forEach((exdateProp) => { + const exdate = exdateProp.getFirstValue(); + exdates.push(exdate.toJSDate().getTime()); + }); + // Recurring event is handled differently + if (event.isRecurring()) { + const iterator = event.iterator(); + let next; + let i = 0; + do { + i += 1; + next = iterator.next(); + if (next) { + const occurrence = event.getOccurrenceDetails(next); + const { startTime, endTime } = getTimes(occurrence); + const isOccurrenceExcluded = exdates.indexOf(startTime) !== -1; + // TODO check that within same day? + const exception = exceptions.find(ex => ex.uid === event.uid && ex.recurrenceId.toJSDate().getTime() === occurrence.startDate.toJSDate().getTime()); + // We have passed the max date, stop + if (before && startTime > before.getTime()) + break; + // Check that we are within our range + if (isEventWithinRange(startTime, endTime)) { + if (exception) { + ret.events.push(exception); + } + else if (!isOccurrenceExcluded) { + ret.occurrences.push(occurrence); + } + } + } + } while (next && (!this.maxIterations || i < this.maxIterations)); + return; + } + // Non-recurring event: + const { startTime, endTime } = getTimes(event); + if (isEventWithinRange(startTime, endTime)) + ret.events.push(event); + }); + return ret; + } + before(before) { + return this.between(undefined, before); + } + after(after) { + return this.between(after); + } + all() { + return this.between(); + } + } + + const eventSourceDef = { + parseMeta(refined) { + if (refined.url && refined.format === 'ics') { + return { + url: refined.url, + format: 'ics', + }; + } + return null; + }, + fetch(arg, successCallback, errorCallback) { + let meta = arg.eventSource.meta; + let { internalState } = meta; + /* + NOTE: isRefetch is a HACK. we would do the recurring-expanding in a separate plugin hook, + but we couldn't leverage built-in allDay-guessing, among other things. + */ + if (!internalState || arg.isRefetch) { + internalState = meta.internalState = { + response: null, + iCalExpanderPromise: fetch(meta.url, { method: 'GET' }).then((response) => { + return response.text().then((icsText) => { + internalState.response = response; + return new IcalExpander({ + ics: icsText, + skipInvalidDates: true, + }); + }); + }), + }; + } + internalState.iCalExpanderPromise.then((iCalExpander) => { + successCallback({ + rawEvents: expandICalEvents(iCalExpander, arg.range), + response: internalState.response, + }); + }, errorCallback); + }, + }; + function expandICalEvents(iCalExpander, range) { + // expand the range. because our `range` is timeZone-agnostic UTC + // or maybe because ical.js always produces dates in local time? i forget + let rangeStart = internal.addDays(range.start, -1); + let rangeEnd = internal.addDays(range.end, 1); + let iCalRes = iCalExpander.between(rangeStart, rangeEnd); // end inclusive. will give extra results + let expanded = []; + // TODO: instead of using startDate/endDate.toString to communicate allDay, + // we can query startDate/endDate.isDate. More efficient to avoid formatting/reparsing. + // single events + for (let iCalEvent of iCalRes.events) { + expanded.push(Object.assign(Object.assign({}, buildNonDateProps(iCalEvent)), { start: iCalEvent.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalEvent.endDate) + ? iCalEvent.endDate.toString() + : null })); + } + // recurring event instances + for (let iCalOccurence of iCalRes.occurrences) { + let iCalEvent = iCalOccurence.item; + expanded.push(Object.assign(Object.assign({}, buildNonDateProps(iCalEvent)), { start: iCalOccurence.startDate.toString(), end: (specifiesEnd(iCalEvent) && iCalOccurence.endDate) + ? iCalOccurence.endDate.toString() + : null })); + } + return expanded; + } + function buildNonDateProps(iCalEvent) { + return { + title: iCalEvent.summary, + url: extractEventUrl(iCalEvent), + extendedProps: { + location: iCalEvent.location, + organizer: iCalEvent.organizer, + description: iCalEvent.description, + }, + }; + } + function extractEventUrl(iCalEvent) { + let urlProp = iCalEvent.component.getFirstProperty('url'); + return urlProp ? urlProp.getFirstValue() : ''; + } + function specifiesEnd(iCalEvent) { + return Boolean(iCalEvent.component.getFirstProperty('dtend')) || + Boolean(iCalEvent.component.getFirstProperty('duration')); + } + + var plugin = core.createPlugin({ + name: '@fullcalendar/icalendar', + eventSourceDefs: [eventSourceDef], + }); + + core.globalPlugins.push(plugin); + + exports["default"] = plugin; + + Object.defineProperty(exports, '__esModule', { value: true }); + + return exports; + +})({}, FullCalendar, FullCalendar.Internal, ICAL); |