From b3ec7b79856128edc30867d48f586cc5abccbac6 Mon Sep 17 00:00:00 2001 From: Jason Morrison Date: Sat, 30 Mar 2019 00:03:17 -0700 Subject: [PATCH] Proof-of-concept of presence operators for the @teamwork/sharedb presence mechanics Provides the following presence functions on the rich-text type, copying them from the @teamwork/ot-rich-text implementation: - createPresence - transformPresence - comparePresence - isValidPresence --- lib/type.js | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/lib/type.js b/lib/type.js index b6e1a2b..b3d576b 100644 --- a/lib/type.js +++ b/lib/type.js @@ -1,5 +1,79 @@ var Delta = require('quill-delta'); +// Slightly modified from the base rich-text implementation +function transformCursor(cursor, delta, isOwnOp) { + // Rewrap in Quill Delta since we seem to get a raw ops object + delta = new Delta(delta); + return delta.transformPosition(cursor, !isOwnOp); +} + +// Copied from https://github.com/Teamwork/ot-rich-text/blob/master/src/Operation.js +function createPresence(presence) { + return isValidPresence(presence) ? presence : { + u: '', + c: 0, + s: [] + }; +} + +// Copied from https://github.com/Teamwork/ot-rich-text/blob/master/src/Operation.js +function transformPresence(presence, operation, isOwnOperation) { + var user = presence.u; + var change = presence.c; + var selections = presence.s; + var newSelections = new Array(selections.length); + + for (var i = 0, l = selections.length; i < l; ++i) { + var selection = selections[i]; + var newStart = transformCursor(selection[0], operation, isOwnOperation); + var newEnd = selection[0] === selection[1] ? newStart : transformCursor(selection[1], operation, isOwnOperation); + newSelections[i] = [newStart, newEnd]; + } + + return { + u: user, + c: change, + s: newSelections + }; +} + +// Copied from https://github.com/Teamwork/ot-rich-text/blob/master/src/Operation.js +function comparePresence(presence1, presence2) { + if (presence1 === presence2) { + return true; + } + + if (presence1 == null || presence2 == null || presence1.u !== presence2.u || presence1.c !== presence2.c || presence1.s.length !== presence2.s.length) { + return false; + } + + for (var i = 0, l = presence1.s.length; i < l; ++i) { + if (presence1.s[i][0] !== presence2.s[i][0] || presence1.s[i][1] !== presence2.s[i][1]) { + return false; + } + } + + return true; +} + +// Copied from https://github.com/Teamwork/ot-rich-text/blob/master/src/Operation.js +function isValidPresence(presence) { + if (presence == null || typeof presence.u !== 'string' || typeof presence.c !== 'number' || !isFinite(presence.c) || Math.floor(presence.c) !== presence.c || !Array.isArray(presence.s)) { + return false; + } + + var selections = presence.s; + + for (var i = 0, l = selections.length; i < l; ++i) { + var selection = selections[i]; + + if (!Array.isArray(selection) || selection.length !== 2 || selection[0] !== (selection[0] | 0) || selection[1] !== (selection[1] | 0)) { + return false; + } + } + + return true; +} module.exports = { Delta: Delta, @@ -36,9 +110,7 @@ module.exports = { return delta2.transform(delta1, side === 'left'); }, - transformCursor: function(cursor, delta, isOwnOp) { - return delta.transformPosition(cursor, !isOwnOp); - }, + transformCursor: transformCursor, normalize: function(delta) { return delta; // quill-delta is already canonical @@ -50,6 +122,11 @@ module.exports = { deserialize: function(ops) { return new Delta(ops); - } + }, + + createPresence: createPresence, + transformPresence: transformPresence, + comparePresence: comparePresence, + isValidPresence: isValidPresence, } };