Hi Michael,
Yes, I'm aware this is a bit unannounced and a lot of code. Thank you for looking at it!Hello, Thanks for the patchset. It is a lot of code to look through indeed.
My thinking was: At the moment, the web interface is quite old-fashined and uses relatively little javascript, scattered in multiple files.On 1 Apr 2023, at 15:43, Leo-Andres Hofmann <hofmann@leo-andres.de> wrote: This patch is an effort to modernize and unify the WUI JavaScript. It will be possible to share e.g. translation strings and common functions between the different modules. This uses native ES6 modules that are supported by all major browsers. Therefore, no change to the toolchain is necessary. Signed-off-by: Leo-Andres Hofmann <hofmann@leo-andres.de> --- Hi all, this patchset brings new modern Javascript modules to the webinterface.I suppose there is no way around this.
This is written from scratch, in the sense that it is not just a modified copy of some existing library.Is this all written from scratch? Did you base this on anything or use some existing code as inspiration?
I looked at a few popular libraries, but in my opinion they are too extensive and do not fit well with the existing web interface. (jquery.i18n, Polyglot, ...)Are they any existing libraries that could be useful for example pulling in the translation?
-MichaelStill on my to-do/wish list: - run make.sh lang - convert pakfire.js to a module - convert/rewrite refreshInetInfo.js, maybe add load displays to all interfaces in index.cgi I hope this is in a presentable state to see where it is headed. Let me know what you think and as always thanks for reading/testing/reviewing :) Best, Leo config/etc/mime.types | 1 + html/html/include/wui.js | 47 ++++++ html/html/include/wui_core.mjs | 154 +++++++++++++++++++ html/html/include/wui_rrdimage.mjs | 30 ++++ html/html/themes/ipfire/include/functions.pl | 3 +- 5 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 html/html/include/wui.js create mode 100644 html/html/include/wui_core.mjs create mode 100644 html/html/include/wui_rrdimage.mjs diff --git a/config/etc/mime.types b/config/etc/mime.types index af82d4886..bb3816db9 100644 --- a/config/etc/mime.types +++ b/config/etc/mime.types @@ -252,6 +252,7 @@ multipart/voice-message text/css css text/directory text/enriched +text/javascript mjs text/plain asc txt text/prs.lines.tag text/rfc822-headers diff --git a/html/html/include/wui.js b/html/html/include/wui.js new file mode 100644 index 000000000..e65924e29 --- /dev/null +++ b/html/html/include/wui.js @@ -0,0 +1,47 @@ +/*############################################################################# +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007-2023 IPFire Team <info@ipfire.org> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +#############################################################################*/ + +// IPFire Web User Interface +// Collection of JavaScript functions and modules (requires jQuery) + +import {WUIcore_i18n as WUI_i18n} from "./wui_core.mjs"; + +import {WUImodule_rrdimage as WUI_rrdimage} from "./wui_rrdimage.mjs"; + +//--- WUI main class --- +class WUImain { + constructor() { + //- Public properties - + // Translation strings + this.i18n = new WUI_i18n(); + + //- Modules - + // RRDtool graph images + this.rrdimage = new WUI_rrdimage(this.i18n); + + //- Defaults - + // These modules are available on every page: + this.rrdimage.enabled = true; + } +} + +//### Initialize WUI ### +const wui = new WUImain(); +export default wui; diff --git a/html/html/include/wui_core.mjs b/html/html/include/wui_core.mjs new file mode 100644 index 000000000..b7b729396 --- /dev/null +++ b/html/html/include/wui_core.mjs @@ -0,0 +1,154 @@ +/*############################################################################# +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007-2023 IPFire Team <info@ipfire.org> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www. gnu.org/licenses/>. # +# # +#############################################################################*/ + +// IPFire Web User Interface - JavaScript module +// Core functions & module helpers + +//--- Module template --- +// Make sure that overridden functions are still executed with super()! +export class WUIcore_moduleBase { + //- Private properties - + #enabled; // Activation state, disabled by default + #readyState; // Loading state similar to Document.readyState + #namespace; // Namespace derived from the class name (without "WUImod_" prefix) + + //- Class constructor - + constructor(translations) { + this.i18n = translations; + + this.#enabled = false; + + this.#readyState = "loading"; + this.#namespace = this.constructor.name.slice(10); + } + + // Module activation state + // Note: Because a module likely changes the DOM, it is not intended that it can + // be cleanly disabled again. Disabling it anyway will trigger "_handleModuleDestroy". + set enabled(state) { + if(this.#enabled !== state) { + this.#enabled = state; + + if(state) { + this._handleModuleEnable(); + } else { + this._handleModuleDestroy(); + } + } + } + get enabled() { + return this.#enabled; + } + + // Module loading state + // loading: Instance created + // interactive: Module enabled, document not ready + // complete: DOMContentLoaded/jQuery.ready event fired + // destroyed: Module disabled, event handlers removed + get readyState() { + return this.#readyState; + } + + // Module namespace + get namespace() { + return this.#namespace; + } + + //### Protected properties ### + + // Module activation state event handlers + _handleModuleEnable() { + if(this.#readyState === "loading") { + this.#readyState = "interactive"; + + // Attach jQuery.ready event + $(this._handleDOMReady.bind(this)); + } + } + _handleModuleDestroy() { + this.#readyState = "destroyed"; + + // Attempt to remove all event handlers of this module + $("body").off(`.${this.namespace}`); + } + + // DOMContentLoaded/jQuery.ready event handler + // The module must be enabled for this event to be triggered once + _handleDOMReady() { + this.#readyState = "complete"; + } + + // Translations quick access in module namespace + _i18n(key) { + return this.i18n.get(key, this.namespace); + } +} + +//--- Simple translation strings helper --- +export class WUIcore_i18n { + //- Private properties - + #strings; + + //- Class constructor - + constructor() { + this.#strings = Object.create(null); //Object without prototypes + } + + // Default module prefix for general translations + get #mainModule() { + return "wui"; + } + + // Get translation + get(key, module = this.#mainModule) { + const index = `${module}%${key}`; + + if(Object.hasOwn(this.#strings, index)) { + return this.#strings[index]; + } + return `(missing string '${key}' in '${module}')`; + } + + // Add translation + add(key, value, module = this.#mainModule) { + if(typeof value === "string" || typeof value === "number") { + this.#strings[`${module}%${key}`] = value; + } + } + + // Load key/translation JS object + // Format: {"key": "translation"} + load(translations, module = this.#mainModule) { + if(translations instanceof Object) { + Object.entries(translations).forEach(([key, value]) => { + this.add(key, value, module); + }); + } + } +} + +//--- Static utility functions --- +export class WUIcore_utilities { + // Reload document (clears POST/GET data from history) + static reloadDocument() { + const url = window.location.origin + window.location.pathname; + window.location.replace(url); + } +} diff --git a/html/html/include/wui_rrdimage.mjs b/html/html/include/wui_rrdimage.mjs new file mode 100644 index 000000000..5254b1e98 --- /dev/null +++ b/html/html/include/wui_rrdimage.mjs @@ -0,0 +1,30 @@ +/*############################################################################# +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2007-2023 IPFire Team <info@ipfire.org> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +#############################################################################*/ + +// IPFire Web User Interface - JavaScript module + +import {WUIcore_moduleBase as WUI_module} from "./wui_core.mjs"; + +//--- RRDtool graph images --- +export class WUImodule_rrdimage extends WUI_module { + constructor(translations) { + super(translations); + } +} diff --git a/html/html/themes/ipfire/include/functions.pl b/html/html/themes/ipfire/include/functions.pl index cbd05d109..445597e51 100644 --- a/html/html/themes/ipfire/include/functions.pl +++ b/html/html/themes/ipfire/include/functions.pl @@ -113,7 +113,8 @@ print <<END; <title>$headline - $title</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <link rel="shortcut icon" href="/favicon.ico" /> - <script type="text/javascript" src="/include/jquery.js"></script> + <script src="/include/jquery.js"></script> + <script src="/include/wui.js" type="module"></script> <script src="/include/rrdimage.js"></script> $extrahead -- 2.37.1.windows.1