You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This change adds the ability for clients to broadcast information about
"Presence" - the notion of a client's position or state in a particular
document. This might be represent a cursor in a text document, or a
highlighted field in a more complex JSON document, or any other
transient, current information about a client that shouldn't necessarily
be stored in the document's chain of ops.
The main complication that this feature solves is the issue of keeping
presence correctly associated with the version of a `Doc` it was created
at. For example, in a "naive" implementation of presence, presence
information can arrive ahead of or behind ops, which - in a text-based
example - can cause the cursor to "jitter" around the change. Using the
ShareDB implementation will ensure that the presence is correctly
transformed against any ops, and will ensure that presence information
is always consistent with the version of the document. We also locally
transform existing presence, which should help to keep (static) remote
presence correctly positioned, independent of latency.
In order to facilitate this, the feature must be used with an OT type
that supports presence. The only requirement for supporting presence is
the support of a `transformPresence` method:
```javascript
type.transformPresence(presence, op, isOwnOperation): presence;
```
* `presence` _Object_: the presence data being transformed. The type
will define this shape to be whatever is appropriate for the type.
* `op` _Op_: the operation against which to transform the presence
* `isOwnOperation`: _boolean_: whether the presence and the op have the
same "owner". This information can be useful for some types to break
ties when transforming a presence, for example as used in
[`rich-text`][1]
This work is based on the [work][2] by @gkubisa and @curran, but with
the following aims:
- avoid modifying the existing `Doc` class as much as possible, and
instead use lifecycle hooks
- keep presence separate as its own conceptual entity
- break the presence subscriptions apart from `Doc` subscriptions
(although in practice, the two are obviously tightly coupled)
- allow multiple presences on a single `Doc` on the same `Connection`
[1]: https://github.com/quilljs/delta#tranformposition
[2]: #288
Get a [`LocalPresence`](#class-sharedblocalpresence) instance that can be used to send presence information to other clients. Note that the `Doc` must use a type that supports presence.
309
+
310
+
*`collection`_(String)_
311
+
Collection name of the `Doc`
312
+
*`id`_(String)_
313
+
ID of the `Doc`
314
+
*`presenceId`_(String)_
315
+
A unique presence ID that will be sent to remote clients along with the presence data
316
+
306
317
### Class: `ShareDB.Doc`
307
318
308
319
`doc.type`_(String_)
@@ -349,6 +360,9 @@ The document was deleted. Document contents before deletion are passed in as an
349
360
`doc.on('error', function(err) {...})`
350
361
There was an error fetching the document or applying an operation.
A remote client has sent presence information. `id` is an ID provided by the remote client, and `presence` is the presence data, whose structure will depend on document's OT type.
365
+
352
366
`doc.removeListener(eventName, listener)`
353
367
Removes any listener you added with `doc.on`. `eventName` should be one of `'load'`, `'create'`, `'before op'`, `'op'`, `'del'`, or `'error'`. `listener` should be the function you passed in as the second argument to `on`. Note that both `on` and `removeListener` are inherited from [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).
354
368
@@ -379,6 +393,12 @@ Invokes the given callback function after
379
393
380
394
Note that `whenNothingPending` does NOT wait for pending `model.query()` calls.
381
395
396
+
`doc.subscribeToPresence([function(err) {...}])`
397
+
Subscribes to presence updates sent by other clients, emitting `presence` events (see above).
Unsubscribe from presence updates sent by other clients, and stop receiving `presence` events (see above).
401
+
382
402
### Class: `ShareDB.Query`
383
403
384
404
`query.ready`_(Boolean)_
@@ -629,6 +649,49 @@ var connectionInfo = getUserPermissions();
629
649
var connection =backend.connect(null, connectionInfo);
630
650
```
631
651
652
+
### Class: `ShareDB.LocalPresence`
653
+
654
+
`LocalPresence` represents the presence of the local client in a given `Doc`. For example, this might be the position of a caret in a text document; which field has been highlighted in a complex JSON object; etc. Multiple presences may exist per `Doc` even on the same client.
Update the local representation of presence, and broadcast that presence to any other document presence subscribers.
663
+
664
+
*`presence`_Object_: the presence object to broadcast. The structure of this will depend on the OT type
665
+
*`options`_Object (optional)_
666
+
*`options.subscribe`_boolean (default `true`)_: if set to `true`, will subscribe to presence updates on the document. Setting to `false` will unsubscribe.
667
+
*`callback`_Function_: a callback with the signature `function (error: Error): void;`
668
+
669
+
#### `clear`
670
+
671
+
```javascript
672
+
localPresence.clear(callback);
673
+
```
674
+
675
+
Tell remote subscribers that this presence is no longer present in the `Doc`. For example, this might prompt remote clients to remove a cursor from a text document, or to clear highlighting around a selected field, etc.
676
+
677
+
The `LocalPresence` object will not be destroyed (see below), and can still be used to send further updates.
678
+
679
+
This is shorthand for `localPresence.update(null, callback)`.
680
+
681
+
*`callback`_Function_: a callback with the signature `function (error: Error): void;`
682
+
683
+
#### `destroy`
684
+
685
+
```javascript
686
+
localPresence.destroy(callback);
687
+
```
688
+
689
+
Updates all remote clients with a `null` presence. Then destroys the local instance of the presence by de-registering all the `Doc` hooks it listens to, and removes it from the `Connection` cache, so that it can be garbage-collected. This should be called when you are done with a presence, and no longer need to use it to fire updates.
690
+
691
+
This method is automatically called when calling `doc.destroy`.
692
+
693
+
*`callback`_Function_: a callback with the signature `function (error: Error): void;`
694
+
632
695
### Logging
633
696
634
697
By default, ShareDB logs to `console`. This can be overridden if you wish to silence logs, or to log to your own logging driver or alert service.
0 commit comments