aboutsummaryrefslogblamecommitdiffstats
path: root/library/fullcalendar/packages/rrule/index.global.js
blob: 795d352b5387c32b23048f809e2ca17d4f6997cc (plain) (tree)
















































































































































                                                                                                                                                                                                                                         
/*!
FullCalendar RRule Plugin v6.0.3
Docs & License: https://fullcalendar.io/docs/rrule-plugin
(c) 2022 Adam Shaw
*/
FullCalendar.RRule = (function (exports, core, rrule, internal) {
    'use strict';

    const recurringType = {
        parse(eventProps, dateEnv) {
            if (eventProps.rrule != null) {
                let eventRRuleData = parseEventRRule(eventProps, dateEnv);
                if (eventRRuleData) {
                    return {
                        typeData: { rruleSet: eventRRuleData.rruleSet, isTimeZoneSpecified: eventRRuleData.isTimeZoneSpecified },
                        allDayGuess: !eventRRuleData.isTimeSpecified,
                        duration: eventProps.duration,
                    };
                }
            }
            return null;
        },
        expand(eventRRuleData, framingRange, dateEnv) {
            let dates;
            if (eventRRuleData.isTimeZoneSpecified) {
                dates = eventRRuleData.rruleSet.between(dateEnv.toDate(framingRange.start), // rrule lib will treat as UTC-zoned
                dateEnv.toDate(framingRange.end), // (same)
                true).map((date) => dateEnv.createMarker(date)); // convert UTC-zoned-date to locale datemarker
            }
            else {
                // when no timezone in given start/end, the rrule lib will assume UTC,
                // which is same as our DateMarkers. no need to manipulate
                dates = eventRRuleData.rruleSet.between(framingRange.start, framingRange.end, true);
            }
            return dates;
        },
    };
    function parseEventRRule(eventProps, dateEnv) {
        let rruleSet;
        let isTimeSpecified = false;
        let isTimeZoneSpecified = false;
        if (typeof eventProps.rrule === 'string') {
            let res = parseRRuleString(eventProps.rrule);
            rruleSet = res.rruleSet;
            isTimeSpecified = res.isTimeSpecified;
            isTimeZoneSpecified = res.isTimeZoneSpecified;
        }
        if (typeof eventProps.rrule === 'object' && eventProps.rrule) { // non-null object
            let res = parseRRuleObject(eventProps.rrule, dateEnv);
            rruleSet = new rrule.RRuleSet();
            rruleSet.rrule(res.rrule);
            isTimeSpecified = res.isTimeSpecified;
            isTimeZoneSpecified = res.isTimeZoneSpecified;
        }
        // convery to arrays. TODO: general util?
        let exdateInputs = [].concat(eventProps.exdate || []);
        let exruleInputs = [].concat(eventProps.exrule || []);
        for (let exdateInput of exdateInputs) {
            let res = internal.parseMarker(exdateInput);
            isTimeSpecified = isTimeSpecified || !res.isTimeUnspecified;
            isTimeZoneSpecified = isTimeZoneSpecified || res.timeZoneOffset !== null;
            rruleSet.exdate(new Date(res.marker.valueOf() - (res.timeZoneOffset || 0) * 60 * 1000));
        }
        // TODO: exrule is deprecated. what to do? (https://icalendar.org/iCalendar-RFC-5545/a-3-deprecated-features.html)
        for (let exruleInput of exruleInputs) {
            let res = parseRRuleObject(exruleInput, dateEnv);
            isTimeSpecified = isTimeSpecified || res.isTimeSpecified;
            isTimeZoneSpecified = isTimeZoneSpecified || res.isTimeZoneSpecified;
            rruleSet.exrule(res.rrule);
        }
        return { rruleSet, isTimeSpecified, isTimeZoneSpecified };
    }
    function parseRRuleObject(rruleInput, dateEnv) {
        let isTimeSpecified = false;
        let isTimeZoneSpecified = false;
        function processDateInput(dateInput) {
            if (typeof dateInput === 'string') {
                let markerData = internal.parseMarker(dateInput);
                if (markerData) {
                    isTimeSpecified = isTimeSpecified || !markerData.isTimeUnspecified;
                    isTimeZoneSpecified = isTimeZoneSpecified || markerData.timeZoneOffset !== null;
                    return new Date(markerData.marker.valueOf() - (markerData.timeZoneOffset || 0) * 60 * 1000); // NOT DRY
                }
                return null;
            }
            return dateInput; // TODO: what about number timestamps?
        }
        let rruleOptions = Object.assign(Object.assign({}, rruleInput), { dtstart: processDateInput(rruleInput.dtstart), until: processDateInput(rruleInput.until), freq: convertConstant(rruleInput.freq), wkst: rruleInput.wkst == null
                ? (dateEnv.weekDow - 1 + 7) % 7 // convert Sunday-first to Monday-first
                : convertConstant(rruleInput.wkst), byweekday: convertConstants(rruleInput.byweekday) });
        return { rrule: new rrule.RRule(rruleOptions), isTimeSpecified, isTimeZoneSpecified };
    }
    function parseRRuleString(str) {
        let rruleSet = rrule.rrulestr(str, { forceset: true });
        let analysis = analyzeRRuleString(str);
        return Object.assign({ rruleSet }, analysis);
    }
    function analyzeRRuleString(str) {
        let isTimeSpecified = false;
        let isTimeZoneSpecified = false;
        function processMatch(whole, introPart, datePart) {
            let result = internal.parseMarker(datePart);
            isTimeSpecified = isTimeSpecified || !result.isTimeUnspecified;
            isTimeZoneSpecified = isTimeZoneSpecified || result.timeZoneOffset !== null;
        }
        str.replace(/\b(DTSTART:)([^\n]*)/, processMatch);
        str.replace(/\b(EXDATE:)([^\n]*)/, processMatch);
        str.replace(/\b(UNTIL=)([^;\n]*)/, processMatch);
        return { isTimeSpecified, isTimeZoneSpecified };
    }
    function convertConstants(input) {
        if (Array.isArray(input)) {
            return input.map(convertConstant);
        }
        return convertConstant(input);
    }
    function convertConstant(input) {
        if (typeof input === 'string') {
            return rrule.RRule[input.toUpperCase()];
        }
        return input;
    }

    const RRULE_EVENT_REFINERS = {
        rrule: internal.identity,
        exrule: internal.identity,
        exdate: internal.identity,
        duration: internal.createDuration,
    };

    var plugin = core.createPlugin({
        name: '@fullcalendar/rrule',
        recurringTypes: [recurringType],
        eventRefiners: RRULE_EVENT_REFINERS,
    });

    core.globalPlugins.push(plugin);

    exports["default"] = plugin;

    Object.defineProperty(exports, '__esModule', { value: true });

    return exports;

})({}, FullCalendar, rrule, FullCalendar.Internal);