Skip to content

Commit

Permalink
Update calendar’s vendored ical.js
Browse files Browse the repository at this point in the history
  • Loading branch information
mattdb committed Jun 13, 2019
1 parent 77a214e commit 7b4b7df
Show file tree
Hide file tree
Showing 11 changed files with 471 additions and 78 deletions.
4 changes: 1 addition & 3 deletions modules/default/calendar/vendor/ical.js/.travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "4.2"
- "8.9"
install: npm install
23 changes: 13 additions & 10 deletions modules/default/calendar/vendor/ical.js/example.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
var ical = require('ical')
, months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
'use strict';

const ical = require('ical');
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function(err, data){
for (var k in data){
if (data.hasOwnProperty(k)){
var ev = data[k]
console.log("Conference", ev.summary, 'is in', ev.location, 'on the', ev.start.getDate(), 'of', months[ev.start.getMonth()] );
}
}
})
ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function (err, data) {
for (let k in data) {
if (data.hasOwnProperty(k)) {
var ev = data[k];
if (data[k].type == 'VEVENT') {
console.log(`${ev.summary} is in ${ev.location} on the ${ev.start.getDate()} of ${months[ev.start.getMonth()]} at ${ev.start.toLocaleTimeString('en-GB')}`);

}
}
}
});
118 changes: 118 additions & 0 deletions modules/default/calendar/vendor/ical.js/example_rrule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
var ical = require('./node-ical')
var moment = require('moment')

var data = ical.parseFile('./examples/example_rrule.ics');

// Complicated example demonstrating how to handle recurrence rules and exceptions.

for (var k in data) {

// When dealing with calendar recurrences, you need a range of dates to query against,
// because otherwise you can get an infinite number of calendar events.
var rangeStart = moment("2017-01-01");
var rangeEnd = moment("2017-12-31");


var event = data[k]
if (event.type === 'VEVENT') {

var title = event.summary;
var startDate = moment(event.start);
var endDate = moment(event.end);

// Calculate the duration of the event for use with recurring events.
var duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));

