-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Changeset Library
you can try all this commands live on the node.js console!
$ cd etherpad-lite $ node
> var Changeset = require("./src/static/js/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. It's just a string that is very difficult to read in this form. Thankfully 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. Changesets also get saved into the history of a pad which allows Etherpad to go back to every revision from the past.
As an example let's look into 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 was applied. We will get to know ops
and charBank
next.
> 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 an 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: =
,-
,+
. Operators describe different changes on the text beginning at the first Character of the Text.
The =
operator doesn't change the text, but it may change the attributes of the text (For example make it bold).
The -
operator removes text.
Finally the +
Operator adds text with attributes.
The opcode
tells us the type of the operator. chars
and lines
is the length of the text these operators apply to. attribs
is which attributes this text has.
An an example, The third operator adds one character with the attribute 0. It takes this one character out of the charBank you have seen above
> 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
. The apool
saves which attributes were used during the history of a pad. There is one apool
for each pad. The apool
only saves the attributes that were really used, it doesn't save unused attributes. Let's 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. An 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
> 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.
- Docs
- Translating
- HTTP API
- Plugin framework (API hooks)
- Plugins (available)
- Plugins (list)
- Plugins (wishlist)
- Etherpad URIs / URLs to specific resources IE export
- Etherpad Full data export
- Introduction to the source
- Release Procedure
- Etherpad Developer guidelines
- Project to-do list
- Changeset Library documentation
- Alternative Etherpad-Clients
- Contribution guidelines
- Installing Etherpad
- Deploying Etherpad as a service
- Deploying Etherpad on CloudFoundry
- Deploying Etherpad on Heroku
- Running Etherpad on Phusion Passenger
- Putting Etherpad behind a reverse Proxy (HTTPS/SSL)
- How to setup Etherpad on Ubuntu 12.04 using Ansible
- Migrating from old Etherpad to Etherpad
- Using Etherpad with MySQL
- Customizing the Etherpad web interface
- Enable import/export functionality with AbiWord
- Getting a list of all pads
- Providing encrypted web access to Etherpad using SSL certificates
- Optimizing Etherpad performance including faster page loads
- Getting to know the tools and scripts in the Etherpad /bin/ folder
- Embedding a pad using the jQuery plugin
- Using Embed Parameters
- Integrating Etherpad in a third party app (Drupal, MediaWiki, WordPress, Atlassian, PmWiki)
- HTTP API client libraries