From baf9cee376435be3096b1ee60a6815fe22e2b165 Mon Sep 17 00:00:00 2001 From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Date: Mon, 11 May 2026 21:24:43 +0200 Subject: [PATCH] refactor: rewrite Module as an ES6 class Drop the old browser-side `Class.extend()` helper and make `Module` a native class, matching the earlier `NodeHelper` rewrite. --- defaultmodules/newsfeed/newsfeed.js | 2 +- index.html | 1 - js/class.js | 119 ------------- js/module.js | 158 +++++++++++------ tests/e2e/translations_spec.js | 6 +- tests/unit/classes/class_spec.js | 117 ------------- tests/unit/classes/module_spec.js | 261 ++++++++++++++++++++++++++++ 7 files changed, 368 insertions(+), 296 deletions(-) delete mode 100644 js/class.js delete mode 100644 tests/unit/classes/class_spec.js create mode 100644 tests/unit/classes/module_spec.js diff --git a/defaultmodules/newsfeed/newsfeed.js b/defaultmodules/newsfeed/newsfeed.js index cbf1aefa9e..fa1476faf5 100644 --- a/defaultmodules/newsfeed/newsfeed.js +++ b/defaultmodules/newsfeed/newsfeed.js @@ -148,7 +148,7 @@ Module.register("newsfeed", { } return Promise.resolve(wrapper); } - return this._super(); + return Module.prototype.getDom.call(this); }, //Override fetching of template name diff --git a/index.html b/index.html index af9df8560d..a91bf469bc 100644 --- a/index.html +++ b/index.html @@ -50,7 +50,6 @@ - diff --git a/js/class.js b/js/class.js deleted file mode 100644 index f0196d5aee..0000000000 --- a/js/class.js +++ /dev/null @@ -1,119 +0,0 @@ -/* global Class, xyz */ - -/* - * Simple JavaScript Inheritance - * By John Resig https://johnresig.com/ - * - * Inspired by base2 and Prototype - * - * MIT Licensed. - */ -(function () { - let initializing = false; - const fnTest = (/xyz/).test(function () { - return xyz; - }) - ? /\b_super\b/ - : /.*/; - - // The base Class implementation (does nothing) - this.Class = function () {}; - - // Create a new Class that inherits from this class - Class.extend = function (prop) { - let _super = this.prototype; - - /* - * Instantiate a base class (but only create the instance, - * don't run the init constructor) - */ - initializing = true; - const prototype = new this(); - initializing = false; - - // Make a copy of all prototype properties, to prevent reference issues. - for (const p in prototype) { - prototype[p] = cloneObject(prototype[p]); - } - - // Copy the properties over onto the new prototype - for (const name in prop) { - // Check if we're overwriting an existing function - prototype[name] - = typeof prop[name] === "function" && typeof _super[name] === "function" && fnTest.test(prop[name]) - ? (function (name, fn) { - return function () { - const tmp = this._super; - - /* - * Add a new ._super() method that is the same method - * but on the super-class - */ - this._super = _super[name]; - - /* - * The method only need to be bound temporarily, so we - * remove it when we're done executing - */ - const ret = fn.apply(this, arguments); - this._super = tmp; - - return ret; - }; - }(name, prop[name])) - : prop[name]; - } - - /** - * The dummy class constructor - */ - function Class () { - // All construction is actually done in the init method - if (!initializing && this.init) { - this.init.apply(this, arguments); - } - } - - // Populate our constructed prototype object - Class.prototype = prototype; - - // Enforce the constructor to be what we expect - Class.prototype.constructor = Class; - - // And make this class extendable - Class.extend = arguments.callee; - - return Class; - }; -}()); - -/** - * Define the clone method for later use. Helper Method. - * @param {object} obj Object to be cloned - * @returns {object} the cloned object - */ -function cloneObject (obj) { - if (obj === null || typeof obj !== "object") { - return obj; - } - - if (obj.constructor.name === "RegExp") { - return new RegExp(obj); - } - - const temp = obj.constructor(); // give temp the original obj's constructor - for (const key in obj) { - temp[key] = cloneObject(obj[key]); - - if (key === "lockStrings") { - Log.log(key); - } - } - - return temp; -} - -/*************** DO NOT EDIT THE LINE BELOW ***************/ -if (typeof module !== "undefined") { - module.exports = Class; -} diff --git a/js/module.js b/js/module.js index f38d808995..96479ec3b8 100644 --- a/js/module.js +++ b/js/module.js @@ -1,10 +1,31 @@ -/* global Class, cloneObject, Loader, MMSocket, nunjucks */ +/* global Loader, MMSocket, nunjucks */ /* * Module Blueprint. * @typedef {Object} Module */ -const Module = Class.extend({ +class Module { + + /** + * Initializes per-instance mutable state. + */ + constructor () { + // Timer reference used for showHide animation callbacks. + this.showHideTimer = null; + + /* + * Array to store lockStrings. These strings are used to lock + * visibility when hiding and showing module. + */ + this.lockStrings = []; + + /* + * Storage of the nunjucks Environment. + * This should not be referenced directly. + * Use the nunjucksEnvironment() method to get it. + */ + this._nunjucksEnvironment = null; + } /** ********************************************************* @@ -12,40 +33,18 @@ const Module = Class.extend({ ********************************************************* */ - // Set the minimum MagicMirror² module version for this module. - requiresVersion: "2.0.0", - - // Module config defaults. - defaults: {}, - - // Timer reference used for showHide animation callbacks. - showHideTimer: null, - - /* - * Array to store lockStrings. These strings are used to lock - * visibility when hiding and showing module. - */ - lockStrings: [], - - /* - * Storage of the nunjucks Environment, - * This should not be referenced directly. - * Use the nunjucksEnvironment() to get it. - */ - _nunjucksEnvironment: null, - /** * Called when the module is instantiated. */ init () { - }, + } /** * Called when the module is started. */ start () { Log.info(`Starting module: ${this.name}`); - }, + } /** * Returns a list of scripts the module requires to be loaded. @@ -53,7 +52,7 @@ const Module = Class.extend({ */ getScripts () { return []; - }, + } /** * Returns a list of stylesheets the module requires to be loaded. @@ -61,7 +60,7 @@ const Module = Class.extend({ */ getStyles () { return []; - }, + } /** * Returns a map of translation files the module requires to be loaded. @@ -71,7 +70,7 @@ const Module = Class.extend({ */ getTranslations () { return false; - }, + } /** * Generates the dom which needs to be displayed. This method is called by the MagicMirror² core. @@ -104,7 +103,7 @@ const Module = Class.extend({ resolve(div); } }); - }, + } /** * Generates the header string which needs to be displayed if a user has a header configured for this module. @@ -114,7 +113,7 @@ const Module = Class.extend({ */ getHeader () { return this.data.header; - }, + } /** * Returns the template for the module which is used by the default getDom implementation. @@ -125,7 +124,7 @@ const Module = Class.extend({ */ getTemplate () { return `