Skip to content
redhog edited this page May 30, 2012 · 6 revisions

you can try all this commands live on the node.js console!

$ cd etherpad-lite/node
$ node

Changesets

> var Changeset = require("./utils/Changeset");

Lets require the Changeset Library. This code is still 99% from the old Etherpad

> var cs = "Z:z>1|2=m=b*0|1+1$\n";

This is a Changeset. Its just a string and its very difficult to read in this form. But the Changeset Library gives us some tools to read it. A changeset describes the diff between two revisions of the document. The Browser sends changesets to the server and the server sends them to the clients to update them. This Changesets gets also saved into the history of a pad. Which allows us to go back to every revision from the past. Let's discover this changeset

> var unpacked = Changeset.unpack(cs);
{ oldLen: 35, newLen: 36, ops: '|2=m=b*0|1+1', charBank: '\n' }

We unpacked the Changeset. oldLen is the original length. newLen is the Length of the text after the Changeset got applied. You will see what ops and charBank is after the next steps

> var opiterator = Changeset.opIterator(unpacked.ops);
> console.log(opiterator)
{ next: [Function: next],
  hasNext: [Function: hasNext],
  lastIndex: [Function: lastIndex] }

We created a operator iterator. This iterator allows us to iterate over all operators that are in the Changeset. Let's see how a operator looks like

  
> opiterator.next()
{ opcode: '=',
  chars: 22,
  lines: 2,
  attribs: '' }
> opiterator.next()
{ opcode: '=',
  chars: 11,
  lines: 0,
  attribs: '' }
> opiterator.next()
{ opcode: '+',
  chars: 1,
  lines: 1,
  attribs: '*0' }
> opiterator.next()
{ opcode: '',
  chars: 0,
  lines: 0,
  attribs: '' }
> opiterator.hasNext()
false

There are 3 operators in this Changeset. There are 3 types of operators: +,-,= . This operators describe different changes on the text beginning by the first Character of the Text. A = operator doesn't change the text, but it may changes the attributes of the text. A - operator removes text. And a + Operator adds text with attributes. The opcode tells us the type of the operator. chars and lines tells us the length of the text this operators apply to. attribs tells us which attributes this text has.

So for example the third operator adds one character with the attribute 0. It takes this one character out of the charBank you have seen above

APool

> var AttributePoolFactory = require("./utils/AttributePoolFactory");
> var apool = AttributePoolFactory.createAttributePool();
> console.log(apool)
{ numToAttrib: {},
  attribToNum: {},
  nextNum: 0,
  putAttrib: [Function],
  getAttrib: [Function],
  getAttribKey: [Function],
  getAttribValue: [Function],
  eachAttrib: [Function],
  toJsonable: [Function],
  fromJsonable: [Function] }

This creates an empty apool. A apool saves which attributes were used during the history of a pad. There is one apool for each pad. It only saves the attributes that were really used, it doesn't save unused attributes. Lets fill this apool with some values

> apool.fromJsonable({"numToAttrib":{"0":["author","a.kVnWeomPADAT2pn9"],"1":["bold","true"],"2":["italic","true"]},"nextNum":3});
> console.log(apool)
{ numToAttrib: 
   { '0': [ 'author', 'a.kVnWeomPADAT2pn9' ],
     '1': [ 'bold', 'true' ],
     '2': [ 'italic', 'true' ] },
  attribToNum: 
   { 'author,a.kVnWeomPADAT2pn9': 0,
     'bold,true': 1,
     'italic,true': 2 },
  nextNum: 3,
  putAttrib: [Function],
  getAttrib: [Function],
  getAttribKey: [Function],
  getAttribValue: [Function],
  eachAttrib: [Function],
  toJsonable: [Function],
  fromJsonable: [Function] }

We used the fromJsonable function to fill the empty apool with values. the fromJsonable and toJsonable functions are used to serialize and deserialize an apool. You can see that it stores the relation between numbers and attributes. So for example the attribute 1 is the attribute bold and vise versa. A attribute is always a key value pair. For stuff like bold and italic its just 'italic':'true'. For authors its author:$AUTHORID. So a character can be bold and italic. But it can't belong to multiple authors

> apool.getAttrib(1)
[ 'bold', 'true' ]

Simple example of how to get the key value pair for the attribute 1

AText

> var atext = {"text":"bold text\nitalic text\nnormal text\n\n","attribs":"*0*1+9*0|1+1*0*1*2+b|1+1*0+b|2+2"};
> console.log(atext)
{ text: 'bold text\nitalic text\nnormal text\n\n',
  attribs: '*0*1+9*0|1+1*0*1*2+b|1+1*0+b|2+2' }

This is an atext. An atext has two parts: text and attribs. The text is just the text of the pad as a string. We will look closer at the attribs at the next steps

> var opiterator = Changeset.opIterator(atext.attribs)
> console.log(opiterator)
{ next: [Function: next],
  hasNext: [Function: hasNext],
  lastIndex: [Function: lastIndex] }
> opiterator.next()
{ opcode: '+',
  chars: 9,
  lines: 0,
  attribs: '*0*1' }
> opiterator.next()
{ opcode: '+',
  chars: 1,
  lines: 1,
  attribs: '*0' }
> opiterator.next()
{ opcode: '+',
  chars: 11,
  lines: 0,
  attribs: '*0*1*2' }
> opiterator.next()
{ opcode: '+',
  chars: 1,
  lines: 1,
  attribs: '' }
> opiterator.next()
{ opcode: '+',
  chars: 11,
  lines: 0,
  attribs: '*0' }
> opiterator.next()
{ opcode: '+',
  chars: 2,
  lines: 2,
  attribs: '' }

The attribs are again a bunch of operators like .ops in the changeset was. But these operators are only + operators. They describe which part of the text has which attributes

For more information see ./doc/easysync/easysync-notes.txt in the source.

General

Resources

For Developers

How to's

Set up

Advanced steps

Integrating Etherpad in your web app

for Developers

Clone this wiki locally