diff --git a/README.md b/README.md deleted file mode 100644 index deb2ced23..000000000 --- a/README.md +++ /dev/null @@ -1,126 +0,0 @@ -# Making collaborative editing the standard on the web - -# About -Etherpad lite is a really-real time collaborative editor spawned from the Hell fire of Etherpad. -We're reusing the well tested Etherpad easysync library to make it really realtime. Etherpad Lite -is based on node.js ergo is much lighter and more stable than the original Etherpad. Our hope -is that this will encourage more users to use and install a realtime collaborative editor. A smaller, manageable and well -documented codebase makes it easier for developers to improve the code and contribute towards the project. - -**Etherpad vs Etherpad lite** - - - - - - - - - - - - - - - - -
 EtherpadEtherpad Lite
Size of the folder (without git history)30 MB1.5 MB
Languages used server sideJavascript (Rhino), Java, ScalaJavascript (node.js)
Lines of server side Javascript code~101k~9k
RAM Usage immediately after start257 MB (grows to ~1GB)16 MB (grows to ~30MB)
- - -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). -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! - -# Installation - -## Windows - -### 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 -2. Extract the folder - -Now, run `start.bat` and open in your browser. You like it? [Next steps](#next-steps). - -### Fancy install -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) -2. start `bin\installOnWindows.bat` - -Now, run `start.bat` and open in your browser. - -Update to the latest version with `git pull origin`, then run `bin\installOnWindows.bat`, again. - -[Next steps](#next-steps). - -## Linux -You'll 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"` - -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` -2. Change into the new directory containing the cloned source code `cd etherpad-lite` - -Now, run `bin\run.sh` and open in your browser. - -Update to the latest version with `git pull origin`. The next start with bin/run.sh will update the dependencies. - -You like it? [Next steps](#next-steps). - -# Next Steps - -## Tweak the settings -You can modify the settings in `settings.json`. (If you need to handle multiple settings files, you can pass the path to a settings file to `bin/run.sh` using the `-s|--settings` option. This allows you to run multiple Etherpad Lite instances from the same installation.) - -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. - -Documentation can be found in `docs/`. - -# Development - -## Things you should know -Read this [git guide](http://learn.github.com/p/intro.html) and watch this [video on getting started with Etherpad Lite Development](http://youtu.be/67-Q26YH97E). - -If you're new to node.js, start with Ryan Dahl's [Introduction to Node.js](http://youtu.be/jo_B4LTHi3I). - -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). - -## 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.) - -Also, and most importantly, read our [**Developer Guidelines**](https://github.com/Pita/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" - -# 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 diff --git a/tests/frontend/index.html b/tests/frontend/index.html index 53541d7f5..4a579a1b3 100644 --- a/tests/frontend/index.html +++ b/tests/frontend/index.html @@ -18,7 +18,11 @@ + + + diff --git a/tests/frontend/specs/button_clear_authorship_colors.js b/tests/frontend/specs/button_clear_authorship_colors.js new file mode 100644 index 000000000..8949a5f75 --- /dev/null +++ b/tests/frontend/specs/button_clear_authorship_colors.js @@ -0,0 +1,52 @@ +describe("clear authorship colors button", function(){ + //create a new pad before each test run + beforeEach(function(cb){ + helper.newPad(cb); + this.timeout(5000); + }); + + it("makes text clear authorship colors", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + // override the confirm dialogue functioon + helper.padChrome$.window.confirm = function(){ + return true; + } + + //get the first text element out of the inner iframe + var $firstTextElement = inner$("div").first(); + + // Get the original text + var originalText = inner$("div").first().text(); + + // Set some new text + var sentText = "Hello"; + + //select this text element + $firstTextElement.sendkeys(sentText); + + helper.waitFor(function(){ + return inner$("div").first().text() === sentText + originalText; // wait until we have the full value available + }).done(function(){ + // does the first divs span include an author class? + var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1; + expect(hasAuthorClass).to.be(true); + + //get the clear authorship colors button and click it + var $clearauthorshipcolorsButton = chrome$(".buttonicon-clearauthorship"); + $clearauthorshipcolorsButton.click(); + + // does the first divs span include an author class? + var hasAuthorClass = inner$("div span").first().attr("class").indexOf("author") !== -1; + expect(hasAuthorClass).to.be(false); + + // does the first div include an author class? + var hasAuthorClass = inner$("div").first().attr("class").indexOf("author") !== -1; + expect(hasAuthorClass).to.be(false); + + done(); + }); + + }); +}); diff --git a/tests/frontend/specs/button_ordered_list.js b/tests/frontend/specs/button_ordered_list.js new file mode 100644 index 000000000..75a26ded6 --- /dev/null +++ b/tests/frontend/specs/button_ordered_list.js @@ -0,0 +1,47 @@ +describe("assign ordered list", function(){ + //create a new pad before each test run + beforeEach(function(cb){ + helper.newPad(cb); + this.timeout(5000); + }); + + it("insert ordered list text", function(done){ + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist"); + $insertorderedlistButton.click(); + + helper.waitFor(function(){ + return inner$("div").first().find("ol li").length === 1; + }).done(done); + }); + + it("keeps the numbered list on enter for the new line - EMULATES PASTING INTO A PAD", function(done){ + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + var $insertorderedlistButton = chrome$(".buttonicon-insertorderedlist"); + $insertorderedlistButton.click(); + + //type a bit, make a line break and type again + var $firstTextElement = inner$("div span").first(); + $firstTextElement.sendkeys('line 1'); + $firstTextElement.sendkeys('{enter}'); + $firstTextElement.sendkeys('line 2'); + $firstTextElement.sendkeys('{enter}'); + + helper.waitFor(function(){ + return inner$("div span").first().text().indexOf("line 2") === -1; + }).done(function(){ + var $newSecondLine = inner$("div").first().next(); + var hasOLElement = $newSecondLine.find("ol li").length === 1; + console.log($newSecondLine.find("ol")); + expect(hasOLElement).to.be(true); + expect($newSecondLine.text()).to.be("line 2"); + var hasLineNumber = $newSecondLine.find("ol").attr("start") === 2; + expect(hasLineNumber).to.be(true); // This doesn't work because pasting in content doesn't work + done(); + }); + }); +}); diff --git a/tests/frontend/specs/button_redo.js b/tests/frontend/specs/button_redo.js new file mode 100644 index 000000000..59991ebec --- /dev/null +++ b/tests/frontend/specs/button_redo.js @@ -0,0 +1,35 @@ +describe("undo button", function(){ + beforeEach(function(cb){ + helper.newPad(cb); // creates a new pad + this.timeout(5000); + }); + + it("undo some typing", function(done){ + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + // get the first text element inside the editable space + var $firstTextElement = inner$("div span").first(); + var originalValue = $firstTextElement.text(); // get the original value + + $firstTextElement.sendkeys("foo"); // send line 1 to the pad + var modifiedValue = $firstTextElement.text(); // get the modified value + expect(modifiedValue).not.to.be(originalValue); // expect the value to change + + // get clear authorship button as a variable + var $undoButton = chrome$(".buttonicon-undo"); + var $redoButton = chrome$(".buttonicon-redo"); + // click the buttons + $undoButton.click(); + $redoButton.click(); + + helper.waitFor(function(){ + return inner$("div span").first().text() === originalValue; + }).done(function(){ + var finalValue = inner$("div span").first().text(); + expect(finalValue).to.be(modifiedValue); // expect the value to change + done(); + }); + }); +}); + diff --git a/tests/frontend/specs/button_strikethrough.js b/tests/frontend/specs/button_strikethrough.js new file mode 100644 index 000000000..0c1fb43d5 --- /dev/null +++ b/tests/frontend/specs/button_strikethrough.js @@ -0,0 +1,36 @@ +describe("strikethrough button", function(){ + //create a new pad before each test run + beforeEach(function(cb){ + helper.newPad(cb); + this.timeout(5000); + }); + + it("makes text strikethrough", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + //get the first text element out of the inner iframe + var $firstTextElement = inner$("div").first(); + + //select this text element + $firstTextElement.sendkeys('{selectall}'); + + //get the strikethrough button and click it + var $strikethroughButton = chrome$(".buttonicon-strikethrough"); + $strikethroughButton.click(); + + //ace creates a new dom element when you press a button, so just get the first text element again + var $newFirstTextElement = inner$("div").first(); + + // is there a element now? + var isstrikethrough = $newFirstTextElement.find("s").length === 1; + + //expect it to be strikethrough + expect(isstrikethrough).to.be(true); + + //make sure the text hasn't changed + expect($newFirstTextElement.text()).to.eql($firstTextElement.text()); + + done(); + }); +}); diff --git a/tests/frontend/specs/button_undo.js b/tests/frontend/specs/button_undo.js new file mode 100644 index 000000000..ea6a28352 --- /dev/null +++ b/tests/frontend/specs/button_undo.js @@ -0,0 +1,33 @@ +describe("undo button", function(){ + beforeEach(function(cb){ + helper.newPad(cb); // creates a new pad + this.timeout(5000); + }); + + it("undo some typing", function(done){ + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + // get the first text element inside the editable space + var $firstTextElement = inner$("div span").first(); + var originalValue = $firstTextElement.text(); // get the original value + + $firstTextElement.sendkeys("foo"); // send line 1 to the pad + var modifiedValue = $firstTextElement.text(); // get the modified value + expect(modifiedValue).not.to.be(originalValue); // expect the value to change + + // get clear authorship button as a variable + var $undoButton = chrome$(".buttonicon-undo"); + // click the button + $undoButton.click(); + + helper.waitFor(function(){ + return inner$("div span").first().text() === originalValue; + }).done(function(){ + var finalValue = inner$("div span").first().text(); + expect(finalValue).to.be(originalValue); // expect the value to change + done(); + }); + }); +}); + diff --git a/tests/frontend/specs/change_user_name.js b/tests/frontend/specs/change_user_name.js new file mode 100644 index 000000000..b40b49534 --- /dev/null +++ b/tests/frontend/specs/change_user_name.js @@ -0,0 +1,31 @@ +describe("change username value", function(){ + //create a new pad before each test run + beforeEach(function(cb){ + helper.newPad(cb); + this.timeout(5000); + }); + + it("makes sure changing username works", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + //click on the settings button to make settings visible + var $userButton = chrome$(".buttonicon-showusers"); + $userButton.click(); + + var $usernameInput = chrome$("#myusernameedit"); + $usernameInput.click(); + + $usernameInput.sendkeys('{selectall}'); + $usernameInput.sendkeys('{del}'); + $usernameInput.sendkeys('John McLear'); + $usernameInput.sendkeys('{enter}'); + + var correctUsernameValue = $usernameInput.val() === "John McLear"; + + //check if the username has been changed to John McLear + expect(correctUsernameValue).to.be(true); + + done(); + }); +}); diff --git a/tests/frontend/specs/chat_always_on_screen.js b/tests/frontend/specs/chat_always_on_screen.js new file mode 100644 index 000000000..8e4e1f01d --- /dev/null +++ b/tests/frontend/specs/chat_always_on_screen.js @@ -0,0 +1,29 @@ +describe("chat always ons creen select", function(){ + //create a new pad before each test run + beforeEach(function(cb){ + helper.newPad(cb); + this.timeout(5000); + }); + + it("makes chat stick to right side of the screen", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + //click on the settings button to make settings visible + var $settingsButton = chrome$(".buttonicon-settings"); + $settingsButton.click(); + + //get the chat selector + var $stickychatCheckbox = chrome$("#options-stickychat"); + + //select monospace and fire change event + $stickychatCheckbox.attr('selected','selected'); + $stickychatCheckbox.change(); + + //check if chat changed to get the stickychat Class + var hasStickyChatClass = chrome$(".chatbox").hasClass("stickychat"); + expect(hasStickyChatClass).to.be(true); + + done(); + }); +}); diff --git a/tests/frontend/specs/keystroke_enter.js b/tests/frontend/specs/keystroke_enter.js new file mode 100644 index 000000000..4d37f00ec --- /dev/null +++ b/tests/frontend/specs/keystroke_enter.js @@ -0,0 +1,34 @@ +describe("enter keystroke", function(){ + //create a new pad before each test run + beforeEach(function(cb){ + helper.newPad(cb); + this.timeout(5000); + }); + + it("creates a enw line & puts cursor onto a new line", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + //get the first text element out of the inner iframe + var $firstTextElement = inner$("div").first(); + + // get the original string value minus the last char + var originalTextValue = $firstTextElement.text(); + + // simulate key presses to enter content + $firstTextElement.sendkeys('{enter}'); + + //ace creates a new dom element when you press a keystroke, so just get the first text element again + var $newFirstTextElement = inner$("div").first(); + + helper.waitFor(function(){ + return inner$("div").first().text() === ""; + }).done(function(){ + var $newSecondLine = inner$("div").first().next(); + var newFirstTextElementValue = inner$("div").first().text(); + expect(newFirstTextElementValue).to.be(""); // expect the first line to be blank + expect($newSecondLine.text()).to.be(originalTextValue); // expect the second line to be the same as the original first line. + done(); + }); + }); +});