From 4eccce3f775b498577122f53b4416653503dcc45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bugsounet=20-=20C=C3=A9dric?= Date: Tue, 19 Sep 2023 20:14:35 +0200 Subject: [PATCH] Fix: AnimateCSS merge hide() and show() animated css class when we do multiple call (#3200) PR: #3113 I see this bugs: AnimateCSS merge hide() and show() animated css class when we do multiple call --> result it will stay en hide state I think event listener (is animateCSS file) is not a proper solution I correct it with like traditional code with timer Fix too: AnimateIn on first start --- CHANGELOG.md | 1 + js/animateCSS.js | 53 ++++++++++++++++++------------------- js/main.js | 69 +++++++++++++++++++++++++++++++++++------------- js/module.js | 2 ++ 4 files changed, 80 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab411fd19f..efb6f59924 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 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); },