diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab838f7b..6e7ae65d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,6 +18,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Added autoLocation options for weather forcast and current weather modules.
- Added autoTimezone option for the default clock module.
- Danish translation for "Feels" and "Weeks"
+- Added option to split multiple day events in calendar to separate numbered events
+- Slovakian translation
+- Alerts now can contain Font Awesome icons
### Updated
- Bumped the Electron dependency to v3.0.13 to support the most recent Raspbian. [#1500](https://github.com/MichMich/MagicMirror/issues/1500)
@@ -31,6 +34,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Installation script problems with raspbian
- Calendar: only show repeating count if the event is actually repeating [#1534](https://github.com/MichMich/MagicMirror/pull/1534)
- Calendar: Fix exdate handling when multiple values are specified (comma separated)
+- Calendar: Fix relative date handling for fulldate events, calculate difference always from start of day [#1572](https://github.com/MichMich/MagicMirror/issues/1572)
+- Fix null dereference in moduleNeedsUpdate when the module isn't visible
+- Calendar: Fixed event end times by setting default calendarEndTime to "LT" (Local time format). [#1479]
+- Calendar: Fixed missing calendar fetchers after server process restarts [#1589](https://github.com/MichMich/MagicMirror/issues/1589)
### New weather module
- Fixed weather forecast table display [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
diff --git a/README.md b/README.md
index e4248411..1cadc57a 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,6 @@
-
**MagicMirror²** is an open source modular smart mirror platform. With a growing list of installable modules, the **MagicMirror²** allows you to convert your hallway or bathroom mirror into your personal assistant. **MagicMirror²** is built by the creator of [the original MagicMirror](http://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MichMich/MagicMirror/graphs/contributors).
diff --git a/js/main.js b/js/main.js
index 7ec9b5f3..21a882f8 100644
--- a/js/main.js
+++ b/js/main.js
@@ -173,6 +173,10 @@ var MM = (function() {
*/
var moduleNeedsUpdate = function(module, newHeader, newContent) {
var moduleWrapper = document.getElementById(module.identifier);
+ if (moduleWrapper === null) {
+ return false;
+ }
+
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
diff --git a/modules/default/alert/alert.js b/modules/default/alert/alert.js
index cc0ae302..9c0d91a7 100644
--- a/modules/default/alert/alert.js
+++ b/modules/default/alert/alert.js
@@ -24,7 +24,7 @@ Module.register("alert",{
return ["classie.js", "modernizr.custom.js", "notificationFx.js"];
},
getStyles: function() {
- return ["ns-default.css"];
+ return ["ns-default.css", "font-awesome.css"];
},
// Define required translations.
getTranslations: function() {
diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md
index e0d727c8..72aedd74 100755
--- a/modules/default/calendar/README.md
+++ b/modules/default/calendar/README.md
@@ -53,6 +53,8 @@ The following properties can be configured:
| `hidePrivate` | Hides private calendar events.
**Possible values:** `true` or `false`
**Default value:** `false`
| `hideOngoing` | Hides calendar events that have already started.
**Possible values:** `true` or `false`
**Default value:** `false`
| `excludedEvents` | An array of words / phrases from event titles that will be excluded from being shown.
Additionally advanced filter objects can be passed in. Below is the configuration for the advance filtering object.
**Required**
`filterBy` - string used to determine if filter is applied.
**Optional**
`until` - Time before an event to display it Ex: [`'3 days'`, `'2 months'`, `'1 week'`]
`caseSensitive` - By default, excludedEvents are case insensitive, set this to true to enforce case sensitivity
`regex` - set to `true` if filterBy is a regex. For those not familiar with regex it is used for pattern matching, please see [here](https://regexr.com/) for more info.
**Example:** `['Birthday', 'Hide This Event', {filterBy: 'Payment', until: '6 days', caseSensitive: true}, {filterBy: '^[0-9]{1,}.*', regex: true}]`
**Default value:** `[]`
+| `sliceMultiDayEvents` | If this is set to true, events exceeding at least one midnight will be sliced into separate events including a counter like (1/2). This is especially helpful in "dateheaders" mode. Events will be sliced at midnight, end time for all events but the last will be 23:59 **Default value:** `true`
+
### Calendar configuration
diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js
index 2c2970ec..a6eeb226 100755
--- a/modules/default/calendar/calendar.js
+++ b/modules/default/calendar/calendar.js
@@ -26,7 +26,7 @@ Module.register("calendar", {
urgency: 7,
timeFormat: "relative",
dateFormat: "MMM Do",
- dateEndFormat: "HH:mm",
+ dateEndFormat: "LT",
fullDayEventDateFormat: "MMM Do",
showEnd: false,
getRelative: 6,
@@ -47,7 +47,8 @@ Module.register("calendar", {
"'s birthday": ""
},
broadcastEvents: true,
- excludedEvents: []
+ excludedEvents: [],
+ sliceMultiDayEvents: false
},
// Define required scripts.
@@ -104,6 +105,13 @@ Module.register("calendar", {
}
this.addCalendar(calendar.url, calendar.auth, calendarConfig);
+
+ // Trigger ADD_CALENDAR every fetchInterval to make sure there is always a calendar
+ // fetcher running on the server side.
+ var self = this;
+ setInterval(function() {
+ self.addCalendar(calendar.url, calendar.auth, calendarConfig);
+ }, self.config.fetchInterval);
}
this.calendarData = {};
@@ -297,12 +305,12 @@ Module.register("calendar", {
if (this.config.timeFormat === "absolute") {
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 = this.capFirst(moment(event.startDate, "x").fromNow());
+ timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
} else {
timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat));
}
} else {
- timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow());
+ timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").from(moment().format("YYYYMMDD")));
}
}
if(this.config.showEnd){
@@ -448,7 +456,31 @@ Module.register("calendar", {
}
event.url = c;
event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000);
- events.push(event);
+
+ /* if sliceMultiDayEvents is set to true, multiday events (events exceeding at least one midnight) are sliced into days,
+ * otherwise, esp. in dateheaders mode it is not clear how long these events are.
+ */
+ if (this.config.sliceMultiDayEvents) {
+ var midnight = moment(event.startDate, "x").clone().startOf("day").add(1, "day").format("x"); //next midnight
+ var count = 1;
+ var maxCount = Math.ceil(((event.endDate - 1) - moment(event.startDate, "x").endOf("day").format("x"))/(1000*60*60*24)) + 1
+ if (event.endDate > midnight) {
+ while (event.endDate > midnight) {
+ var nextEvent = JSON.parse(JSON.stringify(event)); //make a copy without reference to the original event
+ nextEvent.startDate = midnight;
+ event.endDate = midnight;
+ event.title += " (" + count + "/" + maxCount + ")";
+ events.push(event);
+ event = nextEvent;
+ count += 1;
+ midnight = moment(midnight, "x").add(1, "day").format("x"); //move further one day for next split
+ }
+ event.title += " ("+count+"/"+maxCount+")";
+ }
+ events.push(event);
+ } else {
+ events.push(event);
+ }
}
}
diff --git a/translations/sk.json b/translations/sk.json
new file mode 100644
index 00000000..8eaeba6d
--- /dev/null
+++ b/translations/sk.json
@@ -0,0 +1,33 @@
+{
+ "LOADING": "Načítanie …",
+
+ "TODAY": "Dnes",
+ "TOMORROW": "Zajtra",
+ "DAYAFTERTOMORROW": "Pozajtra",
+ "RUNNING": "Končí o",
+ "EMPTY": "Žiadne nadchádzajúce udalosti.",
+
+ "WEEK": "{weekNumber}. týždeň",
+
+ "N": "S",
+ "NNE": "SSV",
+ "NE": "SV",
+ "ENE": "VSV",
+ "E": "V",
+ "ESE": "VJV",
+ "SE": "JV",
+ "SSE": "JJV",
+ "S": "J",
+ "SSW": "JJZ",
+ "SW": "JZ",
+ "WSW": "ZJZ",
+ "W": "Z",
+ "WNW": "ZSZ",
+ "NW": "SZ",
+ "NNW": "SSZ",
+
+ "UPDATE_NOTIFICATION": "Dostupná aktualizácia pre MagicMirror².",
+ "UPDATE_NOTIFICATION_MODULE": "Dostupná aktualizácia pre modul {MODULE_NAME}.",
+ "UPDATE_INFO_SINGLE": "Súčasná inštalácia je na vetve {BRANCH_NAME} pozadu o {COMMIT_COUNT} commit.",
+ "UPDATE_INFO_MULTIPLE": "Súčasná inštalácia je na vetve {BRANCH_NAME} pozadu o {COMMIT_COUNT} commitov."
+}
diff --git a/translations/translations.js b/translations/translations.js
index 6625acde..39bf8d5b 100644
--- a/translations/translations.js
+++ b/translations/translations.js
@@ -38,7 +38,8 @@ var translations = {
"cy" : "translations/cy.json", // Welsh (Cymraeg)
"bg" : "translations/bg.json", // Bulgarian
"cs" : "translations/cs.json", // Czech
- "hr" : "translations/hr.json" // Croatian
+ "hr" : "translations/hr.json", // Croatian
+ "sk" : "translations/sk.json" // Slovak
};
if (typeof module !== "undefined") {module.exports = translations;}