diff --git a/README.md b/README.md
index 84e866585..2a30b9708 100644
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ Here is the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**
**As root:**
- - Install the dependencies. We need gzip, git, curl, libssl develop libraries, python and gcc.
For Debian/Ubuntu apt-get install gzip git-core curl python libssl-dev build-essential
+ - Install the dependencies. We need gzip, git, curl, libssl develop libraries, python and gcc.
For Debian/Ubuntu apt-get install gzip git-core curl python libssl-dev pkg-config build-essential
For Fedora/CentOS yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"
- Install node.js
@@ -73,6 +73,7 @@ Here is the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**
- Move to a folder where you want to install Etherpad Lite. Clone the git repository
git clone 'git://github.com/Pita/etherpad-lite.git'
+ - Change into the directory containing the Etherpad Lite source code clone with
cd etherpad-lite
- Install the dependencies with
bin/installDeps.sh
- Start it with
bin/run.sh
- Open your web browser and visit http://localhost:9001. You like it? Look at the 'Next Steps' section below
diff --git a/README.plugins b/README.plugins
new file mode 100644
index 000000000..72c456447
--- /dev/null
+++ b/README.plugins
@@ -0,0 +1,16 @@
+So, a plugin is an npm package whose name starts with ep_ and that contains a file ep.json
+require("ep_etherpad-lite/static/js/plugingfw/plugins").update() will use npm to list all installed modules and read their ep.json files. These will contain registrations for hooks which are loaded
+A hook registration is a pairs of a hook name and a function reference (filename for require() plus function name)
+require("ep_etherpad-lite/static/js/plugingfw/hooks").callAll("hook_name", {argname:value}) will call all hook functions registered for hook_name
+That is the basis.
+Ok, so that was a slight simplification: inside ep.json, hook registrations are grouped into groups called "parts". Parts from all plugins are ordered using a topological sort according to "pre" and "post" pointers to other plugins/parts (just like dependencies, but non-installed plugins are silently ignored).
+This ordering is honored when you do callAll(hook_name) - hook functions for that hook_name are called in that order
+Ordering between plugins is undefined, only parts are ordered.
+
+A plugin usually has one part, but it van have multiple.
+This is so that it can insert some hook registration before that of another plugin, and another one after.
+This is important for e.g. registering URL-handlers for the express webserver, if you have some very generic and some very specific url-regexps
+So, that's basically it... apart from client-side hooks
+which works the same way, but uses a separate member of the part (part.client_hooks vs part.hooks), and where the hook function must obviously reside in a file require():able from the client...
+One thing more: The main etherpad tree is actually a plugin itself, called ep_etherpad-lite, and it has it's own ep.json...
+was that clear?
\ No newline at end of file
diff --git a/src/ep.json b/src/ep.json
index bc955dbf3..59cbf3aa4 100644
--- a/src/ep.json
+++ b/src/ep.json
@@ -3,7 +3,6 @@
{ "name": "static", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/static:expressCreateServer" } },
{ "name": "specialpages", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/specialpages:expressCreateServer" } },
{ "name": "padurlsanitize", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/padurlsanitize:expressCreateServer" } },
- { "name": "minified", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/minified:expressCreateServer" } },
{ "name": "padreadonly", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/padreadonly:expressCreateServer" } },
{ "name": "webaccess", "hooks": { "expressConfigure": "ep_etherpad-lite/node/hooks/express/webaccess:expressConfigure" } },
{ "name": "apicalls", "hooks": { "expressCreateServer": "ep_etherpad-lite/node/hooks/express/apicalls:expressCreateServer" } },
diff --git a/src/node/hooks/express/minified.js b/src/node/hooks/express/minified.js
deleted file mode 100644
index f8a988d77..000000000
--- a/src/node/hooks/express/minified.js
+++ /dev/null
@@ -1,6 +0,0 @@
-var minify = require('../../utils/Minify');
-
-exports.expressCreateServer = function (hook_name, args, cb) {
- //serve minified files
- args.app.get(/^\/minified\/(.*)/, minify.minifyJS);
-}
diff --git a/src/node/hooks/express/static.js b/src/node/hooks/express/static.js
index 9481eb5a2..e8f9afbb8 100644
--- a/src/node/hooks/express/static.js
+++ b/src/node/hooks/express/static.js
@@ -8,34 +8,9 @@ var fs = require("fs");
var ERR = require("async-stacktrace");
exports.expressCreateServer = function (hook_name, args, cb) {
- /* Handle static files for plugins:
- paths like "/static/plugins/ep_myplugin/js/test.js"
- are rewritten into ROOT_PATH_OF_MYPLUGIN/static/js/test.js,
- commonly ETHERPAD_ROOT/node_modules/ep_myplugin/static/js/test.js
- */
- args.app.get(/^\/minified\/plugins\/([^\/]+)\/static\/(.*)/, function(req, res, next) {
- var plugin_name = req.params[0];
- var modulePath = req.url.split("?")[0].substr("/minified/plugins/".length);
- var fullPath = require.resolve(modulePath);
-
- if (plugins.plugins[plugin_name] == undefined) {
- return next();
- }
-
- fs.readFile(fullPath, "utf8", function(err, data){
- if(ERR(err)) return;
-
- res.send("require.define('" + modulePath + "', function (require, exports, module) {" + data + "})");
- })
-
-//require.define("/plugins.js", function (require, exports, module) {
-
- //res.sendfile(fullPath);
- });
-
// Cache both minified and static.
var assetCache = new CachingMiddleware;
- args.app.all('/(minified|static)/*', assetCache.handle);
+ args.app.all('/(javascripts|static)/*', assetCache.handle);
// Minify will serve static files compressed (minify enabled). It also has
// file-specific hacks for ace/require-kernel/etc.
@@ -44,8 +19,10 @@ exports.expressCreateServer = function (hook_name, args, cb) {
// Setup middleware that will package JavaScript files served by minify for
// CommonJS loader on the client-side.
var jsServer = new (Yajsml.Server)({
- rootPath: 'minified/'
+ rootPath: 'javascripts/src/'
, rootURI: 'http://localhost:' + settings.port + '/static/js/'
+ , libraryPath: 'javascripts/lib/'
+ , libraryURI: 'http://localhost:' + settings.port + '/static/plugins/'
});
var StaticAssociator = Yajsml.associators.StaticAssociator;
diff --git a/src/node/utils/Minify.js b/src/node/utils/Minify.js
index a49195a7b..f569d4b92 100644
--- a/src/node/utils/Minify.js
+++ b/src/node/utils/Minify.js
@@ -27,6 +27,7 @@ var cleanCSS = require('clean-css');
var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;
var path = require('path');
+var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins");
var RequireKernel = require('require-kernel');
var server = require('../server');
@@ -35,11 +36,14 @@ var TAR_PATH = path.join(__dirname, 'tar.json');
var tar = JSON.parse(fs.readFileSync(TAR_PATH, 'utf8'));
// Rewrite tar to include modules with no extensions and proper rooted paths.
+var LIBRARY_PREFIX = 'ep_etherpad-lite/static/js';
exports.tar = {};
for (var key in tar) {
- exports.tar['/' + key] =
- tar[key].map(function (p) {return '/' + p}).concat(
- tar[key].map(function (p) {return '/' + p.replace(/\.js$/, '')})
+ exports.tar[LIBRARY_PREFIX + '/' + key] =
+ tar[key].map(function (p) {return LIBRARY_PREFIX + '/' + p}).concat(
+ tar[key].map(function (p) {
+ return LIBRARY_PREFIX + '/' + p.replace(/\.js$/, '')
+ })
);
}
@@ -63,6 +67,22 @@ exports.minify = function(req, res, next)
return;
}
+ /* Handle static files for plugins:
+ paths like "plugins/ep_myplugin/static/js/test.js"
+ are rewritten into ROOT_PATH_OF_MYPLUGIN/static/js/test.js,
+ commonly ETHERPAD_ROOT/node_modules/ep_myplugin/static/js/test.js
+ */
+ var match = filename.match(/^plugins\/([^\/]+)\/static\/(.*)/);
+ if (match) {
+ var pluginName = match[1];
+ var resourcePath = match[2];
+ var plugin = plugins.plugins[pluginName];
+ if (plugin) {
+ var pluginPath = plugin.package.realPath;
+ filename = path.relative(ROOT_DIR, pluginPath + '/static/' + resourcePath);
+ }
+ }
+
// What content type should this be?
// TODO: This should use a MIME module.
var contentType;
@@ -149,8 +169,10 @@ function getAceFile(callback) {
var request = require('request');
var baseURI = 'http://localhost:' + settings.port
+ var resourceURI = baseURI + path.normalize(path.join('/static/', filename));
+ resourceURI = resourceURI.replace(/\\/g, '/'); // Windows (safe generally?)
- request(baseURI + path.normalize(path.join('/static/', filename)), function (error, response, body) {
+ request(resourceURI, function (error, response, body) {
if (!error && response.statusCode == 200) {
data += 'Ace2Editor.EMBEDED[' + JSON.stringify(filename) + '] = '
+ JSON.stringify(body || '') + ';\n';
diff --git a/src/node/utils/caching_middleware.js b/src/node/utils/caching_middleware.js
index f25059b88..114356f23 100644
--- a/src/node/utils/caching_middleware.js
+++ b/src/node/utils/caching_middleware.js
@@ -21,9 +21,10 @@ var path = require('path');
var server = require('../server');
var zlib = require('zlib');
var util = require('util');
+var settings = require('./Settings');
-var ROOT_DIR = path.normalize(__dirname + "/../");
-var CACHE_DIR = ROOT_DIR + '../var/';
+var CACHE_DIR = path.normalize(path.join(settings.root, 'var/'));
+CACHE_DIR = path.existsSync(CACHE_DIR) ? CACHE_DIR : undefined;
var responseCache = {};
@@ -37,7 +38,7 @@ function CachingMiddleware() {
}
CachingMiddleware.prototype = new function () {
function handle(req, res, next) {
- if (!(req.method == "GET" || req.method == "HEAD")) {
+ if (!(req.method == "GET" || req.method == "HEAD") || !CACHE_DIR) {
return next(undefined, req, res);
}
@@ -54,7 +55,7 @@ CachingMiddleware.prototype = new function () {
var modifiedSince = (req.headers['if-modified-since']
&& new Date(req.headers['if-modified-since']));
var lastModifiedCache = !error && stats.mtime;
- if (lastModifiedCache) {
+ if (lastModifiedCache && responseCache[cacheKey]) {
req.headers['if-modified-since'] = lastModifiedCache.toUTCString();
} else {
delete req.headers['if-modified-since'];
@@ -83,7 +84,7 @@ CachingMiddleware.prototype = new function () {
&& new Date(res.getHeader('last-modified')));
res.writeHead = old_res.writeHead;
- if (status == 200 || status == 404) {
+ if (status == 200) {
// Update cache
var buffer = '';
diff --git a/src/package.json b/src/package.json
index 556b1c494..80378a0a3 100644
--- a/src/package.json
+++ b/src/package.json
@@ -12,7 +12,7 @@
"dependencies" : {
"yajsml" : "1.1.2",
"request" : "2.9.100",
- "require-kernel" : "1.0.3",
+ "require-kernel" : "1.0.5",
"socket.io" : "0.8.7",
"ueberDB" : "0.1.7",
"async" : "0.1.18",
diff --git a/src/static/js/Changeset.js b/src/static/js/Changeset.js
index 2eb89c53b..fd1900ba7 100644
--- a/src/static/js/Changeset.js
+++ b/src/static/js/Changeset.js
@@ -25,7 +25,7 @@
* limitations under the License.
*/
-var AttributePoolFactory = require("ep_etherpad-lite/static/js/AttributePoolFactory");
+var AttributePoolFactory = require("./AttributePoolFactory");
var _opt = null;
diff --git a/src/static/js/ace.js b/src/static/js/ace.js
index 4114b63cf..1306dba01 100644
--- a/src/static/js/ace.js
+++ b/src/static/js/ace.js
@@ -28,7 +28,7 @@ Ace2Editor.registry = {
nextId: 1
};
-var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
+var hooks = require('./pluginfw/hooks');
function Ace2Editor()
{
@@ -156,7 +156,11 @@ function Ace2Editor()
}
function pushRequireScriptTo(buffer) {
var KERNEL_SOURCE = '../static/js/require-kernel.js';
- var KERNEL_BOOT = 'require.setRootURI("../minified/");\nrequire.setLibraryURI("../minified/plugins/");\nrequire.setGlobalKeyPath("require");'
+ var KERNEL_BOOT = '\
+require.setRootURI("../javascripts/src");\n\
+require.setLibraryURI("../javascripts/lib");\n\
+require.setGlobalKeyPath("require");\n\
+';
if (Ace2Editor.EMBEDED && Ace2Editor.EMBEDED[KERNEL_SOURCE]) {
buffer.push('\
-
+
diff --git a/src/static/timeslider.html b/src/static/timeslider.html
index 377740f75..413fbe804 100644
--- a/src/static/timeslider.html
+++ b/src/static/timeslider.html
@@ -200,13 +200,13 @@
-
+