diff --git a/CHANGELOG.md b/CHANGELOG.md index ab411fd1..efb6f599 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ _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 diff --git a/js/animateCSS.js b/js/animateCSS.js index ae6e7bec..cf3f26bc 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(); - } - - node.addEventListener("animationend", handleAnimationEnd, { once: true }); - }); +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); +} + +/** + * 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 3c023af3..c7d4d39f 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 62534b01..4ef3ab1d 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); },