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 @@ License Travis Known Vulnerabilities - Slack Status

**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;}