Merge remote-tracking branch 'mich/develop' into hidePrivate

Resolved merge conflict
This commit is contained in:
Daniel Buecheler
2016-12-22 21:53:47 +01:00
70 changed files with 3217 additions and 715 deletions

View File

@@ -106,10 +106,16 @@ The following properties can be configured:
<td><code>titleReplace</code></td>
<td>An object of textual replacements applied to the tile of the event. This allow to remove or replace certains words in the title.<br>
<br><b>Example:</b> <br>
<code>
titleReplace: {'Birthday of ' : '', 'foo':'bar'}
</code>
<br><b>Default value:</b>
<code>
{
"De verjaardag van ": "",
"'s birthday": ""
}
</code>
</td>
</tr>
<tr>
@@ -119,6 +125,13 @@ The following properties can be configured:
<br><b>Default value:</b> <code>false</code>
</td>
</tr>
<tr>
<td><code>dateFormat</code></td>
<td>Format to use for the date of events (when using absolute dates)<br>
<br><b>Possible values:</b> See <a href="http://momentjs.com/docs/#/parsing/string-format/">Moment.js formats</a>
<br><b>Default value:</b> <code>MMM Do</code> (e.g. Jan 18th)
</td>
</tr>
<tr>
<td><code>timeFormat</code></td>
<td>Display event times as absolute dates, or relative time<br>
@@ -126,12 +139,26 @@ The following properties can be configured:
<br><b>Default value:</b> <code>relative</code>
</td>
</tr>
<tr>
<td><code>getRelative</code></td>
<td>How much time (in hours) should be left until calendar events start getting relative?<br>
<br><b>Possible values:</b> <code>0</code> (events stay absolute) - <code>48</code> (48 hours before the event starts)
<br><b>Default value:</b> <code>6</code>
</td>
</tr>
<tr>
<td><code>urgency</code></td>
<td>When using a timeFormat of <code>absolute</code>, the <code>urgency</code> setting allows you to display events within a specific time frame as <code>relative</code>
This allows events within a certain time frame to be displayed as relative (in xx days) while others are displayed as absolute dates<br>
<br><b>Possible values:</b> a positive integer representing the number of days for which you want a relative date, for example <code>7</code> (for 7 days)<br>
<br><b>Default value:</b> <code>0</code> (disabled)
<br><b>Default value:</b> <code>7</code>
</td>
</tr>
<tr>
<td><code>broadcastEvents</code></td>
<td>If this property is set to true, the calendar will broadcast all the events to all other modules with the notification message: <code>CALENDAR_EVENTS</code>. The event objects are stored in an array and contain the following fields: <code>title</code>, <code>startDate</code>, <code>endDate</code>, <code>fullDayEvent</code>, <code>location</code> and <code>geo</code>.<br>
<br><b>Possible values:</b> <code>true</code>, <code>false</code> <br>
<br><b>Default value:</b> <code>true</code>
</td>
</tr>
<tr>
@@ -178,24 +205,24 @@ config: {
</td>
</tr>
<tr>
<td><code> symbol </code></td>
<td><code>symbol</code></td>
<td>The symbol to show in front of an event. This property is optional.<br>
<br><b>Possible values:</b> See <a href="http://fontawesome.io/icons/" target="_blank">Font Awesome</a> website.
</td>
</tr>
<tr>
<td><code> repeatingCountTitle </code></td>
<td><code>repeatingCountTitle</code></td>
<td>The count title for yearly repating events in this calendar. <br>
<br><b>Example:</b> <br>
<code>'Birthday'</code>
</td>
</tr>
<tr>
<td><code> user </code></td>
<td><code>user</code></td>
<td>The username for HTTP Basic authentication.</td>
</tr>
<tr>
<td><code> pass </code></td>
<td><code>pass</code></td>
<td>The password for HTTP Basic authentication.</td>
</tr>
</tbody>

View File

@@ -7,7 +7,7 @@
* MIT Licensed.
*/
Module.register("calendar",{
Module.register("calendar", {
// Define module defaults
defaults: {
@@ -16,13 +16,15 @@ Module.register("calendar",{
displaySymbol: true,
defaultSymbol: "calendar", // Fontawesome Symbol see http://fontawesome.io/cheatsheet/
displayRepeatingCountTitle: false,
defaultRepeatingCountTitle: '',
defaultRepeatingCountTitle: "",
maxTitleLength: 25,
fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
animationSpeed: 2000,
fade: true,
urgency: 7,
timeFormat: "relative",
dateFormat: "MMM Do",
getRelative: 6,
fadePoint: 0.25, // Start on 1/4th of the list.
hidePrivate: false,
calendars: [
@@ -35,20 +37,21 @@ Module.register("calendar",{
"De verjaardag van ": "",
"'s birthday": ""
},
broadcastEvents: true
},
// Define required scripts.
getStyles: function() {
getStyles: function () {
return ["calendar.css", "font-awesome.css"];
},
// Define required scripts.
getScripts: function() {
getScripts: function () {
return ["moment.js"];
},
// Define required translations.
getTranslations: function() {
getTranslations: function () {
// The translations for the defaut modules are defined in the core translation files.
// Therefor we can just return false. Otherwise we should have returned a dictionairy.
// If you're trying to build your own module including translations, check out the documentation.
@@ -56,7 +59,7 @@ Module.register("calendar",{
},
// Override start method.
start: function() {
start: function () {
Log.log("Starting module: " + this.name);
// Set locale.
@@ -73,11 +76,15 @@ Module.register("calendar",{
},
// Override socket notification handler.
socketNotificationReceived: function(notification, payload) {
socketNotificationReceived: function (notification, payload) {
if (notification === "CALENDAR_EVENTS") {
if (this.hasCalendarURL(payload.url)) {
this.calendarData[payload.url] = payload.events;
this.loaded = true;
if (this.config.broadcastEvents) {
this.broadcastEvents();
}
}
} else if (notification === "FETCH_ERROR") {
Log.error("Calendar Error. Could not fetch calendar: " + payload.url);
@@ -91,7 +98,7 @@ Module.register("calendar",{
},
// Override dom generator.
getDom: function() {
getDom: function () {
var events = this.createEventList();
var wrapper = document.createElement("table");
@@ -110,27 +117,27 @@ Module.register("calendar",{
eventWrapper.className = "normal";
if (this.config.displaySymbol) {
var symbolWrapper = document.createElement("td");
var symbolWrapper = document.createElement("td");
symbolWrapper.className = "symbol";
var symbol = document.createElement("span");
var symbol = document.createElement("span");
symbol.className = "fa fa-" + this.symbolForUrl(event.url);
symbolWrapper.appendChild(symbol);
eventWrapper.appendChild(symbolWrapper);
}
var titleWrapper = document.createElement("td"),
repeatingCountTitle = '';
repeatingCountTitle = "";
if (this.config.displayRepeatingCountTitle) {
repeatingCountTitle = this.countTitleForUrl(event.url);
if(repeatingCountTitle !== '') {
if (repeatingCountTitle !== "") {
var thisYear = new Date().getFullYear(),
yearDiff = thisYear - event.firstYear;
repeatingCountTitle = ', '+ yearDiff + '. ' + repeatingCountTitle;
repeatingCountTitle = ", " + yearDiff + ". " + repeatingCountTitle;
}
}
@@ -138,28 +145,24 @@ Module.register("calendar",{
titleWrapper.className = "title bright";
eventWrapper.appendChild(titleWrapper);
var timeWrapper = document.createElement("td");
var timeWrapper = document.createElement("td");
//console.log(event.today);
var now = new Date();
// Define second, minute, hour, and day variables
var one_second = 1000; // 1,000 milliseconds
var one_minute = one_second * 60;
var one_hour = one_minute * 60;
var one_day = one_hour * 24;
var oneSecond = 1000; // 1,000 milliseconds
var oneMinute = oneSecond * 60;
var oneHour = oneMinute * 60;
var oneDay = oneHour * 24;
if (event.fullDayEvent) {
if (event.today) {
timeWrapper.innerHTML = this.translate("TODAY");
} else if (event.startDate - now < one_day && event.startDate - now > 0) {
timeWrapper.innerHTML = this.translate("TOMORROW");
} else if (event.startDate - now < 2*one_day && event.startDate - now > 0) {
/*Provide ability to show "the day after tomorrow" instead of "in a day"
*if "DAYAFTERTOMORROW" is configured in a language's translation .json file,
*,which can be found in MagicMirror/translations/
*/
if (this.translate('DAYAFTERTOMORROW') !== 'DAYAFTERTOMORROW') {
timeWrapper.innerHTML = this.translate("DAYAFTERTOMORROW");
timeWrapper.innerHTML = this.capFirst(this.translate("TODAY"));
} else if (event.startDate - now < oneDay && event.startDate - now > 0) {
timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW"));
} else if (event.startDate - now < 2 * oneDay && event.startDate - now > 0) {
if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") {
timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW"));
} else {
timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
} else {
/* Check to see if the user displays absolute or relative dates with their events
@@ -170,26 +173,26 @@ Module.register("calendar",{
* Note: this needs to be put in its own function, as the whole thing repeats again verbatim
*/
if (this.config.timeFormat === "absolute") {
if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) {
if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
// This event falls within the config.urgency period that the user has set
timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
} else {
timeWrapper.innerHTML = moment(event.startDate, "x").format("MMM Do");
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
}
} else {
timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
}
} else {
if (event.startDate >= new Date()) {
if (event.startDate - now < 2 * one_day) {
if (event.startDate - now < 2 * oneDay) {
// This event is within the next 48 hours (2 days)
if (event.startDate - now < 6 * one_hour) {
if (event.startDate - now < this.config.getRelative * oneHour) {
// If event is within 6 hour, display 'in xxx' time format or moment.fromNow()
timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
} else {
// Otherwise just say 'Today/Tomorrow at such-n-such time'
timeWrapper.innerHTML = moment(event.startDate, "x").calendar();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").calendar());
}
} else {
/* Check to see if the user displays absolute or relative dates with their events
@@ -200,18 +203,18 @@ Module.register("calendar",{
* Note: this needs to be put in its own function, as the whole thing repeats again verbatim
*/
if (this.config.timeFormat === "absolute") {
if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) {
if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * oneDay))) {
// This event falls within the config.urgency period that the user has set
timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
} else {
timeWrapper.innerHTML = moment(event.startDate, "x").format("MMM Do");
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
}
} else {
timeWrapper.innerHTML = moment(event.startDate, "x").fromNow();
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
}
}
} else {
timeWrapper.innerHTML = this.translate("RUNNING") + ' ' + moment(event.endDate,"x").fromNow(true);
timeWrapper.innerHTML = this.capFirst(this.translate("RUNNING")) + " " + moment(event.endDate, "x").fromNow(true);
}
}
//timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll');
@@ -245,7 +248,7 @@ Module.register("calendar",{
*
* return bool - Has calendar url
*/
hasCalendarURL: function(url) {
hasCalendarURL: function (url) {
for (var c in this.config.calendars) {
var calendar = this.config.calendars[c];
if (calendar.url === url) {
@@ -261,7 +264,7 @@ Module.register("calendar",{
*
* return array - Array with events.
*/
createEventList: function() {
createEventList: function () {
var events = [];
var today = moment().startOf("day");
for (var c in this.calendarData) {
@@ -280,7 +283,7 @@ Module.register("calendar",{
}
}
events.sort(function(a, b) {
events.sort(function (a, b) {
return a.startDate - b.startDate;
});
@@ -292,7 +295,7 @@ Module.register("calendar",{
*
* argument url sting - Url to add.
*/
addCalendar: function(url, user, pass) {
addCalendar: function (url, user, pass) {
this.sendSocketNotification("ADD_CALENDAR", {
url: url,
maximumEntries: this.config.maximumEntries,
@@ -310,10 +313,10 @@ Module.register("calendar",{
*
* return string - The Symbol
*/
symbolForUrl: function(url) {
symbolForUrl: function (url) {
for (var c in this.config.calendars) {
var calendar = this.config.calendars[c];
if (calendar.url === url && typeof calendar.symbol === "string") {
if (calendar.url === url && typeof calendar.symbol === "string") {
return calendar.symbol;
}
}
@@ -327,10 +330,10 @@ Module.register("calendar",{
*
* return string - The Symbol
*/
countTitleForUrl: function(url) {
countTitleForUrl: function (url) {
for (var c in this.config.calendars) {
var calendar = this.config.calendars[c];
if (calendar.url === url && typeof calendar.repeatingCountTitle === "string") {
if (calendar.url === url && typeof calendar.repeatingCountTitle === "string") {
return calendar.repeatingCountTitle;
}
}
@@ -347,14 +350,23 @@ Module.register("calendar",{
*
* return string - The shortened string.
*/
shorten: function(string, maxLength) {
shorten: function (string, maxLength) {
if (string.length > maxLength) {
return string.slice(0,maxLength) + "&hellip;";
return string.slice(0, maxLength) + "&hellip;";
}
return string;
},
/* capFirst(string)
* Capitalize the first letter of a string
* Eeturn capitalized string
*/
capFirst: function (string) {
return string.charAt(0).toUpperCase() + string.slice(1);
},
/* titleTransform(title)
* Transforms the title of an event for usage.
* Replaces parts of the text as defined in config.titleReplace.
@@ -364,7 +376,7 @@ Module.register("calendar",{
*
* return string - The transformed title.
*/
titleTransform: function(title) {
titleTransform: function (title) {
for (var needle in this.config.titleReplace) {
var replacement = this.config.titleReplace[needle];
title = title.replace(needle, replacement);
@@ -372,5 +384,28 @@ Module.register("calendar",{
title = this.shorten(title, this.config.maxTitleLength);
return title;
},
/* broadcastEvents()
* Broadcasts the events to all other modules for reuse.
* The all events available in one array, sorted on startdate.
*/
broadcastEvents: function () {
var eventList = [];
for (url in this.calendarData) {
var calendar = this.calendarData[url];
for (e in calendar) {
var event = cloneObject(calendar[e]);
delete event.url;
eventList.push(event);
}
}
eventList.sort(function(a,b) {
return a.startDate - b.startDate;
});
this.sendNotification("CALENDAR_EVENTS", eventList);
}
});

View File

@@ -25,9 +25,10 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
clearTimeout(reloadTimer);
reloadTimer = null;
nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
var opts = {
headers: {
'User-Agent': 'Mozilla/5.0 (Node.js 6.0.0) MagicMirror/v2 (https://github.com/MichMich/MagicMirror/)'
"User-Agent": "Mozilla/5.0 (Node.js "+ nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)"
}
};
@@ -77,10 +78,11 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
if (!isFacebookBirthday) {
endDate = startDate;
} else {
endDate = moment(startDate).add(1, 'days');
endDate = moment(startDate).add(1, "days");
}
}
// calculate the duration f the event for use with recurring events.
var duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
@@ -95,13 +97,17 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
title = event.description;
}
var location = event.location || false;
var geo = event.geo || false;
var description = event.description || false;
if (typeof event.rrule != "undefined" && !isFacebookBirthday) {
var rule = event.rrule;
var dates = rule.between(today, future, true, limitFunction);
for (var d in dates) {
startDate = moment(new Date(dates[d]));
endDate = moment(parseInt(startDate.format("x")) + duration, 'x');
endDate = moment(parseInt(startDate.format("x")) + duration, "x");
if (endDate.format("x") > now) {
newEvents.push({
title: title,
@@ -109,7 +115,10 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
endDate: endDate.format("x"),
fullDayEvent: isFullDayEvent(event),
class: event.class,
firstYear: event.start.getFullYear()
firstYear: event.start.getFullYear(),
location: location,
geo: geo,
description: description
});
}
}
@@ -133,15 +142,19 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
continue;
}
// Every thing is good. Add it to the list.
// Every thing is good. Add it to the list.
newEvents.push({
title: title,
startDate: startDate.format("x"),
endDate: endDate.format("x"),
fullDayEvent: fullDayEvent,
class: event.class
location: location,
geo: geo,
description: description
});
}
}
}
@@ -188,7 +201,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe
if (end - start === 24 * 60 * 60 * 1000 && startDate.getHours() === 0 && startDate.getMinutes() === 0) {
// Is 24 hours, and starts on the middle of the night.
return true;
return true;
}
return false;

View File

@@ -8,18 +8,18 @@
var CalendarFetcher = require("./calendarfetcher.js");
var url = 'https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics';
var url = "https://calendar.google.com/calendar/ical/pkm1t2uedjbp0uvq1o7oj1jouo%40group.calendar.google.com/private-08ba559f89eec70dd74bbd887d0a3598/basic.ics";
var fetchInterval = 60 * 60 * 1000;
var maximumEntries = 10;
var maximumNumberOfDays = 365;
console.log('Create fetcher ...');
console.log("Create fetcher ...");
fetcher = new CalendarFetcher(url, fetchInterval, maximumEntries, maximumNumberOfDays);
fetcher.onReceive(function(fetcher) {
console.log(fetcher.events());
console.log('------------------------------------------------------------');
console.log(fetcher.events());
console.log("------------------------------------------------------------");
});
fetcher.onError(function(fetcher, error) {
@@ -29,5 +29,5 @@ fetcher.onError(function(fetcher, error) {
fetcher.startFetch();
console.log('Create fetcher done! ');
console.log("Create fetcher done! ");