You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cryptpad/www/_socket/text-patcher.js

89 lines
2.6 KiB
JavaScript

define(function () {
/* applyChange takes:
ctx: the context (aka the realtime)
oldval: the old value
newval: the new value
it performs a diff on the two values, and generates patches
which are then passed into `ctx.remove` and `ctx.insert`
*/
var applyChange = function(ctx, oldval, newval) {
// Strings are immutable and have reference equality. I think this test is O(1), so its worth doing.
if (oldval === newval) {
return;
}
var commonStart = 0;
while (oldval.charAt(commonStart) === newval.charAt(commonStart)) {
commonStart++;
}
var commonEnd = 0;
while (oldval.charAt(oldval.length - 1 - commonEnd) === newval.charAt(newval.length - 1 - commonEnd) &&
commonEnd + commonStart < oldval.length && commonEnd + commonStart < newval.length) {
commonEnd++;
}
var result;
/* throw some assertions in here before dropping patches into the realtime
*/
if (oldval.length !== commonStart + commonEnd) {
if (ctx.localChange) { ctx.localChange(true); }
result = oldval.length - commonStart - commonEnd;
ctx.remove(commonStart, result);
console.log('removal at position: %s, length: %s', commonStart, result);
console.log("remove: [" + oldval.slice(commonStart, commonStart + result ) + ']');
}
if (newval.length !== commonStart + commonEnd) {
if (ctx.localChange) { ctx.localChange(true); }
result = newval.slice(commonStart, newval.length - commonEnd);
ctx.insert(commonStart, result);
console.log("insert: [" + result + "]");
}
var userDoc;
try {
var userDoc = ctx.getUserDoc();
JSON.parse(userDoc);
} catch (err) {
console.error('[textPatcherParseErr]');
console.error(err);
window.REALTIME_MODULE.textPatcher_parseError = {
error: err,
userDoc: userDoc
};
}
};
var create = function(config) {
var ctx = config.realtime;
// initial state will always fail the !== check in genop.
// because nothing will equal this object
var content = {};
// *** remote -> local changes
ctx.onPatch(function(pos, length) {
content = ctx.getUserDoc()
});
// propogate()
return function (newContent) {
if (newContent !== content) {
applyChange(ctx, ctx.getUserDoc(), newContent);
if (ctx.getUserDoc() !== newContent) {
console.log("Expected that: `ctx.getUserDoc() === newContent`!");
}
return true;
}
return false;
};
};
return { create: create };
});