Commit f69806a1 authored by Sebastian's avatar Sebastian
Browse files

Merge branch 'develop'

parents 6280432e 721b9986
......@@ -271,7 +271,13 @@ Empty the Calender.
#### uid([_String_|_Number_ uid]) or id([_String_|_Number_ id])
Use this method to set the event's ID. If not set, an UID will be generated randomly.
Use this method to set the event's ID. If not set, an UID will be generated randomly. When output, the ID will be suffixed with '@' + your calendar's domain.
#### sequence([_Number_ sequence])
Use this method to set the event's revision sequence number of the
calendar component within a sequence of revisions.
#### start([_Date_ start])
......@@ -284,6 +290,13 @@ Appointment date of beginning as Date object. This is required for all events!
Appointment date of end as Date object.
#### timezone([_String_ timezone])
Use this method to set your event's timezone using the TZID property parameter on start and end dates, as per [date-time form #3 in section 3.3.5 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.5).
This and the 'floating' flag (see below) are mutually exclusive, and setting a timezone will unset the 'floating' flag. If neither 'timezone' nor 'floating' are set, the date will be output with in UTC format (see [date-time form #2 in section 3.3.5 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.5)).
#### timestamp([_Date_ stamp]) or stamp([_Date_ stamp])
Appointment date of creation as Date object. Default to `new Date()`.
......@@ -295,6 +308,7 @@ When allDay == true -> appointment is for the whole day
#### floating([_Boolean_ floating])
Appointment is a "floating" time. From [section 3.3.12 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.12):
> Time values of this type are said to be "floating" and are not
......@@ -305,8 +319,11 @@ Appointment is a "floating" time. From [section 3.3.12 of RFC 554](https://tools
> AM to 1:00 PM every day, no matter which time zone the person is
> in. In these cases, a local time can be specified.
This and the 'timezone' setting (see above) are mutually exclusive, and setting the floating flag will unset the 'timezone'. If neither 'timezone' nor 'floating' are set, the date will be output with in UTC format (see [date-time form #2 in section 3.3.5 of RFC 554](https://tools.ietf.org/html/rfc5545#section-3.3.5)).
#### repeating([_Object_ repeating])
Appointment is a repeating event
```javascript
......
......@@ -27,6 +27,23 @@ module.exports.formatDate = function formatDate(d, dateonly, floating) {
return s;
};
// For information about this format, see RFC 5545, section 3.3.5
// https://tools.ietf.org/html/rfc5545#section-3.3.5
module.exports.formatDateTZ = function formatDateTZ(property, date, eventData) {
var tzParam = '';
var floating = eventData.floating;
if(eventData.timezone) {
tzParam = ';TZID=' + eventData.timezone;
// This isn't a 'floating' event because it has a timezone;
// but we use it to omit the 'Z' UTC specifier in formatDate()
floating = true;
}
return property + tzParam + ':' + module.exports.formatDate(date, false, floating);
};
module.exports.escape = function escape(str) {
return str.replace(/[\\;,"]/g, function(match) {
return '\\' + match;
......
......@@ -123,10 +123,10 @@ var ICalCalendar = function(_data) {
* string like "//sebbo.net//ical-generator//EN" or an
* object like
* {
* "company": "sebbo.net",
* "product": "ical-generator"
* "language": "EN"
* }
* "company": "sebbo.net",
* "product": "ical-generator"
* "language": "EN"
* }
*
* `language` is optional and defaults to `EN`.
*
......@@ -285,11 +285,6 @@ var ICalCalendar = function(_data) {
throw 'event.start is a mandatory item!';
}
// validation: end
if(!event.end) {
throw 'event.end is a mandatory item!';
}
// validation: summary
if(!event.summary) {
throw 'event.summary is a mandatory item!';
......
......@@ -7,7 +7,7 @@
* @constructor ICalEvent Event
*/
var ICalEvent = function(_data) {
var attributes = ['id', 'uid', 'start', 'end', 'stamp', 'timestamp', 'allDay', 'floating', 'repeating', 'summary', 'location', 'description', 'organizer', 'attendees', 'alarms', 'method', 'status', 'url'],
var attributes = ['id', 'uid', 'sequence', 'start', 'end', 'timezone', 'stamp', 'timestamp', 'allDay', 'floating', 'repeating', 'summary', 'location', 'description', 'organizer', 'attendees', 'alarms', 'method', 'status', 'url'],
vars,
i,
data;
......@@ -20,8 +20,10 @@ var ICalEvent = function(_data) {
data = {
id: ('0000' + (Math.random() * Math.pow(36, 4) << 0).toString(36)).substr(-4),
sequence: 0,
start: null,
end: null,
timezone: null,
stamp: new Date(),
allDay: false,
floating: false,
......@@ -65,6 +67,27 @@ var ICalEvent = function(_data) {
this.uid = this.id;
/**
* Set/Get the event's SEQUENCE number
*
* @param {Number} sequence
* @since 0.2.6
* @returns {ICalEvent|Number}
*/
this.sequence = function(sequence) {
if(sequence === undefined) {
return data.sequence;
}
var s = parseInt(sequence, 10);
if(isNaN(s)) {
throw '`sequence` must be a number!';
}
data.sequence = s;
return this;
};
/**
* Set/Get the event's start date
*
......@@ -81,7 +104,7 @@ var ICalEvent = function(_data) {
if(typeof start === 'string') {
start = new Date(start);
}
if(!(start instanceof Date) || !start.getTime()) {
if(!(start instanceof Date) || isNaN(start.getTime())) {
throw '`start` must be a Date Object!';
}
data.start = start;
......@@ -110,7 +133,7 @@ var ICalEvent = function(_data) {
if(typeof end === 'string') {
end = new Date(end);
}
if(!(end instanceof Date) || !end.getTime()) {
if(!(end instanceof Date) || isNaN(end.getTime())) {
throw '`end` must be a Date Object!';
}
data.end = end;
......@@ -124,6 +147,26 @@ var ICalEvent = function(_data) {
};
/**
* Set/Get the event's timezone. This unsets the event's floating flag.
* Used on date properties
*
* @param [timezone] Timezone
* @example event.timezone('America/New_York');
* @since 0.2.6
* @returns {ICalEvent|String}
*/
this.timezone = function(timezone) {
if(!timezone) {
return data.timezone;
}
data.timezone = timezone.toString();
data.floating = false;
return this;
};
/**
* Set/Get the event's timestamp
*
......@@ -139,7 +182,7 @@ var ICalEvent = function(_data) {
if(typeof stamp === 'string') {
stamp = new Date(stamp);
}
if(!(stamp instanceof Date) || !stamp.getTime()) {
if(!(stamp instanceof Date) || isNaN(stamp.getTime())) {
throw '`stamp` must be a Date Object!';
}
data.stamp = stamp;
......@@ -176,7 +219,7 @@ var ICalEvent = function(_data) {
/**
* Set/Get the event's floating flag
* Set/Get the event's floating flag. This unsets the event's timezone.
* See https://tools.ietf.org/html/rfc5545#section-3.3.12
*
* @param {Boolean} floating
......@@ -189,6 +232,7 @@ var ICalEvent = function(_data) {
}
data.floating = !!floating;
data.timezone = null;
return this;
};
......@@ -232,7 +276,7 @@ var ICalEvent = function(_data) {
if(typeof repeating.until === 'string') {
repeating.until = new Date(repeating.until);
}
if(!(repeating.until instanceof Date) || !repeating.until.getTime()) {
if(!(repeating.until instanceof Date) || isNaN(repeating.until.getTime())) {
throw '`repeating.until` must be a Date Object!';
}
......@@ -566,16 +610,20 @@ var ICalEvent = function(_data) {
// DATE & TIME
g += 'BEGIN:VEVENT\r\n';
g += 'UID:' + data.id + '@' + calendar.domain() + '\r\n';
// SEQUENCE
g += 'SEQUENCE:' + data.sequence + '\r\n';
g += 'DTSTAMP:' + tools.formatDate(data.stamp) + '\r\n';
if(data.allDay) {
g += 'DTSTART;VALUE=DATE:' + tools.formatDate(data.start, true) + '\r\n';
if (data.end) {
g += 'DTEND;VALUE=DATE:' + tools.formatDate(data.end, true) + '\r\n';
if(data.end) {
g += 'DTEND;VALUE=DATE:' + tools.formatDate(data.end, true) + '\r\n';
}
} else {
g += 'DTSTART:' + tools.formatDate(data.start, false, data.floating) + '\r\n';
if (data.end) {
g += 'DTEND:' + tools.formatDate(data.end, false, data.floating) + '\r\n';
g += tools.formatDateTZ('DTSTART', data.start, data) + '\r\n';
if(data.end) {
g += tools.formatDateTZ('DTEND', data.end, data) + '\r\n';
}
}
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:123@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131004T231500Z
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:123@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131004T231500Z
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:123@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART;VALUE=DATE:20131004
DTEND;VALUE=DATE:20131006
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:1@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131006T231500Z
......@@ -11,6 +12,7 @@ SUMMARY:repeating by month
END:VEVENT
BEGIN:VEVENT
UID:2@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131006T231500Z
......@@ -19,6 +21,7 @@ SUMMARY:repeating by day\, twice
END:VEVENT
BEGIN:VEVENT
UID:3@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131006T231500Z
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:1@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930
DTEND:20131006T231500
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:123@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART;VALUE=DATE:20131004
DTEND;VALUE=DATE:20131006
......
......@@ -3,6 +3,7 @@ VERSION:2.0
PRODID:-//sebbo.net//ical-generator.tests//EN
BEGIN:VEVENT
UID:1@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131006T231500Z
......@@ -11,6 +12,7 @@ SUMMARY:repeating by month
END:VEVENT
BEGIN:VEVENT
UID:2@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131006T231500Z
......@@ -19,6 +21,7 @@ SUMMARY:repeating on Mo/We/Fr\, twice
END:VEVENT
BEGIN:VEVENT
UID:3@sebbo.net
SEQUENCE:0
DTSTAMP:20131004T233453Z
DTSTART:20131004T223930Z
DTEND:20131006T231500Z
......
......@@ -185,17 +185,6 @@ describe('ical-generator 0.1.x', function() {
}, /event\.start must be a Date Object/);
});
it('should throw error when no end time given', function() {
var generator = require(__dirname + '/../lib/index.js'),
cal = generator();
assert.throws(function() {
cal.addEvent({
start: new Date()
});
}, /event\.end is a mandatory item/);
});
it('should throw error when end time is not a date', function() {
var generator = require(__dirname + '/../lib/index.js'),
cal = generator();
......
......@@ -147,7 +147,7 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
assert.equal(cal.timezone(), 'Europe/Berlin');
});
it('should change something', function() {
it('should make a difference to iCal output', function() {
var cal = ical().timezone('Europe/London');
cal.createEvent({
start: new Date(),
......@@ -156,6 +156,20 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
});
assert.ok(cal.toString().indexOf('Europe/London') > -1);
});
it('should mark event as not floating', function() {
var cal = ical().timezone('Europe/London'),
evt = cal.createEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event',
floating: true
});
evt.timezone('Europe/Berlin');
assert.equal(evt.floating(), false);
});
});
describe('ttl()', function() {
......@@ -216,6 +230,15 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
assert.equal(event.summary(), 'Patch-Day');
});
it('should not require optional parameters', function() {
assert.doesNotThrow(function() {
ical().addEvent({
start: new Date(),
summary: 'Patch-Day'
});
}, Error);
});
});
describe('events()', function() {
......@@ -411,6 +434,44 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
});
});
describe('sequence()', function() {
it('setter should return this', function() {
var e = ical().createEvent();
assert.deepEqual(e, e.sequence(1));
});
it('getter should return value', function() {
var e = ical().createEvent().sequence(1048);
assert.equal(e.sequence(), 1048);
});
it('should change something', function() {
var cal = ical();
cal.createEvent({
sequenze: 512,
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event'
});
assert.ok(cal.toString().indexOf('512') > -1);
});
it('setter should throw error when sequence is not valid', function() {
var e = ical().createEvent();
assert.throws(function() {
e.sequence('hello');
}, /`sequence`/);
});
it('setter should work with 0', function() {
var e = ical().createEvent().sequence(12);
assert.equal(e.sequence(), 12);
e.sequence(0);
assert.equal(e.sequence(), 0);
});
});
describe('start()', function() {
it('setter should return this', function() {
var e = ical().createEvent();
......@@ -467,6 +528,30 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
});
});
describe('timezone()', function() {
it('setter should return this', function() {
var e = ical().createEvent();
assert.deepEqual(e, e.timezone('Europe/Berlin'));
});
it('getter should return value', function() {
var e = ical().createEvent().timezone('Europe/Berlin');
assert.equal(e.timezone(), 'Europe/Berlin');
});
it('should change something', function() {
var cal = ical(),
e = cal.createEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event'
});
e.timezone('Europe/London');
assert.ok(cal.toString().indexOf('Europe/London') > -1);
});
});
describe('stamp()', function() {
it('setter should return this', function() {
var e = ical().createEvent();
......@@ -555,6 +640,20 @@ describe('ical-generator 0.2.x / ICalCalendar', function() {
event.floating(true);
assert.ok(str !== cal.toString());
});
it('should mark event as having no time zone', function() {
var cal = ical().timezone('Europe/London'),
evt = cal.createEvent({
start: new Date(),
end: new Date(new Date().getTime() + 3600000),
summary: 'Example Event',
timezone: 'Europe/Berlin'
});
evt.floating(true);
assert.equal(evt.timezone(), null);
});
});
describe('repeating()', function() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment