diff --git a/README.md b/README.md
index 18c145ef4..3d5ff1466 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ documented codebase makes it easier for developers to improve the code. Etherpad
to be easy embeddable. Look at our [FAQ Page](https://github.com/Pita/etherpad-lite/wiki/FAQ)
**Online demo**
-Visit to test it live. You can find the same instance behind a nginx, with ssl and in a subpath here -> [https://pad.pitapoison.de/pad/](https://pad.pitapoison.de/pad/)
+Visit to test it live. You can find the same instance behind a nginx, with ssl and in a subpath here -> [https://pad.pitapoison.de/pad/](https://pad.pitapoison.de/pad/)
# Etherpad vs Etherpad Lite
@@ -31,26 +31,36 @@ Visit to test it live. You can find the same instanc
# Installation
**As root:**
-1. Download the latest **0.4.x** node.js release from , extract it and build it with `./configure && make && make install`.
-The Node.js version of your Linux repository might be too old/new. Please compile from the source to get sure you have the correct version.
-2. Install npm `curl http://npmjs.org/install.sh | sh`
-3. Ensure you have installed the sqlite develob libraries, gzip and git `apt-get install libsqlite3-dev gzip git-core`
+
+
Install all dependencies. We need the sqlite develob libraries, gzip, git, curl, libssl develop libraries and python apt-get install libsqlite3-dev gzip git-core curl python libssl-dev
move into the node folder cd node-v0.4* and build node with ./configure && make && make install
+
+
+
Install npm curl http://npmjs.org/install.sh | sh
+
**As any user (we recommend creating a seperate user called etherpad-lite):**
-4. Clone the git repository `git clone 'git://github.com/Pita/etherpad-lite.git'`
-5. Start it with `bin/run.sh` (the first run will install all dependencies)
-6. Open your web browser and visit
+
+
Clone the git repository git clone 'git://github.com/Pita/etherpad-lite.git'
+
Install the dependencies with bin/installDeps.sh(if you have problems at this step, look at the section Troubleshooting below)
+
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
+
## Troubleshooting
### It fails while installing the sqlite dependency
-The sqlite package of some linux versions (including debian lenny) is too old. You have to use a PPA or debian backports
+The sqlite package of some linux versions (including debian lenny) is too old. We need sqlite >=3.6. You have to use a PPA or debian backports. You find sqlite packages for Ubuntu Hardy [here](https://launchpad.net/~mirabilos/+archive/ppa/+sourcepub/1304941/+listing-archive-extra), Debian Backports can be found [here](http://backports-master.debian.org/Instructions/#index1h2)
### It fails while installing the express dependency, it says my node version is wrong
You might have installed node.js version 0.5. You can check that with `node --version`. Please reinstall node 0.4.x
-### I stopped the installing process, now it doesn't work anymore, what can I do?
+### My installation process stopped, now it doesn't work anymore, what can I do?
Remove the node_modules folder. This forces run.sh to reinstall all dependencies
## Next Steps
@@ -59,6 +69,7 @@ You can modify the settings in the file settings.json
You can update to the latest version with `git pull origin`. The next start with bin/run.sh will update the dependencies
Look at this wiki pages:
+
* [How to deploy Etherpad Lite as a service](https://github.com/Pita/etherpad-lite/wiki/How-to-deploy-Etherpad-Lite-as-a-service)
* [How to put Etherpad Lite behind a reverse Proxy](https://github.com/Pita/etherpad-lite/wiki/How-to-put-Etherpad-Lite-behind-a-reverse-Proxy)
* [How to customize your Etherpad Lite installation](https://github.com/Pita/etherpad-lite/wiki/How-to-customize-your-Etherpad-Lite-installation)
diff --git a/bin/debugRun.sh b/bin/debugRun.sh
index fede0b50b..01197a6b8 100755
--- a/bin/debugRun.sh
+++ b/bin/debugRun.sh
@@ -1,8 +1,7 @@
#!/bin/sh
#Move to the folder where ep-lite is installed
-FOLDER=$(dirname $(readlink -f $0))
-cd $FOLDER
+cd `dirname $0`
#Was this script started in the bin folder? if yes move out
if [ -d "../bin" ]; then
@@ -21,7 +20,7 @@ hash node-inspector > /dev/null 2>&1 || {
node-inspector &
-echo "If you new to node-inspector, take a look at this video: http://youtu.be/AOnK3NVnxL8"
+echo "If you are new to node-inspector, take a look at this video: http://youtu.be/AOnK3NVnxL8"
cd "node"
node --debug server.js
diff --git a/bin/generateJsDoc.sh b/bin/generateJsDoc.sh
index 1667c1ccc..8704d5ad0 100755
--- a/bin/generateJsDoc.sh
+++ b/bin/generateJsDoc.sh
@@ -1,8 +1,7 @@
#!/bin/sh
#Move to the folder where ep-lite is installed
-FOLDER=$(dirname $(readlink -f $0))
-cd $FOLDER
+cd `dirname $0`
#Was this script started in the bin folder? if yes move out
if [ -d "../bin" ]; then
diff --git a/bin/installDeps.sh b/bin/installDeps.sh
index 2c880896c..db46dbfab 100755
--- a/bin/installDeps.sh
+++ b/bin/installDeps.sh
@@ -1,8 +1,7 @@
#!/bin/sh
#Move to the folder where ep-lite is installed
-FOLDER=$(dirname $(readlink -f $0))
-cd $FOLDER
+cd `dirname $0`
#Was this script started in the bin folder? if yes move out
if [ -d "../bin" ]; then
@@ -10,8 +9,8 @@ if [ -d "../bin" ]; then
fi
#Is wget installed?
-hash wget > /dev/null 2>&1 || {
- echo "Please install wget" >&2
+hash curl > /dev/null 2>&1 || {
+ echo "Please install curl" >&2
exit 1
}
@@ -34,7 +33,7 @@ if [ ! -f "settings.json" ]; then
fi
echo "Ensure that all dependencies are up to date..."
-npm install || exit 1
+npm install || rm -rf node_modules; exit 1
echo "Ensure jQuery is downloaded and up to date..."
DOWNLOAD_JQUERY="true"
@@ -48,7 +47,7 @@ if [ -f "static/js/jquery.min.js" ]; then
fi
if [ $DOWNLOAD_JQUERY = "true" ]; then
- wget -O static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js || exit 1
+ curl -lo static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js || exit 1
fi
#Remove all minified data to force node creating it new
diff --git a/bin/run.sh b/bin/run.sh
index b5f851610..a5245ff77 100755
--- a/bin/run.sh
+++ b/bin/run.sh
@@ -1,8 +1,7 @@
#!/bin/sh
#Move to the folder where ep-lite is installed
-FOLDER=$(dirname $(readlink -f $0))
-cd $FOLDER
+cd `dirname $0`
#Was this script started in the bin folder? if yes move out
if [ -d "../bin" ]; then
@@ -16,7 +15,7 @@ if [ "$(id -u)" -eq 0 ]; then
read rocks
if [ ! $rocks = "Etherpad Lite rocks my socks" ]
then
- echo "You're input was wrong"
+ echo "Your input was incorrect"
exit 1
fi
fi
diff --git a/bin/safeRun.sh b/bin/safeRun.sh
index d7d2b99cc..b060f5d19 100755
--- a/bin/safeRun.sh
+++ b/bin/safeRun.sh
@@ -18,8 +18,7 @@ TIME_BETWEEN_EMAILS=600 # 10 minutes
LAST_EMAIL_SEND=0
#Move to the folder where ep-lite is installed
-FOLDER=$(dirname $(readlink -f $0))
-cd $FOLDER
+cd `dirname $0`
#Was this script started in the bin folder? if yes move out
if [ -d "../bin" ]; then
diff --git a/node/handler/ExportHandler.js b/node/handler/ExportHandler.js
index e128fd7b7..674950f40 100644
--- a/node/handler/ExportHandler.js
+++ b/node/handler/ExportHandler.js
@@ -23,11 +23,20 @@ var padManager = require("../db/PadManager");
var async = require("async");
var fs = require("fs");
var settings = require('../utils/Settings');
+var os = require('os');
//load abiword only if its enabled
if(settings.abiword != null)
var abiword = require("../utils/Abiword");
+var tempDirectory = "/tmp";
+
+//tempDirectory changes if the operating system is windows
+if(os.type().indexOf("Windows") > -1)
+{
+ tempDirectory = "c:\\Temp";
+}
+
/**
* do a requested export
*/
@@ -52,7 +61,7 @@ exports.doExport = function(req, res, padId, type)
var html;
var randNum;
var srcFile, destFile;
-
+
async.series([
//render the html document
function(callback)
@@ -76,7 +85,7 @@ exports.doExport = function(req, res, padId, type)
else
{
randNum = Math.floor(Math.random()*new Date().getTime());
- srcFile = "/tmp/eplite_export_" + randNum + ".html";
+ srcFile = tempDirectory + "/eplite_export_" + randNum + ".html";
fs.writeFile(srcFile, html, callback);
}
},
@@ -86,7 +95,7 @@ exports.doExport = function(req, res, padId, type)
//ensure html can be collected by the garbage collector
html = null;
- destFile = "/tmp/eplite_export_" + randNum + "." + type;
+ destFile = tempDirectory + "/eplite_export_" + randNum + "." + type;
abiword.convertFile(srcFile, destFile, type, callback);
},
//send the file
@@ -104,7 +113,11 @@ exports.doExport = function(req, res, padId, type)
},
function(callback)
{
- fs.unlink(destFile, callback);
+ //100ms delay to accomidate for slow windows fs
+ setTimeout(function()
+ {
+ fs.unlink(destFile, callback);
+ }, 100);
}
], callback);
}
diff --git a/node/handler/ImportHandler.js b/node/handler/ImportHandler.js
index 489ee1b09..c02c9f508 100644
--- a/node/handler/ImportHandler.js
+++ b/node/handler/ImportHandler.js
@@ -24,10 +24,19 @@ var async = require("async");
var fs = require("fs");
var settings = require('../utils/Settings');
var formidable = require('formidable');
+var os = require("os");
//load abiword only if its enabled
if(settings.abiword != null)
var abiword = require("../utils/Abiword");
+
+var tempDirectory = "/tmp/";
+
+//tempDirectory changes if the operating system is windows
+if(os.type().indexOf("Windows") > -1)
+{
+ tempDirectory = "c:\\Temp\\";
+}
/**
* do a requested import
@@ -48,6 +57,7 @@ exports.doImport = function(req, res, padId)
{
var form = new formidable.IncomingForm();
form.keepExtensions = true;
+ form.uploadDir = tempDirectory;
form.parse(req, function(err, fields, files)
{
@@ -94,7 +104,7 @@ exports.doImport = function(req, res, padId)
function(callback)
{
var randNum = Math.floor(Math.random()*new Date().getTime());
- destFile = "/tmp/eplite_import_" + randNum + ".txt";
+ destFile = tempDirectory + "eplite_import_" + randNum + ".txt";
abiword.convertFile(srcFile, destFile, "txt", callback);
},
@@ -114,7 +124,13 @@ exports.doImport = function(req, res, padId)
fs.readFile(destFile, "utf8", function(err, _text)
{
text = _text;
- callback(err);
+
+ //node on windows has a delay on releasing of the file lock.
+ //We add a 100ms delay to work around this
+ setTimeout(function()
+ {
+ callback(err);
+ }, 100);
});
},
diff --git a/node/utils/Abiword.js b/node/utils/Abiword.js
index edac46486..3a99f56be 100644
--- a/node/utils/Abiword.js
+++ b/node/utils/Abiword.js
@@ -22,71 +22,121 @@ var util = require('util');
var spawn = require('child_process').spawn;
var async = require("async");
var settings = require("./Settings");
+var os = require('os');
-//Queue with the converts we have to do
-var queue = async.queue(doConvertTask, 1);
-
-//spawn the abiword process
-var abiword = spawn(settings.abiword, ["--plugin", "AbiCommand"]);
-
-//append error messages to the buffer
-abiword.stderr.on('data', function (data)
+//on windows we have to spawn a process for each convertion, cause the plugin abicommand doesn't exist on this platform
+if(os.type().indexOf("Windows") > -1)
{
- stdoutBuffer += data.toString();
-});
+ var stdoutBuffer = "";
-//throw exceptions if abiword is dieing
-abiword.on('exit', function (code)
-{
- throw "Abiword died with exit code " + code;
-});
-
-//delegate the processing of stdout to a other function
-abiword.stdout.on('data',onAbiwordStdout);
-
-var stdoutCallback = null;
-var stdoutBuffer = "";
-var firstPrompt = true;
-
-function onAbiwordStdout(data)
-{
- //add data to buffer
- stdoutBuffer+=data.toString();
-
- //we're searching for the prompt, cause this means everything we need is in the buffer
- if(stdoutBuffer.search("AbiWord:>") != -1)
+ function doConvertTask(task, callback)
{
- //filter the feedback message
- var err = stdoutBuffer.search("OK") != -1 ? null : stdoutBuffer;
+ //span an abiword process to perform the conversion
+ var abiword = spawn(settings.abiword, ["--to=" + task.destFile, task.srcFile]);
- //reset the buffer
- stdoutBuffer = "";
-
- //call the callback with the error message
- //skip the first prompt
- if(stdoutCallback != null && !firstPrompt)
+ //delegate the processing of stdout to another function
+ abiword.stdout.on('data', function (data)
{
- stdoutCallback(err);
- stdoutCallback = null;
- }
-
- firstPrompt = false;
- }
-}
+ //add data to buffer
+ stdoutBuffer+=data.toString();
+ });
-function doConvertTask(task, callback)
-{
- abiword.stdin.write("convert " + task.srcFile + " " + task.destFile + " " + task.type + "\n");
+ //append error messages to the buffer
+ abiword.stderr.on('data', function (data)
+ {
+ stdoutBuffer += data.toString();
+ });
+
+ //throw exceptions if abiword is dieing
+ abiword.on('exit', function (code)
+ {
+ if(code != 0) {
+ throw "Abiword died with exit code " + code;
+ }
+
+ if(stdoutBuffer != "")
+ {
+ console.log(stdoutBuffer);
+ }
+
+ callback();
+ });
+ }
- //create a callback that calls the task callback and the caller callback
- stdoutCallback = function (err)
+ exports.convertFile = function(srcFile, destFile, type, callback)
{
- callback();
- task.callback(err);
+ doConvertTask({"srcFile": srcFile, "destFile": destFile, "type": type}, callback);
};
}
-
-exports.convertFile = function(srcFile, destFile, type, callback)
+//on unix operating systems, we can start abiword with abicommand and communicate with it via stdin/stdout
+//thats much faster, about factor 10
+else
{
- queue.push({"srcFile": srcFile, "destFile": destFile, "type": type, "callback": callback});
-};
+ //Queue with the converts we have to do
+ var queue = async.queue(doConvertTask, 1);
+
+ //spawn the abiword process
+ var abiword = spawn(settings.abiword, ["--plugin", "AbiCommand"]);
+
+ //append error messages to the buffer
+ abiword.stderr.on('data', function (data)
+ {
+ stdoutBuffer += data.toString();
+ });
+
+ //throw exceptions if abiword is dieing
+ abiword.on('exit', function (code)
+ {
+ throw "Abiword died with exit code " + code;
+ });
+
+ //delegate the processing of stdout to a other function
+ abiword.stdout.on('data',onAbiwordStdout);
+
+ var stdoutCallback = null;
+ var stdoutBuffer = "";
+ var firstPrompt = true;
+
+ function onAbiwordStdout(data)
+ {
+ //add data to buffer
+ stdoutBuffer+=data.toString();
+
+ //we're searching for the prompt, cause this means everything we need is in the buffer
+ if(stdoutBuffer.search("AbiWord:>") != -1)
+ {
+ //filter the feedback message
+ var err = stdoutBuffer.search("OK") != -1 ? null : stdoutBuffer;
+
+ //reset the buffer
+ stdoutBuffer = "";
+
+ //call the callback with the error message
+ //skip the first prompt
+ if(stdoutCallback != null && !firstPrompt)
+ {
+ stdoutCallback(err);
+ stdoutCallback = null;
+ }
+
+ firstPrompt = false;
+ }
+ }
+
+ function doConvertTask(task, callback)
+ {
+ abiword.stdin.write("convert " + task.srcFile + " " + task.destFile + " " + task.type + "\n");
+
+ //create a callback that calls the task callback and the caller callback
+ stdoutCallback = function (err)
+ {
+ callback();
+ task.callback(err);
+ };
+ }
+
+ exports.convertFile = function(srcFile, destFile, type, callback)
+ {
+ queue.push({"srcFile": srcFile, "destFile": destFile, "type": type, "callback": callback});
+ };
+}
diff --git a/node/utils/Minify.js b/node/utils/Minify.js
index 4f7170f93..a8146addd 100644
--- a/node/utils/Minify.js
+++ b/node/utils/Minify.js
@@ -29,6 +29,7 @@ var path = require('path');
var Buffer = require('buffer').Buffer;
var gzip = require('gzip');
var server = require('../server');
+var os = require('os');
var padJS = ["jquery.min.js", "pad_utils.js", "plugins.js", "undo-xpopup.js", "json2.js", "pad_cookie.js", "pad_editor.js", "pad_editbar.js", "pad_docbar.js", "pad_modals.js", "ace.js", "collab_client.js", "pad_userlist.js", "pad_impexp.js", "pad_savedrevs.js", "pad_connectionstatus.js", "pad2.js", "jquery-ui.js", "chat.js"];
@@ -222,11 +223,20 @@ exports.minifyJS = function(req, res, jsFilename)
//write the results compressed in a file
function(callback)
{
- gzip(result, 9, function(err, compressedResult){
- if(err) {callback(err); return}
-
- fs.writeFile("../var/minified_" + jsFilename + ".gz", compressedResult, callback);
- });
+ //spawn a gzip process if we're on a unix system
+ if(os.type().indexOf("Windows") == -1)
+ {
+ gzip(result, 9, function(err, compressedResult){
+ if(err) {callback(err); return}
+
+ fs.writeFile("../var/minified_" + jsFilename + ".gz", compressedResult, callback);
+ });
+ }
+ //skip this step on windows
+ else
+ {
+ callback();
+ }
}
],callback);
}
@@ -238,7 +248,7 @@ exports.minifyJS = function(req, res, jsFilename)
var gzipSupport = req.header('Accept-Encoding', '').indexOf('gzip') != -1;
var pathStr;
- if(gzipSupport)
+ if(gzipSupport && os.type().indexOf("Windows") == -1)
{
pathStr = path.normalize(__dirname + "/../../var/minified_" + jsFilename + ".gz");
res.header('Content-Encoding', 'gzip');
diff --git a/package.json b/package.json
index 59e214f8a..4ae1a0877 100644
--- a/package.json
+++ b/package.json
@@ -10,11 +10,11 @@
"name": "Robin Buse"}
],
"dependencies" : {
- "socket.io" : "0.7.7",
- "ueberDB" : "0.0.13",
+ "socket.io" : "0.7.8",
+ "ueberDB" : "0.0.14",
"async" : "0.1.9",
"joose" : "3.18.0",
- "express" : "2.4.3",
+ "express" : "2.4.4",
"clean-css" : "0.2.4",
"uglify-js" : "1.0.6",
"gzip" : "0.1.0",
diff --git a/static/index.html b/static/index.html
index 1cc71bd9b..c4f2e4e92 100644
--- a/static/index.html
+++ b/static/index.html
@@ -57,14 +57,8 @@
#button:active {
box-shadow: inset 0 1px 12px rgba(0, 0, 0, 0.9);
background: #444;
- /*
- background: -webkit-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D);
- background: -moz-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D);
- background: -ms-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D);
- background: -o-linear-gradient(#565656, #4C4C4C 50%, #424242 51%, #2D2D2D);
- */
}
- .label {
+ #label {
text-align: left;
margin: 0 auto;
width: 300px;
@@ -86,13 +80,13 @@