2016-03-31 11:05:32 +02:00
|
|
|
/* global Module */
|
|
|
|
|
|
|
|
/* Magic Mirror
|
|
|
|
* Module: Calendar
|
|
|
|
*
|
|
|
|
* By Michael Teeuw http://michaelteeuw.nl
|
|
|
|
* MIT Licensed.
|
|
|
|
*/
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
Module.register("calendar",{
|
2016-03-31 11:05:32 +02:00
|
|
|
|
|
|
|
// Define module defaults
|
|
|
|
defaults: {
|
|
|
|
maximumEntries: 10, // Total Maximum Entries
|
2016-04-03 19:52:13 +02:00
|
|
|
maximumNumberOfDays: 365,
|
2016-03-31 11:05:32 +02:00
|
|
|
displaySymbol: true,
|
2016-04-05 14:35:11 -04:00
|
|
|
defaultSymbol: "calendar", // Fontawsome Symbol see http://fontawesome.io/cheatsheet/
|
2016-04-03 19:52:13 +02:00
|
|
|
maxTitleLength: 25,
|
2016-03-31 11:05:32 +02:00
|
|
|
fetchInterval: 5 * 60 * 1000, // Update every 5 minutes.
|
|
|
|
animationSpeed: 2000,
|
2016-04-03 19:52:13 +02:00
|
|
|
fade: true,
|
2016-03-31 11:05:32 +02:00
|
|
|
fadePoint: 0.25, // Start on 1/4th of the list.
|
2016-04-05 14:35:11 -04:00
|
|
|
calendars: [
|
2016-03-31 11:05:32 +02:00
|
|
|
{
|
2016-04-05 14:35:11 -04:00
|
|
|
symbol: "calendar",
|
|
|
|
url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics",
|
2016-03-31 11:05:32 +02:00
|
|
|
},
|
|
|
|
],
|
|
|
|
titleReplace: {
|
2016-04-05 14:35:11 -04:00
|
|
|
"De verjaardag van ": ""
|
2016-04-05 10:01:54 +02:00
|
|
|
},
|
2016-04-05 14:35:11 -04:00
|
|
|
loadingText: "Loading events …",
|
|
|
|
emptyCalendarText: "No upcoming events.",
|
2016-04-05 11:20:47 +02:00
|
|
|
|
|
|
|
// TODO: It would be nice if there is a way to get this from the Moment.js locale.
|
2016-04-15 13:13:06 +02:00
|
|
|
todayText: "Today",
|
|
|
|
runningText: "Ends in"
|
2016-03-31 11:05:32 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Define required scripts.
|
|
|
|
getStyles: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
return ["calendar.css", "font-awesome.css"];
|
2016-03-31 11:05:32 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Define required scripts.
|
|
|
|
getScripts: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
return ["moment.js"];
|
2016-03-31 11:05:32 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Override start method.
|
|
|
|
start: function() {
|
2016-04-05 14:35:11 -04:00
|
|
|
Log.log("Starting module: " + this.name);
|
2016-03-31 11:05:32 +02:00
|
|
|
|
|
|
|
// Set locale.
|
|
|
|
moment.locale(config.language);
|
|
|
|
|
|
|
|
for (var c in this.config.calendars) {
|
|
|
|
var calendar = this.config.calendars[c];
|
2016-04-05 14:35:11 -04:00
|
|
|
calendar.url = calendar.url.replace("webcal://", "http://");
|
2016-03-31 11:05:32 +02:00
|
|
|
this.addCalendar(calendar.url);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.calendarData = {};
|
2016-04-05 10:01:54 +02:00
|
|
|
this.loaded = false;
|
2016-03-31 11:05:32 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Override socket notification handler.
|
|
|
|
socketNotificationReceived: function(notification, payload) {
|
2016-04-05 14:35:11 -04:00
|
|
|
if (notification === "CALENDAR_EVENTS") {
|
2016-03-31 11:05:32 +02:00
|
|
|
if (this.hasCalendarURL(payload.url)) {
|
|
|
|
this.calendarData[payload.url] = payload.events;
|
2016-04-05 10:01:54 +02:00
|
|
|
this.loaded = true;
|
2016-03-31 11:05:32 +02:00
|
|
|
}
|
2016-04-05 14:35:11 -04:00
|
|
|
} else if (notification === "FETCH_ERROR") {
|
|
|
|
Log.error("Calendar Error. Could not fetch calendar: " + payload.url);
|
|
|
|
} else if (notification === "INCORRECT_URL") {
|
|
|
|
Log.error("Calendar Error. Incorrect url: " + payload.url);
|
2016-03-31 11:05:32 +02:00
|
|
|
} else {
|
2016-04-05 14:35:11 -04:00
|
|
|
Log.log("Calendar received an unknown socket notification: " + notification);
|
2016-03-31 11:05:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.updateDom(this.config.animationSpeed);
|
|
|
|
},
|
|
|
|
|
|
|
|
// Override dom generator.
|
|
|
|
getDom: function() {
|
|
|
|
|
|
|
|
var events = this.createEventList();
|
|
|
|
var wrapper = document.createElement("table");
|
|
|
|
wrapper.className = "small";
|
|
|
|
|
|
|
|
if (events.length === 0) {
|
2016-04-05 10:01:54 +02:00
|
|
|
wrapper.innerHTML = (this.loaded) ? this.config.emptyCalendarText : this.config.loadingText;
|
2016-03-31 11:05:32 +02:00
|
|
|
wrapper.className = "small dimmed";
|
|
|
|
return wrapper;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var e in events) {
|
|
|
|
var event = events[e];
|
|
|
|
|
|
|
|
var eventWrapper = document.createElement("tr");
|
|
|
|
eventWrapper.className = "normal";
|
|
|
|
|
|
|
|
if (this.config.displaySymbol) {
|
|
|
|
var symbolWrapper = document.createElement("td");
|
|
|
|
symbolWrapper.className = "symbol";
|
|
|
|
var symbol = document.createElement("span");
|
|
|
|
symbol.className = "fa fa-" + this.symbolForUrl(event.url);
|
|
|
|
symbolWrapper.appendChild(symbol);
|
|
|
|
eventWrapper.appendChild(symbolWrapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
var titleWrapper = document.createElement("td");
|
|
|
|
titleWrapper.innerHTML = this.titleTransform(event.title);
|
|
|
|
titleWrapper.className = "title bright";
|
|
|
|
eventWrapper.appendChild(titleWrapper);
|
|
|
|
|
|
|
|
var timeWrapper = document.createElement("td");
|
2016-04-15 12:50:34 +02:00
|
|
|
//console.log(event.today);
|
|
|
|
if (event.fullDayEvent) {
|
|
|
|
timeWrapper.innerHTML = (event.today) ? this.config.todayText : moment(event.startDate,"x").fromNow();
|
|
|
|
} else {
|
2016-04-15 13:13:06 +02:00
|
|
|
if (event.startDate >= new Date()) {
|
|
|
|
timeWrapper.innerHTML = moment(event.startDate,"x").fromNow();
|
|
|
|
} else {
|
|
|
|
timeWrapper.innerHTML = this.config.runningText + ' ' + moment(event.endDate,"x").fromNow(true);
|
|
|
|
}
|
2016-04-15 12:50:34 +02:00
|
|
|
}
|
2016-04-05 11:20:47 +02:00
|
|
|
// timeWrapper.innerHTML = moment(event.startDate,'x').format('lll');
|
2016-03-31 11:05:32 +02:00
|
|
|
timeWrapper.className = "time light";
|
|
|
|
eventWrapper.appendChild(timeWrapper);
|
|
|
|
|
|
|
|
wrapper.appendChild(eventWrapper);
|
|
|
|
|
|
|
|
// Create fade effect.
|
|
|
|
if (this.config.fade && this.config.fadePoint < 1) {
|
|
|
|
if (this.config.fadePoint < 0) {
|
|
|
|
this.config.fadePoint = 0;
|
|
|
|
}
|
|
|
|
var startingPoint = events.length * this.config.fadePoint;
|
|
|
|
var steps = events.length - startingPoint;
|
|
|
|
if (e >= startingPoint) {
|
|
|
|
var currentStep = e - startingPoint;
|
|
|
|
eventWrapper.style.opacity = 1 - (1 / steps * currentStep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return wrapper;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* hasCalendarURL(url)
|
|
|
|
* Check if this config contains the calendar url.
|
|
|
|
*
|
|
|
|
* argument url sting - Url to look for.
|
|
|
|
*
|
|
|
|
* return bool - Has calendar url
|
|
|
|
*/
|
|
|
|
hasCalendarURL: function(url) {
|
|
|
|
for (var c in this.config.calendars) {
|
|
|
|
var calendar = this.config.calendars[c];
|
|
|
|
if (calendar.url === url) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* createEventList()
|
|
|
|
* Creates the sorted list of all events.
|
|
|
|
*
|
|
|
|
* return array - Array with events.
|
|
|
|
*/
|
|
|
|
createEventList: function() {
|
|
|
|
var events = [];
|
2016-04-05 14:35:11 -04:00
|
|
|
var today = moment().startOf("day");
|
2016-03-31 11:05:32 +02:00
|
|
|
for (var c in this.calendarData) {
|
|
|
|
var calendar = this.calendarData[c];
|
|
|
|
for (var e in calendar) {
|
|
|
|
var event = calendar[e];
|
|
|
|
event.url = c;
|
2016-04-05 11:20:47 +02:00
|
|
|
event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000);
|
2016-03-31 11:05:32 +02:00
|
|
|
events.push(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-05 14:35:11 -04:00
|
|
|
events.sort(function(a, b) {
|
2016-03-31 11:05:32 +02:00
|
|
|
return a.startDate - b.startDate;
|
|
|
|
});
|
|
|
|
|
|
|
|
return events.slice(0, this.config.maximumEntries);
|
|
|
|
},
|
|
|
|
|
|
|
|
/* createEventList(url)
|
|
|
|
* Requests node helper to add calendar url.
|
|
|
|
*
|
|
|
|
* argument url sting - Url to add.
|
|
|
|
*/
|
|
|
|
addCalendar: function(url) {
|
2016-04-05 14:35:11 -04:00
|
|
|
this.sendSocketNotification("ADD_CALENDAR", {
|
2016-03-31 11:05:32 +02:00
|
|
|
url: url,
|
|
|
|
maximumEntries: this.config.maximumEntries,
|
2016-04-03 19:52:13 +02:00
|
|
|
maximumNumberOfDays: this.config.maximumNumberOfDays,
|
2016-03-31 11:05:32 +02:00
|
|
|
fetchInterval: this.config.fetchInterval
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
/* symbolForUrl(url)
|
|
|
|
* Retrieves the symbol for a specific url.
|
|
|
|
*
|
|
|
|
* argument url sting - Url to look for.
|
|
|
|
*
|
|
|
|
* return string - The Symbol
|
|
|
|
*/
|
|
|
|
symbolForUrl: function(url) {
|
|
|
|
for (var c in this.config.calendars) {
|
|
|
|
var calendar = this.config.calendars[c];
|
2016-04-05 14:35:11 -04:00
|
|
|
if (calendar.url === url && typeof calendar.symbol === "string") {
|
2016-03-31 11:05:32 +02:00
|
|
|
return calendar.symbol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.config.defaultSymbol;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* shorten(string, maxLength)
|
|
|
|
* Shortens a sting if it's longer than maxLenthg.
|
|
|
|
* Adds an ellipsis to the end.
|
|
|
|
*
|
|
|
|
* argument string string - The string to shorten.
|
|
|
|
* argument maxLength number - The max lenth of the string.
|
|
|
|
*
|
|
|
|
* return string - The shortened string.
|
|
|
|
*/
|
|
|
|
shorten: function(string, maxLength) {
|
|
|
|
if (string.length > maxLength) {
|
|
|
|
return string.slice(0,maxLength) + "…";
|
|
|
|
}
|
|
|
|
|
|
|
|
return string;
|
|
|
|
},
|
|
|
|
|
|
|
|
/* titleTransform(title)
|
|
|
|
* Transforms the title of an event for usage.
|
|
|
|
* Replaces parts of the text as defined in config.titleReplace.
|
|
|
|
* Shortens title based on config.maxTitleLength
|
|
|
|
*
|
|
|
|
* argument title string - The title to transform.
|
|
|
|
*
|
|
|
|
* return string - The transformed title.
|
|
|
|
*/
|
|
|
|
titleTransform: function(title) {
|
|
|
|
for (var needle in this.config.titleReplace) {
|
|
|
|
var replacement = this.config.titleReplace[needle];
|
|
|
|
title = title.replace(needle, replacement);
|
|
|
|
}
|
|
|
|
|
|
|
|
title = this.shorten(title, this.config.maxTitleLength);
|
|
|
|
return title;
|
|
|
|
}
|
2016-04-03 19:52:13 +02:00
|
|
|
});
|