cryptpad/www/_socket/text-patcher.js

72 lines
2.2 KiB
JavaScript
Raw Normal View History

2016-03-25 10:04:27 +00:00
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++;
}
if (oldval.length !== commonStart + commonEnd) {
if (ctx.localChange) { ctx.localChange(true); }
ctx.remove(commonStart, oldval.length - commonStart - commonEnd);
}
if (newval.length !== commonStart + commonEnd) {
if (ctx.localChange) { ctx.localChange(true); }
ctx.insert(commonStart, newval.slice(commonStart, newval.length - commonEnd));
console.log("insert: " + newval.slice(commonStart, newval.length - commonEnd));
2016-03-25 10:04:27 +00:00
}
};
var create = function(config) {
2016-03-25 10:04:27 +00:00
var ctx = config.realtime;
// initial state will always fail the !== check in genop.
// because nothing will equal this object
var content = {};
// FIXME this is only necessary because we need to be able to update the
2016-03-25 11:45:51 +00:00
// textarea. This is being deprecated, however. Instead
2016-03-25 10:04:27 +00:00
var replaceText = function(newText) {
content = newText;
};
// *** remote -> local changes
2016-03-25 11:45:51 +00:00
ctx.onPatch(function(pos, length) {
2016-03-25 10:04:27 +00:00
replaceText(ctx.getUserDoc());
});
2016-03-25 11:45:51 +00:00
// propogate()
2016-03-25 10:04:27 +00:00
return function (newContent) {
if (newContent !== content) {
applyChange(ctx, ctx.getUserDoc(), newContent);
if (ctx.getUserDoc() !== newContent) {
console.log("Expected that: `ctx.getUserDoc() === newContent`!");
}
2016-03-25 11:45:51 +00:00
return true;
2016-03-25 10:04:27 +00:00
}
2016-03-25 11:45:51 +00:00
return false;
2016-03-25 10:04:27 +00:00
};
};
return { create: create };
2016-03-25 10:04:27 +00:00
});