cryptpad/customize.dist/delta-words.js

66 lines
2.0 KiB
JavaScript

// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
define([
'/components/chainpad/chainpad.dist.js',
], function (ChainPad) {
var Diff = ChainPad.Diff;
var isSpace = function (S, i) {
return /^\s$/.test(S.charAt(i));
};
var leadingBoundary = function (S, offset) {
if (/\s/.test(S.charAt(offset))) { return offset; }
while (offset > 0) {
offset--;
if (isSpace(S, offset)) { offset++; break; }
}
return offset;
};
var trailingBoundary = function (S, offset) {
if (isSpace(S, offset)) { return offset; }
while (offset < S.length && !/\s/.test(S.charAt(offset))) {
offset++;
}
return offset;
};
var opsToWords = function (previous, current) {
var output = [];
Diff.diff(previous, current).forEach(function (op) {
// ignore deleted sections...
var offset = op.offset;
var toInsert = op.toInsert;
// given an operation, check whether it is a word fragment,
// if it is, expand it to its word boundaries
var first = current.slice(leadingBoundary(current, offset), offset);
var last = current.slice(offset + toInsert.length, trailingBoundary(current, offset + toInsert.length));
var result = first + toInsert + last;
// concat-in-place
Array.prototype.push.apply(output, result.split(/\s+/));
});
return output.filter(Boolean);
};
var runningDiff = function (getter, f, time) {
var last = getter();
// first time through, send all the words :D
f(opsToWords("", last));
return setInterval(function () {
var current = getter();
// find inserted words...
var words = opsToWords(last, current);
last = current;
f(words);
}, time);
};
return runningDiff;
});