diff --git a/.gitignore b/.gitignore
index 50cd6e212..32f9ea7d7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
node_modules
settings.json
-static/js/jquery.min.js
+static/js/jquery.js
APIKEY.txt
bin/abiword.exe
bin/node.exe
diff --git a/README.md b/README.md
index aaf2c8fbc..4995e852a 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ Here is the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**
- 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
- For Fedora/CentOS yum install gzip git-core curl python openssl-dev && yum groupinstall "Development Tools"
+ For Fedora/CentOS yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"
- Install node.js
@@ -98,7 +98,7 @@ Look at this wiki pages:
You can find more information in the [wiki](https://github.com/Pita/etherpad-lite/wiki). Feel free to improve these wiki pages
# Develop
-If you're new to git and github, start here .
+If you're new to git and github, start by watching [this video](http://youtu.be/67-Q26YH97E) then read this [git guide](http://learn.github.com/p/intro.html).
If you're new to node.js, start with this video .
diff --git a/bin/installDeps.sh b/bin/installDeps.sh
index 0533caf2d..a3f767a24 100755
--- a/bin/installDeps.sh
+++ b/bin/installDeps.sh
@@ -48,8 +48,8 @@ npm install || {
echo "Ensure jQuery is downloaded and up to date..."
DOWNLOAD_JQUERY="true"
NEEDED_VERSION="1.7"
-if [ -f "static/js/jquery.min.js" ]; then
- VERSION=$(cat static/js/jquery.min.js | head -n 3 | grep -o "v[0-9].[0-9]");
+if [ -f "static/js/jquery.js" ]; then
+ VERSION=$(cat static/js/jquery.js | head -n 3 | grep -o "v[0-9].[0-9]");
if [ ${VERSION#v} = $NEEDED_VERSION ]; then
DOWNLOAD_JQUERY="false"
@@ -57,7 +57,7 @@ if [ -f "static/js/jquery.min.js" ]; then
fi
if [ $DOWNLOAD_JQUERY = "true" ]; then
- curl -lo static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js || exit 1
+ curl -lo static/js/jquery.js http://code.jquery.com/jquery-$NEEDED_VERSION.js || exit 1
fi
#Remove all minified data to force node creating it new
diff --git a/node/server.js b/node/server.js
index 50f486337..c0d6ce6ad 100644
--- a/node/server.js
+++ b/node/server.js
@@ -78,7 +78,12 @@ async.waterfall([
{
//create server
var app = express.createServer();
-
+
+ app.use(function (req, res, next) {
+ res.header("Server", serverName);
+ next();
+ });
+
//load modules that needs a initalized db
readOnlyManager = require("./db/ReadOnlyManager");
exporthtml = require("./utils/ExportHtml");
@@ -109,31 +114,24 @@ async.waterfall([
gracefulShutdown();
});
+ //serve minified files
+ app.get('/minified/:filename', minify.minifyJS);
+
//serve static files
+ app.get('/static/js/require-kernel.js', function (req, res, next) {
+ res.header("Content-Type","application/javascript; charset: utf-8");
+ res.write(minify.requireDefinition());
+ res.end();
+ });
app.get('/static/*', function(req, res)
{
- res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/.." +
req.url.replace(/\.\./g, '').split("?")[0]);
res.sendfile(filePath, { maxAge: exports.maxAge });
});
//serve minified files
- app.get('/minified/:id', function(req, res, next)
- {
- res.header("Server", serverName);
-
- var id = req.params.id;
-
- if(id == "pad.js" || id == "timeslider.js")
- {
- minify.minifyJS(req,res,id);
- }
- else
- {
- next();
- }
- });
+ app.get('/minified/:filename', minify.minifyJS);
//checks for padAccess
function hasPadAccess(req, res, callback)
@@ -178,8 +176,6 @@ async.waterfall([
//serve read only pad
app.get('/ro/:id', function(req, res)
{
- res.header("Server", serverName);
-
var html;
var padId;
var pad;
@@ -264,7 +260,6 @@ async.waterfall([
app.get('/p/:pad', function(req, res, next)
{
goToPad(req, res, function() {
- res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/pad.html");
res.sendfile(filePath, { maxAge: exports.maxAge });
});
@@ -274,7 +269,6 @@ async.waterfall([
app.get('/p/:pad/timeslider', function(req, res, next)
{
goToPad(req, res, function() {
- res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/timeslider.html");
res.sendfile(filePath, { maxAge: exports.maxAge });
});
@@ -301,7 +295,6 @@ async.waterfall([
}
res.header("Access-Control-Allow-Origin", "*");
- res.header("Server", serverName);
hasPadAccess(req, res, function()
{
@@ -321,8 +314,6 @@ async.waterfall([
return;
}
- res.header("Server", serverName);
-
hasPadAccess(req, res, function()
{
importHandler.doImport(req, res, req.params.pad);
@@ -335,7 +326,6 @@ async.waterfall([
//This is for making an api call, collecting all post information and passing it to the apiHandler
var apiCaller = function(req, res, fields)
{
- res.header("Server", serverName);
res.header("Content-Type", "application/json; charset=utf-8");
apiLogger.info("REQUEST, " + req.params.func + ", " + JSON.stringify(fields));
@@ -396,7 +386,6 @@ async.waterfall([
//serve index.html under /
app.get('/', function(req, res)
{
- res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/index.html");
res.sendfile(filePath, { maxAge: exports.maxAge });
});
@@ -404,7 +393,6 @@ async.waterfall([
//serve robots.txt
app.get('/robots.txt', function(req, res)
{
- res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/robots.txt");
res.sendfile(filePath, { maxAge: exports.maxAge });
});
@@ -412,7 +400,6 @@ async.waterfall([
//serve favicon.ico
app.get('/favicon.ico', function(req, res)
{
- res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/custom/favicon.ico");
res.sendfile(filePath, { maxAge: exports.maxAge }, function(err)
{
diff --git a/node/utils/Minify.js b/node/utils/Minify.js
index 3477cd010..ea7834dc1 100644
--- a/node/utils/Minify.js
+++ b/node/utils/Minify.js
@@ -28,10 +28,15 @@ var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;
var path = require('path');
var Buffer = require('buffer').Buffer;
-var gzip = require('gzip');
+var zlib = require('zlib');
+var RequireKernel = require('require-kernel');
var server = require('../server');
var os = require('os');
+var ROOT_DIR = path.normalize(__dirname + "/../" );
+var JS_DIR = ROOT_DIR + '../static/js/';
+var CSS_DIR = ROOT_DIR + '../static/css/';
+var CACHE_DIR = ROOT_DIR + '../var/';
var TAR_PATH = path.join(__dirname, 'tar.json');
var tar = JSON.parse(fs.readFileSync(TAR_PATH, 'utf8'));
@@ -40,20 +45,31 @@ var tar = JSON.parse(fs.readFileSync(TAR_PATH, 'utf8'));
* @param req the Express request
* @param res the Express response
*/
-exports.minifyJS = function(req, res, jsFilename)
+exports.minifyJS = function(req, res, next)
{
- res.header("Content-Type","text/javascript");
+ var jsFilename = req.params['filename'];
//choose the js files we need
var jsFiles = undefined;
if (Object.prototype.hasOwnProperty.call(tar, jsFilename)) {
jsFiles = tar[jsFilename];
+ _handle(req, res, jsFilename, jsFiles)
} else {
- throw new Error("there is no profile for creating " + name);
+ // Not in tar list, but try anyways, if it fails, pass to `next`.
+ jsFiles = [jsFilename];
+ fs.stat(JS_DIR + jsFilename, function (error, stats) {
+ if (error || !stats.isFile()) {
+ next();
+ } else {
+ _handle(req, res, jsFilename, jsFiles);
+ }
+ });
}
+}
- var rootPath = path.normalize(__dirname + "/../../" );
-
+function _handle(req, res, jsFilename, jsFiles) {
+ res.header("Content-Type","text/javascript");
+
//minifying is enabled
if(settings.minify)
{
@@ -65,7 +81,7 @@ exports.minifyJS = function(req, res, jsFilename)
//find out the highest modification date
function(callback)
{
- var folders2check = [rootPath + "static/css", rootPath + "static/js"];
+ var folders2check = [CSS_DIR, JS_DIR];
//go trough this two folders
async.forEach(folders2check, function(path, callback)
@@ -104,7 +120,7 @@ exports.minifyJS = function(req, res, jsFilename)
function(callback)
{
//check the modification time of the minified js
- fs.stat(rootPath + "var/minified_" + jsFilename, function(err, stats)
+ fs.stat(CACHE_DIR + "/minified_" + jsFilename, function(err, stats)
{
if(err && err.code != "ENOENT")
{
@@ -129,7 +145,7 @@ exports.minifyJS = function(req, res, jsFilename)
{
async.forEach(jsFiles, function (item, callback)
{
- fs.readFile(rootPath + "static/js/" + item, "utf-8", function(err, data)
+ fs.readFile(JS_DIR + item, "utf-8", function(err, data)
{
if(ERR(err, callback)) return;
fileValues[item] = data;
@@ -147,7 +163,7 @@ exports.minifyJS = function(req, res, jsFilename)
return;
}
- var founds = fileValues["ace.js"].match(/\$\$INCLUDE_[a-zA-Z_]+\([a-zA-Z0-9.\/_"]+\)/gi);
+ var founds = fileValues["ace.js"].match(/\$\$INCLUDE_[a-zA-Z_]+\([a-zA-Z0-9.\/_"-]+\)/gi);
//go trough all includes
async.forEach(founds, function (item, callback)
@@ -158,21 +174,31 @@ exports.minifyJS = function(req, res, jsFilename)
var type = item.match(/INCLUDE_[A-Z]+/g)[0].substr("INCLUDE_".length);
//read the included file
- fs.readFile(filename, "utf-8", function(err, data)
+ var shortFilename = filename.replace(/^..\/static\/js\//, '');
+ if (shortFilename == 'require-kernel.js') {
+ // the kernel isn’t actually on the file system.
+ handleEmbed(null, requireDefinition());
+ } else {
+ fs.readFile(ROOT_DIR + filename, "utf-8", handleEmbed);
+ }
+ function handleEmbed(err, data)
{
if(ERR(err, callback)) return;
if(type == "JS")
{
- embeds[filename] = compressJS([data]);
+ if (shortFilename == 'require-kernel.js') {
+ embeds[filename] = compressJS([data]);
+ } else {
+ embeds[filename] = compressJS([isolateJS(data, shortFilename)]);
+ }
}
else
{
embeds[filename] = compressCSS([data]);
}
-
callback();
- });
+ }
}, function(err)
{
if(ERR(err, callback)) return;
@@ -193,42 +219,28 @@ exports.minifyJS = function(req, res, jsFilename)
//put all together and write it into a file
function(callback)
{
- //put all javascript files in an array
- var values = [];
- for(var i in jsFiles)
- {
- values.push(fileValues[jsFiles[i]]);
- }
-
//minify all javascript files to one
+ var values = [];
+ tarCode(jsFiles, fileValues, function (content) {values.push(content)});
var result = compressJS(values);
async.parallel([
//write the results plain in a file
function(callback)
{
- fs.writeFile(rootPath + "var/minified_" + jsFilename, result, "utf8", callback);
+ fs.writeFile(CACHE_DIR + "minified_" + jsFilename, result, "utf8", callback);
},
//write the results compressed in a file
function(callback)
{
- //spawn a gzip process if we're on a unix system
- if(os.type().indexOf("Windows") == -1)
- {
- gzip(result, 9, function(err, compressedResult){
- //weird gzip bug that returns 0 instead of null if everything is ok
- err = err === 0 ? null : err;
+ zlib.gzip(result, function(err, compressedResult){
+ //weird gzip bug that returns 0 instead of null if everything is ok
+ err = err === 0 ? null : err;
+
+ if(ERR(err, callback)) return;
- if(ERR(err, callback)) return;
-
- fs.writeFile(rootPath + "var/minified_" + jsFilename + ".gz", compressedResult, callback);
- });
- }
- //skip this step on windows
- else
- {
- callback();
- }
+ fs.writeFile(CACHE_DIR + "minified_" + jsFilename + ".gz", compressedResult, callback);
+ });
}
],callback);
}
@@ -245,12 +257,12 @@ exports.minifyJS = function(req, res, jsFilename)
var pathStr;
if(gzipSupport && os.type().indexOf("Windows") == -1)
{
- pathStr = path.normalize(rootPath + "var/minified_" + jsFilename + ".gz");
+ pathStr = path.normalize(CACHE_DIR + "minified_" + jsFilename + ".gz");
res.header('Content-Encoding', 'gzip');
}
else
{
- pathStr = path.normalize(rootPath + "var/minified_" + jsFilename );
+ pathStr = path.normalize(CACHE_DIR + "minified_" + jsFilename );
}
res.sendfile(pathStr, { maxAge: server.maxAge });
@@ -264,7 +276,7 @@ exports.minifyJS = function(req, res, jsFilename)
//read all js files
async.forEach(jsFiles, function (item, callback)
{
- fs.readFile(rootPath + "static/js/" + item, "utf-8", function(err, data)
+ fs.readFile(JS_DIR + item, "utf-8", function(err, data)
{
if(ERR(err, callback)) return;
fileValues[item] = data;
@@ -276,18 +288,44 @@ exports.minifyJS = function(req, res, jsFilename)
{
if(ERR(err)) return;
- for(var i=0;i');
+ buffer.push(Ace2Editor.EMBEDED[KERNEL_SOURCE]);
+ buffer.push('<\/script>');
+ } else {
+ buffer.push('
+
@@ -337,5 +338,13 @@
+
+