diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..ba1cf0ac1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,22 @@
+language: node_js
+node_js:
+ - "0.8"
+install:
+ - "bin/installDeps.sh"
+ - "export GIT_HASH=$(cat .git/HEAD | head -c 7)"
+before_script:
+ - "tests/frontend/travis/sauce_tunnel.sh"
+script:
+ - "tests/frontend/travis/runner.sh"
+env:
+ global:
+ - secure: "oKA4KbSvyxMOFCiOa3hWswnaIrCmX60MfhBhD8xu8sodOqbdK5RUrxDJew9p\n1nNSewxoVmKhX0G5GxIABfGtdU1nrEzCEoejTDJIFmzEbcLcHpcyarouWLSY\nOpn11FKS1rnb69aflHM7K8l4dhrCkA2i0Dwwl8LN3HayGzDV2Rg="
+ - SAUCE_USER=pita
+jdk:
+ - oraclejdk6
+notifications:
+ email:
+ - petermartischka@googlemail.com
+ irc:
+ channels:
+ - "irc.freenode.org#etherpad-lite-dev"
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5810ed255..abcf0a210 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,34 @@
+# v1.2
+ * Internationalization / Language / Translation support (i18n) with support for German/French
+ * A frontend/client side testing framework and backend build tests
+ * Customizable robots.txt
+ * Customizable app title (finally you can name your epl instance!)
+ * eejs render arguments are now passed on to eejs hooks through the newly introduced `renderContext` argument.
+ * Plugin-specific settings in settings.json (finally allowing for things like a google analytics plugin)
+ * Serve admin dashboard at /admin (still very limited, though)
+ * Modify your settings.json through the newly created UI at /admin/settings
+ * Fix: Import
's as 's and not as
's!
+ * Added solaris compatibility (bin/installDeps.sh was broken on solaris)
+ * Fix a bug with IE9 and Password Protected Pads using HTTPS
+
+# v1.1.5
+ * We updated to express v3 (please [make sure](https://github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x) your plugin works under express v3)
+ * `userColor` URL parameter which sets the initial author color
+ * Hooks for "padCreate", "padRemove", "padUpdate" and "padLoad" events
+ * Security patches concerning the handling of messages originating from clients
+ * Our database abstraction layer now natively supports couchDB, levelDB, mongoDB, postgres, and redis!
+ * We now provide a script helping you to migrate from dirtyDB to MySQL
+ * Support running Etherpad Lite behind IIS, using [iisnode](https://github.com/tjanczuk/iisnode/wiki)
+ * LibreJS Licensing information in headers of HTML templates
+ * Default port number to PORT env var, if port isn't specified in settings
+ * Fix for `convert.js`
+ * Raise upper char limit in chat to 999 characters
+ * Fixes for mobile layout
+ * Fixes for usage behind reverse proxy
+ * Improved documentation
+ * Fixed some opera style bugs
+ * Update npm and fix some bugs, this introduces
+
# v1.1
* Introduced Plugin framework
* Many bugfixes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 5f081f27e..b0fff543e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,49 +1,56 @@
# Developer Guidelines
-
-Please talk to people on the mailing list before you change this page
-
-Mailing list: https://groups.google.com/forum/?fromgroups#!forum/etherpad-lite-dev
-
-IRC channels: [#etherpad](irc://freenode/#etherpad) ([webchat](webchat.freenode.net?channels=etherpad)), [#etherpad-lite-dev](irc://freenode/#etherpad-lite-dev) ([webchat](webchat.freenode.net?channels=etherpad-lite-dev))
+(Please talk to people on the mailing list before you change this page, see our section on [how to get in touch](https://github.com/ether/etherpad-lite#get-in-touch))
**Our goal is to iterate in small steps. Release often, release early. Evolution instead of a revolution**
## General goals of Etherpad Lite
-* easy to install for admins
-* easy to use for people
+To make sure everybody is going in the same direction:
+* easy to install for admins and easy to use for people
+* easy to integrate into other apps, but also usable as standalone
* using less resources on server side
-* easy to embed for admins
-* also runable as etherpad lite only
-* keep it maintainable, we don't wanna end ob as the monster Etherpad was
* extensible, as much functionality should be extendable with plugins so changes don't have to be done in core
+Also, keep it maintainable. We don't wanna end ob as the monster Etherpad was!
-## How to code:
-* **Please write comments**. I don't mean you have to comment every line and every loop. I just mean, if you do anything thats a bit complex or a bit weird, please leave a comment. It's easy to do that if you do while you're writing the code. Keep in mind that you will probably leave the project at some point and that other people will read your code. Undocumented huge amounts of code are worthless
-* Never ever use tabs
-* Indentation: JS/CSS: 2 spaces; HTML: 4 spaces
-* Don't overengineer. Don't try to solve any possible problem in one step. Try to solve problems as easy as possible and improve the solution over time
-* Do generalize sooner or later - if an old solution hacked together according to the above point, poses more problems than it solves today, reengineer it, with the lessons learned taken into account.
-* Keep it compatible to API-Clients/older DBs/configurations. Don't make incompatible changes the protocol/database format without good reasons
-
-## How to work with git
-* Make a new branch for every feature you're working on. Don't work in your master branch. This ensures that you can work you can do lot of small pull requests instead of one big one with complete different features
-* Don't use the online edit function of github. This only creates ugly and not working commits
-* Test before you push. Sounds easy, it isn't
-* Try to make clean commits that are easy readable
-* Don't check in stuff that gets generated during build or runtime (like jquery, minified files, dbs etc...)
-* Make pull requests from your feature branch to our develop branch once your feature is ready
+## How to work with git?
+* Don't work in your master branch.
+* Make a new branch for every feature you're working on. (This ensures that you can work you can do lots of small, independent pull requests instead of one big one with complete different features)
+* Don't use the online edit function of github (this only creates ugly and not working commits!)
+* Try to make clean commits that are easy readable (including descriptive commit messages!)
+* Test before you push. Sounds easy, it isn't!
+* Don't check in stuff that gets generated during build or runtime
* Make small pull requests that are easy to review but make sure they do add value by themselves / individually
-## Branching model in Etherpad Lite
+## Coding style
+* Do write comments. (You don't have to comment every line, but if you come up with something thats a bit complex/weird, just leave a comment. Bear in mind that you will probably leave the project at some point and that other people will read your code. Undocumented huge amounts of code are worthless!)
+* Never ever use tabs
+* Indentation: JS/CSS: 2 spaces; HTML: 4 spaces
+* Don't overengineer. Don't try to solve any possible problem in one step, but try to solve problems as easy as possible and improve the solution over time!
+* Do generalize sooner or later! (if an old solution, quickly hacked together, poses more problems than it solves today, refactor it!)
+* Keep it compatible. Do not introduce changes to the public API, db schema or configurations too lightly. Don't make incompatible changes without good reasons!
+* If you do make changes, document them! (see below)
+
+## Branching model / git workflow
see git flow http://nvie.com/posts/a-successful-git-branching-model/
-* master, the stable. This is the branch everyone should use for production stuff
-* develop, everything that is READY to go into master at some point in time. This stuff is tested and ready to go out
-* release branches, stuff that should go into master very soon, only bugfixes go into these (see http://nvie.com/posts/a-successful-git-branching-model/ for why)
-* you can set tags in the master branch, there is no real need for release branches imho
-* The latest tag is not what is shown in github by default. Doing a clone of master should give you latest stable, not what is gonna be latest stable in a week, also, we should not be blocking new features to develop, just because we feel that we should be releasing it to master soon. This is the situation that release branches solve/handle.
-* hotfix branches, fixes for bugs in master
-* feature branches (in your own repos), these are the branches where you develop your features in. If its ready to go out, it will be merged into develop
+### `master` branch
+* the stable
+* This is the branch everyone should use for production stuff
+
+### `develop`branch
+* everything that is READY to go into master at some point in time
+* This stuff is tested and ready to go out
+
+### release branches
+* stuff that should go into master very soon
+* only bugfixes go into these (see http://nvie.com/posts/a-successful-git-branching-model/ for why)
+* we should not be blocking new features to develop, just because we feel that we should be releasing it to master soon. This is the situation that release branches solve/handle.
+
+### hotfix branches
+* fixes for bugs in master
+
+### feature branches (in your own repos)
+* these are the branches where you develop your features in
+* If its ready to go out, it will be merged into develop
Over the time we pull features from feature branches into the develop branch. Every month we pull from develop into master. Bugs in master get fixed in hotfix branches. These branches will get merged into master AND develop. There should never be commits in master that aren't in develop
diff --git a/Makefile b/Makefile
index ab720f284..4e870a452 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,13 @@
doc_sources = $(wildcard doc/*/*.md) $(wildcard doc/*.md)
outdoc_files = $(addprefix out/,$(doc_sources:.md=.html))
-docassets = $(addprefix out/,$(wildcard doc/_assets/*))
+docassets = $(addprefix out/,$(wildcard doc/assets/*))
VERSION = $(shell node -e "console.log( require('./src/package.json').version )")
docs: $(outdoc_files) $(docassets)
-out/doc/_assets/%: doc/_assets/%
+out/doc/assets/%: doc/assets/%
mkdir -p $(@D)
cp $< $@
diff --git a/README.md b/README.md
index deb2ced23..baa8b13e0 100644
--- a/README.md
+++ b/README.md
@@ -27,13 +27,13 @@ documented codebase makes it easier for developers to improve the code and contr
-Etherpad Lite is designed to be easily embeddable and provides a [HTTP API](https://github.com/Pita/etherpad-lite/wiki/HTTP-API)
-that allows your web application to manage pads, users and groups. It is recommended to use the client implementations available for this API, listed on [this wiki page](https://github.com/Pita/etherpad-lite/wiki/HTTP-API-client-libraries).
+Etherpad Lite is designed to be easily embeddable and provides a [HTTP API](https://github.com/ether/etherpad-lite/wiki/HTTP-API)
+that allows your web application to manage pads, users and groups. It is recommended to use the client implementations available for this API, listed on [this wiki page](https://github.com/ether/etherpad-lite/wiki/HTTP-API-client-libraries).
There is also a [jQuery plugin](https://github.com/johnyma22/etherpad-lite-jquery-plugin) that helps you to embed Pads into your website
**Visit [beta.etherpad.org](http://beta.etherpad.org) to test it live**
-Also, check out the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**, really!
+Also, check out the **[FAQ](https://github.com/ether/etherpad-lite/wiki/FAQ)**, really!
# Installation
@@ -42,7 +42,7 @@ Also, check out the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**, r
### Prebuilt windows package
This package works out of the box on any windows machine, but it's not very useful for developing purposes...
-1. Download the windows package
+1. Download the windows package
2. Extract the folder
Now, run `start.bat` and open in your browser. You like it? [Next steps](#next-steps).
@@ -51,8 +51,8 @@ Now, run `start.bat` and open in your browser. You like
You'll need [node.js](http://nodejs.org) and (optionally, though recommended) git.
1. Grab the source, either
- - download
- - or `git clone https://github.com/Pita/etherpad-lite.git` (for this you need git, obviously)
+ - download
+ - or `git clone https://github.com/ether/etherpad-lite.git` (for this you need git, obviously)
2. start `bin\installOnWindows.bat`
Now, run `start.bat` and open in your browser.
@@ -70,7 +70,7 @@ Additionally, you'll need [node.js](http://nodejs.org).
**As any user (we recommend creating a separate user called etherpad-lite):**
-1. Move to a folder where you want to install Etherpad Lite. Clone the git repository `git clone git://github.com/Pita/etherpad-lite.git`
+1. Move to a folder where you want to install Etherpad Lite. Clone the git repository `git clone git://github.com/ether/etherpad-lite.git`
2. Change into the new directory containing the cloned source code `cd etherpad-lite`
Now, run `bin\run.sh` and open in your browser.
@@ -87,7 +87,7 @@ You can modify the settings in `settings.json`. (If you need to handle multiple
You should use a dedicated database such as "mysql", if you are planning on using etherpad-lite in a production environment, since the "dirtyDB" database driver is only for testing and/or development purposes.
## Helpful resources
-The [wiki](https://github.com/Pita/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages.
+The [wiki](https://github.com/ether/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages.
Documentation can be found in `docs/`.
@@ -100,27 +100,27 @@ If you're new to node.js, start with Ryan Dahl's [Introduction to Node.js](http:
You can debug Etherpad lite using `bin/debugRun.sh`.
-If you want to find out how Etherpad's `Easysync` works (the library that makes it really realtime), start with this [PDF](https://github.com/Pita/etherpad-lite/raw/master/doc/easysync/easysync-full-description.pdf) (complex, but worth reading).
+If you want to find out how Etherpad's `Easysync` works (the library that makes it really realtime), start with this [PDF](https://github.com/ether/etherpad-lite/raw/master/doc/easysync/easysync-full-description.pdf) (complex, but worth reading).
## Getting started
You know all this and just want to know how you can help?
-Look at the [TODO list](https://github.com/Pita/etherpad-lite/wiki/TODO) and our [Issue tracker](https://github.com/Pita/etherpad-lite/issues). (Please consider using [jshint](http://www.jshint.com/about/), if you plan to contribute code.)
+Look at the [TODO list](https://github.com/ether/etherpad-lite/wiki/TODO) and our [Issue tracker](https://github.com/ether/etherpad-lite/issues). (Please consider using [jshint](http://www.jshint.com/about/), if you plan to contribute code.)
-Also, and most importantly, read our [**Developer Guidelines**](https://github.com/Pita/etherpad-lite/wiki/Developer-Guidelines), really!
+Also, and most importantly, read our [**Developer Guidelines**](https://github.com/ether/etherpad-lite/wiki/Developer-Guidelines), really!
# Get in touch
Join the [mailinglist](http://groups.google.com/group/etherpad-lite-dev) and make some noise on our freenode irc channel [#etherpad-lite-dev](http://webchat.freenode.net?channels=#etherpad-lite-dev)!
# Modules created for this project
-* [ueberDB](https://github.com/Pita/ueberDB) "transforms every database into a object key value store" - manages all database access
-* [channels](https://github.com/Pita/channels) "Event channels in node.js" - ensures that ueberDB operations are atomic and in series for each key
-* [async-stacktrace](https://github.com/Pita/async-stacktrace) "Improves node.js stacktraces and makes it easier to handle errors"
+* [ueberDB](https://github.com/ether/ueberDB) "transforms every database into a object key value store" - manages all database access
+* [channels](https://github.com/ether/channels) "Event channels in node.js" - ensures that ueberDB operations are atomic and in series for each key
+* [async-stacktrace](https://github.com/ether/async-stacktrace) "Improves node.js stacktraces and makes it easier to handle errors"
# Donate!
* [Flattr] (http://flattr.com/thing/71378/Etherpad-Foundation)
* Paypal - Press the donate button on [etherpad.org](http://etherpad.org)
# License
-[Apache License v2](http://www.apache.org/licenses/LICENSE-2.0.html)
\ No newline at end of file
+[Apache License v2](http://www.apache.org/licenses/LICENSE-2.0.html)
diff --git a/available_plugins/ep_fintest/.npmignore b/available_plugins/ep_fintest/.npmignore
deleted file mode 100644
index 74bd365b4..000000000
--- a/available_plugins/ep_fintest/.npmignore
+++ /dev/null
@@ -1,7 +0,0 @@
-.git*
-docs/
-examples/
-support/
-test/
-testing.js
-.DS_Store
diff --git a/available_plugins/ep_fintest/ep.json b/available_plugins/ep_fintest/ep.json
deleted file mode 100644
index 4ec8e3924..000000000
--- a/available_plugins/ep_fintest/ep.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "parts": [
- {
- "name": "somepart",
- "pre": [],
- "post": ["ep_onemoreplugin/partone"]
- },
- {
- "name": "partlast",
- "pre": ["ep_fintest/otherpart"],
- "post": [],
- "hooks": {
- "somehookname": "ep_fintest/partlast:somehook"
- }
- },
- {
- "name": "partfirst",
- "pre": [],
- "post": ["ep_onemoreplugin/somepart"]
- },
- {
- "name": "otherpart",
- "pre": ["ep_fintest/somepart", "ep_otherplugin/main"],
- "post": [],
- "hooks": {
- "somehookname": "ep_fintest/otherpart:somehook",
- "morehook": "ep_fintest/otherpart:morehook",
- "expressCreateServer": "ep_fintest/otherpart:expressServer",
- "eejsBlock_editbarMenuLeft": "ep_fintest/otherpart:eejsBlock_editbarMenuLeft"
- },
- "client_hooks": {
- "somehookname": "ep_fintest/static/js/test:bar"
- }
- }
- ]
-}
diff --git a/available_plugins/ep_fintest/otherpart.js b/available_plugins/ep_fintest/otherpart.js
deleted file mode 100644
index 718fb095c..000000000
--- a/available_plugins/ep_fintest/otherpart.js
+++ /dev/null
@@ -1,25 +0,0 @@
-test = require("ep_fintest/static/js/test.js");
-console.log("FOOO:", test.foo);
-
-exports.somehook = function (hook_name, args, cb) {
- return cb(["otherpart:somehook was here"]);
-}
-
-exports.morehook = function (hook_name, args, cb) {
- return cb(["otherpart:morehook was here"]);
-}
-
-exports.expressServer = function (hook_name, args, cb) {
- args.app.get('/otherpart', function(req, res) {
- res.send("Abra cadabra");
- });
-}
-
-exports.eejsBlock_editbarMenuLeft = function (hook_name, args, cb) {
- args.content = args.content + '\
-
\
- \
-
\
- ';
- return cb();
-}
diff --git a/available_plugins/ep_fintest/package.json b/available_plugins/ep_fintest/package.json
deleted file mode 100644
index e221b5c18..000000000
--- a/available_plugins/ep_fintest/package.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "ep_fintest",
- "description": "A test plugin",
- "version": "0.0.1",
- "author": "RedHog (Egil Moeller) ",
- "contributors": [],
- "dependencies": {},
- "engines": { "node": ">= 0.4.1 < 0.7.0" }
-}
diff --git a/available_plugins/ep_fintest/partlast.js b/available_plugins/ep_fintest/partlast.js
deleted file mode 100644
index c3f1fc3eb..000000000
--- a/available_plugins/ep_fintest/partlast.js
+++ /dev/null
@@ -1,3 +0,0 @@
-exports.somehook = function (hook_name, args, cb) {
- return cb(["partlast:somehook was here"]);
-}
diff --git a/available_plugins/ep_fintest/static/js/test.js b/available_plugins/ep_fintest/static/js/test.js
deleted file mode 100644
index 22d58cc2f..000000000
--- a/available_plugins/ep_fintest/static/js/test.js
+++ /dev/null
@@ -1,5 +0,0 @@
-exports.foo = 42;
-
-exports.bar = function (hook_name, args, cb) {
- return cb(["FOOOO"]);
-}
\ No newline at end of file
diff --git a/available_plugins/ep_fintest/static/test.html b/available_plugins/ep_fintest/static/test.html
deleted file mode 100644
index 9e7fc5511..000000000
--- a/available_plugins/ep_fintest/static/test.html
+++ /dev/null
@@ -1 +0,0 @@
-Test bla bla
diff --git a/bin/buildForWindows.sh b/bin/buildForWindows.sh
index 1d47bff1b..2f9062386 100755
--- a/bin/buildForWindows.sh
+++ b/bin/buildForWindows.sh
@@ -52,6 +52,9 @@ echo "download windows node..."
cd bin
wget "http://nodejs.org/dist/v$NODE_VERSION/node.exe" -O ../node.exe
+echo "remove git history to reduce folder size"
+rm -rf .git/objects
+
echo "create the zip..."
cd /tmp
zip -9 -r etherpad-lite-win.zip etherpad-lite-win
diff --git a/bin/installDeps.sh b/bin/installDeps.sh
index 9f691e0af..ac2e68cf5 100755
--- a/bin/installDeps.sh
+++ b/bin/installDeps.sh
@@ -8,6 +8,14 @@ if [ -d "../bin" ]; then
cd "../"
fi
+#Is gnu-grep (ggrep) installed on SunOS (Solaris)
+if [ $(uname) = "SunOS" ]; then
+ hash ggrep > /dev/null 2>&1 || {
+ echo "Please install ggrep (pkg install gnu-grep)" >&2
+ exit 1
+ }
+fi
+
#Is wget installed?
hash curl > /dev/null 2>&1 || {
echo "Please install curl" >&2
@@ -52,7 +60,7 @@ done
#Does a $settings exist? if no copy the template
if [ ! -f $settings ]; then
echo "Copy the settings template to $settings..."
- cp -v settings.json.template $settings || exit 1
+ cp settings.json.template $settings || exit 1
fi
echo "Ensure that all dependencies are up to date..."
@@ -61,7 +69,7 @@ echo "Ensure that all dependencies are up to date..."
cd node_modules
[ -e ep_etherpad-lite ] || ln -s ../src ep_etherpad-lite
cd ep_etherpad-lite
- npm install
+ npm install -s
) || {
rm -rf node_modules
exit 1
@@ -71,8 +79,12 @@ echo "Ensure jQuery is downloaded and up to date..."
DOWNLOAD_JQUERY="true"
NEEDED_VERSION="1.7.1"
if [ -f "src/static/js/jquery.js" ]; then
- VERSION=$(cat src/static/js/jquery.js | head -n 3 | grep -o "v[0-9]\.[0-9]\(\.[0-9]\)\?");
-
+ if [ $(uname) = "SunOS"]; then
+ VERSION=$(cat src/static/js/jquery.js | head -n 3 | ggrep -o "v[0-9]\.[0-9]\(\.[0-9]\)\?");
+ else
+ VERSION=$(cat src/static/js/jquery.js | head -n 3 | grep -o "v[0-9]\.[0-9]\(\.[0-9]\)\?");
+ fi
+
if [ ${VERSION#v} = $NEEDED_VERSION ]; then
DOWNLOAD_JQUERY="false"
fi
@@ -91,11 +103,11 @@ echo "ensure custom css/js files are created..."
for f in "index" "pad" "timeslider"
do
if [ ! -f "src/static/custom/$f.js" ]; then
- cp -v "src/static/custom/js.template" "src/static/custom/$f.js" || exit 1
+ cp "src/static/custom/js.template" "src/static/custom/$f.js" || exit 1
fi
if [ ! -f "src/static/custom/$f.css" ]; then
- cp -v "src/static/custom/css.template" "src/static/custom/$f.css" || exit 1
+ cp "src/static/custom/css.template" "src/static/custom/$f.css" || exit 1
fi
done
diff --git a/bin/migrateDirtyDBtoMySQL.js b/bin/migrateDirtyDBtoMySQL.js
index f2bc8efe2..d0273de0d 100644
--- a/bin/migrateDirtyDBtoMySQL.js
+++ b/bin/migrateDirtyDBtoMySQL.js
@@ -1,11 +1,17 @@
-var dirty = require("../src/node_modules/ueberDB/node_modules/dirty")('var/dirty.db');
-var db = require("../src/node/db/DB");
+require("ep_etherpad-lite/node_modules/npm").load({}, function(er,npm) {
-db.init(function() {
- db = db.db;
- dirty.on("load", function() {
- dirty.forEach(function(key, value) {
- db.set(key, value);
+ process.chdir(npm.root+'/..')
+
+ var dirty = require("ep_etherpad-lite/node_modules/ueberDB/node_modules/dirty")('var/dirty.db');
+ var db = require("ep_etherpad-lite/node/db/DB");
+
+ db.init(function() {
+ db = db.db;
+ dirty.on("load", function() {
+ dirty.forEach(function(key, value) {
+ db.set(key, value);
+ });
});
});
+
});
diff --git a/doc/api/embed_parameters.md b/doc/api/embed_parameters.md
index 587305665..3100fff9d 100644
--- a/doc/api/embed_parameters.md
+++ b/doc/api/embed_parameters.md
@@ -36,6 +36,13 @@ Default: "unnamed"
Example: `userName=Etherpad%20User`
+## userColor
+ * String (css hex color value)
+
+Default: randomly chosen by pad server
+
+Example: `userColor=%23ff9900`
+
## noColors
* Boolean
@@ -45,3 +52,11 @@ Default: false
* Boolean
Default: false
+
+## lang
+ * String
+
+Default: en
+
+Example: `lang=ar` (translates the interface into Arabic)
+
diff --git a/doc/api/http_api.md b/doc/api/http_api.md
index 3afab498f..990d1b498 100644
--- a/doc/api/http_api.md
+++ b/doc/api/http_api.md
@@ -62,7 +62,7 @@ Portal submits content into new blog post
### Request Format
-The API is accessible via HTTP. HTTP Requests are in the format /api/$APIVERSION/$FUNCTIONNAME. Parameters are transmitted via HTTP GET. $APIVERSION is 1
+The API is accessible via HTTP. HTTP Requests are in the format /api/$APIVERSION/$FUNCTIONNAME. Parameters are transmitted via HTTP GET. $APIVERSION depends on the endpoints you want to use. The latest version is `1.1`
### Response Format
Responses are valid JSON in the following format:
@@ -116,43 +116,93 @@ Example usage: http://api.jquery.com/jQuery.getJSON/
### Groups
Pads can belong to a group. The padID of grouppads is starting with a groupID like g.asdfasdfasdfasdf$test
-* **createGroup()** creates a new group
*Example returns:*
+#### createGroup()
+ * API >= 1
+
+creates a new group
+
+*Example returns:*
* `{code: 0, message:"ok", data: {groupID: g.s8oes9dhwrvt0zif}}`
-* **createGroupIfNotExistsFor(groupMapper)** this functions helps you to map your application group ids to etherpad lite group ids
*Example returns:*
+#### createGroupIfNotExistsFor(groupMapper)
+ * API >= 1
+
+this functions helps you to map your application group ids to etherpad lite group ids
+
+*Example returns:*
* `{code: 0, message:"ok", data: {groupID: g.s8oes9dhwrvt0zif}}`
-* **deleteGroup(groupID)** deletes a group
*Example returns:*
+#### deleteGroup(groupID)
+ * API >= 1
+
+deletes a group
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"groupID does not exist", data: null}`
-* **listPads(groupID)** returns all pads of this group
*Example returns:*
+#### listPads(groupID)
+ * API >= 1
+
+returns all pads of this group
+
+*Example returns:*
* `{code: 0, message:"ok", data: {padIDs : ["g.s8oes9dhwrvt0zif$test", "g.s8oes9dhwrvt0zif$test2"]}`
* `{code: 1, message:"groupID does not exist", data: null}`
-* **createGroupPad(groupID, padName [, text])** creates a new pad in this group
*Example returns:*
+#### createGroupPad(groupID, padName [, text])
+ * API >= 1
+
+creates a new pad in this group
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"pad does already exist", data: null}`
* `{code: 1, message:"groupID does not exist", data: null}`
-* **listAllGroups()** lists all existing groups
*Example returns:*
+#### listAllGroups()
+ * API >= 1
+
+lists all existing groups
+
+*Example returns:*
* `{code: 0, message:"ok", data: {groupIDs: ["g.mKjkmnAbSMtCt8eL", "g.3ADWx6sbGuAiUmCy"]}}`
* `{code: 0, message:"ok", data: {groupIDs: []}}`
### Author
These authors are bound to the attributes the users choose (color and name).
-* **createAuthor([name])** creates a new author
*Example returns:*
+#### createAuthor([name])
+ * API >= 1
+
+creates a new author
+
+*Example returns:*
* `{code: 0, message:"ok", data: {authorID: "a.s8oes9dhwrvt0zif"}}`
-* **createAuthorIfNotExistsFor(authorMapper [, name])** this functions helps you to map your application author ids to etherpad lite author ids
*Example returns:*
+#### createAuthorIfNotExistsFor(authorMapper [, name])
+ * API >= 1
+
+this functions helps you to map your application author ids to etherpad lite author ids
+
+*Example returns:*
* `{code: 0, message:"ok", data: {authorID: "a.s8oes9dhwrvt0zif"}}`
-* **listPadsOfAuthor(authorID)** returns an array of all pads this author contributed to
*Example returns:*
+#### listPadsOfAuthor(authorID)
+ * API >= 1
+
+returns an array of all pads this author contributed to
+
+*Example returns:*
* `{code: 0, message:"ok", data: {padIDs: ["g.s8oes9dhwrvt0zif$test", "g.s8oejklhwrvt0zif$foo"]}}`
* `{code: 1, message:"authorID does not exist", data: null}`
-* **getAuthorName(authorID)** Returns the Author Name of the author
*Example returns:*
+#### getAuthorName(authorID)
+ * API >= 1.1
+
+Returns the Author Name of the author
+
+*Example returns:*
* `{code: 0, message:"ok", data: {authorName: "John McLear"}}`
-> can't be deleted cause this would involve scanning all the pads where this author was
@@ -160,25 +210,50 @@ These authors are bound to the attributes the users choose (color and name).
### Session
Sessions can be created between a group and an author. This allows an author to access more than one group. The sessionID will be set as a cookie to the client and is valid until a certain date. The session cookie can also contain multiple comma-seperated sessionIDs, allowing a user to edit pads in different groups at the same time. Only users with a valid session for this group, can access group pads. You can create a session after you authenticated the user at your web application, to give them access to the pads. You should save the sessionID of this session and delete it after the user logged out.
-* **createSession(groupID, authorID, validUntil)** creates a new session. validUntil is an unix timestamp in seconds
*Example returns:*
+#### createSession(groupID, authorID, validUntil)
+ * API >= 1
+
+creates a new session. validUntil is an unix timestamp in seconds
+
+*Example returns:*
* `{code: 0, message:"ok", data: {sessionID: "s.s8oes9dhwrvt0zif"}}`
* `{code: 1, message:"groupID doesn't exist", data: null}`
* `{code: 1, message:"authorID doesn't exist", data: null}`
* `{code: 1, message:"validUntil is in the past", data: null}`
-* **deleteSession(sessionID)** deletes a session
*Example returns:*
+#### deleteSession(sessionID)
+ * API >= 1
+
+deletes a session
+
+*Example returns:*
* `{code: 1, message:"ok", data: null}`
* `{code: 1, message:"sessionID does not exist", data: null}`
-* **getSessionInfo(sessionID)** returns informations about a session
*Example returns:*
+#### getSessionInfo(sessionID)
+ * API >= 1
+
+returns informations about a session
+
+*Example returns:*
* `{code: 0, message:"ok", data: {authorID: "a.s8oes9dhwrvt0zif", groupID: g.s8oes9dhwrvt0zif, validUntil: 1312201246}}`
* `{code: 1, message:"sessionID does not exist", data: null}`
-* **listSessionsOfGroup(groupID)** returns all sessions of a group
*Example returns:*
+#### listSessionsOfGroup(groupID)
+ * API >= 1
+
+returns all sessions of a group
+
+*Example returns:*
* `{"code":0,"message":"ok","data":{"s.oxf2ras6lvhv2132":{"groupID":"g.s8oes9dhwrvt0zif","authorID":"a.akf8finncvomlqva","validUntil":2312905480}}}`
* `{code: 1, message:"groupID does not exist", data: null}`
-* **listSessionsOfAuthor(authorID)** returns all sessions of an author
*Example returns:*
+#### listSessionsOfAuthor(authorID)
+ * API >= 1
+
+returns all sessions of an author
+
+*Example returns:*
* `{"code":0,"message":"ok","data":{"s.oxf2ras6lvhv2132":{"groupID":"g.s8oes9dhwrvt0zif","authorID":"a.akf8finncvomlqva","validUntil":2312905480}}}`
* `{code: 1, message:"authorID does not exist", data: null}`
@@ -186,69 +261,149 @@ Sessions can be created between a group and an author. This allows an author to
Pad content can be updated and retrieved through the API
-* **getText(padID, [rev])** returns the text of a pad
*Example returns:*
+#### getText(padID, [rev])
+ * API >= 1
+
+returns the text of a pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {text:"Welcome Text"}}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **setText(padID, text)** sets the text of a pad
*Example returns:*
+#### setText(padID, text)
+ * API >= 1
+
+sets the text of a pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"padID does not exist", data: null}`
* `{code: 1, message:"text too long", data: null}`
-* **getHTML(padID, [rev])** returns the text of a pad formatted as HTML
*Example returns:*
+#### getHTML(padID, [rev])
+ * API >= 1
+
+returns the text of a pad formatted as HTML
+
+*Example returns:*
* `{code: 0, message:"ok", data: {html:"Welcome Text More Text"}}`
* `{code: 1, message:"padID does not exist", data: null}`
### Pad
Group pads are normal pads, but with the name schema GROUPID$PADNAME. A security manager controls access of them and its forbidden for normal pads to include a $ in the name.
-* **createPad(padID [, text])** creates a new (non-group) pad. Note that if you need to create a group Pad, you should call **createGroupPad**.
*Example returns:*
+#### createPad(padID [, text])
+ * API >= 1
+
+creates a new (non-group) pad. Note that if you need to create a group Pad, you should call **createGroupPad**.
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"pad does already exist", data: null}`
-* **getRevisionsCount(padID)** returns the number of revisions of this pad
*Example returns:*
+#### getRevisionsCount(padID)
+ * API >= 1
+
+returns the number of revisions of this pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {revisions: 56}}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **padUsersCount(padID)** returns the number of user that are currently editing this pad
*Example returns:*
+#### padUsersCount(padID)
+ * API >= 1
+
+returns the number of user that are currently editing this pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {padUsersCount: 5}}`
-* **padUsers(padID)** returns the list of users that are currently editing this pad
*Example returns:*
+#### padUsers(padID)
+ * API >= 1.1
+
+returns the list of users that are currently editing this pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {padUsers: [{colorId:"#c1a9d9","name":"username1","timestamp":1345228793126},{"colorId":"#d9a9cd","name":"Hmmm","timestamp":1345228796042}]}}`
* `{code: 0, message:"ok", data: {padUsers: []}}`
-* **deletePad(padID)** deletes a pad
*Example returns:*
+#### deletePad(padID)
+ * API >= 1
+
+deletes a pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **getReadOnlyID(padID)** returns the read only link of a pad
*Example returns:*
+#### getReadOnlyID(padID)
+ * API >= 1
+
+returns the read only link of a pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {readOnlyID: "r.s8oes9dhwrvt0zif"}}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **setPublicStatus(padID, publicStatus)** sets a boolean for the public status of a pad
*Example returns:*
+#### setPublicStatus(padID, publicStatus)
+ * API >= 1
+
+sets a boolean for the public status of a pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **getPublicStatus(padID)** return true of false
*Example returns:*
+#### getPublicStatus(padID)
+ * API >= 1
+
+return true of false
+
+*Example returns:*
* `{code: 0, message:"ok", data: {publicStatus: true}}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **setPassword(padID, password)** returns ok or a error message
*Example returns:*
+#### setPassword(padID, password)
+ * API >= 1
+
+returns ok or a error message
+
+*Example returns:*
* `{code: 0, message:"ok", data: null}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **isPasswordProtected(padID)** returns true or false
*Example returns:*
+#### isPasswordProtected(padID)
+ * API >= 1
+
+returns true or false
+
+*Example returns:*
* `{code: 0, message:"ok", data: {passwordProtection: true}}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **listAuthorsOfPad(padID)** returns an array of authors who contributed to this pad
*Example returns:*
+#### listAuthorsOfPad(padID)
+ * API >= 1
+
+returns an array of authors who contributed to this pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {authorIDs : ["a.s8oes9dhwrvt0zif", "a.akf8finncvomlqva"]}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **getLastEdited(padID)** returns the timestamp of the last revision of the pad
*Example returns:*
+#### getLastEdited(padID)
+ * API >= 1
+
+returns the timestamp of the last revision of the pad
+
+*Example returns:*
* `{code: 0, message:"ok", data: {lastEdited: 1340815946602}}`
* `{code: 1, message:"padID does not exist", data: null}`
-* **sendClientsMessage(padID, msg)** sends a custom message of type `msg` to the pad
', url, escape(suite.title));
+
+ // container
+ stack[0].appendChild(el);
+ stack.unshift(document.createElement('ul'));
+ el.appendChild(stack[0]);
+ });
+
+ runner.on('suite end', function(suite){
+ if (suite.root) return;
+ stack.shift();
+ });
+
+ runner.on('fail', function(test, err){
+ if ('hook' == test.type || err.uncaught) runner.emit('test end', test);
+ });
+
+ runner.on('test end', function(test){
+ window.scrollTo(0, document.body.scrollHeight);
+
+ // TODO: add to stats
+ var percent = stats.tests / total * 100 | 0;
+ if (progress) progress.update(percent).draw(ctx);
+
+ // update stats
+ var ms = new Date - stats.start;
+ text(passes, stats.passes);
+ text(failures, stats.failures);
+ text(duration, (ms / 1000).toFixed(2));
+
+ // test
+ if ('passed' == test.state) {
+ var el = fragment('
%e%ems
', test.speed, test.title, test.duration);
+ } else if (test.pending) {
+ var el = fragment('
%e
', test.title);
+ } else {
+ var el = fragment('
%e
', test.title);
+ var str = test.err.stack || test.err.toString();
+
+ // FF / Opera do not add the message
+ if (!~str.indexOf(test.err.message)) {
+ str = test.err.message + '\n' + str;
+ }
+
+ // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
+ // check for the result of the stringifying.
+ if ('[object Error]' == str) str = test.err.message;
+
+ // Safari doesn't give you a stack. Let's at least provide a source line.
+ if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
+ str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")";
+ }
+
+ el.appendChild(fragment('