Commit b02e05ad authored by Sebastian Pekarek's avatar Sebastian Pekarek
Browse files

Merge branch 'feature/alarm' into develop

close #19
reference #20
parents 27d63a84 221b940f
......@@ -355,6 +355,40 @@ cal.attendees(); // --> [ICalAttendee, ICalAttendee]
```
#### createAlarm([_Object_ options])
Creates a new [Alarm](#alarm) ([`ICalAlarm`](#alarm)) and returns it. Use options to prefill the alarm's attributes.
Calling this method without options will create an empty alarm.
```javascript
var ical = require('ical-generator'),
cal = ical(),
event = cal.createEvent(),
alarm = event.createAlarm({type: 'display', trigger: 300});
// add another alarm
event.createAlarm({
type: 'audio',
trigger: 300, // 5min before event
});
```
#### alarms([_Object_ alarms])
Add alarms to the event or return all attached alarms.
```javascript
var event = ical().createEvent();
cal.alarms([
{type: 'display', trigger: 600},
{type: 'audio', trigger: 300}
]);
cal.attendees(); // --> [ICalAlarm, ICalAlarm]
```
#### url([_String_ url])
Appointment URL
......@@ -420,6 +454,103 @@ attendee.delegatesFrom({email: 'foo@bar.com', name: 'Foo'});
### Alarm
#### type([_String_ type])
Use this method to set the alarm type. Right now, `audio` and `display` is supported.
#### trigger([_String_|_Date_ trigger]) / triggerBefore([_String_|_Date_ trigger])
Use this method to set the alarm time.
```javascript
var cal = ical(),
event = cal.createEvent(),
alarm = cal.createAlarm();
alarm.trigger(600); // -> 10 minutes before event starts
alarm.trigger(new Date()); // -> now
```
#### triggerAfter([_String_|_Date_ trigger])
Use this method to set the alarm time.
```javascript
var cal = ical(),
event = cal.createEvent(),
alarm = cal.createAlarm();
alarm.trigger(600); // -> 10 minutes after the event finishes
alarm.trigger(new Date()); // -> now
```
#### repeat([_Number_ repeat])
Use this method to repeat the alarm.
```javascript
var cal = ical(),
event = cal.createEvent(),
// repeat the alarm 4 times every 5 minutes…
cal.createAlarm({
repeat: 4,
interval: 300
});
```
#### interval([_Number_ interval])
Use this method to set the alarm's interval.
```javascript
var cal = ical(),
event = cal.createEvent(),
// repeat the alarm 4 times every 5 minutes…
cal.createAlarm({
repeat: 4,
interval: 300
});
```
#### attach([_String_|_Object_ attach])
Alarm attachment; used to set the alarm sound if type = audio. Defaults to "Basso".
```javascript
var cal = ical(),
event = cal.createEvent(),
event.createAlarm({
attach: 'https://example.com/notification.aud'
});
// OR
event.createAlarm({
attach: {
uri: 'https://example.com/notification.aud',
mime: 'audio/basic'
}
});
```
#### description([_String_| description])
Alarm description; used to set the alarm message if type = display. Defaults to the event's summary.
## Tests
```
......
'use strict';
module.exports = {};
module.exports.formatDate = function formatDate(d, dateonly, floating) {
var s;
function pad(i) {
return (i < 10 ? '0': '') + i;
}
s = d.getUTCFullYear();
s += pad(d.getUTCMonth() + 1);
s += pad(d.getUTCDate());
if(!dateonly) {
s += 'T';
s += pad(d.getUTCHours());
s += pad(d.getUTCMinutes());
s += pad(d.getUTCSeconds());
if(!floating) {
s += 'Z';
}
}
return s;
};
module.exports.escape = function escape(str) {
return str.replace(/[\\;,\n"]/g, function(match) {
if (match === '\n') {
return '\\n';
}
return '\\' + match;
});
};
module.exports.duration = function duration(seconds) {
var string = '';
// < 0
if(seconds < 0) {
string = '-';
seconds *= -1;
}
string += 'PT';
// HOURS
if(seconds >= 3600) {
string += Math.floor(seconds / 3600) + 'H';
seconds %= 3600;
}
// MINUTES
if(seconds >= 60) {
string += Math.floor(seconds / 60) + 'M';
seconds %= 60;
}
// SECONDS
if(seconds > 0) {
string += seconds + 'S';
}
else if(string.length <= 2) {
string += '0S';
}
return string;
};
\ No newline at end of file
'use strict';
/**
* @author Sebastian Pekarek
* @module alarm
* @constructor ICalAlarm Alarm
*/
var ICalAlarm = function(_data, event) {
var vars,
i,
data;
if(!event) {
throw '`event` option required!';
}
vars = {
types: ['display', 'audio']
};
data = {
type: null,
trigger: null,
repeat: null,
repeatInterval: null,
attach: null,
description: null
};
/**
* Set/Get the alarm type
*
* @param type Type
* @since 0.2.1
* @returns {ICalAlarm|String}
*/
this.type = function(type) {
if(!type) {
return data.type;
}
if(vars.types.indexOf(type) === -1) {
throw '`type` is not correct, must be either `display` or `audio`!';
}
data.type = type;
return this;
};
/**
* Set/Get seconds before event to trigger alarm
*
* @param {Number|Date} trigger Seconds before alarm triggeres
* @since 0.2.1
* @returns {ICalAlarm|Number|Date}
*/
this.trigger = function(trigger) {
if(!trigger && data.trigger instanceof Date) {
return data.trigger;
}
if(!trigger) {
return -1 * data.trigger;
}
if(trigger instanceof Date) {
data.trigger = trigger;
return this;
}
if(typeof trigger === 'number' && isFinite(trigger)) {
data.trigger = -1 * trigger;
return this;
}
throw '`trigger` is not correct, must be either typeof `Number` or `Date`!';
};
/**
* Set/Get seconds after event to trigger alarm
*
* @param {Number|Date} trigger Seconds after alarm triggeres
* @since 0.2.1
* @returns {ICalAlarm|Number|Date}
*/
this.triggerAfter = function(trigger) {
if(!trigger) {
return data.trigger;
}
return this.trigger(typeof trigger === 'number' ? -1 * trigger : trigger);
};
/**
* Set/Get seconds before event to trigger alarm
*
* @param {Number|Date} trigger Seconds before alarm triggeres
* @since 0.2.1
* @alias trigger
* @returns {ICalAlarm|Number|Date}
*/
this.triggerBefore = this.trigger;
/**
* Set/Get Alarm Repetitions
*
* @param {Number} Number of repetitions
* @since 0.2.1
* @returns {ICalAlarm|Number}
*/
this.repeat = function(repeat) {
if(!repeat) {
return data.repeat;
}
if(typeof repeat !== 'number' || !isFinite(repeat)) {
throw '`repeat` is not correct, must be numeric!';
}
data.repeat = repeat;
return this;
};
/**
* Set/Get Repeat Interval
*
* @param {Number} Interval in seconds
* @since 0.2.1
* @returns {ICalAlarm|Number|Null}
*/
this.interval = function(interval) {
if(!interval) {
return data.interval;
}
if(typeof interval !== 'number' || !isFinite(interval)) {
throw '`interval` is not correct, must be numeric!';
}
data.interval = interval;
return this;
};
/**
* Set/Get Attachment
*
* @param {Object|String} File-URI or Object
* @since 0.2.1
* @returns {ICalAlarm|Object}
*/
this.attach = function(_attach) {
if(!_attach) {
return data.attach;
}
var attach= null;
if(typeof _attach === 'string') {
attach = {
uri: _attach,
mime: null
};
}
else if(typeof _attach === 'object') {
attach = {
uri: _attach.uri,
mime: _attach.mime || null
};
}
else {
throw '`attach` needs to be a valid formed string or an object. See https://github.com/sebbo2002/ical-generator#attachstringobject-attach';
}
if(!attach.uri) {
throw '`attach.uri` is empty!';
}
data.attach = {
uri: attach.uri,
mime: attach.mime
};
return this;
};
/**
* Set/Get the alarm description
*
* @param description Description
* @since 0.2.1
* @returns {ICalAlarm|String}
*/
this.description = function(description) {
if(!description) {
return data.description;
}
data.description = description;
return this;
};
/**
* Export Event to iCal
*
* @since 0.2.0
* @returns {String}
*/
this.generate = function() {
var tools = require('./_tools.js'),
g = 'BEGIN:VALARM\n';
if(!data.type) {
throw 'No value for `type` in ICalAlarm given!';
}
if(!data.trigger) {
throw 'No value for `trigger` in ICalAlarm given!';
}
// ACTION
g += 'ACTION:' + data.type.toUpperCase() + '\n';
if(data.trigger instanceof Date) {
g += 'TRIGGER;VALUE=DATE-TIME:' + tools.formatDate(data.trigger) + '\n';
}
else if(data.trigger > 0) {
g += 'TRIGGER;RELATED=END:' + tools.duration(data.trigger) + '\n';
}
else {
g += 'TRIGGER:' + tools.duration(data.trigger) + '\n';
}
// REPEAT
if(data.repeat && !data.interval) {
throw 'No value for `interval` in ICalAlarm given, but required for `repeat`!';
}
if(data.repeat) {
g += 'REPEAT:' + data.repeat + '\n';
}
// INTERVAL
if(data.interval && !data.repeat) {
throw 'No value for `repeat` in ICalAlarm given, but required for `interval`!';
}
if(data.interval) {
g += 'DURATION:' + tools.duration(data.interval) + '\n';
}
// ATTACH
if(data.type === 'audio' && data.attach && data.attach.mime) {
g += 'ATTACH;FMTTYPE=' + data.attach.mime + ':' + data.attach.uri + '\n';
}
else if(data.type === 'audio' && data.attach ) {
g += 'ATTACH;VALUE=URI:' + data.attach.uri + '\n';
}
else if(data.type === 'audio') {
g += 'ATTACH;VALUE=URI:Basso\n';
}
// DESCRIPTION
if(data.type === 'display' && data.description) {
g += 'DESCRIPTION:' + tools.escape(data.description) + '\n';
}
else if(data.type === 'display') {
g += 'DESCRIPTION:' + tools.escape(event.summary()) + '\n';
}
g += 'END:VALARM\n';
return g;
};
for(i in _data) {
if(_data.hasOwnProperty(i) && ['type', 'trigger', 'triggerBefore', 'triggerAfter', 'repeat', 'interval', 'attach', 'description'].indexOf(i) > -1) {
this[i](_data[i]);
}
}
};
module.exports = ICalAlarm;
\ No newline at end of file
......@@ -30,6 +30,7 @@ var ICalEvent = function(_data) {
description: null,
organizer: null,
attendees: [],
alarms: [],
method: null,
status: null,
url: null
......@@ -378,6 +379,41 @@ var ICalEvent = function(_data) {
};
/**
* Create a new Alarm and return the alarm object…
*
* @param [alarmData] Alarm-Options
* @since 0.2.1
* @returns {ICalAlarm}
*/
this.createAlarm = function(alarmData) {
var ICalAlarm = require('./alarm.js'),
alarm = new ICalAlarm(alarmData, this);
data.alarms.push(alarm);
return alarm;
};
/**
* Get all alarms or add alarms…
*
* @since 0.2.0
* @returns {ICalAlarms[]|ICalEvent}
*/
this.alarms = function(alarms) {
if(!alarms) {
return data.alarms;
}
var cal = this;
alarms.forEach(function(e) {
cal.createAlarm(e);
});
return cal;
};
/**
* Set/Get the event's method
*
......@@ -445,7 +481,8 @@ var ICalEvent = function(_data) {
* @returns {String}
*/
this.generate = function(calendar) {
var g = '';
var tools = require('./_tools.js'),
g = '';
if(!calendar) {
throw '`calendar` option required!';
......@@ -457,52 +494,16 @@ var ICalEvent = function(_data) {
throw 'No value for `end` in ICalEvent #' + data.id + ' given!';
}
function _formatDate(d, dateonly, floating) {
var s;
function pad(i) {
return (i < 10 ? '0': '') + i;
}
s = d.getUTCFullYear();
s += pad(d.getUTCMonth() + 1);
s += pad(d.getUTCDate());
if(!dateonly) {
s += 'T';
s += pad(d.getUTCHours());
s += pad(d.getUTCMinutes());
s += pad(d.getUTCSeconds());
if(!floating) {
s += 'Z';
}
}
return s;
}
function escape(str) {
return str.replace(/[\\;,\n]/g, function (match) {
if (match === '\n') {
return '\\n';
}
return '\\' + match;
});
}
// DATE & TIME
g += 'BEGIN:VEVENT\n';
g += 'UID:' + _formatDate(data.start) + '-' + data.id + '@' + calendar.domain() + '\n';
g += 'DTSTAMP:' + _formatDate(data.stamp) + '\n';
g += 'UID:' + tools.formatDate(data.start) + '-' + data.id + '@' + calendar.domain() + '\n';
g += 'DTSTAMP:' + tools.formatDate(data.stamp) + '\n';
if(data.allDay) {
g += 'DTSTART;VALUE=DATE:' + _formatDate(data.start, true) + '\n';
g += 'DTEND;VALUE=DATE:' + _formatDate(data.end, true) + '\n';
g += 'DTSTART;VALUE=DATE:' + tools.formatDate(data.start, true) + '\n';
g += 'DTEND;VALUE=DATE:' + tools.formatDate(data.end, true) + '\n';
}else{
g += 'DTSTART:' + _formatDate(data.start, false, data.floating) + '\n';
g += 'DTEND:' + _formatDate(data.end, false, data.floating) + '\n';
g += 'DTSTART:' + tools.formatDate(data.start, false, data.floating) + '\n';
g += 'DTEND:' + tools.formatDate(data.end, false, data.floating) + '\n';
}
// REPEATING
......@@ -518,28 +519,28 @@ var ICalEvent = function(_data) {
}
if(data.repeating.until) {
g += ';UNTIL=' + _formatDate(data.repeating.until);
g += ';UNTIL=' + tools.formatDate(data.repeating.until);
}
g += '\n';
}
// SUMMARY
g += 'SUMMARY:' + escape(data.summary) + '\n';