Skip to content
josephg edited this page Sep 8, 2011 · 20 revisions

Client API

The client library lets you view and edit sharejs documents remotely using the server's socket.io frontend.

The API lets you do the following things:

  • Get document snapshots
  • Stream ops as they are submitted to a document
  • Submit ops

The following stuff is currently unsupported:

  • Getting historical operations
  • Undo
  • Listing documents
  • Deleting documents

Accessing the client library

From node.js:

var sharejs = require('share').client;

sharejs.open('hello', 'text', 'http://example.com:8000/sjs', function(doc, error) {
    ...
});

From a website hosted by the share.js server:

<script src="/socket.io/socket.io.js"></script>
<script src="/share/share.js"></script>
<script>
  sharejs.open('hello', 'text', function(doc, error) {
      ...
  });
</script>

From a website hosted elsewhere:

<script src="http://example.com:8000/socket.io/socket.io.js"></script>
<script src="http://example.com:8000/share/share.js"></script>
<script>
  sharejs.open('hello', 'text', 'http://example.com:8000/sjs', function(doc, error) {
      ...
  });
</script>

Opening documents

The easy way

  • open()

sharejs.open(docName, type, [url], function(doc, error){ ... })


    Open a sharejs document with the given name and type. A handle to the document will be passed to the callback once its snapshot has been received by the server.

    This method is a convenience method for `connection.open`, below.

    If the document does not already exist, it will be created using the specified type before being returned to the callback. If the document already exists and has a different type, an error will be passed to the callback.

    Document names are case sensitive.

    The type can be specified as a string (eg, `'text'`) or an object (eg, `require('share').types.text`).

    The URL is a socket.io URL. It looks like `http[s]://hostname:port/sjs`. (Note the `sjs` on the end specifies the default sharejs resource identifier. This may change in a future version.)

    The URL is only needed when using sharejs from a node.js app or when you're running sharejs from a different machine than the page's host. In the browser, it will default to 'PROTO://HOSTNAME:PORT/sjs'. If the default is fine, leave it out.


### Manually managed connections

You only need to manually use connections if you're doing something tricky. Most people should just call `sharejs.open`.

> __NOTE:__ Connections don't currently automatically reconnect when disconnected. If this is important to you, please help out :)

A Connection manages a connection to a share.js server. You only need one connection to a given server no matter how many documents you have open.

If you use the `sharejs.open` API (above), connections are created for you automatically.

* **new Connection()**

    ```javascript
connection = new sharejs.Connection(host, port)
Create a connection to a sharejs server running at the default hostname & path. Set basePath to whatever the socket.io basepath is set to in the server (blank if you haven't changed it).
  • connection.open()

connection.open(docName, type, [url], function(doc, error) {...})


    Open a sharejs document with the given name and type. A handle to the document will be passed to the callback once its snapshot has been received by the server.

    If all you want to do is open documents of a known type on a known server, I recommend using `sharejs.open`, above. This way, the connection will be managed for you.

    If the document does not already exist, it will be created using the specified type before being returned to the callback. If the document already exists and has a different type, an error will be passed to the callback.
    
    Document names are case sensitive.

    The type can be specified as a string (eg, `'text'`) or an object (eg, `require('share').types.text`).


* **connection.openExisting()**

    ```javascript
connection.openExisting(docName, function(doc, error) {...})
Open an existing document. If the document does not exist, the callback is passed `null`.
  • connection.disconnect()

connection.disconnect()


    Disconnect from the server. Once disconnected, all documents currently open through the connection will stop sending and receiving ops. There is no reconnect.


## Documents

All open methods in the client return `Document` objects. These objects are handles to documents sitting on the share.js server. The document object implements client-side OT so you don't have to worry about concurrency in your app.

You cannot create documents directly. Instead, use any of the `open()` methods described above.


* **doc.getText()** *(Text documents only)*

    ```javascript
doc.getText()
Get the contents of the document as a string.
  • doc.insert() (Text documents only)

doc.insert(text, position, [function(appliedOp, error) {...}])

    
    Insert the given text at the specified position in the document. The position is an integer specifying the character position from the start of the document.

    Eg: Given a document with text `abc`, insert a `d` at the end by calling `doc.insert('d', 3)`.

    Locally, the document is edited immediately. (If you call getText() straight after doc.insert, your document will already have been edited). The callback is called once the server has acknowledged the operation.

    The world won't end if you don't, but for consistency you should use unix line endings.

    If you make multiple calls to `doc.insert()`, `doc.del()` and `doc.submitOp()` within the same event handler, your edits will be composed together and sent as a single operation.


* **doc.del()** *(Text documents only)*

    ```javascript
