From b0d71df604b182b45d83eee6872293f3d910109d Mon Sep 17 00:00:00 2001 From: Chad Weider Date: Mon, 28 May 2012 17:46:14 -0700 Subject: [PATCH 1/5] Fix worthless indentation. --- src/static/js/pluginfw/plugins.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/static/js/pluginfw/plugins.js b/src/static/js/pluginfw/plugins.js index 7efcb49c..5925e7d2 100644 --- a/src/static/js/pluginfw/plugins.js +++ b/src/static/js/pluginfw/plugins.js @@ -165,10 +165,10 @@ exports.update = function (cb) { }, function (err) { if (err) cb(err); - exports.plugins = plugins; + exports.plugins = plugins; exports.parts = exports.sortParts(parts); - exports.hooks = exports.extractHooks(exports.parts, "hooks"); - exports.loaded = true; + exports.hooks = exports.extractHooks(exports.parts, "hooks"); + exports.loaded = true; exports.callInit(cb); } ); @@ -200,9 +200,9 @@ exports.getPackages = function (cb) { flatten(tmp); cb(null, packages); }); - }; +}; - exports.loadPlugin = function (packages, plugin_name, plugins, parts, cb) { +exports.loadPlugin = function (packages, plugin_name, plugins, parts, cb) { var plugin_path = path.resolve(packages[plugin_name].path, "ep.json"); fs.readFile( plugin_path, @@ -226,7 +226,7 @@ exports.getPackages = function (cb) { cb(); } ); - }; +}; exports.partsToParentChildList = function (parts) { var res = []; From e375b6212a97af529427614134bcab0e1ef91751 Mon Sep 17 00:00:00 2001 From: Chad Weider Date: Mon, 28 May 2012 18:11:59 -0700 Subject: [PATCH 2/5] Static functions are static. --- src/static/js/pluginfw/plugins.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/static/js/pluginfw/plugins.js b/src/static/js/pluginfw/plugins.js index 5925e7d2..e691e4c2 100644 --- a/src/static/js/pluginfw/plugins.js +++ b/src/static/js/pluginfw/plugins.js @@ -53,7 +53,7 @@ exports.formatHooks = function (hook_set_name) { return "
" + res.join("\n") + "
"; }; -exports.loadFn = function (path, hookName) { +function loadFn(path, hookName) { var functionName , parts = path.split(":"); @@ -95,7 +95,7 @@ exports.extractHooks = function (parts, hook_set_name) { } try { - var hook_fn = exports.loadFn(hook_fn_name, hook_name); + var hook_fn = loadFn(hook_fn_name, hook_name); if (!hook_fn) { throw "Not a function"; } @@ -161,12 +161,12 @@ exports.update = function (cb) { async.forEach( Object.keys(packages), function (plugin_name, cb) { - exports.loadPlugin(packages, plugin_name, plugins, parts, cb); + loadPlugin(packages, plugin_name, plugins, parts, cb); }, function (err) { if (err) cb(err); exports.plugins = plugins; - exports.parts = exports.sortParts(parts); + exports.parts = sortParts(parts); exports.hooks = exports.extractHooks(exports.parts, "hooks"); exports.loaded = true; exports.callInit(cb); @@ -202,7 +202,10 @@ exports.getPackages = function (cb) { }); }; -exports.loadPlugin = function (packages, plugin_name, plugins, parts, cb) { +} + + +function loadPlugin(packages, plugin_name, plugins, parts, cb) { var plugin_path = path.resolve(packages[plugin_name].path, "ep.json"); fs.readFile( plugin_path, @@ -226,9 +229,9 @@ exports.loadPlugin = function (packages, plugin_name, plugins, parts, cb) { cb(); } ); -}; +} -exports.partsToParentChildList = function (parts) { +function partsToParentChildList(parts) { var res = []; _.chain(parts).keys().forEach(function (name) { _.each(parts[name].post || [], function (child_name) { @@ -242,18 +245,15 @@ exports.partsToParentChildList = function (parts) { } }); return res; -}; - +} // Used only in Node, so no need for _ -exports.sortParts = function(parts) { +function sortParts(parts) { return tsort( - exports.partsToParentChildList(parts) + partsToParentChildList(parts) ).filter( function (name) { return parts[name] !== undefined; } ).map( function (name) { return parts[name]; } ); -}; - -} \ No newline at end of file +} From 3631f0ece3abb0f40ca368a2133ee3397f12a617 Mon Sep 17 00:00:00 2001 From: Chad Weider Date: Mon, 28 May 2012 18:33:03 -0700 Subject: [PATCH 3/5] Inject special normalization behavior. --- src/static/js/pluginfw/plugins.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/static/js/pluginfw/plugins.js b/src/static/js/pluginfw/plugins.js index e691e4c2..9a8b7ac5 100644 --- a/src/static/js/pluginfw/plugins.js +++ b/src/static/js/pluginfw/plugins.js @@ -76,7 +76,7 @@ function loadFn(path, hookName) { return fn; }; -exports.extractHooks = function (parts, hook_set_name) { +function extractHooks(parts, hook_set_name, normalizer) { var hooks = {}; _.each(parts,function (part) { _.chain(part[hook_set_name] || {}) @@ -90,8 +90,8 @@ exports.extractHooks = function (parts, hook_set_name) { * require("pluginname/whatever") if the plugin is installed as * a dependency of another plugin! Bah, pesky little details of * npm... */ - if (!exports.isClient) { - hook_fn_name = path.normalize(path.join(path.dirname(exports.plugins[part.plugin].package.path), hook_fn_name)); + if (normalizer) { + hook_fn_name = normalizer(part, hook_fn_name); } try { @@ -121,7 +121,7 @@ if (exports.isClient) { jQuery.getJSON(exports.baseURL + 'pluginfw/plugin-definitions.json', function(data) { exports.plugins = data.plugins; exports.parts = data.parts; - exports.hooks = exports.extractHooks(exports.parts, "client_hooks"); + exports.hooks = extractHooks(exports.parts, "client_hooks"); exports.loaded = true; callback(); }).error(function(xhr, s, err){ @@ -153,6 +153,10 @@ exports.callInit = function (cb) { ); } +exports.pathNormalization = function (part, hook_fn_name) { + return path.normalize(path.join(path.dirname(exports.plugins[part.plugin].package.path), hook_fn_name)); +} + exports.update = function (cb) { exports.getPackages(function (er, packages) { var parts = []; @@ -167,7 +171,7 @@ exports.update = function (cb) { if (err) cb(err); exports.plugins = plugins; exports.parts = sortParts(parts); - exports.hooks = exports.extractHooks(exports.parts, "hooks"); + exports.hooks = exports.extractHooks(exports.parts, "hooks", exports.pathNormalization); exports.loaded = true; exports.callInit(cb); } From 93944953640cc2fd2af05f63cd32b809ca2b7e6b Mon Sep 17 00:00:00 2001 From: Chad Weider Date: Mon, 28 May 2012 18:58:55 -0700 Subject: [PATCH 4/5] Inject plugins into hooks. --- src/static/js/pluginfw/hooks.js | 17 ++++++++--------- src/templates/pad.html | 2 ++ src/templates/timeslider.html | 3 +++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/static/js/pluginfw/hooks.js b/src/static/js/pluginfw/hooks.js index 44f5fc3f..d9a14d85 100644 --- a/src/static/js/pluginfw/hooks.js +++ b/src/static/js/pluginfw/hooks.js @@ -1,4 +1,3 @@ -var plugins = require("./plugins"); var async = require("async"); var _ = require("underscore"); @@ -71,8 +70,8 @@ exports.flatten = function (lst) { exports.callAll = function (hook_name, args) { if (!args) args = {}; - if (plugins.hooks[hook_name] === undefined) return []; - return _.flatten(_.map(plugins.hooks[hook_name], function (hook) { + if (exports.plugins.hooks[hook_name] === undefined) return []; + return _.flatten(_.map(exports.plugins.hooks[hook_name], function (hook) { return hookCallWrapper(hook, hook_name, args); }), true); } @@ -80,9 +79,9 @@ exports.callAll = function (hook_name, args) { exports.aCallAll = function (hook_name, args, cb) { if (!args) args = {}; if (!cb) cb = function () {}; - if (plugins.hooks[hook_name] === undefined) return cb(null, []); + if (exports.plugins.hooks[hook_name] === undefined) return cb(null, []); async.map( - plugins.hooks[hook_name], + exports.plugins.hooks[hook_name], function (hook, cb) { hookCallWrapper(hook, hook_name, args, function (res) { cb(null, res); }); }, @@ -94,8 +93,8 @@ exports.aCallAll = function (hook_name, args, cb) { exports.callFirst = function (hook_name, args) { if (!args) args = {}; - if (plugins.hooks[hook_name] === undefined) return []; - return exports.syncMapFirst(plugins.hooks[hook_name], function (hook) { + if (exports.plugins.hooks[hook_name] === undefined) return []; + return exports.syncMapFirst(exports.plugins.hooks[hook_name], function (hook) { return hookCallWrapper(hook, hook_name, args); }); } @@ -103,9 +102,9 @@ exports.callFirst = function (hook_name, args) { exports.aCallFirst = function (hook_name, args, cb) { if (!args) args = {}; if (!cb) cb = function () {}; - if (plugins.hooks[hook_name] === undefined) return cb(null, []); + if (exports.plugins.hooks[hook_name] === undefined) return cb(null, []); exports.mapFirst( - plugins.hooks[hook_name], + exports.plugins.hooks[hook_name], function (hook, cb) { hookCallWrapper(hook, hook_name, args, function (res) { cb(null, res); }); }, diff --git a/src/templates/pad.html b/src/templates/pad.html index 1f179785..c1264783 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -374,6 +374,8 @@ plugins.baseURL = baseURL; plugins.update(function () { + hooks.plugins = plugins; + // Call documentReady hook $(function() { hooks.aCallAll('documentReady'); diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index 02af9f6c..d02a5f64 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -179,6 +179,9 @@ plugins.baseURL = baseURL; plugins.update(function () { + var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); + hooks.plugins = plugins; + var timeslider = require('ep_etherpad-lite/static/js/timeslider') timeslider.baseURL = baseURL; timeslider.init(); From 1258ed3a0d676f60707e619af757d8b6b9270bfb Mon Sep 17 00:00:00 2001 From: Chad Weider Date: Mon, 28 May 2012 18:39:32 -0700 Subject: [PATCH 5/5] Split client and server plugin functionality. There is virtually no shared code for the client, extract it into its own module and do away with the switches. --- src/node/server.js | 1 + src/node/utils/tar.json | 3 +- src/static/js/ace.js | 2 +- src/static/js/ace2_inner.js | 2 +- src/static/js/pluginfw/client_plugins.js | 36 +++++++ src/static/js/pluginfw/plugins.js | 116 +++-------------------- src/static/js/pluginfw/shared.js | 61 ++++++++++++ src/templates/pad.html | 2 +- src/templates/timeslider.html | 2 +- 9 files changed, 117 insertions(+), 108 deletions(-) create mode 100644 src/static/js/pluginfw/client_plugins.js create mode 100644 src/static/js/pluginfw/shared.js diff --git a/src/node/server.js b/src/node/server.js index d2ef9334..cca76c1f 100755 --- a/src/node/server.js +++ b/src/node/server.js @@ -29,6 +29,7 @@ var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins"); var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks"); var npm = require("npm/lib/npm.js"); +hooks.plugins = plugins; //set loglevel log4js.setGlobalLogLevel(settings.loglevel); diff --git a/src/node/utils/tar.json b/src/node/utils/tar.json index 36276767..9bb2027e 100644 --- a/src/node/utils/tar.json +++ b/src/node/utils/tar.json @@ -68,7 +68,8 @@ , "security.js" , "$security.js" , "json2.js" - , "pluginfw/plugins.js" + , "pluginfw/client_plugins.js" + , "pluginfw/shared.js" , "pluginfw/hooks.js" , "pluginfw/parent_require.js" ] diff --git a/src/static/js/ace.js b/src/static/js/ace.js index dabe5595..6bea8d22 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -244,7 +244,7 @@ require.setGlobalKeyPath("require");\n\ \ '); diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 07580faa..6bf6720f 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -23,7 +23,7 @@ var editor, _, $, jQuery, plugins, Ace2Common; Ace2Common = require('./ace2_common'); -plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins'); +plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins'); $ = jQuery = require('./rjquery').$; _ = require("./underscore"); diff --git a/src/static/js/pluginfw/client_plugins.js b/src/static/js/pluginfw/client_plugins.js new file mode 100644 index 00000000..27350028 --- /dev/null +++ b/src/static/js/pluginfw/client_plugins.js @@ -0,0 +1,36 @@ +var $, jQuery; +$ = jQuery = require("ep_etherpad-lite/static/js/rjquery").$; +var _ = require("underscore"); + +var pluginUtils = require('./shared'); + +exports.loaded = false; +exports.plugins = {}; +exports.parts = []; +exports.hooks = {}; +exports.baseURL = ''; + +exports.ensure = function (cb) { + if (!exports.loaded) + exports.update(cb); + else + cb(); +}; + +exports.update = function (cb) { + // It appears that this response (see #620) may interrupt the current thread + // of execution on Firefox. This schedules the response in the run-loop, + // which appears to fix the issue. + var callback = function () {setTimeout(cb, 0);}; + + jQuery.getJSON(exports.baseURL + 'pluginfw/plugin-definitions.json', function(data) { + exports.plugins = data.plugins; + exports.parts = data.parts; + exports.hooks = pluginUtils.extractHooks(exports.parts, "client_hooks"); + exports.loaded = true; + callback(); + }).error(function(xhr, s, err){ + console.error("Failed to load plugin-definitions: " + err); + callback(); + }); +}; diff --git a/src/static/js/pluginfw/plugins.js b/src/static/js/pluginfw/plugins.js index 9a8b7ac5..12ba94a2 100644 --- a/src/static/js/pluginfw/plugins.js +++ b/src/static/js/pluginfw/plugins.js @@ -1,30 +1,21 @@ -exports.isClient = typeof global != "object"; +var npm = require("npm/lib/npm.js"); +var readInstalled = require("./read-installed.js"); +var relativize = require("npm/lib/utils/relativize.js"); +var readJson = require("npm/lib/utils/read-json.js"); +var path = require("path"); +var async = require("async"); +var fs = require("fs"); +var tsort = require("./tsort"); +var util = require("util"); +var _ = require("underscore"); -var _; - -if (!exports.isClient) { - var npm = require("npm/lib/npm.js"); - var readInstalled = require("./read-installed.js"); - var relativize = require("npm/lib/utils/relativize.js"); - var readJson = require("npm/lib/utils/read-json.js"); - var path = require("path"); - var async = require("async"); - var fs = require("fs"); - var tsort = require("./tsort"); - var util = require("util"); - _ = require("underscore"); -}else{ - var $, jQuery; - $ = jQuery = require("ep_etherpad-lite/static/js/rjquery").$; - _ = require("ep_etherpad-lite/static/js/underscore"); -} +var pluginUtils = require('./shared'); exports.prefix = 'ep_'; exports.loaded = false; exports.plugins = {}; exports.parts = []; exports.hooks = {}; -exports.baseURL = ''; exports.ensure = function (cb) { if (!exports.loaded) @@ -43,7 +34,7 @@ exports.formatParts = function () { exports.formatHooks = function (hook_set_name) { var res = []; - var hooks = exports.extractHooks(exports.parts, hook_set_name || "hooks"); + var hooks = pluginUtils.extractHooks(exports.parts, hook_set_name || "hooks"); _.chain(hooks).keys().forEach(function (hook_name) { _.forEach(hooks[hook_name], function (hook) { @@ -53,84 +44,6 @@ exports.formatHooks = function (hook_set_name) { return "
" + res.join("\n") + "
"; }; -function loadFn(path, hookName) { - var functionName - , parts = path.split(":"); - - // on windows: C:\foo\bar:xyz - if(parts[0].length == 1) { - if(parts.length == 3) - functionName = parts.pop(); - path = parts.join(":"); - }else{ - path = parts[0]; - functionName = parts[1]; - } - - var fn = require(path); - functionName = functionName ? functionName : hookName; - - _.each(functionName.split("."), function (name) { - fn = fn[name]; - }); - return fn; -}; - -function extractHooks(parts, hook_set_name, normalizer) { - var hooks = {}; - _.each(parts,function (part) { - _.chain(part[hook_set_name] || {}) - .keys() - .each(function (hook_name) { - if (hooks[hook_name] === undefined) hooks[hook_name] = []; - - var hook_fn_name = part[hook_set_name][hook_name]; - - /* On the server side, you can't just - * require("pluginname/whatever") if the plugin is installed as - * a dependency of another plugin! Bah, pesky little details of - * npm... */ - if (normalizer) { - hook_fn_name = normalizer(part, hook_fn_name); - } - - try { - var hook_fn = loadFn(hook_fn_name, hook_name); - if (!hook_fn) { - throw "Not a function"; - } - } catch (exc) { - console.error("Failed to load '" + hook_fn_name + "' for '" + part.full_name + "/" + hook_set_name + "/" + hook_name + "': " + exc.toString()) - } - if (hook_fn) { - hooks[hook_name].push({"hook_name": hook_name, "hook_fn": hook_fn, "hook_fn_name": hook_fn_name, "part": part}); - } - }); - }); - return hooks; -}; - - -if (exports.isClient) { - exports.update = function (cb) { - // It appears that this response (see #620) may interrupt the current thread - // of execution on Firefox. This schedules the response in the run-loop, - // which appears to fix the issue. - var callback = function () {setTimeout(cb, 0);}; - - jQuery.getJSON(exports.baseURL + 'pluginfw/plugin-definitions.json', function(data) { - exports.plugins = data.plugins; - exports.parts = data.parts; - exports.hooks = extractHooks(exports.parts, "client_hooks"); - exports.loaded = true; - callback(); - }).error(function(xhr, s, err){ - console.error("Failed to load plugin-definitions: " + err); - callback(); - }); - }; -} else { - exports.callInit = function (cb) { var hooks = require("./hooks"); async.map( @@ -171,7 +84,7 @@ exports.update = function (cb) { if (err) cb(err); exports.plugins = plugins; exports.parts = sortParts(parts); - exports.hooks = exports.extractHooks(exports.parts, "hooks", exports.pathNormalization); + exports.hooks = pluginUtils.extractHooks(exports.parts, "hooks", exports.pathNormalization); exports.loaded = true; exports.callInit(cb); } @@ -206,9 +119,6 @@ exports.getPackages = function (cb) { }); }; -} - - function loadPlugin(packages, plugin_name, plugins, parts, cb) { var plugin_path = path.resolve(packages[plugin_name].path, "ep.json"); fs.readFile( diff --git a/src/static/js/pluginfw/shared.js b/src/static/js/pluginfw/shared.js new file mode 100644 index 00000000..4df71aee --- /dev/null +++ b/src/static/js/pluginfw/shared.js @@ -0,0 +1,61 @@ +var _ = require("underscore"); + +function loadFn(path, hookName) { + var functionName + , parts = path.split(":"); + + // on windows: C:\foo\bar:xyz + if (parts[0].length == 1) { + if (parts.length == 3) { + functionName = parts.pop(); + } + path = parts.join(":"); + } else { + path = parts[0]; + functionName = parts[1]; + } + + var fn = require(path); + functionName = functionName ? functionName : hookName; + + _.each(functionName.split("."), function (name) { + fn = fn[name]; + }); + return fn; +}; + +function extractHooks(parts, hook_set_name, normalizer) { + var hooks = {}; + _.each(parts,function (part) { + _.chain(part[hook_set_name] || {}) + .keys() + .each(function (hook_name) { + if (hooks[hook_name] === undefined) hooks[hook_name] = []; + + var hook_fn_name = part[hook_set_name][hook_name]; + + /* On the server side, you can't just + * require("pluginname/whatever") if the plugin is installed as + * a dependency of another plugin! Bah, pesky little details of + * npm... */ + if (normalizer) { + hook_fn_name = normalizer(part, hook_fn_name); + } + + try { + var hook_fn = loadFn(hook_fn_name, hook_name); + if (!hook_fn) { + throw "Not a function"; + } + } catch (exc) { + console.error("Failed to load '" + hook_fn_name + "' for '" + part.full_name + "/" + hook_set_name + "/" + hook_name + "': " + exc.toString()) + } + if (hook_fn) { + hooks[hook_name].push({"hook_name": hook_name, "hook_fn": hook_fn, "hook_fn_name": hook_fn_name, "part": part}); + } + }); + }); + return hooks; +}; + +exports.extractHooks = extractHooks; diff --git a/src/templates/pad.html b/src/templates/pad.html index c1264783..425e476d 100644 --- a/src/templates/pad.html +++ b/src/templates/pad.html @@ -369,7 +369,7 @@ document.domain = document.domain; // for comet } - var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins'); + var plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins'); var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); plugins.baseURL = baseURL; diff --git a/src/templates/timeslider.html b/src/templates/timeslider.html index d02a5f64..469ddd94 100644 --- a/src/templates/timeslider.html +++ b/src/templates/timeslider.html @@ -175,7 +175,7 @@ document.domain = document.domain; // for comet } - var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins'); + var plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins'); plugins.baseURL = baseURL; plugins.update(function () {