From a7db8cf7cdb818516b6e3a97f044ce65a44ce302 Mon Sep 17 00:00:00 2001 From: Andrew McOlash Date: Wed, 17 Aug 2016 21:51:48 -0500 Subject: [PATCH 001/169] Humidity data to the current weather module --- modules/default/currentweather/README.md | 11 ++- .../default/currentweather/currentweather.css | 4 + .../default/currentweather/currentweather.js | 85 +++++++++++-------- 3 files changed, 64 insertions(+), 36 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 2a6f78445b..1cafd11a8d 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -14,7 +14,7 @@ modules: [ config: { // See 'Configuration options' for more information. location: 'Amsterdam,Netherlands', - locationID: '', //Location ID from http://bulk.openweather.org/sample/ + locationID: '', //Location ID from http://bulk.openweather.org/sample/ appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key. } } @@ -35,7 +35,7 @@ The following properties can be configured: - + location The location used for weather information.
@@ -106,6 +106,13 @@ The following properties can be configured: + showHumidity + Show the current humidity
+
Possible values: true or false +
Default value: false + + + useBeaufort Pick between using the Beaufort scale for wind speed or using the default units.

Possible values: true or false diff --git a/modules/default/currentweather/currentweather.css b/modules/default/currentweather/currentweather.css index 9e9d9ed39a..08c040d6a0 100644 --- a/modules/default/currentweather/currentweather.css +++ b/modules/default/currentweather/currentweather.css @@ -6,3 +6,7 @@ -webkit-transform: translate(0, -3px); /* Safari */ transform: translate(0, -3px); } + +.currentweather .humidity-padding { + padding-bottom: 6px; +} diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index db3d5de2f4..5875c12117 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -23,6 +23,7 @@ Module.register("currentweather",{ showWindDirection: true, useBeaufort: true, lang: config.language, + showHumidity: false, initialLoadDelay: 0, // 0 seconds delay retryDelay: 2500, @@ -142,6 +143,21 @@ Module.register("currentweather",{ sunriseSunsetTime.innerHTML = " " + this.sunriseSunsetTime; small.appendChild(sunriseSunsetTime); + wrapper.appendChild(small); + + if (this.config.showHumidity) { + var middle = document.createElement("div"); + middle.className = "normal small humidity-padding"; + + var humidity = document.createElement("span"); + humidity.innerHTML = "Humidity: " + this.humidity + "%"; // TODO: Localization + var br = document.createElement("br"); + + middle.appendChild(humidity); + middle.appendChild(br); + wrapper.appendChild(middle); + } + var large = document.createElement("div"); large.className = "large light"; @@ -154,8 +170,8 @@ Module.register("currentweather",{ temperature.innerHTML = " " + this.temperature + "°"; large.appendChild(temperature); - wrapper.appendChild(small); wrapper.appendChild(large); + return wrapper; }, @@ -224,6 +240,7 @@ Module.register("currentweather",{ return; } + this.humidity = parseFloat(data.main.humidity); this.temperature = this.roundValue(data.main.temp); if (this.config.useBeaufort){ @@ -315,39 +332,39 @@ Module.register("currentweather",{ */ deg2Cardinal: function(deg) { - if (deg>11.25 && deg<=33.75){ - return "NNE"; - } else if (deg > 33.75 && deg <= 56.25) { - return "NE"; - } else if (deg > 56.25 && deg <= 78.75) { - return "ENE"; - } else if (deg > 78.75 && deg <= 101.25) { - return "E"; - } else if (deg > 101.25 && deg <= 123.75) { - return "ESE"; - } else if (deg > 123.75 && deg <= 146.25) { - return "SE"; - } else if (deg > 146.25 && deg <= 168.75) { - return "SSE"; - } else if (deg > 168.75 && deg <= 191.25) { - return "S"; - } else if (deg > 191.25 && deg <= 213.75) { - return "SSW"; - } else if (deg > 213.75 && deg <= 236.25) { - return "SW"; - } else if (deg > 236.25 && deg <= 258.75) { - return "WSW"; - } else if (deg > 258.75 && deg <= 281.25) { - return "W"; - } else if (deg > 281.25 && deg <= 303.75) { - return "WNW"; - } else if (deg > 303.75 && deg <= 326.25) { - return "NW"; - } else if (deg > 326.25 && deg <= 348.75) { - return "NNW"; - } else { - return "N"; - } + if (deg>11.25 && deg<=33.75){ + return "NNE"; + } else if (deg > 33.75 && deg <= 56.25) { + return "NE"; + } else if (deg > 56.25 && deg <= 78.75) { + return "ENE"; + } else if (deg > 78.75 && deg <= 101.25) { + return "E"; + } else if (deg > 101.25 && deg <= 123.75) { + return "ESE"; + } else if (deg > 123.75 && deg <= 146.25) { + return "SE"; + } else if (deg > 146.25 && deg <= 168.75) { + return "SSE"; + } else if (deg > 168.75 && deg <= 191.25) { + return "S"; + } else if (deg > 191.25 && deg <= 213.75) { + return "SSW"; + } else if (deg > 213.75 && deg <= 236.25) { + return "SW"; + } else if (deg > 236.25 && deg <= 258.75) { + return "WSW"; + } else if (deg > 258.75 && deg <= 281.25) { + return "W"; + } else if (deg > 281.25 && deg <= 303.75) { + return "WNW"; + } else if (deg > 303.75 && deg <= 326.25) { + return "NW"; + } else if (deg > 326.25 && deg <= 348.75) { + return "NNW"; + } else { + return "N"; + } }, From c6f424201b7b3fe9d8d444250937074d1179eee7 Mon Sep 17 00:00:00 2001 From: Andrew McOlash Date: Thu, 18 Aug 2016 09:32:19 -0500 Subject: [PATCH 002/169] Fix indentation and spacing --- modules/default/currentweather/README.md | 6 +- .../default/currentweather/currentweather.js | 67 +++++++++---------- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 1cafd11a8d..3df8817390 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -14,7 +14,7 @@ modules: [ config: { // See 'Configuration options' for more information. location: 'Amsterdam,Netherlands', - locationID: '', //Location ID from http://bulk.openweather.org/sample/ + locationID: '', //Location ID from http://bulk.openweather.org/sample/ appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key. } } @@ -35,7 +35,7 @@ The following properties can be configured: - + location The location used for weather information.
@@ -112,7 +112,7 @@ The following properties can be configured:
Default value: false - + useBeaufort Pick between using the Beaufort scale for wind speed or using the default units.

Possible values: true or false diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 5875c12117..57884ad7f4 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -171,7 +171,6 @@ Module.register("currentweather",{ large.appendChild(temperature); wrapper.appendChild(large); - return wrapper; }, @@ -332,39 +331,39 @@ Module.register("currentweather",{ */ deg2Cardinal: function(deg) { - if (deg>11.25 && deg<=33.75){ - return "NNE"; - } else if (deg > 33.75 && deg <= 56.25) { - return "NE"; - } else if (deg > 56.25 && deg <= 78.75) { - return "ENE"; - } else if (deg > 78.75 && deg <= 101.25) { - return "E"; - } else if (deg > 101.25 && deg <= 123.75) { - return "ESE"; - } else if (deg > 123.75 && deg <= 146.25) { - return "SE"; - } else if (deg > 146.25 && deg <= 168.75) { - return "SSE"; - } else if (deg > 168.75 && deg <= 191.25) { - return "S"; - } else if (deg > 191.25 && deg <= 213.75) { - return "SSW"; - } else if (deg > 213.75 && deg <= 236.25) { - return "SW"; - } else if (deg > 236.25 && deg <= 258.75) { - return "WSW"; - } else if (deg > 258.75 && deg <= 281.25) { - return "W"; - } else if (deg > 281.25 && deg <= 303.75) { - return "WNW"; - } else if (deg > 303.75 && deg <= 326.25) { - return "NW"; - } else if (deg > 326.25 && deg <= 348.75) { - return "NNW"; - } else { - return "N"; - } + if (deg>11.25 && deg<=33.75){ + return "NNE"; + } else if (deg > 33.75 && deg <= 56.25) { + return "NE"; + } else if (deg > 56.25 && deg <= 78.75) { + return "ENE"; + } else if (deg > 78.75 && deg <= 101.25) { + return "E"; + } else if (deg > 101.25 && deg <= 123.75) { + return "ESE"; + } else if (deg > 123.75 && deg <= 146.25) { + return "SE"; + } else if (deg > 146.25 && deg <= 168.75) { + return "SSE"; + } else if (deg > 168.75 && deg <= 191.25) { + return "S"; + } else if (deg > 191.25 && deg <= 213.75) { + return "SSW"; + } else if (deg > 213.75 && deg <= 236.25) { + return "SW"; + } else if (deg > 236.25 && deg <= 258.75) { + return "WSW"; + } else if (deg > 258.75 && deg <= 281.25) { + return "W"; + } else if (deg > 281.25 && deg <= 303.75) { + return "WNW"; + } else if (deg > 303.75 && deg <= 326.25) { + return "NW"; + } else if (deg > 326.25 && deg <= 348.75) { + return "NNW"; + } else { + return "N"; + } }, From a592ca25ffb7a578f36981e77ce27b16a47048d1 Mon Sep 17 00:00:00 2001 From: Andrew McOlash Date: Sun, 28 Aug 2016 01:52:08 -0500 Subject: [PATCH 003/169] Add in icon for the current humidity --- modules/default/currentweather/currentweather.css | 4 ++++ modules/default/currentweather/currentweather.js | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/default/currentweather/currentweather.css b/modules/default/currentweather/currentweather.css index 08c040d6a0..768b0f8d9f 100644 --- a/modules/default/currentweather/currentweather.css +++ b/modules/default/currentweather/currentweather.css @@ -7,6 +7,10 @@ transform: translate(0, -3px); } +.currentweather .humidityIcon { + padding-right: 8px; +} + .currentweather .humidity-padding { padding-bottom: 6px; } diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 57884ad7f4..87e4d04ab5 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -149,10 +149,15 @@ Module.register("currentweather",{ var middle = document.createElement("div"); middle.className = "normal small humidity-padding"; + var humidityIcon = document.createElement("span"); + humidityIcon.className = "wi wi-humidity humidityIcon"; + small.appendChild(sunriseSunsetIcon); + var humidity = document.createElement("span"); - humidity.innerHTML = "Humidity: " + this.humidity + "%"; // TODO: Localization + humidity.innerHTML = this.humidity + "%"; var br = document.createElement("br"); + middle.appendChild(humidityIcon); middle.appendChild(humidity); middle.appendChild(br); wrapper.appendChild(middle); From 853fa870121f89905ab8e8bebb676cceb3e876bb Mon Sep 17 00:00:00 2001 From: Andrew McOlash Date: Sun, 28 Aug 2016 01:58:56 -0500 Subject: [PATCH 004/169] Slight change to padding of humidity icon, just too much before --- modules/default/currentweather/currentweather.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/currentweather/currentweather.css b/modules/default/currentweather/currentweather.css index 768b0f8d9f..a40be87811 100644 --- a/modules/default/currentweather/currentweather.css +++ b/modules/default/currentweather/currentweather.css @@ -8,7 +8,7 @@ } .currentweather .humidityIcon { - padding-right: 8px; + padding-right: 4px; } .currentweather .humidity-padding { From c1b8fc123350f6a14f845b69f31529d18d81d002 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 00:39:46 +0200 Subject: [PATCH 005/169] calendar dates are uniformly capitalized This is an attempt at standardizing the calendar layout. Currently the calendar times are only partly capitalized, some time phrases start with lower-case letters, some don't (The ones pulled from the TRANSLATIONS folder start with upper-case letters, the others don't). Behavior has been changed to create a more standardized layout. --- modules/default/calendar/calendar.js | 39 ++++++++++++++++------------ 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index d487133838..9b83e3c54c 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -147,18 +147,14 @@ Module.register("calendar",{ var one_day = one_hour * 24; if (event.fullDayEvent) { if (event.today) { - timeWrapper.innerHTML = this.translate("TODAY"); + timeWrapper.innerHTML = this.capFirst(this.translate("TODAY")); } else if (event.startDate - now < one_day && event.startDate - now > 0) { - timeWrapper.innerHTML = this.translate("TOMORROW"); + timeWrapper.innerHTML = this.capFirst(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("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 @@ -171,12 +167,12 @@ Module.register("calendar",{ if (this.config.timeFormat === "absolute") { if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) { // 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("MMM Do")); } } else { - timeWrapper.innerHTML = moment(event.startDate, "x").fromNow(); + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); } } } else { @@ -185,10 +181,10 @@ Module.register("calendar",{ // This event is within the next 48 hours (2 days) if (event.startDate - now < 6 * one_hour) { // 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 @@ -201,16 +197,16 @@ Module.register("calendar",{ if (this.config.timeFormat === "absolute") { if ((this.config.urgency > 1) && (event.startDate - now < (this.config.urgency * one_day))) { // 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("MMM Do")); } } 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")) + ' ' + this.capFirst(moment(event.endDate,"x").fromNow(true)); } } //timeWrapper.innerHTML += ' - '+ moment(event.startDate,'x').format('lll'); @@ -346,6 +342,15 @@ Module.register("calendar",{ 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. From 8f4effbb8df33e01e276936455a7158c192b2ad3 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:17:46 +0200 Subject: [PATCH 006/169] poinst of time when calendar event gets relative now customizable --- modules/default/calendar/calendar.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 9b83e3c54c..31395c4f07 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -23,6 +23,7 @@ Module.register("calendar",{ fade: true, urgency: 7, timeFormat: "relative", + getRelative: '6', fadePoint: 0.25, // Start on 1/4th of the list. calendars: [ { @@ -179,7 +180,7 @@ Module.register("calendar",{ if (event.startDate >= new Date()) { if (event.startDate - now < 2 * one_day) { // This event is within the next 48 hours (2 days) - if (event.startDate - now < 6 * one_hour) { + if (event.startDate - now < this.config.getRelative * one_hour) { // If event is within 6 hour, display 'in xxx' time format or moment.fromNow() timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); } else { From 4ca185cf45fedbf5eac85ec0d79c61ac9653c20a Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:22:37 +0200 Subject: [PATCH 007/169] point of time when calendar event gets relative now customizable --- modules/default/calendar/calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 31395c4f07..e4827b10ec 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -21,7 +21,7 @@ Module.register("calendar",{ fetchInterval: 5 * 60 * 1000, // Update every 5 minutes. animationSpeed: 2000, fade: true, - urgency: 7, + urgency: 7, timeFormat: "relative", getRelative: '6', fadePoint: 0.25, // Start on 1/4th of the list. From 493367da5ea73a4b54fb3f7efe49c15b64d325dc Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:22:51 +0200 Subject: [PATCH 008/169] point of time when calendar event gets relative now customizable --- modules/default/calendar/calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index e4827b10ec..31395c4f07 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -21,7 +21,7 @@ Module.register("calendar",{ fetchInterval: 5 * 60 * 1000, // Update every 5 minutes. animationSpeed: 2000, fade: true, - urgency: 7, + urgency: 7, timeFormat: "relative", getRelative: '6', fadePoint: 0.25, // Start on 1/4th of the list. From f47b8084787bc3a398a067c78e3b9eb0569292d2 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:28:07 +0200 Subject: [PATCH 009/169] Added calendar.js tweaks (capitalization / 'getRelative' tag) --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e2cda4214..63acbfa30d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Added ability to remove tags from the beginning or end of newsfeed items in 'newsfeed.js'. - Added ability to define "the day after tomorrow" for calendar events (Definition for German and Dutch already included). +- Added ability to change the point of time when calendar events get relative. + +### Changed +- Calendar times are now uniformly capitalized + ## [2.0.4] - 2016-08-07 From c4c8955bc28cf9276c6d48116b7b69b56c01d1d8 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:36:29 +0200 Subject: [PATCH 010/169] Added 'getRelative' tag --- modules/default/calendar/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 3189d92c90..2a9573d065 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -126,6 +126,13 @@ The following properties can be configured:
Default value: relative + + getRelative + Determine how much time (in hours) should be left when calendar events start getting relative (If you want this to start half an hour before an event occurs)
+
Possible values: 0 (never) - 48 (48 hours before the event) +
Default value: 6 + + urgency When using a timeFormat of absolute, the urgency setting allows you to display events within a specific time frame as relative From 4e47f9eb6831022d8f5c38aaaf57d90a7badb532 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:37:09 +0200 Subject: [PATCH 011/169] Added 'getRelative' tag --- modules/default/calendar/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 2a9573d065..5bd3aceb9a 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -129,7 +129,7 @@ The following properties can be configured: getRelative Determine how much time (in hours) should be left when calendar events start getting relative (If you want this to start half an hour before an event occurs)
-
Possible values: 0 (never) - 48 (48 hours before the event) +
Possible values: 0 (never) - 48 (48 hours before the event)
Default value: 6 From e1fa5fb18044c458e390781d9ebbb5d379934e44 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:39:32 +0200 Subject: [PATCH 012/169] Added 'getRelative' tag --- modules/default/calendar/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 5bd3aceb9a..1f22dae4c1 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -128,7 +128,7 @@ The following properties can be configured: getRelative - Determine how much time (in hours) should be left when calendar events start getting relative (If you want this to start half an hour before an event occurs)
+ Determine how much time (in hours) should be left until calendar events start getting relative

Possible values: 0 (never) - 48 (48 hours before the event)
Default value: 6 From 2dfdedf7b0accd2132a48849fba58f9e4984be26 Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:40:29 +0200 Subject: [PATCH 013/169] Update README.md --- modules/default/calendar/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 1f22dae4c1..01dc66451f 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -129,7 +129,7 @@ The following properties can be configured: getRelative Determine how much time (in hours) should be left until calendar events start getting relative
-
Possible values: 0 (never) - 48 (48 hours before the event) +
Possible values: 0 (events stay absolute) - 48 (48 hours before the event starts)
Default value: 6 From 0ff4884d3a2519dc1fa3caea547c8f1ad763371b Mon Sep 17 00:00:00 2001 From: Jens Date: Sat, 3 Sep 2016 23:42:24 +0200 Subject: [PATCH 014/169] Added 'getRelative' tag --- modules/default/calendar/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 01dc66451f..611c6be4ad 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -128,7 +128,7 @@ The following properties can be configured: getRelative - Determine how much time (in hours) should be left until calendar events start getting relative
+ How much time (in hours) should be left until calendar events start getting relative?

Possible values: 0 (events stay absolute) - 48 (48 hours before the event starts)
Default value: 6 From 4630740ac7d6baf1adf22128102066f833ebef3a Mon Sep 17 00:00:00 2001 From: Jens Date: Sun, 4 Sep 2016 00:05:02 +0200 Subject: [PATCH 015/169] Added 'getRelative' tag --- modules/default/calendar/calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 31395c4f07..d480679f5a 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -23,7 +23,7 @@ Module.register("calendar",{ fade: true, urgency: 7, timeFormat: "relative", - getRelative: '6', + getRelative: 6, fadePoint: 0.25, // Start on 1/4th of the list. calendars: [ { From 63351553d840193e4280d06abe33ecba00c43035 Mon Sep 17 00:00:00 2001 From: Jens Date: Sun, 4 Sep 2016 14:24:49 +0200 Subject: [PATCH 016/169] calendar.js doesn't overcapitalize future events --- modules/default/calendar/calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index d480679f5a..6477ac4ebc 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -207,7 +207,7 @@ Module.register("calendar",{ } } } else { - timeWrapper.innerHTML = this.capFirst(this.translate("RUNNING")) + ' ' + this.capFirst(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'); From b2a7d3584bad2752d59d2325c581f5018e875306 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 20 Sep 2016 17:22:24 +0200 Subject: [PATCH 017/169] Add getHeader functionlity.. --- CHANGELOG.md | 8 +++++++- js/main.js | 44 +++++++++++++++++++++++++++++++------------- js/module.js | 11 +++++++++++ modules/README.md | 17 +++++++++++++++++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f95c84fa..859ca30dfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,19 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). + +## [2.1.0] - Unreleased + +### Added +- Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) + ## [2.0.5] - 2016-09-20 ### Added - Added ability to remove tags from the beginning or end of newsfeed items in 'newsfeed.js'. - Added ability to define "the day after tomorrow" for calendar events (Definition for German and Dutch already included). - Added CII Badge (we are compliant with the CII Best Practices) -- Add support for doing http basic auth when loading calendars +- Add support for doing http basic auth when loading calendars - Add the abilty to turn off and on the date display in the Clock Module ### Fixed diff --git a/js/main.js b/js/main.js index abd93e40ad..c0c6300638 100644 --- a/js/main.js +++ b/js/main.js @@ -40,6 +40,7 @@ var MM = (function() { if (typeof module.data.header !== "undefined" && module.data.header !== "") { var moduleHeader = document.createElement("header"); moduleHeader.innerHTML = module.data.header; + moduleHeader.className = "module-header"; dom.appendChild(moduleHeader); } @@ -94,26 +95,27 @@ var MM = (function() { */ var updateDom = function(module, speed) { var newContent = module.getDom(); + var newHeader = module.getHeader(); if (!module.hidden) { - if (!moduleNeedsUpdate(module, newContent)) { + if (!moduleNeedsUpdate(module, newHeader, newContent)) { return; } if (!speed) { - updateModuleContent(module, newContent); + updateModuleContent(module, newHeader, newContent); return; } hideModule(module, speed / 2, function() { - updateModuleContent(module, newContent); + updateModuleContent(module, newHeader, newContent); if (!module.hidden) { showModule(module, speed / 2); } }); } else { - updateModuleContent(module, newContent); + updateModuleContent(module, newHeader, newContent); } }; @@ -125,14 +127,23 @@ var MM = (function() { * * return bool - Does the module need an update? */ - var moduleNeedsUpdate = function(module, newContent) { + var moduleNeedsUpdate = function(module, newHeader, newContent) { var moduleWrapper = document.getElementById(module.identifier); - var contentWrapper = moduleWrapper.getElementsByClassName("module-content")[0]; + var contentWrapper = moduleWrapper.getElementsByClassName("module-content"); + var headerWrapper = moduleWrapper.getElementsByClassName("module-header"); - var tempWrapper = document.createElement("div"); - tempWrapper.appendChild(newContent); + var headerNeedsUpdate = false; + var contentNeedsUpdate = false; - return tempWrapper.innerHTML !== contentWrapper.innerHTML; + if (headerWrapper.length > 0) { + headerNeedsUpdate = newHeader !== headerWrapper.innerHTML; + } + + var tempContentWrapper = document.createElement("div"); + tempContentWrapper.appendChild(newContent); + contentNeedsUpdate = tempContentWrapper.innerHTML !== contentWrapper[0].innerHTML; + + return headerNeedsUpdate || contentNeedsUpdate; }; /* moduleNeedsUpdate(module, newContent) @@ -141,12 +152,19 @@ var MM = (function() { * argument module Module - The module to check. * argument newContent Domobject - The new content that is generated. */ - var updateModuleContent = function(module, content) { + var updateModuleContent = function(module, newHeader, newContent) { var moduleWrapper = document.getElementById(module.identifier); - var contentWrapper = moduleWrapper.getElementsByClassName("module-content")[0]; + var headerWrapper = moduleWrapper.getElementsByClassName("module-header"); + var contentWrapper = moduleWrapper.getElementsByClassName("module-content"); + + contentWrapper[0].innerHTML = ""; + contentWrapper[0].appendChild(newContent); + + if( headerWrapper.length > 0 && newHeader) { + headerWrapper[0].innerHTML = newHeader; + } + - contentWrapper.innerHTML = ""; - contentWrapper.appendChild(content); }; /* hideModule(module, speed, callback) diff --git a/js/module.js b/js/module.js index 293d00b553..9c26bc7b0a 100644 --- a/js/module.js +++ b/js/module.js @@ -84,6 +84,17 @@ var Module = Class.extend({ return div; }, + /* getHeader() + * This method generates the header string which needs to be displayed if a user has a header configured for this module. + * This method is called by the Magic Mirror core, but only if the user has configured a default header for the module. + * This method needs to be subclassed if the module wants to display modified headers on the mirror. + * + * return string - The header to display above the header. + */ + getHeader: function() { + return this.data.header; + }, + /* notificationReceived(notification, payload, sender) * This method is called when a notification arrives. * This method is called by the Magic Mirror core. diff --git a/modules/README.md b/modules/README.md index f4a8debd2d..61989a93f7 100644 --- a/modules/README.md +++ b/modules/README.md @@ -166,6 +166,23 @@ getDom: function() { ```` +####`getHeader()` +**Should return:** String + +Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getHeader method to retrieve the module's header. This method should therefor return a string. If this method is not subclassed, this function will return the user's configured header. + +If you want to use the original user's configured header, reference `this.data.header`. + +**NOTE:** If the user did not confiugure a default header, no header will be displayed and thus this method will not be called. + +**Example:** +````javascript +getHeader: function() { + return this.data.header + ' Foo Bar'; +} + +```` + ####`notificationReceived(notification, payload, sender)` That MagicMirror core has the ability to send notifications to modules. Or even better: the modules have the possibility to send notifications to other modules. When this module is called, it has 3 arguments: From 56a45977840257de78e909e6e0cd58a1b2d0b149 Mon Sep 17 00:00:00 2001 From: Wilco Land Date: Wed, 21 Sep 2016 09:57:47 +0200 Subject: [PATCH 018/169] Update fy.json Added "DAYAFTERTOMORROW" --- translations/fy.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/fy.json b/translations/fy.json index af6bcde8da..770ae3a1bd 100644 --- a/translations/fy.json +++ b/translations/fy.json @@ -5,6 +5,7 @@ /* CALENDAR */ "TODAY": "Hjoed", "TOMORROW": "Moarn", + "DAYAFTERTOMORROW": "Oaremoarn", "RUNNING": "Einigest oer", "EMPTY": "Gjin plande ôfspraken.", From 30eaec29d34af1048db3c8c7c967384b16fb448a Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Wed, 21 Sep 2016 10:29:34 +0200 Subject: [PATCH 019/169] Modified translations for Frysk. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 859ca30dfb..1f78e9ed20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) +### Updated +- Modified translations for Frysk. + ## [2.0.5] - 2016-09-20 ### Added From 4ff86795b9a6c55ab16023609fb7e6e5e304646c Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 22 Sep 2016 19:56:54 +0200 Subject: [PATCH 020/169] Snyk security update. --- CHANGELOG.md | 3 ++- package.json | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f78e9ed20..326bfc49de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [2.1.0] - Unreleased ### Added -- Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) +- Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) ### Updated - Modified translations for Frysk. +- Updated package.json as a result of Snyk security update. ## [2.0.5] - 2016-09-20 diff --git a/package.json b/package.json index ad2c010927..afdad5f610 100644 --- a/package.json +++ b/package.json @@ -37,17 +37,17 @@ "time-grunt": "latest" }, "dependencies": { - "electron-prebuilt": "latest", + "electron-prebuilt": "^0.37.2", "express": "^4.14.0", "feedme": "latest", "iconv-lite": "latest", "moment": "latest", "request": "^2.74.0", "rrule": "latest", + "snyk": "^1.14.1", "socket.io": "^1.4.6", "valid-url": "latest", - "walk": "latest", - "snyk": "^1.14.1" + "walk": "latest" }, "snyk": true } From ca95c75df3b3e52e5d1f5f832d1a4c5bf402736e Mon Sep 17 00:00:00 2001 From: Kasper Wandahl Fogh Date: Sat, 24 Sep 2016 10:41:44 +0200 Subject: [PATCH 021/169] Added danish translation --- translations/da.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 translations/da.json diff --git a/translations/da.json b/translations/da.json new file mode 100644 index 0000000000..06827ea1f8 --- /dev/null +++ b/translations/da.json @@ -0,0 +1,28 @@ +{ + /* GENERAL */ + "LOADING": "Indlæser …", + + /* CALENDAR */ + "TODAY": "I dag", + "TOMORROW": "I morgen", + "RUNNING": "Slutter om", + "EMPTY": "Ingen kommende begivenheder.", + + /* WEATHER */ + "N": "N", + "NNE": "NNØ", + "NE": "NØ", + "ENE": "ØNØ", + "E": "Ø", + "ESE": "ØSØ", + "SE": "SØ", + "SSE": "SSØ", + "S": "S", + "SSW": "SSV", + "SW": "SV", + "WSW": "VSV", + "W": "V", + "WNW": "VNV", + "NW": "NV", + "NNW": "NNV" +} From 02ac9fa0d7d467492158ccbad688449fc70627ec Mon Sep 17 00:00:00 2001 From: Kasper Wandahl Fogh Date: Sat, 24 Sep 2016 10:57:02 +0200 Subject: [PATCH 022/169] Added danish in translations.js and updated changelog --- CHANGELOG.md | 5 +++++ translations/translations.js | 1 + 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f95c84fa..8fc2151622 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [unreleased] - 2016-09-24 + +### Added +- Danish translation + ## [2.0.5] - 2016-09-20 ### Added diff --git a/translations/translations.js b/translations/translations.js index 2a458ef26e..c9d5db0a30 100644 --- a/translations/translations.js +++ b/translations/translations.js @@ -23,4 +23,5 @@ var translations = { "ja" : "translations/ja.json", // Japanese "pl" : "translations/pl.json", // Polish "gr" : "translations/gr.json", // Greek + "da" : "translations/da.json", // Danish }; From fc0c706100ba39ad6b8ba575692d1baadc284456 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 29 Sep 2016 11:05:37 +0200 Subject: [PATCH 023/169] Add MagPi Logo --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index d86cca7ca5..8e44f42b70 100644 --- a/README.md +++ b/README.md @@ -129,3 +129,8 @@ Please keep the following in mind: - **New Features**: please please discuss in a GitHub issue before you start to alter a big part of the code. Without discussion upfront, the pull request will not be accepted / merged. Thanks for your help in making MagicMirror² better! + +

+
+ MagPi Top 50 +

From 54f04c9141c3acf7cdca2d3d1ebb5b8c4f98e478 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 29 Sep 2016 11:12:49 +0200 Subject: [PATCH 024/169] Fix ESLint issues --- js/class.js | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/js/class.js b/js/class.js index b1793f1639..9d04944e0d 100644 --- a/js/class.js +++ b/js/class.js @@ -25,24 +25,22 @@ for (var name in prop) { // Check if we're overwriting an existing function prototype[name] = typeof prop[name] == "function" && - typeof _super[name] == "function" && fnTest.test(prop[name]) ? - (function(name, fn) { - return function() { - var tmp = this._super; + typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn) { + return function() { + var tmp = this._super; - // Add a new ._super() method that is the same method - // but on the super-class - this._super = _super[name]; + // Add a new ._super() method that is the same method + // but on the super-class + this._super = _super[name]; - // The method only need to be bound temporarily, so we - // remove it when we're done executing - var ret = fn.apply(this, arguments); - this._super = tmp; + // The method only need to be bound temporarily, so we + // remove it when we're done executing + var ret = fn.apply(this, arguments); + this._super = tmp; - return ret; - }; - })(name, prop[name]) : - prop[name]; + return ret; + }; + })(name, prop[name]) : prop[name]; } // The dummy class constructor From 5d29fa5e626c7f990d84fa81c556d824f8761d41 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 16:34:57 +0200 Subject: [PATCH 025/169] ip address filtering --- CHANGELOG.md | 1 + config/config.js.sample | 3 +++ js/server.js | 6 ++++++ package.json | 1 + 4 files changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 326bfc49de..74cb3f7e61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) +- Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)) ### Updated - Modified translations for Frysk. diff --git a/config/config.js.sample b/config/config.js.sample index 04c7fba99a..b10c991555 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -6,6 +6,9 @@ var config = { port: 8080, + ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], + // you use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] + // you use also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] language: 'en', timeFormat: 24, diff --git a/js/server.js b/js/server.js index 2ab0b1b9de..b8dcec5997 100644 --- a/js/server.js +++ b/js/server.js @@ -10,11 +10,17 @@ var app = require("express")(); var server = require("http").Server(app); var io = require("socket.io")(server); var path = require("path"); +var ipfilter = require('express-ipfilter').IpFilter; var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); server.listen(config.port); + if (config.ipWhitelist === undefined) { + config.ipWhitelist = ['127.0.0.1', '::ffff:127.0.0.1']; + console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); + } + app.use(ipfilter(config.ipWhitelist, {mode: 'allow', log: false})); app.use("/js", express.static(__dirname)); app.use("/config", express.static(path.resolve(__dirname + "/../config"))); app.use("/css", express.static(path.resolve(__dirname + "/../css"))); diff --git a/package.json b/package.json index afdad5f610..cfef5f85fd 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dependencies": { "electron-prebuilt": "^0.37.2", "express": "^4.14.0", + "express-ipfilter": "latest", "feedme": "latest", "iconv-lite": "latest", "moment": "latest", From f378c93dd3e7a558d6835fd9f4a29e6e42405e8a Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:07:22 +0200 Subject: [PATCH 026/169] replace ugly error message --- js/server.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/js/server.js b/js/server.js index b8dcec5997..ddcf1dd3cf 100644 --- a/js/server.js +++ b/js/server.js @@ -20,7 +20,16 @@ var Server = function(config, callback) { config.ipWhitelist = ['127.0.0.1', '::ffff:127.0.0.1']; console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); } - app.use(ipfilter(config.ipWhitelist, {mode: 'allow', log: false})); + + app.use(function(req, res, next) { + var result = ipfilter(config.ipWhitelist, {mode: 'allow', log: false})(req, res, function(err) { + if (err === undefined) { + return next(); + } + res.status(403).send("This device is not allowed to access your mirror.
Please check your config.js or config.js.sample to change this."); + }); + }); + app.use("/js", express.static(__dirname)); app.use("/config", express.static(path.resolve(__dirname + "/../config"))); app.use("/css", express.static(path.resolve(__dirname + "/../css"))); From b58314007794d92e7e33dcc5e30a82cd9f2b6ab8 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:26:32 +0200 Subject: [PATCH 027/169] fix double quotes and config.js.sample --- config/config.js.sample | 4 ++-- js/defaults.js | 1 + js/server.js | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/config/config.js.sample b/config/config.js.sample index b10c991555..933b62fd3d 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -7,8 +7,8 @@ var config = { port: 8080, ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], - // you use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] - // you use also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] + // you can use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] + // you can also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] language: 'en', timeFormat: 24, diff --git a/js/defaults.js b/js/defaults.js index 0688595c8f..d1d78bce98 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,6 +10,7 @@ var defaults = { port: 8080, kioskmode: false, + ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], language: "en", timeFormat: 24, diff --git a/js/server.js b/js/server.js index ddcf1dd3cf..edae0e12dd 100644 --- a/js/server.js +++ b/js/server.js @@ -10,19 +10,19 @@ var app = require("express")(); var server = require("http").Server(app); var io = require("socket.io")(server); var path = require("path"); -var ipfilter = require('express-ipfilter').IpFilter; +var ipfilter = require("express-ipfilter").IpFilter; var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); server.listen(config.port); if (config.ipWhitelist === undefined) { - config.ipWhitelist = ['127.0.0.1', '::ffff:127.0.0.1']; + config.ipWhitelist = ["127.0.0.1", "::ffff:127.0.0.1"]; console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); } app.use(function(req, res, next) { - var result = ipfilter(config.ipWhitelist, {mode: 'allow', log: false})(req, res, function(err) { + var result = ipfilter(config.ipWhitelist, {mode: "allow", log: false})(req, res, function(err) { if (err === undefined) { return next(); } From 66eb99e5068cd69d394946d0c635e4d8012f0b13 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:49:54 +0200 Subject: [PATCH 028/169] transfer usage information to readme --- README.md | 2 ++ config/config.js.sample | 4 +--- js/defaults.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d86cca7ca5..986e600b5f 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,8 @@ The following properties can be configured: | **Option** | **Description** | | --- | --- | | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | +| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1"]`.It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`). + | | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | diff --git a/config/config.js.sample b/config/config.js.sample index 933b62fd3d..269492baa4 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -6,9 +6,7 @@ var config = { port: 8080, - ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], - // you can use ips with subnet mask: ['127.0.0.1', '127.0.0.1/24'] - // you can also use ip ranges: ['127.0.0.1', ['192.168.0.1', '192.168.0.100']] + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1"], language: 'en', timeFormat: 24, diff --git a/js/defaults.js b/js/defaults.js index d1d78bce98..e2ee615131 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,7 +10,7 @@ var defaults = { port: 8080, kioskmode: false, - ipWhitelist: ['127.0.0.1', '::ffff:127.0.0.1'], + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1"], language: "en", timeFormat: 24, From 2c758a9981a8b586639b6218c8c44f5e984fcfae Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:52:22 +0200 Subject: [PATCH 029/169] remove warning message --- js/server.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/server.js b/js/server.js index edae0e12dd..cd3d77f2d4 100644 --- a/js/server.js +++ b/js/server.js @@ -16,10 +16,6 @@ var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); server.listen(config.port); - if (config.ipWhitelist === undefined) { - config.ipWhitelist = ["127.0.0.1", "::ffff:127.0.0.1"]; - console.log("Warning: Missing value (ipWhitelist) from config.js, assuming default (localhost access only): " + config.ipWhitelist); - } app.use(function(req, res, next) { var result = ipfilter(config.ipWhitelist, {mode: "allow", log: false})(req, res, function(err) { From 5899497aa73bbbf1deb3297f8fe29b7c044b4671 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Thu, 29 Sep 2016 17:55:32 +0200 Subject: [PATCH 030/169] log denied access attempts on server --- js/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/server.js b/js/server.js index cd3d77f2d4..e1a909469b 100644 --- a/js/server.js +++ b/js/server.js @@ -22,6 +22,7 @@ var Server = function(config, callback) { if (err === undefined) { return next(); } + console.log(err.message); res.status(403).send("This device is not allowed to access your mirror.
Please check your config.js or config.js.sample to change this."); }); }); From c4048f4c7b6155c01681456f33002a1a279f2a41 Mon Sep 17 00:00:00 2001 From: Doug McInnes Date: Fri, 23 Sep 2016 21:48:49 -0700 Subject: [PATCH 031/169] fix typos in the module dev docs --- modules/README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/modules/README.md b/modules/README.md index 61989a93f7..e7a23abd4f 100644 --- a/modules/README.md +++ b/modules/README.md @@ -6,11 +6,11 @@ This document describes the way to develop your own MagicMirror² modules. All modules are loaded in the `modules` folder. The default modules are grouped together in the `modules/default` folder. Your module should be placed in a subfolder of `modules`. Note that any file or folder your create in the `modules` folder will be ignored by git, allowing you to upgrade the MagicMirror² without the loss of your files. -A module can be placed in one single folder. Or multiple modules can be grouped in a subfoler. Note that name of the module must be unique. Even when a module with a similar name is placed in a different folder, they can't be loaded at the same time. +A module can be placed in one single folder. Or multiple modules can be grouped in a subfolder. Note that name of the module must be unique. Even when a module with a similar name is placed in a different folder, they can't be loaded at the same time. ### Files - **modulename/modulename.js** - This is your core module script. -- **modulename/node_helper.js** - This is an optional helper that whill be loaded by the node script. The node helper and module script can communicate with each other using an intergrated socket system. +- **modulename/node_helper.js** - This is an optional helper that will be loaded by the node script. The node helper and module script can communicate with each other using an intergrated socket system. - **modulename/public** - Any files in this folder can be accesed via the browser on `/modulename/filename.ext`. - **modulename/anyfileorfolder** Any other file or folder in the module folder can be used by the core module script. For example: *modulename/css/modulename.css* would be a good path for your additional module styles. @@ -104,7 +104,7 @@ The getScripts method is called to request any additional scripts that need to b getScripts: function() { return [ 'script.js', // will try to load it from the vendor folder, otherwise it will load is from the module folder. - 'moment.js', // this file is available in the vendor folder, so it doesn't need to be avialable in the module folder. + 'moment.js', // this file is available in the vendor folder, so it doesn't need to be available in the module folder. this.file('anotherfile.js'), // this file will be loaded straight from the module folder. 'https://code.jquery.com/jquery-2.2.3.min.js', // this file will be loaded from the jquery servers. ] @@ -154,7 +154,7 @@ getTranslations: function() { ####`getDom()` **Should return:** Dom Object -Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getDom method. This method should therefor return a dom object. +Whenever the MagicMirror needs to update the information on screen (because it starts, or because your module asked a refresh using `this.updateDom()`), the system calls the getDom method. This method should therefore return a dom object. **Example:** ````javascript @@ -202,7 +202,7 @@ notificationReceived: function(notification, payload, sender) { } ```` -**Note:** the system sends two notifiations when starting up. These notifications could come in handy! +**Note:** the system sends two notifications when starting up. These notifications could come in handy! - `ALL_MODULES_STARTED` - All modules are started. You can now send notifications to other modules. @@ -215,8 +215,8 @@ When using a node_helper, the node helper can send your module notifications. Wh - `notification` - String - The notification identifier. - `payload` - AnyType - The payload of a notification. -**Note 1:** When a node helper send a notification, all modules of that module type receive the same notifications.
-**Note 2:** The socket connection is established as soon as the module sends it's first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). +**Note 1:** When a node helper sends a notification, all modules of that module type receive the same notifications.
+**Note 2:** The socket connection is established as soon as the module sends its first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). **Example:** ````javascript @@ -234,7 +234,7 @@ When a module will be shown after it was previously hidden (using the `module.sh ### Module instance methods -Each module instance has some handy methods which can be helpfull building your module. +Each module instance has some handy methods which can be helpful building your module. ####`this.file(filename)` @@ -246,7 +246,7 @@ If you want to create a path to a file in your module folder, use the `file()` m ####`this.updateDom(speed)` ***speed* Number** - Optional. Animation speed in milliseconds.
-Whenever your module need to be updated, call the `updateDom(speed)` method. It requests the MagicMirror core to update it's dom object. If you define the speed, the content update will be animated, but only if the content will realy change. +Whenever your module need to be updated, call the `updateDom(speed)` method. It requests the MagicMirror core to update its dom object. If you define the speed, the content update will be animated, but only if the content will really change. As an example: the clock modules calls this method every second: @@ -265,7 +265,7 @@ start: function() { ***notification* String** - The notification identifier.
***payload* AnyType** - Optional. A notification payload.
-If you want to send a notification to all other modules, use the `sendNotification(notification, payload)`. All other modules will receive the message via the [notificationReceived](#notificationreceivednotification-payload-sender) method. In that case, the sender is automaticly set to the instance calling the sendNotification method. +If you want to send a notification to all other modules, use the `sendNotification(notification, payload)`. All other modules will receive the message via the [notificationReceived](#notificationreceivednotification-payload-sender) method. In that case, the sender is automatically set to the instance calling the sendNotification method. **Example:** ````javascript @@ -276,7 +276,7 @@ this.sendNotification('MYMODULE_READY_FOR_ACTION', {foo:bar}); ***notification* String** - The notification identifier.
***payload* AnyType** - Optional. A notification payload.
-If you want to send a notification to the node_helper, use the `sendSocketNotification(notification, payload)`. Only the node_helper of this module will recieve the socket notification. +If you want to send a notification to the node_helper, use the `sendSocketNotification(notification, payload)`. Only the node_helper of this module will receive the socket notification. **Example:** ````javascript @@ -287,7 +287,7 @@ this.sendSocketNotification('SET_CONFIG', this.config); ***speed* Number** - Optional, The speed of the hide animation in milliseconds. ***callback* Function** - Optional, The callback after the hide animation is finished. -To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itselve using `this.hide()`, but of course you can also hide an other module using `anOtherModule.hide()`. +To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itself using `this.hide()`, but of course you can also hide another module using `anOtherModule.hide()`. **Note 1:** If the hide animation is canceled, for instance because the show method is called before the hide animation was finished, the callback will not be called.
**Note 2:** If the hide animation is hijacked (an other method calls hide on the same module), the callback will not be called.
@@ -297,7 +297,7 @@ To hide a module, you can call the `hide(speed, callback)` method. You can call ***speed* Number** - Optional, The speed of the show animation in milliseconds. ***callback* Function** - Optional, The callback after the show animation is finished. -To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itselve using `this.show()`, but of course you can also show an other module using `anOtherModule.show()`. +To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itself using `this.show()`, but of course you can also show another module using `anOtherModule.show()`. **Note 1:** If the show animation is canceled, for instance because the hide method is called before the show animation was finished, the callback will not be called.
**Note 2:** If the show animation is hijacked (an other method calls show on the same module), the callback will not be called.
@@ -345,7 +345,7 @@ var NodeHelper = require("node_helper"); module.exports = NodeHelper.create({}); ```` -Of course, the above helper would not do anything usefull. So with the information above, you should be able to make it a bit more sophisticated. +Of course, the above helper would not do anything useful. So with the information above, you should be able to make it a bit more sophisticated. ### Available module instance properties @@ -389,7 +389,7 @@ This is a link to the IO instance. It will allow you to do some Socket.IO magic. This method is called when a node helper gets instantiated. In most cases you do not need to subclass this method. ####`start()` -This method is called when all node helper are loaded an the system is ready to boot up. The start method is a perfect place to define any additional module properties: +This method is called when all node helpers are loaded and the system is ready to boot up. The start method is a perfect place to define any additional module properties: **Example:** ````javascript @@ -400,12 +400,12 @@ start: function() { ```` ####`socketNotificationReceived: function(notification, payload)` -With this method, your node helper can receive notifications form your modules. When this method is called, it has 2 arguments: +With this method, your node helper can receive notifications from your modules. When this method is called, it has 2 arguments: - `notification` - String - The notification identifier. - `payload` - AnyType - The payload of a notification. -**Note:** The socket connection is established as soon as the module sends it's first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). +**Note:** The socket connection is established as soon as the module sends its first message using [sendSocketNotification](thissendsocketnotificationnotification-payload). **Example:** ````javascript @@ -416,15 +416,15 @@ socketNotificationReceived: function(notification, payload) { ### Module instance methods -Each node helper has some handy methods which can be helpfull building your module. +Each node helper has some handy methods which can be helpful building your module. ####`this.sendSocketNotification(notification, payload)` ***notification* String** - The notification identifier.
***payload* AnyType** - Optional. A notification payload.
-If you want to send a notification to all your modules, use the `sendSocketNotification(notification, payload)`. Only the module of your module type will recieve the socket notification. +If you want to send a notification to all your modules, use the `sendSocketNotification(notification, payload)`. Only the module of your module type will receive the socket notification. -**Note:** Since all instances of you module will receive the notifications, it's your task to make sure the right module responds to your messages. +**Note:** Since all instances of your module will receive the notifications, it's your task to make sure the right module responds to your messages. **Example:** ````javascript @@ -447,10 +447,10 @@ To make a selection of all currently loaded module instances, run the `MM.getMod #####`.withClass(classnames)` -***classnames* String or Array** - The class names on which you want to filer. +***classnames* String or Array** - The class names on which you want to filter. **Returns Array** - An array with module instances.
-If you want to make a selection based on one ore more class names, use the withClass method on a result of the `MM.getModules()` method. The argument of the `withClass(classname)` method can be an array, or space separated string. +If you want to make a selection based on one or more class names, use the withClass method on a result of the `MM.getModules()` method. The argument of the `withClass(classname)` method can be an array, or space separated string. **Examples:** ````javascript @@ -476,7 +476,7 @@ var modules = MM.getModules().exceptWithClass(['classname1','classname2']); ***module* Module Object** - The reference to a module you want to remove from the results. **Returns Array** - An array with module instances.
-If you to remove a specific module instance from a selection based on a classname, use the exceptWithClass method on a result of the `MM.getModules()` method. This can be helpfull if you want to select all module instances except the instance of your module. +If you to remove a specific module instance from a selection based on a classname, use the exceptWithClass method on a result of the `MM.getModules()` method. This can be helpful if you want to select all module instances except the instance of your module. **Examples:** ````javascript From 5edf377f4b030ebf2dfffcce23c7b081c1cb514e Mon Sep 17 00:00:00 2001 From: Harri Kapanen Date: Fri, 30 Sep 2016 20:44:53 +0300 Subject: [PATCH 032/169] Finnish translation --- CHANGELOG.md | 1 + translations/fi.json | 28 ++++++++++++++++++++++++++++ translations/translations.js | 1 + 3 files changed, 30 insertions(+) create mode 100644 translations/fi.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 74cb3f7e61..3f40dec282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [2.1.0] - Unreleased ### Added +- Finnish translation. - Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) - Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)) diff --git a/translations/fi.json b/translations/fi.json new file mode 100644 index 0000000000..f370e41c9f --- /dev/null +++ b/translations/fi.json @@ -0,0 +1,28 @@ +{ + /* GENERAL */ + "LOADING": "Lataa …", + + /* CALENDAR */ + "TODAY": "Tänään", + "TOMORROW": "Huomenna", + "RUNNING": "Meneillään", + "EMPTY": "Ei tulevia tapahtumia.", + + /* WEATHER */ + "N": "P", + "NNE": "PPI", + "NE": "PI", + "ENE": "IPI", + "E": "I", + "ESE": "IEI", + "SE": "EI", + "SSE": "EEI", + "S": "E", + "SSW": "EEL", + "SW": "EL", + "WSW": "LEL", + "W": "L", + "WNW": "LPL", + "NW": "PL", + "NNW": "PPL" +} diff --git a/translations/translations.js b/translations/translations.js index 2a458ef26e..09036efc29 100644 --- a/translations/translations.js +++ b/translations/translations.js @@ -9,6 +9,7 @@ var translations = { "en" : "translations/en.json", // English "nl" : "translations/nl.json", // Dutch "de" : "translations/de.json", // German + "fi" : "translations/fi.json", // Suomi "fr" : "translations/fr.json", // French "fy" : "translations/fy.json", // Frysk "es" : "translations/es.json", // Spanish From cbb82ed63574a63727907245e37119d877b6d093 Mon Sep 17 00:00:00 2001 From: fewieden Date: Sat, 1 Oct 2016 00:38:14 +0200 Subject: [PATCH 033/169] replace system output with MagicMirror splash screen on boot --- CHANGELOG.md | 1 + installers/raspberry.sh | 28 +++++++++++++++++ splashscreen/MagicMirror.plymouth | 8 +++++ splashscreen/MagicMirror.script | 50 ++++++++++++++++++++++++++++++ splashscreen/splash.png | Bin 0 -> 19621 bytes 5 files changed, 87 insertions(+) create mode 100644 splashscreen/MagicMirror.plymouth create mode 100644 splashscreen/MagicMirror.script create mode 100644 splashscreen/splash.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f40dec282..254472434f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Finnish translation. - Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) - Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)) +- Add Splash screen on boot. ### Updated - Modified translations for Frysk. diff --git a/installers/raspberry.sh b/installers/raspberry.sh index ce37e86f98..4c42dcde03 100644 --- a/installers/raspberry.sh +++ b/installers/raspberry.sh @@ -113,6 +113,34 @@ else exit; fi +# Check if plymouth is installed (default with PIXEL desktop environment), then install custom splashscreen. +echo -e "\e[96mCheck plymouth installation ...\e[0m" +if command_exists plymouth; then + THEME_DIR="/usr/share/plymouth/themes" + echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m" + if [ -d $THEME_DIR ]; then + echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m" + if [ ! -d $THEME_DIR/MagicMirror ]; then + sudo mkdir $THEME_DIR/MagicMirror + fi + + if sudo cp ~/MagicMirror/splashscreen/splash.png $THEME_DIR/MagicMirror/splash.png && sudo cp ~/MagicMirror/splashscreen/MagicMirror.plymouth $THEME_DIR/MagicMirror/MagicMirror.plymouth && sudo cp ~/MagicMirror/splashscreen/MagicMirror.script $THEME_DIR/MagicMirror/MagicMirror.script; then + echo -e "\e[90mSplashscreen: Theme copied successfully.\e[0m" + if sudo plymouth-set-default-theme -R MagicMirror; then + echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m" + else + echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m" + fi + else + echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m" + fi + else + echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m" + fi +else + echo -e "\e[93mplymouth is not installed.\e[0m"; +fi + echo " " echo -e "\e[92mWe're ready! Run \e[1m\e[97mDISPLAY=:0 npm start\e[0m\e[92m from the ~/MagicMirror directory to start your MagicMirror.\e[0m" echo " " diff --git a/splashscreen/MagicMirror.plymouth b/splashscreen/MagicMirror.plymouth new file mode 100644 index 0000000000..b6887bf56b --- /dev/null +++ b/splashscreen/MagicMirror.plymouth @@ -0,0 +1,8 @@ +[Plymouth Theme] +Name=MagicMirror +Description=Mirror Splash +ModuleName=script + +[script] +ImageDir=/usr/share/plymouth/themes/MagicMirror +ScriptFile=/usr/share/plymouth/themes/MagicMirror/MagicMirror.script diff --git a/splashscreen/MagicMirror.script b/splashscreen/MagicMirror.script new file mode 100644 index 0000000000..d7e7b8607c --- /dev/null +++ b/splashscreen/MagicMirror.script @@ -0,0 +1,50 @@ +screen_width = Window.GetWidth(); +screen_height = Window.GetHeight(); + +theme_image = Image("splash.png"); +image_width = theme_image.GetWidth(); +image_height = theme_image.GetHeight(); + +scale_x = image_width / screen_width; +scale_y = image_height / screen_height; + +flag = 1; + +if (scale_x > 1 || scale_y > 1) +{ + if (scale_x > scale_y) + { + resized_image = theme_image.Scale (screen_width, image_height / scale_x); + image_x = 0; + image_y = (screen_height - ((image_height * screen_width) / image_width)) / 2; + } + else + { + resized_image = theme_image.Scale (image_width / scale_y, screen_height); + image_x = (screen_width - ((image_width * screen_height) / image_height)) / 2; + image_y = 0; + } +} +else +{ + resized_image = theme_image.Scale (image_width, image_height); + image_x = (screen_width - image_width) / 2; + image_y = (screen_height - image_height) / 2; +} + +if (Plymouth.GetMode() != "shutdown") +{ + sprite = Sprite (resized_image); + sprite.SetPosition (image_x, image_y, -100); +} + +message_sprite = Sprite(); +message_sprite.SetPosition(screen_width * 0.1, screen_height * 0.9, 10000); + +fun message_callback (text) { + my_image = Image.Text(text, 1, 1, 1); + message_sprite.SetImage(my_image); + sprite.SetImage (resized_image); +} + +Plymouth.SetUpdateStatusFunction(message_callback); diff --git a/splashscreen/splash.png b/splashscreen/splash.png new file mode 100644 index 0000000000000000000000000000000000000000..f76b0cff5617be2df50daddabc4e9385d38a2ade GIT binary patch literal 19621 zcmd742UJtd)-Ze!1Pk>MkPd>1Ql)nSN>Qo^NRy&S@4XjA1wlYWiVz5b5Gm4o3y2iy zQltb3MZkm-dVrARJ9yu<{=2^K{_lP6TL1g6@2r(Mlbo47d+*t^+sw)9`+Ax*7uYTU z06=r^uG#|tpa84nz&T3r*4W5I1K!Si-Zk?9fQy$-KV(1#lm!4T=sVrHbN{}hhp&f^ zqlYKYy*qb!JiR^aom}kzAaFX%(80(M&8&o*+qi*WX@JmGH*@df~0R6eDr&oLkd}P33xT2yU zZyQxBKo&T9@f^^mo7r}YBbr2qx&7f0S>y|{Hs2&!?Q@ZgfJ$(}?E*kWgDf&D{kkEL zLjlIO0gU$A z-{gQvVc^z16Z^YBc^%L;NPn>sI7bcKGKhJ36QBqIYv8M_EEck~1APR|Au|+CSM!FGmuWeE|T3yWX z!^PQG(y7z{Ip}GVUC&eAsDFIhFg3OO>(`{#x7!wvdriWK4qvU?ObD(=;fg1?{rT3# ztIxzOpJ`GY&VTLS)5+%;dUyWClbMx7&6B!|q!Z3j-f#DwG?)r7E*bpgm7tdKW>-9) z_x0^}H#@J5ke)80gz)6bC@G-aS(z*(N%*s+E%|{qKfS4M+aeACcA7le$8MY>k93S$ z7z!X^Aq35wYe1y^y?0&!V5N3d#HhCl(tQp9)N-B)l&iAuwX+DdQF64OooT;#Vk7IG4U}^V*ocm)a7wlrIKE2uq!syUTu-ayNq7ACTz317 z=4aYTW!Bts3g9*-V*8RxLqMDbUxX(uY$LPy10w2{9y@s)9ZcPp^5;C zzn-bLotLHvxXtsJOZBd)j;Y?{-OoH6S0x#y&&!-Ae_`;IpEvolcJ=i}hNEvRPsGKd zP45cv{roHOk|=#h%$;vCSO0o_N1VUm?U{QOpNvNS8qpYWf53+pD$JC;%f^@defp_O zC6(NJAs)e=m%p-pb^Ma}#s2Hcj>UznCn{c_4hfTe8{Lu-TT5U4K=;AJ*i@ia zAe1So_d<$R%Jmd>0a2sEqJpBiqKn46#(hSKg;s`Pr5eT(hD(L#$5M-pi?Z&o8L}HX z6e@gMzigPT*{cQz|O_D0fFfOTwh;!R~u|2-Q-$*CEtb@BHcwc-n4w>>MNZ=HgBE0!f_) zF}p`DMX712rp0%Q4T?3_TBJ)i;8_JN>P=?&XSAx_TKtdrH60QM&t|O}P8rU^FTj~~ zmE`wJMT%VV**`X^1t8qvo9WrDR*~5{9`L!Kmepg9Fj0aL!R;8nuSso6Sw(%75=lMC zqSz_r<)O$a+Kt>cxMSI&awq?B%Hy)N^)-OY>#x(x+43lww|bh-!n2XY5~evryk5}OcT&0Ni#$VAoIm!xOZ`XdWEv#cLU!J5y zme#t}hCOz8a@nD-v$SI~xg|NQF)W^-L`4%lMO(~i&Kd4g?ae6vP<}3B5V{Eo>)cC4 zi#nJN(GN{ZEY)7>yZOy2%P@0P)8Vp1gHP0MOx$bj=Y1k+$|9NUU9&wczqEY!y(|}k zNA|Nat1`cCd`6aSN^d%CM$f?dC1E$S%_Mw=J9_TS8!Z2TT!f|EazT}Z>)+9T=1{ZB zCu%F2Wb$RAye>bW2=^F!S@}TO8@8mpq$o2dK4)g#FVj}nQ`e{8;gN0q5_KnnkMxuj zO!@)9Bd?J;kiUMW`pn`C{xCT73L*g_kF-0eoZ3)*lhdHeq?-8r%k$;-FIOCU*57`) zf?G`=Od52eeR)6p_s?Of$19KHI>M>>Uq-()c?C)Ej4@^VA(kc;@MGqV4@&J=EmdtU z(?LvMu1r`f}0=*hm{Ql%I8%>3rs&ZU5B2^WICa(;E-75yRo zBWCi>BLObGox1|M!SB|Snx%rSc1q+6EjPU2FMQjqL!&dBDWA=p;m_kHt|Z?g7WFRa zt=H|ME4srGuS` zJ!0T>uUu+zw&1`YIw1p=ur< zzsh1)W_lf4%80z2#uPDmV$4!{Ivg@kdg(e zQEq=u2ToDv+Zj6<8kvR}c#9_%jr#q{KYn87f=@J&+;mV$MYABSU8C<#)9B};$qqY1 zZ?aOd!oo$4W^9nTwIQpvgD7V@4{Rg7@4|>WDQ;DvSz++ePQC9=C35+aNxex%nY^_d z#uuYVOdi$mZh|&tlr}taY1j;IsR^;iq1m%#250wLg0`7SKgYA>lxACYgFSGaxP27! zY`8Z+VX&`hDu93UOS68n^`6Rx>eQXt=y8Yzab^-b6XDzzkhA+^MiWQ*GHQsJw4X?K z=WODK#J*QFuhz0IV^3H;8`)1m9xmx;N=zS7IgqTz?*YZHS%(tmtR+eu4C zxP|5uFl}qBWyr3tU0ki-10}?)_8#Il+5=_+II(#sI{javJP|iYjz<;yhQn}tGHY@& ziGn7_irXFpzS zJ8uX!P*!I8W#M>uq2S(=8{2d$Rugh^_pZiJIJC9*(?zvcMUV(GATE)k2as6s4xGBh zK;&rw(ElmVoR%tos-T|&USy{Q&uQ_`)qmShk&HK~6SWtBfL|1|!m>c3~v-$Xg`5BR@{GSC0h_@Ange}4V%#`}**{ny<3@5cM@ zhWj?l{G;)IGOH?o!2eBB|06;C z(>U@E_`lhY=TGCmN$TH3S>+GRGl2T({XbcHk$*b=PhbvhBHaKniCk)IZeG_=t2?f0 zYHGSSi&6?Xa9zTZ2srDPeI472rwGXQMn=#xl=0>w9*+j8>F_SPsJ+2%Zmyj9hrQWg zIYcDJEbtLSxft?d>dh#~{_DX2`-wHYon$z`x45{u=`IAQoKiCkeHOvbtK3a^PqJ)0 z+Cz`l{4qr#hN*U7KhP|Ox#|6`%DoY8;LKoWM&v^3eh)Ka?0hHTJ)|a1>@&a_wvn^5v#xy;NXF|YJLpk(0}!c8)MVIFBUh(qU?^iE<5#}Rra^G- z?5Gr~IlnQiTjvGEd(Apc2bBo*g^!8S|J1%hHoV>*5io!YVq*}k<2=z+o0*-p{6^5p zvCEp=e8PAJxV07b)Zq*J8r-(MFfg-WHbgz2;GU!!x3>HR6V(;MjY5fEW)RbkA|2UU zOTGk>nGkHPLAwQclMFz)ev2gV^Vy3_DW&fYypa^w3O1aROoU6*^fH72$@`7RkVo6a zad2v4aaq;M>Ye;V0Lbbgcr(2+tQ*gn%lRZVcq|>sXeG0KGVbO0_4@%Ge?UM$vSo8% zW0+0#qKSRL6~G2NSo`r_)@tb;U^u*PP-UMyMDo#gRVF8*dx8nFb~Bg)SVzjCD0%Fb zIdpK%N|f!>SSp|BYtack> z3-;|4OgDIO@7xPy!Z$%`oaSnO;r%%oCbV57b!bjLrr1-3Z@?Jk&H%I@EmG~uZp5Nl zLm!Tkyq65kJ*EvA;SKA@SnaF2FlzMmJLVcrpt8k4B&59n@6^DGl0i|%_`^RMgYHFAhXHJ z9;u>(!ZEI|uWv9GusJwg1|zCKTj?*~1ic1wxtL=#N&c;h1rlpW>*-TKittMZgvE#H z)Pc5Ef=u3Hxn&2fRbL*2tWG55G26c3jQ){yk-eC}>?(mx(S0dS}d-sby)pyBa* zz9#>6DffnCbKA`tRMe$IXw+vI(PJBu!vr$oRGsfFnbjXB0+Dxmnqz%0#NAu=eU6al zjbvtZaP_%RM`qg0B%9J6A@dN0Ck>8A)NXUDx6#TcnXr=oHi&~Pt@V4$%Avz2t<+AS zM9yv79S$#Uih+@ch&X)6j{>L8?PTMdu+?o(WViQGKi?Dco0(2(I{hqi=2?D*S;7fx zo3ECFGcX=p3=vrmW|`E*1pBV06d<@1}#@-XeaAb<~&Z zh>a%GIPD+H3V#^39l)P{NQ^es)@)3mb!V;uzwH z12X8C0cy;6NZ9eGBv9T%bq}VtOG2>sB(JU`D|d4OSk*zUfB3-ga8ti#2L z&8uXt`zO9(0*U@2eLDiYMAz^0h)czAVj}3%Xqa<=E9h%c7sLTLsg2J{{|wWbSZOC2 z+s#KfM#UUTShhH>1Gz$dD85A;x!)57hV2luRG5B#vfm5&wKThiq4ENebB7YP7+>2n zkyjlkN6TMEcktM<$JK2*00f6$`gc4=TIojTNriZ2p=JK z)z7e_v8z~iN_@j~bshv#-dv}Zc=~g76IPaY<|M zboK5C%xgxaG;>gYLYV7>4q1svOG}F~Z5jO83C`4`;wT`}R-w~DYhnXi;xs^0Q041M;TO7#?7p>OP5Sv^Q`shGUVF@&|G;c>)YE}duVETOnwmxJYd>|&+ z>kYW7ox6YjZpLt-8Pl0_!1QS0ntF)6_pg$rkpeRy>W!NY$-}=%4l>*tutbzDE1)B0 z$|^h_PL&oJpl7dLFRsBHbU3NaIQj(&=#$y-$L6M|*~yin18dM9M&z<)McoQvW8Z_c zsNCM^DU#x&9r8@5@@HcXZ_)%G>z^ZQfLe2UxuG#i7=;5@?su`T|pA_!EWlRLxRN)D1$1zlEBF znMDUrN7BObbg2k9#&$F4R{>gTS0frqX#?yIDkxczp?kv9-*M&1M@mq&Z{51x z5y#=W0;@T9*75lMFvPu${l+kuF(qM%a}!l7F;ak@A$;~xFM@f=^S7XOpt3@JJ7ooD z$DJy^HWG&vYtHBCu10IIl-K!q1^+@7Sv=6-I_eeyRaaJ_?^_vkjg43#6ixc#7&FS0 zpt`cM8xshI03J<^XRH}Jn{ULf)x)^b6+Bru7R2r#A6-e$_imh2mvb}FsB6!)ZPpFb zsawb@eTa1bNITAk`^$k37_q3E$|s>5*|V_;8gu=j{^!@zPQkJF>GraFiy}kDEZBX zk+5ed0MM=Zs-xEx9WIRz3rE)`w2jhbdT-_!X9MQYgWfLKer~-y<@!F>OAD_-Ll|2cI5l@VX z^KG}Cdy&=B+}vzsh~314%b+ShIn46T_%GUDJQzbabR0}|e%1Yxx6AKKg%Y3J zVfjSI*toq_i^j-?!Vq=3!ZUkv_EMQNY@wlJ8=0U=ta93l_%Sjx_9ASEW)r7;Xzk2i zd!B4g`s(j>j;0xLDpHoIlFyUSfB>ATA*g_B9d{-2Pu;jw#jaZcZ@snzISWs`^_)cq zo1r3KotH`cmaOdduJXtyw_5v-*&MhgI$l9!no0?qlG}g$P-YUc%&8h@wfwz;iey27 zi}M*#rK+&#pI=k+@dyZ>XrtfqIbnIov8?zC0J6Q`rK?>mVL>-_I@zu@O02|b*WD2{FDp2dos(_|YmOG7u~fSbW9C@83AC3GwE4|_HI_~F;*C_M#6 zNg)Oi*IcN2FNH# zZm=wNC%RnQk90sr98 zJ&6RmIMT*YwbM`p>g%T~`T{+zoEwu085sFhsHE$CC6r_#sdk~2^c}RIHP_FQ0lLXj zJbjOJith18t3n6&NYIeg%wg7Sd)Lv~ZgzOF@NDXPLq7R1&D2ZGdKsQ)#r?!JSu+n3 z%R`1F>iSseTb!r1#V#D=4-DNvIQ4{6izDmr#r1wkW}a56H5)A;b`!!#ePM5dB$pmC zQUF_5{cu4tXn_Zo4*qj(mwIfe26nFtJx`uWIttSFfJq!?Naa_hP}Z(0Mt*nV&!}#* z(DU3|Jcl2jS_~{!ILNF{e>}S_=8kSbyWMgd&hfQ~XSoj#zb|7uTJVA?ZZ|-0O6tmu zW~UL=)mAXjfHr!u>(Mrhk}Qli{WxEv&xfUU2Up}R;oc5)vo^pdZtoBo{_7EuWezkewzwWKpNk%LhhgNbOwMvOm6lsQcxfNp`? zL~iFN?}LT+@^7msH~RMOVv(pH!0+LxUMDCF+Q=s3iQrc_eANBkut2xIG2pMby4tbk zPCEsc`;O_O%#tFG_m*XlKUR@xUC{2)Fj6ts(Ld0JN()_2ksu(LvY`FOyCf%5s-0oG zvDc|H*MGd&agKyev7y-NQ4w|=akB-?!5QM#6Pr?x#X1^yyLGFHicWbLqffmroAZUnpaXJb2Yp_SA zb1Va}`T1=%@v^$u%|7wfDqXgj>^HrY&0kobB4U?be)20O)!83B)E>gR2_vr$Y&ow{ z!#l-p3HNzhjcV+H0R_jEZ;oonj7_|?-<9=_+1adv*Lj{7f#~}IDf8)I_^T8W@N>9u zUU5#J75RCW^6pRoWVsPjZNt4L|5>wvW}X7{F*09=pAl4{c`u+UU!LXVDEjeX>aNfa*PuL0|IQTQdLl8a=E zTU7w%2mD}obx^8N^7I>bF#Z>=KesKsgrAI)XeMm!?CkjK!fb;<)zZ?33*KEBD6mf4 zb2$x?8tTY69><#MQSFEcVh_fGo2XLk!z48Z0}2QH_6mIaV_2U9{Jz&^y7VO>s)Jk1`^2vh_qa?)V zhN`Q8V*<3eVzgj0)POPXQeiYSrIm_ddqD*+(KF-VSP512S{l-HN_DU#mF6{mloLAB zb0vOF-jC{$j&pewA>S_JWX6vRb!2oQM0CliO9eFI0XH3vNk#)+XY7Tih8nRJ`o_0? zKwe*wauO?S94EnbL#tWzQ!fF56g(%695nSbJTC*moXH~soW|Q;wkDrj+$0Oq*whr_ z{}~s2ux>Wn`k9`X$O>@in7=LDe0t!F!W)3eT3en&gZTCz`_ADIV>PPe(d)Fd<=k>u zu?LpWyNE(zGL?;FrU$5t^uVx&K2$@gbZv%nUOI9@VN&0QgqeQcz$^b->z7E)8nGHOtu7-AgdR2ky{6y&&6@g=#&~_pk>i?Ff@RTL+6A5XPih{Of ze-ad6*0x&5fN``^$e|+W0&y+uEO5%$qC%2jSvbZMqQ6`lry4OjFs@i4nGl1_aGTTk z)}+)z;_>1BNOLTOfC=!b0Bwbbe=%TXPQqa(NtlAf!J!6nGc%htV?~1VV|Il{@|NWq zpp#T71g|&}II&42Q?bM=NfTg~#65nr%6r_7GbN9-WwCRWm>dn6XxW_7C5iS`8m2CT zZYqRt5nGS=IuVe5MsQ4+a&or&i8YAdz})ktbip(9K%05DxsHIY0~VtaF0+Nuiy{s! z$hD}ncy&qRO{upw5)NoU3Oy_SITN8@yb-b;zyu4dxXgsL{P}?$=$3 zPnhZN?Obz>n^MAa7r-3`HX(*y_e;(Ko}mzh{T z&r_{sz_?o})Xg9^Q$EGxkCTj49l&-wp9RU2M9I=<$pmpW1vU3i`SbKua@fD$6{s>2 zK@HluQScxqGJqT~i!op57L6u>Svz;Kc}LosbR#gWC<-_2D%=fiT88QJF4lo=?9JH4 ztaeCwE`dvv;0BcWZ#@Llo1ih_|3x2nFKc;^R4D|;?3%yy@i6soeYrQRF!#w>G1ITx zY3FQBckxNir<)PNNzCpU6RropJ3o!^)R&S66~&PVt)24`j0^~7bullaGaoS1gL)ay z_9qWQ=pE!kE`n4*E4>D=RQiD%ASi_2NEnIGKOhS37|13&IIf0vm6lx{)0TjP&Y;q= zbYzuPGn4tJvUA{$2y$}O4e;aaaSFb=P#A;&NAcC@HXpQ61rHT~nMZELg&HdTP!Gq- zpaE=1>^V@Ky%WEjJPl^uL4yI}<~^!8I!=PBuE#q#kn0;wyi)#029lczA}sv{zj@Dl8?JQ?9|!^;NEG z&W)1-Xywdp%y;pvyv{Eg1-CmS`2_1Y*S@h1&OMhxy_7z5qS}xHRT^~tSm1$K>g*fZ zUlW&vdZ8BAG#r{ee=6E$!ov70jIB9PvbLG+%w;lQqIbx)Q?GA8ycS*at7>d>^@ETk z^%-E&i{Beb`%6Uri`(eXC~2@Fsr{?t{onY=URJN3PpuwXEs`(+^>w75 za~bbO4!N9uB9~$}FrRs+q?Kl67_$-JUc%K^~dtuuS5;}5>=9#Smw!eTm43tZgp%ja9Ao{wvI*Z&YnXb8WhN6j1V+r`6VDCrGj@XeLDPWEXh6Z0V^-wv5S6HOGL=c{RgXovk&D%qaUuHq=Z=!5Hga|vK+1f_UFH@Cy|C14E=E;T zNKK;1*S!cm{Xw@NQ8psDYUUf_=s*t1%aQN3XTV@_r83PJKzCE+hgBO>jnvbf6kGBy9(d97b5F?rU5m`r7ZdRAf`Ol8Xxy>M7 zg}+!xm_9v|ES9iQ#!KT|3&9tYXhNE2w_>naKB(nl%Ab}bYK5NUH?=tvZLI8mxQ#)* z!|(%9V zkMyVh^%;_%o8_05q~WcvXppO*3e>MPgx=1aVqP{hc}U3sDv>VfEXr*1xy|2I;6Cah z1UW-_Una~qgG(&1*Spji$5vTZXArS$10#QLwgQweMD_YY5#!9RdyO|0GK1{a$FOmn z9tPGPutW1ksznxKw*h27AYJah0;o`T-?$|Z1Dhme z*(7tCy%Sy+_|_+|rAt1&Wfl+`0P14trx8A1W4^zhF#G8SFnhdQw{5<}fMu^l$l=B0 zqArSp0-)q~BI92zQC1s2lv7f`isbN{&yvT(>JF1P84|y!N3UUe?0zP$=z2gt_gg&Y z<#kWwocx5;z_dE>qr~(K57v~IkmZ4bLLz~`s?VErhp#(<>8zxHeQQsuGeF?`Mzn29 zPr7pO^_#wW{0%-O#h;vP4&-W^-nG<$r{JB^X8BU5uo=%vYI$;5O?te~l=`4qCc*|) z$D*$l(EEtEdn40r&t{Ul)@=4#R_ceW$k1 zLtOATqvCMUEIj%9tl5%>kT#?48QKZeQlT`vDKL$eD7%X%PEg%#EIhASc zb8qFT>neg8=OwH1Mv*=r;`t)f4~FpTp83az5jeM-`^N^~VY#bx6rW>xrbyE;K~G^x=hu+6KfPnD@*YqP&|}j#t{j zzUG9NqdC^r#9$$zuO6Ql`nlUMxu_q^uvF6KfOB^b|n3;1W4u;HEFv zbqi`n(DdUCsqWgD9gF}6*m~aWA9)UVNJIu<0;@aBU{^K`S}vA?toyKx;$>{k)_?f z;I|86m6OQx$+2B;6zc0-4SLYfNm#VoWwNWgQM~H3m2TmV1#{V{c7vLn)`T2kHfuYD6%D~`bXN2`34L8ugDLZACn_2rcALogPN3!KUOO94!aALByg ze-?8t6*dZVCqZnVJiSH6plMTd;5bhWlD52 zMqHb-*hO(F7n9R|7aGAmjZCQ3=XJgDy}uXr}nPL6ZsC<(W%U1H7R zzMSVy>k9f;Jc*TwH&q&L^zB^do$FfSa;e?i4SkKr|EwdpF3EmnA`17pJ-k_mE1Z#6 zIBpg0b(?#B@VGMSVClXec)rFUxPN?&lWT2!=va)mi>9ba+IP@{cX2!eCAENwFdTd~ z`ifh->J^vuE;ANyIH=t*Hn>q4&#w6`?bR!9IYLPgAgF}Lp(0YwKr19w*gmNSiu%|n z=yQ&FI02GM9p3DpcBTtv?6sGrkvmGHn2de;*xbOC&vSt#IKIW8qN=%6@=EntT{e2j zGeUJ|mAH>7VYShFKRoSiAtMXJ@?K>CIGX2p z{a&qVop*G?|D0l^kcD47Jvci&lK=%ykI-&8GLum_CW5I3{#fv&5gE{irUD=EfS*5y zmi|=d>zyAKS*PE;`RDxY#?SAQE8LwFKqUAw)NC*-vY!!rCG89l=^r8jc2WTV&*Ni1 zc1CqE1D!vo`^^8iKV@XMjKTNXz(J-r{JNws{R04xA?Q_8ZvMPwo9W?9cRHlX+&oF1 zm#Aa7nOUjd(Gy5vW58%Db?(n-;W@K$F*v7kLW5AB9{E9G@3|=V}=>ENkKh*4#Z@8;9Tkfu@ zpYsfx55sigB>s|aFo*+yUx5c$1WDlRJd`{V!kY`LKwsq*0X5S`P{b<+FLu_8q)x&( z$$E?zfNn=_PF2MtWajdEse$>KWo6|uZrs|LnN8bgZD2Tdy6uY>BsG*pd^`p*wW9<) z4@TNT>N{cJsR0fK?zr4^XeT_d$g=g3n2!9lM3#VlLv*j|#f?IQU0H7R6Z!`6DU>yUn4VDs{V3vW~e`27@Y^c59R-tfej(sl^gX5J|90?_tOvWF&{lG4KCWw zd2Y}y-y#QWqN=q>_{o830GXlrP1k^tdki!?-YO21r_=tEiYzZC&>{c7;LZoCw()?A zY;)pVy85@Ym_wU+I&juOp_AmN{@qE)BUp7Vac#>a;_-Nd`nPXN#8Yg*c@H`BOi!2P zmM%G|u=wO3zs0+Os7D^$0{LnSHaR5(yg(5GFYqe>;(dBioEDL%#py8Mb>_7Ar>e^7 z_y4xvzXtKI`$bmaxYYsZa~Y30YQ85d3}N}IeM!y-Ng1GICVoOu#%lWb~N!3M9oI9ZnxLl+6^Q5w235$lnf4AwnQv?=-`C+DzW-jbO~qp z4xa*xU+i|Oh?~gD-w0u^wS;F{!83^w*#}OQPmor@u+G}5y}Bx;5g)s?^wJdnqa);s);;nqQAofV_;*vmgNKM}IZ%ZKfd14F^ro3M}lHrv`Q0BaqoW zxzf~wfbHyL(}=T;$61*sz4qI46BgBw32m&gaAqe;Ul3Kdj2cKy$n36GH%SqX%~*18 z+zYC65;UoC=tI4JoG)^m;%`^I5@2wIlXhDvSX!vqXsa<4;Q>#IW*5iQ$HzpBkVwsA ztY!W$P;e44l}M-^IbX6iNz1qBvy5FuW1|J<*1|A3kg{eInGJ^kC!Vo;S-q=X5r{R} zjiJ?Ep5o)i*KZdhIL>8sB$`}~7ueIRZrc3LpH=?T(Nk+X(xP0+Ioey0ZTlNO2aX6$=>Z}nZ zA%Gt(qjn5I z6EL^m0bW2LrP;&ZP>W{rbx}r;_%BK+*Z7Yt7W;4ow$jG%|k{0Ihn2G1TB@l(FY2{ zX2Eok8a@{RPiOa0mE25X!#&R0_E^=?x|qY7k%p$bSv`*jLVOKZcgpsx2z$qfe4M$| zR(Q4*!Wu0bq0Ncjd=R;AUH&^JF~BGwj=&LGyok(RRbxyp!&+c1bawf89K*b*-Omh|vE^}{fS%Nt*# zd&8}bTLTFF!|UT9zm1O*tc;YA>H@eK+pQpZtA{iKCIt5%sm6(f@a0KT`HE8Or(>+c z`smR1Ef?D#{$bx;1=EmK>Xw9*1k&JxBhlNX#(stb%ZQtIL#)ovFuScxXx*<^S6^=O ztog|K+i37g@}AOR{s?oJ#WBaJz9+}Cp!63ksojIMvqm~qa^=fe^ApfKd4}vxO_-2) zL;k(-SlWfO{PxaJv|mvfK`I<-6=KXO91skV73*u5Med#E*8To z>=wdAXCeoaSIH83Nh>;nH(qmm$l8C9*6Y!r?7dcHu9=+wtP_H6DP3B)u&LOJQ2!`@ zi@+ZaWvB?uS{TWZdpNdxb)&nqMJp<0dqnKeuA{=6DM){+zUX~GP4>^0gS!0T$M3=q z3_~N3ZJ`6WI>hxyEXE00cHB>P$B1qv$Aj^Uj|+MoJH;mZLN`1rh|+J35lz#c>k;>& zrUqjPh}aX0ETWm%-BztKL)FZ%eV|)fe453 z+oueTUj+4Qo57>9!zpj7=CtryXHSXvWALrnWBhgo?Ls52h?X~G+cUq=9qFtY+`tDz zR=_$FtN56sUOS|au%#^X##9~^QGiW#?i*WOGa<@1<>i z+n%nnuU0IY52A%5aOt&<)yv8QKSK+g#;lJv;chD~2_N7Xk3+5jLxmrGiu$ess~&|= zxc+C0NR4vPb#Y$#09h+RQ~1NSl*eHK;?{6BJzoLNgEjt5&4e|{^kb#XvKY%U^g3>7 zA$#Qx^+O*_70e7q;9T!;r9uu0;3Zx!S&FT9;&83F0MAEZF?jkFpHM_3(l%krZLW@; zZY^XiEMPT6`Fg;1UR5!B75fS{HiE&fHD1TY{%SU z($LS;>%`dTPW0e_K8<`qrl|?#2B1B227nfOctPU9v|{&qVCzh|^+d?;Z*)uHs>Pj3 z9ixZa7yMTH*Qz$ilRM{0mWng9!-*%|>MNny%S*qplS4YukJ;{r$KzkF2X7N{y*M=V zGCi{}n7l@CI|NLkJFWPOE*_dh7pu0FZ7(HL+gHF+(6C(YCYVMumJqLHsZVz}H|q;^ zGq-W)?*6fuGFV`x%g z*h?yw8)k->j5g7>lQc7gXG!fVCXQdx)ca6+k^Q(L_*r!~mu8j}`S4Lf-w`qvhcUvC z#G?AbwUL!xii+9p#z7}FQNVm>hV3eN`fyutgQM&@pL9MjN)`+>J2cG zt@ z*8KMM`Ufy>-o>FwLgV?&-d&h4by!SvNEZM0EgE?NyQ<06PO(5^xmOQc4su0mg-4yH z%j(d6uL_}E+qYgeHAO8sz9WWsaR`@=Vda7JPdRo_<-X{A?0t{EiP$}P6JhEz8tl`# z#_er}y`cum6NT#}_I;PTLJ3iwV#->0>Eah;#@0($?z6f6&=Z=jDDDj)Npqs|?mX_O2=)p}p^g8+}E1HC+`GUeQYaRqLmTpr%|Mj|V}mWzFvH zA4KNX-13!~@q3yV0DFDegq4&XRKS!qoB(n$B#B53xW41o5@!Xi5eBq)J^$SHhy17k&@ z*oB;r*#tZmq4g}9d~r(RrHV^S(C$h_#B{OmRqi|(rT!Y_eNw@*PCq-mlLl4ACAy)b zxd4aC%sG$7r5y~`k<^5SeJ8{CnACn*{hnYQU@51uj%(d==WwT=MH(mtj6kX!>l$kv zEs}fJM0!JrF%#Ht{VPd^!g(o`!9IGk{b11N#3C%z6Ic@^53#f1vz_zJIEMa|K>Jr^WvlvFiW$B%R{< zZ&6k`ZS{|-{HN-_@Ao(5D)JQi{|mQN{yh8FQpEG;+25AO)7F2J)c-^f|A#XWe;4I{ zV$nZU|2>QT6H+5jS@=JfZ26B!Rr!O<{~e_A{K4gK3gSN+|4l*sL!ZhY@PCuk|7gt( c&XKqQrvz{5zRjlM(^2lJ>#3FAwt4=)04?oeRR910 literal 0 HcmV?d00001 From 430193891fc1d0d9b033b7021b97db6a3aab64e3 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 1 Oct 2016 10:35:22 +0200 Subject: [PATCH 034/169] Fix Config keys. --- Gruntfile.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index e5bc690b4f..c47f55b933 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -47,7 +47,6 @@ module.exports = function(grunt) { "MD018": false, "MD012": false, "MD026": false, - "MD036": false, "MD038": false } }, From b267491934fcdc46e361f4876cf201a2c8785314 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 1 Oct 2016 13:49:41 +0200 Subject: [PATCH 035/169] Add IPv6 loopback IP address to default whitelist. --- config/config.js.sample | 2 +- js/defaults.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.js.sample b/config/config.js.sample index 269492baa4..e611f872fa 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -6,7 +6,7 @@ var config = { port: 8080, - ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1"], + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], language: 'en', timeFormat: 24, diff --git a/js/defaults.js b/js/defaults.js index e2ee615131..0ec033c378 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,7 +10,7 @@ var defaults = { port: 8080, kioskmode: false, - ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1"], + ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], language: "en", timeFormat: 24, From d8d425c963c412740c528a46e5ec4482db603295 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 1 Oct 2016 14:06:10 +0200 Subject: [PATCH 036/169] Visual changes. --- .../default/currentweather/currentweather.js | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 170e9ab6f0..587080db23 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -118,6 +118,7 @@ Module.register("currentweather",{ var small = document.createElement("div"); small.className = "normal medium"; + var windIcon = document.createElement("span"); windIcon.className = "wi wi-strong-wind dimmed"; small.appendChild(windIcon); @@ -135,6 +136,18 @@ Module.register("currentweather",{ spacer.innerHTML = " "; small.appendChild(spacer); + if (this.config.showHumidity) { + var humidity = document.createElement("span"); + humidity.innerHTML = this.humidity; + + var humidityIcon = document.createElement("sup"); + humidityIcon.className = "wi wi-humidity humidityIcon"; + humidityIcon.innerHTML = " "; + + small.appendChild(humidity); + small.appendChild(humidityIcon); + } + var sunriseSunsetIcon = document.createElement("span"); sunriseSunsetIcon.className = "wi dimmed " + this.sunriseSunsetIcon; small.appendChild(sunriseSunsetIcon); @@ -145,24 +158,6 @@ Module.register("currentweather",{ wrapper.appendChild(small); - if (this.config.showHumidity) { - var middle = document.createElement("div"); - middle.className = "normal small humidity-padding"; - - var humidityIcon = document.createElement("span"); - humidityIcon.className = "wi wi-humidity humidityIcon"; - small.appendChild(sunriseSunsetIcon); - - var humidity = document.createElement("span"); - humidity.innerHTML = this.humidity + "%"; - var br = document.createElement("br"); - - middle.appendChild(humidityIcon); - middle.appendChild(humidity); - middle.appendChild(br); - wrapper.appendChild(middle); - } - var large = document.createElement("div"); large.className = "large light"; From ee48a5660341a120e25ed737f4d8b424cd30dcdf Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 1 Oct 2016 14:08:15 +0200 Subject: [PATCH 037/169] Add info about humidity. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc4bde6974..09381c6ab0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)). - Added ability to change the point of time when calendar events get relative. - Add Splash screen on boot. +- Add option to show humidity in currentWeather module. ### Updated - Modified translations for Frysk. From c9e6af96d08ba6a836d3a4c761b530f59353990d Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 4 Oct 2016 16:19:33 +0200 Subject: [PATCH 038/169] Change update information. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 856ab6e041..9c3a3ce562 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ The following wiki links are helpful in the configuration of your MagicMirror² If you want to update your MagicMirror² to the latest version, use your terminal to go to your Magic Mirror folder and type the following command: ```bash -git pull +git pull && npm install ``` If you changed nothing more than the config or the modules, this should work without any problems. From 0671e7d456296c357999068e20d1b1a8d1619939 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 4 Oct 2016 16:21:53 +0200 Subject: [PATCH 039/169] Add update information. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09381c6ab0..7d95b9b03c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [2.1.0] - Unreleased +**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install` + ### Added - Finnish translation. - Danish translation. From 67582d388ad0cf2e80e18d7e7e5eaf8b298c3c5c Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 4 Oct 2016 16:25:39 +0200 Subject: [PATCH 040/169] Fix Table. --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9c3a3ce562..1a06ca6c7a 100644 --- a/README.md +++ b/README.md @@ -73,18 +73,17 @@ Type `git status` to see your changes, if there are any, you can reset them with The following properties can be configured: - | **Option** | **Description** | | --- | --- | | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | -| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1"]`.It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`). - | +| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1"]`.It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | | `units` | The units that will be used in the default weather modules. Possible values are `metric` or `imperial`. The default is `metric`. | | `modules` | An array of active modules. **The array must contain objects. See the next table below for more information.** | + Module configuration: | **Option** | **Description** | From 7dab00be879f8d0f6c96e7134372a2939d2e1620 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 4 Oct 2016 16:26:35 +0200 Subject: [PATCH 041/169] Fix info about default setting. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a06ca6c7a..d8ee167677 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ The following properties can be configured: | **Option** | **Description** | | --- | --- | | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | -| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1"]`.It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| +| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1","::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | From d5d22844ab17bbf084e560282d22f5b4bbbb702b Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 4 Oct 2016 16:27:06 +0200 Subject: [PATCH 042/169] Fix info about default setting. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d8ee167677..0f9ec65dbb 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ The following properties can be configured: | **Option** | **Description** | | --- | --- | | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | -| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1","::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| +| `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1", "::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | From 2b4939a8756237f50f0dc81b40717ab8947eb4db Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 13:10:33 +0200 Subject: [PATCH 043/169] Add VSCode IntelliSense support. --- jsconfig.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000000..2b354edc00 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,13 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=759670 + // for the documentation about the jsconfig.json format + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "allowSyntheticDefaultImports": true + }, + "exclude": [ + "modules", + "node_modules" + ] +} From af63f4098f5d0c58deb0523d9baafdc2fdf80927 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 13:24:56 +0200 Subject: [PATCH 044/169] Improve logger. --- js/logger.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/js/logger.js b/js/logger.js index 5b2df9900b..6c07372093 100644 --- a/js/logger.js +++ b/js/logger.js @@ -13,35 +13,35 @@ var Log = (function() { return { - info: function(message) { - console.info(message); + info: function() { + console.info.apply(this, arguments); }, - log: function(message) { - console.log(message); + log: function() { + console.log.apply(this, arguments); }, - error: function(message) { - console.error(message); + error: function() { + console.error.apply(this, arguments); }, - warn: function(message) { - console.warn(message); + warn: function() { + console.warn.apply(this, arguments); }, - group: function(message) { - console.group(message); + group: function() { + console.group.apply(this, arguments); }, - groupCollapsed: function(message) { - console.groupCollapsed(message); + groupCollapsed: function() { + console.groupCollapsed.apply(this, arguments); }, groupEnd: function() { console.groupEnd(); }, - time: function(message) { - console.time(message); + time: function() { + console.time.apply(this, arguments); }, - timeEnd: function(message) { - console.timeEnd(message); + timeEnd: function() { + console.timeEnd.apply(this, arguments); }, - timeStamp: function(message) { - console.timeStamp(message); + timeStamp: function() { + console.timeStamp.apply(this, arguments); } }; })(); From 55371f9c78e3412707aa5368e1debf939c1cedae Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 14:25:53 +0200 Subject: [PATCH 045/169] Improve object instantiation to prevent reference errors. --- js/class.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/js/class.js b/js/class.js index 9d04944e0d..2b011b29c4 100644 --- a/js/class.js +++ b/js/class.js @@ -11,6 +11,24 @@ // The base Class implementation (does nothing) this.Class = function() {}; + //Define the clone method for later use. + function cloneObject(obj) { + if (obj === null || typeof obj !== "object") { + return obj; + } + + var temp = obj.constructor(); // give temp the original obj's constructor + for (var key in obj) { + temp[key] = cloneObject(obj[key]); + + if (key === "lockStrings") { + Log.log(key); + } + } + + return temp; + } + // Create a new Class that inherits from this class Class.extend = function(prop) { var _super = this.prototype; @@ -21,6 +39,11 @@ var prototype = new this(); initializing = false; + // Make a copy of all prototype properies, to prevent reference issues. + for (var name in prototype) { + prototype[name] = cloneObject(prototype[name]); + } + // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function From 4dc5bbe6012042d9b40b6fa2c73a7cdcd5e7b396 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 15:00:59 +0200 Subject: [PATCH 046/169] First implementation of Visibility locking. --- js/main.js | 49 ++++++++++++++++++++++++++----- js/module.js | 32 +++++++++++++++++---- modules/README.md | 73 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 138 insertions(+), 16 deletions(-) diff --git a/js/main.js b/js/main.js index c0c6300638..a8572c6ae9 100644 --- a/js/main.js +++ b/js/main.js @@ -174,7 +174,17 @@ var MM = (function() { * argument speed Number - The speed of the hide animation. * argument callback function - Called when the animation is done. */ - var hideModule = function(module, speed, callback) { + var hideModule = function(module, speed, callback, options) { + options = options || {}; + + // set lockString if set in options. + if (options.lockString) { + Log.log("Has lockstring: " + options.lockString); + if (module.lockStrings.indexOf(options.lockString) === -1) { + module.lockStrings.push(options.lockString); + } + } + var moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper !== null) { moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; @@ -183,7 +193,7 @@ var MM = (function() { clearTimeout(module.showHideTimer); module.showHideTimer = setTimeout(function() { // To not take up any space, we just make the position absolute. - // since it"s fade out anyway, we can see it lay above or + // since it's fade out anyway, we can see it lay above or // below other modules. This works way better than adjusting // the .display property. moduleWrapper.style.position = "absolute"; @@ -200,7 +210,30 @@ var MM = (function() { * argument speed Number - The speed of the show animation. * argument callback function - Called when the animation is done. */ - var showModule = function(module, speed, callback) { + var showModule = function(module, speed, callback, options) { + options = options || {}; + + // remove lockString if set in options. + if (options.lockString) { + var index = module.lockStrings.indexOf(options.lockString) + if ( index !== -1) { + module.lockStrings.splice(index, 1); + } + } + + // Check if there are no more lockstrings set, or the force option is set. + // Otherwise cancel show action. + if (module.lockStrings.length !== 0 && options.force !== true) { + Log.log("Will not show " + module.name + ". LockStrings active: " + module.lockStrings.join(",")); + return; + } + + // If forced show, clean current lockstrings. + if (module.lockStrings.length !== 0 && options.force === true) { + Log.log("Force show of module: " + module.name); + module.lockStrings = []; + } + var moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper !== null) { moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; @@ -419,10 +452,11 @@ var MM = (function() { * argument module Module - The module hide. * argument speed Number - The speed of the hide animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - hideModule: function(module, speed, callback) { + hideModule: function(module, speed, callback, options) { module.hidden = true; - hideModule(module, speed, callback); + hideModule(module, speed, callback, options); }, /* showModule(module, speed, callback) @@ -431,10 +465,11 @@ var MM = (function() { * argument module Module - The module show. * argument speed Number - The speed of the show animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - showModule: function(module, speed, callback) { + showModule: function(module, speed, callback, options) { module.hidden = false; - showModule(module, speed, callback); + showModule(module, speed, callback, options); } }; diff --git a/js/module.js b/js/module.js index 9c26bc7b0a..fe669cee78 100644 --- a/js/module.js +++ b/js/module.js @@ -20,6 +20,10 @@ var Module = Class.extend({ // Timer reference used for showHide animation callbacks. showHideTimer: null, + // Array to store lockStrings. These stings are used to lock + // visibility when hiding and showing module. + lockStrings: [], + /* init() * Is called when the module is instantiated. */ @@ -314,15 +318,24 @@ var Module = Class.extend({ * * argument speed Number - The speed of the hide animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - hide: function(speed, callback) { + hide: function(speed, callback, options) { + if (typeof callback === "object") { + options = callback; + callback = function() {}; + } + callback = callback || function() {}; + options = options || {}; var self = this; MM.hideModule(self, speed, function() { self.suspend(); callback(); - }); + }, options); + + Log.log(options); }, /* showModule(module, speed, callback) @@ -330,10 +343,19 @@ var Module = Class.extend({ * * argument speed Number - The speed of the show animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - show: function(speed, callback) { + show: function(speed, callback, options) { + if (typeof callback === "object") { + options = callback; + callback = function() {}; + } + + callback = callback || function() {}; + options = options || {}; + this.resume(); - MM.showModule(this, speed, callback); + MM.showModule(this, speed, callback, options); } }); @@ -347,7 +369,7 @@ Module.create = function(name) { return obj; } - var temp = obj.constructor(); // give temp the original obj"s constructor + var temp = obj.constructor(); // give temp the original obj's constructor for (var key in obj) { temp[key] = cloneObject(obj[key]); } diff --git a/modules/README.md b/modules/README.md index e7a23abd4f..ec9c018c77 100644 --- a/modules/README.md +++ b/modules/README.md @@ -283,26 +283,91 @@ If you want to send a notification to the node_helper, use the `sendSocketNotifi this.sendSocketNotification('SET_CONFIG', this.config); ```` -####`this.hide(speed, callback)` -***speed* Number** - Optional, The speed of the hide animation in milliseconds. +####`this.hide(speed, callback, options)` +***speed* Number** - Optional (Required when setting callback or options), The speed of the hide animation in milliseconds. ***callback* Function** - Optional, The callback after the hide animation is finished. +***options* Function** - Optional, Object with additional options for the hide action (see below). To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itself using `this.hide()`, but of course you can also hide another module using `anOtherModule.hide()`. +Possible configurable options: +* `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. It's considered best practice to use your modules identifier as the locksString: `this.identifier`. See *visibility locking* below. + + **Note 1:** If the hide animation is canceled, for instance because the show method is called before the hide animation was finished, the callback will not be called.
**Note 2:** If the hide animation is hijacked (an other method calls hide on the same module), the callback will not be called.
**Note 3:** If the dom is not yet created, the hide method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender). -####`this.show(speed, callback)` -***speed* Number** - Optional, The speed of the show animation in milliseconds. + +####`this.show(speed, callback, options)` +***speed* Number** - Optional (Required when setting callback or options), The speed of the show animation in milliseconds. ***callback* Function** - Optional, The callback after the show animation is finished. +***options* Function** - Optional, Object with additional options for the show action (see below). To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itself using `this.show()`, but of course you can also show another module using `anOtherModule.show()`. +Possible configurable options: +* `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. See *visibility locking* below. +* `force` - Boolean - When setting the force tag to `true`, the locking mechanism will be overwritten. Use this option with caution. It's considered best practice to let the usage of the force option be user configurable. See *visibility locking* below. + **Note 1:** If the show animation is canceled, for instance because the hide method is called before the show animation was finished, the callback will not be called.
**Note 2:** If the show animation is hijacked (an other method calls show on the same module), the callback will not be called.
**Note 3:** If the dom is not yet created, the show method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender). +####Visibility locking +Visiblity locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept: + +**Module B asks module A to hide:** +```` +moduleA.hide(0, {lockString: "module_b_identifier"}); +```` +Module A is now hidden, and has an lock array with the following strings: +```` +moduleA.lockStrings == ["module_b_identifier"] +moduleA.hidden == true +```` +**Module C asks module A to hide:** +```` +moduleA.hide(0, {lockString: "module_c_identifier"}); +```` +Module A is now hidden, and has an lock array with the following strings: +```` +moduleA.lockStrings == ["module_b_identifier", "module_c_identifier"] +moduleA.hidden == true +```` +**Module B asks module A to show:** +```` +moduleA.show(0, {lockString: "module_b_identifier"}); +```` +The lockString will be removed from moduleA’s locks array, but since there still is an other lock string available, the module remains hidden: +```` +moduleA.lockStrings == ["module_c_identifier"] +moduleA.hidden == true +```` +**Module C asks module A to show:** +```` +moduleA.show(0, {lockString: "module_c_identifier"}); +```` +The lockString will be removed from moduleA’s locks array, and since this will result in an empty lock array, the module will be visible: +```` +moduleA.lockStrings == [] +moduleA.hidden == false +```` + +**Note:** The locking mechanism can be overwritten by using the force tag: +```` +moduleA.show(0, {force: true}); +```` +This will reset the lockstring array, and will show the module. +```` +moduleA.lockStrings == [] +moduleA.hidden == false +```` + +Use this `force` method with caution. See `show()` method for more information. + + + ####`this.translate(identifier)` ***identifier* String** - Identifier of the string that should be translated. From 8d8374b8e2630d1e0cb6bb53624aecc10c0a694b Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 15:00:59 +0200 Subject: [PATCH 047/169] First implementation of Visibility locking. --- js/main.js | 49 ++++++++++++++++++++++++++----- js/module.js | 32 ++++++++++++++++---- modules/README.md | 75 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 140 insertions(+), 16 deletions(-) diff --git a/js/main.js b/js/main.js index c0c6300638..a8572c6ae9 100644 --- a/js/main.js +++ b/js/main.js @@ -174,7 +174,17 @@ var MM = (function() { * argument speed Number - The speed of the hide animation. * argument callback function - Called when the animation is done. */ - var hideModule = function(module, speed, callback) { + var hideModule = function(module, speed, callback, options) { + options = options || {}; + + // set lockString if set in options. + if (options.lockString) { + Log.log("Has lockstring: " + options.lockString); + if (module.lockStrings.indexOf(options.lockString) === -1) { + module.lockStrings.push(options.lockString); + } + } + var moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper !== null) { moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; @@ -183,7 +193,7 @@ var MM = (function() { clearTimeout(module.showHideTimer); module.showHideTimer = setTimeout(function() { // To not take up any space, we just make the position absolute. - // since it"s fade out anyway, we can see it lay above or + // since it's fade out anyway, we can see it lay above or // below other modules. This works way better than adjusting // the .display property. moduleWrapper.style.position = "absolute"; @@ -200,7 +210,30 @@ var MM = (function() { * argument speed Number - The speed of the show animation. * argument callback function - Called when the animation is done. */ - var showModule = function(module, speed, callback) { + var showModule = function(module, speed, callback, options) { + options = options || {}; + + // remove lockString if set in options. + if (options.lockString) { + var index = module.lockStrings.indexOf(options.lockString) + if ( index !== -1) { + module.lockStrings.splice(index, 1); + } + } + + // Check if there are no more lockstrings set, or the force option is set. + // Otherwise cancel show action. + if (module.lockStrings.length !== 0 && options.force !== true) { + Log.log("Will not show " + module.name + ". LockStrings active: " + module.lockStrings.join(",")); + return; + } + + // If forced show, clean current lockstrings. + if (module.lockStrings.length !== 0 && options.force === true) { + Log.log("Force show of module: " + module.name); + module.lockStrings = []; + } + var moduleWrapper = document.getElementById(module.identifier); if (moduleWrapper !== null) { moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; @@ -419,10 +452,11 @@ var MM = (function() { * argument module Module - The module hide. * argument speed Number - The speed of the hide animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - hideModule: function(module, speed, callback) { + hideModule: function(module, speed, callback, options) { module.hidden = true; - hideModule(module, speed, callback); + hideModule(module, speed, callback, options); }, /* showModule(module, speed, callback) @@ -431,10 +465,11 @@ var MM = (function() { * argument module Module - The module show. * argument speed Number - The speed of the show animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - showModule: function(module, speed, callback) { + showModule: function(module, speed, callback, options) { module.hidden = false; - showModule(module, speed, callback); + showModule(module, speed, callback, options); } }; diff --git a/js/module.js b/js/module.js index 9c26bc7b0a..fe669cee78 100644 --- a/js/module.js +++ b/js/module.js @@ -20,6 +20,10 @@ var Module = Class.extend({ // Timer reference used for showHide animation callbacks. showHideTimer: null, + // Array to store lockStrings. These stings are used to lock + // visibility when hiding and showing module. + lockStrings: [], + /* init() * Is called when the module is instantiated. */ @@ -314,15 +318,24 @@ var Module = Class.extend({ * * argument speed Number - The speed of the hide animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - hide: function(speed, callback) { + hide: function(speed, callback, options) { + if (typeof callback === "object") { + options = callback; + callback = function() {}; + } + callback = callback || function() {}; + options = options || {}; var self = this; MM.hideModule(self, speed, function() { self.suspend(); callback(); - }); + }, options); + + Log.log(options); }, /* showModule(module, speed, callback) @@ -330,10 +343,19 @@ var Module = Class.extend({ * * argument speed Number - The speed of the show animation. * argument callback function - Called when the animation is done. + * argument options object - Optional settings for the hide method. */ - show: function(speed, callback) { + show: function(speed, callback, options) { + if (typeof callback === "object") { + options = callback; + callback = function() {}; + } + + callback = callback || function() {}; + options = options || {}; + this.resume(); - MM.showModule(this, speed, callback); + MM.showModule(this, speed, callback, options); } }); @@ -347,7 +369,7 @@ Module.create = function(name) { return obj; } - var temp = obj.constructor(); // give temp the original obj"s constructor + var temp = obj.constructor(); // give temp the original obj's constructor for (var key in obj) { temp[key] = cloneObject(obj[key]); } diff --git a/modules/README.md b/modules/README.md index e7a23abd4f..d157c983eb 100644 --- a/modules/README.md +++ b/modules/README.md @@ -283,26 +283,93 @@ If you want to send a notification to the node_helper, use the `sendSocketNotifi this.sendSocketNotification('SET_CONFIG', this.config); ```` -####`this.hide(speed, callback)` -***speed* Number** - Optional, The speed of the hide animation in milliseconds. +####`this.hide(speed, callback, options)` +***speed* Number** - Optional (Required when setting callback or options), The speed of the hide animation in milliseconds. ***callback* Function** - Optional, The callback after the hide animation is finished. +***options* Function** - Optional, Object with additional options for the hide action (see below). To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itself using `this.hide()`, but of course you can also hide another module using `anOtherModule.hide()`. +Possible configurable options: + +- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. It's considered best practice to use your modules identifier as the locksString: `this.identifier`. See *visibility locking* below. + + **Note 1:** If the hide animation is canceled, for instance because the show method is called before the hide animation was finished, the callback will not be called.
**Note 2:** If the hide animation is hijacked (an other method calls hide on the same module), the callback will not be called.
**Note 3:** If the dom is not yet created, the hide method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender). -####`this.show(speed, callback)` -***speed* Number** - Optional, The speed of the show animation in milliseconds. + +####`this.show(speed, callback, options)` +***speed* Number** - Optional (Required when setting callback or options), The speed of the show animation in milliseconds. ***callback* Function** - Optional, The callback after the show animation is finished. +***options* Function** - Optional, Object with additional options for the show action (see below). To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itself using `this.show()`, but of course you can also show another module using `anOtherModule.show()`. +Possible configurable options: + +- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. See *visibility locking- below. +- `force` - Boolean - When setting the force tag to `true`, the locking mechanism will be overwritten. Use this option with caution. It's considered best practice to let the usage of the force option be use- configurable. See *visibility locking* below. + **Note 1:** If the show animation is canceled, for instance because the hide method is called before the show animation was finished, the callback will not be called.
**Note 2:** If the show animation is hijacked (an other method calls show on the same module), the callback will not be called.
**Note 3:** If the dom is not yet created, the show method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender). +####Visibility locking +Visiblity locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept: + +**Module B asks module A to hide:** +```` +moduleA.hide(0, {lockString: "module_b_identifier"}); +```` +Module A is now hidden, and has an lock array with the following strings: +```` +moduleA.lockStrings == ["module_b_identifier"] +moduleA.hidden == true +```` +**Module C asks module A to hide:** +```` +moduleA.hide(0, {lockString: "module_c_identifier"}); +```` +Module A is now hidden, and has an lock array with the following strings: +```` +moduleA.lockStrings == ["module_b_identifier", "module_c_identifier"] +moduleA.hidden == true +```` +**Module B asks module A to show:** +```` +moduleA.show(0, {lockString: "module_b_identifier"}); +```` +The lockString will be removed from moduleA’s locks array, but since there still is an other lock string available, the module remains hidden: +```` +moduleA.lockStrings == ["module_c_identifier"] +moduleA.hidden == true +```` +**Module C asks module A to show:** +```` +moduleA.show(0, {lockString: "module_c_identifier"}); +```` +The lockString will be removed from moduleA’s locks array, and since this will result in an empty lock array, the module will be visible: +```` +moduleA.lockStrings == [] +moduleA.hidden == false +```` + +**Note:** The locking mechanism can be overwritten by using the force tag: +```` +moduleA.show(0, {force: true}); +```` +This will reset the lockstring array, and will show the module. +```` +moduleA.lockStrings == [] +moduleA.hidden == false +```` + +Use this `force` method with caution. See `show()` method for more information. + + + ####`this.translate(identifier)` ***identifier* String** - Identifier of the string that should be translated. From 0433432e6295e6cf217abda2426cfb36092d45ba Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 15:15:38 +0200 Subject: [PATCH 048/169] Add information about recent changes. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d95b9b03c..08cc8850be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added ability to change the point of time when calendar events get relative. - Add Splash screen on boot. - Add option to show humidity in currentWeather module. +- Add Visibility locking to module system. See [documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. +- Add VSCode IntelliSense support. ### Updated - Modified translations for Frysk. - Updated package.json as a result of Snyk security update. +- Improve object instantiation to prevent reference errors. +- Improve logger. `Log.log()` now accepts multiple arguments. ### Changed - Calendar times are now uniformly capitalized. From 15a5e3c77936e8cb4e2fff87ab458c8f705169c9 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 15:19:12 +0200 Subject: [PATCH 049/169] Fix typo. --- modules/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/README.md b/modules/README.md index d157c983eb..52456016a7 100644 --- a/modules/README.md +++ b/modules/README.md @@ -309,7 +309,7 @@ To show a module, you can call the `show(speed, callback)` method. You can call Possible configurable options: -- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. See *visibility locking- below. +- `lockString` - String - When setting lock string, the module can not be shown without passing the correct lockstring. This way (multiple) modules can prevent a module from showing. See *visibility locking* below. - `force` - Boolean - When setting the force tag to `true`, the locking mechanism will be overwritten. Use this option with caution. It's considered best practice to let the usage of the force option be use- configurable. See *visibility locking* below. **Note 1:** If the show animation is canceled, for instance because the hide method is called before the show animation was finished, the callback will not be called.
From 95edbc16bbd2d28cb4f997e92df8bae860daed56 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 16:42:15 +0200 Subject: [PATCH 050/169] Add requiresVersion property to module API. --- CHANGELOG.md | 5 +- index.html | 4 ++ js/app.js | 37 ++++++++++++++ js/loader.js | 8 ++- js/module.js | 128 ++++++++++++++++++++++++++++++---------------- js/server.js | 10 +++- modules/README.md | 27 +++++++++- package.json | 2 +- 8 files changed, 169 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08cc8850be..09c8e0a602 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,13 +9,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Finnish translation. - Danish translation. -- Method to overwrite the module's header. [See documentation.](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) - Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)). - Added ability to change the point of time when calendar events get relative. - Add Splash screen on boot. - Add option to show humidity in currentWeather module. -- Add Visibility locking to module system. See [documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. - Add VSCode IntelliSense support. +- Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. +- Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information. +- Module API: Option to define the minimumn MagicMirror verion to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresVersion) for more information. ### Updated - Modified translations for Frysk. diff --git a/index.html b/index.html index 4288eba18a..86a69a4ad5 100644 --- a/index.html +++ b/index.html @@ -8,6 +8,10 @@ + +
diff --git a/js/app.js b/js/app.js index 14f10e8b8d..84e89d1387 100644 --- a/js/app.js +++ b/js/app.js @@ -10,6 +10,10 @@ var Server = require(__dirname + "/server.js"); var defaultModules = require(__dirname + "/../modules/default/defaultmodules.js"); var path = require("path"); +// Get version number. +global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version; +console.log("Starting MagicMirror: v" + global.version); + // The next part is here to prevent a major exception when there // is no internet connection. This could probable be solved better. process.on("uncaughtException", function (err) { @@ -82,6 +86,17 @@ var App = function() { if (loadModule) { var Module = require(helperPath); var m = new Module(); + + if (m.requiresVersion) { + console.log("Check MagicMirror version for node helper '" + moduleName + "' - Minimum version: " + m.requiresVersion + " - Current version: " + global.version); + if (cmpVersions(global.version, m.requiresVersion) >= 0) { + console.log("Version is ok!"); + } else { + console.log("Version is incorrect. Skip module: '" + moduleName + "'"); + return; + } + } + m.setName(moduleName); m.setPath(path.resolve(moduleFolder)); nodeHelpers.push(m); @@ -103,6 +118,28 @@ var App = function() { console.log("All module helpers loaded."); }; + /* cmpVersions(a,b) + * Compare two symantic version numbers and return the difference. + * + * argument a string - Version number a. + * argument a string - Version number b. + */ + function cmpVersions(a, b) { + var i, diff; + var regExStrip0 = /(\.0+)+$/; + var segmentsA = a.replace(regExStrip0, "").split("."); + var segmentsB = b.replace(regExStrip0, "").split("."); + var l = Math.min(segmentsA.length, segmentsB.length); + + for (i = 0; i < l; i++) { + diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); + if (diff) { + return diff; + } + } + return segmentsA.length - segmentsB.length; + } + /* start(callback) * This methods starts the core app. * It loads the config, then it loads all modules. diff --git a/js/loader.js b/js/loader.js index 3656c7cd88..84e42a0ad2 100644 --- a/js/loader.js +++ b/js/loader.js @@ -117,9 +117,13 @@ var Loader = (function() { var afterLoad = function() { var moduleObject = Module.create(module.name); - bootstrapModule(module, moduleObject, function() { + if (moduleObject) { + bootstrapModule(module, moduleObject, function() { + callback(); + }); + } else { callback(); - }); + } }; if (loadedModuleFiles.indexOf(url) !== -1) { diff --git a/js/module.js b/js/module.js index fe669cee78..17ca959588 100644 --- a/js/module.js +++ b/js/module.js @@ -14,6 +14,9 @@ var Module = Class.extend({ * All methods (and properties) below can be subclassed. * *********************************************************/ + // Set the minimum MagicMirror module version for this module. + requiresVersion: "2.0.0", + // Module config defaults. defaults: {}, @@ -27,14 +30,14 @@ var Module = Class.extend({ /* init() * Is called when the module is instantiated. */ - init: function() { + init: function () { //Log.log(this.defaults); }, /* start() * Is called when the module is started. */ - start: function() { + start: function () { Log.info("Starting module: " + this.name); }, @@ -43,7 +46,7 @@ var Module = Class.extend({ * * return Array - An array with filenames. */ - getScripts: function() { + getScripts: function () { return []; }, @@ -52,7 +55,7 @@ var Module = Class.extend({ * * return Array - An array with filenames. */ - getStyles: function() { + getStyles: function () { return []; }, @@ -61,7 +64,7 @@ var Module = Class.extend({ * * return Map - A map with langKeys and filenames. */ - getTranslations: function() { + getTranslations: function () { return false; }, @@ -71,7 +74,7 @@ var Module = Class.extend({ * * return domobject - The dom to display. */ - getDom: function() { + getDom: function () { var nameWrapper = document.createElement("div"); var name = document.createTextNode(this.name); nameWrapper.appendChild(name); @@ -95,7 +98,7 @@ var Module = Class.extend({ * * return string - The header to display above the header. */ - getHeader: function() { + getHeader: function () { return this.data.header; }, @@ -107,7 +110,7 @@ var Module = Class.extend({ * argument payload mixed - The payload of the notification. * argument sender Module - The module that sent the notification. */ - notificationReceived: function(notification, payload, sender) { + notificationReceived: function (notification, payload, sender) { if (sender) { Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name); } else { @@ -121,21 +124,21 @@ var Module = Class.extend({ * argument notification string - The identifier of the noitication. * argument payload mixed - The payload of the notification. */ - socketNotificationReceived: function(notification, payload) { + socketNotificationReceived: function (notification, payload) { Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload); }, /* suspend() * This method is called when a module is hidden. */ - suspend: function() { + suspend: function () { Log.log(this.name + " is suspended."); }, /* resume() * This method is called when a module is shown. */ - resume: function() { + resume: function () { Log.log(this.name + " is resumed."); }, @@ -148,7 +151,7 @@ var Module = Class.extend({ * * argument data obejct - Module data. */ - setData: function(data) { + setData: function (data) { this.data = data; this.name = data.name; this.identifier = data.identifier; @@ -162,7 +165,7 @@ var Module = Class.extend({ * * argument config obejct - Module config. */ - setConfig: function(config) { + setConfig: function (config) { this.config = Object.assign(this.defaults, config); }, @@ -170,13 +173,13 @@ var Module = Class.extend({ * Returns a socket object. If it doesn"t exist, it"s created. * It also registers the notification callback. */ - socket: function() { + socket: function () { if (typeof this._socket === "undefined") { this._socket = this._socket = new MMSocket(this.name); } var self = this; - this._socket.setNotificationCallback(function(notification, payload) { + this._socket.setNotificationCallback(function (notification, payload) { self.socketNotificationReceived(notification, payload); }); @@ -190,7 +193,7 @@ var Module = Class.extend({ * * return string - File path. */ - file: function(file) { + file: function (file) { return this.data.path + "/" + file; }, @@ -199,14 +202,14 @@ var Module = Class.extend({ * * argument callback function - Function called when done. */ - loadStyles: function(callback) { + loadStyles: function (callback) { var self = this; var styles = this.getStyles(); - var loadNextStyle = function() { + var loadNextStyle = function () { if (styles.length > 0) { var nextStyle = styles[0]; - Loader.loadFile(nextStyle, self, function() { + Loader.loadFile(nextStyle, self, function () { styles = styles.slice(1); loadNextStyle(); }); @@ -223,14 +226,14 @@ var Module = Class.extend({ * * argument callback function - Function called when done. */ - loadScripts: function(callback) { + loadScripts: function (callback) { var self = this; var scripts = this.getScripts(); - var loadNextScript = function() { + var loadNextScript = function () { if (scripts.length > 0) { var nextScript = scripts[0]; - Loader.loadFile(nextScript, self, function() { + Loader.loadFile(nextScript, self, function () { scripts = scripts.slice(1); loadNextScript(); }); @@ -247,14 +250,14 @@ var Module = Class.extend({ * * argument callback function - Function called when done. */ - loadTranslations: function(callback) { + loadTranslations: function (callback) { var self = this; var translations = this.getTranslations(); var lang = config.language.toLowerCase(); // The variable `first` will contain the first // defined translation after the following line. - for (var first in translations) {break;} + for (var first in translations) { break; } if (translations) { var translationFile = translations[lang] || undefined; @@ -263,7 +266,7 @@ var Module = Class.extend({ // If a translation file is set, load it and then also load the fallback translation file. // Otherwise only load the fallback translation file. if (translationFile !== undefined && translationFile !== translationsFallbackFile) { - Translator.load(self, translationFile, false, function() { + Translator.load(self, translationFile, false, function () { Translator.load(self, translationsFallbackFile, true, callback); }); } else { @@ -274,13 +277,13 @@ var Module = Class.extend({ } }, - /* translate(key, defaultValue) - * Request the translation for a given key. - * - * argument key string - The key of the string to translage - * argument defaultValue string - The default value if no translation was found. (Optional) - */ - translate: function(key, defaultValue) { + /* translate(key, defaultValue) + * Request the translation for a given key. + * + * argument key string - The key of the string to translage + * argument defaultValue string - The default value if no translation was found. (Optional) + */ + translate: function (key, defaultValue) { return Translator.translate(this, key) || defaultValue || ""; }, @@ -289,7 +292,7 @@ var Module = Class.extend({ * * argument speed Number - The speed of the animation. (Optional) */ - updateDom: function(speed) { + updateDom: function (speed) { MM.updateDom(this, speed); }, @@ -299,7 +302,7 @@ var Module = Class.extend({ * argument notification string - The identifier of the noitication. * argument payload mixed - The payload of the notification. */ - sendNotification: function(notification, payload) { + sendNotification: function (notification, payload) { MM.sendNotification(notification, payload, this); }, @@ -309,7 +312,7 @@ var Module = Class.extend({ * argument notification string - The identifier of the noitication. * argument payload mixed - The payload of the notification. */ - sendSocketNotification: function(notification, payload) { + sendSocketNotification: function (notification, payload) { this.socket().sendNotification(notification, payload); }, @@ -320,17 +323,17 @@ var Module = Class.extend({ * argument callback function - Called when the animation is done. * argument options object - Optional settings for the hide method. */ - hide: function(speed, callback, options) { + hide: function (speed, callback, options) { if (typeof callback === "object") { options = callback; - callback = function() {}; + callback = function () { }; } - callback = callback || function() {}; + callback = callback || function () { }; options = options || {}; var self = this; - MM.hideModule(self, speed, function() { + MM.hideModule(self, speed, function () { self.suspend(); callback(); }, options); @@ -345,13 +348,13 @@ var Module = Class.extend({ * argument callback function - Called when the animation is done. * argument options object - Optional settings for the hide method. */ - show: function(speed, callback, options) { + show: function (speed, callback, options) { if (typeof callback === "object") { options = callback; - callback = function() {}; + callback = function () { }; } - callback = callback || function() {}; + callback = callback || function () { }; options = options || {}; this.resume(); @@ -361,7 +364,12 @@ var Module = Class.extend({ Module.definitions = {}; -Module.create = function(name) { +Module.create = function (name) { + + // Make sure module definition is available. + if (!Module.definitions[name]) { + return; + } //Define the clone method for later use. function cloneObject(obj) { @@ -387,7 +395,39 @@ Module.create = function(name) { }; -Module.register = function(name, moduleDefinition) { +/* cmpVersions(a,b) +* Compare two symantic version numbers and return the difference. +* +* argument a string - Version number a. +* argument a string - Version number b. +*/ +function cmpVersions(a, b) { + var i, diff; + var regExStrip0 = /(\.0+)+$/; + var segmentsA = a.replace(regExStrip0, "").split("."); + var segmentsB = b.replace(regExStrip0, "").split("."); + var l = Math.min(segmentsA.length, segmentsB.length); + + for (i = 0; i < l; i++) { + diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10); + if (diff) { + return diff; + } + } + return segmentsA.length - segmentsB.length; +} + +Module.register = function (name, moduleDefinition) { + + if (moduleDefinition.requiresVersion) { + Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + version); + if (cmpVersions(version, moduleDefinition.requiresVersion) >= 0) { + Log.log("Version is ok!"); + } else { + Log.log("Version is incorrect. Skip module: '" + name + "'"); + return; + } + } Log.log("Module registered: " + name); Module.definitions[name] = moduleDefinition; }; diff --git a/js/server.js b/js/server.js index e1a909469b..9ab47a7dd0 100644 --- a/js/server.js +++ b/js/server.js @@ -11,6 +11,7 @@ var server = require("http").Server(app); var io = require("socket.io")(server); var path = require("path"); var ipfilter = require("express-ipfilter").IpFilter; +var fs = require("fs"); var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); @@ -35,8 +36,15 @@ var Server = function(config, callback) { app.use("/vendor", express.static(path.resolve(__dirname + "/../vendor"))); app.use("/translations", express.static(path.resolve(__dirname + "/../translations"))); + app.get("/version", function(req,res) { + res.send(global.version); + }); + app.get("/", function(req, res) { - res.sendFile(path.resolve(__dirname + "/../index.html")); + var html = fs.readFileSync(path.resolve(__dirname + "/../index.html"), {encoding: "utf8"}); + html = html.replace("#VERSION#", global.version); + + res.send(html); }); if (typeof callback === "function") { diff --git a/modules/README.md b/modules/README.md index 52456016a7..9332d009ad 100644 --- a/modules/README.md +++ b/modules/README.md @@ -78,6 +78,16 @@ The data object contains additional metadata about the module instance: ####`defaults: {}` Any properties defined in the defaults object, will be merged with the module config as defined in the user's config.js file. This is the best place to set your modules's configuration defaults. Any of the module configuration properties can be accessed using `this.config.propertyName`, but more about that later. +####'requiresVersion:' + +*Introduced in version: 2.1.0.* + +A string that defines the minimum version of the MagicMirror framework. If it is set, the system compares the required version with the users version. If the version of the user is out of date, it won't run the module. Make sure to also set this value in the Node helper. + +**Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. + +Example: `"2.1.0"` + ### Subclassable module methods ####`init()` @@ -286,7 +296,7 @@ this.sendSocketNotification('SET_CONFIG', this.config); ####`this.hide(speed, callback, options)` ***speed* Number** - Optional (Required when setting callback or options), The speed of the hide animation in milliseconds. ***callback* Function** - Optional, The callback after the hide animation is finished. -***options* Function** - Optional, Object with additional options for the hide action (see below). +***options* Function** - Optional, Object with additional options for the hide action (see below). (*Introduced in version: 2.1.0.*) To hide a module, you can call the `hide(speed, callback)` method. You can call the hide method on the module instance itself using `this.hide()`, but of course you can also hide another module using `anOtherModule.hide()`. @@ -303,7 +313,7 @@ Possible configurable options: ####`this.show(speed, callback, options)` ***speed* Number** - Optional (Required when setting callback or options), The speed of the show animation in milliseconds. ***callback* Function** - Optional, The callback after the show animation is finished. -***options* Function** - Optional, Object with additional options for the show action (see below). +***options* Function** - Optional, Object with additional options for the show action (see below). (*Introduced in version: 2.1.0.*) To show a module, you can call the `show(speed, callback)` method. You can call the show method on the module instance itself using `this.show()`, but of course you can also show another module using `anOtherModule.show()`. @@ -317,6 +327,9 @@ Possible configurable options: **Note 3:** If the dom is not yet created, the show method won't work. Wait for the `DOM_OBJECTS_CREATED` [notification](#notificationreceivednotification-payload-sender). ####Visibility locking + +(*Introduced in version: 2.1.0.*) + Visiblity locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept: **Module B asks module A to hide:** @@ -450,6 +463,16 @@ this.expressApp.use("/" + this.name, express.static(this.path + "/public")); This is a link to the IO instance. It will allow you to do some Socket.IO magic. In most cases you won't need this, since the Node Helper has a few convenience methods to make this simple. + +####'requiresVersion:' +*Introduced in version: 2.1.0.* + +A string that defines the minimum version of the MagicMirror framework. If it is set, the system compares the required version with the users version. If the version of the user is out of date, it won't run the module. + +**Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. + +Example: `"2.1.0"` + ### Subclassable module methods ####`init()` diff --git a/package.json b/package.json index cfef5f85fd..202c3e5981 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "magicmirror", - "version": "2.0.0", + "version": "2.1.0", "description": "A modular interface for smart mirrors.", "main": "js/electron.js", "scripts": { From 0d45eb91db6928f27edfaa0a42440232248301a8 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 16:43:43 +0200 Subject: [PATCH 051/169] Fix typo. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09c8e0a602..5e407d8c95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Add VSCode IntelliSense support. - Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. - Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information. -- Module API: Option to define the minimumn MagicMirror verion to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresVersion) for more information. +- Module API: Option to define the minimumn MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information. ### Updated - Modified translations for Frysk. From a75ff0c061986aade69bf2a9b59d5437c4dc34a9 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 16:45:23 +0200 Subject: [PATCH 052/169] Improve documentation. --- modules/README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/README.md b/modules/README.md index 9332d009ad..313c888095 100644 --- a/modules/README.md +++ b/modules/README.md @@ -86,7 +86,10 @@ A string that defines the minimum version of the MagicMirror framework. If it is **Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. -Example: `"2.1.0"` +Example: +```` +requiresVersion: "2.1.0", +```` ### Subclassable module methods @@ -471,7 +474,10 @@ A string that defines the minimum version of the MagicMirror framework. If it is **Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. -Example: `"2.1.0"` +Example: +```` +requiresVersion: "2.1.0", +```` ### Subclassable module methods From a6191320a100dc9c0017ef24dc47634e405b514e Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 16:47:00 +0200 Subject: [PATCH 053/169] Improve documentation. --- modules/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/README.md b/modules/README.md index 313c888095..54043b6982 100644 --- a/modules/README.md +++ b/modules/README.md @@ -87,7 +87,7 @@ A string that defines the minimum version of the MagicMirror framework. If it is **Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. Example: -```` +````javascript requiresVersion: "2.1.0", ```` @@ -336,48 +336,48 @@ Possible configurable options: Visiblity locking helps the module system to prevent unwanted hide/show actions. The following scenario explains the concept: **Module B asks module A to hide:** -```` +````javascript moduleA.hide(0, {lockString: "module_b_identifier"}); ```` Module A is now hidden, and has an lock array with the following strings: -```` +````javascript moduleA.lockStrings == ["module_b_identifier"] moduleA.hidden == true ```` **Module C asks module A to hide:** -```` +````javascript moduleA.hide(0, {lockString: "module_c_identifier"}); ```` Module A is now hidden, and has an lock array with the following strings: -```` +````javascript moduleA.lockStrings == ["module_b_identifier", "module_c_identifier"] moduleA.hidden == true ```` **Module B asks module A to show:** -```` +````javascript moduleA.show(0, {lockString: "module_b_identifier"}); ```` The lockString will be removed from moduleA’s locks array, but since there still is an other lock string available, the module remains hidden: -```` +````javascript moduleA.lockStrings == ["module_c_identifier"] moduleA.hidden == true ```` **Module C asks module A to show:** -```` +````javascript moduleA.show(0, {lockString: "module_c_identifier"}); ```` The lockString will be removed from moduleA’s locks array, and since this will result in an empty lock array, the module will be visible: -```` +````javascript moduleA.lockStrings == [] moduleA.hidden == false ```` **Note:** The locking mechanism can be overwritten by using the force tag: -```` +````javascript moduleA.show(0, {force: true}); ```` This will reset the lockstring array, and will show the module. -```` +````javascript moduleA.lockStrings == [] moduleA.hidden == false ```` @@ -475,7 +475,7 @@ A string that defines the minimum version of the MagicMirror framework. If it is **Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. Example: -```` +````javascript requiresVersion: "2.1.0", ```` From 6510de5d299253434b612a86eb747a47bb4c5f28 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 20:22:30 +0200 Subject: [PATCH 054/169] Fix logger issue on electron. --- js/logger.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/js/logger.js b/js/logger.js index 6c07372093..280103abb0 100644 --- a/js/logger.js +++ b/js/logger.js @@ -14,34 +14,34 @@ var Log = (function() { return { info: function() { - console.info.apply(this, arguments); + console.info.apply(console, arguments); }, log: function() { - console.log.apply(this, arguments); + console.log.apply(console, arguments); }, error: function() { - console.error.apply(this, arguments); + console.error.apply(console, arguments); }, warn: function() { - console.warn.apply(this, arguments); + console.warn.apply(console, arguments); }, group: function() { - console.group.apply(this, arguments); + console.group.apply(console, arguments); }, groupCollapsed: function() { - console.groupCollapsed.apply(this, arguments); + console.groupCollapsed.apply(console, arguments); }, groupEnd: function() { console.groupEnd(); }, time: function() { - console.time.apply(this, arguments); + console.time.apply(console, arguments); }, timeEnd: function() { - console.timeEnd.apply(this, arguments); + console.timeEnd.apply(console, arguments); }, timeStamp: function() { - console.timeStamp.apply(this, arguments); + console.timeStamp.apply(console, arguments); } }; })(); From 4a53e4207c125d784fc2c81b868525e88616d856 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Thu, 13 Oct 2016 21:05:48 +0200 Subject: [PATCH 055/169] Small visual change. --- modules/default/currentweather/currentweather.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 587080db23..0662ef6215 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -140,11 +140,15 @@ Module.register("currentweather",{ var humidity = document.createElement("span"); humidity.innerHTML = this.humidity; + var spacer = document.createElement("sup"); + spacer.innerHTML = " "; + var humidityIcon = document.createElement("sup"); humidityIcon.className = "wi wi-humidity humidityIcon"; humidityIcon.innerHTML = " "; small.appendChild(humidity); + small.appendChild(spacer); small.appendChild(humidityIcon); } From 8b004a549aba125e8ef88171f936b267382677d3 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Fri, 14 Oct 2016 14:19:03 +0200 Subject: [PATCH 056/169] Change Newsfeed logging. --- CHANGELOG.md | 3 +-- modules/default/newsfeed/fetcher.js | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e407d8c95..5e3413bbd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,8 +23,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Updated package.json as a result of Snyk security update. - Improve object instantiation to prevent reference errors. - Improve logger. `Log.log()` now accepts multiple arguments. - -### Changed +- Remove extensive logging in newsfeed node helper. - Calendar times are now uniformly capitalized. ## [2.0.5] - 2016-09-20 diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/fetcher.js index ff0a998014..665c5e15d6 100644 --- a/modules/default/newsfeed/fetcher.js +++ b/modules/default/newsfeed/fetcher.js @@ -60,11 +60,11 @@ var Fetcher = function(url, reloadInterval, encoding) { } else { - console.log("Can't parse feed item:"); - console.log(item); - console.log('Title: ' + title); - console.log('Description: ' + description); - console.log('Pubdate: ' + pubdate); + // console.log("Can't parse feed item:"); + // console.log(item); + // console.log('Title: ' + title); + // console.log('Description: ' + description); + // console.log('Pubdate: ' + pubdate); } }); From 5858e862d95b8b1b4b248615d41559c338229dd8 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Fri, 14 Oct 2016 15:23:03 +0200 Subject: [PATCH 057/169] Broadcast calendar eventlist to other modules. --- CHANGELOG.md | 1 + js/class.js | 37 +++---- js/module.js | 14 --- modules/default/calendar/README.md | 8 +- modules/default/calendar/calendar.js | 112 ++++++++++++-------- modules/default/calendar/calendarfetcher.js | 17 ++- 6 files changed, 109 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e3413bbd1..efdd1aac4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. - Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information. - Module API: Option to define the minimumn MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information. +- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/master/modules/default/calendar) for more information. ### Updated - Modified translations for Frysk. diff --git a/js/class.js b/js/class.js index 2b011b29c4..01a92603ee 100644 --- a/js/class.js +++ b/js/class.js @@ -11,24 +11,6 @@ // The base Class implementation (does nothing) this.Class = function() {}; - //Define the clone method for later use. - function cloneObject(obj) { - if (obj === null || typeof obj !== "object") { - return obj; - } - - var temp = obj.constructor(); // give temp the original obj's constructor - for (var key in obj) { - temp[key] = cloneObject(obj[key]); - - if (key === "lockStrings") { - Log.log(key); - } - } - - return temp; - } - // Create a new Class that inherits from this class Class.extend = function(prop) { var _super = this.prototype; @@ -87,5 +69,24 @@ }; })(); +//Define the clone method for later use. +//Helper Method +function cloneObject(obj) { + if (obj === null || typeof obj !== "object") { + return obj; + } + + var temp = obj.constructor(); // give temp the original obj's constructor + for (var key in obj) { + temp[key] = cloneObject(obj[key]); + + if (key === "lockStrings") { + Log.log(key); + } + } + + return temp; +} + /*************** DO NOT EDIT THE LINE BELOW ***************/ if (typeof module !== "undefined") {module.exports = Class;} diff --git a/js/module.js b/js/module.js index 17ca959588..397d479967 100644 --- a/js/module.js +++ b/js/module.js @@ -371,20 +371,6 @@ Module.create = function (name) { return; } - //Define the clone method for later use. - function cloneObject(obj) { - if (obj === null || typeof obj !== "object") { - return obj; - } - - var temp = obj.constructor(); // give temp the original obj's constructor - for (var key in obj) { - temp[key] = cloneObject(obj[key]); - } - - return temp; - } - var moduleDefinition = Module.definitions[name]; var clonedDefinition = cloneObject(moduleDefinition); diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index fc5530953d..54d318ce33 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -106,7 +106,6 @@ The following properties can be configured: titleReplace An object of textual replacements applied to the tile of the event. This allow to remove or replace certains words in the title.

Example:
- titleReplace: {'Birthday of ' : '', 'foo':'bar'} @@ -141,6 +140,13 @@ The following properties can be configured:
Default value: 0 (disabled) + + broadcastEvents + If this property is set to true, the calendar will broadcast all the events to all other modules with the notification message: CALENDAR_EVENTS. The event objects are stored in an array and contain the following fields: title, startDate, endDate, fullDayEvent, location and geo.
+
Possible values: true, false
+
Default value: true + + diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index c2a2c851a7..39ea6b58cd 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -7,7 +7,7 @@ * MIT Licensed. */ -Module.register("calendar",{ +Module.register("calendar", { // Define module defaults defaults: { @@ -16,7 +16,7 @@ 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, @@ -35,20 +35,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 +57,7 @@ Module.register("calendar",{ }, // Override start method. - start: function() { + start: function () { Log.log("Starting module: " + this.name); // Set locale. @@ -73,11 +74,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 +96,7 @@ Module.register("calendar",{ }, // Override dom generator. - getDom: function() { + getDom: function () { var events = this.createEventList(); var wrapper = document.createElement("table"); @@ -110,27 +115,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,24 +143,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.capFirst(this.translate("TODAY")); - } else if (event.startDate - now < one_day && event.startDate - now > 0) { + } else if (event.startDate - now < oneDay && event.startDate - now > 0) { timeWrapper.innerHTML = this.capFirst(this.translate("TOMORROW")); - } else if (event.startDate - now < 2*one_day && event.startDate - now > 0) { - if (this.translate('DAYAFTERTOMORROW') !== 'DAYAFTERTOMORROW') { - timeWrapper.innerHTML = this.capFirst(this.translate("DAYAFTERTOMORROW")); + } 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 = this.capFirst(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 @@ -166,21 +171,21 @@ 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 = this.capFirst(moment(event.startDate, "x").fromNow()); } else { timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format("MMM Do")); } } else { - timeWrapper.innerHTML = this.capFirst(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 < this.config.getRelative * 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 = this.capFirst(moment(event.startDate, "x").fromNow()); } else { @@ -196,7 +201,7 @@ 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 = this.capFirst(moment(event.startDate, "x").fromNow()); } else { @@ -207,7 +212,7 @@ Module.register("calendar",{ } } } else { - timeWrapper.innerHTML = this.capFirst(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'); @@ -241,7 +246,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) { @@ -257,7 +262,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) { @@ -270,7 +275,7 @@ Module.register("calendar",{ } } - events.sort(function(a, b) { + events.sort(function (a, b) { return a.startDate - b.startDate; }); @@ -282,7 +287,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, @@ -300,10 +305,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; } } @@ -317,10 +322,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; } } @@ -337,9 +342,9 @@ 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) + "…"; + return string.slice(0, maxLength) + "…"; } return string; @@ -349,8 +354,8 @@ Module.register("calendar",{ * Capitalize the first letter of a string * Eeturn capitalized string */ - - capFirst: function(string) { + + capFirst: function (string) { return string.charAt(0).toUpperCase() + string.slice(1); }, @@ -363,7 +368,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); @@ -371,5 +376,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); + } }); diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 214e2e5a3e..7f14254676 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -27,7 +27,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe 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 6.0.0) MagicMirror/v2 (https://github.com/MichMich/MagicMirror/)" } }; @@ -77,7 +77,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe if (!isFacebookBirthday) { endDate = startDate; } else { - endDate = moment(startDate).add(1, 'days'); + endDate = moment(startDate).add(1, "days"); } } @@ -101,7 +101,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe 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, @@ -132,12 +132,19 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe continue; } - // Every thing is good. Add it to the list. + + var location = event.location || false; + var geo = event.geo || false; + + // Every thing is good. Add it to the list. + newEvents.push({ title: title, startDate: startDate.format("x"), endDate: endDate.format("x"), - fullDayEvent: fullDayEvent + fullDayEvent: fullDayEvent, + location: location, + geo: geo }); } From 84dc1fa15194a0921925837b2b4229b7c6e1043c Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Fri, 14 Oct 2016 17:42:07 +0200 Subject: [PATCH 058/169] Possibility to use the the calendar feed as the source for the weather. --- CHANGELOG.md | 3 +- js/main.js | 2 +- js/module.js | 2 - modules/default/currentweather/README.md | 21 ++++- .../default/currentweather/currentweather.js | 75 ++++++++++++++---- modules/default/weatherforecast/README.md | 23 ++++-- .../weatherforecast/weatherforecast.js | 76 +++++++++++++++---- 7 files changed, 162 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index efdd1aac4a..bcb7b9b7eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. - Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information. - Module API: Option to define the minimumn MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information. -- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/master/modules/default/calendar) for more information. +- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information. +- Possibility to use the the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information. ### Updated - Modified translations for Frysk. diff --git a/js/main.js b/js/main.js index a8572c6ae9..e97f3e1075 100644 --- a/js/main.js +++ b/js/main.js @@ -179,7 +179,7 @@ var MM = (function() { // set lockString if set in options. if (options.lockString) { - Log.log("Has lockstring: " + options.lockString); + // Log.log("Has lockstring: " + options.lockString); if (module.lockStrings.indexOf(options.lockString) === -1) { module.lockStrings.push(options.lockString); } diff --git a/js/module.js b/js/module.js index 397d479967..4815895e7f 100644 --- a/js/module.js +++ b/js/module.js @@ -337,8 +337,6 @@ var Module = Class.extend({ self.suspend(); callback(); }, options); - - Log.log(options); }, /* showModule(module, speed, callback) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 3df8817390..067dce54f9 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -35,19 +35,20 @@ The following properties can be configured: - location The location used for weather information.
-
Example: Amsterdam,Netherlands -
Default value: New York +
Example: 'Amsterdam,Netherlands' +
Default value: New York

+ Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. locationID Location ID from OpenWeather This will override anything you put in location.
Leave blank if you want to use location.
Example: 1234567 -
Default value: +
Default value:

+ Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. @@ -158,6 +159,18 @@ The following properties can be configured:
Default value: 'weather' + + appendLocationNameToHeader + If set to true, the returned location name will be appended to the header of the module, if the header is enabled. This is mainly intresting when using calender based weather.
+
Default value: true + + + + calendarClass + The class for the calender module to base the event based weather information on.
+
Default value: 'calendar' + + iconTable The conversion table to convert the weather conditions to weather-icons.
diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 0662ef6215..39db3f09a5 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -11,8 +11,8 @@ Module.register("currentweather",{ // Default module config. defaults: { - location: "", - locationID: "", + location: false, + locationID: false, appid: "", units: config.units, updateInterval: 10 * 60 * 1000, // every 10 minutes @@ -32,6 +32,9 @@ Module.register("currentweather",{ apiBase: "http://api.openweathermap.org/data/", weatherEndpoint: "weather", + appendLocationNameToHeader: true, + calendarClass: "calendar", + iconTable: { "01d": "wi-day-sunny", "02d": "wi-day-cloudy", @@ -54,6 +57,12 @@ Module.register("currentweather",{ }, }, + // create a variable for the first upcoming calendaar event. Used if no location is specified. + firstEvent: false, + + // create a variable to hold the location name based on the API result. + fetchedLocatioName: "", + // Define required scripts. getScripts: function() { return ["moment.js"]; @@ -103,12 +112,6 @@ Module.register("currentweather",{ return wrapper; } - if (this.config.location === "") { - wrapper.innerHTML = "Please set the openweather location in the config for module: " + this.name + "."; - wrapper.className = "dimmed light small"; - return wrapper; - } - if (!this.loaded) { wrapper.innerHTML = this.translate('LOADING'); wrapper.className = "dimmed light small"; @@ -178,11 +181,50 @@ Module.register("currentweather",{ return wrapper; }, + // Override getHeader method. + getHeader: function() { + if (this.config.appendLocationNameToHeader) { + return this.data.header + " " + this.fetchedLocatioName; + } + + return this.data.header; + }, + + // Override notification handler. + notificationReceived: function(notification, payload, sender) { + if (notification === "DOM_OBJECTS_CREATED") { + if (this.config.appendLocationNameToHeader) { + this.hide(0, {lockString: this.identifier}); + } + } + if (notification === "CALENDAR_EVENTS") { + var senderClasses = sender.data.classes.toLowerCase().split(" "); + if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) { + var lastEvent = this.firstEvent; + this.firstEvent = false; + + for (e in payload) { + var event = payload[e]; + if (event.location || event.geo) { + this.firstEvent = event; + //Log.log("First upcoming event with location: ", event); + break; + } + } + } + } + }, + /* updateWeather(compliments) * Requests new data from openweather.org. * Calls processWeather on succesfull response. */ updateWeather: function() { + if (this.config.appid === "") { + Log.error("CurrentWeather: APPID not set!"); + return; + } + var url = this.config.apiBase + this.config.apiVersion + "/" + this.config.weatherEndpoint + this.getParams(); var self = this; var retry = true; @@ -194,11 +236,10 @@ Module.register("currentweather",{ if (this.status === 200) { self.processWeather(JSON.parse(this.response)); } else if (this.status === 401) { - self.config.appid = ""; self.updateDom(self.config.animationSpeed); Log.error(self.name + ": Incorrect APPID."); - retry = false; + retry = true; } else { Log.error(self.name + ": Could not load weather."); } @@ -218,11 +259,19 @@ Module.register("currentweather",{ */ getParams: function() { var params = "?"; - if(this.config.locationID !== "") { + if(this.config.locationID !== false) { params += "id=" + this.config.locationID; - } else { + } else if(this.config.location !== false) { params += "q=" + this.config.location; + } else if (this.firstEvent && this.firstEvent.geo) { + params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon + } else if (this.firstEvent && this.firstEvent.location) { + params += "q=" + this.firstEvent.location; + } else { + this.hide(this.config.animationSpeed, {lockString:this.identifier}); + return; } + params += "&units=" + this.config.units; params += "&lang=" + this.config.lang; params += "&APPID=" + this.config.appid; @@ -285,7 +334,7 @@ Module.register("currentweather",{ this.sunriseSunsetIcon = (sunrise < now && sunset > now) ? "wi-sunset" : "wi-sunrise"; - + this.show(this.config.animationSpeed, {lockString:this.identifier}); this.loaded = true; this.updateDom(this.config.animationSpeed); }, diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index aba03a41a8..a1df57c1ea 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -35,19 +35,20 @@ The following properties can be configured: - location The location used for weather information.
-
Example: Amsterdam,Netherlands -
Default value: New York +
Example: 'Amsterdam,Netherlands' +
Default value: New York

+ Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. locationID Location ID from OpenWeather This will override anything you put in location.
Leave blank if you want to use location.
Example: 1234567 -
Default value: +
Default value:

+ Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. @@ -85,7 +86,6 @@ The following properties can be configured:
Default value: 2000 (2 seconds) - lang The language of the days.
@@ -139,6 +139,18 @@ The following properties can be configured:
Default value: 'forecast/daily' + + appendLocationNameToHeader + If set to true, the returned location name will be appended to the header of the module, if the header is enabled. This is mainly intresting when using calender based weather.
+
Default value: true + + + + calendarClass + The class for the calender module to base the event based weather information on.
+
Default value: 'calendar' + + iconTable The conversion table to convert the weather conditions to weather-icons.
@@ -164,6 +176,5 @@ The following properties can be configured: } - diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index a8a8ca6c64..7119f79ede 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -11,8 +11,8 @@ Module.register("weatherforecast",{ // Default module config. defaults: { - location: "", - locationID: "", + location: false, + locationID: false, appid: "", units: config.units, maxNumberOfDays: 7, @@ -30,6 +30,9 @@ Module.register("weatherforecast",{ apiBase: "http://api.openweathermap.org/data/", forecastEndpoint: "forecast/daily", + appendLocationNameToHeader: true, + calendarClass: "calendar", + iconTable: { "01d": "wi-day-sunny", "02d": "wi-day-cloudy", @@ -52,6 +55,12 @@ Module.register("weatherforecast",{ }, }, + // create a variable for the first upcoming calendaar event. Used if no location is specified. + firstEvent: false, + + // create a variable to hold the location name based on the API result. + fetchedLocatioName: "", + // Define required scripts. getScripts: function() { return ["moment.js"]; @@ -95,12 +104,6 @@ Module.register("weatherforecast",{ return wrapper; } - if (this.config.location === "") { - wrapper.innerHTML = "Please set the openweather location in the config for module: " + this.name + "."; - wrapper.className = "dimmed light small"; - return wrapper; - } - if (!this.loaded) { wrapper.innerHTML = this.translate("LOADING"); wrapper.className = "dimmed light small"; @@ -156,11 +159,50 @@ Module.register("weatherforecast",{ return table; }, + // Override getHeader method. + getHeader: function() { + if (this.config.appendLocationNameToHeader) { + return this.data.header + " " + this.fetchedLocatioName; + } + + return this.data.header; + }, + + // Override notification handler. + notificationReceived: function(notification, payload, sender) { + if (notification === "DOM_OBJECTS_CREATED") { + if (this.config.appendLocationNameToHeader) { + this.hide(0, {lockString: this.identifier}); + } + } + if (notification === "CALENDAR_EVENTS") { + var senderClasses = sender.data.classes.toLowerCase().split(" "); + if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) { + var lastEvent = this.firstEvent; + this.firstEvent = false; + + for (e in payload) { + var event = payload[e]; + if (event.location || event.geo) { + this.firstEvent = event; + //Log.log("First upcoming event with location: ", event); + break; + } + } + } + } + }, + /* updateWeather(compliments) * Requests new data from openweather.org. * Calls processWeather on succesfull response. */ updateWeather: function() { + if (this.config.appid === "") { + Log.error("WeatherForecast: APPID not set!"); + return; + } + var url = this.config.apiBase + this.config.apiVersion + "/" + this.config.forecastEndpoint + this.getParams(); var self = this; var retry = true; @@ -172,11 +214,10 @@ Module.register("weatherforecast",{ if (this.status === 200) { self.processWeather(JSON.parse(this.response)); } else if (this.status === 401) { - self.config.appid = ""; self.updateDom(self.config.animationSpeed); Log.error(self.name + ": Incorrect APPID."); - retry = false; + retry = true; } else { Log.error(self.name + ": Could not load weather."); } @@ -196,11 +237,19 @@ Module.register("weatherforecast",{ */ getParams: function() { var params = "?"; - if(this.config.locationID !== "") { + if(this.config.locationID !== false) { params += "id=" + this.config.locationID; - } else { + } else if(this.config.location !== false) { params += "q=" + this.config.location; + } else if (this.firstEvent && this.firstEvent.geo) { + params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon + } else if (this.firstEvent && this.firstEvent.location) { + params += "q=" + this.firstEvent.location; + } else { + this.hide(this.config.animationSpeed, {lockString:this.identifier}); + return; } + params += "&units=" + this.config.units; params += "&lang=" + this.config.lang; /* @@ -220,6 +269,7 @@ Module.register("weatherforecast",{ * argument data object - Weather information received form openweather.org. */ processWeather: function(data) { + this.fetchedLocatioName = data.city.name + ", " + data.city.country; this.forecast = []; for (var i = 0, count = data.list.length; i < count; i++) { @@ -236,7 +286,7 @@ Module.register("weatherforecast",{ } //Log.log(this.forecast); - + this.show(this.config.animationSpeed, {lockString:this.identifier}); this.loaded = true; this.updateDom(this.config.animationSpeed); }, From bd49bd6e33e2da6e6cd3c3dc05c6728813a642e3 Mon Sep 17 00:00:00 2001 From: Joseph Bethge Date: Fri, 14 Oct 2016 23:07:13 +0200 Subject: [PATCH 059/169] option to show rain amount --- modules/default/weatherforecast/README.md | 8 ++++++++ .../default/weatherforecast/weatherforecast.css | 5 +++++ .../default/weatherforecast/weatherforecast.js | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index a1df57c1ea..0d321aa327 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -72,6 +72,14 @@ The following properties can be configured:
This value is optional. By default the weatherforecast module will return 7 days. + + showRainAmount + Should the predicted rain amount be displayed?
+
Possible values: true or false +
Default value: false +
This value is optional. By default the weatherforecast module will not display the predicted amount of rain. + + updateInterval How often does the content needs to be fetched? (Milliseconds)
diff --git a/modules/default/weatherforecast/weatherforecast.css b/modules/default/weatherforecast/weatherforecast.css index 7b12c42d62..62c9767f68 100644 --- a/modules/default/weatherforecast/weatherforecast.css +++ b/modules/default/weatherforecast/weatherforecast.css @@ -12,3 +12,8 @@ padding-left: 20px; padding-right: 0; } + +.weatherforecast .rain { + padding-left: 20px; + padding-right: 0; +} diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index 7119f79ede..7f3ef71d04 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -16,6 +16,7 @@ Module.register("weatherforecast",{ appid: "", units: config.units, maxNumberOfDays: 7, + showRainAmount: false, updateInterval: 10 * 60 * 1000, // every 10 minutes animationSpeed: 1000, timeFormat: config.timeFormat, @@ -142,6 +143,17 @@ Module.register("weatherforecast",{ minTempCell.className = "align-right min-temp"; row.appendChild(minTempCell); + if (this.config.showRainAmount) { + var rainCell = document.createElement("td"); + if (isNaN(forecast.rain)) { + rainCell.innerHTML = ""; + } else { + rainCell.innerHTML = forecast.rain + " mm"; + } + rainCell.className = "align-right bright rain"; + row.appendChild(rainCell); + } + if (this.config.fade && this.config.fadePoint < 1) { if (this.config.fadePoint < 0) { this.config.fadePoint = 0; @@ -280,7 +292,8 @@ Module.register("weatherforecast",{ day: moment(forecast.dt, "X").format("ddd"), icon: this.config.iconTable[forecast.weather[0].icon], maxTemp: this.roundValue(forecast.temp.max), - minTemp: this.roundValue(forecast.temp.min) + minTemp: this.roundValue(forecast.temp.min), + rain: this.roundValue(forecast.rain) }); } From 0cde1d496923329604f4a8a88b84a606409b916b Mon Sep 17 00:00:00 2001 From: Jopyth Date: Fri, 14 Oct 2016 23:13:13 +0200 Subject: [PATCH 060/169] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb7b9b7eb..39902b3821 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Module API: Option to define the minimumn MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information. - Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information. - Possibility to use the the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information. +- Added option to show rain amount in the weatherforecast default module ### Updated - Modified translations for Frysk. From e721d2204bb409951e8f0d9186acdf1bd7304136 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 15 Oct 2016 11:27:34 +0200 Subject: [PATCH 061/169] Fix typo. --- modules/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/README.md b/modules/README.md index 54043b6982..5f2713a6a6 100644 --- a/modules/README.md +++ b/modules/README.md @@ -456,7 +456,7 @@ start: function() { } ```` -**Note: ** By default, a public path to your module's public folder will be created: +**Note:** By default, a public path to your module's public folder will be created: ````javascript this.expressApp.use("/" + this.name, express.static(this.path + "/public")); ```` From a66a4f62bda6a967b016ce94f84c0693dae47f22 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 15 Oct 2016 13:08:46 +0200 Subject: [PATCH 062/169] Add module 'updatenotification'. --- CHANGELOG.md | 1 + config/config.js.sample | 4 ++ js/defaults.js | 4 ++ modules/default/defaultmodules.js | 3 +- modules/default/updatenotification/README.md | 42 ++++++++++++++ .../default/updatenotification/node_helper.js | 45 ++++++++++++++ .../updatenotification/updatenotification.js | 58 +++++++++++++++++++ package.json | 1 + translations/en.json | 6 +- translations/nl.json | 6 +- 10 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 modules/default/updatenotification/README.md create mode 100644 modules/default/updatenotification/node_helper.js create mode 100644 modules/default/updatenotification/updatenotification.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 39902b3821..2d68cd3473 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information. - Possibility to use the the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information. - Added option to show rain amount in the weatherforecast default module +- Add module `updatenotification` to get an update whenever a new version is availabe. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information. ### Updated - Modified translations for Frysk. diff --git a/config/config.js.sample b/config/config.js.sample index e611f872fa..c2607dbf39 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -16,6 +16,10 @@ var config = { { module: 'alert', }, + { + module: "updatenotification", + position: "top_center" + }, { module: 'clock', position: 'top_left' diff --git a/js/defaults.js b/js/defaults.js index 0ec033c378..0f27e81743 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -17,6 +17,10 @@ var defaults = { units: "metric", modules: [ + { + module: "updatenotification", + position: "top_center" + }, { module: "helloworld", position: "upper_third", diff --git a/modules/default/defaultmodules.js b/modules/default/defaultmodules.js index 42e89ee0bd..fccf3c5249 100644 --- a/modules/default/defaultmodules.js +++ b/modules/default/defaultmodules.js @@ -15,7 +15,8 @@ var defaultModules = [ "currentweather", "helloworld", "newsfeed", - "weatherforecast" + "weatherforecast", + "updatenotification" ]; /*************** DO NOT EDIT THE LINE BELOW ***************/ diff --git a/modules/default/updatenotification/README.md b/modules/default/updatenotification/README.md new file mode 100644 index 0000000000..7d839087c2 --- /dev/null +++ b/modules/default/updatenotification/README.md @@ -0,0 +1,42 @@ +# Module: Update Notification +The `updatenotification` module is one of the default modules of the MagicMirror. +This will display a message whenever a new version of the MagicMirror application is available. + +## Using the module + +To use this module, add it to the modules array in the `config/config.js` file: +````javascript +modules: [ + { + module: 'updatenotification', + position: 'top_center', // This can be any of the regions. + config: { + // The config property is optional. + // See 'Configuration options' for more information. + } + } +] +```` + +## Configuration options + +The following properties can be configured: + + + + + + + + + + + + + + + +
OptionDescription
updateIntervalHow often do you want to check for a new version? This value represents the interval in milliseconds.
+
Possible values: Any value above 60000 (1 minute); +
Default value: 600000 (10 minutes); +
\ No newline at end of file diff --git a/modules/default/updatenotification/node_helper.js b/modules/default/updatenotification/node_helper.js new file mode 100644 index 0000000000..d049e34bd2 --- /dev/null +++ b/modules/default/updatenotification/node_helper.js @@ -0,0 +1,45 @@ +var simpleGit = require("simple-git")(__dirname + "/../.."); +var NodeHelper = require("node_helper"); + +module.exports = NodeHelper.create({ + + config: {}, + + updateTimer: null, + + start: function () { + + }, + + socketNotificationReceived: function (notification, payload) { + if (notification === "CONFIG") { + this.config = payload; + this.preformFetch(); + } + }, + + preformFetch() { + var self = this; + simpleGit.fetch().status(function(err, data) { + if (!err) { + self.sendSocketNotification("STATUS", data); + } + }); + + this.scheduleNextFetch(this.config.updateInterval); + }, + + scheduleNextFetch: function(delay) { + if (delay < 60 * 1000) { + delay = 60 * 1000 + } + + console.log(delay); + var self = this; + clearTimeout(this.updateTimer); + this.updateTimer = setTimeout(function() { + self.preformFetch(); + }, delay); + } + +}); \ No newline at end of file diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js new file mode 100644 index 0000000000..6b79e86269 --- /dev/null +++ b/modules/default/updatenotification/updatenotification.js @@ -0,0 +1,58 @@ +Module.register("updatenotification", { + + + + defaults: { + updateInterval: 10 * 60 * 1000, // every 10 minutes + }, + + status: false, + + start: function () { + Log.log("Start updatenotification"); + var self = this; + }, + + notificationReceived: function(notification, payload, sender) { + if (notification === "DOM_OBJECTS_CREATED") { + this.sendSocketNotification("CONFIG", this.config); + } + }, + + socketNotificationReceived: function (notification, payload) { + if (notification === "STATUS") { + this.status = payload; + this.updateDom(1000); + } + }, + + // Override dom generator. + getDom: function () { + var wrapper = document.createElement("div"); + + if (this.status && this.status.behind > 0) { + var message = document.createElement("div"); + message.className = "small bright"; + + var icon = document.createElement("i"); + icon.className = "fa fa-exclamation-circle"; + icon.innerHTML = " "; + message.appendChild(icon); + + var text = document.createElement("span"); + text.innerHTML = this.translate("UPDATE_NOTIFICATION"); + message.appendChild(text); + + wrapper.appendChild(message); + + var subtext = document.createElement("div"); + subtext.innerHTML = this.translate("UPDATE_INFO") + .replace("COMMIT_COUNT", this.status.behind + " " + ((this.status.behind == 1)? 'commit' : 'commits')) + .replace("BRANCH_NAME", this.status.current); + subtext.className = "xsmall dimmed"; + wrapper.appendChild(subtext); + } + + return wrapper; + } +}); diff --git a/package.json b/package.json index 202c3e5981..4d7944e691 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "moment": "latest", "request": "^2.74.0", "rrule": "latest", + "simple-git": "^1.54.0", "snyk": "^1.14.1", "socket.io": "^1.4.6", "valid-url": "latest", diff --git a/translations/en.json b/translations/en.json index a2d5933ad2..e169ba1b82 100644 --- a/translations/en.json +++ b/translations/en.json @@ -24,5 +24,9 @@ "W": "W", "WNW": "WNW", "NW": "NW", - "NNW": "NNW" + "NNW": "NNW", + + /* UPDATE INFO */ + "UPDATE_NOTIFICATION": "MagicMirror² update available.", + "UPDATE_INFO": "The current installation is COMMIT_COUNT behind on the BRANCH_NAME branch." } diff --git a/translations/nl.json b/translations/nl.json index e4e882ea2d..582b62e64b 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -25,5 +25,9 @@ "W": "W", "WNW": "WNW", "NW": "NW", - "NNW": "NNW" + "NNW": "NNW", + + /* UPDATE INFO */ + "UPDATE_NOTIFICATION": "MagicMirror² update beschikbaar.", + "UPDATE_INFO": "De huidige installatie loopt COMMIT_COUNT achter op de BRANCH_NAME branch." } From a419ad201dcb3c731aea814e05db9bf72bb85929 Mon Sep 17 00:00:00 2001 From: fewieden Date: Sat, 15 Oct 2016 13:39:42 +0200 Subject: [PATCH 063/169] added german translation for updatenotification --- translations/de.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/translations/de.json b/translations/de.json index d8a254a9fd..58a4ca1417 100644 --- a/translations/de.json +++ b/translations/de.json @@ -25,5 +25,9 @@ "W": "W", "WNW": "WNW", "NW": "NW", - "NNW": "NNW" + "NNW": "NNW", + + /* UPDATE INFO */ + "UPDATE_NOTIFICATION": "Aktualisierung für MagicMirror² verfügbar.", + "UPDATE_INFO": "Die aktuelle Installation ist COMMIT_COUNT hinter dem BRANCH_NAME branch." } From 6816bd8badfb68037efbede88299d62214c76192 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 15 Oct 2016 17:06:52 +0200 Subject: [PATCH 064/169] Solve margin issue. --- CHANGELOG.md | 3 +++ css/main.css | 8 +++++--- .../updatenotification/updatenotification.js | 13 +++++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d68cd3473..b1b1c8a140 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Remove extensive logging in newsfeed node helper. - Calendar times are now uniformly capitalized. +### Fixed +- Solve an issue where module margins would appear when the first module of a section was hidden. + ## [2.0.5] - 2016-09-20 ### Added diff --git a/css/main.css b/css/main.css index 7ae902d6d9..f2188c66f9 100644 --- a/css/main.css +++ b/css/main.css @@ -113,13 +113,15 @@ sup { */ .module { - margin-top: 30px; + margin-bottom: 30px; } -.module:first-child { - margin-top: 0; +.region.bottom .module { + margin-top: 30px; + margin-bottom: 0px; } + /** * Region Definitions. */ diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js index 6b79e86269..cd2ba42cf5 100644 --- a/modules/default/updatenotification/updatenotification.js +++ b/modules/default/updatenotification/updatenotification.js @@ -10,19 +10,28 @@ Module.register("updatenotification", { start: function () { Log.log("Start updatenotification"); - var self = this; + }, notificationReceived: function(notification, payload, sender) { if (notification === "DOM_OBJECTS_CREATED") { this.sendSocketNotification("CONFIG", this.config); + this.hide(0,{lockString: self.identifier}); } }, socketNotificationReceived: function (notification, payload) { if (notification === "STATUS") { this.status = payload; - this.updateDom(1000); + this.updateUI(); + } + }, + + updateUI: function() { + var self = this; + if (this.status && this.status.behind > 0) { + self.updateDom(0); + self.show(1000, {lockString: self.identifier}); } }, From b9f308c8327b0f0ea659cfad23db1fcacd8bbce2 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 15 Oct 2016 17:11:03 +0200 Subject: [PATCH 065/169] Stylelint fixes --- css/main.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/css/main.css b/css/main.css index f2188c66f9..5e63e59630 100644 --- a/css/main.css +++ b/css/main.css @@ -118,10 +118,9 @@ sup { .region.bottom .module { margin-top: 30px; - margin-bottom: 0px; + margin-bottom: 0; } - /** * Region Definitions. */ From cc10cd88d34e834607dd991d6995809b34c011ea Mon Sep 17 00:00:00 2001 From: Jopyth Date: Sun, 16 Oct 2016 17:24:21 +0200 Subject: [PATCH 066/169] change position from absolute to fixed --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index e97f3e1075..9c489ee08b 100644 --- a/js/main.js +++ b/js/main.js @@ -196,7 +196,7 @@ var MM = (function() { // since it's fade out anyway, we can see it lay above or // below other modules. This works way better than adjusting // the .display property. - moduleWrapper.style.position = "absolute"; + moduleWrapper.style.position = "fixed"; if (typeof callback === "function") { callback(); } }, speed); From ece0d9301f01518aace892d5797e599a307150db Mon Sep 17 00:00:00 2001 From: Jopyth Date: Sun, 16 Oct 2016 17:32:05 +0200 Subject: [PATCH 067/169] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1b1c8a140..8d51f39be4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Solve an issue where module margins would appear when the first module of a section was hidden. +- Solve visual display errors on chrome, if all modules in one of the right sections are hidden ## [2.0.5] - 2016-09-20 From 4d2eedc56bb3da61ccec2e6c292b87b966ba8df0 Mon Sep 17 00:00:00 2001 From: Jopyth Date: Sun, 16 Oct 2016 17:32:17 +0200 Subject: [PATCH 068/169] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d51f39be4..5c9e649a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Solve an issue where module margins would appear when the first module of a section was hidden. -- Solve visual display errors on chrome, if all modules in one of the right sections are hidden +- Solved visual display errors on chrome, if all modules in one of the right sections are hidden ## [2.0.5] - 2016-09-20 From 1b7fe286a657f4dc7f16fe56e48516e24df6793a Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Mon, 17 Oct 2016 17:03:10 +0200 Subject: [PATCH 069/169] remove logging --- modules/default/updatenotification/node_helper.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/default/updatenotification/node_helper.js b/modules/default/updatenotification/node_helper.js index d049e34bd2..862087d8ad 100644 --- a/modules/default/updatenotification/node_helper.js +++ b/modules/default/updatenotification/node_helper.js @@ -34,7 +34,6 @@ module.exports = NodeHelper.create({ delay = 60 * 1000 } - console.log(delay); var self = this; clearTimeout(this.updateTimer); this.updateTimer = setTimeout(function() { @@ -42,4 +41,4 @@ module.exports = NodeHelper.create({ }, delay); } -}); \ No newline at end of file +}); From 2cc9356c321b05d36aafece319b6b7e718d26aa7 Mon Sep 17 00:00:00 2001 From: xander Date: Thu, 20 Oct 2016 09:05:12 +0200 Subject: [PATCH 070/169] Push location, geo and description on events stack for single and repeating events. --- modules/default/calendar/calendarfetcher.js | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 7f14254676..3ca92974f8 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -80,6 +80,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe 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,6 +96,10 @@ 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); @@ -108,7 +113,10 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe startDate: startDate.format("x"), endDate: endDate.format("x"), fullDayEvent: isFullDayEvent(event), - firstYear: event.start.getFullYear() + firstYear: event.start.getFullYear(), + location: location, + geo: geo, + description: description }); } } @@ -132,10 +140,6 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe continue; } - - var location = event.location || false; - var geo = event.geo || false; - // Every thing is good. Add it to the list. newEvents.push({ @@ -143,8 +147,9 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe startDate: startDate.format("x"), endDate: endDate.format("x"), fullDayEvent: fullDayEvent, - location: location, - geo: geo + location: location, + geo: geo, + description: description }); } From 80df01c8ee4a445803278fbc35478e8fbe4c23f0 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 22 Oct 2016 12:04:58 +0200 Subject: [PATCH 071/169] Fix unit for display time. --- modules/default/alert/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/default/alert/README.md b/modules/default/alert/README.md index 5c04848c63..5ddf763902 100644 --- a/modules/default/alert/README.md +++ b/modules/default/alert/README.md @@ -45,9 +45,9 @@ The following properties can be configured: display_time - Time a notification is displayed in seconds.
-
Possible values: float int -
Default value: 3.5 + Time a notification is displayed in milliseconds.
+
Possible values: int +
Default value: 3500 @@ -162,4 +162,4 @@ self.sendNotification("SHOW_ALERT", {}); ## Open Source Licenses ###[NotificationStyles](https://github.com/codrops/NotificationStyles) -See [ympanus.net](http://tympanus.net/codrops/licensing/) for license. \ No newline at end of file +See [ympanus.net](http://tympanus.net/codrops/licensing/) for license. From 95f1382fbfd4b4db0de8c9dcc1bda6dbbb6873fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Mon, 24 Oct 2016 23:53:34 -0300 Subject: [PATCH 072/169] add support to enable set timezone for show in clock module. --- CHANGELOG.md | 1 + modules/default/clock/README.md | 10 +- modules/default/clock/clock.js | 32 +- vendor/moment/moment-timezone.js | 1197 ++++++++++++++++++++++++++++++ vendor/vendor.js | 1 + 5 files changed, 1228 insertions(+), 13 deletions(-) create mode 100644 vendor/moment/moment-timezone.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f95c84fa..1957436d48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added CII Badge (we are compliant with the CII Best Practices) - Add support for doing http basic auth when loading calendars - Add the abilty to turn off and on the date display in the Clock Module +- Add the abilty to set timezone on the date display in the Clock Module ### Fixed - Fix typo in installer. diff --git a/modules/default/clock/README.md b/modules/default/clock/README.md index 6eca1efb3d..76a979d4ba 100644 --- a/modules/default/clock/README.md +++ b/modules/default/clock/README.md @@ -115,5 +115,13 @@ The following properties can be configured:
Default value: top + + timezone + Specific a timezone to show clock.
+
Possible examples values: America/New_York, America/Santiago, Etc/GMT+10 +
Default value: none + + + - \ No newline at end of file + diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js index db41d7e02b..3fc23ad774 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -23,10 +23,11 @@ Module.register("clock",{ analogPlacement: 'bottom', // options: 'top', 'bottom', 'left', 'right' analogShowDate: 'top', // options: false, 'top', or 'bottom' secondsColor: '#888888', + timezone: null, }, // Define required scripts. getScripts: function() { - return ["moment.js"]; + return ["moment.js", "moment-timezone.js"]; }, // Define styles. getStyles: function() { @@ -69,10 +70,14 @@ Module.register("clock",{ // So we need to generate the timestring manually. // See issue: https://github.com/MichMich/MagicMirror/issues/181 var timeString; + var now = moment(); + if (this.config.timezone) { + now.tz(this.config.timezone); + } if (this.config.clockBold === true) { - timeString = moment().format("HH[]mm[]"); + timeString = now.format("HH[]mm[]"); } else { - timeString = moment().format("HH:mm"); + timeString = now.format("HH:mm"); } if (this.config.timeFormat !== 24) { @@ -80,21 +85,21 @@ Module.register("clock",{ // var hours = now.getHours() % 12 || 12; if (this.config.clockBold === true) { //timeString = hours + moment().format("[]mm[]"); - timeString = moment().format("h[]mm[]"); + timeString = now.format("h[]mm[]"); } else { //timeString = hours + moment().format(":mm"); - timeString = moment().format("h:mm"); + timeString = now.format("h:mm"); } } if(this.config.showDate){ - dateWrapper.innerHTML = moment().format("dddd, LL"); + dateWrapper.innerHTML = now.format("dddd, LL"); } timeWrapper.innerHTML = timeString; - secondsWrapper.innerHTML = moment().format("ss"); + secondsWrapper.innerHTML = now.format("ss"); if (this.config.showPeriodUpper) { - periodWrapper.innerHTML = moment().format("A"); + periodWrapper.innerHTML = now.format("A"); } else { - periodWrapper.innerHTML = moment().format("a"); + periodWrapper.innerHTML = now.format("a"); } if (this.config.displaySeconds) { timeWrapper.appendChild(secondsWrapper); @@ -117,8 +122,11 @@ Module.register("clock",{ // If it isn't 'digital', then an 'analog' clock was also requested // Calculate the degree offset for each hand of the clock - var now = moment(), - second = now.seconds() * 6, + var now = moment(); + if (this.config.timezone) { + now.tz(this.config.timezone); + } + var second = now.seconds() * 6, minute = now.minute() * 6 + second / 60, hour = ((now.hours() % 12) / 12) * 360 + 90 + minute / 12; @@ -227,4 +235,4 @@ Module.register("clock",{ // Return the wrapper to the dom. return wrapper; } -}); \ No newline at end of file +}); diff --git a/vendor/moment/moment-timezone.js b/vendor/moment/moment-timezone.js new file mode 100644 index 0000000000..e98675cc61 --- /dev/null +++ b/vendor/moment/moment-timezone.js @@ -0,0 +1,1197 @@ +//! moment-timezone.js +//! version : 0.5.7 +//! author : Tim Wood +//! license : MIT +//! github.com/moment/moment-timezone + +(function (root, factory) { + "use strict"; + + /*global define*/ + if (typeof define === 'function' && define.amd) { + define(['moment'], factory); // AMD + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('moment')); // Node + } else { + factory(root.moment); // Browser + } +}(this, function (moment) { + "use strict"; + + // Do not load moment-timezone a second time. + if (moment.tz !== undefined) { + logError('Moment Timezone ' + moment.tz.version + ' was already loaded ' + (moment.tz.dataVersion ? 'with data from ' : 'without any data') + moment.tz.dataVersion); + return moment; + } + + var VERSION = "0.5.7", + zones = {}, + links = {}, + names = {}, + guesses = {}, + cachedGuess, + + momentVersion = moment.version.split('.'), + major = +momentVersion[0], + minor = +momentVersion[1]; + + // Moment.js version check + if (major < 2 || (major === 2 && minor < 6)) { + logError('Moment Timezone requires Moment.js >= 2.6.0. You are using Moment.js ' + moment.version + '. See momentjs.com'); + } + + /************************************ + Unpacking + ************************************/ + + function charCodeToInt(charCode) { + if (charCode > 96) { + return charCode - 87; + } else if (charCode > 64) { + return charCode - 29; + } + return charCode - 48; + } + + function unpackBase60(string) { + var i = 0, + parts = string.split('.'), + whole = parts[0], + fractional = parts[1] || '', + multiplier = 1, + num, + out = 0, + sign = 1; + + // handle negative numbers + if (string.charCodeAt(0) === 45) { + i = 1; + sign = -1; + } + + // handle digits before the decimal + for (i; i < whole.length; i++) { + num = charCodeToInt(whole.charCodeAt(i)); + out = 60 * out + num; + } + + // handle digits after the decimal + for (i = 0; i < fractional.length; i++) { + multiplier = multiplier / 60; + num = charCodeToInt(fractional.charCodeAt(i)); + out += num * multiplier; + } + + return out * sign; + } + + function arrayToInt (array) { + for (var i = 0; i < array.length; i++) { + array[i] = unpackBase60(array[i]); + } + } + + function intToUntil (array, length) { + for (var i = 0; i < length; i++) { + array[i] = Math.round((array[i - 1] || 0) + (array[i] * 60000)); // minutes to milliseconds + } + + array[length - 1] = Infinity; + } + + function mapIndices (source, indices) { + var out = [], i; + + for (i = 0; i < indices.length; i++) { + out[i] = source[indices[i]]; + } + + return out; + } + + function unpack (string) { + var data = string.split('|'), + offsets = data[2].split(' '), + indices = data[3].split(''), + untils = data[4].split(' '); + + arrayToInt(offsets); + arrayToInt(indices); + arrayToInt(untils); + + intToUntil(untils, indices.length); + + return { + name : data[0], + abbrs : mapIndices(data[1].split(' '), indices), + offsets : mapIndices(offsets, indices), + untils : untils, + population : data[5] | 0 + }; + } + + /************************************ + Zone object + ************************************/ + + function Zone (packedString) { + if (packedString) { + this._set(unpack(packedString)); + } + } + + Zone.prototype = { + _set : function (unpacked) { + this.name = unpacked.name; + this.abbrs = unpacked.abbrs; + this.untils = unpacked.untils; + this.offsets = unpacked.offsets; + this.population = unpacked.population; + }, + + _index : function (timestamp) { + var target = +timestamp, + untils = this.untils, + i; + + for (i = 0; i < untils.length; i++) { + if (target < untils[i]) { + return i; + } + } + }, + + parse : function (timestamp) { + var target = +timestamp, + offsets = this.offsets, + untils = this.untils, + max = untils.length - 1, + offset, offsetNext, offsetPrev, i; + + for (i = 0; i < max; i++) { + offset = offsets[i]; + offsetNext = offsets[i + 1]; + offsetPrev = offsets[i ? i - 1 : i]; + + if (offset < offsetNext && tz.moveAmbiguousForward) { + offset = offsetNext; + } else if (offset > offsetPrev && tz.moveInvalidForward) { + offset = offsetPrev; + } + + if (target < untils[i] - (offset * 60000)) { + return offsets[i]; + } + } + + return offsets[max]; + }, + + abbr : function (mom) { + return this.abbrs[this._index(mom)]; + }, + + offset : function (mom) { + return this.offsets[this._index(mom)]; + } + }; + + /************************************ + Current Timezone + ************************************/ + + function OffsetAt(at) { + var timeString = at.toTimeString(); + var abbr = timeString.match(/\([a-z ]+\)/i); + if (abbr && abbr[0]) { + // 17:56:31 GMT-0600 (CST) + // 17:56:31 GMT-0600 (Central Standard Time) + abbr = abbr[0].match(/[A-Z]/g); + abbr = abbr ? abbr.join('') : undefined; + } else { + // 17:56:31 CST + // 17:56:31 GMT+0800 (台北標準時間) + abbr = timeString.match(/[A-Z]{3,5}/g); + abbr = abbr ? abbr[0] : undefined; + } + + if (abbr === 'GMT') { + abbr = undefined; + } + + this.at = +at; + this.abbr = abbr; + this.offset = at.getTimezoneOffset(); + } + + function ZoneScore(zone) { + this.zone = zone; + this.offsetScore = 0; + this.abbrScore = 0; + } + + ZoneScore.prototype.scoreOffsetAt = function (offsetAt) { + this.offsetScore += Math.abs(this.zone.offset(offsetAt.at) - offsetAt.offset); + if (this.zone.abbr(offsetAt.at).replace(/[^A-Z]/g, '') !== offsetAt.abbr) { + this.abbrScore++; + } + }; + + function findChange(low, high) { + var mid, diff; + + while ((diff = ((high.at - low.at) / 12e4 | 0) * 6e4)) { + mid = new OffsetAt(new Date(low.at + diff)); + if (mid.offset === low.offset) { + low = mid; + } else { + high = mid; + } + } + + return low; + } + + function userOffsets() { + var startYear = new Date().getFullYear() - 2, + last = new OffsetAt(new Date(startYear, 0, 1)), + offsets = [last], + change, next, i; + + for (i = 1; i < 48; i++) { + next = new OffsetAt(new Date(startYear, i, 1)); + if (next.offset !== last.offset) { + change = findChange(last, next); + offsets.push(change); + offsets.push(new OffsetAt(new Date(change.at + 6e4))); + } + last = next; + } + + for (i = 0; i < 4; i++) { + offsets.push(new OffsetAt(new Date(startYear + i, 0, 1))); + offsets.push(new OffsetAt(new Date(startYear + i, 6, 1))); + } + + return offsets; + } + + function sortZoneScores (a, b) { + if (a.offsetScore !== b.offsetScore) { + return a.offsetScore - b.offsetScore; + } + if (a.abbrScore !== b.abbrScore) { + return a.abbrScore - b.abbrScore; + } + return b.zone.population - a.zone.population; + } + + function addToGuesses (name, offsets) { + var i, offset; + arrayToInt(offsets); + for (i = 0; i < offsets.length; i++) { + offset = offsets[i]; + guesses[offset] = guesses[offset] || {}; + guesses[offset][name] = true; + } + } + + function guessesForUserOffsets (offsets) { + var offsetsLength = offsets.length, + filteredGuesses = {}, + out = [], + i, j, guessesOffset; + + for (i = 0; i < offsetsLength; i++) { + guessesOffset = guesses[offsets[i].offset] || {}; + for (j in guessesOffset) { + if (guessesOffset.hasOwnProperty(j)) { + filteredGuesses[j] = true; + } + } + } + + for (i in filteredGuesses) { + if (filteredGuesses.hasOwnProperty(i)) { + out.push(names[i]); + } + } + + return out; + } + + function rebuildGuess () { + + // use Intl API when available and returning valid time zone + try { + var intlName = Intl.DateTimeFormat().resolvedOptions().timeZone; + if (intlName){ + var name = names[normalizeName(intlName)]; + if (name) { + return name; + } + logError("Moment Timezone found " + intlName + " from the Intl api, but did not have that data loaded."); + } + } catch (e) { + // Intl unavailable, fall back to manual guessing. + } + + var offsets = userOffsets(), + offsetsLength = offsets.length, + guesses = guessesForUserOffsets(offsets), + zoneScores = [], + zoneScore, i, j; + + for (i = 0; i < guesses.length; i++) { + zoneScore = new ZoneScore(getZone(guesses[i]), offsetsLength); + for (j = 0; j < offsetsLength; j++) { + zoneScore.scoreOffsetAt(offsets[j]); + } + zoneScores.push(zoneScore); + } + + zoneScores.sort(sortZoneScores); + + return zoneScores.length > 0 ? zoneScores[0].zone.name : undefined; + } + + function guess (ignoreCache) { + if (!cachedGuess || ignoreCache) { + cachedGuess = rebuildGuess(); + } + return cachedGuess; + } + + /************************************ + Global Methods + ************************************/ + + function normalizeName (name) { + return (name || '').toLowerCase().replace(/\//g, '_'); + } + + function addZone (packed) { + var i, name, split, normalized; + + if (typeof packed === "string") { + packed = [packed]; + } + + for (i = 0; i < packed.length; i++) { + split = packed[i].split('|'); + name = split[0]; + normalized = normalizeName(name); + zones[normalized] = packed[i]; + names[normalized] = name; + if (split[5]) { + addToGuesses(normalized, split[2].split(' ')); + } + } + } + + function getZone (name, caller) { + name = normalizeName(name); + + var zone = zones[name]; + var link; + + if (zone instanceof Zone) { + return zone; + } + + if (typeof zone === 'string') { + zone = new Zone(zone); + zones[name] = zone; + return zone; + } + + // Pass getZone to prevent recursion more than 1 level deep + if (links[name] && caller !== getZone && (link = getZone(links[name], getZone))) { + zone = zones[name] = new Zone(); + zone._set(link); + zone.name = names[name]; + return zone; + } + + return null; + } + + function getNames () { + var i, out = []; + + for (i in names) { + if (names.hasOwnProperty(i) && (zones[i] || zones[links[i]]) && names[i]) { + out.push(names[i]); + } + } + + return out.sort(); + } + + function addLink (aliases) { + var i, alias, normal0, normal1; + + if (typeof aliases === "string") { + aliases = [aliases]; + } + + for (i = 0; i < aliases.length; i++) { + alias = aliases[i].split('|'); + + normal0 = normalizeName(alias[0]); + normal1 = normalizeName(alias[1]); + + links[normal0] = normal1; + names[normal0] = alias[0]; + + links[normal1] = normal0; + names[normal1] = alias[1]; + } + } + + function loadData (data) { + addZone(data.zones); + addLink(data.links); + tz.dataVersion = data.version; + } + + function zoneExists (name) { + if (!zoneExists.didShowError) { + zoneExists.didShowError = true; + logError("moment.tz.zoneExists('" + name + "') has been deprecated in favor of !moment.tz.zone('" + name + "')"); + } + return !!getZone(name); + } + + function needsOffset (m) { + return !!(m._a && (m._tzm === undefined)); + } + + function logError (message) { + if (typeof console !== 'undefined' && typeof console.error === 'function') { + console.error(message); + } + } + + /************************************ + moment.tz namespace + ************************************/ + + function tz (input) { + var args = Array.prototype.slice.call(arguments, 0, -1), + name = arguments[arguments.length - 1], + zone = getZone(name), + out = moment.utc.apply(null, args); + + if (zone && !moment.isMoment(input) && needsOffset(out)) { + out.add(zone.parse(out), 'minutes'); + } + + out.tz(name); + + return out; + } + + tz.version = VERSION; + tz.dataVersion = ''; + tz._zones = zones; + tz._links = links; + tz._names = names; + tz.add = addZone; + tz.link = addLink; + tz.load = loadData; + tz.zone = getZone; + tz.zoneExists = zoneExists; // deprecated in 0.1.0 + tz.guess = guess; + tz.names = getNames; + tz.Zone = Zone; + tz.unpack = unpack; + tz.unpackBase60 = unpackBase60; + tz.needsOffset = needsOffset; + tz.moveInvalidForward = true; + tz.moveAmbiguousForward = false; + + /************************************ + Interface with Moment.js + ************************************/ + + var fn = moment.fn; + + moment.tz = tz; + + moment.defaultZone = null; + + moment.updateOffset = function (mom, keepTime) { + var zone = moment.defaultZone, + offset; + + if (mom._z === undefined) { + if (zone && needsOffset(mom) && !mom._isUTC) { + mom._d = moment.utc(mom._a)._d; + mom.utc().add(zone.parse(mom), 'minutes'); + } + mom._z = zone; + } + if (mom._z) { + offset = mom._z.offset(mom); + if (Math.abs(offset) < 16) { + offset = offset / 60; + } + if (mom.utcOffset !== undefined) { + mom.utcOffset(-offset, keepTime); + } else { + mom.zone(offset, keepTime); + } + } + }; + + fn.tz = function (name) { + if (name) { + this._z = getZone(name); + if (this._z) { + moment.updateOffset(this); + } else { + logError("Moment Timezone has no data for " + name + ". See http://momentjs.com/timezone/docs/#/data-loading/."); + } + return this; + } + if (this._z) { return this._z.name; } + }; + + function abbrWrap (old) { + return function () { + if (this._z) { return this._z.abbr(this); } + return old.call(this); + }; + } + + function resetZoneWrap (old) { + return function () { + this._z = null; + return old.apply(this, arguments); + }; + } + + fn.zoneName = abbrWrap(fn.zoneName); + fn.zoneAbbr = abbrWrap(fn.zoneAbbr); + fn.utc = resetZoneWrap(fn.utc); + + moment.tz.setDefault = function(name) { + if (major < 2 || (major === 2 && minor < 9)) { + logError('Moment Timezone setDefault() requires Moment.js >= 2.9.0. You are using Moment.js ' + moment.version + '.'); + } + moment.defaultZone = name ? getZone(name) : null; + return moment; + }; + + // Cloning a moment should include the _z property. + var momentProperties = moment.momentProperties; + if (Object.prototype.toString.call(momentProperties) === '[object Array]') { + // moment 2.8.1+ + momentProperties.push('_z'); + momentProperties.push('_a'); + } else if (momentProperties) { + // moment 2.7.0 + momentProperties._z = null; + } + + loadData({ + "version": "2016h", + "zones": [ + "Africa/Abidjan|GMT|0|0||48e5", + "Africa/Khartoum|EAT|-30|0||51e5", + "Africa/Algiers|CET|-10|0||26e5", + "Africa/Lagos|WAT|-10|0||17e6", + "Africa/Maputo|CAT|-20|0||26e5", + "Africa/Cairo|EET EEST|-20 -30|010101010|1Cby0 Fb0 c10 8n0 8Nd0 gL0 e10 mn0|15e6", + "Africa/Casablanca|WET WEST|0 -10|01010101010101010101010101010101010101010|1Cco0 Db0 1zd0 Lz0 1Nf0 wM0 co0 go0 1o00 s00 dA0 vc0 11A0 A00 e00 y00 11A0 uM0 e00 Dc0 11A0 s00 e00 IM0 WM0 mo0 gM0 LA0 WM0 jA0 e00 Rc0 11A0 e00 e00 U00 11A0 8o0 e00 11A0|32e5", + "Europe/Paris|CET CEST|-10 -20|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|11e6", + "Africa/Johannesburg|SAST|-20|0||84e5", + "Africa/Tripoli|EET CET CEST|-20 -10 -20|0120|1IlA0 TA0 1o00|11e5", + "Africa/Windhoek|WAST WAT|-20 -10|01010101010101010101010|1C1c0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 11B0|32e4", + "America/Adak|HST HDT|a0 90|01010101010101010101010|1BR00 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|326", + "America/Anchorage|AKST AKDT|90 80|01010101010101010101010|1BQX0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|30e4", + "America/Santo_Domingo|AST|40|0||29e5", + "America/Araguaina|BRT BRST|30 20|010|1IdD0 Lz0|14e4", + "America/Argentina/Buenos_Aires|ART|30|0|", + "America/Asuncion|PYST PYT|30 40|01010101010101010101010|1C430 1a10 1fz0 1a10 1fz0 1cN0 17b0 1ip0 17b0 1ip0 17b0 1ip0 19X0 1fB0 19X0 1fB0 19X0 1ip0 17b0 1ip0 17b0 1ip0|28e5", + "America/Panama|EST|50|0||15e5", + "America/Bahia|BRT BRST|30 20|010|1FJf0 Rb0|27e5", + "America/Bahia_Banderas|MST CDT CST|70 50 60|01212121212121212121212|1C1l0 1nW0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0|84e3", + "America/Fortaleza|BRT|30|0||34e5", + "America/Managua|CST|60|0||22e5", + "America/Manaus|AMT|40|0||19e5", + "America/Bogota|COT|50|0||90e5", + "America/Denver|MST MDT|70 60|01010101010101010101010|1BQV0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|26e5", + "America/Campo_Grande|AMST AMT|30 40|01010101010101010101010|1BIr0 1zd0 On0 1zd0 Rb0 1zd0 Lz0 1C10 Lz0 1C10 On0 1zd0 On0 1zd0 On0 1zd0 On0 1C10 Lz0 1C10 Lz0 1C10|77e4", + "America/Cancun|CST CDT EST|60 50 50|010101010102|1C1k0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 Dd0|63e4", + "America/Caracas|VET VET|4u 40|01|1QMT0|29e5", + "America/Cayenne|GFT|30|0||58e3", + "America/Chicago|CST CDT|60 50|01010101010101010101010|1BQU0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|92e5", + "America/Chihuahua|MST MDT|70 60|01010101010101010101010|1C1l0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0|81e4", + "America/Phoenix|MST|70|0||42e5", + "America/Los_Angeles|PST PDT|80 70|01010101010101010101010|1BQW0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|15e6", + "America/New_York|EST EDT|50 40|01010101010101010101010|1BQT0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|21e6", + "America/Rio_Branco|AMT ACT|40 50|01|1KLE0|31e4", + "America/Fort_Nelson|PST PDT MST|80 70 70|010101010102|1BQW0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0|39e2", + "America/Halifax|AST ADT|40 30|01010101010101010101010|1BQS0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|39e4", + "America/Godthab|WGT WGST|30 20|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|17e3", + "America/Goose_Bay|AST ADT|40 30|01010101010101010101010|1BQQ1 1zb0 Op0 1zcX Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|76e2", + "America/Grand_Turk|EST EDT AST|50 40 40|0101010101012|1BQT0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|37e2", + "America/Guayaquil|ECT|50|0||27e5", + "America/Guyana|GYT|40|0||80e4", + "America/Havana|CST CDT|50 40|01010101010101010101010|1BQR0 1wo0 U00 1zc0 U00 1qM0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Rc0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0 Oo0 1zc0|21e5", + "America/La_Paz|BOT|40|0||19e5", + "America/Lima|PET|50|0||11e6", + "America/Mexico_City|CST CDT|60 50|01010101010101010101010|1C1k0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0 14p0 1lb0 14p0 1nX0 11B0 1nX0 11B0 1nX0 14p0 1lb0 14p0 1lb0|20e6", + "America/Metlakatla|PST AKST AKDT|80 90 80|012121212121|1PAa0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|14e2", + "America/Miquelon|PMST PMDT|30 20|01010101010101010101010|1BQR0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|61e2", + "America/Montevideo|UYST UYT|20 30|010101010101|1BQQ0 1ld0 14n0 1ld0 14n0 1o10 11z0 1o10 11z0 1o10 11z0|17e5", + "America/Noronha|FNT|20|0||30e2", + "America/North_Dakota/Beulah|MST MDT CST CDT|70 60 60 50|01232323232323232323232|1BQV0 1zb0 Oo0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0", + "America/Paramaribo|SRT|30|0||24e4", + "America/Port-au-Prince|EST EDT|50 40|010101010|1GI70 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|23e5", + "America/Santiago|CLST CLT|30 40|010101010101010101010|1C1f0 1fB0 1nX0 G10 1EL0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1Nb0 Ap0|62e5", + "America/Sao_Paulo|BRST BRT|20 30|01010101010101010101010|1BIq0 1zd0 On0 1zd0 Rb0 1zd0 Lz0 1C10 Lz0 1C10 On0 1zd0 On0 1zd0 On0 1zd0 On0 1C10 Lz0 1C10 Lz0 1C10|20e6", + "America/Scoresbysund|EGT EGST|10 0|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|452", + "America/St_Johns|NST NDT|3u 2u|01010101010101010101010|1BQPv 1zb0 Op0 1zcX Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Rd0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0 Op0 1zb0|11e4", + "Antarctica/Casey|+11 +08|-b0 -80|0101|1BN30 40P0 KL0|10", + "Antarctica/Davis|+05 +07|-50 -70|0101|1BPw0 3Wn0 KN0|70", + "Antarctica/DumontDUrville|+10|-a0|0||80", + "Antarctica/Macquarie|AEDT MIST|-b0 -b0|01|1C140|1", + "Asia/Tashkent|+05|-50|0||23e5", + "Pacific/Auckland|NZDT NZST|-d0 -c0|01010101010101010101010|1C120 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00|14e5", + "Antarctica/Rothera|-03|30|0||130", + "Antarctica/Syowa|+03|-30|0||20", + "Antarctica/Troll|+00 +02|0 -20|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|40", + "Asia/Almaty|+06|-60|0||15e5", + "Asia/Baghdad|AST|-30|0||66e5", + "Asia/Amman|EET EEST|-20 -30|010101010101010101010|1BVy0 1qM0 11A0 1o00 11A0 4bX0 Dd0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0|25e5", + "Asia/Kamchatka|+12 +11|-c0 -b0|010|1Dp30 WM0|18e4", + "Asia/Baku|+04 +05|-40 -50|0101010101010|1BWo0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00|27e5", + "Asia/Bangkok|ICT|-70|0||15e6", + "Asia/Barnaul|+06 +07|-60 -70|010101|1BWk0 1qM0 WM0 8Hz0 3rd0", + "Asia/Beirut|EET EEST|-20 -30|01010101010101010101010|1BWm0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0|22e5", + "Asia/Brunei|BNT|-80|0||42e4", + "Asia/Kolkata|IST|-5u|0||15e6", + "Asia/Chita|+09 +10 +08|-90 -a0 -80|010120|1BWh0 1qM0 WM0 8Hz0 3re0|33e4", + "Asia/Choibalsan|CHOT CHOST|-80 -90|0101010101010|1O8G0 1cJ0 1cP0 1cJ0 1cP0 1fx0 1cP0 1cJ0 1cP0 1cJ0 1cP0 1cJ0|38e3", + "Asia/Shanghai|CST|-80|0||23e6", + "Asia/Colombo|+0530|-5u|0||22e5", + "Asia/Dhaka|BDT|-60|0||16e6", + "Asia/Damascus|EET EEST|-20 -30|01010101010101010101010|1C0m0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0 WN0 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1nX0 11B0 1qL0|26e5", + "Asia/Dili|TLT|-90|0||19e4", + "Asia/Dubai|GST|-40|0||39e5", + "Asia/Gaza|EET EEST|-20 -30|01010101010101010101010|1BVW1 SKX 1xd1 MKX 1AN0 1a00 1fA0 1cL0 1cN0 1nX0 1210 1nz0 1220 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1qL0|18e5", + "Asia/Hebron|EET EEST|-20 -30|0101010101010101010101010|1BVy0 Tb0 1xd1 MKX bB0 cn0 1cN0 1a00 1fA0 1cL0 1cN0 1nX0 1210 1nz0 1220 1qL0 WN0 1qL0 11B0 1nX0 11B0 1nX0 11B0 1qL0|25e4", + "Asia/Hong_Kong|HKT|-80|0||73e5", + "Asia/Hovd|HOVT HOVST|-70 -80|0101010101010|1O8H0 1cJ0 1cP0 1cJ0 1cP0 1fx0 1cP0 1cJ0 1cP0 1cJ0 1cP0 1cJ0|81e3", + "Asia/Irkutsk|+08 +09|-80 -90|01010|1BWi0 1qM0 WM0 8Hz0|60e4", + "Europe/Istanbul|EET EEST +03|-20 -30 -30|010101010101012|1BWp0 1qM0 Xc0 1qo0 WM0 1qM0 11A0 1o00 1200 1nA0 11A0 1tA0 U00 15w0|13e6", + "Asia/Jakarta|WIB|-70|0||31e6", + "Asia/Jayapura|WIT|-90|0||26e4", + "Asia/Jerusalem|IST IDT|-20 -30|01010101010101010101010|1BVA0 17X0 1kp0 1dz0 1c10 1aL0 1eN0 1oL0 10N0 1oL0 10N0 1oL0 10N0 1rz0 W10 1rz0 W10 1rz0 10N0 1oL0 10N0 1oL0|81e4", + "Asia/Kabul|AFT|-4u|0||46e5", + "Asia/Karachi|PKT|-50|0||24e6", + "Asia/Urumqi|XJT|-60|0||32e5", + "Asia/Kathmandu|NPT|-5J|0||12e5", + "Asia/Khandyga|+10 +11 +09|-a0 -b0 -90|010102|1BWg0 1qM0 WM0 17V0 7zD0|66e2", + "Asia/Krasnoyarsk|+07 +08|-70 -80|01010|1BWj0 1qM0 WM0 8Hz0|10e5", + "Asia/Kuala_Lumpur|MYT|-80|0||71e5", + "Asia/Magadan|+11 +12 +10|-b0 -c0 -a0|010120|1BWf0 1qM0 WM0 8Hz0 3Cq0|95e3", + "Asia/Makassar|WITA|-80|0||15e5", + "Asia/Manila|PHT|-80|0||24e6", + "Europe/Athens|EET EEST|-20 -30|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|35e5", + "Asia/Novokuznetsk|+07 +06|-70 -60|010|1Dp80 WM0|55e4", + "Asia/Novosibirsk|+06 +07|-60 -70|010101|1BWk0 1qM0 WM0 8Hz0 4eN0|15e5", + "Asia/Omsk|+06 +07|-60 -70|01010|1BWk0 1qM0 WM0 8Hz0|12e5", + "Asia/Pyongyang|KST KST|-90 -8u|01|1P4D0|29e5", + "Asia/Rangoon|MMT|-6u|0||48e5", + "Asia/Sakhalin|+10 +11|-a0 -b0|010101|1BWg0 1qM0 WM0 8Hz0 3rd0|58e4", + "Asia/Seoul|KST|-90|0||23e6", + "Asia/Singapore|SGT|-80|0||56e5", + "Asia/Srednekolymsk|+11 +12|-b0 -c0|01010|1BWf0 1qM0 WM0 8Hz0|35e2", + "Asia/Tbilisi|+04|-40|0||11e5", + "Asia/Tehran|IRST IRDT|-3u -4u|01010101010101010101010|1BTUu 1dz0 1cp0 1dz0 1cp0 1dz0 1cN0 1dz0 1cp0 1dz0 1cp0 1dz0 1cp0 1dz0 1cN0 1dz0 1cp0 1dz0 1cp0 1dz0 1cp0 1dz0|14e6", + "Asia/Thimphu|BTT|-60|0||79e3", + "Asia/Tokyo|JST|-90|0||38e6", + "Asia/Tomsk|+06 +07|-60 -70|010101|1BWk0 1qM0 WM0 8Hz0 3Qp0|10e5", + "Asia/Ulaanbaatar|ULAT ULAST|-80 -90|0101010101010|1O8G0 1cJ0 1cP0 1cJ0 1cP0 1fx0 1cP0 1cJ0 1cP0 1cJ0 1cP0 1cJ0|12e5", + "Asia/Ust-Nera|+11 +12 +10|-b0 -c0 -a0|010102|1BWf0 1qM0 WM0 17V0 7zD0|65e2", + "Asia/Vladivostok|+10 +11|-a0 -b0|01010|1BWg0 1qM0 WM0 8Hz0|60e4", + "Asia/Yakutsk|+09 +10|-90 -a0|01010|1BWh0 1qM0 WM0 8Hz0|28e4", + "Asia/Yekaterinburg|+05 +06|-50 -60|01010|1BWl0 1qM0 WM0 8Hz0|14e5", + "Asia/Yerevan|+04 +05|-40 -50|01010|1BWm0 1qM0 WM0 1qM0|13e5", + "Atlantic/Azores|AZOT AZOST|10 0|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|25e4", + "Europe/Lisbon|WET WEST|0 -10|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|27e5", + "Atlantic/Cape_Verde|CVT|10|0||50e4", + "Atlantic/South_Georgia|GST|20|0||30", + "Atlantic/Stanley|FKST FKT|30 40|010|1C6R0 U10|21e2", + "Australia/Sydney|AEDT AEST|-b0 -a0|01010101010101010101010|1C140 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|40e5", + "Australia/Adelaide|ACDT ACST|-au -9u|01010101010101010101010|1C14u 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1cM0 1fA0 1cM0 1cM0 1cM0 1cM0|11e5", + "Australia/Brisbane|AEST|-a0|0||20e5", + "Australia/Darwin|ACST|-9u|0||12e4", + "Australia/Eucla|ACWST|-8J|0||368", + "Australia/Lord_Howe|LHDT LHST|-b0 -au|01010101010101010101010|1C130 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1cMu 1cLu 1fAu 1cLu 1cMu 1cLu 1cMu|347", + "Australia/Perth|AWST|-80|0||18e5", + "Pacific/Easter|EASST EAST|50 60|010101010101010101010|1C1f0 1fB0 1nX0 G10 1EL0 Op0 1zb0 Rd0 1wn0 Rd0 46n0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1Nb0 Ap0 1Nb0 Ap0|30e2", + "Europe/Dublin|GMT IST|0 -10|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|12e5", + "Etc/GMT+1|-01|10|0|", + "Etc/GMT+10|-10|a0|0|", + "Etc/GMT+11|-11|b0|0|", + "Etc/GMT+12|-12|c0|0|", + "Etc/GMT+2|-02|20|0|", + "Etc/GMT+4|-04|40|0|", + "Etc/GMT+5|-05|50|0|", + "Etc/GMT+6|-06|60|0|", + "Etc/GMT+7|-07|70|0|", + "Etc/GMT+8|-08|80|0|", + "Etc/GMT+9|-09|90|0|", + "Etc/GMT-1|+01|-10|0|", + "Etc/GMT-11|+11|-b0|0|", + "Etc/GMT-12|+12|-c0|0|", + "Etc/GMT-13|+13|-d0|0|", + "Etc/GMT-14|+14|-e0|0|", + "Etc/GMT-2|+02|-20|0|", + "Etc/GMT-7|+07|-70|0|", + "Etc/GMT-8|+08|-80|0|", + "Etc/GMT-9|+09|-90|0|", + "Etc/UCT|UCT|0|0|", + "Etc/UTC|UTC|0|0|", + "Europe/Astrakhan|+03 +04|-30 -40|010101|1BWn0 1qM0 WM0 8Hz0 3rd0", + "Europe/London|GMT BST|0 -10|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|10e6", + "Europe/Chisinau|EET EEST|-20 -30|01010101010101010101010|1BWo0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00|67e4", + "Europe/Kaliningrad|EET EEST +03|-20 -30 -30|01020|1BWo0 1qM0 WM0 8Hz0|44e4", + "Europe/Volgograd|+03 +04|-30 -40|01010|1BWn0 1qM0 WM0 8Hz0|10e5", + "Europe/Minsk|EET EEST +03|-20 -30 -30|0102|1BWo0 1qM0 WM0|19e5", + "Europe/Moscow|MSK MSD MSK|-30 -40 -40|01020|1BWn0 1qM0 WM0 8Hz0|16e6", + "Europe/Samara|+04 +03|-40 -30|010|1Dpb0 WM0|12e5", + "Europe/Simferopol|EET EEST MSK MSK|-20 -30 -40 -30|01010101023|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11z0 1nW0|33e4", + "Pacific/Honolulu|HST|a0|0||37e4", + "Indian/Chagos|IOT|-60|0||30e2", + "Indian/Christmas|CXT|-70|0||21e2", + "Indian/Cocos|CCT|-6u|0||596", + "Indian/Mahe|SCT|-40|0||79e3", + "Indian/Maldives|MVT|-50|0||35e4", + "Indian/Mauritius|MUT|-40|0||15e4", + "Indian/Reunion|RET|-40|0||84e4", + "Pacific/Majuro|MHT|-c0|0||28e3", + "MET|MET MEST|-10 -20|01010101010101010101010|1BWp0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00 11A0 1o00 11A0 1qM0 WM0 1qM0 WM0 1qM0 11A0 1o00 11A0 1o00", + "Pacific/Chatham|CHADT CHAST|-dJ -cJ|01010101010101010101010|1C120 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00|600", + "Pacific/Apia|SST SDT WSDT WSST|b0 a0 -e0 -d0|01012323232323232323232|1Dbn0 1ff0 1a00 CI0 AQ0 1cM0 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1a00 1fA0 1cM0 1fA0 1a00 1fA0 1a00|37e3", + "Pacific/Bougainville|PGT BST|-a0 -b0|01|1NwE0|18e4", + "Pacific/Chuuk|CHUT|-a0|0||49e3", + "Pacific/Efate|VUT|-b0|0||66e3", + "Pacific/Enderbury|PHOT|-d0|0||1", + "Pacific/Fakaofo|TKT TKT|b0 -d0|01|1Gfn0|483", + "Pacific/Fiji|FJST FJT|-d0 -c0|01010101010101010101010|1BWe0 1o00 Rc0 1wo0 Ao0 1Nc0 Ao0 1Q00 xz0 1SN0 uM0 1SM0 uM0 1VA0 s00 1VA0 uM0 1SM0 uM0 1SM0 uM0 1SM0|88e4", + "Pacific/Funafuti|TVT|-c0|0||45e2", + "Pacific/Galapagos|GALT|60|0||25e3", + "Pacific/Gambier|GAMT|90|0||125", + "Pacific/Guadalcanal|SBT|-b0|0||11e4", + "Pacific/Guam|ChST|-a0|0||17e4", + "Pacific/Kiritimati|LINT|-e0|0||51e2", + "Pacific/Kosrae|KOST|-b0|0||66e2", + "Pacific/Marquesas|MART|9u|0||86e2", + "Pacific/Pago_Pago|SST|b0|0||37e2", + "Pacific/Nauru|NRT|-c0|0||10e3", + "Pacific/Niue|NUT|b0|0||12e2", + "Pacific/Norfolk|NFT NFT|-bu -b0|01|1PoCu|25e4", + "Pacific/Noumea|NCT|-b0|0||98e3", + "Pacific/Palau|PWT|-90|0||21e3", + "Pacific/Pitcairn|PST|80|0||56", + "Pacific/Pohnpei|PONT|-b0|0||34e3", + "Pacific/Port_Moresby|PGT|-a0|0||25e4", + "Pacific/Rarotonga|CKT|a0|0||13e3", + "Pacific/Tahiti|TAHT|a0|0||18e4", + "Pacific/Tarawa|GILT|-c0|0||29e3", + "Pacific/Tongatapu|TOT|-d0|0||75e3", + "Pacific/Wake|WAKT|-c0|0||16e3", + "Pacific/Wallis|WFT|-c0|0||94" + ], + "links": [ + "Africa/Abidjan|Africa/Accra", + "Africa/Abidjan|Africa/Bamako", + "Africa/Abidjan|Africa/Banjul", + "Africa/Abidjan|Africa/Bissau", + "Africa/Abidjan|Africa/Conakry", + "Africa/Abidjan|Africa/Dakar", + "Africa/Abidjan|Africa/Freetown", + "Africa/Abidjan|Africa/Lome", + "Africa/Abidjan|Africa/Monrovia", + "Africa/Abidjan|Africa/Nouakchott", + "Africa/Abidjan|Africa/Ouagadougou", + "Africa/Abidjan|Africa/Sao_Tome", + "Africa/Abidjan|Africa/Timbuktu", + "Africa/Abidjan|America/Danmarkshavn", + "Africa/Abidjan|Atlantic/Reykjavik", + "Africa/Abidjan|Atlantic/St_Helena", + "Africa/Abidjan|Etc/GMT", + "Africa/Abidjan|Etc/GMT+0", + "Africa/Abidjan|Etc/GMT-0", + "Africa/Abidjan|Etc/GMT0", + "Africa/Abidjan|Etc/Greenwich", + "Africa/Abidjan|GMT", + "Africa/Abidjan|GMT+0", + "Africa/Abidjan|GMT-0", + "Africa/Abidjan|GMT0", + "Africa/Abidjan|Greenwich", + "Africa/Abidjan|Iceland", + "Africa/Algiers|Africa/Tunis", + "Africa/Cairo|Egypt", + "Africa/Casablanca|Africa/El_Aaiun", + "Africa/Johannesburg|Africa/Maseru", + "Africa/Johannesburg|Africa/Mbabane", + "Africa/Khartoum|Africa/Addis_Ababa", + "Africa/Khartoum|Africa/Asmara", + "Africa/Khartoum|Africa/Asmera", + "Africa/Khartoum|Africa/Dar_es_Salaam", + "Africa/Khartoum|Africa/Djibouti", + "Africa/Khartoum|Africa/Juba", + "Africa/Khartoum|Africa/Kampala", + "Africa/Khartoum|Africa/Mogadishu", + "Africa/Khartoum|Africa/Nairobi", + "Africa/Khartoum|Indian/Antananarivo", + "Africa/Khartoum|Indian/Comoro", + "Africa/Khartoum|Indian/Mayotte", + "Africa/Lagos|Africa/Bangui", + "Africa/Lagos|Africa/Brazzaville", + "Africa/Lagos|Africa/Douala", + "Africa/Lagos|Africa/Kinshasa", + "Africa/Lagos|Africa/Libreville", + "Africa/Lagos|Africa/Luanda", + "Africa/Lagos|Africa/Malabo", + "Africa/Lagos|Africa/Ndjamena", + "Africa/Lagos|Africa/Niamey", + "Africa/Lagos|Africa/Porto-Novo", + "Africa/Maputo|Africa/Blantyre", + "Africa/Maputo|Africa/Bujumbura", + "Africa/Maputo|Africa/Gaborone", + "Africa/Maputo|Africa/Harare", + "Africa/Maputo|Africa/Kigali", + "Africa/Maputo|Africa/Lubumbashi", + "Africa/Maputo|Africa/Lusaka", + "Africa/Tripoli|Libya", + "America/Adak|America/Atka", + "America/Adak|US/Aleutian", + "America/Anchorage|America/Juneau", + "America/Anchorage|America/Nome", + "America/Anchorage|America/Sitka", + "America/Anchorage|America/Yakutat", + "America/Anchorage|US/Alaska", + "America/Argentina/Buenos_Aires|America/Argentina/Catamarca", + "America/Argentina/Buenos_Aires|America/Argentina/ComodRivadavia", + "America/Argentina/Buenos_Aires|America/Argentina/Cordoba", + "America/Argentina/Buenos_Aires|America/Argentina/Jujuy", + "America/Argentina/Buenos_Aires|America/Argentina/La_Rioja", + "America/Argentina/Buenos_Aires|America/Argentina/Mendoza", + "America/Argentina/Buenos_Aires|America/Argentina/Rio_Gallegos", + "America/Argentina/Buenos_Aires|America/Argentina/Salta", + "America/Argentina/Buenos_Aires|America/Argentina/San_Juan", + "America/Argentina/Buenos_Aires|America/Argentina/San_Luis", + "America/Argentina/Buenos_Aires|America/Argentina/Tucuman", + "America/Argentina/Buenos_Aires|America/Argentina/Ushuaia", + "America/Argentina/Buenos_Aires|America/Buenos_Aires", + "America/Argentina/Buenos_Aires|America/Catamarca", + "America/Argentina/Buenos_Aires|America/Cordoba", + "America/Argentina/Buenos_Aires|America/Jujuy", + "America/Argentina/Buenos_Aires|America/Mendoza", + "America/Argentina/Buenos_Aires|America/Rosario", + "America/Campo_Grande|America/Cuiaba", + "America/Chicago|America/Indiana/Knox", + "America/Chicago|America/Indiana/Tell_City", + "America/Chicago|America/Knox_IN", + "America/Chicago|America/Matamoros", + "America/Chicago|America/Menominee", + "America/Chicago|America/North_Dakota/Center", + "America/Chicago|America/North_Dakota/New_Salem", + "America/Chicago|America/Rainy_River", + "America/Chicago|America/Rankin_Inlet", + "America/Chicago|America/Resolute", + "America/Chicago|America/Winnipeg", + "America/Chicago|CST6CDT", + "America/Chicago|Canada/Central", + "America/Chicago|US/Central", + "America/Chicago|US/Indiana-Starke", + "America/Chihuahua|America/Mazatlan", + "America/Chihuahua|Mexico/BajaSur", + "America/Denver|America/Boise", + "America/Denver|America/Cambridge_Bay", + "America/Denver|America/Edmonton", + "America/Denver|America/Inuvik", + "America/Denver|America/Ojinaga", + "America/Denver|America/Shiprock", + "America/Denver|America/Yellowknife", + "America/Denver|Canada/Mountain", + "America/Denver|MST7MDT", + "America/Denver|Navajo", + "America/Denver|US/Mountain", + "America/Fortaleza|America/Belem", + "America/Fortaleza|America/Maceio", + "America/Fortaleza|America/Recife", + "America/Fortaleza|America/Santarem", + "America/Halifax|America/Glace_Bay", + "America/Halifax|America/Moncton", + "America/Halifax|America/Thule", + "America/Halifax|Atlantic/Bermuda", + "America/Halifax|Canada/Atlantic", + "America/Havana|Cuba", + "America/Los_Angeles|America/Dawson", + "America/Los_Angeles|America/Ensenada", + "America/Los_Angeles|America/Santa_Isabel", + "America/Los_Angeles|America/Tijuana", + "America/Los_Angeles|America/Vancouver", + "America/Los_Angeles|America/Whitehorse", + "America/Los_Angeles|Canada/Pacific", + "America/Los_Angeles|Canada/Yukon", + "America/Los_Angeles|Mexico/BajaNorte", + "America/Los_Angeles|PST8PDT", + "America/Los_Angeles|US/Pacific", + "America/Los_Angeles|US/Pacific-New", + "America/Managua|America/Belize", + "America/Managua|America/Costa_Rica", + "America/Managua|America/El_Salvador", + "America/Managua|America/Guatemala", + "America/Managua|America/Regina", + "America/Managua|America/Swift_Current", + "America/Managua|America/Tegucigalpa", + "America/Managua|Canada/East-Saskatchewan", + "America/Managua|Canada/Saskatchewan", + "America/Manaus|America/Boa_Vista", + "America/Manaus|America/Porto_Velho", + "America/Manaus|Brazil/West", + "America/Mexico_City|America/Merida", + "America/Mexico_City|America/Monterrey", + "America/Mexico_City|Mexico/General", + "America/New_York|America/Detroit", + "America/New_York|America/Fort_Wayne", + "America/New_York|America/Indiana/Indianapolis", + "America/New_York|America/Indiana/Marengo", + "America/New_York|America/Indiana/Petersburg", + "America/New_York|America/Indiana/Vevay", + "America/New_York|America/Indiana/Vincennes", + "America/New_York|America/Indiana/Winamac", + "America/New_York|America/Indianapolis", + "America/New_York|America/Iqaluit", + "America/New_York|America/Kentucky/Louisville", + "America/New_York|America/Kentucky/Monticello", + "America/New_York|America/Louisville", + "America/New_York|America/Montreal", + "America/New_York|America/Nassau", + "America/New_York|America/Nipigon", + "America/New_York|America/Pangnirtung", + "America/New_York|America/Thunder_Bay", + "America/New_York|America/Toronto", + "America/New_York|Canada/Eastern", + "America/New_York|EST5EDT", + "America/New_York|US/East-Indiana", + "America/New_York|US/Eastern", + "America/New_York|US/Michigan", + "America/Noronha|Brazil/DeNoronha", + "America/Panama|America/Atikokan", + "America/Panama|America/Cayman", + "America/Panama|America/Coral_Harbour", + "America/Panama|America/Jamaica", + "America/Panama|EST", + "America/Panama|Jamaica", + "America/Phoenix|America/Creston", + "America/Phoenix|America/Dawson_Creek", + "America/Phoenix|America/Hermosillo", + "America/Phoenix|MST", + "America/Phoenix|US/Arizona", + "America/Rio_Branco|America/Eirunepe", + "America/Rio_Branco|America/Porto_Acre", + "America/Rio_Branco|Brazil/Acre", + "America/Santiago|Antarctica/Palmer", + "America/Santiago|Chile/Continental", + "America/Santo_Domingo|America/Anguilla", + "America/Santo_Domingo|America/Antigua", + "America/Santo_Domingo|America/Aruba", + "America/Santo_Domingo|America/Barbados", + "America/Santo_Domingo|America/Blanc-Sablon", + "America/Santo_Domingo|America/Curacao", + "America/Santo_Domingo|America/Dominica", + "America/Santo_Domingo|America/Grenada", + "America/Santo_Domingo|America/Guadeloupe", + "America/Santo_Domingo|America/Kralendijk", + "America/Santo_Domingo|America/Lower_Princes", + "America/Santo_Domingo|America/Marigot", + "America/Santo_Domingo|America/Martinique", + "America/Santo_Domingo|America/Montserrat", + "America/Santo_Domingo|America/Port_of_Spain", + "America/Santo_Domingo|America/Puerto_Rico", + "America/Santo_Domingo|America/St_Barthelemy", + "America/Santo_Domingo|America/St_Kitts", + "America/Santo_Domingo|America/St_Lucia", + "America/Santo_Domingo|America/St_Thomas", + "America/Santo_Domingo|America/St_Vincent", + "America/Santo_Domingo|America/Tortola", + "America/Santo_Domingo|America/Virgin", + "America/Sao_Paulo|Brazil/East", + "America/St_Johns|Canada/Newfoundland", + "Antarctica/DumontDUrville|Etc/GMT-10", + "Antarctica/Rothera|Etc/GMT+3", + "Antarctica/Syowa|Etc/GMT-3", + "Asia/Almaty|Antarctica/Vostok", + "Asia/Almaty|Asia/Bishkek", + "Asia/Almaty|Asia/Qyzylorda", + "Asia/Almaty|Etc/GMT-6", + "Asia/Baghdad|Asia/Aden", + "Asia/Baghdad|Asia/Bahrain", + "Asia/Baghdad|Asia/Kuwait", + "Asia/Baghdad|Asia/Qatar", + "Asia/Baghdad|Asia/Riyadh", + "Asia/Bangkok|Asia/Ho_Chi_Minh", + "Asia/Bangkok|Asia/Phnom_Penh", + "Asia/Bangkok|Asia/Saigon", + "Asia/Bangkok|Asia/Vientiane", + "Asia/Dhaka|Asia/Dacca", + "Asia/Dubai|Asia/Muscat", + "Asia/Hong_Kong|Hongkong", + "Asia/Jakarta|Asia/Pontianak", + "Asia/Jerusalem|Asia/Tel_Aviv", + "Asia/Jerusalem|Israel", + "Asia/Kamchatka|Asia/Anadyr", + "Asia/Kathmandu|Asia/Katmandu", + "Asia/Kolkata|Asia/Calcutta", + "Asia/Kuala_Lumpur|Asia/Kuching", + "Asia/Makassar|Asia/Ujung_Pandang", + "Asia/Rangoon|Asia/Yangon", + "Asia/Seoul|ROK", + "Asia/Shanghai|Asia/Chongqing", + "Asia/Shanghai|Asia/Chungking", + "Asia/Shanghai|Asia/Harbin", + "Asia/Shanghai|Asia/Macao", + "Asia/Shanghai|Asia/Macau", + "Asia/Shanghai|Asia/Taipei", + "Asia/Shanghai|PRC", + "Asia/Shanghai|ROC", + "Asia/Singapore|Singapore", + "Asia/Tashkent|Antarctica/Mawson", + "Asia/Tashkent|Asia/Aqtau", + "Asia/Tashkent|Asia/Aqtobe", + "Asia/Tashkent|Asia/Ashgabat", + "Asia/Tashkent|Asia/Ashkhabad", + "Asia/Tashkent|Asia/Dushanbe", + "Asia/Tashkent|Asia/Oral", + "Asia/Tashkent|Asia/Samarkand", + "Asia/Tashkent|Etc/GMT-5", + "Asia/Tashkent|Indian/Kerguelen", + "Asia/Tbilisi|Etc/GMT-4", + "Asia/Tehran|Iran", + "Asia/Thimphu|Asia/Thimbu", + "Asia/Tokyo|Japan", + "Asia/Ulaanbaatar|Asia/Ulan_Bator", + "Asia/Urumqi|Asia/Kashgar", + "Australia/Adelaide|Australia/Broken_Hill", + "Australia/Adelaide|Australia/South", + "Australia/Adelaide|Australia/Yancowinna", + "Australia/Brisbane|Australia/Lindeman", + "Australia/Brisbane|Australia/Queensland", + "Australia/Darwin|Australia/North", + "Australia/Lord_Howe|Australia/LHI", + "Australia/Perth|Australia/West", + "Australia/Sydney|Australia/ACT", + "Australia/Sydney|Australia/Canberra", + "Australia/Sydney|Australia/Currie", + "Australia/Sydney|Australia/Hobart", + "Australia/Sydney|Australia/Melbourne", + "Australia/Sydney|Australia/NSW", + "Australia/Sydney|Australia/Tasmania", + "Australia/Sydney|Australia/Victoria", + "Etc/UCT|UCT", + "Etc/UTC|Etc/Universal", + "Etc/UTC|Etc/Zulu", + "Etc/UTC|UTC", + "Etc/UTC|Universal", + "Etc/UTC|Zulu", + "Europe/Astrakhan|Europe/Ulyanovsk", + "Europe/Athens|Asia/Nicosia", + "Europe/Athens|EET", + "Europe/Athens|Europe/Bucharest", + "Europe/Athens|Europe/Helsinki", + "Europe/Athens|Europe/Kiev", + "Europe/Athens|Europe/Mariehamn", + "Europe/Athens|Europe/Nicosia", + "Europe/Athens|Europe/Riga", + "Europe/Athens|Europe/Sofia", + "Europe/Athens|Europe/Tallinn", + "Europe/Athens|Europe/Uzhgorod", + "Europe/Athens|Europe/Vilnius", + "Europe/Athens|Europe/Zaporozhye", + "Europe/Chisinau|Europe/Tiraspol", + "Europe/Dublin|Eire", + "Europe/Istanbul|Asia/Istanbul", + "Europe/Istanbul|Turkey", + "Europe/Lisbon|Atlantic/Canary", + "Europe/Lisbon|Atlantic/Faeroe", + "Europe/Lisbon|Atlantic/Faroe", + "Europe/Lisbon|Atlantic/Madeira", + "Europe/Lisbon|Portugal", + "Europe/Lisbon|WET", + "Europe/London|Europe/Belfast", + "Europe/London|Europe/Guernsey", + "Europe/London|Europe/Isle_of_Man", + "Europe/London|Europe/Jersey", + "Europe/London|GB", + "Europe/London|GB-Eire", + "Europe/Moscow|W-SU", + "Europe/Paris|Africa/Ceuta", + "Europe/Paris|Arctic/Longyearbyen", + "Europe/Paris|Atlantic/Jan_Mayen", + "Europe/Paris|CET", + "Europe/Paris|Europe/Amsterdam", + "Europe/Paris|Europe/Andorra", + "Europe/Paris|Europe/Belgrade", + "Europe/Paris|Europe/Berlin", + "Europe/Paris|Europe/Bratislava", + "Europe/Paris|Europe/Brussels", + "Europe/Paris|Europe/Budapest", + "Europe/Paris|Europe/Busingen", + "Europe/Paris|Europe/Copenhagen", + "Europe/Paris|Europe/Gibraltar", + "Europe/Paris|Europe/Ljubljana", + "Europe/Paris|Europe/Luxembourg", + "Europe/Paris|Europe/Madrid", + "Europe/Paris|Europe/Malta", + "Europe/Paris|Europe/Monaco", + "Europe/Paris|Europe/Oslo", + "Europe/Paris|Europe/Podgorica", + "Europe/Paris|Europe/Prague", + "Europe/Paris|Europe/Rome", + "Europe/Paris|Europe/San_Marino", + "Europe/Paris|Europe/Sarajevo", + "Europe/Paris|Europe/Skopje", + "Europe/Paris|Europe/Stockholm", + "Europe/Paris|Europe/Tirane", + "Europe/Paris|Europe/Vaduz", + "Europe/Paris|Europe/Vatican", + "Europe/Paris|Europe/Vienna", + "Europe/Paris|Europe/Warsaw", + "Europe/Paris|Europe/Zagreb", + "Europe/Paris|Europe/Zurich", + "Europe/Paris|Poland", + "Europe/Volgograd|Europe/Kirov", + "Pacific/Auckland|Antarctica/McMurdo", + "Pacific/Auckland|Antarctica/South_Pole", + "Pacific/Auckland|NZ", + "Pacific/Chatham|NZ-CHAT", + "Pacific/Chuuk|Pacific/Truk", + "Pacific/Chuuk|Pacific/Yap", + "Pacific/Easter|Chile/EasterIsland", + "Pacific/Guam|Pacific/Saipan", + "Pacific/Honolulu|HST", + "Pacific/Honolulu|Pacific/Johnston", + "Pacific/Honolulu|US/Hawaii", + "Pacific/Majuro|Kwajalein", + "Pacific/Majuro|Pacific/Kwajalein", + "Pacific/Pago_Pago|Pacific/Midway", + "Pacific/Pago_Pago|Pacific/Samoa", + "Pacific/Pago_Pago|US/Samoa", + "Pacific/Pohnpei|Pacific/Ponape" + ] + }); + + + return moment; +})); diff --git a/vendor/vendor.js b/vendor/vendor.js index e21ae50268..bc43731106 100644 --- a/vendor/vendor.js +++ b/vendor/vendor.js @@ -9,6 +9,7 @@ var vendor = { 'moment.js' : 'moment/moment-with-locales.js', + 'moment-timezone.js' : 'moment/moment-timezone.js', 'weather-icons.css': 'weather-icons/css/weather-icons.css', 'weather-icons-wind.css': 'weather-icons/css/weather-icons-wind.css', 'font-awesome.css': 'font-awesome-4.5.0/css/font-awesome.min.css' From 8ea955fb231957358f7e937e54aac1ac885036af Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 25 Oct 2016 12:24:01 +0200 Subject: [PATCH 073/169] Fix type. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4d7944e691..632742db77 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "modular" ], "author": "Michael Teeuw", - "contributors": "https://github.com/MichMich/MagicMirror/graphs/contributors", + "contributors": ["https://github.com/MichMich/MagicMirror/graphs/contributors"], "license": "MIT", "bugs": { "url": "https://github.com/MichMich/MagicMirror/issues" From 89c0939d5882d200c0332ef5e756bac859f0aca1 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 25 Oct 2016 12:30:24 +0200 Subject: [PATCH 074/169] Fix needs update check. --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 9c489ee08b..984df4fd55 100644 --- a/js/main.js +++ b/js/main.js @@ -136,7 +136,7 @@ var MM = (function() { var contentNeedsUpdate = false; if (headerWrapper.length > 0) { - headerNeedsUpdate = newHeader !== headerWrapper.innerHTML; + headerNeedsUpdate = newHeader !== headerWrapper[0].innerHTML; } var tempContentWrapper = document.createElement("div"); From 5c125ca9b4026309a91ef39230b8db0ae2df8645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 25 Oct 2016 16:14:59 -0300 Subject: [PATCH 075/169] Fix position note for add the feature into Pull Request #479 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3dee05e33..263cc19ffd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Possibility to use the the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information. - Added option to show rain amount in the weatherforecast default module - Add module `updatenotification` to get an update whenever a new version is availabe. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information. +- Add the abilty to set timezone on the date display in the Clock Module ### Updated - Modified translations for Frysk. @@ -42,7 +43,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added CII Badge (we are compliant with the CII Best Practices) - Add support for doing http basic auth when loading calendars - Add the abilty to turn off and on the date display in the Clock Module -- Add the abilty to set timezone on the date display in the Clock Module ### Fixed - Fix typo in installer. From 2f6e650c1bf3f9a84771725cbc73d9bf95afb5e0 Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Wed, 26 Oct 2016 18:59:56 +0000 Subject: [PATCH 076/169] currentweather, weatherforecast: fix locationID empty Fix when the option locationID the value = '' If you have the next config config: { // See 'Configuration options' for more information. location: 'Chillan, Chile', locationID: '', appid: 'abcde12345abcde12345abcde12345ab' } The modules dont get the data, because the parameters of query is created in id='' --- modules/default/currentweather/currentweather.js | 4 ++-- modules/default/weatherforecast/weatherforecast.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 39db3f09a5..bc7ccbb7a2 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -259,9 +259,9 @@ Module.register("currentweather",{ */ getParams: function() { var params = "?"; - if(this.config.locationID !== false) { + if(this.config.locationID) { params += "id=" + this.config.locationID; - } else if(this.config.location !== false) { + } else if(this.config.location) { params += "q=" + this.config.location; } else if (this.firstEvent && this.firstEvent.geo) { params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index 7f3ef71d04..51c3f56ea1 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -249,9 +249,9 @@ Module.register("weatherforecast",{ */ getParams: function() { var params = "?"; - if(this.config.locationID !== false) { + if(this.config.locationID) { params += "id=" + this.config.locationID; - } else if(this.config.location !== false) { + } else if(this.config.location) { params += "q=" + this.config.location; } else if (this.firstEvent && this.firstEvent.geo) { params += "lat=" + this.firstEvent.geo.lat + "&lon=" + this.firstEvent.geo.lon From cd146cf822b8b5ab413451d912819bc43d0b199a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 27 Oct 2016 11:12:15 -0300 Subject: [PATCH 077/169] README Fix updateInterval for currentweather, weatherforecast: Fix milliseconds in the example for the updateInterval option --- modules/default/currentweather/README.md | 2 +- modules/default/weatherforecast/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 067dce54f9..84d4e2c5be 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -68,7 +68,7 @@ The following properties can be configured: updateInterval How often does the content needs to be fetched? (Milliseconds)

Possible values: 1000 - 86400000 -
Default value: 300000 (10 minutes) +
Default value: 600000 (10 minutes) diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index 0d321aa327..df89ffe93b 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -84,7 +84,7 @@ The following properties can be configured: updateInterval How often does the content needs to be fetched? (Milliseconds)

Possible values: 1000 - 86400000 -
Default value: 300000 (10 minutes) +
Default value: 600000 (10 minutes) From f26e43144ee54876b036982f32379beede28f517 Mon Sep 17 00:00:00 2001 From: Doug Shamoo Date: Sat, 29 Oct 2016 12:27:34 -0700 Subject: [PATCH 078/169] Fix typo in README --- modules/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/README.md b/modules/README.md index 5f2713a6a6..7884e4323e 100644 --- a/modules/README.md +++ b/modules/README.md @@ -186,7 +186,7 @@ Whenever the MagicMirror needs to update the information on screen (because it s If you want to use the original user's configured header, reference `this.data.header`. -**NOTE:** If the user did not confiugure a default header, no header will be displayed and thus this method will not be called. +**NOTE:** If the user did not configure a default header, no header will be displayed and thus this method will not be called. **Example:** ````javascript From 6fd0fcfdb527d9c0d8902a8d9e8333561673e058 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 31 Oct 2016 20:10:52 +0100 Subject: [PATCH 079/169] Update module.js --- js/module.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/module.js b/js/module.js index 4815895e7f..37d3f14544 100644 --- a/js/module.js +++ b/js/module.js @@ -166,7 +166,7 @@ var Module = Class.extend({ * argument config obejct - Module config. */ setConfig: function (config) { - this.config = Object.assign(this.defaults, config); + this.config = Object.assign({}, this.defaults, config); }, /* socket() From e7493c38d1234f29043c476bcad3c26256adf146 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 31 Oct 2016 20:16:55 +0100 Subject: [PATCH 080/169] Update CHANGELOG.md --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3dee05e33..709bc1f67e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Solve an issue where module margins would appear when the first module of a section was hidden. -- Solved visual display errors on chrome, if all modules in one of the right sections are hidden +- Solved visual display errors on chrome, if all modules in one of the right sections are hidden. +- Module default config values are no longer modified when setting config values. ## [2.0.5] - 2016-09-20 From c9f201755ea5077248fba23ea891e32457ac441d Mon Sep 17 00:00:00 2001 From: Onur Yilmaz Date: Wed, 2 Nov 2016 22:01:14 +0000 Subject: [PATCH 081/169] Turkish translation added --- translations/tr.json | 26 ++++++++++++++++++++++++++ translations/translations.js | 1 + 2 files changed, 27 insertions(+) create mode 100644 translations/tr.json diff --git a/translations/tr.json b/translations/tr.json new file mode 100644 index 0000000000..9a488bf82e --- /dev/null +++ b/translations/tr.json @@ -0,0 +1,26 @@ +{ + /* GENERAL */ + "LOADING": "Yükleniyor …", + /* CALENDAR */ + "TODAY": "Bugün", + "TOMORROW": "Yarın", + "RUNNING": "Biten", + "EMPTY": "Yakında etkinlik yok.", + /* WEATHER */ + "N": "K", + "NNE": "KKD", + "NE": "KD", + "ENE": "DKD", + "E": "D", + "ESE": "DGD", + "SE": "GD", + "SSE": "GGD", + "S": "G", + "SSW": "GGB", + "SW": "GB", + "WSW": "BGB", + "W": "B", + "WNW": "BKB", + "NW": "KB", + "NNW": "KKB" +} \ No newline at end of file diff --git a/translations/translations.js b/translations/translations.js index 81cf25a697..d572c80335 100644 --- a/translations/translations.js +++ b/translations/translations.js @@ -25,4 +25,5 @@ var translations = { "pl" : "translations/pl.json", // Polish "gr" : "translations/gr.json", // Greek "da" : "translations/da.json", // Danish + "tr" : "translations/tr.json", // Turkish }; From ab1f34726be1e33c4cbe9542fcab0b24f54858a4 Mon Sep 17 00:00:00 2001 From: Onur Yilmaz Date: Wed, 2 Nov 2016 22:03:17 +0000 Subject: [PATCH 082/169] Turkish translation added --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 709bc1f67e..cc4a76e4c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Finnish translation. - Danish translation. +- Turkish translation. - Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)). - Added ability to change the point of time when calendar events get relative. - Add Splash screen on boot. From 1d16c96ca4a16787422150a7aacfba7c9ae80102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 3 Nov 2016 00:19:32 -0300 Subject: [PATCH 083/169] Update: translations es --- translations/es.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/translations/es.json b/translations/es.json index 6de069c73b..0a160abe06 100644 --- a/translations/es.json +++ b/translations/es.json @@ -25,4 +25,8 @@ "WNW": "ONO", "NW": "NO", "NNW": "NNO" + + /* UPDATE INFO */ + "UPDATE_NOTIFICATION": "MagicMirror² actualización disponible.", + "UPDATE_INFO": "Tu actual instalación está COMMIT_COUNT cambios detrás de la rama BRANCH_NAME." } From 678d5fc53254b19aa7b958d4841877bf4a7cf826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Wed, 26 Oct 2016 13:03:01 -0300 Subject: [PATCH 084/169] currentweather, weatherforecast: sample URL for LocationID: Changed from README the sample URLs for get the LocationID. The http://bulk.openweather.org/sample/ doesn't work --- modules/default/currentweather/README.md | 4 ++-- modules/default/weatherforecast/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 067dce54f9..0f560dc792 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -14,7 +14,7 @@ modules: [ config: { // See 'Configuration options' for more information. location: 'Amsterdam,Netherlands', - locationID: '', //Location ID from http://bulk.openweather.org/sample/ + locationID: '', //Location ID from http://openweathermap.org/help/city_list.txt appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key. } } @@ -45,7 +45,7 @@ The following properties can be configured: locationID - Location ID from OpenWeather This will override anything you put in location.
Leave blank if you want to use location. + Location ID from OpenWeatherMap This will override anything you put in location.
Leave blank if you want to use location.
Example: 1234567
Default value:

Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index 0d321aa327..d88dfd54d1 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -14,7 +14,7 @@ modules: [ config: { // See 'Configuration options' for more information. location: 'Amsterdam,Netherlands', - locationID: '', //Location ID from http://bulk.openweather.org/sample/ + locationID: '', //Location ID from http://openweathermap.org/help/city_list.txt appid: 'abcde12345abcde12345abcde12345ab' //openweathermap.org API key. } } @@ -45,7 +45,7 @@ The following properties can be configured: locationID - Location ID from OpenWeather This will override anything you put in location.
Leave blank if you want to use location. + Location ID from OpenWeatherMap This will override anything you put in location.
Leave blank if you want to use location.
Example: 1234567
Default value:

Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. From d01b1a706c1f9083a796b426a3a532215f9f044d Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Thu, 3 Nov 2016 17:51:31 -0300 Subject: [PATCH 085/169] error missing coma into es translations --- translations/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translations/es.json b/translations/es.json index 0a160abe06..4d613f542f 100644 --- a/translations/es.json +++ b/translations/es.json @@ -24,7 +24,7 @@ "W": "O", "WNW": "ONO", "NW": "NO", - "NNW": "NNO" + "NNW": "NNO", /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² actualización disponible.", From 1fa5c53b725a6124f41992ac2e6cf9f47081df56 Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Sat, 5 Nov 2016 21:21:23 -0300 Subject: [PATCH 086/169] calendar: fix space vs tab into caledarfetcher.js --- modules/default/calendar/calendarfetcher.js | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 3ca92974f8..0881afb364 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -80,7 +80,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe 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")); @@ -96,10 +96,10 @@ 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; - + 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); @@ -114,9 +114,9 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe endDate: endDate.format("x"), fullDayEvent: isFullDayEvent(event), firstYear: event.start.getFullYear(), - location: location, - geo: geo, - description: description + location: location, + geo: geo, + description: description }); } } @@ -140,18 +140,18 @@ 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, - location: location, - geo: geo, - description: description + location: location, + geo: geo, + description: description }); - + } } } @@ -198,7 +198,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; From 18edb13e7619be0c21b76c4149740e660de4ae03 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sun, 6 Nov 2016 12:37:04 +0100 Subject: [PATCH 087/169] Remove Snyk since it gives to many NPM issues. --- package.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/package.json b/package.json index 632742db77..67c258a578 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,6 @@ "main": "js/electron.js", "scripts": { "start": "electron js/electron.js", - "test": "snyk test", - "snyk-protect": "snyk protect", - "prepublish": "npm run snyk-protect" }, "repository": { "type": "git", @@ -46,10 +43,8 @@ "request": "^2.74.0", "rrule": "latest", "simple-git": "^1.54.0", - "snyk": "^1.14.1", "socket.io": "^1.4.6", "valid-url": "latest", "walk": "latest" - }, - "snyk": true + } } From af660bc63107d4b8a26dd366dd11f94e889c21d1 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sun, 6 Nov 2016 12:54:00 +0100 Subject: [PATCH 088/169] Fix typo. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 67c258a578..c2f6080ebc 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "A modular interface for smart mirrors.", "main": "js/electron.js", "scripts": { - "start": "electron js/electron.js", + "start": "electron js/electron.js" }, "repository": { "type": "git", From 66ef72a0401af42675fecda31934d401fd69ee74 Mon Sep 17 00:00:00 2001 From: derwehr Date: Mon, 7 Nov 2016 17:49:32 +0100 Subject: [PATCH 089/169] added url to the newsfeed fetcher --- modules/default/newsfeed/fetcher.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/fetcher.js index 665c5e15d6..e4fefca9e1 100644 --- a/modules/default/newsfeed/fetcher.js +++ b/modules/default/newsfeed/fetcher.js @@ -46,6 +46,7 @@ var Fetcher = function(url, reloadInterval, encoding) { var title = item.title; var description = item.description || item.summary || item.content || ''; var pubdate = item.pubdate || item.published || item.updated; + var url = item.url || item.link; if (title && pubdate) { @@ -56,6 +57,7 @@ var Fetcher = function(url, reloadInterval, encoding) { title: title, description: description, pubdate: pubdate, + url: url, }); } else { From 41327bfb03ea5fc1186525a9965202746e3b2cdc Mon Sep 17 00:00:00 2001 From: derwehr Date: Mon, 7 Nov 2016 20:46:28 +0100 Subject: [PATCH 090/169] quick fix to prevent issues with feeds that omit url and link --- modules/default/newsfeed/fetcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/fetcher.js index e4fefca9e1..8d920eec75 100644 --- a/modules/default/newsfeed/fetcher.js +++ b/modules/default/newsfeed/fetcher.js @@ -46,7 +46,7 @@ var Fetcher = function(url, reloadInterval, encoding) { var title = item.title; var description = item.description || item.summary || item.content || ''; var pubdate = item.pubdate || item.published || item.updated; - var url = item.url || item.link; + var url = item.url || item.link || ''; if (title && pubdate) { From e4197012f65778f815cd73a6c7fab1a30ef3b92f Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 8 Nov 2016 20:07:31 +0100 Subject: [PATCH 091/169] updateWrapperStates to hide unused regions. --- config/config.js.sample | 2 +- js/main.js | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/config/config.js.sample b/config/config.js.sample index c2607dbf39..6b090cca33 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -18,7 +18,7 @@ var config = { }, { module: "updatenotification", - position: "top_center" + position: "top_bar" }, { module: 'clock', diff --git a/js/main.js b/js/main.js index 984df4fd55..a69e56c26c 100644 --- a/js/main.js +++ b/js/main.js @@ -198,6 +198,8 @@ var MM = (function() { // the .display property. moduleWrapper.style.position = "fixed"; + updateWrapperStates(); + if (typeof callback === "function") { callback(); } }, speed); } @@ -241,6 +243,8 @@ var MM = (function() { moduleWrapper.style.position = "static"; moduleWrapper.style.opacity = 1; + updateWrapperStates(); + clearTimeout(module.showHideTimer); module.showHideTimer = setTimeout(function() { if (typeof callback === "function") { callback(); } @@ -249,6 +253,37 @@ var MM = (function() { } }; + /* updateWrapperStates() + * Checks for all positions if it has visible content. + * If not, if will hide the position to prevent unwanted margins. + * This method schould be called by the show and hide methods. + * + * Example: + * If the top_bar only contains the update notification. And no update is available, + * the update notification is hidden. The top bar still occupies space making for + * an ugly top margin. By using this function, the top bar will be hidden if the + * update notification is not visible. + */ + + var updateWrapperStates = function() { + var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; + + positions.forEach(function(position) { + var wrapper = selectWrapper(position); + var moduleWrappers = wrapper.getElementsByClassName("module"); + + var showWrapper = false; + Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) { + console.log(moduleWrapper, moduleWrapper.style.position); + if (moduleWrapper.style.position == "static") { + showWrapper = true; + } + }); + + wrapper.style.display = showWrapper ? "block" : "none"; + }); + }; + /* loadConfig() * Loads the core config and combines it with de system defaults. */ From 50b37f2ddd5bf142573be297752b8a3b196401aa Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Tue, 8 Nov 2016 20:11:46 +0100 Subject: [PATCH 092/169] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f6e9022a8..63b06a919e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Solve an issue where module margins would appear when the first module of a section was hidden. - Solved visual display errors on chrome, if all modules in one of the right sections are hidden. - Module default config values are no longer modified when setting config values. +- Hide a region if all modules in a region are hidden. Prevention unwanted margins. ## [2.0.5] - 2016-09-20 From d0a3e8f7895119359630cf97a223a7444d8bc761 Mon Sep 17 00:00:00 2001 From: Stefan Bols Date: Wed, 9 Nov 2016 17:20:35 +0100 Subject: [PATCH 093/169] Added DAYAFTERTOMORROW key to translation file Key found at NL translation file, and are missing in the Danish translation --- translations/da.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/da.json b/translations/da.json index 06827ea1f8..f8b95c8eca 100644 --- a/translations/da.json +++ b/translations/da.json @@ -5,6 +5,7 @@ /* CALENDAR */ "TODAY": "I dag", "TOMORROW": "I morgen", + "DAYAFTERTOMORROW": "I overmorgen", "RUNNING": "Slutter om", "EMPTY": "Ingen kommende begivenheder.", From 557426246c94bd5be3f32922bc1ed3c072fac3e4 Mon Sep 17 00:00:00 2001 From: Stefan Bols Date: Wed, 9 Nov 2016 17:22:33 +0100 Subject: [PATCH 094/169] Added key DAYAFTERTOMORROW to translation file The key was found in the NL translation file, and were missing in the EN file --- translations/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/en.json b/translations/en.json index e169ba1b82..0ea83e560b 100644 --- a/translations/en.json +++ b/translations/en.json @@ -5,6 +5,7 @@ /* CALENDAR */ "TODAY": "Today", "TOMORROW": "Tomorrow", + "DAYAFTERTOMORROW": "The day after tomorrow", "RUNNING": "Ends in", "EMPTY": "No upcoming events.", From 9812654bfae0349f3d2b369fa9cf1241ea09d4f7 Mon Sep 17 00:00:00 2001 From: Stefan Bols Date: Wed, 9 Nov 2016 17:30:20 +0100 Subject: [PATCH 095/169] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63b06a919e..6163007265 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Updated - Modified translations for Frysk. +- Modified core English translations. - Updated package.json as a result of Snyk security update. - Improve object instantiation to prevent reference errors. - Improve logger. `Log.log()` now accepts multiple arguments. From d4946d931a8921853dae9406117e821ef1125c1f Mon Sep 17 00:00:00 2001 From: Stefan Bols Date: Wed, 9 Nov 2016 17:40:51 +0100 Subject: [PATCH 096/169] Create da.json --- modules/default/alert/translations/da.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 modules/default/alert/translations/da.json diff --git a/modules/default/alert/translations/da.json b/modules/default/alert/translations/da.json new file mode 100644 index 0000000000..234f22b15d --- /dev/null +++ b/modules/default/alert/translations/da.json @@ -0,0 +1,4 @@ +{ + "sysTitle": "MagicMirror Notifikation", + "welcome": "Velkommen, modulet er succesfuldt startet!" +} From 9fd81bf6c7437c1c1d94bfff0043ae58a326edd5 Mon Sep 17 00:00:00 2001 From: Chris van Marle Date: Thu, 10 Nov 2016 17:26:29 +0100 Subject: [PATCH 097/169] Add dateFormat to calendar module --- modules/default/calendar/README.md | 7 +++++++ modules/default/calendar/calendar.js | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 54d318ce33..9492c6ae05 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -118,6 +118,13 @@ The following properties can be configured:
Default value: false + + dateFormat + Format to use for the date of events (when using absolute dates)
+
Possible values: See Moment.js formats +
Default value: MMM Do (e.g. Jan 18th) + + timeFormat Display event times as absolute dates, or relative time
diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 39ea6b58cd..6282d13053 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -23,6 +23,7 @@ Module.register("calendar", { fade: true, urgency: 7, timeFormat: "relative", + dateFormat: "MMM Do", getRelative: 6, fadePoint: 0.25, // Start on 1/4th of the list. calendars: [ @@ -175,7 +176,7 @@ Module.register("calendar", { // This event falls within the config.urgency period that the user has set timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); } else { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format("MMM Do")); + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); } } else { timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); @@ -205,7 +206,7 @@ Module.register("calendar", { // This event falls within the config.urgency period that the user has set timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); } else { - timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format("MMM Do")); + timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").format(this.config.dateFormat)); } } else { timeWrapper.innerHTML = this.capFirst(moment(event.startDate, "x").fromNow()); From 70befe900c37d7add5c6c4fabe2ad0ad47406fe4 Mon Sep 17 00:00:00 2001 From: Chris van Marle Date: Thu, 10 Nov 2016 17:28:39 +0100 Subject: [PATCH 098/169] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6163007265..dce79ec52c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option to show rain amount in the weatherforecast default module - Add module `updatenotification` to get an update whenever a new version is availabe. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information. - Add the abilty to set timezone on the date display in the Clock Module +- Ability to set date format in calendar module ### Updated - Modified translations for Frysk. From 70d6d4246d7345d0fe7dc7475d85e1b39c718825 Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Mon, 7 Nov 2016 20:08:56 -0300 Subject: [PATCH 099/169] compliments: Add feature use current weather. Possibility the use the actual type of currentweather to show the compliments. --- CHANGELOG.md | 1 + modules/default/compliments/README.md | 38 ++++++++++++++ modules/default/compliments/compliments.js | 52 +++++++++++++++++-- .../default/currentweather/currentweather.js | 1 + 4 files changed, 88 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f6e9022a8..87059da3e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option to show rain amount in the weatherforecast default module - Add module `updatenotification` to get an update whenever a new version is availabe. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information. - Add the abilty to set timezone on the date display in the Clock Module +- Possibility to use currentweather for the compliments ### Updated - Modified translations for Frysk. diff --git a/modules/default/compliments/README.md b/modules/default/compliments/README.md index bf5b953884..911de4b04b 100644 --- a/modules/default/compliments/README.md +++ b/modules/default/compliments/README.md @@ -63,6 +63,44 @@ The following properties can be configured: The `compliments` property contains an object with three arrays: morning, afternoon andevening. Based on the time of the day, the compliments will be picked out of one of these arrays. The arrays contain one or multiple compliments. + +If use the currentweather is possible use a actual weather for set compliments. The availables properties are: +* day_sunny +* day_cloudy +* cloudy +* cloudy_windy +* showers +* rain +* thunderstorm +* snow +* fog +* night_clear +* night_cloudy +* night_showers +* night_rain +* night_thunderstorm +* night_snow +* night_alt_cloudy_windy + +#### Example use with currentweather module +````javascript +config: { + compliments: { + day_sunny: [ + 'Today is a sunny day', + 'It\'s a beautiful day' + ], + snow: [ + 'Snowball battle!' + ], + rain: [ + 'Don\'t forget your umbrella' + ] + } +} +```` + + #### Default value: ````javascript config: { diff --git a/modules/default/compliments/compliments.js b/modules/default/compliments/compliments.js index 61f9ec5fdd..f05cd9c1b6 100644 --- a/modules/default/compliments/compliments.js +++ b/modules/default/compliments/compliments.js @@ -32,6 +32,9 @@ Module.register("compliments",{ fadeSpeed: 4000 }, + // Set currentweather from module + currentWeatherType: "", + // Define required scripts. getScripts: function() { return ["moment.js"]; @@ -84,14 +87,21 @@ Module.register("compliments",{ */ complimentArray: function() { var hour = moment().hour(); + var compliments = null; if (hour >= 3 && hour < 12) { - return this.config.compliments.morning; + compliments = this.config.compliments.morning; } else if (hour >= 12 && hour < 17) { - return this.config.compliments.afternoon; + compliments = this.config.compliments.afternoon; } else { - return this.config.compliments.evening; + compliments = this.config.compliments.evening; + } + + if ( this.currentWeatherType in this.config.compliments) { + compliments.push.apply(compliments, this.config.compliments[this.currentWeatherType]); } + return compliments; + }, /* complimentArray() @@ -116,6 +126,40 @@ Module.register("compliments",{ wrapper.appendChild(compliment); return wrapper; - } + }, + + + // From data currentweather set weather type + setCurrentWeatherType: function(data) { + var weatherIconTable = { + "01d": "day_sunny", + "02d": "day_cloudy", + "03d": "cloudy", + "04d": "cloudy_windy", + "09d": "showers", + "10d": "rain", + "11d": "thunderstorm", + "13d": "snow", + "50d": "fog", + "01n": "night_clear", + "02n": "night_cloudy", + "03n": "night_cloudy", + "04n": "night_cloudy", + "09n": "night_showers", + "10n": "night_rain", + "11n": "night_thunderstorm", + "13n": "night_snow", + "50n": "night_alt_cloudy_windy" + }; + this.currentWeatherType = weatherIconTable[data.weather[0].icon]; + }, + + + // Override notification handler. + notificationReceived: function(notification, payload, sender) { + if (notification == "CURRENTWEATHER_DATA") { + this.setCurrentWeatherType(payload.data); + } + }, }); diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index bc7ccbb7a2..b72b59439a 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -337,6 +337,7 @@ Module.register("currentweather",{ this.show(this.config.animationSpeed, {lockString:this.identifier}); this.loaded = true; this.updateDom(this.config.animationSpeed); + this.sendNotification("CURRENTWEATHER_DATA", {data: data}); }, /* scheduleUpdate() From 048985bdf435889dbe8583ca6755edbabae2f109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 10 Nov 2016 15:26:55 -0300 Subject: [PATCH 100/169] translations: add Spanish translations for alert module --- modules/default/alert/translations/es.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 modules/default/alert/translations/es.json diff --git a/modules/default/alert/translations/es.json b/modules/default/alert/translations/es.json new file mode 100644 index 0000000000..39478251bf --- /dev/null +++ b/modules/default/alert/translations/es.json @@ -0,0 +1,4 @@ +{ + "sysTitle": "MagicMirror Notificaciones", + "welcome": "Bienvenido, ¡se iniciado correctamente!" +} From 434089395a840169e53931445124040f365159fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 10 Nov 2016 15:27:10 -0300 Subject: [PATCH 101/169] translations: add DAYAFTERTOMORROW key Spanish language. --- translations/es.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/es.json b/translations/es.json index 4d613f542f..9766f41d84 100644 --- a/translations/es.json +++ b/translations/es.json @@ -5,6 +5,7 @@ /* CALENDAR */ "TODAY": "Hoy", "TOMORROW": "Mañana", + "DAYAFTERTOMORROW": "Pasado mañana", "RUNNING": "Termina en", "EMPTY": "No hay eventos programados.", From deda869cc5d752c6a2253e6e19d249e592983b45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 10 Nov 2016 15:33:16 -0300 Subject: [PATCH 102/169] currentweather: Remove variable updateTimer not used --- modules/default/currentweather/currentweather.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index bc7ccbb7a2..071ec5cb2f 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -98,8 +98,6 @@ Module.register("currentweather",{ this.loaded = false; this.scheduleUpdate(this.config.initialLoadDelay); - this.updateTimer = null; - }, // Override dom generator. From b63194c0aa2365cadd3252a048cddec7224ab9ae Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Fri, 11 Nov 2016 10:13:40 -0300 Subject: [PATCH 103/169] remove extra console.log introduced in commit e419701 --- js/main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/main.js b/js/main.js index a69e56c26c..457255ddf7 100644 --- a/js/main.js +++ b/js/main.js @@ -274,7 +274,6 @@ var MM = (function() { var showWrapper = false; Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) { - console.log(moduleWrapper, moduleWrapper.style.position); if (moduleWrapper.style.position == "static") { showWrapper = true; } From e311f170625799c2d987f2b9d07157c0d8eb441f Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 12 Nov 2016 11:19:58 +0100 Subject: [PATCH 104/169] Temp fix for wrapper issue. --- js/main.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 457255ddf7..41eeba0e81 100644 --- a/js/main.js +++ b/js/main.js @@ -274,11 +274,17 @@ var MM = (function() { var showWrapper = false; Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) { - if (moduleWrapper.style.position == "static") { + if (moduleWrapper.style.position == "static" || moduleWrapper.style.position == "") { showWrapper = true; } }); + // if (showWrapper) { + // console.log('Hide wrapper: ' + position); + // } else { + // console.log('Show wrapper: ' + position); + // } + wrapper.style.display = showWrapper ? "block" : "none"; }); }; From 688b5f29b6d5a43c62e9bd3887e2c2e430b39940 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 12 Nov 2016 20:03:56 +0100 Subject: [PATCH 105/169] Cleanup. --- js/main.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/js/main.js b/js/main.js index 41eeba0e81..0fc4a8aac8 100644 --- a/js/main.js +++ b/js/main.js @@ -52,6 +52,8 @@ var MM = (function() { } } + updateWrapperStates(); + sendNotification("DOM_OBJECTS_CREATED"); }; @@ -274,17 +276,11 @@ var MM = (function() { var showWrapper = false; Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) { - if (moduleWrapper.style.position == "static" || moduleWrapper.style.position == "") { + if (moduleWrapper.style.position == "" || moduleWrapper.style.position == "static") { showWrapper = true; } }); - // if (showWrapper) { - // console.log('Hide wrapper: ' + position); - // } else { - // console.log('Show wrapper: ' + position); - // } - wrapper.style.display = showWrapper ? "block" : "none"; }); }; From 07a86800c9cbed31e031541245ddeb6a14ebe65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sat, 12 Nov 2016 21:10:37 -0300 Subject: [PATCH 106/169] calendar: little fix format README --- modules/default/calendar/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 9492c6ae05..29a593aaa4 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -191,24 +191,24 @@ config: { - symbol + symbol The symbol to show in front of an event. This property is optional.

Possible values: See Font Awesome website. - repeatingCountTitle + repeatingCountTitle The count title for yearly repating events in this calendar.

Example:
'Birthday' - user + user The username for HTTP Basic authentication. - pass + pass The password for HTTP Basic authentication. From 83fb5b4d1bd7d3e8385778194c0fc87bf3f23cb3 Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Mon, 14 Nov 2016 00:00:12 -0300 Subject: [PATCH 107/169] logger: Show line number where is called the function for the log --- js/logger.js | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/js/logger.js b/js/logger.js index 280103abb0..1392a72ba1 100644 --- a/js/logger.js +++ b/js/logger.js @@ -13,35 +13,15 @@ var Log = (function() { return { - info: function() { - console.info.apply(console, arguments); - }, - log: function() { - console.log.apply(console, arguments); - }, - error: function() { - console.error.apply(console, arguments); - }, - warn: function() { - console.warn.apply(console, arguments); - }, - group: function() { - console.group.apply(console, arguments); - }, - groupCollapsed: function() { - console.groupCollapsed.apply(console, arguments); - }, - groupEnd: function() { - console.groupEnd(); - }, - time: function() { - console.time.apply(console, arguments); - }, - timeEnd: function() { - console.timeEnd.apply(console, arguments); - }, - timeStamp: function() { - console.timeStamp.apply(console, arguments); - } + info: Function.prototype.bind.call(console.info, console), + log: Function.prototype.bind.call(console.log, console), + error: Function.prototype.bind.call(console.error, console), + warn: Function.prototype.bind.call(console.warn, console), + group: Function.prototype.bind.call(console.group, console), + groupCollapsed: Function.prototype.bind.call(console.groupCollapsed, console), + groupEnd: Function.prototype.bind.call(console.groupEnd, console), + time: Function.prototype.bind.call(console.time, console), + timeEnd: Function.prototype.bind.call(console.timeEnd, console), + timeStamp: Function.prototype.bind.call(console.timeStamp, console) }; })(); From 62567264f09ae186c3c68b0f2eba6e926ca6387d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Mon, 14 Nov 2016 14:43:30 -0300 Subject: [PATCH 108/169] Config: Add option disabled for modules configuration --- CHANGELOG.md | 1 + README.md | 1 + js/app.js | 4 ++-- js/loader.js | 4 ++++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cf68a595a..7a2a7e88c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Add the abilty to set timezone on the date display in the Clock Module - Ability to set date format in calendar module - Possibility to use currentweather for the compliments +- Added option `disabled` for modules. ### Updated - Modified translations for Frysk. diff --git a/README.md b/README.md index 0f9ec65dbb..11672ef87e 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Module configuration: | `position` | The location of the module in which the module will be loaded. Possible values are `top_ bar`, `top_left`, `top_center`, `top_right`, `upper_third`, `middle_center`, `lower_third`, `bottom_left`, `bottom_center`, `bottom_right`, `bottom_bar`, `fullscreen_above`, and `fullscreen_below`. This field is optional but most modules require this field to set. Check the documentation of the module for more information. Multiple modules with the same position will be ordered based on the order in the configuration file. | | `classes` | Additional classes which are passed to the module. The field is optional. | | `header` | To display a header text above the module, add the header property. This field is optional. | +| `disabled` | Set disabled to `true` to skip creating the module. This field is optional. | | `config` | An object with the module configuration properties. Check the documentation of the module for more information. This field is optional, unless the module requires extra configuration. | ## Modules diff --git a/js/app.js b/js/app.js index 84e89d1387..29036f694c 100644 --- a/js/app.js +++ b/js/app.js @@ -156,7 +156,7 @@ var App = function() { for (var m in config.modules) { var module = config.modules[m]; - if (modules.indexOf(module.module) === -1) { + if (modules.indexOf(module.module) === -1 && !module.disabled) { modules.push(module.module); } } @@ -184,4 +184,4 @@ var App = function() { }; }; -module.exports = new App(); \ No newline at end of file +module.exports = new App(); diff --git a/js/loader.js b/js/loader.js index 84e42a0ad2..0c7c643ac0 100644 --- a/js/loader.js +++ b/js/loader.js @@ -89,6 +89,10 @@ var Loader = (function() { moduleFolder = config.paths.modules + "/default/" + module; } + if (moduleData.disabled === true) { + continue; + } + moduleFiles.push({ index: m, identifier: "module_" + m + "_" + module, From 3008bfbe0a89510f5941674045fa860bf6e71388 Mon Sep 17 00:00:00 2001 From: Stefan Bols Date: Tue, 15 Nov 2016 22:54:47 +0100 Subject: [PATCH 109/169] Added UPDATE INFO to da.json --- translations/da.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/translations/da.json b/translations/da.json index f8b95c8eca..4fb9b1c354 100644 --- a/translations/da.json +++ b/translations/da.json @@ -26,4 +26,9 @@ "WNW": "VNV", "NW": "NV", "NNW": "NNV" + + + /* UPDATE INFO */ + "UPDATE_NOTIFICATION": "MagicMirror² opdatering tilgængelig.", + "UPDATE_INFO": "Den nuværende installation er COMMIT_COUNT bagud på BRANCH_NAME branch'en." } From 7329515a4d8ca3eb247999249c2bcbf66b572c73 Mon Sep 17 00:00:00 2001 From: Chris van Marle Date: Wed, 16 Nov 2016 18:19:44 +0100 Subject: [PATCH 110/169] Check for module updates --- .../default/updatenotification/node_helper.js | 31 +++++++++++++++---- .../updatenotification/updatenotification.js | 6 +++- translations/en.json | 1 + translations/nl.json | 1 + 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/modules/default/updatenotification/node_helper.js b/modules/default/updatenotification/node_helper.js index 862087d8ad..c6a38da13d 100644 --- a/modules/default/updatenotification/node_helper.js +++ b/modules/default/updatenotification/node_helper.js @@ -1,4 +1,7 @@ -var simpleGit = require("simple-git")(__dirname + "/../.."); +var SimpleGit = require("simple-git"); +var simpleGits = []; +var fs = require("fs"); +var path = require("path"); var NodeHelper = require("node_helper"); module.exports = NodeHelper.create({ @@ -8,7 +11,19 @@ module.exports = NodeHelper.create({ updateTimer: null, start: function () { - + var srcdir = __dirname + "/../../"; + fs.readdir(srcdir, function(err, names) { + if (err) { + console.error("Error reading dir " + srcdir + ": " + err); + return; + } + + names.filter(function(name) { + return fs.statSync(path.join(srcdir, name)).isDirectory() && name != "node_modules"; + }).forEach(function(name) { + simpleGits.push({"module": name, "git": SimpleGit(path.join(srcdir, name))}); + }); + }); }, socketNotificationReceived: function (notification, payload) { @@ -20,10 +35,14 @@ module.exports = NodeHelper.create({ preformFetch() { var self = this; - simpleGit.fetch().status(function(err, data) { - if (!err) { - self.sendSocketNotification("STATUS", data); - } + + simpleGits.forEach(function(sg) { + sg.git.fetch().status(function(err, data) { + data.module = sg.module; + if (!err) { + self.sendSocketNotification("STATUS", data); + } + }); }); this.scheduleNextFetch(this.config.updateInterval); diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js index cd2ba42cf5..2f0870ed6f 100644 --- a/modules/default/updatenotification/updatenotification.js +++ b/modules/default/updatenotification/updatenotification.js @@ -49,7 +49,11 @@ Module.register("updatenotification", { message.appendChild(icon); var text = document.createElement("span"); - text.innerHTML = this.translate("UPDATE_NOTIFICATION"); + if (this.status.module == "default") { + text.innerHTML = this.translate("UPDATE_NOTIFICATION"); + } else { + text.innerHTML = this.translate("UPDATE_NOTIFICATION_MODULE").replace("MODULE_NAME", this.status.module); + } message.appendChild(text); wrapper.appendChild(message); diff --git a/translations/en.json b/translations/en.json index 0ea83e560b..916b81ca56 100644 --- a/translations/en.json +++ b/translations/en.json @@ -29,5 +29,6 @@ /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² update available.", + "UPDATE_NOTIFICATION_MODULE": "Update available for MODULE_NAME module.", "UPDATE_INFO": "The current installation is COMMIT_COUNT behind on the BRANCH_NAME branch." } diff --git a/translations/nl.json b/translations/nl.json index 582b62e64b..e2d1c8c432 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -29,5 +29,6 @@ /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² update beschikbaar.", + "UPDATE_NOTIFICATION_MODULE": "Update beschikbaar voor MODULE_NAME module.", "UPDATE_INFO": "De huidige installatie loopt COMMIT_COUNT achter op de BRANCH_NAME branch." } From ac9f42a8fe003686c95145aff69a6486b27f8b1c Mon Sep 17 00:00:00 2001 From: Stefan Bols Date: Wed, 16 Nov 2016 20:35:55 +0100 Subject: [PATCH 111/169] Updated da translationfile --- translations/da.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/da.json b/translations/da.json index 4fb9b1c354..ee5c03f055 100644 --- a/translations/da.json +++ b/translations/da.json @@ -30,5 +30,6 @@ /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² opdatering tilgængelig.", + "UPDATE_NOTIFICATION_MODULE": "Opdatering tilgængelig for MODULE_NAME modulet.", "UPDATE_INFO": "Den nuværende installation er COMMIT_COUNT bagud på BRANCH_NAME branch'en." } From c59f47f4b5b18445d2451aa53692323d58a61bce Mon Sep 17 00:00:00 2001 From: Nicholas Hubbard Date: Wed, 16 Nov 2016 20:02:37 -0500 Subject: [PATCH 112/169] Update Electron: Part I Replace `electron-prebuilt` with `electron`. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c2f6080ebc..0abae75c30 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "time-grunt": "latest" }, "dependencies": { - "electron-prebuilt": "^0.37.2", + "electron": "^1.4.6", "express": "^4.14.0", "express-ipfilter": "latest", "feedme": "latest", From 4f4fe5f06bc2c6d4b25515a7cccdfbedff7fc254 Mon Sep 17 00:00:00 2001 From: Nicholas Hubbard Date: Wed, 16 Nov 2016 20:04:56 -0500 Subject: [PATCH 113/169] Update Electron: Part II Add the change to the changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a2a7e88c2..031a791d9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Solved visual display errors on chrome, if all modules in one of the right sections are hidden. - Module default config values are no longer modified when setting config values. - Hide a region if all modules in a region are hidden. Prevention unwanted margins. +- Replaced `electron-prebuilt` package with `electron` in order to fix issues that would happen after 2017. ## [2.0.5] - 2016-09-20 From f1ca72aee904be809ed98403672ef6e5dd1c9d22 Mon Sep 17 00:00:00 2001 From: Nicholas Hubbard Date: Thu, 17 Nov 2016 09:34:11 -0500 Subject: [PATCH 114/169] Improve Security and Update Dependencies --- js/server.js | 2 ++ package.json | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/js/server.js b/js/server.js index 9ab47a7dd0..1f2006d910 100644 --- a/js/server.js +++ b/js/server.js @@ -12,6 +12,7 @@ var io = require("socket.io")(server); var path = require("path"); var ipfilter = require("express-ipfilter").IpFilter; var fs = require("fs"); +var helmet = require("helmet"); var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); @@ -27,6 +28,7 @@ var Server = function(config, callback) { res.status(403).send("This device is not allowed to access your mirror.
Please check your config.js or config.js.sample to change this."); }); }); + app.use(helmet()); app.use("/js", express.static(__dirname)); app.use("/config", express.static(path.resolve(__dirname + "/../config"))); diff --git a/package.json b/package.json index 0abae75c30..118c9837b0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,9 @@ "modular" ], "author": "Michael Teeuw", - "contributors": ["https://github.com/MichMich/MagicMirror/graphs/contributors"], + "contributors": [ + "https://github.com/MichMich/MagicMirror/graphs/contributors" + ], "license": "MIT", "bugs": { "url": "https://github.com/MichMich/MagicMirror/issues" @@ -27,23 +29,24 @@ "grunt": "latest", "grunt-eslint": "latest", "grunt-jsonlint": "latest", - "grunt-markdownlint": "^1.0.4", + "grunt-markdownlint": "^1.0.13", "grunt-stylelint": "latest", "grunt-yamllint": "latest", "stylelint-config-standard": "latest", "time-grunt": "latest" }, "dependencies": { - "electron": "^1.4.6", + "electron": "^1.4.7", "express": "^4.14.0", "express-ipfilter": "latest", "feedme": "latest", + "helmet": "^3.1.0", "iconv-lite": "latest", "moment": "latest", - "request": "^2.74.0", + "request": "^2.78.0", "rrule": "latest", - "simple-git": "^1.54.0", - "socket.io": "^1.4.6", + "simple-git": "^1.62.0", + "socket.io": "^1.5.1", "valid-url": "latest", "walk": "latest" } From 690d4616931da220b99bb60156bbdce3a1f11f20 Mon Sep 17 00:00:00 2001 From: Nicholas Hubbard Date: Thu, 17 Nov 2016 10:33:13 -0500 Subject: [PATCH 115/169] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 031a791d9c..118378a5ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Improve logger. `Log.log()` now accepts multiple arguments. - Remove extensive logging in newsfeed node helper. - Calendar times are now uniformly capitalized. +- Modules are now secure, and Helmet is now used to prevent abuse of the Mirror's API. ### Fixed - Solve an issue where module margins would appear when the first module of a section was hidden. From 482dd4db7650304dd241e7c5073bae77e2deff45 Mon Sep 17 00:00:00 2001 From: Chris van Marle Date: Fri, 18 Nov 2016 12:53:49 +0100 Subject: [PATCH 116/169] Check updates for configured modules only --- .../default/updatenotification/node_helper.js | 35 +++++++++++++------ .../updatenotification/updatenotification.js | 5 ++- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/modules/default/updatenotification/node_helper.js b/modules/default/updatenotification/node_helper.js index c6a38da13d..6147c061ed 100644 --- a/modules/default/updatenotification/node_helper.js +++ b/modules/default/updatenotification/node_helper.js @@ -2,6 +2,7 @@ var SimpleGit = require("simple-git"); var simpleGits = []; var fs = require("fs"); var path = require("path"); +var defaultModules = require(__dirname + "/../defaultmodules.js"); var NodeHelper = require("node_helper"); module.exports = NodeHelper.create({ @@ -11,24 +12,36 @@ module.exports = NodeHelper.create({ updateTimer: null, start: function () { - var srcdir = __dirname + "/../../"; - fs.readdir(srcdir, function(err, names) { - if (err) { - console.error("Error reading dir " + srcdir + ": " + err); - return; + }, + + configureModules: function(modules) { + for (moduleName in modules) { + if (defaultModules.indexOf(moduleName) < 0) { + // Default modules are included in the main MagicMirror repo + var moduleFolder = path.normalize(__dirname + "/../../" + moduleName); + + var stat; + try { + stat = fs.statSync(path.join(moduleFolder, '.git')); + } catch(err) { + // Error when directory .git doesn't exist + // This module is not managed with git, skip + continue; + } + + simpleGits.push({"module": moduleName, "git": SimpleGit(moduleFolder)}); } + } - names.filter(function(name) { - return fs.statSync(path.join(srcdir, name)).isDirectory() && name != "node_modules"; - }).forEach(function(name) { - simpleGits.push({"module": name, "git": SimpleGit(path.join(srcdir, name))}); - }); - }); + // Push MagicMirror itself last, biggest chance it'll show up last in UI and isn't overwritten + simpleGits.push({"module": "default", "git": SimpleGit(path.normalize(__dirname + "/../../../"))}); }, socketNotificationReceived: function (notification, payload) { if (notification === "CONFIG") { this.config = payload; + } else if(notification === "MODULES") { + this.configureModules(payload); this.preformFetch(); } }, diff --git a/modules/default/updatenotification/updatenotification.js b/modules/default/updatenotification/updatenotification.js index 2f0870ed6f..31b45c40f6 100644 --- a/modules/default/updatenotification/updatenotification.js +++ b/modules/default/updatenotification/updatenotification.js @@ -1,7 +1,5 @@ Module.register("updatenotification", { - - defaults: { updateInterval: 10 * 60 * 1000, // every 10 minutes }, @@ -10,12 +8,13 @@ Module.register("updatenotification", { start: function () { Log.log("Start updatenotification"); - + }, notificationReceived: function(notification, payload, sender) { if (notification === "DOM_OBJECTS_CREATED") { this.sendSocketNotification("CONFIG", this.config); + this.sendSocketNotification("MODULES", Module.definitions); this.hide(0,{lockString: self.identifier}); } }, From 7f86d2aa0ab35b0653c0f923797fa949bbefe596 Mon Sep 17 00:00:00 2001 From: Jopyth Date: Fri, 18 Nov 2016 17:07:55 +0100 Subject: [PATCH 117/169] Fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 118378a5ce..2127b6bfdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Add VSCode IntelliSense support. - Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information. - Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information. -- Module API: Option to define the minimumn MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information. +- Module API: Option to define the minimum MagicMirror version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information. - Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information. - Possibility to use the the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information. - Added option to show rain amount in the weatherforecast default module From c82cc309682b98275ecb8ce34805d1fead08774e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 18 Nov 2016 19:18:39 -0300 Subject: [PATCH 118/169] translations: Add UPDATE_NOTIFICATION_MODULE string for spanish. --- translations/es.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/es.json b/translations/es.json index 9766f41d84..3a8d382553 100644 --- a/translations/es.json +++ b/translations/es.json @@ -29,5 +29,6 @@ /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² actualización disponible.", + "UPDATE_NOTIFICATION_MODULE": "Disponible una actualización para el módulo MODULE_NAME.", "UPDATE_INFO": "Tu actual instalación está COMMIT_COUNT cambios detrás de la rama BRANCH_NAME." } From f0fa9f2033115be55f316a8d3f1aca1fff043b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 18 Nov 2016 22:19:45 -0300 Subject: [PATCH 119/169] translations: Fix massive tabs into translations files. --- translations/da.json | 32 ++++++++++++------------- translations/de.json | 32 ++++++++++++------------- translations/en.json | 32 ++++++++++++------------- translations/es.json | 32 ++++++++++++------------- translations/fi.json | 32 ++++++++++++------------- translations/fr.json | 32 ++++++++++++------------- translations/fy.json | 32 ++++++++++++------------- translations/it.json | 32 ++++++++++++------------- translations/ja.json | 46 ++++++++++++++++++------------------ translations/nb.json | 32 ++++++++++++------------- translations/nl.json | 32 ++++++++++++------------- translations/nn.json | 32 ++++++++++++------------- translations/pl.json | 32 ++++++++++++------------- translations/pt.json | 32 ++++++++++++------------- translations/pt_br.json | 32 ++++++++++++------------- translations/sv.json | 32 ++++++++++++------------- translations/tr.json | 52 +++++++++++++++++++++-------------------- translations/zh_cn.json | 32 ++++++++++++------------- translations/zh_tw.json | 32 ++++++++++++------------- 19 files changed, 322 insertions(+), 320 deletions(-) diff --git a/translations/da.json b/translations/da.json index ee5c03f055..4b346437eb 100644 --- a/translations/da.json +++ b/translations/da.json @@ -10,22 +10,22 @@ "EMPTY": "Ingen kommende begivenheder.", /* WEATHER */ - "N": "N", - "NNE": "NNØ", - "NE": "NØ", - "ENE": "ØNØ", - "E": "Ø", - "ESE": "ØSØ", - "SE": "SØ", - "SSE": "SSØ", - "S": "S", - "SSW": "SSV", - "SW": "SV", - "WSW": "VSV", - "W": "V", - "WNW": "VNV", - "NW": "NV", - "NNW": "NNV" + "N": "N", + "NNE": "NNØ", + "NE": "NØ", + "ENE": "ØNØ", + "E": "Ø", + "ESE": "ØSØ", + "SE": "SØ", + "SSE": "SSØ", + "S": "S", + "SSW": "SSV", + "SW": "SV", + "WSW": "VSV", + "W": "V", + "WNW": "VNV", + "NW": "NV", + "NNW": "NNV" /* UPDATE INFO */ diff --git a/translations/de.json b/translations/de.json index 58a4ca1417..67565b8975 100644 --- a/translations/de.json +++ b/translations/de.json @@ -10,22 +10,22 @@ "EMPTY": "Keine Termine.", /* WEATHER */ - "N": "N", - "NNE": "NNO", - "NE": "NO", - "ENE": "ONO", - "E": "O", - "ESE": "OSO", - "SE": "SO", - "SSE": "SSO", - "S": "S", - "SSW": "SSW", - "SW": "SW", - "WSW": "WSW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW", + "N": "N", + "NNE": "NNO", + "NE": "NO", + "ENE": "ONO", + "E": "O", + "ESE": "OSO", + "SE": "SO", + "SSE": "SSO", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW", /* UPDATE INFO */ "UPDATE_NOTIFICATION": "Aktualisierung für MagicMirror² verfügbar.", diff --git a/translations/en.json b/translations/en.json index 916b81ca56..45609f6159 100644 --- a/translations/en.json +++ b/translations/en.json @@ -10,22 +10,22 @@ "EMPTY": "No upcoming events.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSW", - "SW": "SW", - "WSW": "WSW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW", + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW", /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² update available.", diff --git a/translations/es.json b/translations/es.json index 9766f41d84..9a3dfa4af3 100644 --- a/translations/es.json +++ b/translations/es.json @@ -10,22 +10,22 @@ "EMPTY": "No hay eventos programados.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSO", - "SW": "SO", - "WSW": "OSO", - "W": "O", - "WNW": "ONO", - "NW": "NO", - "NNW": "NNO", + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO", /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² actualización disponible.", diff --git a/translations/fi.json b/translations/fi.json index f370e41c9f..b753039eac 100644 --- a/translations/fi.json +++ b/translations/fi.json @@ -9,20 +9,20 @@ "EMPTY": "Ei tulevia tapahtumia.", /* WEATHER */ - "N": "P", - "NNE": "PPI", - "NE": "PI", - "ENE": "IPI", - "E": "I", - "ESE": "IEI", - "SE": "EI", - "SSE": "EEI", - "S": "E", - "SSW": "EEL", - "SW": "EL", - "WSW": "LEL", - "W": "L", - "WNW": "LPL", - "NW": "PL", - "NNW": "PPL" + "N": "P", + "NNE": "PPI", + "NE": "PI", + "ENE": "IPI", + "E": "I", + "ESE": "IEI", + "SE": "EI", + "SSE": "EEI", + "S": "E", + "SSW": "EEL", + "SW": "EL", + "WSW": "LEL", + "W": "L", + "WNW": "LPL", + "NW": "PL", + "NNW": "PPL" } diff --git a/translations/fr.json b/translations/fr.json index 7cea070049..2701eb084d 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -9,20 +9,20 @@ "EMPTY": "Aucun RDV.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSO", - "SW": "SO", - "WSW": "OSO", - "W": "O", - "WNW": "ONO", - "NW": "NO", - "NNW": "NNO" + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO" } diff --git a/translations/fy.json b/translations/fy.json index 770ae3a1bd..44f1b476e9 100644 --- a/translations/fy.json +++ b/translations/fy.json @@ -10,20 +10,20 @@ "EMPTY": "Gjin plande ôfspraken.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSW", - "SW": "SW", - "WSW": "WSW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW" + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW" } diff --git a/translations/it.json b/translations/it.json index 74048a8bff..bde608b46b 100644 --- a/translations/it.json +++ b/translations/it.json @@ -9,20 +9,20 @@ "EMPTY": "Nessun evento in arrivo.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSW", - "SW": "SW", - "WSW": "WSW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW" + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW" } diff --git a/translations/ja.json b/translations/ja.json index 40d5996a49..728495598b 100644 --- a/translations/ja.json +++ b/translations/ja.json @@ -1,28 +1,28 @@ { /* GENERAL */ - "LOADING": "ローディング …", + "LOADING": "ローディング …", - /* CALENDAR */ - "TODAY":"今日", - "TOMORROW":"明日", - "RUNNING":"で終わります", - "EMPTY":"直近のイベントはありません", + /* CALENDAR */ + "TODAY": "今日", + "TOMORROW": "明日", + "RUNNING": "で終わります", + "EMPTY": "直近のイベントはありません", - /* WEATHER */ - "N":"北", - "NNE":"北北東", - "NE":"北東", - "ENE":"東北東", - "E":"東", - "ESE":"東南東", - "SE":"南東", - "SSE":"南南東", - "S":"南", - "SSW":"南南西", - "SW":"南西", - "WSW":"西南西", - "W":"西", - "WNW":"西北西", - "NW":"北西", - "NNW":"北北西" + /* WEATHER */ + "N": "北", + "NNE": "北北東", + "NE": "北東", + "ENE": "東北東", + "E": "東", + "ESE": "東南東", + "SE": "南東", + "SSE": "南南東", + "S": "南", + "SSW": "南南西", + "SW": "南西", + "WSW": "西南西", + "W": "西", + "WNW": "西北西", + "NW": "北西", + "NNW": "北北西" } diff --git a/translations/nb.json b/translations/nb.json index 737d0e267b..48f0ac6fe5 100644 --- a/translations/nb.json +++ b/translations/nb.json @@ -9,20 +9,20 @@ "EMPTY": "Ingen kommende arrangementer.", /* WEATHER */ - "N": "N", - "NNE": "NNØ", - "NE": "NØ", - "ENE": "ØNØ", - "E": "Ø", - "ESE": "ØSØ", - "SE": "SØ", - "SSE": "SSØ", - "S": "S", - "SSW": "SSV", - "SW": "SV", - "WSW": "VSV", - "W": "V", - "WNW": "VNV", - "NW": "NV", - "NNW": "NNV" + "N": "N", + "NNE": "NNØ", + "NE": "NØ", + "ENE": "ØNØ", + "E": "Ø", + "ESE": "ØSØ", + "SE": "SØ", + "SSE": "SSØ", + "S": "S", + "SSW": "SSV", + "SW": "SV", + "WSW": "VSV", + "W": "V", + "WNW": "VNV", + "NW": "NV", + "NNW": "NNV" } diff --git a/translations/nl.json b/translations/nl.json index e2d1c8c432..803db06c4b 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -10,22 +10,22 @@ "EMPTY": "Geen geplande afspraken.", /* WEATHER */ - "N": "N", - "NNE": "NNO", - "NE": "NO", - "ENE": "ONO", - "E": "O", - "ESE": "OZO", - "SE": "ZO", - "SSE": "ZZO", - "S": "Z", - "SSW": "ZZW", - "SW": "ZW", - "WSW": "WZW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW", + "N": "N", + "NNE": "NNO", + "NE": "NO", + "ENE": "ONO", + "E": "O", + "ESE": "OZO", + "SE": "ZO", + "SSE": "ZZO", + "S": "Z", + "SSW": "ZZW", + "SW": "ZW", + "WSW": "WZW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW", /* UPDATE INFO */ "UPDATE_NOTIFICATION": "MagicMirror² update beschikbaar.", diff --git a/translations/nn.json b/translations/nn.json index 2eb072eac5..b7dbe3ea16 100644 --- a/translations/nn.json +++ b/translations/nn.json @@ -9,20 +9,20 @@ "EMPTY": "Ingen komande hendingar.", /* WEATHER */ - "N": "N", - "NNE": "NNA", - "NE": "NA", - "ENE": "ANA", - "E": "A", - "ESE": "ASA", - "SE": "SA", - "SSE": "SSA", - "S": "S", - "SSW": "SSV", - "SW": "SV", - "WSW": "VSV", - "W": "V", - "WNW": "VNV", - "NW": "NV", - "NNW": "NNV" + "N": "N", + "NNE": "NNA", + "NE": "NA", + "ENE": "ANA", + "E": "A", + "ESE": "ASA", + "SE": "SA", + "SSE": "SSA", + "S": "S", + "SSW": "SSV", + "SW": "SV", + "WSW": "VSV", + "W": "V", + "WNW": "VNV", + "NW": "NV", + "NNW": "NNV" } diff --git a/translations/pl.json b/translations/pl.json index bc6753aceb..98fe7c61df 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -9,20 +9,20 @@ "EMPTY": "Brak wydarzeń.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSW", - "SW": "SW", - "WSW": "WSW", - "W": "W", - "WNW": "WNW", - "NW": "NW", - "NNW": "NNW" + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSW", + "SW": "SW", + "WSW": "WSW", + "W": "W", + "WNW": "WNW", + "NW": "NW", + "NNW": "NNW" } diff --git a/translations/pt.json b/translations/pt.json index e7269ac15b..f8797f0f4d 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -9,20 +9,20 @@ "EMPTY": "Sem eventos a chegar.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSO", - "SW": "SO", - "WSW": "OSO", - "W": "O", - "WNW": "ONO", - "NW": "NO", - "NNW": "NNO" + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO" } diff --git a/translations/pt_br.json b/translations/pt_br.json index 57bb4314df..17d3e63636 100644 --- a/translations/pt_br.json +++ b/translations/pt_br.json @@ -9,20 +9,20 @@ "EMPTY": "Nenhum evento novo.", /* WEATHER */ - "N": "N", - "NNE": "NNE", - "NE": "NE", - "ENE": "ENE", - "E": "E", - "ESE": "ESE", - "SE": "SE", - "SSE": "SSE", - "S": "S", - "SSW": "SSO", - "SW": "SO", - "WSW": "OSO", - "W": "O", - "WNW": "ONO", - "NW": "NO", - "NNW": "NNO" + "N": "N", + "NNE": "NNE", + "NE": "NE", + "ENE": "ENE", + "E": "E", + "ESE": "ESE", + "SE": "SE", + "SSE": "SSE", + "S": "S", + "SSW": "SSO", + "SW": "SO", + "WSW": "OSO", + "W": "O", + "WNW": "ONO", + "NW": "NO", + "NNW": "NNO" } diff --git a/translations/sv.json b/translations/sv.json index 6badd3bc30..9643a07b43 100644 --- a/translations/sv.json +++ b/translations/sv.json @@ -9,20 +9,20 @@ "EMPTY": "Inga kommande händelser.", /* WEATHER */ - "N": "N", - "NNE": "NNO", - "NE": "NO", - "ENE": "ONO", - "E": "Ö", - "ESE": "OSO", - "SE": "SO", - "SSE": "SSO", - "S": "S", - "SSW": "SSV", - "SW": "SV", - "WSW": "VSV", - "W": "V", - "WNW": "VNV", - "NW": "NV", - "NNW": "NNV" + "N": "N", + "NNE": "NNO", + "NE": "NO", + "ENE": "ONO", + "E": "Ö", + "ESE": "OSO", + "SE": "SO", + "SSE": "SSO", + "S": "S", + "SSW": "SSV", + "SW": "SV", + "WSW": "VSV", + "W": "V", + "WNW": "VNV", + "NW": "NV", + "NNW": "NNV" } diff --git a/translations/tr.json b/translations/tr.json index 9a488bf82e..a0d61ac706 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -1,26 +1,28 @@ { - /* GENERAL */ - "LOADING": "Yükleniyor …", - /* CALENDAR */ - "TODAY": "Bugün", - "TOMORROW": "Yarın", - "RUNNING": "Biten", - "EMPTY": "Yakında etkinlik yok.", - /* WEATHER */ - "N": "K", - "NNE": "KKD", - "NE": "KD", - "ENE": "DKD", - "E": "D", - "ESE": "DGD", - "SE": "GD", - "SSE": "GGD", - "S": "G", - "SSW": "GGB", - "SW": "GB", - "WSW": "BGB", - "W": "B", - "WNW": "BKB", - "NW": "KB", - "NNW": "KKB" -} \ No newline at end of file + /* GENERAL */ + "LOADING": "Yükleniyor …", + + /* CALENDAR */ + "TODAY": "Bugün", + "TOMORROW": "Yarın", + "RUNNING": "Biten", + "EMPTY": "Yakında etkinlik yok.", + + /* WEATHER */ + "N": "K", + "NNE": "KKD", + "NE": "KD", + "ENE": "DKD", + "E": "D", + "ESE": "DGD", + "SE": "GD", + "SSE": "GGD", + "S": "G", + "SSW": "GGB", + "SW": "GB", + "WSW": "BGB", + "W": "B", + "WNW": "BKB", + "NW": "KB", + "NNW": "KKB" +} diff --git a/translations/zh_cn.json b/translations/zh_cn.json index b6d21d378a..a8c32d7083 100644 --- a/translations/zh_cn.json +++ b/translations/zh_cn.json @@ -9,20 +9,20 @@ "EMPTY": "没有更多的活动。", /* WEATHER */ - "N": "北风", - "NNE": "北偏东风", - "NE": "东北风", - "ENE": "东偏北风", - "E": "东风", - "ESE": "东偏南风", - "SE": "东南风", - "SSE": "南偏东风", - "S": "南风", - "SSW": "南偏西风", - "SW": "西南风", - "WSW": "西偏南风", - "W": "西风", - "WNW": "西偏北风", - "NW": "西北风", - "NNW": "北偏西风" + "N": "北风", + "NNE": "北偏东风", + "NE": "东北风", + "ENE": "东偏北风", + "E": "东风", + "ESE": "东偏南风", + "SE": "东南风", + "SSE": "南偏东风", + "S": "南风", + "SSW": "南偏西风", + "SW": "西南风", + "WSW": "西偏南风", + "W": "西风", + "WNW": "西偏北风", + "NW": "西北风", + "NNW": "北偏西风" } diff --git a/translations/zh_tw.json b/translations/zh_tw.json index b6f78f1275..1a5827bede 100644 --- a/translations/zh_tw.json +++ b/translations/zh_tw.json @@ -9,20 +9,20 @@ "EMPTY": "沒有更多的活動。", /* WEATHER */ - "N": "北風", - "NNE": "北偏東風", - "NE": "東北風", - "ENE": "東偏北風", - "E": "東風", - "ESE": "東偏南風", - "SE": "東南風", - "SSE": "南偏東風", - "S": "南風", - "SSW": "南偏西風", - "SW": "西南風", - "WSW": "西偏南風", - "W": "西風", - "WNW": "西偏北風", - "NW": "西北風", - "NNW": "北偏西風" + "N": "北風", + "NNE": "北偏東風", + "NE": "東北風", + "ENE": "東偏北風", + "E": "東風", + "ESE": "東偏南風", + "SE": "東南風", + "SSE": "南偏東風", + "S": "南風", + "SSW": "南偏西風", + "SW": "西南風", + "WSW": "西偏南風", + "W": "西風", + "WNW": "西偏北風", + "NW": "西北風", + "NNW": "北偏西風" } From bfb6c001a0a1bc05ed8a614752b8a58df0548250 Mon Sep 17 00:00:00 2001 From: Jopyth Date: Sat, 19 Nov 2016 07:46:30 +0100 Subject: [PATCH 120/169] add german translation for module update --- translations/de.json | 1 + 1 file changed, 1 insertion(+) diff --git a/translations/de.json b/translations/de.json index 58a4ca1417..10a2c45cb2 100644 --- a/translations/de.json +++ b/translations/de.json @@ -29,5 +29,6 @@ /* UPDATE INFO */ "UPDATE_NOTIFICATION": "Aktualisierung für MagicMirror² verfügbar.", + "UPDATE_NOTIFICATION_MODULE": "Aktualisierung für das MODULE_NAME Modul verfügbar.", "UPDATE_INFO": "Die aktuelle Installation ist COMMIT_COUNT hinter dem BRANCH_NAME branch." } From 3c8fa3382bbb37b32e641ae80cda6738fef55d11 Mon Sep 17 00:00:00 2001 From: Jopyth Date: Sun, 20 Nov 2016 16:47:49 +0100 Subject: [PATCH 121/169] update documentation to module default config --- modules/default/alert/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/alert/README.md b/modules/default/alert/README.md index 5ddf763902..d566313dc7 100644 --- a/modules/default/alert/README.md +++ b/modules/default/alert/README.md @@ -62,7 +62,7 @@ The following properties can be configured: welcome_message Message shown at startup.

Possible values: string false -
Default value: Welcome, start was successfull! +
Default value: false (no message at startup) From c584b51726acb5ba61cf1b0123ce439b1abfa916 Mon Sep 17 00:00:00 2001 From: Jopyth Date: Sun, 20 Nov 2016 16:49:30 +0100 Subject: [PATCH 122/169] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2127b6bfdb..eb4cc37b0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Module default config values are no longer modified when setting config values. - Hide a region if all modules in a region are hidden. Prevention unwanted margins. - Replaced `electron-prebuilt` package with `electron` in order to fix issues that would happen after 2017. +- Documentation of alert module ## [2.0.5] - 2016-09-20 From 6c9d33f05c44154f1e9f835c991f15979f589118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sun, 20 Nov 2016 20:06:58 -0300 Subject: [PATCH 123/169] newsfeed: fix set default value for animationSpeed option in README --- modules/default/newsfeed/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/newsfeed/README.md b/modules/default/newsfeed/README.md index 951fa51c20..e177be255b 100644 --- a/modules/default/newsfeed/README.md +++ b/modules/default/newsfeed/README.md @@ -98,7 +98,7 @@ The following properties can be configured: animationSpeed Speed of the update animation. (Milliseconds)

Possible values:0 - 5000 -
Default value: 2000 (2 seconds) +
Default value: 2500 (2.5 seconds) From 2ea7ef327ee088d9d10611d7f201e808827d0963 Mon Sep 17 00:00:00 2001 From: Rodrigo Ramez Norambuena Date: Sun, 20 Nov 2016 22:13:14 -0300 Subject: [PATCH 124/169] currentweather: add option onlyTemp. Is added option onlyTemp for show only current temperature and weather icon. --- modules/default/currentweather/README.md | 9 +++- .../default/currentweather/currentweather.js | 41 ++++++++++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index dd58ad75e8..35c0340447 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -113,7 +113,14 @@ The following properties can be configured:
Default value: false - + + onlyTemp + Show only current Temperature and weather icon.
+
Possible values: true or false +
Default value: false + + + useBeaufort Pick between using the Beaufort scale for wind speed or using the default units.

Possible values: true or false diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 044962f6db..ed068b7b72 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -35,6 +35,8 @@ Module.register("currentweather",{ appendLocationNameToHeader: true, calendarClass: "calendar", + onlyTemp: false, + iconTable: { "01d": "wi-day-sunny", "02d": "wi-day-cloudy", @@ -100,21 +102,9 @@ Module.register("currentweather",{ }, - // Override dom generator. - getDom: function() { - var wrapper = document.createElement("div"); - - if (this.config.appid === "") { - wrapper.innerHTML = "Please set the correct openweather appid in the config for module: " + this.name + "."; - wrapper.className = "dimmed light small"; - return wrapper; - } - - if (!this.loaded) { - wrapper.innerHTML = this.translate('LOADING'); - wrapper.className = "dimmed light small"; - return wrapper; - } + // add extra information of current weather + // windDirection, humidity, sunrise and sunset + addExtraInfoWeather: function(wrapper) { var small = document.createElement("div"); small.className = "normal medium"; @@ -162,6 +152,27 @@ Module.register("currentweather",{ small.appendChild(sunriseSunsetTime); wrapper.appendChild(small); + }, + + // Override dom generator. + getDom: function() { + var wrapper = document.createElement("div"); + + if (this.config.appid === "") { + wrapper.innerHTML = "Please set the correct openweather appid in the config for module: " + this.name + "."; + wrapper.className = "dimmed light small"; + return wrapper; + } + + if (!this.loaded) { + wrapper.innerHTML = this.translate('LOADING'); + wrapper.className = "dimmed light small"; + return wrapper; + } + + if (this.config.onlyTemp === false) { + this.addExtraInfoWeather(wrapper); + } var large = document.createElement("div"); large.className = "large light"; From e425adc230cc9d461ef88a23e0a6dc1c9d543178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Sun, 20 Nov 2016 22:18:09 -0300 Subject: [PATCH 125/169] fix some tabs --- modules/default/currentweather/currentweather.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index ed068b7b72..a379332dce 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -132,7 +132,7 @@ Module.register("currentweather",{ humidity.innerHTML = this.humidity; var spacer = document.createElement("sup"); - spacer.innerHTML = " "; + spacer.innerHTML = " "; var humidityIcon = document.createElement("sup"); humidityIcon.className = "wi wi-humidity humidityIcon"; @@ -208,15 +208,15 @@ Module.register("currentweather",{ } if (notification === "CALENDAR_EVENTS") { var senderClasses = sender.data.classes.toLowerCase().split(" "); - if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) { + if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) { var lastEvent = this.firstEvent; this.firstEvent = false; - + for (e in payload) { var event = payload[e]; if (event.location || event.geo) { this.firstEvent = event; - //Log.log("First upcoming event with location: ", event); + //Log.log("First upcoming event with location: ", event); break; } } @@ -233,7 +233,7 @@ Module.register("currentweather",{ Log.error("CurrentWeather: APPID not set!"); return; } - + var url = this.config.apiBase + this.config.apiVersion + "/" + this.config.weatherEndpoint + this.getParams(); var self = this; var retry = true; From b922fe35ab4ac530508b58881810dece16ada33b Mon Sep 17 00:00:00 2001 From: Platimir Date: Mon, 21 Nov 2016 22:14:16 +0100 Subject: [PATCH 126/169] Added update info translation Added 2/3 update info translation --- translations/pl.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/translations/pl.json b/translations/pl.json index 98fe7c61df..7a47745bea 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -25,4 +25,9 @@ "WNW": "WNW", "NW": "NW", "NNW": "NNW" + + /* UPDATE INFO */ + "UPDATE_NOTIFICATION": "Dostępna jest aktualizacja MagicMirror².", + "UPDATE_NOTIFICATION_MODULE": "Dostępna jest aktualizacja modułu MODULE_NAME.", + "UPDATE_INFO": "The current installation is COMMIT_COUNT behind on the BRANCH_NAME branch." } From 677312648b34a2f7a2afb7d244e6ad6cd2556b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 22 Nov 2016 18:53:46 -0300 Subject: [PATCH 127/169] comments fix for js/module.js --- js/module.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/js/module.js b/js/module.js index 37d3f14544..67305a9c1e 100644 --- a/js/module.js +++ b/js/module.js @@ -23,7 +23,7 @@ var Module = Class.extend({ // Timer reference used for showHide animation callbacks. showHideTimer: null, - // Array to store lockStrings. These stings are used to lock + // Array to store lockStrings. These strings are used to lock // visibility when hiding and showing module. lockStrings: [], @@ -106,7 +106,7 @@ var Module = Class.extend({ * This method is called when a notification arrives. * This method is called by the Magic Mirror core. * - * argument notification string - The identifier of the noitication. + * argument notification string - The identifier of the notification. * argument payload mixed - The payload of the notification. * argument sender Module - The module that sent the notification. */ @@ -121,7 +121,7 @@ var Module = Class.extend({ /* socketNotificationReceived(notification, payload) * This method is called when a socket notification arrives. * - * argument notification string - The identifier of the noitication. + * argument notification string - The identifier of the notification. * argument payload mixed - The payload of the notification. */ socketNotificationReceived: function (notification, payload) { @@ -299,7 +299,7 @@ var Module = Class.extend({ /* sendNotification(notification, payload) * Send a notification to all modules. * - * argument notification string - The identifier of the noitication. + * argument notification string - The identifier of the notification. * argument payload mixed - The payload of the notification. */ sendNotification: function (notification, payload) { @@ -309,7 +309,7 @@ var Module = Class.extend({ /* sendSocketNotification(notification, payload) * Send a socket notification to the node helper. * - * argument notification string - The identifier of the noitication. + * argument notification string - The identifier of the notification. * argument payload mixed - The payload of the notification. */ sendSocketNotification: function (notification, payload) { From 27644776f3fb2d30d97ae7013837964149a488f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 24 Nov 2016 00:20:04 -0300 Subject: [PATCH 128/169] fix tab into config.js.sample --- config/config.js.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.js.sample b/config/config.js.sample index 6b090cca33..913dbc439b 100644 --- a/config/config.js.sample +++ b/config/config.js.sample @@ -55,9 +55,9 @@ var config = { position: 'top_right', header: 'Weather Forecast', config: { - location: 'New York', + location: 'New York', locationID: '5128581', //ID from http://www.openweathermap.org - appid: 'YOUR_OPENWEATHER_API_KEY' + appid: 'YOUR_OPENWEATHER_API_KEY' } }, { From edfd9e46b6af7b90ce5f40b6bed714df148ab40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 24 Nov 2016 00:26:40 -0300 Subject: [PATCH 129/169] fix comments and space js/main.js --- js/main.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/js/main.js b/js/main.js index 0fc4a8aac8..4de028ee98 100644 --- a/js/main.js +++ b/js/main.js @@ -76,7 +76,7 @@ var MM = (function() { /* sendNotification(notification, payload, sender) * Send a notification to all modules. * - * argument notification string - The identifier of the noitication. + * argument notification string - The identifier of the notification. * argument payload mixed - The payload of the notification. * argument sender Module - The module that sent the notification. */ @@ -258,27 +258,27 @@ var MM = (function() { /* updateWrapperStates() * Checks for all positions if it has visible content. * If not, if will hide the position to prevent unwanted margins. - * This method schould be called by the show and hide methods. - * - * Example: + * This method schould be called by the show and hide methods. + * + * Example: * If the top_bar only contains the update notification. And no update is available, * the update notification is hidden. The top bar still occupies space making for - * an ugly top margin. By using this function, the top bar will be hidden if the - * update notification is not visible. + * an ugly top margin. By using this function, the top bar will be hidden if the + * update notification is not visible. */ var updateWrapperStates = function() { var positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"]; - + positions.forEach(function(position) { - var wrapper = selectWrapper(position); + var wrapper = selectWrapper(position); var moduleWrappers = wrapper.getElementsByClassName("module"); var showWrapper = false; - Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) { + Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) { if (moduleWrapper.style.position == "" || moduleWrapper.style.position == "static") { showWrapper = true; - } + } }); wrapper.style.display = showWrapper ? "block" : "none"; @@ -308,7 +308,7 @@ var MM = (function() { /* withClass(className) * filters a collection of modules based on classname(s). * - * argument className string/array - one or multiple classnames. (array or space devided) + * argument className string/array - one or multiple classnames. (array or space divided) * * return array - Filtered collection of modules. */ @@ -338,7 +338,7 @@ var MM = (function() { /* exceptWithClass(className) * filters a collection of modules based on classname(s). (NOT) * - * argument className string/array - one or multiple classnames. (array or space devided) + * argument className string/array - one or multiple classnames. (array or space divided) * * return array - Filtered collection of modules. */ From df2ebbf384ad8b78f9c67aae9bc6c80d5d3d36d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 25 Nov 2016 20:14:34 -0300 Subject: [PATCH 130/169] Add option to set bind address --- README.md | 1 + js/server.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11672ef87e..e087b4cca1 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ The following properties can be configured: | **Option** | **Description** | | --- | --- | | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | +| `address` | The ip address the accept connections. The default open bind `::` is IPv6 is available or `0.0.0.0` IPv4 run on. Example config: `192.168.10.100`. | | `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1", "::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | diff --git a/js/server.js b/js/server.js index 1f2006d910..0ffd76c6fc 100644 --- a/js/server.js +++ b/js/server.js @@ -17,7 +17,7 @@ var helmet = require("helmet"); var Server = function(config, callback) { console.log("Starting server op port " + config.port + " ... "); - server.listen(config.port); + server.listen(config.port, config.address ? config.address : null); app.use(function(req, res, next) { var result = ipfilter(config.ipWhitelist, {mode: "allow", log: false})(req, res, function(err) { From facc1dc94468b917a9a9cfb7ce37aba3c0555f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 25 Nov 2016 20:20:20 -0300 Subject: [PATCH 131/169] add label where is bind serveronly --- serveronly/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/serveronly/index.js b/serveronly/index.js index ea435a8ed9..e033bdc186 100644 --- a/serveronly/index.js +++ b/serveronly/index.js @@ -1,5 +1,6 @@ var app = require("../js/app.js"); app.start(function(config) { console.log(""); - console.log("Ready to go! Please point your browser to: http://localhost:" + config.port); + var bind_address = config.address ? config.address : "localhost"; + console.log("Ready to go! Please point your browser to: http://" + bind_address + ":" + config.port); }); From a05d7059fb0aade2f3f1a1bdb0e898c04c9523b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 25 Nov 2016 21:54:03 -0300 Subject: [PATCH 132/169] Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4cc37b0c..6777c9ab55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Ability to set date format in calendar module - Possibility to use currentweather for the compliments - Added option `disabled` for modules. +- Added option `address` to set bind address. +- Added option `onlyTemp` for currentweather module to show show only current temperature and weather icon. ### Updated - Modified translations for Frysk. From c966d34b07c82875870193634aa2186ad8dfbecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 25 Nov 2016 21:55:51 -0300 Subject: [PATCH 133/169] fix camelCase detected eslint --- serveronly/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/serveronly/index.js b/serveronly/index.js index e033bdc186..ccd4c294aa 100644 --- a/serveronly/index.js +++ b/serveronly/index.js @@ -1,6 +1,6 @@ var app = require("../js/app.js"); app.start(function(config) { console.log(""); - var bind_address = config.address ? config.address : "localhost"; - console.log("Ready to go! Please point your browser to: http://" + bind_address + ":" + config.port); + var bindAddress = config.address ? config.address : "localhost"; + console.log("Ready to go! Please point your browser to: http://" + bindAddress + ":" + config.port); }); From 35f2ebc2aa79c332e44856cd50e68c59d9d0f3a1 Mon Sep 17 00:00:00 2001 From: Andreas Date: Sat, 26 Nov 2016 15:33:10 +0100 Subject: [PATCH 134/169] Fixed Global Default Config Being Modified --- CHANGELOG.md | 2 +- js/main.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6777c9ab55..c5b5d31e22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Fixed - Solve an issue where module margins would appear when the first module of a section was hidden. - Solved visual display errors on chrome, if all modules in one of the right sections are hidden. -- Module default config values are no longer modified when setting config values. +- Global and Module default config values are no longer modified when setting config values. - Hide a region if all modules in a region are hidden. Prevention unwanted margins. - Replaced `electron-prebuilt` package with `electron` in order to fix issues that would happen after 2017. - Documentation of alert module diff --git a/js/main.js b/js/main.js index 4de028ee98..325a7efe24 100644 --- a/js/main.js +++ b/js/main.js @@ -295,7 +295,7 @@ var MM = (function() { return; } - config = Object.assign(defaults, config); + config = Object.assign({}, defaults, config); }; /* setSelectionMethodsForModules() From db6e0ccf63fd5a6a56ddd60738891e6bbfc65722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 25 Nov 2016 23:17:45 -0300 Subject: [PATCH 135/169] clock: remove statement of repetead code. --- modules/default/clock/clock.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js index 3fc23ad774..cfd8f52447 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -107,12 +107,6 @@ Module.register("clock",{ if (this.config.showPeriod && this.config.timeFormat !== 24) { timeWrapper.appendChild(periodWrapper); } - if (this.config.displaySeconds) { - timeWrapper.appendChild(secondsWrapper); - } - if (this.config.showPeriod && this.config.timeFormat !== 24) { - timeWrapper.appendChild(periodWrapper); - } /**************************************************************** * Create wrappers for ANALOG clock, only if specified in config From 950fa84d1ce44fc50270aeba19f3864964542b32 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Nov 2016 10:30:49 -0500 Subject: [PATCH 136/169] Added capability to load compliments from the host file system. --- modules/default/compliments/compliments.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/modules/default/compliments/compliments.js b/modules/default/compliments/compliments.js index f05cd9c1b6..3bfdc8be65 100644 --- a/modules/default/compliments/compliments.js +++ b/modules/default/compliments/compliments.js @@ -29,6 +29,7 @@ Module.register("compliments",{ ] }, updateInterval: 30000, + remoteFile: null, fadeSpeed: 4000 }, @@ -46,6 +47,12 @@ Module.register("compliments",{ this.lastComplimentIndex = -1; + if (this.config.remoteFile != null) { + this.complimentFile((response) => { + this.config.compliments = JSON.parse(response); + }); + } + // Schedule update timer. var self = this; setInterval(function() { @@ -104,6 +111,21 @@ Module.register("compliments",{ }, + /* complimentFile(callback) + * Retrieve a file from the local filesystem + */ + complimentFile: function(callback) { + var xobj = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open('GET', this.file(this.config.remoteFile), true); + xobj.onreadystatechange = function () { + if (xobj.readyState == 4 && xobj.status == "200") { + callback(xobj.responseText); + } + }; + xobj.send(null); + }, + /* complimentArray() * Retrieve a random compliment. * From 829ccfca88364aa79d94b94e614bb55b5e647e0b Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Nov 2016 10:31:19 -0500 Subject: [PATCH 137/169] Updated changelog and compliments documentation. --- CHANGELOG.md | 1 + modules/default/compliments/README.md | 38 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5b5d31e22..d3acbcc483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option `disabled` for modules. - Added option `address` to set bind address. - Added option `onlyTemp` for currentweather module to show show only current temperature and weather icon. +- Added option `remoteFile` to compliments module to load compliment array from filesystem. ### Updated - Modified translations for Frysk. diff --git a/modules/default/compliments/README.md b/modules/default/compliments/README.md index 911de4b04b..1dab242a29 100644 --- a/modules/default/compliments/README.md +++ b/modules/default/compliments/README.md @@ -56,6 +56,15 @@ The following properties can be configured:
Default value: See compliment configuration below. + + remoteFile + External file from which to load the compliments
+
Possible values:Path to a JSON file containing compliments, configured + as per the value of the compliments configuration (see below). An object with three arrays: + morning, afternoon and evening. - compliments.json +
Default value: null (Do not load from file) + + @@ -123,3 +132,32 @@ config: { } } ```` + +### External Compliment File +You may specify an external file that contains the three compliment arrays. This is particularly useful if you have a +large number of compliments and do not wish to crowd your `config.js` file with a large array of compliments. +Adding the `remoteFile` variable will override an array you specify in the configuration file. + +This file must be straight JSON. Note that the array names need quotes +around them ("morning", "afternoon", "evening", "snow", "rain", etc.). +#### Example compliments.json file: +````json +{ + "morning" : [ + "Good morning, sunshine!", + "Who needs coffee when you have your smile?", + "Go get 'em, Tiger!" + ], + "afternoon" : [ + "Hitting your stride!", + "You are making a difference!", + "You're more fun than bubble wrap!" + ], + "evening" : [ + "You made someone smile today, I know it.", + "You are making a difference.", + "The day was better for your efforts." + ] +} +```` + From cfeef982617bbb1a99b9f99ce20dedc6c85d2bb4 Mon Sep 17 00:00:00 2001 From: Daniel Buecheler Date: Wed, 30 Nov 2016 21:09:57 +0100 Subject: [PATCH 138/169] Private events are hidden Events with the class:PRIVATE iCal property are not shown in the calendar module. They are not added to the array of calendar events in createEventList. This feature can be turned on and off in the config via the property hidePrivate: true/false. --- modules/default/calendar/calendar.js | 6 ++++++ modules/default/calendar/calendarfetcher.js | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 3151467a58..e643ea9798 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -267,6 +267,12 @@ Module.register("calendar",{ var calendar = this.calendarData[c]; for (var e in calendar) { var event = calendar[e]; + if(this.config.hidePrivate) { + if(event.class === "PRIVATE") { + // do not add the current event, skip it + continue; + } + } event.url = c; event.today = event.startDate >= today && event.startDate < (today + 24 * 60 * 60 * 1000); events.push(event); diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 214e2e5a3e..398fac3f02 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -108,6 +108,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe startDate: startDate.format("x"), endDate: endDate.format("x"), fullDayEvent: isFullDayEvent(event), + class: event.class, firstYear: event.start.getFullYear() }); } @@ -137,7 +138,8 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe title: title, startDate: startDate.format("x"), endDate: endDate.format("x"), - fullDayEvent: fullDayEvent + fullDayEvent: fullDayEvent, + class: event.class }); } From e61bccab3673b54e6801870459ea6b112ffad5d6 Mon Sep 17 00:00:00 2001 From: Daniel Buecheler Date: Wed, 30 Nov 2016 21:24:04 +0100 Subject: [PATCH 139/169] Calendar Module: Added false as default for hidePrivate --- modules/default/calendar/calendar.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index e643ea9798..5e46e9fcfb 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -24,6 +24,7 @@ Module.register("calendar",{ urgency: 7, timeFormat: "relative", fadePoint: 0.25, // Start on 1/4th of the list. + hidePrivate: false, calendars: [ { symbol: "calendar", From c66ecbdd29127ee47d6f4272acfbb6a35e744b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20B=C3=BCcheler?= Date: Wed, 30 Nov 2016 21:28:44 +0100 Subject: [PATCH 140/169] Added hidePrivate to README.md Added explanation of hidePrivate option to the Calendar Module's README --- modules/default/calendar/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 936abdde87..e39fd39391 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -134,6 +134,13 @@ The following properties can be configured:
Default value: 0 (disabled) + + hidePrivate + Hides private calendar events.
+
Possible values: true or false +
Default value: false + + From 7afc908c32d6f64a1caf2597b057ec6a9b04b728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20B=C3=BCcheler?= Date: Wed, 30 Nov 2016 21:28:49 +0100 Subject: [PATCH 141/169] Added hidePrivate option of calendar module --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20f95c84fa..2902363afe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). + +## Unpublished + +### Added +- Calendar module: option to hide private events + +### Fixed + +### Updated + ## [2.0.5] - 2016-09-20 ### Added From c2aec5ae36b59c57e9d63e78f342cbe153c2fafd Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 17:17:58 +0100 Subject: [PATCH 142/169] implemented roundTemperature in weather modules --- modules/default/currentweather/README.md | 7 +++++++ modules/default/currentweather/currentweather.js | 7 ++++++- modules/default/weatherforecast/README.md | 7 +++++++ modules/default/weatherforecast/weatherforecast.js | 13 +++++++++++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 2a6f78445b..e0bb392fa8 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -63,6 +63,13 @@ The following properties can be configured:
Default value: config.units + + roundTemperature + Round temperature value to nearest integer.
+
Possible values: true (round to integer) or false (display exact value with decimal point) +
Default value: false + + updateInterval How often does the content needs to be fetched? (Milliseconds)
diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 5265b099f4..ea548f8014 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -15,6 +15,7 @@ Module.register("currentweather",{ locationID: "", appid: "", units: config.units, + roundTemperature: false, updateInterval: 10 * 60 * 1000, // every 10 minutes animationSpeed: 1000, timeFormat: config.timeFormat, @@ -149,9 +150,13 @@ Module.register("currentweather",{ weatherIcon.className = "wi weathericon " + this.weatherType; large.appendChild(weatherIcon); + var temp = this.temperature; + if (this.config.roundTemperature) { + temp = Math.round(temp); + } var temperature = document.createElement("span"); temperature.className = "bright"; - temperature.innerHTML = " " + this.temperature + "°"; + temperature.innerHTML = " " + temp + "°"; large.appendChild(temperature); wrapper.appendChild(small); diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index aba03a41a8..a2492f7043 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -63,6 +63,13 @@ The following properties can be configured:
Default value: config.units + + roundTemperature + Round temperature values to nearest integer.
+
Possible values: true (round to integer) or false (display exact value with decimal point) +
Default value: false + + maxNumberOfDays How many days of forecast to return. Specified by config.js
diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index a8a8ca6c64..006dd68532 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -15,6 +15,7 @@ Module.register("weatherforecast",{ locationID: "", appid: "", units: config.units, + roundTemperature: false, maxNumberOfDays: 7, updateInterval: 10 * 60 * 1000, // every 10 minutes animationSpeed: 1000, @@ -129,13 +130,20 @@ Module.register("weatherforecast",{ icon.className = "wi weathericon " + forecast.icon; iconCell.appendChild(icon); + var maxTemp = forecast.maxTemp; + var minTemp = forecast.minTemp; + if (this.config.roundTemperature) { + maxTemp = Math.round(maxTemp); + minTemp = Math.round(minTemp); + } + var maxTempCell = document.createElement("td"); - maxTempCell.innerHTML = forecast.maxTemp; + maxTempCell.innerHTML = maxTemp; maxTempCell.className = "align-right bright max-temp"; row.appendChild(maxTempCell); var minTempCell = document.createElement("td"); - minTempCell.innerHTML = forecast.minTemp; + minTempCell.innerHTML = minTemp; minTempCell.className = "align-right min-temp"; row.appendChild(minTempCell); @@ -289,3 +297,4 @@ Module.register("weatherforecast",{ return parseFloat(temperature).toFixed(1); } }); + From 3c33969d23b388df670bd8d0cbfafacee1b56e04 Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 17:17:58 +0100 Subject: [PATCH 143/169] implemented roundTemperature in weather modules --- modules/default/currentweather/README.md | 7 +++++++ modules/default/currentweather/currentweather.js | 7 ++++++- modules/default/weatherforecast/README.md | 7 +++++++ modules/default/weatherforecast/weatherforecast.js | 13 +++++++++++-- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 35c0340447..d71169300e 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -64,6 +64,13 @@ The following properties can be configured:
Default value: config.units + + roundTemperature + Round temperature value to nearest integer.
+
Possible values: true (round to integer) or false (display exact value with decimal point) +
Default value: false + + updateInterval How often does the content needs to be fetched? (Milliseconds)
diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index a379332dce..43b57f4f30 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -15,6 +15,7 @@ Module.register("currentweather",{ locationID: false, appid: "", units: config.units, + roundTemperature: false, updateInterval: 10 * 60 * 1000, // every 10 minutes animationSpeed: 1000, timeFormat: config.timeFormat, @@ -181,9 +182,13 @@ Module.register("currentweather",{ weatherIcon.className = "wi weathericon " + this.weatherType; large.appendChild(weatherIcon); + var temp = this.temperature; + if (this.config.roundTemperature) { + temp = Math.round(temp); + } var temperature = document.createElement("span"); temperature.className = "bright"; - temperature.innerHTML = " " + this.temperature + "°"; + temperature.innerHTML = " " + temp + "°"; large.appendChild(temperature); wrapper.appendChild(large); diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index 6b88d21e9e..8b80e9825c 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -64,6 +64,13 @@ The following properties can be configured:
Default value: config.units + + roundTemperature + Round temperature values to nearest integer.
+
Possible values: true (round to integer) or false (display exact value with decimal point) +
Default value: false + + maxNumberOfDays How many days of forecast to return. Specified by config.js
diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index 51c3f56ea1..014e00cdf4 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -15,6 +15,7 @@ Module.register("weatherforecast",{ locationID: false, appid: "", units: config.units, + roundTemperature: false, maxNumberOfDays: 7, showRainAmount: false, updateInterval: 10 * 60 * 1000, // every 10 minutes @@ -133,13 +134,20 @@ Module.register("weatherforecast",{ icon.className = "wi weathericon " + forecast.icon; iconCell.appendChild(icon); + var maxTemp = forecast.maxTemp; + var minTemp = forecast.minTemp; + if (this.config.roundTemperature) { + maxTemp = Math.round(maxTemp); + minTemp = Math.round(minTemp); + } + var maxTempCell = document.createElement("td"); - maxTempCell.innerHTML = forecast.maxTemp; + maxTempCell.innerHTML = maxTemp; maxTempCell.className = "align-right bright max-temp"; row.appendChild(maxTempCell); var minTempCell = document.createElement("td"); - minTempCell.innerHTML = forecast.minTemp; + minTempCell.innerHTML = minTemp; minTempCell.className = "align-right min-temp"; row.appendChild(minTempCell); @@ -352,3 +360,4 @@ Module.register("weatherforecast",{ return parseFloat(temperature).toFixed(1); } }); + From 32df3e80b135971ac15bc43228d66d84defc50e3 Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 17:33:41 +0100 Subject: [PATCH 144/169] Renamed roundTemperature option to roundTemp Added changelog entry --- CHANGELOG.md | 1 + modules/default/currentweather/README.md | 2 +- modules/default/currentweather/currentweather.js | 6 +++--- modules/default/weatherforecast/README.md | 2 +- modules/default/weatherforecast/weatherforecast.js | 5 +++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3acbcc483..0acfecc91d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option `address` to set bind address. - Added option `onlyTemp` for currentweather module to show show only current temperature and weather icon. - Added option `remoteFile` to compliments module to load compliment array from filesystem. +- Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer. ### Updated - Modified translations for Frysk. diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index d71169300e..335dc0dea1 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -65,7 +65,7 @@ The following properties can be configured: - roundTemperature + roundTemp Round temperature value to nearest integer.

Possible values: true (round to integer) or false (display exact value with decimal point)
Default value: false diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 43b57f4f30..2d5635af3d 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -15,7 +15,6 @@ Module.register("currentweather",{ locationID: false, appid: "", units: config.units, - roundTemperature: false, updateInterval: 10 * 60 * 1000, // every 10 minutes animationSpeed: 1000, timeFormat: config.timeFormat, @@ -37,7 +36,8 @@ Module.register("currentweather",{ calendarClass: "calendar", onlyTemp: false, - + roundTemp: false, + iconTable: { "01d": "wi-day-sunny", "02d": "wi-day-cloudy", @@ -183,7 +183,7 @@ Module.register("currentweather",{ large.appendChild(weatherIcon); var temp = this.temperature; - if (this.config.roundTemperature) { + if (this.config.roundTemp) { temp = Math.round(temp); } var temperature = document.createElement("span"); diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index 8b80e9825c..0cc3e46b6c 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -65,7 +65,7 @@ The following properties can be configured: - roundTemperature + roundTemp Round temperature values to nearest integer.

Possible values: true (round to integer) or false (display exact value with decimal point)
Default value: false diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index 014e00cdf4..6eba014a18 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -15,7 +15,6 @@ Module.register("weatherforecast",{ locationID: false, appid: "", units: config.units, - roundTemperature: false, maxNumberOfDays: 7, showRainAmount: false, updateInterval: 10 * 60 * 1000, // every 10 minutes @@ -35,6 +34,8 @@ Module.register("weatherforecast",{ appendLocationNameToHeader: true, calendarClass: "calendar", + roundTemp: false, + iconTable: { "01d": "wi-day-sunny", "02d": "wi-day-cloudy", @@ -136,7 +137,7 @@ Module.register("weatherforecast",{ var maxTemp = forecast.maxTemp; var minTemp = forecast.minTemp; - if (this.config.roundTemperature) { + if (this.config.roundTemp) { maxTemp = Math.round(maxTemp); minTemp = Math.round(minTemp); } From d67e9468c0e070fbacbeccad24a3d3590bce5868 Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 20:52:36 +0100 Subject: [PATCH 145/169] Changed roundTemp implementation to a cleaner one --- modules/default/currentweather/currentweather.js | 9 +++------ .../default/weatherforecast/weatherforecast.js | 16 +++++----------- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 2d5635af3d..7cdcf51c86 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -182,13 +182,9 @@ Module.register("currentweather",{ weatherIcon.className = "wi weathericon " + this.weatherType; large.appendChild(weatherIcon); - var temp = this.temperature; - if (this.config.roundTemp) { - temp = Math.round(temp); - } var temperature = document.createElement("span"); temperature.className = "bright"; - temperature.innerHTML = " " + temp + "°"; + temperature.innerHTML = " " + this.temperature + "°"; large.appendChild(temperature); wrapper.appendChild(large); @@ -436,6 +432,7 @@ Module.register("currentweather",{ roundValue: function(temperature) { - return parseFloat(temperature).toFixed(1); + var decimals = this.config.roundTemp ? 0 : 1; + return parseFloat(temperature).toFixed(decimals); } }); diff --git a/modules/default/weatherforecast/weatherforecast.js b/modules/default/weatherforecast/weatherforecast.js index 6eba014a18..5078c9b60c 100644 --- a/modules/default/weatherforecast/weatherforecast.js +++ b/modules/default/weatherforecast/weatherforecast.js @@ -135,20 +135,13 @@ Module.register("weatherforecast",{ icon.className = "wi weathericon " + forecast.icon; iconCell.appendChild(icon); - var maxTemp = forecast.maxTemp; - var minTemp = forecast.minTemp; - if (this.config.roundTemp) { - maxTemp = Math.round(maxTemp); - minTemp = Math.round(minTemp); - } - var maxTempCell = document.createElement("td"); - maxTempCell.innerHTML = maxTemp; + maxTempCell.innerHTML = forecast.maxTemp; maxTempCell.className = "align-right bright max-temp"; row.appendChild(maxTempCell); var minTempCell = document.createElement("td"); - minTempCell.innerHTML = minTemp; + minTempCell.innerHTML = forecast.minTemp; minTempCell.className = "align-right min-temp"; row.appendChild(minTempCell); @@ -351,14 +344,15 @@ Module.register("weatherforecast",{ }, /* function(temperature) - * Rounds a temperature to 1 decimal. + * Rounds a temperature to 1 decimal or integer (depending on config.roundTemp). * * argument temperature number - Temperature. * * return number - Rounded Temperature. */ roundValue: function(temperature) { - return parseFloat(temperature).toFixed(1); + var decimals = this.config.roundTemp ? 0 : 1; + return parseFloat(temperature).toFixed(decimals); } }); From 4d8d30f89731a2530c4f8e10c3a43f7d942e30ad Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 20:53:02 +0100 Subject: [PATCH 146/169] Moved misplaced method signature --- modules/default/currentweather/currentweather.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 7cdcf51c86..46cb7dd664 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -386,14 +386,6 @@ Module.register("currentweather",{ return 12; }, - /* function(temperature) - * Rounds a temperature to 1 decimal. - * - * argument temperature number - Temperature. - * - * return number - Rounded Temperature. - */ - deg2Cardinal: function(deg) { if (deg>11.25 && deg<=33.75){ return "NNE"; @@ -430,7 +422,13 @@ Module.register("currentweather",{ } }, - + /* function(temperature) + * Rounds a temperature to 1 decimal. + * + * argument temperature number - Temperature. + * + * return number - Rounded Temperature. + */ roundValue: function(temperature) { var decimals = this.config.roundTemp ? 0 : 1; return parseFloat(temperature).toFixed(decimals); From 89bc3137ba8ab44702cf0333acb19f3e1a20358a Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 20:56:10 +0100 Subject: [PATCH 147/169] Fixed method description. --- modules/default/currentweather/currentweather.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index 46cb7dd664..ab48b91105 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -423,7 +423,7 @@ Module.register("currentweather",{ }, /* function(temperature) - * Rounds a temperature to 1 decimal. + * Rounds a temperature to 1 decimal or integer (depending on config.roundTemp). * * argument temperature number - Temperature. * From a08fa721cfca454994484b11f0956c3cc00a8cd5 Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 21:05:36 +0100 Subject: [PATCH 148/169] Added zoom factor config value and Electron option --- js/defaults.js | 3 ++- js/electron.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/js/defaults.js b/js/defaults.js index 0f27e81743..b48edb21cc 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -11,10 +11,11 @@ var defaults = { port: 8080, kioskmode: false, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], - + language: "en", timeFormat: 24, units: "metric", + zoom: 1, modules: [ { diff --git a/js/electron.js b/js/electron.js index 75dc47fda8..6b4c935a7e 100644 --- a/js/electron.js +++ b/js/electron.js @@ -20,9 +20,9 @@ let mainWindow; function createWindow() { // Create the browser window. if (config.kioskmode) { - mainWindow = new BrowserWindow({width: 800, height: 600, x: 0, y: 0, kiosk:true, darkTheme: true, webPreferences: {nodeIntegration: false}}); + mainWindow = new BrowserWindow({width: 800, height: 600, x: 0, y: 0, kiosk:true, darkTheme: true, webPreferences: {nodeIntegration: false, zoomFactor: config.zoom}}); } else { - mainWindow = new BrowserWindow({width: 800, height: 600, x: 0, y: 0, fullscreen: true, autoHideMenuBar: true, darkTheme: true, webPreferences: {nodeIntegration: false}}); + mainWindow = new BrowserWindow({width: 800, height: 600, x: 0, y: 0, fullscreen: true, autoHideMenuBar: true, darkTheme: true, webPreferences: {nodeIntegration: false, zoomFactor: config.zoom}}); } // and load the index.html of the app. From c8d5a5319e4349d1272f89b274401969312e72f8 Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 21:09:16 +0100 Subject: [PATCH 149/169] Clean up duplicate code in Electron options --- js/electron.js | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/js/electron.js b/js/electron.js index 6b4c935a7e..589c265c94 100644 --- a/js/electron.js +++ b/js/electron.js @@ -18,13 +18,29 @@ const BrowserWindow = electron.BrowserWindow; let mainWindow; function createWindow() { - // Create the browser window. + + var electronOptions = { + width: 800, + height: 600, + x: 0, + y: 0, + darkTheme: true, + webPreferences: { + nodeIntegration: false, + zoomFactor: config.zoom + } + } + if (config.kioskmode) { - mainWindow = new BrowserWindow({width: 800, height: 600, x: 0, y: 0, kiosk:true, darkTheme: true, webPreferences: {nodeIntegration: false, zoomFactor: config.zoom}}); + electronOptions.kiosk = true; } else { - mainWindow = new BrowserWindow({width: 800, height: 600, x: 0, y: 0, fullscreen: true, autoHideMenuBar: true, darkTheme: true, webPreferences: {nodeIntegration: false, zoomFactor: config.zoom}}); + electronOptions.fullscreen = true; + electronOptions.autoHideMenuBar = true; } + // Create the browser window. + mainWindow = new BrowserWindow(electronOptions); + // and load the index.html of the app. //mainWindow.loadURL('file://' + __dirname + '../../index.html'); mainWindow.loadURL("http://localhost:" + config.port); From 7d08a7c9cd6fbffa3076eef3522c6b610e9e01e6 Mon Sep 17 00:00:00 2001 From: Olexandr Savchuk Date: Fri, 2 Dec 2016 21:14:41 +0100 Subject: [PATCH 150/169] Added documentation and changelog entry. --- CHANGELOG.md | 1 + README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3acbcc483..466bae6727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option `address` to set bind address. - Added option `onlyTemp` for currentweather module to show show only current temperature and weather icon. - Added option `remoteFile` to compliments module to load compliment array from filesystem. +- Added option `zoom` to scale the whole mirror display with a given factor. ### Updated - Modified translations for Frysk. diff --git a/README.md b/README.md index e087b4cca1..4476447d26 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ The following properties can be configured: | `address` | The ip address the accept connections. The default open bind `::` is IPv6 is available or `0.0.0.0` IPv4 run on. Example config: `192.168.10.100`. | | `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1", "::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| | `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| +| `zoom` | This allows to scale the mirror contents with a given zoom factor. The default value is `1.0`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | | `units` | The units that will be used in the default weather modules. Possible values are `metric` or `imperial`. The default is `metric`. | From 8ad00025ad6106c82c6a71c916e9e67dd93c3b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 1 Dec 2016 19:15:28 -0300 Subject: [PATCH 151/169] use Gruntfile into modules/default/* --- Gruntfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index c47f55b933..aa8420b361 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,7 +6,7 @@ module.exports = function(grunt) { options: { configFile: ".eslintrc.json" }, - target: ["js/*.js", "modules/default/*.js", "serveronly/*.js", "*.js"] + target: ["js/*.js", "modules/default/*.js", "modules/default/*/*.js", "serveronly/*.js", "*.js"] }, stylelint: { simple: { @@ -63,4 +63,4 @@ module.exports = function(grunt) { grunt.loadNpmTasks("grunt-yamllint"); grunt.loadNpmTasks("grunt-markdownlint"); grunt.registerTask("default", ["eslint", "stylelint", "jsonlint", "markdownlint", "yamllint"]); -}; \ No newline at end of file +}; From 83ee0534f27a5e95e3b2f3d6abb096193059b247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 1 Dec 2016 19:48:53 -0300 Subject: [PATCH 152/169] fixed eslint error into modules for Javascript files --- Gruntfile.js | 5 +- modules/default/calendar/debug.js | 10 +-- modules/default/clock/clock.js | 34 ++++----- modules/default/compliments/compliments.js | 34 ++++----- .../default/currentweather/currentweather.js | 76 +++++++++---------- modules/default/newsfeed/fetcher.js | 6 +- modules/default/newsfeed/newsfeed.js | 36 +++++---- modules/default/newsfeed/node_helper.js | 4 +- .../default/updatenotification/node_helper.js | 2 +- .../updatenotification/updatenotification.js | 2 +- 10 files changed, 110 insertions(+), 99 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index aa8420b361..ec3128efad 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,7 +6,10 @@ module.exports = function(grunt) { options: { configFile: ".eslintrc.json" }, - target: ["js/*.js", "modules/default/*.js", "modules/default/*/*.js", "serveronly/*.js", "*.js"] + target: ["js/*.js", "modules/default/*.js", "modules/default/*/*.js", + "serveronly/*.js", "*.js", "!modules/default/alert/notificationFx.js", + "!modules/default/alert/modernizr.custom.js", "!modules/default/alert/classie.js" + ] }, stylelint: { simple: { diff --git a/modules/default/calendar/debug.js b/modules/default/calendar/debug.js index bc0adae6d5..d52cdc9f17 100644 --- a/modules/default/calendar/debug.js +++ b/modules/default/calendar/debug.js @@ -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! "); diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js index cfd8f52447..4455b15afe 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -8,7 +8,7 @@ Module.register("clock",{ // Module config defaults. defaults: { - displayType: 'digital', // options: digital, analog, both + displayType: "digital", // options: digital, analog, both timeFormat: config.timeFormat, displaySeconds: true, @@ -18,11 +18,11 @@ Module.register("clock",{ showDate: true, /* specific to the analog clock */ - analogSize: '200px', - analogFace: 'simple', // options: 'none', 'simple', 'face-###' (where ### is 001 to 012 inclusive) - analogPlacement: 'bottom', // options: 'top', 'bottom', 'left', 'right' - analogShowDate: 'top', // options: false, 'top', or 'bottom' - secondsColor: '#888888', + analogSize: "200px", + analogFace: "simple", // options: 'none', 'simple', 'face-###' (where ### is 001 to 012 inclusive) + analogPlacement: "bottom", // options: 'top', 'bottom', 'left', 'right' + analogShowDate: "top", // options: false, 'top', or 'bottom' + secondsColor: "#888888", timezone: null, }, // Define required scripts. @@ -92,7 +92,7 @@ Module.register("clock",{ } } if(this.config.showDate){ - dateWrapper.innerHTML = now.format("dddd, LL"); + dateWrapper.innerHTML = now.format("dddd, LL"); } timeWrapper.innerHTML = timeString; secondsWrapper.innerHTML = now.format("ss"); @@ -112,7 +112,7 @@ Module.register("clock",{ * Create wrappers for ANALOG clock, only if specified in config */ - if (this.config.displayType !== 'digital') { + if (this.config.displayType !== "digital") { // If it isn't 'digital', then an 'analog' clock was also requested // Calculate the degree offset for each hand of the clock @@ -131,10 +131,10 @@ Module.register("clock",{ clockCircle.style.width = this.config.analogSize; clockCircle.style.height = this.config.analogSize; - if (this.config.analogFace != '' && this.config.analogFace != 'simple' && this.config.analogFace != 'none') { + if (this.config.analogFace != "" && this.config.analogFace != "simple" && this.config.analogFace != "none") { clockCircle.style.background = "url("+ this.data.path + "faces/" + this.config.analogFace + ".svg)"; clockCircle.style.backgroundSize = "100%"; - } else if (this.config.analogFace != 'none') { + } else if (this.config.analogFace != "none") { clockCircle.style.border = "2px solid white"; } var clockFace = document.createElement("div"); @@ -168,18 +168,18 @@ Module.register("clock",{ * Combine wrappers, check for .displayType */ - if (this.config.displayType === 'digital') { + if (this.config.displayType === "digital") { // Display only a digital clock wrapper.appendChild(dateWrapper); wrapper.appendChild(timeWrapper); - } else if (this.config.displayType === 'analog') { + } else if (this.config.displayType === "analog") { // Display only an analog clock dateWrapper.style.textAlign = "center"; dateWrapper.style.paddingBottom = "15px"; - if (this.config.analogShowDate === 'top') { + if (this.config.analogShowDate === "top") { wrapper.appendChild(dateWrapper); wrapper.appendChild(clockCircle); - } else if (this.config.analogShowDate === 'bottom') { + } else if (this.config.analogShowDate === "bottom") { wrapper.appendChild(clockCircle); wrapper.appendChild(dateWrapper); } else { @@ -199,11 +199,11 @@ Module.register("clock",{ digitalWrapper.appendChild(dateWrapper); digitalWrapper.appendChild(timeWrapper); - if (placement === 'left' || placement === 'right') { + if (placement === "left" || placement === "right") { digitalWrapper.style.display = "inline-block"; digitalWrapper.style.verticalAlign = "top"; analogWrapper.style.display = "inline-block"; - if (placement === 'left') { + if (placement === "left") { analogWrapper.style.padding = "0 20px 0 0"; wrapper.appendChild(analogWrapper); wrapper.appendChild(digitalWrapper); @@ -214,7 +214,7 @@ Module.register("clock",{ } } else { digitalWrapper.style.textAlign = "center"; - if (placement === 'top') { + if (placement === "top") { analogWrapper.style.padding = "0 0 20px 0"; wrapper.appendChild(analogWrapper); wrapper.appendChild(digitalWrapper); diff --git a/modules/default/compliments/compliments.js b/modules/default/compliments/compliments.js index 3bfdc8be65..cabda03f54 100644 --- a/modules/default/compliments/compliments.js +++ b/modules/default/compliments/compliments.js @@ -29,7 +29,7 @@ Module.register("compliments",{ ] }, updateInterval: 30000, - remoteFile: null, + remoteFile: null, fadeSpeed: 4000 }, @@ -47,11 +47,11 @@ Module.register("compliments",{ this.lastComplimentIndex = -1; - if (this.config.remoteFile != null) { - this.complimentFile((response) => { - this.config.compliments = JSON.parse(response); - }); - } + if (this.config.remoteFile != null) { + this.complimentFile((response) => { + this.config.compliments = JSON.parse(response); + }); + } // Schedule update timer. var self = this; @@ -114,17 +114,17 @@ Module.register("compliments",{ /* complimentFile(callback) * Retrieve a file from the local filesystem */ - complimentFile: function(callback) { - var xobj = new XMLHttpRequest(); - xobj.overrideMimeType("application/json"); - xobj.open('GET', this.file(this.config.remoteFile), true); - xobj.onreadystatechange = function () { - if (xobj.readyState == 4 && xobj.status == "200") { - callback(xobj.responseText); - } - }; - xobj.send(null); - }, + complimentFile: function(callback) { + var xobj = new XMLHttpRequest(); + xobj.overrideMimeType("application/json"); + xobj.open("GET", this.file(this.config.remoteFile), true); + xobj.onreadystatechange = function () { + if (xobj.readyState == 4 && xobj.status == "200") { + callback(xobj.responseText); + } + }; + xobj.send(null); + }, /* complimentArray() * Retrieve a random compliment. diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index a379332dce..35b392ae35 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -165,7 +165,7 @@ Module.register("currentweather",{ } if (!this.loaded) { - wrapper.innerHTML = this.translate('LOADING'); + wrapper.innerHTML = this.translate("LOADING"); wrapper.className = "dimmed light small"; return wrapper; } @@ -322,20 +322,20 @@ Module.register("currentweather",{ // So we need to generate the timestring manually. // See issue: https://github.com/MichMich/MagicMirror/issues/181 var sunriseSunsetDateObject = (sunrise < now && sunset > now) ? sunset : sunrise; - var timeString = moment(sunriseSunsetDateObject).format('HH:mm'); + var timeString = moment(sunriseSunsetDateObject).format("HH:mm"); if (this.config.timeFormat !== 24) { //var hours = sunriseSunsetDateObject.getHours() % 12 || 12; if (this.config.showPeriod) { if (this.config.showPeriodUpper) { //timeString = hours + moment(sunriseSunsetDateObject).format(':mm A'); - timeString = moment(sunriseSunsetDateObject).format('h:mm A'); + timeString = moment(sunriseSunsetDateObject).format("h:mm A"); } else { //timeString = hours + moment(sunriseSunsetDateObject).format(':mm a'); - timeString = moment(sunriseSunsetDateObject).format('h:mm a'); + timeString = moment(sunriseSunsetDateObject).format("h:mm a"); } } else { //timeString = hours + moment(sunriseSunsetDateObject).format(':mm'); - timeString = moment(sunriseSunsetDateObject).format('h:mm'); + timeString = moment(sunriseSunsetDateObject).format("h:mm"); } } @@ -394,39 +394,39 @@ Module.register("currentweather",{ */ deg2Cardinal: function(deg) { - if (deg>11.25 && deg<=33.75){ - return "NNE"; - } else if (deg > 33.75 && deg <= 56.25) { - return "NE"; - } else if (deg > 56.25 && deg <= 78.75) { - return "ENE"; - } else if (deg > 78.75 && deg <= 101.25) { - return "E"; - } else if (deg > 101.25 && deg <= 123.75) { - return "ESE"; - } else if (deg > 123.75 && deg <= 146.25) { - return "SE"; - } else if (deg > 146.25 && deg <= 168.75) { - return "SSE"; - } else if (deg > 168.75 && deg <= 191.25) { - return "S"; - } else if (deg > 191.25 && deg <= 213.75) { - return "SSW"; - } else if (deg > 213.75 && deg <= 236.25) { - return "SW"; - } else if (deg > 236.25 && deg <= 258.75) { - return "WSW"; - } else if (deg > 258.75 && deg <= 281.25) { - return "W"; - } else if (deg > 281.25 && deg <= 303.75) { - return "WNW"; - } else if (deg > 303.75 && deg <= 326.25) { - return "NW"; - } else if (deg > 326.25 && deg <= 348.75) { - return "NNW"; - } else { - return "N"; - } + if (deg>11.25 && deg<=33.75){ + return "NNE"; + } else if (deg > 33.75 && deg <= 56.25) { + return "NE"; + } else if (deg > 56.25 && deg <= 78.75) { + return "ENE"; + } else if (deg > 78.75 && deg <= 101.25) { + return "E"; + } else if (deg > 101.25 && deg <= 123.75) { + return "ESE"; + } else if (deg > 123.75 && deg <= 146.25) { + return "SE"; + } else if (deg > 146.25 && deg <= 168.75) { + return "SSE"; + } else if (deg > 168.75 && deg <= 191.25) { + return "S"; + } else if (deg > 191.25 && deg <= 213.75) { + return "SSW"; + } else if (deg > 213.75 && deg <= 236.25) { + return "SW"; + } else if (deg > 236.25 && deg <= 258.75) { + return "WSW"; + } else if (deg > 258.75 && deg <= 281.25) { + return "W"; + } else if (deg > 281.25 && deg <= 303.75) { + return "WNW"; + } else if (deg > 303.75 && deg <= 326.25) { + return "NW"; + } else if (deg > 326.25 && deg <= 348.75) { + return "NNW"; + } else { + return "N"; + } }, diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/fetcher.js index 8d920eec75..3b0d251690 100644 --- a/modules/default/newsfeed/fetcher.js +++ b/modules/default/newsfeed/fetcher.js @@ -44,9 +44,9 @@ var Fetcher = function(url, reloadInterval, encoding) { parser.on("item", function(item) { var title = item.title; - var description = item.description || item.summary || item.content || ''; + var description = item.description || item.summary || item.content || ""; var pubdate = item.pubdate || item.published || item.updated; - var url = item.url || item.link || ''; + var url = item.url || item.link || ""; if (title && pubdate) { @@ -81,7 +81,7 @@ var Fetcher = function(url, reloadInterval, encoding) { scheduleTimer(); }); - var headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A'}; + var headers = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A"}; request({uri: url, encoding: null, headers: headers}).pipe(iconv.decodeStream(encoding)).pipe(parser); }; diff --git a/modules/default/newsfeed/newsfeed.js b/modules/default/newsfeed/newsfeed.js index 7d8d08c7ed..32fdabdf89 100644 --- a/modules/default/newsfeed/newsfeed.js +++ b/modules/default/newsfeed/newsfeed.js @@ -25,8 +25,8 @@ Module.register("newsfeed",{ updateInterval: 10 * 1000, animationSpeed: 2.5 * 1000, maxNewsItems: 0, // 0 for unlimited - removeStartTags: '', - removeEndTags: '', + removeStartTags: "", + removeEndTags: "", startTags: [], endTags: [] @@ -93,33 +93,41 @@ Module.register("newsfeed",{ var sourceAndTimestamp = document.createElement("div"); sourceAndTimestamp.className = "light small dimmed"; - if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== '') sourceAndTimestamp.innerHTML = this.newsItems[this.activeItem].sourceTitle; - if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== '' && this.config.showPublishDate) sourceAndTimestamp.innerHTML += ', '; - if (this.config.showPublishDate) sourceAndTimestamp.innerHTML += moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow(); - if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== '' || this.config.showPublishDate) sourceAndTimestamp.innerHTML += ':'; + if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "") { + sourceAndTimestamp.innerHTML = this.newsItems[this.activeItem].sourceTitle; + } + if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "" && this.config.showPublishDate) { + sourceAndTimestamp.innerHTML += ", "; + } + if (this.config.showPublishDate) { + sourceAndTimestamp.innerHTML += moment(new Date(this.newsItems[this.activeItem].pubdate)).fromNow(); + } + if (this.config.showSourceTitle && this.newsItems[this.activeItem].sourceTitle !== "" || this.config.showPublishDate) { + sourceAndTimestamp.innerHTML += ":"; + } wrapper.appendChild(sourceAndTimestamp); } //Remove selected tags from the beginning of rss feed items (title or description) - if (this.config.removeStartTags == 'title' || 'both') { + if (this.config.removeStartTags == "title" || "both") { for (f=0; f Date: Tue, 6 Dec 2016 19:57:38 +0100 Subject: [PATCH 153/169] Fetch remote git only if repo has a remote --- modules/default/updatenotification/node_helper.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/modules/default/updatenotification/node_helper.js b/modules/default/updatenotification/node_helper.js index 6147c061ed..b8e58a7def 100644 --- a/modules/default/updatenotification/node_helper.js +++ b/modules/default/updatenotification/node_helper.js @@ -29,7 +29,18 @@ module.exports = NodeHelper.create({ continue; } - simpleGits.push({"module": moduleName, "git": SimpleGit(moduleFolder)}); + var res = function(mn, mf) { + var git = SimpleGit(mf); + git.getRemotes(true, function(err, remotes) { + if (remotes.length < 1 || remotes[0].name.length < 1) { + // No valid remote for folder, skip + return; + } + + // Folder has .git and has at least one git remote, watch this folder + simpleGits.push({"module": mn, "git": git}); + }); + }(moduleName, moduleFolder); } } From 9e2bbd50b6ab491283e624cc43dff2bb07ea6616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Wed, 7 Dec 2016 21:50:06 -0300 Subject: [PATCH 154/169] README compliments: Close code tag and fix tabs --- modules/default/compliments/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/default/compliments/README.md b/modules/default/compliments/README.md index 1dab242a29..ac410d30d3 100644 --- a/modules/default/compliments/README.md +++ b/modules/default/compliments/README.md @@ -57,14 +57,14 @@ The following properties can be configured: - remoteFile - External file from which to load the compliments
-
Possible values:Path to a JSON file containing compliments, configured - as per the value of the compliments configuration (see below). An object with three arrays: - morning, afternoon and evening. - compliments.json -
Default value: null (Do not load from file) - - + remoteFile + External file from which to load the compliments
+
Possible values:Path to a JSON file containing compliments, configured + as per the value of the compliments configuration (see below). An object with three arrays: + morning, afternoon and evening. - compliments.json +
Default value: null (Do not load from file) + + @@ -89,7 +89,7 @@ If use the currentweather is possible use a actual weather for set compliments. * night_rain * night_thunderstorm * night_snow -* night_alt_cloudy_windy +* night_alt_cloudy_windy #### Example use with currentweather module ````javascript From 9b86049964bd05a7aec8ac9ae89f6582df9cd6dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 8 Dec 2016 01:29:55 -0300 Subject: [PATCH 155/169] newsfeed, calendar: Standardize user-agent. Add node and MagicMirror version. --- modules/default/calendar/calendarfetcher.js | 3 ++- modules/default/newsfeed/fetcher.js | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 0881afb364..cb989edf12 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -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/)" } }; diff --git a/modules/default/newsfeed/fetcher.js b/modules/default/newsfeed/fetcher.js index 8d920eec75..3b45a3b505 100644 --- a/modules/default/newsfeed/fetcher.js +++ b/modules/default/newsfeed/fetcher.js @@ -81,7 +81,9 @@ var Fetcher = function(url, reloadInterval, encoding) { scheduleTimer(); }); - var headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A'}; + nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]); + headers = {"User-Agent": "Mozilla/5.0 (Node.js "+ nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)"} + request({uri: url, encoding: null, headers: headers}).pipe(iconv.decodeStream(encoding)).pipe(parser); }; From 53d2c7e89fd662789bea98e4cc0d74560368821d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Wed, 7 Dec 2016 22:00:12 -0300 Subject: [PATCH 156/169] compliments: add abilty to set classes for compliments module --- CHANGELOG.md | 1 + modules/default/compliments/compliments.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f757b0bfcd..673b5669e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option `remoteFile` to compliments module to load compliment array from filesystem. - Added option `zoom` to scale the whole mirror display with a given factor. - Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer. +- Added abilty set the classes option to compliments module for style and text size of compliments. ### Updated - Modified translations for Frysk. diff --git a/modules/default/compliments/compliments.js b/modules/default/compliments/compliments.js index 3bfdc8be65..e43abe0ddd 100644 --- a/modules/default/compliments/compliments.js +++ b/modules/default/compliments/compliments.js @@ -144,7 +144,7 @@ Module.register("compliments",{ var compliment = document.createTextNode(complimentText); var wrapper = document.createElement("div"); - wrapper.className = "thin xlarge bright"; + wrapper.className = this.config.classes ? this.config.classes : "thin xlarge bright"; wrapper.appendChild(compliment); return wrapper; From 21bf1dd1a36867ccc3e8035ca1ce906183334e89 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 12 Dec 2016 14:52:00 +0100 Subject: [PATCH 157/169] Updated module READMEs with current default values --- modules/default/calendar/README.md | 2 +- modules/default/calendar/calendar.js | 5 +---- modules/default/currentweather/README.md | 6 +++--- modules/default/newsfeed/README.md | 1 + modules/default/weatherforecast/README.md | 10 +++++----- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 29a593aaa4..96ad556145 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -144,7 +144,7 @@ The following properties can be configured: When using a timeFormat of absolute, the urgency setting allows you to display events within a specific time frame as relative This allows events within a certain time frame to be displayed as relative (in xx days) while others are displayed as absolute dates

Possible values: a positive integer representing the number of days for which you want a relative date, for example 7 (for 7 days)
-
Default value: 0 (disabled) +
Default value: 7 diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 6282d13053..d112b2379d 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -32,10 +32,7 @@ Module.register("calendar", { url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics", }, ], - titleReplace: { - "De verjaardag van ": "", - "'s birthday": "" - }, + titleReplace: {}, broadcastEvents: true }, diff --git a/modules/default/currentweather/README.md b/modules/default/currentweather/README.md index 335dc0dea1..ccef543cd6 100644 --- a/modules/default/currentweather/README.md +++ b/modules/default/currentweather/README.md @@ -39,7 +39,7 @@ The following properties can be configured: location The location used for weather information.

Example: 'Amsterdam,Netherlands' -
Default value: New York

+
Default value: false

Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. @@ -47,7 +47,7 @@ The following properties can be configured: locationID Location ID from OpenWeatherMap This will override anything you put in location.
Leave blank if you want to use location.
Example: 1234567 -
Default value:

+
Default value: false

Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. @@ -82,7 +82,7 @@ The following properties can be configured: animationSpeed Speed of the update animation. (Milliseconds)

Possible values:0 - 5000 -
Default value: 2000 (2 seconds) +
Default value: 1000 (1 second) diff --git a/modules/default/newsfeed/README.md b/modules/default/newsfeed/README.md index e177be255b..baaf5ac34e 100644 --- a/modules/default/newsfeed/README.md +++ b/modules/default/newsfeed/README.md @@ -53,6 +53,7 @@ The following properties can be configured: { title: "New York Times", url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml", + encoding: "UTF-8" //ISO-8859-1 } ]
diff --git a/modules/default/weatherforecast/README.md b/modules/default/weatherforecast/README.md index 0cc3e46b6c..2842af54f1 100644 --- a/modules/default/weatherforecast/README.md +++ b/modules/default/weatherforecast/README.md @@ -39,7 +39,7 @@ The following properties can be configured: location The location used for weather information.

Example: 'Amsterdam,Netherlands' -
Default value: New York

+
Default value: false

Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. @@ -47,7 +47,7 @@ The following properties can be configured: locationID Location ID from OpenWeatherMap This will override anything you put in location.
Leave blank if you want to use location.
Example: 1234567 -
Default value:

+
Default value: false

Note: When the location and locationID are both not set, the location will be based on the information provided by the calendar module. The first upcoming event with location data will be used. @@ -98,7 +98,7 @@ The following properties can be configured: animationSpeed Speed of the update animation. (Milliseconds)

Possible values:0 - 5000 -
Default value: 2000 (2 seconds) +
Default value: 1000 (1 second) @@ -126,7 +126,7 @@ The following properties can be configured: initialLoadDelay The initial delay before loading. If you have multiple modules that use the same API key, you might want to delay one of the requests. (Milliseconds)

Possible values: 1000 - 5000 -
Default value: 0 +
Default value: 2500 (2.5 seconds delay. This delay is used to keep the OpenWeather API happy.) @@ -149,7 +149,7 @@ The following properties can be configured: - weatherEndpoint + forecastEndpoint The OpenWeatherMap API endPoint.

Default value: 'forecast/daily' From 6c1dbc5e61e8a5e6b7b34060918857e22f1c3beb Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 12 Dec 2016 14:55:07 +0100 Subject: [PATCH 158/169] Updated module READMEs with current default values --- modules/default/newsfeed/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/newsfeed/README.md b/modules/default/newsfeed/README.md index baaf5ac34e..21d3910e1b 100644 --- a/modules/default/newsfeed/README.md +++ b/modules/default/newsfeed/README.md @@ -53,7 +53,7 @@ The following properties can be configured: { title: "New York Times", url: "http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml", - encoding: "UTF-8" //ISO-8859-1 + encoding: "UTF-8" } ]
From 3c11c3fc16101d6e2afa48e1638a68ca8f82db6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 13 Dec 2016 00:33:29 -0300 Subject: [PATCH 159/169] splashscreen: remove flag not used into script plymouth --- splashscreen/MagicMirror.script | 2 -- 1 file changed, 2 deletions(-) diff --git a/splashscreen/MagicMirror.script b/splashscreen/MagicMirror.script index d7e7b8607c..9b6143898b 100644 --- a/splashscreen/MagicMirror.script +++ b/splashscreen/MagicMirror.script @@ -8,8 +8,6 @@ image_height = theme_image.GetHeight(); scale_x = image_width / screen_width; scale_y = image_height / screen_height; -flag = 1; - if (scale_x > 1 || scale_y > 1) { if (scale_x > scale_y) From 6a184b069be952c6c23cce432d5e0650e79dcc03 Mon Sep 17 00:00:00 2001 From: Andreas 'count' Kotes Date: Sat, 10 Dec 2016 17:02:54 +0100 Subject: [PATCH 160/169] make electronOptions configurable, remove kioskmode from documentation --- CHANGELOG.md | 1 + README.md | 2 +- js/defaults.js | 1 + js/electron.js | 12 ++++++++---- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 673b5669e1..fb41a8de89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added option `zoom` to scale the whole mirror display with a given factor. - Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer. - Added abilty set the classes option to compliments module for style and text size of compliments. +- Added ability to configure electronOptions ### Updated - Modified translations for Frysk. diff --git a/README.md b/README.md index 4476447d26..7c5286ddb4 100644 --- a/README.md +++ b/README.md @@ -78,12 +78,12 @@ The following properties can be configured: | `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. | | `address` | The ip address the accept connections. The default open bind `::` is IPv6 is available or `0.0.0.0` IPv4 run on. Example config: `192.168.10.100`. | | `ipWhitelist` | The list of IPs from which you are allowed to access the MagicMirror². The default value is `["127.0.0.1", "::ffff:127.0.0.1", "::1"]`. It is possible to specify IPs with subnet masks (`["127.0.0.1", "127.0.0.1/24"]`) or define ip ranges (`["127.0.0.1", ["192.168.0.1", "192.168.0.100"]]`).| -| `kioskmode` | This allows MagicMirror² to run in Kiosk Mode. It protects from other programs popping on top of your screen. The default value is `false`| | `zoom` | This allows to scale the mirror contents with a given zoom factor. The default value is `1.0`| | `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. | | `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. | | `units` | The units that will be used in the default weather modules. Possible values are `metric` or `imperial`. The default is `metric`. | | `modules` | An array of active modules. **The array must contain objects. See the next table below for more information.** | +| `electronOptions` | An optional array of Electron (browser) options. This allows configuration of e.g. the browser screen size and position (defaults `.width = 800` & `.height = 600`). Kiosk mode can be enabled by setting `.kiosk = true`, `.autoHideMenuBar = false`, `.fullscreen = false`. More options can be found [here](https://github.com/electron/electron/blob/master/docs/api/browser-window.md). | Module configuration: diff --git a/js/defaults.js b/js/defaults.js index b48edb21cc..b5b11561db 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -10,6 +10,7 @@ var defaults = { port: 8080, kioskmode: false, + electronOptions: {}, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], language: "en", diff --git a/js/electron.js b/js/electron.js index 589c265c94..edd4896b24 100644 --- a/js/electron.js +++ b/js/electron.js @@ -19,7 +19,7 @@ let mainWindow; function createWindow() { - var electronOptions = { + var electronOptionsDefaults = { width: 800, height: 600, x: 0, @@ -31,13 +31,17 @@ function createWindow() { } } + // DEPRECATED: "kioskmode" backwards compatibility, to be removed + // settings these options directly instead provides cleaner interface if (config.kioskmode) { - electronOptions.kiosk = true; + electronOptionsDefaults.kiosk = true; } else { - electronOptions.fullscreen = true; - electronOptions.autoHideMenuBar = true; + electronOptionsDefaults.fullscreen = true; + electronOptionsDefaults.autoHideMenuBar = true; } + var electronOptions = Object.assign({}, electronOptionsDefaults, config.electronOptions); + // Create the browser window. mainWindow = new BrowserWindow(electronOptions); From de71b1b3976b2f896fcd8c162f6fc1ef24cd8649 Mon Sep 17 00:00:00 2001 From: Andreas Date: Tue, 13 Dec 2016 17:16:46 +0100 Subject: [PATCH 161/169] Revert calendar default value and add documentation --- modules/default/calendar/README.md | 7 +++++++ modules/default/calendar/calendar.js | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index 96ad556145..31eb1e2fb8 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -109,6 +109,13 @@ The following properties can be configured: titleReplace: {'Birthday of ' : '', 'foo':'bar'} +
Default value: + + { + "De verjaardag van ": "", + "'s birthday": "" + } + diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index d112b2379d..6282d13053 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -32,7 +32,10 @@ Module.register("calendar", { url: "http://www.calendarlabs.com/templates/ical/US-Holidays.ics", }, ], - titleReplace: {}, + titleReplace: { + "De verjaardag van ": "", + "'s birthday": "" + }, broadcastEvents: true }, From 243cdfefa230f27f090a01ea176d4dff3019d476 Mon Sep 17 00:00:00 2001 From: Daniel Buecheler Date: Thu, 22 Dec 2016 22:00:59 +0100 Subject: [PATCH 162/169] Fix failed linter test --- modules/default/calendar/calendarfetcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 93be83f0b8..e24ee004a4 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -149,7 +149,7 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe startDate: startDate.format("x"), endDate: endDate.format("x"), fullDayEvent: fullDayEvent, - class: event.class + class: event.class, location: location, geo: geo, description: description From f58e758a41c29db94a95d0e76520cb2963754a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Tue, 27 Dec 2016 14:31:35 -0300 Subject: [PATCH 163/169] global: Add the root_path variable in global. This will can be help for work the better way in use the path into the core and modules. --- CHANGELOG.md | 1 + js/app.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c6244a99..ee5b97f21b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added abilty set the classes option to compliments module for style and text size of compliments. - Added ability to configure electronOptions - Calendar module: option to hide private events +- Add root_path for global vars ### Updated - Modified translations for Frysk. diff --git a/js/app.js b/js/app.js index 29036f694c..45b22f59ac 100644 --- a/js/app.js +++ b/js/app.js @@ -14,6 +14,9 @@ var path = require("path"); global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version; console.log("Starting MagicMirror: v" + global.version); +// global absolute root path +global.root_path = path.resolve(__dirname + "/../"); + // The next part is here to prevent a major exception when there // is no internet connection. This could probable be solved better. process.on("uncaughtException", function (err) { From 3607875714c33bd296fb19731880979a7c1d4a2c Mon Sep 17 00:00:00 2001 From: henglert Date: Thu, 29 Dec 2016 15:31:01 +0100 Subject: [PATCH 164/169] Fix repeating count of yearly calendar events The occurrence counter for a yearly repeating event e was calculated by "current year" - "e.firstYear", instead of "e.year" - "e.firstYear". That leads to a repeating event counter - 1 at the end of the year. E.g. event e: first Date: 2015-01-02, yearly repetition repeating count evaluated on 2015-12-31: 2015-2015 = 0 => incorrect repeating count evaluated on 2016-01-01: 2016-2015 = 1 => correct Fix: repeating count has to be calculated from event date instead of current date. --- modules/default/calendar/calendar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 3b6639df29..3e0a098592 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -134,7 +134,7 @@ Module.register("calendar", { repeatingCountTitle = this.countTitleForUrl(event.url); if (repeatingCountTitle !== "") { - var thisYear = new Date().getFullYear(), + var thisYear = new Date(parseInt(event.startDate)).getFullYear(), yearDiff = thisYear - event.firstYear; repeatingCountTitle = ", " + yearDiff + ". " + repeatingCountTitle; From 2f933a90fd0c5dae80943b19369591c7c265d343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 29 Dec 2016 19:06:47 -0300 Subject: [PATCH 165/169] global.root_path for js core Use global.root_path instead of "/../" syntax to go back directory --- js/app.js | 2 +- js/server.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/js/app.js b/js/app.js index 45b22f59ac..ba6cd1a9b5 100644 --- a/js/app.js +++ b/js/app.js @@ -41,7 +41,7 @@ var App = function() { var loadConfig = function(callback) { console.log("Loading config ..."); var defaults = require(__dirname + "/defaults.js"); - var configFilename = path.resolve(__dirname + "/../config/config.js"); + var configFilename = path.resolve(global.root_path + "/config/config.js"); try { fs.accessSync(configFilename, fs.F_OK); var c = require(configFilename); diff --git a/js/server.js b/js/server.js index 0ffd76c6fc..c1174561d3 100644 --- a/js/server.js +++ b/js/server.js @@ -31,19 +31,19 @@ var Server = function(config, callback) { app.use(helmet()); app.use("/js", express.static(__dirname)); - app.use("/config", express.static(path.resolve(__dirname + "/../config"))); - app.use("/css", express.static(path.resolve(__dirname + "/../css"))); - app.use("/fonts", express.static(path.resolve(__dirname + "/../fonts"))); - app.use("/modules", express.static(path.resolve(__dirname + "/../modules"))); - app.use("/vendor", express.static(path.resolve(__dirname + "/../vendor"))); - app.use("/translations", express.static(path.resolve(__dirname + "/../translations"))); + app.use("/config", express.static(path.resolve(global.root_path + "/config"))); + app.use("/css", express.static(path.resolve(global.root_path + "/css"))); + app.use("/fonts", express.static(path.resolve(global.root_path + "/fonts"))); + app.use("/modules", express.static(path.resolve(global.root_path + "/modules"))); + app.use("/vendor", express.static(path.resolve(global.root_path + "/vendor"))); + app.use("/translations", express.static(path.resolve(global.root_path + "/translations"))); app.get("/version", function(req,res) { res.send(global.version); }); app.get("/", function(req, res) { - var html = fs.readFileSync(path.resolve(__dirname + "/../index.html"), {encoding: "utf8"}); + var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), {encoding: "utf8"}); html = html.replace("#VERSION#", global.version); res.send(html); From 19d906c5e4684fb2717cc859e923e2fac77e4910 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Thu, 29 Dec 2016 22:23:08 -0300 Subject: [PATCH 166/169] fix tabs, remove extra spaces and lines. --- .github/CONTRIBUTING.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CHANGELOG.md | 2 +- installers/raspberry.sh | 66 +++++++++---------- js/class.js | 2 +- js/defaults.js | 2 +- js/electron.js | 12 ++-- js/server.js | 2 +- modules/README.md | 10 +-- modules/default/alert/alert.js | 3 +- modules/default/calendar/README.md | 4 +- modules/default/clock/clock.js | 2 +- modules/default/compliments/README.md | 4 +- .../default/currentweather/currentweather.js | 2 +- modules/default/newsfeed/README.md | 10 +-- modules/default/newsfeed/newsfeed.js | 22 +++---- .../weatherforecast/weatherforecast.js | 9 ++- 17 files changed, 77 insertions(+), 79 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ee3b721964..254458863d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -23,7 +23,7 @@ To run StyleLint, use `grunt stylelint`. ### Submitting Issues -Please only submit reproducible issues. +Please only submit reproducible issues. If you're not sure if it's a real bug or if it's just you, please open a topic on the forum: [https://forum.magicmirror.builders/category/15/bug-hunt](https://forum.magicmirror.builders/category/15/bug-hunt) Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 215950e069..acecd6f96e 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,4 @@ -> Please send your pull requests the develop branch. +> Please send your pull requests the develop branch. > Don't forget to add the change to CHANGELOG.md. * Does the pull request solve a **related** issue? diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c6244a99..df21866d2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Solve an issue where module margins would appear when the first module of a section was hidden. - Solved visual display errors on chrome, if all modules in one of the right sections are hidden. - Global and Module default config values are no longer modified when setting config values. -- Hide a region if all modules in a region are hidden. Prevention unwanted margins. +- Hide a region if all modules in a region are hidden. Prevention unwanted margins. - Replaced `electron-prebuilt` package with `electron` in order to fix issues that would happen after 2017. - Documentation of alert module diff --git a/installers/raspberry.sh b/installers/raspberry.sh index 4c42dcde03..cd995a1e22 100644 --- a/installers/raspberry.sh +++ b/installers/raspberry.sh @@ -18,7 +18,7 @@ echo ' \$$$$$$ |' echo ' \______/' echo -e "\e[0m" -# Define the tested version of Node.js. +# Define the tested version of Node.js. NODE_TESTED="v5.1.0" #Determine which Pi is running. @@ -49,19 +49,19 @@ if command_exists node; then echo -e "\e[0mMinimum Node version: \e[1m$NODE_TESTED\e[0m" echo -e "\e[0mInstalled Node version: \e[1m$NODE_CURRENT\e[0m" if version_gt $NODE_TESTED $NODE_CURRENT; then - echo -e "\e[96mNode should be upgraded.\e[0m" - NODE_INSTALL=true - - #Check if a node process is currenlty running. - #If so abort installation. - if pgrep "node" > /dev/null; then - echo -e "\e[91mA Node process is currently running. Can't upgrade." - echo "Please quit all Node processes and restart the installer." - exit; + echo -e "\e[96mNode should be upgraded.\e[0m" + NODE_INSTALL=true + + #Check if a node process is currenlty running. + #If so abort installation. + if pgrep "node" > /dev/null; then + echo -e "\e[91mA Node process is currently running. Can't upgrade." + echo "Please quit all Node processes and restart the installer." + exit; fi - else - echo -e "\e[92mNo Node.js upgrade nessecery.\e[0m" + else + echo -e "\e[92mNo Node.js upgrade nessecery.\e[0m" fi else @@ -116,27 +116,27 @@ fi # Check if plymouth is installed (default with PIXEL desktop environment), then install custom splashscreen. echo -e "\e[96mCheck plymouth installation ...\e[0m" if command_exists plymouth; then - THEME_DIR="/usr/share/plymouth/themes" - echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m" - if [ -d $THEME_DIR ]; then - echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m" - if [ ! -d $THEME_DIR/MagicMirror ]; then - sudo mkdir $THEME_DIR/MagicMirror - fi - - if sudo cp ~/MagicMirror/splashscreen/splash.png $THEME_DIR/MagicMirror/splash.png && sudo cp ~/MagicMirror/splashscreen/MagicMirror.plymouth $THEME_DIR/MagicMirror/MagicMirror.plymouth && sudo cp ~/MagicMirror/splashscreen/MagicMirror.script $THEME_DIR/MagicMirror/MagicMirror.script; then - echo -e "\e[90mSplashscreen: Theme copied successfully.\e[0m" - if sudo plymouth-set-default-theme -R MagicMirror; then - echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m" - else - echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m" - fi - else - echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m" - fi - else - echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m" - fi + THEME_DIR="/usr/share/plymouth/themes" + echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m" + if [ -d $THEME_DIR ]; then + echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m" + if [ ! -d $THEME_DIR/MagicMirror ]; then + sudo mkdir $THEME_DIR/MagicMirror + fi + + if sudo cp ~/MagicMirror/splashscreen/splash.png $THEME_DIR/MagicMirror/splash.png && sudo cp ~/MagicMirror/splashscreen/MagicMirror.plymouth $THEME_DIR/MagicMirror/MagicMirror.plymouth && sudo cp ~/MagicMirror/splashscreen/MagicMirror.script $THEME_DIR/MagicMirror/MagicMirror.script; then + echo -e "\e[90mSplashscreen: Theme copied successfully.\e[0m" + if sudo plymouth-set-default-theme -R MagicMirror; then + echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m" + else + echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m" + fi + else + echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m" + fi + else + echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m" + fi else echo -e "\e[93mplymouth is not installed.\e[0m"; fi diff --git a/js/class.js b/js/class.js index 01a92603ee..6c56f656b6 100644 --- a/js/class.js +++ b/js/class.js @@ -79,7 +79,7 @@ function cloneObject(obj) { var temp = obj.constructor(); // give temp the original obj's constructor for (var key in obj) { temp[key] = cloneObject(obj[key]); - + if (key === "lockStrings") { Log.log(key); } diff --git a/js/defaults.js b/js/defaults.js index b5b11561db..4639e2b3b5 100644 --- a/js/defaults.js +++ b/js/defaults.js @@ -12,7 +12,7 @@ var defaults = { kioskmode: false, electronOptions: {}, ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], - + language: "en", timeFormat: 24, units: "metric", diff --git a/js/electron.js b/js/electron.js index edd4896b24..173abe6892 100644 --- a/js/electron.js +++ b/js/electron.js @@ -18,15 +18,15 @@ const BrowserWindow = electron.BrowserWindow; let mainWindow; function createWindow() { - + var electronOptionsDefaults = { - width: 800, - height: 600, - x: 0, + width: 800, + height: 600, + x: 0, y: 0, - darkTheme: true, + darkTheme: true, webPreferences: { - nodeIntegration: false, + nodeIntegration: false, zoomFactor: config.zoom } } diff --git a/js/server.js b/js/server.js index 0ffd76c6fc..fd06a6b662 100644 --- a/js/server.js +++ b/js/server.js @@ -41,7 +41,7 @@ var Server = function(config, callback) { app.get("/version", function(req,res) { res.send(global.version); }); - + app.get("/", function(req, res) { var html = fs.readFileSync(path.resolve(__dirname + "/../index.html"), {encoding: "utf8"}); html = html.replace("#VERSION#", global.version); diff --git a/modules/README.md b/modules/README.md index 7884e4323e..42a31dfa3c 100644 --- a/modules/README.md +++ b/modules/README.md @@ -82,11 +82,11 @@ Any properties defined in the defaults object, will be merged with the module co *Introduced in version: 2.1.0.* -A string that defines the minimum version of the MagicMirror framework. If it is set, the system compares the required version with the users version. If the version of the user is out of date, it won't run the module. Make sure to also set this value in the Node helper. +A string that defines the minimum version of the MagicMirror framework. If it is set, the system compares the required version with the users version. If the version of the user is out of date, it won't run the module. Make sure to also set this value in the Node helper. **Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. -Example: +Example: ````javascript requiresVersion: "2.1.0", ```` @@ -117,7 +117,7 @@ The getScripts method is called to request any additional scripts that need to b getScripts: function() { return [ 'script.js', // will try to load it from the vendor folder, otherwise it will load is from the module folder. - 'moment.js', // this file is available in the vendor folder, so it doesn't need to be available in the module folder. + 'moment.js', // this file is available in the vendor folder, so it doesn't need to be available in the module folder. this.file('anotherfile.js'), // this file will be loaded straight from the module folder. 'https://code.jquery.com/jquery-2.2.3.min.js', // this file will be loaded from the jquery servers. ] @@ -339,7 +339,7 @@ Visiblity locking helps the module system to prevent unwanted hide/show actions. ````javascript moduleA.hide(0, {lockString: "module_b_identifier"}); ```` -Module A is now hidden, and has an lock array with the following strings: +Module A is now hidden, and has an lock array with the following strings: ````javascript moduleA.lockStrings == ["module_b_identifier"] moduleA.hidden == true @@ -474,7 +474,7 @@ A string that defines the minimum version of the MagicMirror framework. If it is **Note:** Since this check is introduced in version 2.1.0, this check will not be run in older versions. Keep this in mind if you get issue reports on your module. -Example: +Example: ````javascript requiresVersion: "2.1.0", ```` diff --git a/modules/default/alert/alert.js b/modules/default/alert/alert.js index cc25a31c5f..787a0b4ada 100644 --- a/modules/default/alert/alert.js +++ b/modules/default/alert/alert.js @@ -35,7 +35,6 @@ Module.register("alert",{ }, show_notification: function(message) { if (this.config.effect == "slide") {this.config.effect = this.config.effect + "-" + this.config.position;} - msg = ""; if (message.title) { msg += "" + message.title + ""; @@ -46,7 +45,7 @@ Module.register("alert",{ } msg += "" + message.message + ""; } - + new NotificationFx({ message: msg, layout: "growl", diff --git a/modules/default/calendar/README.md b/modules/default/calendar/README.md index de57f3b1af..c5745152ee 100644 --- a/modules/default/calendar/README.md +++ b/modules/default/calendar/README.md @@ -109,7 +109,7 @@ The following properties can be configured: titleReplace: {'Birthday of ' : '', 'foo':'bar'} -
Default value: +
Default value: { "De verjaardag van ": "", @@ -158,7 +158,7 @@ The following properties can be configured: broadcastEvents If this property is set to true, the calendar will broadcast all the events to all other modules with the notification message: CALENDAR_EVENTS. The event objects are stored in an array and contain the following fields: title, startDate, endDate, fullDayEvent, location and geo.

Possible values: true, false
-
Default value: true +
Default value: true diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js index 4455b15afe..c84c133e0a 100644 --- a/modules/default/clock/clock.js +++ b/modules/default/clock/clock.js @@ -220,7 +220,7 @@ Module.register("clock",{ wrapper.appendChild(digitalWrapper); } else { analogWrapper.style.padding = "20px 0 0 0"; - wrapper.appendChild(digitalWrapper); + wrapper.appendChild(digitalWrapper); wrapper.appendChild(analogWrapper); } } diff --git a/modules/default/compliments/README.md b/modules/default/compliments/README.md index ac410d30d3..430c4fbfa5 100644 --- a/modules/default/compliments/README.md +++ b/modules/default/compliments/README.md @@ -57,7 +57,7 @@ The following properties can be configured: - remoteFile + remoteFile External file from which to load the compliments

Possible values:Path to a JSON file containing compliments, configured as per the value of the compliments configuration (see below). An object with three arrays: @@ -136,7 +136,7 @@ config: { ### External Compliment File You may specify an external file that contains the three compliment arrays. This is particularly useful if you have a large number of compliments and do not wish to crowd your `config.js` file with a large array of compliments. -Adding the `remoteFile` variable will override an array you specify in the configuration file. +Adding the `remoteFile` variable will override an array you specify in the configuration file. This file must be straight JSON. Note that the array names need quotes around them ("morning", "afternoon", "evening", "snow", "rain", etc.). diff --git a/modules/default/currentweather/currentweather.js b/modules/default/currentweather/currentweather.js index b42ef12a14..e92550eaa2 100644 --- a/modules/default/currentweather/currentweather.js +++ b/modules/default/currentweather/currentweather.js @@ -37,7 +37,7 @@ Module.register("currentweather",{ onlyTemp: false, roundTemp: false, - + iconTable: { "01d": "wi-day-sunny", "02d": "wi-day-cloudy", diff --git a/modules/default/newsfeed/README.md b/modules/default/newsfeed/README.md index 21d3910e1b..58c7b9ae18 100644 --- a/modules/default/newsfeed/README.md +++ b/modules/default/newsfeed/README.md @@ -113,13 +113,13 @@ The following properties can be configured: removeEndTags: false, startTags: [], endTags: [] - - + + removeStartTags Some newsfeeds feature tags at the beginning of their titles or descriptions, such as [VIDEO]. This setting allows for the removal of specified tags from the beginning of an item's description and/or title.
-
Possible values:'title', 'description', 'both' +
Possible values:'title', 'description', 'both' @@ -131,7 +131,7 @@ The following properties can be configured: removeEndTags Remove specified tags from the end of an item's description and/or title.
-
Possible values:'title', 'description', 'both' +
Possible values:'title', 'description', 'both' @@ -173,7 +173,7 @@ The `feeds` property contains an array with multiple objects. These objects have The encoding of the news feed.

This property is optional.
Possible values:'UTF-8', 'ISO-8859-1', etc ... -
Default value: 'UTF-8' +
Default value: 'UTF-8' diff --git a/modules/default/newsfeed/newsfeed.js b/modules/default/newsfeed/newsfeed.js index 32fdabdf89..74014208d9 100644 --- a/modules/default/newsfeed/newsfeed.js +++ b/modules/default/newsfeed/newsfeed.js @@ -29,7 +29,7 @@ Module.register("newsfeed",{ removeEndTags: "", startTags: [], endTags: [] - + }, // Define required scripts. @@ -112,17 +112,17 @@ Module.register("newsfeed",{ //Remove selected tags from the beginning of rss feed items (title or description) if (this.config.removeStartTags == "title" || "both") { - + for (f=0; f Date: Fri, 30 Dec 2016 17:44:41 -0300 Subject: [PATCH 167/169] add rules "no-trailing-spaces" and "no-irregular-whitespace" for ESLint --- .eslintrc.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 833095051a..150a081d8d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,11 +4,13 @@ "quotes": ["error", "double"], "max-len": ["error", 250], "curly": "error", - "camelcase": ["error", {"properties": "never"}] + "camelcase": ["error", {"properties": "never"}], + "no-trailing-spaces": ["error"], + "no-irregular-whitespace": ["error"] }, "env": { "browser": true, "node": true, "es6": true } -} \ No newline at end of file +} From a48cb052c2dccabc2472b4520c3e8b847468dfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Ram=C3=ADrez=20Norambuena?= Date: Fri, 30 Dec 2016 17:47:33 -0300 Subject: [PATCH 168/169] resolv some missing fix eslint rules no-trailing-spaces --- modules/default/calendar/calendar.js | 2 +- modules/default/calendar/debug.js | 3 +-- modules/default/newsfeed/node_helper.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index 3b6639df29..c53dbdc319 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -388,7 +388,7 @@ Module.register("calendar", { /* broadcastEvents() * Broadcasts the events to all other modules for reuse. - * The all events available in one array, sorted on startdate. + * The all events available in one array, sorted on startdate. */ broadcastEvents: function () { var eventList = []; diff --git a/modules/default/calendar/debug.js b/modules/default/calendar/debug.js index d52cdc9f17..9b72d51d42 100644 --- a/modules/default/calendar/debug.js +++ b/modules/default/calendar/debug.js @@ -1,5 +1,5 @@ /* CalendarFetcher Tester - * use this script with `node debug.js` to test the fetcher without the need + * use this script with `node debug.js` to test the fetcher without the need * of starting the MagicMirror core. Adjust the values below to your desire. * * By Michael Teeuw http://michaelteeuw.nl @@ -30,4 +30,3 @@ fetcher.onError(function(fetcher, error) { fetcher.startFetch(); console.log("Create fetcher done! "); - diff --git a/modules/default/newsfeed/node_helper.js b/modules/default/newsfeed/node_helper.js index cfb06817ee..e5243304e4 100644 --- a/modules/default/newsfeed/node_helper.js +++ b/modules/default/newsfeed/node_helper.js @@ -72,7 +72,7 @@ module.exports = NodeHelper.create({ }, /* broadcastFeeds() - * Creates an object with all feed items of the different registered feeds, + * Creates an object with all feed items of the different registered feeds, * and broadcasts these using sendSocketNotification. */ broadcastFeeds: function() { From da772e66494a442b2f1207cb587f8089aa6ee681 Mon Sep 17 00:00:00 2001 From: Michael Teeuw Date: Sat, 31 Dec 2016 21:12:53 +0100 Subject: [PATCH 169/169] Add release date. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9ae75e689..b9551b79d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [2.1.0] - Unreleased +## [2.1.0] - 2016-12-31 **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`