To run the demo:
$ ./sbt
> container:start
...then open: http://127.0.0.1:8080. This will give you a shared document, using the ACE editor.
WOOT is a collaborative text editing algorithm, allowing multiple users ("sites") to insert or delete characters (WChar
) from a shared document (WString
). The algorithm preserves the intention of users, and ensures that the text converges to the same state for all users.
Its key properties are simplicity, and avoiding the need for a reliable network or vector clocks (it can be peer-to-peer).
The key references are:
-
Oster et al. (2005) Real time group editors without Operational transformation, report paper 5580, INRIA - PDF
-
Oster et al. (2006) Data Consistency for P2P Collaborative Editing, CSCW'06 - PDF
WOOT stands for With Out Operational Transforms.
The JavaScript implementation is of the model: you need to bring your own editor and transport mechanism.
You'll find the code in src/main/webapp/wootmodel.js
and it uses Underscore.js and RequireJS.
// Empty model for site A, clock value 0.
var model = new WString("A", 0)
// Locally insert "a" at position 0.
// This returns an operation you can send to your peers.
var op = model.localIntegrate("ins", "a", 0);
// If you receive an operation:
model.remoteIntegrate(op, function(p) {
if (op.op == "del")
console.log("Delete the char at pos ", p);
else
console.log("Insert ", op.wchar.alpha, " at ", p);
});
The remoteIntegrate
call will update the model (the data-structure is mutable). It may not happen immediately. For example, if the model cannot integrate the remote operation, the operation will go onto a queue and be applied when preconditions are satisfied.
Queued operations are automatically tested on any remoteIntegrate
call. You don't have to work the WOOT queue yourself.
For a full example of using the library via RequireJS, see src/main/webapp/index.html
which imports code via main.js
.
## Data Structures
{
site: "X",
clock: N
}
{
id: ID,
alpha: "X",
isVisible: true,
prev: ID,
next: ID
}
{
op: "ins" (or "del"),
from: "X" (site id),
wchar: WCHAR
}
To run the Jasmine tests, open src/test/javascript/SpecRunner.html
in a browser.
The Scala version of the model is intended to be a passive peer in a collaborative editing session. As such the integrate
method is a remote integrate, and there is no equivalent of the JavaScript localIntegrate
function. (Only because I don't need it -- it wouldn't be hard to add at all.)
The Scala WString
data structure is immutable, which is another difference from the JavaScript version.
import spiralarm.woot._
val s = WString()
val c = WChar(CharId("A",1), 'a', Beginning, Ending)
val s_prime = s.integrate(InsOperation(c, from="A"))
s_prime.text == "a"
To build the documentation:
$ ./docco.sh
and then open the files in the docs folder.
There are unit tests:
$ sbt test
There is a Lift application, which you can start with:
$ sbt
> container:start
This is a single document example using the ACE editor, with Lift providing the transport. Running this example gives you a shared editor at http://127.0.0.1:8080.
If you see either of these errors in your chrome console...
- GET http://localhost:8080/jquery-1.10.2.min.map 404 (Not Found)
- GET http://localhost:8080/underscore-min.map 404 (Not Found)
view this Stackoverflow question for a solution.