diff --git a/README.md b/README.md index e1a937d7..873c0339 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,8 @@ This version of the Magic Mirror software focusses on a modular plugin system. B ##Todo Things that still have to be implemented or changed. -####Loader -- Loading of module uses `eval()`. We might want to look into a better solution. [loader.js#L112](https://github.com/MichMich/MagicMirror/blob/v2-beta/js/loader.js#L112). - +####Documentation +- Write all the documentation. :) ##Modules diff --git a/css/main.css b/css/main.css index 6492d8a8..aa676d7f 100644 --- a/css/main.css +++ b/css/main.css @@ -1,7 +1,9 @@ body { cursor: none; margin: 60px; - position: relative; + position: absolute; + height: calc(100% - 120px); + width: calc(100% - 120px); background: #000; color: #aaa; font-family: 'roboto_condensedregular', arial; @@ -33,7 +35,7 @@ body { header { - margin-top: 40px; + margin-top: 30px; text-transform: uppercase; font-size: 15px; font-family: 'roboto_condensedregular'; @@ -44,10 +46,6 @@ header { color: #666; } -header:first-child { - margin-top: 0px; -} - sup { font-size: 50%; line-height: 50%; diff --git a/js/loader.js b/js/loader.js index edfe3106..a35c013c 100644 --- a/js/loader.js +++ b/js/loader.js @@ -87,7 +87,8 @@ var Loader = (function() { file: module + '.js', position: moduleData.position, header: moduleData.header, - config: moduleData.config + config: moduleData.config, + classes: (typeof moduleData.classes !== 'undefined') ? moduleData.classes + ' ' + module : module }); diff --git a/js/main.js b/js/main.js index 2325f9e0..fb1411e9 100644 --- a/js/main.js +++ b/js/main.js @@ -21,22 +21,35 @@ var MM = (function() { var createDomObjects = function() { for (var m in modules) { var module = modules[m]; - if (module.data.position) { + + if (typeof module.data.position === 'string') { var wrapper = selectWrapper(module.data.position); - if (typeof module.data.header !== 'undefined' && module.data.header !== '') { - var header = document.createElement("header"); - header.innerHTML = module.data.header; - wrapper.appendChild(header); - } - var dom = document.createElement("div"); dom.id = module.identifier; dom.className = module.name; + + if (typeof module.data.classes === 'string') { + dom.className = dom.className + ' ' + module.data.classes; + } + + dom.opacity = 0; wrapper.appendChild(dom); - dom.appendChild(module.getDom()); + if (typeof module.data.header !== 'undefined' && module.data.header !== '') { + var moduleHeader = document.createElement("header"); + moduleHeader.innerHTML = module.data.header; + dom.appendChild(moduleHeader); + } + + var moduleContent = document.createElement("div"); + moduleContent.className = "module-content"; + dom.appendChild(moduleContent); + + + + updateDom(module, 500); } } @@ -82,34 +95,100 @@ var MM = (function() { * argument speed Number - The number of microseconds for the animation. (optional) */ var updateDom = function(module, speed) { - var wrapper = document.getElementById(module.identifier); var newContent = module.getDom(); + if (!module.hidden) { + + + if (!moduleNeedsUpdate(module, newContent)) { + return; + } + + if (!speed) { + updateModuleContent(module, newContent); + return; + } + + hideModule(module, speed / 2, function() { + updateModuleContent(module, newContent); + if (!module.hidden) { + showModule(module, speed / 2); + } + }); + } else { + updateModuleContent(module, newContent); + } + }; + + + /* moduleNeedsUpdate(module, newContent) + * Check if the content has changed. + * + * argument module Module - The module to check. + * argument newContent Domobject - The new content that is generated. + * + * return bool - Does the module need an update? + */ + var moduleNeedsUpdate = function(module, newContent) { + var moduleWrapper = document.getElementById(module.identifier); + var contentWrapper = moduleWrapper.getElementsByClassName('module-content')[0]; + var tempWrapper = document.createElement('div'); tempWrapper.appendChild(newContent); - if (tempWrapper.innerHTML === wrapper.innerHTML) { - // Content did not change. Abort update. - return; + return tempWrapper.innerHTML !== contentWrapper.innerHTML; + }; + + /* moduleNeedsUpdate(module, newContent) + * Update the content of a module on screen. + * + * argument module Module - The module to check. + * argument newContent Domobject - The new content that is generated. + */ + var updateModuleContent = function(module, content) { + var moduleWrapper = document.getElementById(module.identifier); + var contentWrapper = moduleWrapper.getElementsByClassName('module-content')[0]; + + contentWrapper.innerHTML = null; + contentWrapper.appendChild(content); + }; + + /* hideModule(module, speed, callback) + * Hide the module. + * + * argument module Module - The module to hide. + * argument speed Number - The speed of the hide animation. + * argument callback function - Called when the animation is done. + */ + var hideModule = function(module, speed, callback) { + var moduleWrapper = document.getElementById(module.identifier); + if (moduleWrapper !== null) { + moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; + moduleWrapper.style.opacity = 0; + + setTimeout(function() { + if (typeof callback === 'function') { callback(); } + }, speed); } + }; - if (!speed) { - wrapper.innerHTML = null; - wrapper.appendChild(newContent); - return; + /* showModule(module, speed, callback) + * Show the module. + * + * argument module Module - The module to show. + * argument speed Number - The speed of the show animation. + * argument callback function - Called when the animation is done. + */ + var showModule = function(module, speed, callback) { + var moduleWrapper = document.getElementById(module.identifier); + if (moduleWrapper !== null) { + moduleWrapper.style.transition = "opacity " + speed / 1000 + "s"; + moduleWrapper.style.opacity = 1; + + setTimeout(function() { + if (typeof callback === 'function') { callback(); } + }, speed); } - - wrapper.style.opacity = 1; - wrapper.style.transition = "opacity " + speed / 2 / 1000 + "s"; - wrapper.style.opacity = 0; - - setTimeout(function() { - wrapper.innerHTML = null; - wrapper.appendChild(newContent); - - wrapper.style.opacity = 1; - }, speed / 2); - }; /* loadConfig() @@ -125,9 +204,124 @@ var MM = (function() { config = Object.assign(defaults, config); }; + /* setSelectionMethodsForModules() + * Adds special selectors on a collection of modules. + * + * argument modules array - Array of modules. + */ + var setSelectionMethodsForModules = function(modules) { + + /* withClass(className) + * filters a collection of modules based on classname(s). + * + * argument className string/array - one or multiple classnames. (array or space devided) + * + * return array - Filtered collection of modules. + */ + var withClass = function(className) { + var newModules = []; + + var searchClasses = className; + if (typeof className === 'string') { + searchClasses = className.split(' '); + } + + for (var m in modules) { + var module = modules[m]; + var classes = module.data.classes.toLowerCase().split(' '); + + for (var c in searchClasses) { + var searchClass = searchClasses[c]; + if (classes.indexOf(searchClass.toLowerCase()) !== -1) { + newModules.push(module); + } + } + } + + setSelectionMethodsForModules(newModules); + return newModules; + }; + + /* exceptWithClass(className) + * filters a collection of modules based on classname(s). (NOT) + * + * argument className string/array - one or multiple classnames. (array or space devided) + * + * return array - Filtered collection of modules. + */ + var exceptWithClass = function(className) { + var newModules = []; + + var searchClasses = className; + if (typeof className === 'string') { + searchClasses = className.split(' '); + } + + for (var m in modules) { + var module = modules[m]; + var classes = module.data.classes.toLowerCase().split(' '); + var foundClass = false; + for (var c in searchClasses) { + var searchClass = searchClasses[c]; + if (classes.indexOf(searchClass.toLowerCase()) !== -1) { + foundClass = true; + break; + } + } + if (!foundClass) { + newModules.push(module); + } + } + + setSelectionMethodsForModules(newModules); + return newModules; + }; + + /* exceptModule(module) + * Removes a module instance from the collection. + * + * argument module Module object - The module instance to remove from the collection. + * + * return array - Filtered collection of modules. + */ + var exceptModule = function(module) { + var newModules = []; + + for (var m in modules) { + var mod = modules[m]; + if (mod.identifier !== module.identifier) { + newModules.push(mod); + } + } + + setSelectionMethodsForModules(newModules); + return newModules; + }; + + /* enumerate(callback) + * Walks thru a collection of modules and executes the callback with the module as an argument. + * + * argument callback function - The function to execute with the module as an argument. + */ + var enumerate = function(callback) { + for (var m in modules) { + var module = modules[m]; + callback(module); + } + }; + + + + if (typeof modules.withClass === 'undefined') { Object.defineProperty(modules, 'withClass', {value: withClass, enumerable: false}); } + if (typeof modules.exceptWithClass === 'undefined') { Object.defineProperty(modules, 'exceptWithClass', {value: exceptWithClass, enumerable: false}); } + if (typeof modules.exceptModule === 'undefined') { Object.defineProperty(modules, 'exceptModule', {value: exceptModule, enumerable: false}); } + if (typeof modules.enumerate === 'undefined') { Object.defineProperty(modules, 'enumerate', {value: enumerate, enumerable: false}); } + }; + + + return { - /* Public Methods */ /* init() @@ -198,8 +392,43 @@ var MM = (function() { // Further implementation is done in the private method. updateDom(module, speed); + }, + + /* getModules(module, speed) + * Returns a collection of all modules currently active. + * + * return array - A collection of all modules currently active. + */ + getModules: function() { + setSelectionMethodsForModules(modules); + return modules; + }, + + /* hideModule(module, speed, callback) + * Hide the module. + * + * argument module Module - The module hide. + * argument speed Number - The speed of the hide animation. + * argument callback function - Called when the animation is done. + */ + hideModule: function(module, speed, callback) { + hideModule(module, speed, function() { + module.hidden = true; + if (typeof callback === 'function') { callback(); } + }); + }, + + /* showModule(module, speed, callback) + * Show the module. + * + * argument module Module - The module show. + * argument speed Number - The speed of the show animation. + * argument callback function - Called when the animation is done. + */ + showModule: function(module, speed, callback) { + module.hidden = false; + showModule(module, speed, callback); } - }; })(); diff --git a/js/module.js b/js/module.js index f77f288a..20609b54 100644 --- a/js/module.js +++ b/js/module.js @@ -113,6 +113,7 @@ var Module = Class.extend({ this.data = data; this.name = data.name; this.identifier = data.identifier; + this.hidden = false; this.setConfig(data.config); }, @@ -229,6 +230,26 @@ var Module = Class.extend({ */ sendSocketNotification: function(notification, payload) { this.socket().sendNotification(notification, payload); + }, + + /* hideModule(module, speed, callback) + * Hide this module. + * + * argument speed Number - The speed of the hide animation. + * argument callback function - Called when the animation is done. + */ + hide: function(speed, callback) { + MM.hideModule(this, speed, callback); + }, + + /* showModule(module, speed, callback) + * Show this module. + * + * argument speed Number - The speed of the show animation. + * argument callback function - Called when the animation is done. + */ + show: function(speed, callback) { + MM.showModule(this, speed, callback); } });