// Simple case - no recurrences, just print out the calendar event.
if (typeof event.rrule === 'undefined')
{
console.log('title:' + title);
console.log('startDate:' + startDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('endDate:' + endDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('duration:' + moment.duration(duration).humanize());
console.log();
}

// Complicated case - if an RRULE exists, handle multiple recurrences of the event.
else if (typeof event.rrule !== 'undefined')
{
// For recurring events, get the set of event start dates that fall within the range
// of dates we're looking for.
var dates = event.rrule.between(
rangeStart.toDate(),
rangeEnd.toDate(),
true,
function(date, i) {return true;}
)

// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
// had its date changed from outside the range to inside the range. One way to handle this is
// to add *all* recurrence override entries into the set of dates that we check, and then later
// filter out any recurrences that don't actually belong within our range.
if (event.recurrences != undefined)
{
for (var r in event.recurrences)
{
// Only add dates that weren't already in the range we added from the rrule so that
// we don't double-add those events.
if (moment(new Date(r)).isBetween(rangeStart, rangeEnd) != true)
{
dates.push(new Date(r));
}
}
}

// Loop through the set of date entries to see which recurrences should be printed.
for(var i in dates) {

var date = dates[i];
var curEvent = event;
var showRecurrence = true;
var curDuration = duration;

startDate = moment(date);

// Use just the date of the recurrence to look up overrides and exceptions (i.e. chop off time information)
var dateLookupKey = date.toISOString().substring(0, 10);

// For each date that we're checking, it's possible that there is a recurrence override for that one day.
if ((curEvent.recurrences != undefined) && (curEvent.recurrences[dateLookupKey] != undefined))
{
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
curEvent = curEvent.recurrences[dateLookupKey];
startDate = moment(curEvent.start);
curDuration = parseInt(moment(curEvent.end).format("x")) - parseInt(startDate.format("x"));
}
// If there's no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
else if ((curEvent.exdate != undefined) && (curEvent.exdate[dateLookupKey] != undefined))
{
// This date is an exception date, which means we should skip it in the recurrence pattern.
showRecurrence = false;
}

// Set the the title and the end date from either the regular event or the recurrence override.
var recurrenceTitle = curEvent.summary;
endDate = moment(parseInt(startDate.format("x")) + curDuration, 'x');

// If this recurrence ends before the start of the date range, or starts after the end of the date range,
// don't process it.
if (endDate.isBefore(rangeStart) || startDate.isAfter(rangeEnd)) {
showRecurrence = false;
}

if (showRecurrence === true) {

console.log('title:' + recurrenceTitle);
console.log('startDate:' + startDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('endDate:' + endDate.format('MMMM Do YYYY, h:mm:ss a'));
console.log('duration:' + moment.duration(curDuration).humanize());
console.log();
}

}
}
}
}


40 changes: 40 additions & 0 deletions modules/default/calendar/vendor/ical.js/examples/example_rrule.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:ical
X-WR-TIMEZONE:US/Central
X-WR-CALDESC:
BEGIN:VEVENT
UID:98765432-ABCD-DCBB-999A-987765432123
DTSTART;TZID=US/Central:20170601T090000
DTEND;TZID=US/Central:20170601T170000
DTSTAMP:20170727T044436Z
EXDATE;TZID=US/Central:20170706T090000,20170713T090000,20170720T090000,20
170803T090000
LAST-MODIFIED:20170727T044435Z
RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20170814T045959Z;BYDAY=TH
SEQUENCE:0
SUMMARY:Recurring weekly meeting from June 1 - Aug 14 (except July 6, July 13, July 20, Aug 3)
END:VEVENT
BEGIN:VEVENT
UID:98765432-ABCD-DCBB-999A-987765432123
RECURRENCE-ID;TZID=US/Central:20170629T090000
DTSTART;TZID=US/Central:20170703T090000
DTEND;TZID=US/Central:20170703T120000
DTSTAMP:20170727T044436Z
LAST-MODIFIED:20170216T143445Z
SEQUENCE:0
SUMMARY:Last meeting in June moved to Monday July 3 and shortened to half day
END:VEVENT
BEGIN:VEVENT
UID:12354454-ABCD-DCBB-999A-2349872354897
DTSTART;TZID=US/Central:20171201T130000
DTEND;TZID=US/Central:20171201T150000
DTSTAMP:20170727T044436Z
LAST-MODIFIED:20170727T044435Z
SEQUENCE:0
SUMMARY:Single event on Dec 1
END:VEVENT
END:VCALENDAR
78 changes: 42 additions & 36 deletions modules/default/calendar/vendor/ical.js/node-ical.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@ exports.fromURL = function(url, opts, cb){
if (!cb)
return;
request(url, opts, function(err, r, data){
if (err)
return cb(err, null);
cb(undefined, ical.parseICS(data));
if (err)
{
return cb(err, null);
}
else if (r.statusCode != 200)
{
return cb(r.statusCode + ": " + r.statusMessage, null);
}

cb(undefined, ical.parseICS(data));
})
}

Expand All @@ -17,44 +24,43 @@ exports.parseFile = function(filename){
}


var rrule = require('rrule-alt').RRule
var rrulestr = rrule.rrulestr
var rrule = require('rrule').RRule

ical.objectHandlers['RRULE'] = function(val, params, curr, stack, line){
curr.rrule = line;
return curr
}
var originalEnd = ical.objectHandlers['END'];
ical.objectHandlers['END'] = function(val, params, curr, stack){
if (curr.rrule) {
var rule = curr.rrule;
if (rule.indexOf('DTSTART') === -1) {

if (curr.start.length === 8) {
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(curr.start);
if (comps) {
curr.start = new Date (comps[1], comps[2] - 1, comps[3]);
}
}

if( typeof (curr.start) === "date") {
rule += ' DTSTART:' + curr.start.toISOString().replace(/[-:]/g, '');
rule = rule.replace(/\.[0-9]{3}/, '');
}
}
for (var i in curr.exdates) {
if( typeof (curr.exdates[i]) === "date") {
rule += ' EXDATE:' + curr.exdates[i].toISOString().replace(/[-:]/g, '');
rule = rule.replace(/\.[0-9]{3}/, '');
}
}
try {
curr.rrule = rrulestr(rule);
}
catch(err) {
console.log("Unrecognised element in calendar feed, ignoring: " + rule);
curr.rrule = null;
}
}
ical.objectHandlers['END'] = function (val, params, curr, stack) {
// Recurrence rules are only valid for VEVENT, VTODO, and VJOURNAL.
// More specifically, we need to filter the VCALENDAR type because we might end up with a defined rrule
// due to the subtypes.
if ((val === "VEVENT") || (val === "VTODO") || (val === "VJOURNAL")) {
if (curr.rrule) {
var rule = curr.rrule.replace('RRULE:', '');
if (rule.indexOf('DTSTART') === -1) {

if (curr.start.length === 8) {
var comps = /^(\d{4})(\d{2})(\d{2})$/.exec(curr.start);
if (comps) {
curr.start = new Date(comps[1], comps[2] - 1, comps[3]);
}
}


if (typeof curr.start.toISOString === 'function') {
try {
rule += ';DTSTART=' + curr.start.toISOString().replace(/[-:]/g, '');
rule = rule.replace(/\.[0-9]{3}/, '');
} catch (error) {
console.error("ERROR when trying to convert to ISOString", error);
}
} else {
console.error("No toISOString function in curr.start", curr.start);
}
}
curr.rrule = rrule.fromString(rule);
}
}
return originalEnd.call(this, val, params, curr, stack);
}
9 changes: 5 additions & 4 deletions modules/default/calendar/vendor/ical.js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,18 @@
],
"homepage": "https://github.com/peterbraden/ical.js",
"author": "Peter Braden <[email protected]> (peterbraden.co.uk)",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "git://github.com/peterbraden/ical.js.git"
},
"dependencies": {
"request": "2.68.0",
"rrule": "2.0.0"
"request": "^2.88.0",
"rrule": "2.4.1"
},
"devDependencies": {
"vows": "0.7.0",
"underscore": "1.3.0"
"vows": "0.8.2",
"underscore": "1.9.1"
},
"scripts": {
"test": "./node_modules/vows/bin/vows ./test/test.js"
Expand Down
41 changes: 26 additions & 15 deletions modules/default/calendar/vendor/ical.js/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ A tolerant, minimal icalendar parser for javascript/node
(http://tools.ietf.org/html/rfc5545)



## Install - Node.js ##

ical.js is availble on npm:
Expand All @@ -33,19 +34,29 @@ Use the request library to fetch the specified URL (```opts``` gets passed on to

## Example 1 - Print list of upcoming node conferences (see example.js)
```javascript
var ical = require('ical')
, months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function(err, data) {
for (var k in data){
if (data.hasOwnProperty(k)) {
var ev = data[k]
console.log("Conference",
ev.summary,
'is in',
ev.location,
'on the', ev.start.getDate(), 'of', months[ev.start.getMonth()]);
}
}
});
'use strict';

const ical = require('ical');
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

ical.fromURL('http://lanyrd.com/topics/nodejs/nodejs.ics', {}, function (err, data) {
for (let k in data) {
if (data.hasOwnProperty(k)) {
var ev = data[k];
if (data[k].type == 'VEVENT') {
console.log(`${ev.summary} is in ${ev.location} on the ${ev.start.getDate()} of ${months[ev.start.getMonth()]} at ${ev.start.toLocaleTimeString('en-GB')}`);

}
}
}
});
```

## Recurrences and Exceptions ##
Calendar events with recurrence rules can be significantly more complicated to handle correctly. There are three parts to handling them:

1. rrule - the recurrence rule specifying the pattern of recurring dates and times for the event.
2. recurrences - an optional array of event data that can override specific occurrences of the event.
3. exdate - an optional array of dates that should be excluded from the recurrence pattern.

See example_rrule.js for an example of handling recurring calendar events.
Loading

0 comments on commit 7b4b7df

Please sign in to comment.