Skip to content

Commit a8dcff9

Browse files
author
Alec Gibson
committed
Add support for presence (range) transformations
This change adds support for presence transformations, which are being [added to ShareDB][1]. In order to support presence updates, this change adds support for the optional `transformPresence` method, which simply reuses the existing `transformCursor` method, but also: - applies changes to the `length` of a range - keeps existing metadata - returns `null` if no range has been provided [1]: share/sharedb#322
1 parent 6cbc401 commit a8dcff9

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ We need the following features on top of the original `rich-text` type:
66

77
- additional metadata fields
88
- support for complex attributes
9+
- support for ShareDB's presence functionality with `transformPresence`
910

1011
### Metadata fields
1112

lib/type.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@ module.exports = {
6161

6262
deserialize: function(ops) {
6363
return new DeltaWithMetadata(ops);
64+
},
65+
66+
transformPresence: function(range, op, isOwnOp) {
67+
if (!range) {
68+
return null;
69+
}
70+
71+
const delta = new Delta(op);
72+
const start = this.transformCursor(range.index, delta, isOwnOp);
73+
const end = this.transformCursor(range.index + range.length, delta, isOwnOp);
74+
75+
return Object.assign({}, range, {
76+
index: start,
77+
length: end - start,
78+
});
6479
}
6580
}
6681
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
},
2020
"license": "MIT",
2121
"scripts": {
22-
"test": "mocha test/fuzzer.js --timeout 5000"
22+
"test": "mocha test/**/*.js --timeout 5000"
2323
},
2424
"repository": {
2525
"type": "git",

test/presence.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const Delta = require("quill-delta");
2+
var richText = require('../lib/type').type;
3+
var expect = require('chai').expect;
4+
5+
describe('presence', function() {
6+
it('transforms a zero-length range by an op before it', function() {
7+
const range = {index: 10, length: 0};
8+
const op = new Delta().insert('foo');
9+
const transformed = richText.transformPresence(range, op);
10+
expect(transformed).to.eql({index: 13, length: 0});
11+
});
12+
13+
it('does not transform a zero-length range by an op after it', function() {
14+
const range = {index: 10, length: 0};
15+
const op = new Delta().retain(20).insert('foo');
16+
const transformed = richText.transformPresence(range, op);
17+
expect(transformed).to.eql({index: 10, length: 0});
18+
});
19+
20+
it('transforms a range with length by an op before it', function() {
21+
const range = {index: 10, length: 3};
22+
const op = new Delta().insert('foo');
23+
const transformed = richText.transformPresence(range, op);
24+
expect(transformed).to.eql({index: 13, length: 3});
25+
});
26+
27+
it('transforms a range with length by an op that deletes part of it', function() {
28+
const range = {index: 10, length: 3};
29+
const op = new Delta().retain(9).delete(3);
30+
const transformed = richText.transformPresence(range, op);
31+
expect(transformed).to.eql({index: 9, length: 1});
32+
});
33+
34+
it('transforms a range with length by an op that deletes the whole range', function() {
35+
const range = {index: 10, length: 3};
36+
const op = new Delta().retain(9).delete(5);
37+
const transformed = richText.transformPresence(range, op);
38+
expect(transformed).to.eql({index: 9, length: 0});
39+
});
40+
41+
it('keeps extra metadata when transforming', function() {
42+
const range = {index: 10, length: 0, meta: 'lorem ipsum'};
43+
const op = new Delta().insert('foo');
44+
const transformed = richText.transformPresence(range, op);
45+
expect(transformed).to.eql({index: 13, length: 0, meta: 'lorem ipsum'});
46+
});
47+
48+
it('returns null when no presence is provided', function() {
49+
const op = new Delta().insert('foo');
50+
const transformed = richText.transformPresence(undefined, op);
51+
expect(transformed).to.be.null;
52+
});
53+
54+
it('advances the cursor if inserting at own index', function() {
55+
const range = {index: 10, length: 2};
56+
const op = new Delta().retain(10).insert('foo');
57+
const transformed = richText.transformPresence(range, op, true);
58+
expect(transformed).to.eql({index: 13, length: 2});
59+
});
60+
61+
it('does not advance the cursor if not own op', function () {
62+
const range = {index: 10, length: 2};
63+
const op = new Delta().retain(10).insert('foo');
64+
const transformed = richText.transformPresence(range, op, false);
65+
expect(transformed).to.eql({index: 10, length: 5});
66+
});
67+
68+
it('accepts an array of ops rather than a Delta', function() {
69+
const range = {index: 10, length: 0};
70+
const op = [{insert: 'foo'}];
71+
const transformed = richText.transformPresence(range, op);
72+
expect(transformed).to.eql({index: 13, length: 0});
73+
});
74+
75+
it('does nothing if no op is provided', function() {
76+
const range = {index: 10, length: 0};
77+
const transformed = richText.transformPresence(range, undefined);
78+
expect(transformed).to.eql({index: 10, length: 0});
79+
});
80+
81+
it('does not mutate the original range', function() {
82+
const range = {index: 10, length: 0};
83+
const op = new Delta().insert('foo');
84+
richText.transformPresence(range, op);
85+
expect(range).to.eql({index: 10, length: 0});
86+
});
87+
});

0 commit comments

Comments
 (0)