### Install Prerequisites Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Ensure all necessary prerequisites for running tests are installed by executing npm install. ```shell npm install ``` -------------------------------- ### Install ical.js via npm Source: https://github.com/kewisch/ical.js/blob/main/README.md Install the ical.js library using npm for Node.js projects. ```bash npm install ical.js ``` -------------------------------- ### Example Generated RRULE Source: https://github.com/kewisch/ical.js/blob/main/tools/ICALTester/README.md Shows a possible output RRULE string generated based on the rules.json example. ```text RRULE:FREQ=MONTHLY;BYMONTHDAY=1,15,17,20,31 ``` -------------------------------- ### Example libical-recur Usage Source: https://github.com/kewisch/ical.js/blob/main/tools/ICALTester/README.md Demonstrates how the comparison binary should be invoked and the expected output format for recurrence rules. ```bash # Usage: ./support/libical-recur $ ./support/libical-recur "FREQ=MONTHLY;BYDAY=1FR,3SU" "2014-11-11T08:00:00" 10 20141116T080000 20141205T080000 20141221T080000 20150102T080000 20150118T080000 20150206T080000 20150215T080000 20150306T080000 20150315T080000 20150403T080000 ``` -------------------------------- ### Example rules.json Structure Source: https://github.com/kewisch/ical.js/blob/main/tools/ICALTester/README.md Illustrates the format for defining recurrence rules in JSON, including the use of '%' for random value generation. ```json [ { "freq": "MONTHLY", "bymonthday": "%" } ] ``` -------------------------------- ### Import ical.js in Node.js Source: https://github.com/kewisch/ical.js/blob/main/README.md Import the ical.js library after installing it via npm for use in Node.js. ```javascript import ICAL from "ical.js"; ``` -------------------------------- ### iCalendar Data Example Source: https://github.com/kewisch/ical.js/wiki/Home An example of iCalendar data in the standard RFC5545 format. ```ics BEGIN:VCALENDAR CALSCALE:GREGORIAN PRODID:-//Example Inc.//Example Calendar//EN VERSION:2.0 BEGIN:VEVENT DTSTAMP:20080205T191224Z DTSTART:20081006 SUMMARY:Planning meeting UID:4088E990AD89CB3DBB484909 END:VEVENT END:VCALENDAR ``` -------------------------------- ### node-ical JSON Data Structure Source: https://github.com/kewisch/ical.js/wiki/Migrating-from-Other-Libraries Example of the JSON output structure produced by node-ical for an event with an alarm. ```json { "eb9e1bd2-ceba-499f-be77-f02773954c72": { "type": "VEVENT", "params": [], "uid": "eb9e1bd2-ceba-499f-be77-f02773954c72", "summary": "Event with an alarm", "description": "This is an event with an alarm.", "attendee": [ { "params": { "PARTSTAT": "ACCEPTED" }, "val": "MAILTO:attendee1@example.com" }, { "params": { "PARTSTAT": "ACCEPTED" }, "val": "MAILTO:attendee2@example.com" } ], "start": "2013-04-18T09:00:00.000Z", "end": "2013-04-18T10:00:00.000Z", "status": "CONFIRMED", "class": "PUBLIC", "transparency": "OPAQUE", "lastmodified": "2013-04-18T17:56:32.000Z", "dtstamp": "2013-04-18T17:56:32.000Z", "sequence": "3", "61170.614696615514": { "type": "VALARM", "params": [], "action": "DISPLAY", "trigger": { "params": { "RELATED": "START" }, "val": "-PT5M" }, "description": "Reminder" } } } ``` -------------------------------- ### Expand Recurring Events with RecurExpansion Source: https://github.com/kewisch/ical.js/wiki/Parsing-iCalendar Use the RecurExpansion class to iterate through occurrences of a recurring event, considering recurrence rules, exceptions (RDATE, EXDATE), and count limits. Expansion starts from the event's start date. ```javascript let expand = new ICAL.RecurExpansion({ component: vevent, dtstart: vevent.getFirstPropertyValue('dtstart') }); // next is always an ICAL.Time or null let next; while (someCondition && (next = expand.next())) { // do something with next } ``` -------------------------------- ### Parse iCalendar Data and Extract VEVENT Source: https://github.com/kewisch/ical.js/wiki/Parsing-iCalendar Use ICAL.parse to get calendar data and then extract specific VEVENT components and their properties like summary, UID, and description. It also shows how to get start and end dates as JavaScript Date objects. ```javascript var jCalData = ICAL.parse(someICalData); var comp = new ICAL.Component(jCalData[1]); // Fetch the VEVENT part var vevent = comp.getFirstSubcomponent('vevent'); var event = new ICAL.Event(vevent); console.log(event.summary, event.uid, event.description); // Get start and end dates as local time on current machine console.log(event.startDate.toJSDate(), event.endDate.toJSDate()); ``` -------------------------------- ### ICAL.js jCal Data Structure Source: https://github.com/kewisch/ical.js/wiki/Migrating-from-Other-Libraries Example of the jCal output structure produced by ICAL.js for an event with an alarm. ```json ["vcalendar", [], [ ["vevent", [ [ "uid", {}, "text", "eb9e1bd2-ceba-499f-be77-f02773954c72" ], [ "summary", {}, "text", "Event with an alarm" ], [ "description", {}, "text", "This is an event with an alarm." ], [ "organizer", {}, "cal-address", "MAILTO:organizer@example.com" ], [ "attendee", { "partstat": "ACCEPTED" }, "cal-address", "MAILTO:attendee1@example.com" ], [ "attendee", { "partstat": "ACCEPTED" }, "cal-address", "MAILTO:attendee2@example.com" ], [ "dtstart", { "tzid": "America/Los_Angeles" }, "date-time", "2013-04-18T11:00:00" ], [ "dtend", { "tzid": "America/Los_Angeles" }, "date-time", "2013-04-18T12:00:00" ], [ "status", {}, "text", "CONFIRMED" ], [ "class", {}, "text", "PUBLIC" ], [ "transp", {}, "text", "OPAQUE" ], [ "last-modified", {}, "date-time", "2013-04-18T17:56:32Z" ], [ "dtstamp", {}, "date-time", "2013-04-18T17:56:32Z" ], [ "sequence", {}, "integer", 3 ] ], [ ["valarm", [ [ "action", {}, "text", "DISPLAY" ], [ "trigger", { "related": "START" }, "duration", "-PT5M" ], [ "description", {}, "text", "Reminder" ] ], [] ] ] ] ] ] ] ``` -------------------------------- ### Expand Recurring Events with RecurExpansion Source: https://github.com/kewisch/ical.js/wiki/Common-Use-Cases Use `RecurExpansion` for a higher-level abstraction to iterate through recurring event occurrences within a specified date range. You may need to skip occurrences before your desired start date. ```javascript let expand = new ICAL.RecurExpansion({ component: event, dtstart: event.getFirstPropertyValue('dtstart') }); let rangeStart = ICAL.Time.fromString("2013-04-19T00:00:00"); let rangeEnd = ICAL.Time.fromString("2013-04-21T00:00:00"); let next = iterator.next() for (let next = iterator.next(); next && next.compare(rangeEnd) < 0; next = iterator.next()) { if (next.compare(rangeStart) < 0) { continue; } // Do something with the date } ``` -------------------------------- ### Iterate RRULE with Recurrence Iterator Source: https://github.com/kewisch/ical.js/wiki/Parsing-iCalendar Access the recurrence iterator directly from an RRULE component to iterate through occurrences based on the rule and a starting datetime. The loop continues until the iterator is completed. ```javascript let rrule = vevent.getFirstProperty('rrule'); let dtstart = vevent.getFirstPropertyValue('dtstart') let iter = rrule.iterator(dtstart) let next; for (let next = iter.next(); next && !iter.completed; next = iter.next()) { // do something with next } ``` -------------------------------- ### Run ICALTester Comparison Source: https://github.com/kewisch/ical.js/blob/main/tools/ICALTester/README.md Execute the comparison script with the rules file and the path to the comparison binary. ```bash $ node compare.js rules.json ./support/libical-recur ``` -------------------------------- ### Initialize Date Inputs and Event Listener Source: https://github.com/kewisch/ical.js/blob/main/tools/recur-tester.html Sets up default date values for DTSTART and range inputs and attaches a submit event listener to the form. It imports the ICAL.js library. ```javascript import ICAL from "https://unpkg.com/ical.js"; document.addEventListener('DOMContentLoaded', function() { const now = new Date(); now.setMinutes(0); now.setSeconds(0); now.setMilliseconds(0); const oneMonthLater = new Date(now.getFullYear(), now.getMonth() + 1, now.getDate()); // Format dates for input fields const dtstartValue = now.toISOString().slice(0, 16); // Formats to YYYY-MM-DDTHH:MM const rangeEndValue = oneMonthLater.toISOString().slice(0, 16); // Formats to YYYY-MM-DDTHH:MM // Set default values document.getElementById('dtstart').value = dtstartValue; document.getElementById('rangeStart').value = dtstartValue; document.getElementById('rangeEnd').value = rangeEndValue; }); ``` -------------------------------- ### Run a Single Test in Node.js Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Execute a specific test file in Node.js by providing its path using the --test argument. ```shell grunt test-node:single --test=test/period_test.js # Run a single test (of any type) ``` -------------------------------- ### Run Specific Test Suites in Node.js Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Execute individual test suites (unit, acceptance, performance) separately in Node.js. ```shell grunt test-node:unit # Run all unit tests ``` ```shell grunt test-node:acceptance # Run all acceptance tests ``` ```shell grunt test-node:performance # Run all performance tests ``` -------------------------------- ### Run All Tests in Node.js Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Execute all test suites (performance, acceptance, unit) in the Node.js environment using grunt test-node. ```shell $ grunt test-node ``` -------------------------------- ### Run Code Coverage with Grunt Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Execute the `grunt coverage` command to generate code coverage reports. This command runs the unit tests and produces output detailing the test progress and coverage summary. ```shell $ grunt coverage Running "mocha_istanbul:coverage" (mocha_istanbul) task ․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․ ․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․ ․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․ ․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․․ 506 tests complete (5 seconds) ============================================================================= Writing coverage object [/Users/kewisch/mozilla/github/ical.js/coverage/coverage.json] Writing coverage reports at [/Users/kewisch/mozilla/github/ical.js/coverage] ============================================================================= =============================== Coverage summary =============================== Statements : 94.69% ( 2512/2653 ), 14 ignored Branches : 90.69% ( 1276/1407 ), 23 ignored Functions : 98.6% ( 351/356 ), 5 ignored Lines : 94.62% ( 2478/2619 ) ================================================================================ >> Done. Check coverage folder. Done, without errors. ``` -------------------------------- ### Import ICAL.js Library Source: https://github.com/kewisch/ical.js/blob/main/tools/validator.html Import the ICAL.js library from a CDN. This is required to use the parsing and stringifying functionalities. ```javascript import ICAL from "https://unpkg.com/ical.js"; ``` -------------------------------- ### Create iCalendar Component and Set Property Source: https://github.com/kewisch/ical.js/wiki/Convert-to-iCalendar-(rfc5545) Initializes a new iCalendar component and sets a product identifier property. ```javascript var comp = new ICAL.Component(['vcalendar', [], []]); comp.updatePropertyWithValue('prodid', '-//iCal.js Wiki Example'); comp.toString(); ``` -------------------------------- ### Parsing ICS and Accessing Event Data (node-ical vs ICAL.js) Source: https://github.com/kewisch/ical.js/wiki/Migrating-from-Other-Libraries Compares how to parse ICS input and access basic event properties like type and summary using node-ical and ICAL.js. ```javascript let data = ical.parseICS(input); let firstEvent = [...Object.values(data)][0]; div.querySelector(".type").textContent = firstEvent.type; div.querySelector(".title").textContent = firstEvent.summary; let recdates = firstEvent.rrule.between(rangeStart, rangeEnd, true, () => true); div.querySelector(".occurrences").textContent = recdates.map(dt => dt.toISOString()).join("\n"); ``` ```javascript let vcalendar = new ICAL.Component(ICAL.parse(input)); let vevent = vcalendar.getFirstSubcomponent("vevent"); let recur = vevent.getFirstPropertyValue("rrule"); let dtstart = vevent.getFirstPropertyValue("dtstart"); let iterator = recur.iterator(dtstart); div.querySelector(".type").textContent = vevent.name; div.querySelector(".title").textContent = vevent.getFirstProperty("summary"); let next, recdates = []; while ((next = iterator.next()) && next.compare(rangeEnd) < 0) { if (next.compare(rangeStart) < 0) { continue; } recdates.push(next); } div.querySelector(".occurrences").textContent = recdates.map(dt => dt.toString()).join("\n"); ``` -------------------------------- ### Run Tests in Browser Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Execute browser-based tests using the grunt test-browser command. ```shell $ grunt test-browser ``` -------------------------------- ### Expand Recurring Events via Components and Properties Source: https://github.com/kewisch/ical.js/wiki/Common-Use-Cases Manually iterate through RRULEs, RDATEs, and EXDATEs for granular control over recurring event expansion. Ensure you use the event's DTSTART for iterator calculations. This method requires you to manage date and exception logic yourself. ```javascript let vcalendar = new ICAL.Component(ICAL.parse(ics)); let vevent = vcalendar.getFirstSubcomponent("vevent"); // Let's start with RRULEs let recur = vevent.getFirstPropertyValue("rrule"); // When creating the iterator, you must use the DTSTART of the event, it is used for the basis of some calculations let dtstart = vevent.getFirstPropertyValue("dtstart"); let iterator = recur.iterator(dtstart); let rangeStart = ICAL.Time.fromString("2013-04-19T00:00:00"); let rangeEnd = ICAL.Time.fromString("2013-04-21T00:00:00"); // Iterate through the start dates in the range. let next = iterator.next() for (let next = iterator.next(); next && next.compare(rangeEnd) < 0; next = iterator.next()) { if (next.compare(rangeStart) < 0) { continue; } // Do something with the date } // Now grab some RDATEs (additional occurrences) and EXDATEs (removed occurrences) let rdates = vevent.getAllProperties("rdate").reduce((acc, prop) => acc.concat(prop.getValues())); let exdates = vevent.getAllProperties("rdate").reduce((acc, prop) => acc.concat(prop.getValues())); // Do somthing with the dates ``` -------------------------------- ### Create Multi-value EXDATE Property Source: https://github.com/kewisch/ical.js/wiki/Convert-to-iCalendar-(rfc5545) Illustrates the creation of a multi-value EXDATE property in iCalendar format, setting multiple dates for exceptions. ```javascript const times = [new ICAL.Time({year: 2020}), new ICAL.Time({year: 2021})]; const vevent = new ICAL.Component('vevent'); const exdate = new ICAL.Property('exdate'); exdate.setValues(times); vevent.addProperty(exdate); exdate.toICALString(); ``` -------------------------------- ### Registering and Using Time Zones in ICAL.js Source: https://github.com/kewisch/ical.js/wiki/Common-Use-Cases Demonstrates how to register custom time zones (Europe/Berlin and America/Los_Angeles) using the TimezoneService and then convert dates between these registered time zones. This is useful when your application already provides time zone information. ```javascript // We're going to start by registering a few time zones. You'll want to import these from the IANA database. let berlinComp = new ICAL.Component(ICAL.parse(` BEGIN:VTIMEZONE TZID:Europe/Berlin X-LIC-LOCATION:Europe/Berlin BEGIN:DAYLIGHT TZOFFSETFROM:+0100 TZOFFSETTO:+0200 TZNAME:CEST DTSTART:19700329T020000 RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:+0200 TZOFFSETTO:+0100 TZNAME:CET DTSTART:19701025T030000 RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU END:STANDARD END:VTIMEZONE`)); ICAL.TimezoneService.register("Europe/Berlin", new ICAL.Timezone({ component: berlinComp, tzid: "Europe/Berlin" })); let losAngelesComp = new ICAL.Component(ICAL.parse( `BEGIN:VTIMEZONE TZID:America/Los_Angeles X-LIC-LOCATION:America/Los_Angeles BEGIN:DAYLIGHT TZOFFSETFROM:-0800 TZOFFSETTO:-0700 TZNAME:PDT DTSTART:19700308T020000 RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU END:DAYLIGHT BEGIN:STANDARD TZOFFSETFROM:-0700 TZOFFSETTO:-0800 TZNAME:PST DTSTART:19701101T020000 RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU END:STANDARD END:VTIMEZONE`)); ICAL.TimezoneService.register("America/Los_Angeles", new ICAL.Timezone({ component: losAngelesComp, tzid: "America/Los_Angeles" })); // You can grab a time with a time zone from a property value let property = ICAL.Property.fromString("DTSTART;TZID=Europe/Berlin:20240102T030405"); let fromDate = property.getFirstValue(); let toDate = fromDate.convertToZone(ICAL.TimezoneService.get("America/Los_Angeles")); console.log(fromDate.toString(), "->", toDate.toString()); /* 2024-01-02T03:04:05 -> 2024-01-01T18:04:05 */ // If you convert a local time to a time zone, it will assign the time zone fromDate = ICAL.Time.fromString("2024-03-04T10:11:12"); toDate = fromDate.convertToZone(ICAL.TimezoneService.get("America/Los_Angeles")); console.log(fromDate.toString(), "->", toDate.toString()); /* 2024-03-04T10:11:12 -> 2024-03-04T10:11:12 */ fromDate = toDate; toDate = fromDate.convertToZone(ICAL.TimezoneService.get("Europe/Berlin")); console.log(fromDate.toString(), "->", toDate.toString()); /* 2024-03-04T10:11:12 -> 2024-03-04T19:11:12 */ ``` -------------------------------- ### Manual Node-Inspector Access Source: https://github.com/kewisch/ical.js/wiki/Running-Tests If the automatic debugger connection fails, manually access the node-inspector UI via the provided URL. ```shell http://127.0.0.1:8080/debug?port=5858 ``` -------------------------------- ### Use ical.js in Browser with ES5 Script Tag Source: https://github.com/kewisch/ical.js/blob/main/README.md Include and use the ical.js library in a browser using a transpiled ES5 script tag. A button click triggers parsing of textarea content. ```html ``` -------------------------------- ### Access Summary Property using Component Model Source: https://github.com/kewisch/ical.js/wiki/Home Retrieves the summary property value from a vevent component using the Component Model Layer. ```javascript var comp = new ICAL.Component(jcalData); var vevent = comp.getFirstSubcomponent("vevent"); var summary = vevent.getFirstPropertyValue("summary"); ``` -------------------------------- ### Use ical.js in Browser with ES6 Module Source: https://github.com/kewisch/ical.js/blob/main/README.md Include and use the ical.js library in a browser using an ES6 module script tag. An event listener is attached to a button to parse textarea content. ```html ``` -------------------------------- ### Decorating and Undecorating Values Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Use `decorate()` and `undecorate()` functions to convert jCal data into rich objects (like `ICAL.Time` or `ICAL.Recur`) and vice-versa. These functions operate on jCal data, not raw iCalendar values. ```javascript var icalTime = ICAL.design.icalendar.value['date-time'].decorate("2014-01-02T03:04:05"); // Returns an ICAL.Time object ICAL.design.icalendar.value['date-time'].undecorate(icalTime); // Returns "2014-01-02T03:04:05" var icalRecur = ICAL.design.icalendar.value['recur'].decorate({ freq: "WEEKLY", count: 2 }); // Returns an ICAL.Recur object ICAL.design.icalendar.value['recur'].undecorate(icalRecur); // Returns { freq: "WEEKLY", count: 2 } ``` -------------------------------- ### Registering Custom Parameter Value Types Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Register custom parameter types with their valid values, X-Name, IANA token, or value type. Use this when defining new parameters not covered by the RFC. ```javascript ICAL.design.icalendar.param["myenumparam"] = { values: [ "FOO", "BAR" ], // [optional] An array of valid values for this parameter allowXName: true, // If true, X-Parameters are also allowed allowIanaToken: true // If true, other IANA tokens are also allowed }; ICAL.design.icalendar.param["mytypedparam"] = { valueType: "cal-address", // If set, the parameter must use this value type as a format multiValue: "," // The parameter can consist of multiple values itself, which will be an array }; ICAL.design.icalendar.param["mymultiparam"] = { valueType: "text", // If set, the parameter must use this value type as a format multiValue: ",", // The parameter can consist of multiple values itself, which will be an array multiValueSeparateDQuote: true // If true, double quotes enclose (multi-)values instead of the whole property. }; ``` -------------------------------- ### Registering a Multi-Value Property Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Register a property that accepts multiple comma-separated values. Each value will be converted into a separate jCal value. ```javascript ICAL.design.icalendar.property["x-my-multival"] = { defaultType: "text", // [required] The default type from ICAL.design.value multiValue: "," // [optional] This property takes multiple, comma-separated values // and turns each of them into a jCal value. }; ``` -------------------------------- ### Convert jCal Object to iCalendar String Source: https://github.com/kewisch/ical.js/wiki/Convert-to-iCalendar-(rfc5545) Demonstrates how to convert a jCal data structure directly into an iCalendar formatted string using ICAL.stringify. ```javascript var jCal = ["vcalendar", [ ["calscale", {}, "text", "GREGORIAN"], ["prodid", {}, "text", "-//Example Inc.//Example Calendar//EN"], ["version", {}, "text", "2.0"] ], [ ["vevent", [ ["dtstamp", {}, "date-time", "2008-02-05T19:12:24Z"], ["dtstart", {}, "date", "2008-10-06"], ["summary", {}, "text", "Planning meeting"], ["uid", {}, "text", "4088E990AD89CB3DBB484909"] ], [] ] ] ]; ICAL.stringify(jCal); ``` -------------------------------- ### Debug Tests in Node.js Source: https://github.com/kewisch/ical.js/wiki/Running-Tests Enable debugging for tests in Node.js by adding the --debug flag to the grunt command. This will open node-inspector in Chrome. ```shell grunt test-node:single --test=test/period_test.js --debug ``` -------------------------------- ### Access Summary Property using Item Model Source: https://github.com/kewisch/ical.js/wiki/Home Retrieves the summary property value from a vevent component using the Item Model Layer, which offers convenient access to common properties. ```javascript var comp = new ICAL.Component(jcalData); var vevent = comp.getFirstSubcomponent("vevent"); var event = new ICAL.Event(vevent); var summary = event.summary; ``` -------------------------------- ### Extract VTIMEZONE Component Source: https://github.com/kewisch/ical.js/wiki/Parsing-iCalendar This snippet demonstrates how to extract a VTIMEZONE component from parsed iCalendar data and create a Timezone object. ```javascript var vtz = comp.getFirstSubcomponent('vtimezone'), var tz = new ICAL.Timezone(vtz); ... ``` -------------------------------- ### Error Formatting Function Source: https://github.com/kewisch/ical.js/blob/main/tools/validator.html A utility function to format error objects into a readable string, including filename, line number, and stack trace if available. ```javascript function stringError(e) { return "Error: " + e + ("fileName" in e ? "\nFilename: " + e.fileName : "") + ("lineNumber" in e ? "\nLine: " + e.lineNumber : "") + ("stack" in e ? "\nStack: " + e.stack : ""); } ``` -------------------------------- ### Add Event Subcomponent to iCalendar Source: https://github.com/kewisch/ical.js/wiki/Convert-to-iCalendar-(rfc5545) Creates an event subcomponent, sets its properties, and adds it to the main calendar component. ```javascript var vevent = new ICAL.Component('vevent'), event = new ICAL.Event(vevent); // Set standard properties event.summary = 'foo bar'; event.uid = 'abcdef...'; event.startDate = ICAL.Time.now(); // Set custom property vevent.addPropertyWithValue('x-my-custom-property', 'custom'); // Add the new component comp.addSubcomponent(vevent); // Getting the full calendar now comp.toString(); ``` -------------------------------- ### Registering New Data Value Types Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Register a new data value type, typically for new RFC-defined types. This is a rare operation. ```javascript ICAL.design.icalendar.value["newvalue"] = { ... }; ``` -------------------------------- ### Handle Form Submission and Calculate Occurrences Source: https://github.com/kewisch/ical.js/blob/main/tools/recur-tester.html Processes form data, validates inputs, converts dates to ICAL.js Time objects, parses the RRULE, iterates through occurrences within the specified range, and displays the results. It also generates a JavaScript test case snippet. ```javascript document.getElementById("form").addEventListener("submit", (event) => { event.preventDefault(); let dtstart = new Date(document.getElementById('dtstart').value); let rruleString = document.getElementById('rrule').value; let rangeStart = new Date(document.getElementById('rangeStart').value); let rangeEnd = new Date(document.getElementById('rangeEnd').value); if (isNaN(dtstart.getTime()) || !rruleString || isNaN(rangeStart.getTime()) || isNaN(rangeEnd.getTime())) { alert('Please fill all fields correctly.'); return; } let icDtStart = ICAL.Time.fromJSDate(dtstart); let icRangeEnd = ICAL.Time.fromJSDate(rangeEnd); let icRangeStart = ICAL.Time.fromJSDate(rangeStart); if (rruleString.startsWith("RRULE;")) { rruleString = rruleString.substring(6); } let rrule = ICAL.Recur.fromString(`RRULE;${rruleString}`); let vevent = new ICAL.Component('vevent'); vevent.addPropertyWithValue('dtstart', icDtStart); vevent.addPropertyWithValue('rrule', rrule); let iter = rrule.iterator(icDtStart); let occurrences = []; let next; while ((next = iter.next())) { if (next.compare(icRangeStart) < 0) { continue; } else if (next.compare(icRangeEnd) > 0) { break; } occurrences.push(next.toString()); } console.log(dtstart, rangeStart); document.getElementById("testcase").textContent = `// \n` + `testRRULE('${rruleString}', {\n` + (dtstart.getTime() == rangeStart.getTime() ? "" : ` dtStart: '${icRangeStart.toString()}',\n` ) + " dates: [\n" + ` '${occurrences.join("',\n '")}'\n` + " ]\n" + "});"; document.getElementById('occurrences').textContent = occurrences.join('\n'); }); ``` -------------------------------- ### Converting Between iCalendar and jCal Values Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Use `fromICAL()` and `toICAL()` functions to convert property values between iCalendar and jCal formats for specific value types like 'date-time' and 'recur'. ```javascript ICAL.design.icalendar.value['date-time'].fromICAL("20140102T030405"); // "2014-01-02T03:04:05" ICAL.design.icalendar.value['date-time'].toICAL("2014-01-02T03:04:05"); // "20140102T030405" ICAL.design.icalendar.value['recur'].fromICAL("FREQ=WEEKLY;COUNT=2"); // { freq: "WEEKLY", count: 2 } ICAL.design.icalendar.value['recur'].toICAL({ freq: "WEEKLY", count: 2 }); // "FREQ=WEEKLY;COUNT=2" ``` -------------------------------- ### Registering a New Text Property Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Use this to register a new custom property with a default text type. The jCal representation will be a simple array with the property name, an empty object for parameters, the type, and the value. ```javascript ICAL.design.icalendar.property["x-my-property"] = { defaultType: "text", // [required] The default type from ICAL.design.value allowedTypes: ["period", "text"], // [optional] Valid value types this property can have (currently unused) detectType: function(value) { ... } // [optional] A function called to determine which type the value is }; ``` -------------------------------- ### Registering a Structured Value Property Source: https://github.com/kewisch/ical.js/wiki/Parser-Design-Data Register a property that uses a semicolon as a separator for structured values. These values are grouped into a single jCal value. ```javascript ICAL.design.icalendar.property["x-my-structuredval"] = { defaultType: "text", // [required] The default type from ICAL.design.value structuredValue: ";" // [optional] This property takes multiple, semicolon-separated values // and turns them into a single jCal value. }; ``` -------------------------------- ### jCal Data Representation Source: https://github.com/kewisch/ical.js/wiki/Home The structure of jCal data after parsing an iCalendar string, representing calendar components and properties. ```javascript ["vcalendar", [ ["calscale", {}, "text", "GREGORIAN"], ["prodid", {}, "text", "-//Example Inc.//Example Calendar//EN"], ["version", {}, "text", "2.0"] ], [ ["vevent", [ ["dtstamp", {}, "date-time", "2008-02-05T19:12:24Z"], ["dtstart", {}, "date", "2008-10-06"], ["summary", {}, "text", "Planning meeting"], ["uid", {}, "text", "4088E990AD89CB3DBB484909"] ], [] ] ] ] ``` -------------------------------- ### Validator Function Source: https://github.com/kewisch/ical.js/blob/main/tools/validator.html The main validation function that parses input data (either iCalendar or jCal), converts it to the other format, and re-serializes it. It also measures and displays the execution time. ```javascript window.validate = function validate() { let duration = document.getElementById("duration"); let data = document.getElementById("data"); let error = document.getElementById("error"); let jcalres = document.getElementById("jcal"); let icalres = document.getElementById("ical"); duration.textContent = ''; error.textContent = jcalres.textContent = icalres.textContent = ""; let beginTime = Date.now(); let jcal, ical, from; try { jcal = JSON.parse(data.value); from = "json"; } catch (jsonerr) { try { jcal = ICAL.parse(data.value); from = "ical"; } catch (icalerr) { error.textContent = "Couldn't parse as iCalendar:\n" + stringError(icalerr) + "\n\nNor as jCal:\n" + stringError(jsonerr); } } if (from == "json") { ical = ICAL.stringify(jcal); jcal = ICAL.parse(ical); } else if (from == "ical") { ical = ICAL.stringify(jcal); } else { ical = jcal = null; } let totalRuntime = Date.now() - beginTime; duration.textContent = 'Total Runtime: ' + totalRuntime + ' ms'; try { jcalres.textContent = jcal ? JSON.stringify(jcal, null, " ") : ""; icalres.textContent = ical; document.getElementById("jcalbox").style.display = ""; document.getElementById("icalbox").style.display = ""; } catch (e) { error.textContent = stringError(e); } return false; }; ``` -------------------------------- ### Parse iCalendar String to jCal Source: https://github.com/kewisch/ical.js/wiki/Home Parses an iCalendar string into the jCal JSON format. If multiple top-level components exist, it returns an array. ```javascript var iCalendarData = "BEGIN:VCALENDAR" + /* ... */ + "END:VCALENDAR"; var jcalData = ICAL.parse(iCalendarData); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.