diff --git a/CHANGELOG.md b/CHANGELOG.md
index ca9184d796..c4ed028b7f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -35,6 +35,7 @@ _This release is scheduled to be released on 2023-10-01._
- Update typescript definition for modules
- Cleaned up nunjuck templates
- Replace `node-fetch` with internal fetch (#2649) and remove `digest-fetch`
+- Updated the French translation according to the English file.
### Fixed
@@ -46,6 +47,8 @@ _This release is scheduled to be released on 2023-10-01._
- Fix ipWhiteList test (#3179)
- Fix newsfeed: Convert HTML entities, codes and tag in description (#3191)
- Respect width/height (no fullscreen) if set in electronOptions (together with `fullscreen: false`) in `config.js` (#3174)
+- Fix: AnimateCSS merge hide() and show() animated css class when we do multiple call
+- Fix `Uncaught SyntaxError: Identifier 'getCorsUrl' has already been declared (at utils.js:1:1)` when using `clock` and `weather` module (#3204)
## [2.24.0] - 2023-07-01
@@ -88,6 +91,7 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al
- Fix date not shown when clock in analog mode (#3100)
- Fix envcanada today percentage-of-precipitation (#3106)
- Fix updatenotification where no branch is checked out but e.g. a version tag (#3130)
+- Fix yr weather provider after changes in yr API (#3189)
## [2.23.0] - 2023-04-04
diff --git a/index.html b/index.html
index 501c1af5b0..b97124be10 100644
--- a/index.html
+++ b/index.html
@@ -46,6 +46,7 @@
+
diff --git a/js/animateCSS.js b/js/animateCSS.js
index ae6e7bec7b..cf3f26bcb7 100644
--- a/js/animateCSS.js
+++ b/js/animateCSS.js
@@ -130,36 +130,35 @@ const AnimateCSSOut = [
/**
* Create an animation with Animate CSS
- * resolved as Promise when done
* @param {string} [element] div element to animate.
* @param {string} [animation] animation name.
* @param {number} [animationTime] animation duration.
*/
-function AnimateCSS(element, animation, animationTime) {
- /* We create a Promise and return it */
- return new Promise((resolve) => {
- const animationName = `animate__${animation}`;
- const node = document.getElementById(element);
- if (!node) {
- // don't execute animate and resolve
- Log.warn(`AnimateCSS: node not found for`, element);
- resolve();
- return;
- }
- node.style.setProperty("--animate-duration", `${animationTime}s`);
- node.classList.add("animate__animated", animationName);
-
- /**
- * When the animation ends, we clean the classes and resolve the Promise
- * @param {object} event object
- */
- function handleAnimationEnd(event) {
- node.classList.remove("animate__animated", animationName);
- node.style.removeProperty("--animate-duration", `${animationTime}s`);
- event.stopPropagation();
- resolve();
- }
+function addAnimateCSS(element, animation, animationTime) {
+ const animationName = `animate__${animation}`;
+ const node = document.getElementById(element);
+ if (!node) {
+ // don't execute animate: we don't find div
+ Log.warn(`addAnimateCSS: node not found for`, element);
+ return;
+ }
+ node.style.setProperty("--animate-duration", `${animationTime}s`);
+ node.classList.add("animate__animated", animationName);
+}
- node.addEventListener("animationend", handleAnimationEnd, { once: true });
- });
+/**
+ * Remove an animation with Animate CSS
+ * @param {string} [element] div element to animate.
+ * @param {string} [animation] animation name.
+ */
+function removeAnimateCSS(element, animation) {
+ const animationName = `animate__${animation}`;
+ const node = document.getElementById(element);
+ if (!node) {
+ // don't execute animate: we don't find div
+ Log.warn(`removeAnimateCSS: node not found for`, element);
+ return;
+ }
+ node.classList.remove("animate__animated", animationName);
+ node.style.removeProperty("--animate-duration");
}
diff --git a/js/main.js b/js/main.js
index 3c023af359..c7d4d39f77 100644
--- a/js/main.js
+++ b/js/main.js
@@ -1,4 +1,4 @@
-/* global Loader, defaults, Translator, AnimateCSS, AnimateCSSIn, AnimateCSSOut */
+/* global Loader, defaults, Translator, addAnimateCSS, removeAnimateCSS, AnimateCSSIn, AnimateCSSOut */
/* MagicMirror²
* Main System
@@ -57,7 +57,7 @@ const MM = (function () {
// create the domCreationPromise with AnimateCSS (with animateIn of module definition)
// or just display it
var domCreationPromise;
- if (haveAnimateIn) domCreationPromise = updateDom(module, 1000, null, haveAnimateIn, true);
+ if (haveAnimateIn) domCreationPromise = updateDom(module, { options: { speed: 1000, animate: { in: haveAnimateIn } } }, true);
else domCreationPromise = updateDom(module, 0);
domCreationPromises.push(domCreationPromise);
@@ -269,7 +269,7 @@ const MM = (function () {
* @param {Function} callback Called when the animation is done.
* @param {object} [options] Optional settings for the hide method.
*/
- const hideModule = async function (module, speed, callback, options = {}) {
+ const hideModule = function (module, speed, callback, options = {}) {
// set lockString if set in options.
if (options.lockString) {
// Log.log("Has lockstring: " + options.lockString);
@@ -281,7 +281,17 @@ const MM = (function () {
const moduleWrapper = document.getElementById(module.identifier);
if (moduleWrapper !== null) {
clearTimeout(module.showHideTimer);
-
+ // reset all animations if needed
+ if (module.hasAnimateOut) {
+ removeAnimateCSS(module.identifier, module.hasAnimateOut);
+ Log.debug(`${module.identifier} Force remove animateOut (in hide): ${module.hasAnimateOut}`);
+ module.hasAnimateOut = false;
+ }
+ if (module.hasAnimateIn) {
+ removeAnimateCSS(module.identifier, module.hasAnimateIn);
+ Log.debug(`${module.identifier} Force remove animateIn (in hide): ${module.hasAnimateIn}`);
+ module.hasAnimateIn = false;
+ }
// haveAnimateName for verify if we are using AninateCSS library
// we check AnimateCSSOut Array for validate it
// and finaly return the animate name or `null` (for default MM² animation)
@@ -294,16 +304,22 @@ const MM = (function () {
if (haveAnimateName) {
// with AnimateCSS
Log.debug(`${module.identifier} Has animateOut: ${haveAnimateName}`);
- await AnimateCSS(module.identifier, haveAnimateName, speed / 1000);
- // AnimateCSS is now done
- moduleWrapper.style.opacity = 0;
- moduleWrapper.classList.add("hidden");
- moduleWrapper.style.position = "fixed";
+ module.hasAnimateOut = haveAnimateName;
+ addAnimateCSS(module.identifier, haveAnimateName, speed / 1000);
+ module.showHideTimer = setTimeout(function () {
+ removeAnimateCSS(module.identifier, haveAnimateName);
+ Log.debug(`${module.identifier} Remove animateOut: ${module.hasAnimateOut}`);
+ // AnimateCSS is now done
+ moduleWrapper.style.opacity = 0;
+ moduleWrapper.classList.add("hidden");
+ moduleWrapper.style.position = "fixed";
+ module.hasAnimateOut = false;
- updateWrapperStates();
- if (typeof callback === "function") {
- callback();
- }
+ updateWrapperStates();
+ if (typeof callback === "function") {
+ callback();
+ }
+ }, speed);
} else {
// default MM² Animate
moduleWrapper.style.transition = `opacity ${speed / 1000}s`;
@@ -338,7 +354,7 @@ const MM = (function () {
* @param {Function} callback Called when the animation is done.
* @param {object} [options] Optional settings for the show method.
*/
- const showModule = async function (module, speed, callback, options = {}) {
+ const showModule = function (module, speed, callback, options = {}) {
// remove lockString if set in options.
if (options.lockString) {
const index = module.lockStrings.indexOf(options.lockString);
@@ -356,6 +372,17 @@ const MM = (function () {
}
return;
}
+ // reset all animations if needed
+ if (module.hasAnimateOut) {
+ removeAnimateCSS(module.identifier, module.hasAnimateOut);
+ Log.debug(`${module.identifier} Force remove animateOut (in show): ${module.hasAnimateOut}`);
+ module.hasAnimateOut = false;
+ }
+ if (module.hasAnimateIn) {
+ removeAnimateCSS(module.identifier, module.hasAnimateIn);
+ Log.debug(`${module.identifier} Force remove animateIn (in show): ${module.hasAnimateIn}`);
+ module.hasAnimateIn = false;
+ }
module.hidden = false;
@@ -392,10 +419,16 @@ const MM = (function () {
if (haveAnimateName) {
// with AnimateCSS
Log.debug(`${module.identifier} Has animateIn: ${haveAnimateName}`);
- await AnimateCSS(module.identifier, haveAnimateName, speed / 1000);
- if (typeof callback === "function") {
- callback();
- }
+ module.hasAnimateIn = haveAnimateName;
+ addAnimateCSS(module.identifier, haveAnimateName, speed / 1000);
+ module.showHideTimer = setTimeout(function () {
+ removeAnimateCSS(module.identifier, haveAnimateName);
+ Log.debug(`${module.identifier} Remove animateIn: ${haveAnimateName}`);
+ module.hasAnimateIn = false;
+ if (typeof callback === "function") {
+ callback();
+ }
+ }, speed);
} else {
// default MM² Animate
module.showHideTimer = setTimeout(function () {
diff --git a/js/module.js b/js/module.js
index 62534b0178..4ef3ab1d61 100644
--- a/js/module.js
+++ b/js/module.js
@@ -205,6 +205,8 @@ const Module = Class.extend({
this.name = data.name;
this.identifier = data.identifier;
this.hidden = false;
+ this.hasAnimateIn = false;
+ this.hasAnimateOut = false;
this.setConfig(data.config, data.configDeepMerge);
},
diff --git a/modules/default/clock/clock.js b/modules/default/clock/clock.js
index 4345d20a49..c063d4dc88 100644
--- a/modules/default/clock/clock.js
+++ b/modules/default/clock/clock.js
@@ -38,7 +38,7 @@ Module.register("clock", {
},
// Define required scripts.
getScripts: function () {
- return ["moment.js", "moment-timezone.js", "suncalc.js", this.file("../utils.js")];
+ return ["moment.js", "moment-timezone.js", "suncalc.js"];
},
// Define styles.
getStyles: function () {
diff --git a/modules/default/weather/providers/yr.js b/modules/default/weather/providers/yr.js
index 52de53ba12..be876a6dc8 100644
--- a/modules/default/weather/providers/yr.js
+++ b/modules/default/weather/providers/yr.js
@@ -352,8 +352,7 @@ WeatherProvider.register("yr", {
if (hours.length < 2) {
hours = `0${hours}`;
}
-
- return `${this.config.apiBase}/sunrise/2.0/.json?date=${date}&days=${days}&height=${altitude}&lat=${lat}&lon=${lon}&offset=${utcOffsetPrefix}${hours}%3A${minutes}`;
+ return `${this.config.apiBase}/sunrise/2.3/sun?lat=${lat}&lon=${lon}&date=${date}&offset=${utcOffsetPrefix}${hours}%3A${minutes}`;
},
cacheStellarData(data) {
@@ -362,8 +361,6 @@ WeatherProvider.register("yr", {
getWeatherDataFrom(forecast, stellarData, units) {
const weather = new WeatherObject();
- const stellarTimesToday = stellarData?.today ? this.getStellarTimesFrom(stellarData.today, moment().format("YYYY-MM-DD")) : undefined;
- const stellarTimesTomorrow = stellarData?.tomorrow ? this.getStellarTimesFrom(stellarData.tomorrow, moment().add(1, "days").format("YYYY-MM-DD")) : undefined;
weather.date = moment(forecast.time);
weather.windSpeed = forecast.data.instant.details.wind_speed;
@@ -377,10 +374,8 @@ WeatherProvider.register("yr", {
weather.precipitationProbability = forecast.precipitationProbability;
weather.precipitationUnits = units.precipitation_amount;
- if (stellarTimesToday) {
- weather.sunset = moment(stellarTimesToday.sunset.time);
- weather.sunrise = weather.sunset < moment() && stellarTimesTomorrow ? moment(stellarTimesTomorrow.sunrise.time) : moment(stellarTimesToday.sunrise.time);
- }
+ weather.sunrise = stellarData?.today?.properties?.sunrise?.time;
+ weather.sunset = stellarData?.today?.properties?.sunset?.time;
return weather;
},
diff --git a/modules/default/weather/weather.js b/modules/default/weather/weather.js
index 701e151622..57c91d7b07 100644
--- a/modules/default/weather/weather.js
+++ b/modules/default/weather/weather.js
@@ -62,7 +62,7 @@ Module.register("weather", {
// Return the scripts that are necessary for the weather module.
getScripts: function () {
- return ["moment.js", this.file("../utils.js"), "weatherutils.js", "weatherobject.js", this.file("providers/overrideWrapper.js"), "weatherprovider.js", "suncalc.js", this.file(`providers/${this.config.weatherProvider.toLowerCase()}.js`)];
+ return ["moment.js", "weatherutils.js", "weatherobject.js", this.file("providers/overrideWrapper.js"), "weatherprovider.js", "suncalc.js", this.file(`providers/${this.config.weatherProvider.toLowerCase()}.js`)];
},
// Override getHeader method.
diff --git a/translations/fr.json b/translations/fr.json
index 1e4a294652..319e0fda3d 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -29,9 +29,16 @@
"FEELS": "Ressenti {DEGREE}",
"PRECIP_POP": "Probabilité de précipitations",
+ "PRECIP_AMOUNT": "Quantité des précipitations",
"MODULE_CONFIG_CHANGED": "Les options de configuration du module {MODULE_NAME} ont changé.\nVeuillez consulter la documentation.",
"MODULE_CONFIG_ERROR": "Erreur dans le module {MODULE_NAME}. {ERROR}",
+ "MODULE_ERROR_MALFORMED_URL": "URL mal formée.",
+ "MODULE_ERROR_NO_CONNECTION": "Pas de connexion Internet.",
+ "MODULE_ERROR_UNAUTHORIZED": "L'autorisation à échouée.",
+ "MODULE_ERROR_UNSPECIFIED": "Consultez les journaux pour plus de détails.",
+
+ "NEWSFEED_NO_ITEMS": "Aucune nouvelle pour le moment.",
"UPDATE_NOTIFICATION": "Une mise à jour de MagicMirror² est disponible",
"UPDATE_NOTIFICATION_MODULE": "Une mise à jour est disponible pour le module {MODULE_NAME}.",