From baa9fec8760272f91859db678424b4f5feaa1c30 Mon Sep 17 00:00:00 2001 From: yflory Date: Tue, 7 May 2024 16:52:01 +0200 Subject: [PATCH] Improve plugins system --- customize.dist/messages.js | 1 + lib/http-worker.js | 31 ++++++++++++++++++++++++++++++- lib/plugin-manager.js | 14 ++++++++++++++ www/common/extensions.js | 30 ++++++++++++++++++++++++++++++ www/common/sframe-common.js | 4 +++- www/lib/optional/optional.js | 2 +- 6 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 www/common/extensions.js diff --git a/customize.dist/messages.js b/customize.dist/messages.js index 579dcd31e..84253819f 100755 --- a/customize.dist/messages.js +++ b/customize.dist/messages.js @@ -45,6 +45,7 @@ var getLanguage = Messages._getLanguage = function () { (map[l.split('_')[0]] ? l.split('_')[0] : 'en')); }; var language = getLanguage(); +window.cryptpadLanguage = language; // Translations files were migrated from requirejs modules to json. // To avoid asking every administrator to update their customized translation files, diff --git a/lib/http-worker.js b/lib/http-worker.js index bf33ec8ee..6822496c4 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -630,6 +630,35 @@ var serveBroadcast = makeRouteCache(function () { app.get('/api/config', serveConfig); app.get('/api/broadcast', serveBroadcast); +(function () { +let extensions = plugins._extensions; +let styles = plugins._styles; +let str = JSON.stringify(extensions); +let str2 = JSON.stringify(styles); +let js = `let extensions = ${str}; +let styles = ${str2}; +let lang = window.cryptpadLanguage; +let paths = []; +extensions.forEach(name => { + paths.push(\`optional!/\${name}/extensions.js\`); + paths.push(\`optional!json!/\${name}/translations/messages.json\`); + paths.push(\`optional!json!/\${name}/translations/messages.\${lang}.json\`); +}); +styles.forEach(name => { + paths.push(\`optional!less!/\${name}/style.less\`); +}); +define(paths, function () { + let args = Array.prototype.slice.apply(arguments); + return args; +}, function () { + // ignore missing files +});` +app.get('/extensions.js', (req, res) => { + res.setHeader('Content-Type', 'text/javascript'); + res.send(js); +}); +})(); + var Define = function (obj) { return `define(function (){ return ${JSON.stringify(obj, null, '\t')}; @@ -723,7 +752,7 @@ app.post('/api/auth', function (req, res, next) { }); app.use(function (req, res /*, next */) { - if (/^(\/favicon\.ico\/|.*\.js\.map)$/.test(req.url)) { + if (/^(\/favicon\.ico\/|.*\.js\.map|.*\/translations\/.*\.json)$/.test(req.url)) { // ignore common 404s } else { Log.info('HTTP_404', req.url); diff --git a/lib/plugin-manager.js b/lib/plugin-manager.js index 8f51120b6..2643bbe0d 100644 --- a/lib/plugin-manager.js +++ b/lib/plugin-manager.js @@ -4,6 +4,8 @@ const fs = require('node:fs'); const plugins = {}; +const extensions = plugins._extensions = []; +const styles = plugins._styles = []; try { let pluginsDir = fs.readdirSync(__dirname + '/plugins'); @@ -12,6 +14,18 @@ try { try { let plugin = require(`./plugins/${name}/index`); plugins[plugin.name] = plugin.modules; + try { + let hasExt = fs.existsSync(`lib/plugins/${name}/client/extensions.js`); + if (hasExt) { + extensions.push(plugin.name.toLowerCase()); + } + } catch (e) {} + try { + let hasStyle = fs.existsSync(`lib/plugins/${name}/client/style.less`); + if (hasStyle) { + styles.push(plugin.name.toLowerCase()); + } + } catch (e) {} } catch (err) { console.error(err); } diff --git a/www/common/extensions.js b/www/common/extensions.js new file mode 100644 index 000000000..0fad27b03 --- /dev/null +++ b/www/common/extensions.js @@ -0,0 +1,30 @@ +define([ + '/extensions.js' +], (Extensions) => { + console.error(Extensions); + const ext = {}; + if (!Array.isArray(Extensions) || !Extensions.length) { return ext; } + + let all = Extensions.slice(); + while(all.length) { + let current = all.splice(0, 3); + console.error(current); + let f = current[0]; + if (typeof(f) !== "function") { + continue; + } + let defaultLang = current[1]; + let lang = current[2]; + if (!Object.keys(lang).length && Object.keys(defaultLang).length) { + lang = defaultLang; + } + let currentExt = f(lang) || {}; + + Object.keys(currentExt).forEach(key => { + ext[key] = ext[key] || []; + Array.prototype.push.apply(ext[key], currentExt[key]); // concat in place + }); + } + + return ext; +}); diff --git a/www/common/sframe-common.js b/www/common/sframe-common.js index 625a0dfe6..cd893395a 100644 --- a/www/common/sframe-common.js +++ b/www/common/sframe-common.js @@ -34,6 +34,7 @@ define([ '/common/common-constants.js', '/components/localforage/dist/localforage.min.js', '/common/hyperscript.js', + '/common/extensions.js' ], function ( $, ApiConfig, @@ -64,7 +65,8 @@ define([ Language, Constants, localForage, - h + h, + Ext ) { // Chainpad Netflux Inner var funcs = {}; diff --git a/www/lib/optional/optional.js b/www/lib/optional/optional.js index 00767379f..c42ec2835 100644 --- a/www/lib/optional/optional.js +++ b/www/lib/optional/optional.js @@ -13,7 +13,7 @@ define("optional", [], { var onLoadFailure = function(err){ // optional module failed to load. var failedId = err.requireModules && err.requireModules[0]; - console.warn("Could not load optional module: " + failedId); + //console.warn("Could not load optional module: " + failedId); // Undefine the module to cleanup internal stuff in requireJS requirejs.undef(failedId);