Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: AnimateCSS merge hide() and show() animated css class when we do multiple call #3200

Merged
merged 8 commits into from
Sep 19, 2023
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 26 additions & 27 deletions js/animateCSS.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
69 changes: 51 additions & 18 deletions js/main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global Loader, defaults, Translator, AnimateCSS, AnimateCSSIn, AnimateCSSOut */
/* global Loader, defaults, Translator, addAnimateCSS, removeAnimateCSS, AnimateCSSIn, AnimateCSSOut */

/* MagicMirror²
* Main System
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand All @@ -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`;
Expand Down Expand Up @@ -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);
Expand All @@ -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;

Expand Down Expand Up @@ -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 () {
Expand Down
2 changes: 2 additions & 0 deletions js/module.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
Expand Down