doc.del(length, position, [function(appliedOp, error) {...}])
Delete `length` characters from the document at the specified position in the document. The position is an integer specifying the character position from the start of the document.

Eg: Given a document with text `abcd`, delete the `d` at the end by calling `doc.del(1, 3)`.

Locally, the document is edited immediately. (If you call getText() straight after doc.insert, your document will already have been edited). The callback is called once the server has acknowledged the operation.

If you make multiple calls to `doc.insert()`, `doc.del()` and `doc.submitOp()` within the same event handler, your edits will be composed together and sent as a single operation.
  • doc.snapshot

      doc.snapshot
    

    The document's current state. For text documents, this is a string containing the contents of the document. This snapshot includes any modifications made locally which have not yet propagated to the server.

  • doc.version

      doc.version
    

    The document's version on the server. This is a number counting from 1 when the document was first created. It is incremented each time an operation is applied to the document on the server. The client will compose together multiple operations if they happen close together, so be aware may not be incremented as often as you expect it to.

  • doc.type

      doc.type
    

    The OT type of the document. This object contains the document type's OT functions. See the section on OT types for details.

  • doc.submitOp()

doc.submitOp(op, [function(appliedOp, error) {...}])


    **This is a pretty low level function for editing documents. If you're editing text, you probably want to use the high level API methods (insert(), del(), etc) instead.**

    **This has been changed since v0.3 - the optional version parameter was removed.**

    Submit an operation to the document. The operation must be valid given the document's type. The operation will be applied to the local document snapshot immediately (before submitOp returns).

    It will be applied to the server as soon as possible (only one op is allowed in-flight at a time). If multiple ops are applied within the same scheduler frame, they are composed together before being sent. Ie, if you call `doc.submit(op1); doc.submit(op2);`, the client will compose `op1` and `op2` for you.

    If a callback is specified, it will be called once the server has acknowledged the operation. It is passed the operation as it was accepted by the server, or an error message in the second argument. This will not necessarily be the same as the op that was submitted originally. You don't need to wait for the callback before calling submitOp() again.

    If the op is invalid, submitOp will throw an exception and the document will not be modified. If your code generating the ops is correct, this should never happen.

    I expect most people will never use the callback field of submitOp. Just call `submitOp(myCoolOp)` as much as you like and the client code should take care of everything else.

    Text operations look like this:

    Insert 'Some text' at position 100 in the document:

        {i:'Some text', p:100}

    Delete 'blargh' at position 300:

        {d:'blargh', p:300}

    Multiple changes can be specified in the same operation. This deletes 'Sam' in the document at position 10 in the document string, and replaces it with 'Seph' at the same location.

        [{d:'Sam', p:10}, {i:'Seph', p:10}]

    See the documentation on types for more detail, as well as op specs for other types.

* **doc.close()**

        doc.close([callback])

    Close the document. When the server acknowledges that the document has been closed, the callback is called and the `'closed'` event is emitted.


### Events

The document is a simple event emitter. Use `doc.on(event, callback)` to register callbacks and `doc.removeListener(event, callback)` to remove them.


* **insert**

    ```javascript
doc.on('insert', function(text, position) {})
*(Text documents only)*
Emitted whenever a remote client inserts `text` at `position`. Positions are specified as character offsets from the start of the document.

If a remote client makes multiple changes to the document within a single operation, the document snapshot will be updated with all changes before your callbacks are called.

Eg: Given a document `ace`, a client inserts a `b` and a `d` to make the document `abcde`. You have registered `doc.on('insert', foo)`. ShareJS will call `foo('b', 1)` then `foo('d', 3)`.
  • delete

doc.on('delete', function(text, position) {})


    *(Text documents only)*
    Emitted whenever a remote client deletes `text` at `position`. Positions are specified as character offsets from the start of the document.

    If a remote client makes multiple changes to the document within a single operation, the document snapshot will be updated with all changes before your callbacks are called.

    Eg: Given a document `abcde`, a client deletes a `b` and a `d` to make the document `ace`. You have registered `doc.on('delete', foo)`. ShareJS will call `foo('b', 1)` then `foo('d', 2)`.


* **remoteop**

    ```javascript
doc.on('remoteop', function(op) {})
Emitted each time the document is changed remotely with the op from the server. If you're hooking sharejs up to an editor, listen to this event and update the contents of the editor window accordingly.

By the time your callback is called, the document's `snapshot` and `version` will have been updated by the change. If you want, your listener method can just read the snapshot out of the document again.
  • change

doc.on('change', function(op) {})


    Emitted each time the document is changed either locally or remotely. The op which modified the document is passed to the callback.


* **closed**

    ```javascript
doc.on('closed', function() {})
Emitted when the server has acknowledged that the document is closed.
Clone this wiki locally