Skip to content

Commit

Permalink
Add support for presence (range) transformations
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Alec Gibson committed Mar 2, 2020
1 parent f4350e5 commit ce14c8f
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 2 deletions.
17 changes: 16 additions & 1 deletion lib/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ module.exports = {

deserialize: function(ops) {
return new Delta(ops);
}
},

transformPresence: function(range, op, isOwnOp) {
if (!range) {
return null;
}

const delta = new Delta(op);
const start = this.transformCursor(range.index, delta, isOwnOp);
const end = this.transformCursor(range.index + range.length, delta, isOwnOp);

return Object.assign({}, range, {
index: start,
length: end - start,
});
},
}
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
"license": "MIT",
"scripts": {
"test": "mocha test/fuzzer.js --timeout 5000"
"test": "mocha test/**/*.js --timeout 5000"
},
"repository": {
"type": "git",
Expand Down
87 changes: 87 additions & 0 deletions test/presence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const Delta = require("quill-delta");
var richText = require('../lib/type').type;
var expect = require('chai').expect;

describe('presence', function() {
it('transforms a zero-length range by an op before it', function() {
const range = {index: 10, length: 0};
const op = new Delta().insert('foo');
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 13, length: 0});
});

it('does not transform a zero-length range by an op after it', function() {
const range = {index: 10, length: 0};
const op = new Delta().retain(20).insert('foo');
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 10, length: 0});
});

it('transforms a range with length by an op before it', function() {
const range = {index: 10, length: 3};
const op = new Delta().insert('foo');
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 13, length: 3});
});

it('transforms a range with length by an op that deletes part of it', function() {
const range = {index: 10, length: 3};
const op = new Delta().retain(9).delete(3);
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 9, length: 1});
});

it('transforms a range with length by an op that deletes the whole range', function() {
const range = {index: 10, length: 3};
const op = new Delta().retain(9).delete(5);
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 9, length: 0});
});

it('keeps extra metadata when transforming', function() {
const range = {index: 10, length: 0, meta: 'lorem ipsum'};
const op = new Delta().insert('foo');
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 13, length: 0, meta: 'lorem ipsum'});
});

it('returns null when no presence is provided', function() {
const op = new Delta().insert('foo');
const transformed = richText.transformPresence(undefined, op);
expect(transformed).to.be.null;
});

it('advances the cursor if inserting at own index', function() {
const range = {index: 10, length: 2};
const op = new Delta().retain(10).insert('foo');
const transformed = richText.transformPresence(range, op, true);
expect(transformed).to.eql({index: 13, length: 2});
});

it('does not advance the cursor if not own op', function () {
const range = {index: 10, length: 2};
const op = new Delta().retain(10).insert('foo');
const transformed = richText.transformPresence(range, op, false);
expect(transformed).to.eql({index: 10, length: 5});
});

it('accepts an array of ops rather than a Delta', function() {
const range = {index: 10, length: 0};
const op = [{insert: 'foo'}];
const transformed = richText.transformPresence(range, op);
expect(transformed).to.eql({index: 13, length: 0});
});

it('does nothing if no op is provided', function() {
const range = {index: 10, length: 0};
const transformed = richText.transformPresence(range, undefined);
expect(transformed).to.eql({index: 10, length: 0});
});

it('does not mutate the original range', function() {
const range = {index: 10, length: 0};
const op = new Delta().insert('foo');
richText.transformPresence(range, op);
expect(range).to.eql({index: 10, length: 0});
});
});

0 comments on commit ce14c8f

Please sign in to comment.