2020-05-03 18:59:26 +02:00
/* global Class, cloneObject, Loader, MMSocket, nunjucks, Translator */
2016-03-24 17:19:32 +01:00
2022-01-26 23:09:26 +01:00
/ * M a g i c M i r r o r ²
2016-03-24 17:19:32 +01:00
* Module Blueprint .
2020-08-01 16:31:42 +02:00
* @ typedef { Object } Module
2016-03-24 17:19:32 +01:00
*
2020-04-28 23:05:28 +02:00
* By Michael Teeuw https : //michaelteeuw.nl
2016-03-24 17:19:32 +01:00
* MIT Licensed .
* /
2021-07-14 15:06:23 +02:00
const Module = Class . extend ( {
2016-03-24 17:19:32 +01:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* All methods ( and properties ) below can be subclassed . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2022-01-26 23:47:51 +01:00
// Set the minimum MagicMirror² module version for this module.
2016-10-13 16:42:15 +02:00
requiresVersion : "2.0.0" ,
2016-03-24 17:19:32 +01:00
// Module config defaults.
defaults : { } ,
2016-04-08 17:27:02 +02:00
// Timer reference used for showHide animation callbacks.
showHideTimer : null ,
2016-11-22 18:53:46 -03:00
// Array to store lockStrings. These strings are used to lock
2016-10-13 15:00:59 +02:00
// visibility when hiding and showing module.
lockStrings : [ ] ,
2017-10-12 10:23:40 +02:00
// Storage of the nunjuck Environment,
2017-09-28 16:11:25 +02:00
// This should not be referenced directly.
// Use the nunjucksEnvironment() to get it.
_nunjucksEnvironment : null ,
2020-07-28 16:48:03 +02:00
/ * *
* Called when the module is instantiated .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
init : function ( ) {
2016-03-24 17:19:32 +01:00
//Log.log(this.defaults);
} ,
2020-07-28 16:48:03 +02:00
/ * *
* Called when the module is started .
2016-03-24 17:19:32 +01:00
* /
2023-02-22 18:58:29 +01:00
start : async function ( ) {
2016-04-05 14:35:11 -04:00
Log . info ( "Starting module: " + this . name ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Returns a list of scripts the module requires to be loaded .
*
2020-08-01 16:31:42 +02:00
* @ returns { string [ ] } An array with filenames .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
getScripts : function ( ) {
2016-03-24 17:19:32 +01:00
return [ ] ;
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Returns a list of stylesheets the module requires to be loaded .
*
2020-08-01 16:31:42 +02:00
* @ returns { string [ ] } An array with filenames .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
getStyles : function ( ) {
2016-03-24 17:19:32 +01:00
return [ ] ;
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-04-21 01:03:26 +02:00
* Returns a map of translation files the module requires to be loaded .
*
2020-07-28 16:48:03 +02:00
* return Map < String , String > -
*
* @ returns { * } A map with langKeys and filenames .
2016-04-21 01:03:26 +02:00
* /
2016-10-13 16:42:15 +02:00
getTranslations : function ( ) {
2016-05-11 12:38:41 +02:00
return false ;
2016-04-21 01:03:26 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2022-01-26 23:09:26 +01:00
* Generates the dom which needs to be displayed . This method is called by the MagicMirror² core .
2017-09-28 16:11:25 +02:00
* This method can to be subclassed if the module wants to display info on the mirror .
2019-06-04 09:33:53 +02:00
* Alternatively , the getTemplate method could be subclassed .
2016-03-24 17:19:32 +01:00
*
2020-07-28 16:48:03 +02:00
* @ returns { HTMLElement | Promise } The dom or a promise with the dom to display .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
getDom : function ( ) {
2021-03-23 22:40:24 +01:00
return new Promise ( ( resolve ) => {
const div = document . createElement ( "div" ) ;
const template = this . getTemplate ( ) ;
const templateData = this . getTemplateData ( ) ;
2018-01-01 10:55:39 -06:00
2018-01-01 09:42:34 -06:00
// Check to see if we need to render a template string or a file.
if ( /^.*((\.html)|(\.njk))$/ . test ( template ) ) {
// the template is a filename
2021-03-23 22:40:24 +01:00
this . nunjucksEnvironment ( ) . render ( template , templateData , function ( err , res ) {
2018-01-01 09:42:34 -06:00
if ( err ) {
2019-06-05 10:23:58 +02:00
Log . error ( err ) ;
2018-01-01 09:42:34 -06:00
}
div . innerHTML = res ;
resolve ( div ) ;
} ) ;
} else {
// the template is a template string.
2021-03-23 22:40:24 +01:00
div . innerHTML = this . nunjucksEnvironment ( ) . renderString ( template , templateData ) ;
2018-01-01 09:42:34 -06:00
resolve ( div ) ;
}
} ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
* Generates the header string which needs to be displayed if a user has a header configured for this module .
2022-01-26 23:09:26 +01:00
* This method is called by the MagicMirror² core , but only if the user has configured a default header for the module .
2016-09-20 17:22:24 +02:00
* This method needs to be subclassed if the module wants to display modified headers on the mirror .
*
2020-07-28 16:48:03 +02:00
* @ returns { string } The header to display above the header .
2016-09-20 17:22:24 +02:00
* /
2016-10-13 16:42:15 +02:00
getHeader : function ( ) {
2016-09-20 17:22:24 +02:00
return this . data . header ;
} ,
2020-07-28 16:48:03 +02:00
/ * *
* Returns the template for the module which is used by the default getDom implementation .
2019-06-04 09:33:53 +02:00
* This method needs to be subclassed if the module wants to use a template .
2017-09-28 16:11:25 +02:00
* It can either return a template sting , or a template filename .
* If the string ends with '.html' it 's considered a file from within the module' s folder .
*
2020-07-28 16:48:03 +02:00
* @ returns { string } The template string of filename .
2017-09-28 16:11:25 +02:00
* /
getTemplate : function ( ) {
2020-05-11 22:22:32 +02:00
return '<div class="normal">' + this . name + '</div><div class="small dimmed">' + this . identifier + "</div>" ;
2017-09-28 16:11:25 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
* Returns the data to be used in the template .
2017-09-28 16:11:25 +02:00
* This method needs to be subclassed if the module wants to use a custom data .
*
2020-07-28 16:48:03 +02:00
* @ returns { object } The data for the template
2017-09-28 16:11:25 +02:00
* /
getTemplateData : function ( ) {
2019-06-05 10:23:58 +02:00
return { } ;
2017-09-28 16:11:25 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2022-01-26 23:09:26 +01:00
* Called by the MagicMirror² core when a notification arrives .
2016-03-24 17:19:32 +01:00
*
2020-07-28 16:48:03 +02:00
* @ param { string } notification The identifier of the notification .
* @ param { * } payload The payload of the notification .
2020-08-01 16:31:42 +02:00
* @ param { Module } sender The module that sent the notification .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
notificationReceived : function ( notification , payload , sender ) {
2016-03-24 17:19:32 +01:00
if ( sender ) {
2020-02-01 19:12:05 +01:00
// Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name);
2016-03-24 17:19:32 +01:00
} else {
2020-02-01 19:12:05 +01:00
// Log.log(this.name + " received a system notification: " + notification);
2016-03-24 17:19:32 +01:00
}
} ,
2020-07-28 16:48:03 +02:00
/ * *
2017-09-29 11:05:59 +02:00
* Returns the nunjucks environment for the current module .
2017-09-28 16:11:25 +02:00
* The environment is checked in the _nunjucksEnvironment instance variable .
2020-07-28 16:48:03 +02:00
*
* @ returns { object } The Nunjucks Environment
2017-09-28 16:11:25 +02:00
* /
2020-05-11 22:22:32 +02:00
nunjucksEnvironment : function ( ) {
2019-06-05 09:32:10 +02:00
if ( this . _nunjucksEnvironment !== null ) {
2017-09-28 16:11:25 +02:00
return this . _nunjucksEnvironment ;
}
2020-05-11 22:22:32 +02:00
this . _nunjucksEnvironment = new nunjucks . Environment ( new nunjucks . WebLoader ( this . file ( "" ) , { async : true } ) , {
2017-10-18 13:49:03 +02:00
trimBlocks : true ,
lstripBlocks : true
} ) ;
2020-07-28 16:48:03 +02:00
2021-03-23 22:40:24 +01:00
this . _nunjucksEnvironment . addFilter ( "translate" , ( str , variables ) => {
return nunjucks . runtime . markSafe ( this . translate ( str , variables ) ) ;
2017-09-28 16:11:25 +02:00
} ) ;
return this . _nunjucksEnvironment ;
} ,
2020-07-28 16:48:03 +02:00
/ * *
* Called when a socket notification arrives .
2016-03-30 12:20:46 +02:00
*
2020-07-28 16:48:03 +02:00
* @ param { string } notification The identifier of the notification .
* @ param { * } payload The payload of the notification .
2016-03-30 12:20:46 +02:00
* /
2016-10-13 16:42:15 +02:00
socketNotificationReceived : function ( notification , payload ) {
2016-04-05 14:35:11 -04:00
Log . log ( this . name + " received a socket notification: " + notification + " - Payload: " + payload ) ;
2016-03-30 12:20:46 +02:00
} ,
2016-03-24 17:19:32 +01:00
2021-03-23 22:40:24 +01:00
/ * *
2020-07-28 16:48:03 +02:00
* Called when the module is hidden .
2016-05-11 13:49:40 +02:00
* /
2016-10-13 16:42:15 +02:00
suspend : function ( ) {
2016-07-20 13:31:46 -06:00
Log . log ( this . name + " is suspended." ) ;
2016-05-11 13:49:40 +02:00
} ,
2021-03-23 22:40:24 +01:00
/ * *
2020-07-28 16:48:03 +02:00
* Called when the module is shown .
2016-05-11 13:49:40 +02:00
* /
2016-10-13 16:42:15 +02:00
resume : function ( ) {
2016-05-11 13:49:40 +02:00
Log . log ( this . name + " is resumed." ) ;
} ,
2016-03-24 17:19:32 +01:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2016-05-03 19:09:38 -04:00
* The methods below don " t need subclassing . *
2016-03-24 17:19:32 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Set the module data .
*
2021-03-23 22:40:24 +01:00
* @ param { object } data The module data
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
setData : function ( data ) {
2016-03-24 17:19:32 +01:00
this . data = data ;
this . name = data . name ;
this . identifier = data . identifier ;
2016-03-31 19:15:58 +02:00
this . hidden = false ;
2016-03-24 17:19:32 +01:00
2020-09-22 00:26:24 +02:00
this . setConfig ( data . config , data . configDeepMerge ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Set the module config and combine it with the module defaults .
*
2020-07-28 16:48:03 +02:00
* @ param { object } config The combined module config .
2020-12-29 18:48:45 +01:00
* @ param { boolean } deep Merge module config in deep .
2016-03-24 17:19:32 +01:00
* /
2020-09-21 23:21:43 +02:00
setConfig : function ( config , deep ) {
2020-09-22 00:26:24 +02:00
this . config = deep ? configMerge ( { } , this . defaults , config ) : Object . assign ( { } , this . defaults , config ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
* Returns a socket object . If it doesn 't exist, it' s created .
2016-03-30 12:20:46 +02:00
* It also registers the notification callback .
2020-07-28 16:48:03 +02:00
*
* @ returns { MMSocket } a socket object
2016-03-30 12:20:46 +02:00
* /
2016-10-13 16:42:15 +02:00
socket : function ( ) {
2016-04-05 14:35:11 -04:00
if ( typeof this . _socket === "undefined" ) {
2020-05-02 10:39:09 +02:00
this . _socket = new MMSocket ( this . name ) ;
2016-03-30 12:20:46 +02:00
}
2021-03-23 22:40:24 +01:00
this . _socket . setNotificationCallback ( ( notification , payload ) => {
this . socketNotificationReceived ( notification , payload ) ;
2016-03-30 12:20:46 +02:00
} ) ;
return this . _socket ;
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-04-20 23:13:31 +02:00
* Retrieve the path to a module file .
2016-03-24 17:19:32 +01:00
*
2020-07-28 16:48:03 +02:00
* @ param { string } file Filename
* @ returns { string } the file path
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
file : function ( file ) {
2017-08-03 21:34:23 +02:00
return ( this . data . path + "/" + file ) . replace ( "//" , "/" ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Load all required stylesheets by requesting the MM object to load the files .
2016-03-31 13:05:23 +02:00
*
2020-07-28 16:48:03 +02:00
* @ param { Function } callback Function called when done .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
loadStyles : function ( callback ) {
2017-02-08 00:05:28 +01:00
this . loadDependencies ( "getStyles" , callback ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Load all required scripts by requesting the MM object to load the files .
2016-03-31 13:05:23 +02:00
*
2020-07-28 16:48:03 +02:00
* @ param { Function } callback Function called when done .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
loadScripts : function ( callback ) {
2017-02-07 23:51:13 +01:00
this . loadDependencies ( "getScripts" , callback ) ;
2016-03-24 17:19:32 +01:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2017-02-07 23:51:13 +01:00
* Helper method to load all dependencies .
*
2020-07-28 16:48:03 +02:00
* @ param { string } funcName Function name to call to get scripts or styles .
* @ param { Function } callback Function called when done .
2017-02-07 23:51:13 +01:00
* /
2017-02-08 00:05:28 +01:00
loadDependencies : function ( funcName , callback ) {
2021-03-23 22:40:24 +01:00
let dependencies = this [ funcName ] ( ) ;
2017-02-08 00:05:28 +01:00
2021-03-23 22:40:24 +01:00
const loadNextDependency = ( ) => {
2017-02-08 00:05:28 +01:00
if ( dependencies . length > 0 ) {
2021-03-23 22:40:24 +01:00
const nextDependency = dependencies [ 0 ] ;
Loader . loadFile ( nextDependency , this , ( ) => {
2017-02-08 00:05:28 +01:00
dependencies = dependencies . slice ( 1 ) ;
loadNextDependency ( ) ;
} ) ;
} else {
callback ( ) ;
}
} ;
loadNextDependency ( ) ;
} ,
2017-02-07 23:51:13 +01:00
2020-07-28 16:48:03 +02:00
/ * *
* Load all translations .
2016-04-21 01:03:26 +02:00
* /
2023-02-21 22:58:18 +01:00
async loadTranslations ( ) {
2021-01-29 22:25:49 +01:00
const translations = this . getTranslations ( ) || { } ;
const language = config . language . toLowerCase ( ) ;
const languages = Object . keys ( translations ) ;
const fallbackLanguage = languages [ 0 ] ;
2016-05-11 12:38:41 +02:00
2021-01-29 22:34:12 +01:00
if ( languages . length === 0 ) {
2021-02-06 22:55:59 +01:00
return ;
2020-05-11 22:22:32 +02:00
}
2016-05-11 12:38:41 +02:00
2021-01-29 22:34:12 +01:00
const translationFile = translations [ language ] ;
const translationsFallbackFile = translations [ fallbackLanguage ] ;
2016-05-11 12:38:41 +02:00
2021-01-29 22:34:12 +01:00
if ( ! translationFile ) {
2023-02-21 22:58:18 +01:00
return Translator . load ( this , translationsFallbackFile , true ) ;
2021-01-29 22:34:12 +01:00
}
2023-02-21 22:58:18 +01:00
await Translator . load ( this , translationFile , false ) ;
if ( translationFile !== translationsFallbackFile ) {
return Translator . load ( this , translationsFallbackFile , true ) ;
}
2016-04-21 01:03:26 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2017-04-25 23:15:34 +03:00
* Request the translation for a given key with optional variables and default value .
2016-10-13 16:42:15 +02:00
*
2020-07-28 16:48:03 +02:00
* @ param { string } key The key of the string to translate
* @ param { string | object } [ defaultValueOrVariables ] The default value or variables for translating .
* @ param { string } [ defaultValue ] The default value with variables .
* @ returns { string } the translated key
2016-10-13 16:42:15 +02:00
* /
2017-04-25 23:15:34 +03:00
translate : function ( key , defaultValueOrVariables , defaultValue ) {
2020-05-11 22:22:32 +02:00
if ( typeof defaultValueOrVariables === "object" ) {
2017-04-25 23:15:34 +03:00
return Translator . translate ( this , key , defaultValueOrVariables ) || defaultValue || "" ;
}
return Translator . translate ( this , key ) || defaultValueOrVariables || "" ;
2016-04-21 01:03:26 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Request an ( animated ) update of the module .
*
2020-07-28 16:48:03 +02:00
* @ param { number } [ speed ] The speed of the animation .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
updateDom : function ( speed ) {
2016-03-24 17:19:32 +01:00
MM . updateDom ( this , speed ) ;
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-24 17:19:32 +01:00
* Send a notification to all modules .
*
2020-07-28 16:48:03 +02:00
* @ param { string } notification The identifier of the notification .
* @ param { * } payload The payload of the notification .
2016-03-24 17:19:32 +01:00
* /
2016-10-13 16:42:15 +02:00
sendNotification : function ( notification , payload ) {
2016-03-24 17:19:32 +01:00
MM . sendNotification ( notification , payload , this ) ;
2016-03-30 12:20:46 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-30 12:20:46 +02:00
* Send a socket notification to the node helper .
*
2020-07-28 16:48:03 +02:00
* @ param { string } notification The identifier of the notification .
* @ param { * } payload The payload of the notification .
2016-03-30 12:20:46 +02:00
* /
2016-10-13 16:42:15 +02:00
sendSocketNotification : function ( notification , payload ) {
2016-03-30 12:20:46 +02:00
this . socket ( ) . sendNotification ( notification , payload ) ;
2016-03-31 19:15:58 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-31 19:15:58 +02:00
* Hide this module .
*
2020-07-28 16:48:03 +02:00
* @ param { number } speed The speed of the hide animation .
* @ param { Function } callback Called when the animation is done .
2020-08-01 16:31:42 +02:00
* @ param { object } [ options ] Optional settings for the hide method .
2016-03-31 19:15:58 +02:00
* /
2016-10-13 16:42:15 +02:00
hide : function ( speed , callback , options ) {
2016-10-13 15:00:59 +02:00
if ( typeof callback === "object" ) {
options = callback ;
2020-05-11 22:22:32 +02:00
callback = function ( ) { } ;
2016-10-13 15:00:59 +02:00
}
2020-05-11 22:22:32 +02:00
callback = callback || function ( ) { } ;
2016-10-13 15:00:59 +02:00
options = options || { } ;
2016-05-11 13:49:40 +02:00
2020-05-11 22:22:32 +02:00
MM . hideModule (
2021-03-23 22:40:24 +01:00
this ,
2020-05-11 22:22:32 +02:00
speed ,
2021-03-23 22:40:24 +01:00
( ) => {
this . suspend ( ) ;
2020-05-11 22:22:32 +02:00
callback ( ) ;
} ,
options
) ;
2016-03-31 19:15:58 +02:00
} ,
2020-07-28 16:48:03 +02:00
/ * *
2016-03-31 19:15:58 +02:00
* Show this module .
*
2020-07-28 16:48:03 +02:00
* @ param { number } speed The speed of the show animation .
* @ param { Function } callback Called when the animation is done .
2020-08-01 16:31:42 +02:00
* @ param { object } [ options ] Optional settings for the show method .
2016-03-31 19:15:58 +02:00
* /
2021-02-13 08:29:13 +01:00
show : function ( speed , callback , options ) {
2016-10-13 15:00:59 +02:00
if ( typeof callback === "object" ) {
options = callback ;
2020-05-11 22:22:32 +02:00
callback = function ( ) { } ;
2016-10-13 15:00:59 +02:00
}
2020-05-11 22:22:32 +02:00
callback = callback || function ( ) { } ;
2016-10-13 15:00:59 +02:00
options = options || { } ;
2020-12-29 18:48:45 +01:00
MM . showModule (
this ,
speed ,
2021-02-06 21:22:13 +01:00
( ) => {
this . resume ( ) ;
callback ( ) ;
2020-12-29 18:48:45 +01:00
} ,
options
) ;
2016-03-24 17:19:32 +01:00
}
} ) ;
2020-12-29 18:48:45 +01:00
/ * *
2022-01-26 23:47:51 +01:00
* Merging MagicMirror² ( or other ) default / c o n f i g s c r i p t b y @ b u g s o u n e t
2020-12-29 18:48:45 +01:00
* Merge 2 objects or / with array
*
* Usage :
2020-09-21 23:17:41 +02:00
* -- -- -- -
* this . config = configMerge ( { } , this . defaults , this . config )
* -- -- -- -
2020-12-29 18:48:45 +01:00
* arg1 : initial object
2020-09-21 23:17:41 +02:00
* arg2 : config model
* arg3 : config to merge
* -- -- -- -
* why using it ?
* Object . assign ( ) function don ' t to all job
* it don ' t merge all thing in deep
* - > object in object and array is not merging
* -- -- -- -
2020-12-29 18:48:45 +01:00
*
* Todo : idea of Mich determinate what do you want to merge or not
*
* @ param { object } result the initial object
* @ returns { object } the merged config
2020-09-21 23:17:41 +02:00
* /
function configMerge ( result ) {
2021-03-23 22:40:24 +01:00
const stack = Array . prototype . slice . call ( arguments , 1 ) ;
let item , key ;
2020-09-21 23:17:41 +02:00
while ( stack . length ) {
item = stack . shift ( ) ;
for ( key in item ) {
if ( item . hasOwnProperty ( key ) ) {
if ( typeof result [ key ] === "object" && result [ key ] && Object . prototype . toString . call ( result [ key ] ) !== "[object Array]" ) {
if ( typeof item [ key ] === "object" && item [ key ] !== null ) {
result [ key ] = configMerge ( { } , result [ key ] , item [ key ] ) ;
} else {
result [ key ] = item [ key ] ;
}
} else {
result [ key ] = item [ key ] ;
}
}
}
}
return result ;
2020-09-22 00:26:24 +02:00
}
2020-09-21 23:17:41 +02:00
2016-03-31 13:05:23 +02:00
Module . definitions = { } ;
2016-10-13 16:42:15 +02:00
Module . create = function ( name ) {
// Make sure module definition is available.
if ( ! Module . definitions [ name ] ) {
return ;
}
2016-03-31 13:05:23 +02:00
2021-03-23 22:40:24 +01:00
const moduleDefinition = Module . definitions [ name ] ;
const clonedDefinition = cloneObject ( moduleDefinition ) ;
2016-03-31 13:05:23 +02:00
// Note that we clone the definition. Otherwise the objects are shared, which gives problems.
2021-03-23 22:40:24 +01:00
const ModuleClass = Module . extend ( clonedDefinition ) ;
2016-03-31 13:05:23 +02:00
return new ModuleClass ( ) ;
} ;
2020-07-28 16:48:03 +02:00
Module . register = function ( name , moduleDefinition ) {
if ( moduleDefinition . requiresVersion ) {
2022-01-26 23:47:51 +01:00
Log . log ( "Check MagicMirror² version for module '" + name + "' - Minimum version: " + moduleDefinition . requiresVersion + " - Current version: " + window . mmVersion ) ;
2021-04-25 22:11:51 +02:00
if ( cmpVersions ( window . mmVersion , moduleDefinition . requiresVersion ) >= 0 ) {
2020-07-28 16:48:03 +02:00
Log . log ( "Version is ok!" ) ;
} else {
2021-01-01 14:44:39 +01:00
Log . warn ( "Version is incorrect. Skip module: '" + name + "'" ) ;
2020-07-28 16:48:03 +02:00
return ;
}
}
Log . log ( "Module registered: " + name ) ;
Module . definitions [ name ] = moduleDefinition ;
} ;
2021-07-14 15:06:23 +02:00
window . Module = Module ;
2020-07-27 14:24:30 +02:00
/ * *
2020-05-11 22:22:32 +02:00
* Compare two semantic version numbers and return the difference .
*
2020-07-27 14:24:30 +02:00
* @ param { string } a Version number a .
* @ param { string } b Version number b .
2020-07-28 16:48:03 +02:00
* @ returns { number } A positive number if a is larger than b , a negative
* number if a is smaller and 0 if they are the same
2020-05-11 22:22:32 +02:00
* /
2016-10-13 16:42:15 +02:00
function cmpVersions ( a , b ) {
2021-03-23 22:40:24 +01:00
const regExStrip0 = /(\.0+)+$/ ;
const segmentsA = a . replace ( regExStrip0 , "" ) . split ( "." ) ;
const segmentsB = b . replace ( regExStrip0 , "" ) . split ( "." ) ;
const l = Math . min ( segmentsA . length , segmentsB . length ) ;
for ( let i = 0 ; i < l ; i ++ ) {
let diff = parseInt ( segmentsA [ i ] , 10 ) - parseInt ( segmentsB [ i ] , 10 ) ;
2016-10-13 16:42:15 +02:00
if ( diff ) {
return diff ;
}
}
return segmentsA . length - segmentsB . length ;
}