Add AnimateCSS (#3113)

Hi,

This is my testing code for AnimateCSS for `show()`, `hide()`,
`updateDom()`

Naturally, we have to do better !

I voluntarily modify `newsfeed` and `compliments` in order to test

Note: I will correct checks later... it's a test...

---------

Co-authored-by: bugsounet <bugsounet@bugsounet.fr>
Co-authored-by: veeck <michael.veeck@nebenan.de>
This commit is contained in:
Bugsounet - Cédric
2023-09-08 07:43:39 +02:00
committed by GitHub
parent 5cbdd28db3
commit a92b3d3f71
8 changed files with 308 additions and 33 deletions

View File

@@ -1,4 +1,4 @@
/* global Loader, defaults, Translator */
/* global Loader, defaults, Translator, AnimateCSS, AnimateCSSIn, AnimateCSSOut */
/* MagicMirror²
* Main System
@@ -22,6 +22,10 @@ const MM = (function () {
return;
}
let haveAnimateIn = null;
// check if have valid animateIn in module definition (module.data.animateIn)
if (module.data.animateIn && AnimateCSSIn.indexOf(module.data.animateIn) !== -1) haveAnimateIn = module.data.animateIn;
const wrapper = selectWrapper(module.data.position);
const dom = document.createElement("div");
@@ -50,7 +54,12 @@ const MM = (function () {
moduleContent.className = "module-content";
dom.appendChild(moduleContent);
const domCreationPromise = updateDom(module, 0);
// 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);
else domCreationPromise = updateDom(module, 0);
domCreationPromises.push(domCreationPromise);
domCreationPromise
.then(function () {
@@ -101,11 +110,30 @@ const MM = (function () {
/**
* Update the dom for a specific module.
* @param {Module} module The module that needs an update.
* @param {number} [speed] The (optional) number of microseconds for the animation.
* @param {object|number} [updateOptions] The (optional) number of microseconds for the animation or object with updateOptions (speed/animates)
* @param {boolean} [createAnimatedDom] for displaying only animateIn (used on first start of MagicMirror)
* @returns {Promise} Resolved when the dom is fully updated.
*/
const updateDom = function (module, speed) {
const updateDom = function (module, updateOptions, createAnimatedDom = false) {
return new Promise(function (resolve) {
let speed = updateOptions;
let animateOut = null;
let animateIn = null;
if (typeof updateOptions === "object") {
if (typeof updateOptions.options === "object" && updateOptions.options.speed !== undefined) {
speed = updateOptions.options.speed;
Log.debug(`updateDom: ${module.identifier} Has speed in object: ${speed}`);
if (typeof updateOptions.options.animate === "object") {
animateOut = updateOptions.options.animate.out;
animateIn = updateOptions.options.animate.in;
Log.debug(`updateDom: ${module.identifier} Has animate in object: out->${animateOut}, in->${animateIn}`);
}
} else {
Log.debug(`updateDom: ${module.identifier} Has no speed in object`);
speed = 0;
}
}
const newHeader = module.getHeader();
let newContentPromise = module.getDom();
@@ -116,7 +144,7 @@ const MM = (function () {
newContentPromise
.then(function (newContent) {
const updatePromise = updateDomWithContent(module, speed, newHeader, newContent);
const updatePromise = updateDomWithContent(module, speed, newHeader, newContent, animateOut, animateIn, createAnimatedDom);
updatePromise.then(resolve).catch(Log.error);
})
@@ -130,9 +158,12 @@ const MM = (function () {
* @param {number} [speed] The (optional) number of microseconds for the animation.
* @param {string} newHeader The new header that is generated.
* @param {HTMLElement} newContent The new content that is generated.
* @param {string} [animateOut] AnimateCss animation name before hidden
* @param {string} [animateIn] AnimateCss animation name on show
* @param {boolean} [createAnimatedDom] for displaying only animateIn (used on first start)
* @returns {Promise} Resolved when the module dom has been updated.
*/
const updateDomWithContent = function (module, speed, newHeader, newContent) {
const updateDomWithContent = function (module, speed, newHeader, newContent, animateOut, animateIn, createAnimatedDom = false) {
return new Promise(function (resolve) {
if (module.hidden || !speed) {
updateModuleContent(module, newHeader, newContent);
@@ -151,13 +182,28 @@ const MM = (function () {
return;
}
hideModule(module, speed / 2, function () {
if (createAnimatedDom && animateIn !== null) {
Log.debug(`${module.identifier} createAnimatedDom (${animateIn})`);
updateModuleContent(module, newHeader, newContent);
if (!module.hidden) {
showModule(module, speed / 2);
showModule(module, speed, null, { animate: animateIn });
}
resolve();
});
return;
}
hideModule(
module,
speed / 2,
function () {
updateModuleContent(module, newHeader, newContent);
if (!module.hidden) {
showModule(module, speed / 2, null, { animate: animateIn });
}
resolve();
},
{ animate: animateOut }
);
});
};
@@ -223,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 = function (module, speed, callback, options = {}) {
const hideModule = async function (module, speed, callback, options = {}) {
// set lockString if set in options.
if (options.lockString) {
// Log.log("Has lockstring: " + options.lockString);
@@ -234,24 +280,49 @@ const MM = (function () {
const moduleWrapper = document.getElementById(module.identifier);
if (moduleWrapper !== null) {
moduleWrapper.style.transition = `opacity ${speed / 1000}s`;
moduleWrapper.style.opacity = 0;
moduleWrapper.classList.add("hidden");
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
// below other modules. This works way better than adjusting
// the .display property.
// 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)
let haveAnimateName = null;
// check if have valid animateOut in module definition (module.data.animateOut)
if (module.data.animateOut && AnimateCSSOut.indexOf(module.data.animateOut) !== -1) haveAnimateName = module.data.animateOut;
// can't be override with options.animate
else if (options.animate && AnimateCSSOut.indexOf(options.animate) !== -1) haveAnimateName = options.animate;
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";
updateWrapperStates();
if (typeof callback === "function") {
callback();
}
}, speed);
} else {
// default MM² Animate
moduleWrapper.style.transition = `opacity ${speed / 1000}s`;
moduleWrapper.style.opacity = 0;
moduleWrapper.classList.add("hidden");
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
// below other modules. This works way better than adjusting
// the .display property.
moduleWrapper.style.position = "fixed";
updateWrapperStates();
if (typeof callback === "function") {
callback();
}
}, speed);
}
} else {
// invoke callback even if no content, issue 1308
if (typeof callback === "function") {
@@ -267,7 +338,7 @@ const MM = (function () {
* @param {Function} callback Called when the animation is done.
* @param {object} [options] Optional settings for the show method.
*/
const showModule = function (module, speed, callback, options = {}) {
const showModule = async function (module, speed, callback, options = {}) {
// remove lockString if set in options.
if (options.lockString) {
const index = module.lockStrings.indexOf(options.lockString);
@@ -296,7 +367,18 @@ const MM = (function () {
const moduleWrapper = document.getElementById(module.identifier);
if (moduleWrapper !== null) {
moduleWrapper.style.transition = `opacity ${speed / 1000}s`;
clearTimeout(module.showHideTimer);
// haveAnimateName for verify if we are using AninateCSS library
// we check AnimateCSSIn Array for validate it
// and finaly return the animate name or `null` (for default MM² animation)
let haveAnimateName = null;
// check if have valid animateOut in module definition (module.data.animateIn)
if (module.data.animateIn && AnimateCSSIn.indexOf(module.data.animateIn) !== -1) haveAnimateName = module.data.animateIn;
// can't be override with options.animate
else if (options.animate && AnimateCSSIn.indexOf(options.animate) !== -1) haveAnimateName = options.animate;
if (!haveAnimateName) moduleWrapper.style.transition = `opacity ${speed / 1000}s`;
// Restore the position. See hideModule() for more info.
moduleWrapper.style.position = "static";
moduleWrapper.classList.remove("hidden");
@@ -307,12 +389,21 @@ const MM = (function () {
const dummy = moduleWrapper.parentElement.parentElement.offsetHeight;
moduleWrapper.style.opacity = 1;
clearTimeout(module.showHideTimer);
module.showHideTimer = setTimeout(function () {
if (haveAnimateName) {
// with AnimateCSS
Log.debug(`${module.identifier} Has animateIn: ${haveAnimateName}`);
await AnimateCSS(module.identifier, haveAnimateName, speed / 1000);
if (typeof callback === "function") {
callback();
}
}, speed);
} else {
// default MM² Animate
module.showHideTimer = setTimeout(function () {
if (typeof callback === "function") {
callback();
}
}, speed);
}
} else {
// invoke callback
if (typeof callback === "function") {
@@ -514,9 +605,9 @@ const MM = (function () {
/**
* Update the dom for a specific module.
* @param {Module} module The module that needs an update.
* @param {number} [speed] The number of microseconds for the animation.
* @param {object|number} [updateOptions] The (optional) number of microseconds for the animation or object with updateOptions (speed/animates)
*/
updateDom: function (module, speed) {
updateDom: function (module, updateOptions) {
if (!(module instanceof Module)) {
Log.error("updateDom: Sender should be a module.");
return;
@@ -528,7 +619,7 @@ const MM = (function () {
}
// Further implementation is done in the private method.
updateDom(module, speed);
updateDom(module, updateOptions);
},
/**