mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-23 00:46:16 -04:00
Fixed startup to "Running npm to get a list of installed plugins"
This commit is contained in:
parent
76a6f665a4
commit
aa6323e488
63 changed files with 1536 additions and 1767 deletions
|
@ -19,7 +19,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Changeset from '../../static/js/Changeset';
|
||||
import {builder, deserializeOps} from '../../static/js/Changeset';
|
||||
import ChatMessage from '../../static/js/ChatMessage';
|
||||
import {CustomError} from '../utils/customError';
|
||||
import {doesPadExist, getPad, isValidPadId, listAllPads} from './PadManager';
|
||||
|
@ -518,7 +518,7 @@ export const restoreRevision = async (padID, rev, authorId = '') => {
|
|||
let textIndex = 0;
|
||||
const newTextStart = 0;
|
||||
const newTextEnd = atext.text.length;
|
||||
for (const op of Changeset.deserializeOps(attribs)) {
|
||||
for (const op of deserializeOps(attribs)) {
|
||||
const nextIndex = textIndex + op.chars;
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
|
||||
func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
|
||||
|
@ -528,19 +528,19 @@ export const restoreRevision = async (padID, rev, authorId = '') => {
|
|||
};
|
||||
|
||||
// create a new changeset with a helper builder object
|
||||
const builder = Changeset.builder(oldText.length);
|
||||
const builder2 = builder(oldText.length);
|
||||
|
||||
// assemble each line into the builder
|
||||
eachAttribRun(atext.attribs, (start, end, attribs) => {
|
||||
builder.insert(atext.text.substring(start, end), attribs);
|
||||
builder2.insert(atext.text.substring(start, end), attribs);
|
||||
});
|
||||
|
||||
const lastNewlinePos = oldText.lastIndexOf('\n');
|
||||
if (lastNewlinePos < 0) {
|
||||
builder.remove(oldText.length - 1, 0);
|
||||
builder2.remove(oldText.length - 1, 0);
|
||||
} else {
|
||||
builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1);
|
||||
builder.remove(oldText.length - lastNewlinePos - 1, 0);
|
||||
builder2.remove(lastNewlinePos, oldText.match(/\n/g).length - 1);
|
||||
builder2.remove(oldText.length - lastNewlinePos - 1, 0);
|
||||
}
|
||||
|
||||
const changeset = builder.toString();
|
||||
|
|
|
@ -21,7 +21,16 @@
|
|||
|
||||
import AttributeMap from '../../static/js/AttributeMap';
|
||||
import {getPad} from '../db/PadManager';
|
||||
import {} from '../../static/js/Changeset';
|
||||
import {
|
||||
builder,
|
||||
checkRep, cloneAText, compose,
|
||||
deserializeOps,
|
||||
follow, inverse, makeAText,
|
||||
makeSplice,
|
||||
moveOpsToNewPool, mutateAttributionLines, mutateTextLines,
|
||||
oldLen, prepareForWire, splitAttributionLines, splitTextLines,
|
||||
unpack
|
||||
} from '../../static/js/Changeset';
|
||||
import ChatMessage from '../../static/js/ChatMessage';
|
||||
import {AttributePool} from '../../static/js/AttributePool';
|
||||
import AttributeManager from '../../static/js/AttributeManager';
|
||||
|
@ -62,6 +71,7 @@ import {ErrorCaused} from "../models/ErrorCaused";
|
|||
import {Pad} from "../db/Pad";
|
||||
import {SessionInfo} from "../models/SessionInfo";
|
||||
import {randomString} from "../utils/randomstring";
|
||||
import {identity} from "lodash";
|
||||
|
||||
const securityManager = require('../db/SecurityManager');
|
||||
|
||||
|
@ -610,10 +620,10 @@ const handleUserChanges = async (socket, message) => {
|
|||
const pad = await getPad(thisSession.padId, null, thisSession.author);
|
||||
|
||||
// Verify that the changeset has valid syntax and is in canonical form
|
||||
Changeset.checkRep(changeset);
|
||||
checkRep(changeset);
|
||||
|
||||
// Validate all added 'author' attribs to be the same value as the current user
|
||||
for (const op of Changeset.deserializeOps(Changeset.unpack(changeset).ops)) {
|
||||
for (const op of deserializeOps(unpack(changeset).ops)) {
|
||||
// + can add text with attribs
|
||||
// = can change or add attribs
|
||||
// - can have attribs, but they are discarded and don't show up in the attribs -
|
||||
|
@ -632,7 +642,7 @@ const handleUserChanges = async (socket, message) => {
|
|||
// ex. adoptChangesetAttribs
|
||||
|
||||
// Afaik, it copies the new attributes from the changeset, to the global Attribute Pool
|
||||
let rebasedChangeset = Changeset.moveOpsToNewPool(changeset, wireApool, pad.pool);
|
||||
let rebasedChangeset = moveOpsToNewPool(changeset, wireApool, pad.pool);
|
||||
|
||||
// ex. applyUserChanges
|
||||
let r = baseRev;
|
||||
|
@ -645,21 +655,21 @@ const handleUserChanges = async (socket, message) => {
|
|||
const {changeset: c, meta: {author: authorId}} = await pad.getRevision(r);
|
||||
if (changeset === c && thisSession.author === authorId) {
|
||||
// Assume this is a retransmission of an already applied changeset.
|
||||
rebasedChangeset = Changeset.identity(Changeset.unpack(changeset).oldLen);
|
||||
rebasedChangeset = identity(unpack(changeset).oldLen);
|
||||
}
|
||||
// At this point, both "c" (from the pad) and "changeset" (from the
|
||||
// client) are relative to revision r - 1. The follow function
|
||||
// rebases "changeset" so that it is relative to revision r
|
||||
// and can be applied after "c".
|
||||
rebasedChangeset = Changeset.follow(c, rebasedChangeset, false, pad.pool);
|
||||
rebasedChangeset = follow(c, rebasedChangeset, false, pad.pool);
|
||||
}
|
||||
|
||||
const prevText = pad.text();
|
||||
|
||||
if (Changeset.oldLen(rebasedChangeset) !== prevText.length) {
|
||||
if (oldLen(rebasedChangeset) !== prevText.length) {
|
||||
throw new Error(
|
||||
`Can't apply changeset ${rebasedChangeset} with oldLen ` +
|
||||
`${Changeset.oldLen(rebasedChangeset)} to document of length ${prevText.length}`);
|
||||
`${oldLen(rebasedChangeset)} to document of length ${prevText.length}`);
|
||||
}
|
||||
|
||||
const newRev = await pad.appendRevision(rebasedChangeset, thisSession.author);
|
||||
|
@ -674,7 +684,7 @@ const handleUserChanges = async (socket, message) => {
|
|||
|
||||
// Make sure the pad always ends with an empty line.
|
||||
if (pad.text().lastIndexOf('\n') !== pad.text().length - 1) {
|
||||
const nlChangeset = Changeset.makeSplice(pad.text(), pad.text().length - 1, 0, '\n');
|
||||
const nlChangeset = makeSplice(pad.text(), pad.text().length - 1, 0, '\n');
|
||||
await pad.appendRevision(nlChangeset, thisSession.author);
|
||||
}
|
||||
|
||||
|
@ -729,7 +739,7 @@ export const updatePadClients = async (pad) => {
|
|||
const revChangeset = revision.changeset;
|
||||
const currentTime = revision.meta.timestamp;
|
||||
|
||||
const forWire = Changeset.prepareForWire(revChangeset, pad.pool);
|
||||
const forWire = prepareForWire(revChangeset, pad.pool);
|
||||
const msg = {
|
||||
type: 'COLLABROOM',
|
||||
data: {
|
||||
|
@ -764,7 +774,7 @@ const _correctMarkersInPad = (atext, apool) => {
|
|||
// that aren't at the start of a line
|
||||
const badMarkers = [];
|
||||
let offset = 0;
|
||||
for (const op of Changeset.deserializeOps(atext.attribs)) {
|
||||
for (const op of deserializeOps(atext.attribs)) {
|
||||
const attribs = AttributeMap.fromString(op.attribs, apool);
|
||||
const hasMarker = AttributeManager.lineAttributes.some((a) => attribs.has(a));
|
||||
if (hasMarker) {
|
||||
|
@ -786,15 +796,15 @@ const _correctMarkersInPad = (atext, apool) => {
|
|||
// create changeset that removes these bad markers
|
||||
offset = 0;
|
||||
|
||||
const builder = Changeset.builder(text.length);
|
||||
const builder2 = builder(text.length);
|
||||
|
||||
badMarkers.forEach((pos) => {
|
||||
builder.keepText(text.substring(offset, pos));
|
||||
builder.remove(1);
|
||||
builder2.keepText(text.substring(offset, pos));
|
||||
builder2.remove(1);
|
||||
offset = pos + 1;
|
||||
});
|
||||
|
||||
return builder.toString();
|
||||
return builder2.toString();
|
||||
};
|
||||
|
||||
export let clientVars:any
|
||||
|
@ -918,7 +928,7 @@ const handleClientReady = async (socket, message) => {
|
|||
|
||||
// return pending changesets
|
||||
for (const r of revisionsNeeded) {
|
||||
const forWire = Changeset.prepareForWire(changesets[r].changeset, pad.pool);
|
||||
const forWire = prepareForWire(changesets[r].changeset, pad.pool);
|
||||
const wireMsg = {type: 'COLLABROOM',
|
||||
data: {type: 'CLIENT_RECONNECT',
|
||||
headRev: pad.getHeadRevisionNumber(),
|
||||
|
@ -943,8 +953,8 @@ const handleClientReady = async (socket, message) => {
|
|||
let apool;
|
||||
// prepare all values for the wire, there's a chance that this throws, if the pad is corrupted
|
||||
try {
|
||||
atext = Changeset.cloneAText(pad.atext);
|
||||
const attribsForWire = Changeset.prepareForWire(atext.attribs, pad.pool);
|
||||
atext = cloneAText(pad.atext);
|
||||
const attribsForWire = prepareForWire(atext.attribs, pad.pool);
|
||||
apool = attribsForWire.pool.toJsonable();
|
||||
atext.attribs = attribsForWire.translated;
|
||||
} catch (e) {
|
||||
|
@ -1175,13 +1185,13 @@ const getChangesetInfo = async (pad: Pad, startNum: number, endNum: number, gran
|
|||
if (compositeEnd > endNum || compositeEnd > headRevision + 1) break;
|
||||
|
||||
const forwards = composedChangesets[`${compositeStart}/${compositeEnd}`];
|
||||
const backwards = Changeset.inverse(forwards, lines.textlines, lines.alines, pad.apool());
|
||||
const backwards = inverse(forwards, lines.textlines, lines.alines, pad.apool());
|
||||
|
||||
Changeset.mutateAttributionLines(forwards, lines.alines, pad.apool());
|
||||
Changeset.mutateTextLines(forwards, lines.textlines);
|
||||
mutateAttributionLines(forwards, lines.alines, pad.apool());
|
||||
mutateTextLines(forwards, lines.textlines);
|
||||
|
||||
const forwards2 = Changeset.moveOpsToNewPool(forwards, pad.apool(), apool);
|
||||
const backwards2 = Changeset.moveOpsToNewPool(backwards, pad.apool(), apool);
|
||||
const forwards2 = moveOpsToNewPool(forwards, pad.apool(), apool);
|
||||
const backwards2 = moveOpsToNewPool(backwards, pad.apool(), apool);
|
||||
|
||||
const t1 = (compositeStart === 0) ? revisionDate[0] : revisionDate[compositeStart - 1];
|
||||
const t2 = revisionDate[compositeEnd - 1];
|
||||
|
@ -1209,12 +1219,12 @@ const getPadLines = async (pad, revNum) => {
|
|||
if (revNum >= 0) {
|
||||
atext = await pad.getInternalRevisionAText(revNum);
|
||||
} else {
|
||||
atext = Changeset.makeAText('\n');
|
||||
atext = makeAText('\n');
|
||||
}
|
||||
|
||||
return {
|
||||
textlines: Changeset.splitTextLines(atext.text),
|
||||
alines: Changeset.splitAttributionLines(atext.attribs, atext.text),
|
||||
textlines: splitTextLines(atext.text),
|
||||
alines: splitAttributionLines(atext.attribs, atext.text),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -1249,7 +1259,7 @@ const composePadChangesets = async (pad, startNum, endNum) => {
|
|||
|
||||
for (r = startNum + 1; r < endNum; r++) {
|
||||
const cs = changesets[r];
|
||||
changeset = Changeset.compose(changeset, cs, pool);
|
||||
changeset = compose(changeset, cs, pool);
|
||||
}
|
||||
return changeset;
|
||||
} catch (e) {
|
||||
|
|
|
@ -50,7 +50,7 @@ const getAllLocales = () => {
|
|||
|
||||
// Build a locale index (merge all locale data other than user-supplied overrides)
|
||||
const locales = {};
|
||||
_.each(locales2paths, (files, langcode) => {
|
||||
_.each(locales2paths, (files:[], langcode) => {
|
||||
locales[langcode] = {};
|
||||
|
||||
files.forEach((file) => {
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
*/
|
||||
|
||||
import AttributeMap from '../../static/js/AttributeMap';
|
||||
import Changeset from '../../static/js/Changeset';
|
||||
import {deserializeOps, splitAttributionLines, subattribution} from '../../static/js/Changeset';
|
||||
|
||||
export const getPadPlainText = (pad, revNum) => {
|
||||
const atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) : pad.atext);
|
||||
const textLines = atext.text.slice(0, -1).split('\n');
|
||||
const attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
|
||||
const attribLines = splitAttributionLines(atext.attribs, atext.text);
|
||||
const apool = pad.pool;
|
||||
|
||||
const pieces = [];
|
||||
|
@ -57,7 +57,7 @@ export const _analyzeLine = (text, aline, apool) => {
|
|||
let lineMarker = 0;
|
||||
line.listLevel = 0;
|
||||
if (aline) {
|
||||
const [op] = Changeset.deserializeOps(aline);
|
||||
const [op] = deserializeOps(aline);
|
||||
if (op != null) {
|
||||
const attribs = AttributeMap.fromString(op.attribs, apool);
|
||||
let listType = attribs.get('list');
|
||||
|
@ -77,7 +77,7 @@ export const _analyzeLine = (text, aline, apool) => {
|
|||
}
|
||||
if (lineMarker) {
|
||||
line.text = text.substring(1);
|
||||
line.aline = Changeset.subattribution(aline, 1);
|
||||
line.aline = subattribution(aline, 1);
|
||||
} else {
|
||||
line.text = text;
|
||||
line.aline = aline;
|
||||
|
|
|
@ -15,14 +15,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Changeset from '../../static/js/Changeset';
|
||||
import attributes from "../../static/js/attributes";
|
||||
import {
|
||||
deserializeOps,
|
||||
splitAttributionLines,
|
||||
stringAssembler,
|
||||
stringIterator,
|
||||
subattribution
|
||||
} from '../../static/js/Changeset';
|
||||
import {decodeAttribString} from "../../static/js/attributes";
|
||||
|
||||
import {getPad} from "../db/PadManager";
|
||||
|
||||
import _ from "underscore";
|
||||
|
||||
import Security from '../../static/js/security';
|
||||
// FIXME this is a hack to get around the fact that we don't have a good way
|
||||
// @ts-ignore
|
||||
import {escapeHTML,escapeHTMLAttribute} from '../../static/js/security';
|
||||
import {aCallAll} from '../../static/js/pluginfw/hooks';
|
||||
import {required} from '../eejs';
|
||||
import {_analyzeLine, _encodeWhitespace} from "./ExportHelper";
|
||||
|
@ -44,7 +52,7 @@ const getPadHTML = async (pad, revNum) => {
|
|||
export const getHTMLFromAtext = async (pad, atext, authorColors?) => {
|
||||
const apool = pad.apool();
|
||||
const textLines = atext.text.slice(0, -1).split('\n');
|
||||
const attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
|
||||
const attribLines = splitAttributionLines(atext.attribs, atext.text);
|
||||
|
||||
const tags = ['h1', 'h2', 'strong', 'em', 'u', 's'];
|
||||
const props = ['heading1', 'heading2', 'bold', 'italic', 'underline', 'strikethrough'];
|
||||
|
@ -127,8 +135,8 @@ export const getHTMLFromAtext = async (pad, atext, authorColors?) => {
|
|||
// <b>Just bold<b> <b><i>Bold and italics</i></b> <i>Just italics</i>
|
||||
// becomes
|
||||
// <b>Just bold <i>Bold and italics</i></b> <i>Just italics</i>
|
||||
const taker = Changeset.stringIterator(text);
|
||||
const assem = Changeset.stringAssembler();
|
||||
const taker = stringIterator(text);
|
||||
const assem = stringAssembler();
|
||||
const openTags = [];
|
||||
|
||||
const getSpanClassFor = (i) => {
|
||||
|
@ -200,7 +208,7 @@ export const getHTMLFromAtext = async (pad, atext, authorColors?) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const ops = Changeset.deserializeOps(Changeset.subattribution(attribs, idx, idx + numChars));
|
||||
const ops = deserializeOps(subattribution(attribs, idx, idx + numChars));
|
||||
idx += numChars;
|
||||
|
||||
// this iterates over every op string and decides which tags to open or to close
|
||||
|
@ -209,7 +217,7 @@ export const getHTMLFromAtext = async (pad, atext, authorColors?) => {
|
|||
const usedAttribs = [];
|
||||
|
||||
// mark all attribs as used
|
||||
for (const a of attributes.decodeAttribString(o.attribs)) {
|
||||
for (const a of decodeAttribString(o.attribs)) {
|
||||
if (a in anumMap) {
|
||||
usedAttribs.push(anumMap[a]); // i = 0 => bold, etc.
|
||||
}
|
||||
|
@ -249,7 +257,7 @@ export const getHTMLFromAtext = async (pad, atext, authorColors?) => {
|
|||
// from but they break the abiword parser and are completly useless
|
||||
s = s.replace(String.fromCharCode(12), '');
|
||||
|
||||
assem.append(_encodeWhitespace(Security.escapeHTML(s)));
|
||||
assem.append(_encodeWhitespace(escapeHTML(s)));
|
||||
} // end iteration over spans in line
|
||||
|
||||
// close all the tags that are open after the last op
|
||||
|
@ -272,7 +280,7 @@ export const getHTMLFromAtext = async (pad, atext, authorColors?) => {
|
|||
// https://html.spec.whatwg.org/multipage/links.html#link-type-noopener
|
||||
// https://mathiasbynens.github.io/rel-noopener/
|
||||
// https://github.com/ether/etherpad-lite/pull/3636
|
||||
assem.append(`<a href="${Security.escapeHTMLAttribute(url)}" rel="noreferrer noopener">`);
|
||||
assem.append(`<a href="${escapeHTMLAttribute(url)}" rel="noreferrer noopener">`);
|
||||
processNextChars(urlLength);
|
||||
assem.append('</a>');
|
||||
});
|
||||
|
@ -477,7 +485,7 @@ export const getPadHTMLDocument = async (padId, revNum, readOnlyId?) => {
|
|||
|
||||
return required('ep_etherpad-lite/templates/export_html.html', {
|
||||
body: html,
|
||||
padId: Security.escapeHTML(readOnlyId || padId),
|
||||
padId: escapeHTML(readOnlyId || padId),
|
||||
extraCSS: stylesForExportCSS,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
*/
|
||||
|
||||
import log4js from 'log4js';
|
||||
import Changeset from '../../static/js/Changeset';
|
||||
import contentcollector from '../../static/js/contentcollector';
|
||||
import {builder, deserializeOps} from '../../static/js/Changeset';
|
||||
import {makeContentCollector} from '../../static/js/contentcollector';
|
||||
import jsdom from 'jsdom';
|
||||
|
||||
const apiLogger = log4js.getLogger('ImportHtml');
|
||||
|
@ -42,7 +42,7 @@ export const setPadHTML = async (pad, html, authorId = '') => {
|
|||
|
||||
// Convert a dom tree into a list of lines and attribute liens
|
||||
// using the content collector object
|
||||
const cc = contentcollector.makeContentCollector(true, null, pad.pool);
|
||||
const cc = makeContentCollector(true, null, pad.pool);
|
||||
try {
|
||||
// we use a try here because if the HTML is bad it will blow up
|
||||
cc.collectContent(document.body);
|
||||
|
@ -68,24 +68,24 @@ export const setPadHTML = async (pad, html, authorId = '') => {
|
|||
const newAttribs = `${result.lineAttribs.join('|1+1')}|1+1`;
|
||||
|
||||
// create a new changeset with a helper builder object
|
||||
const builder = Changeset.builder(1);
|
||||
const builder2 = builder(1);
|
||||
|
||||
// assemble each line into the builder
|
||||
let textIndex = 0;
|
||||
const newTextStart = 0;
|
||||
const newTextEnd = newText.length;
|
||||
for (const op of Changeset.deserializeOps(newAttribs)) {
|
||||
for (const op of deserializeOps(newAttribs)) {
|
||||
const nextIndex = textIndex + op.chars;
|
||||
if (!(nextIndex <= newTextStart || textIndex >= newTextEnd)) {
|
||||
const start = Math.max(newTextStart, textIndex);
|
||||
const end = Math.min(newTextEnd, nextIndex);
|
||||
builder.insert(newText.substring(start, end), op.attribs);
|
||||
builder2.insert(newText.substring(start, end), op.attribs);
|
||||
}
|
||||
textIndex = nextIndex;
|
||||
}
|
||||
|
||||
// the changeset is ready!
|
||||
const theChangeset = builder.toString();
|
||||
const theChangeset = builder2.toString();
|
||||
|
||||
apiLogger.debug(`The changeset: ${theChangeset}`);
|
||||
await pad.setText('\n', authorId);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
*/
|
||||
|
||||
import exp from "constants";
|
||||
|
||||
import packageJSON from '../../../package.json'
|
||||
import {findEtherpadRoot, makeAbsolute, isSubdir} from './AbsolutePaths';
|
||||
import deepEqual from 'fast-deep-equal/es6';
|
||||
import fs from 'fs';
|
||||
|
@ -507,7 +507,7 @@ export const getGitCommit = () => {
|
|||
};
|
||||
|
||||
// Return etherpad version from package.json
|
||||
export const getEpVersion = () => require('../../package.json').version;
|
||||
export const getEpVersion = () => packageJSON.version;
|
||||
|
||||
/**
|
||||
* Receives a settingsObj and, if the property name is a valid configuration
|
||||
|
|
|
@ -48,12 +48,11 @@ export const needsUpdate = (cb?:(arg0: boolean)=>void) => {
|
|||
}
|
||||
|
||||
const check = () => {
|
||||
const needsUpdate = ((needsUpdate: boolean) => {
|
||||
if (needsUpdate && infos) {
|
||||
console.warn(`Update available: Download the latest version ${infos.latestVersion}`);
|
||||
needsUpdate((needsUpdate)=>{
|
||||
if (needsUpdate) {
|
||||
console.warn(`Update available: Download the actual version ${infos.latestVersion}`);
|
||||
}
|
||||
})
|
||||
needsUpdate(infos.latestVersion > getEpVersion());
|
||||
}
|
||||
|
||||
export default {check, getLatestVersion}
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
'use strict';
|
||||
|
||||
import AttributeMap from '../../static/js/AttributeMap';
|
||||
import Changeset from '../../static/js/Changeset';
|
||||
import attributes from '../../static/js/attributes';
|
||||
import {
|
||||
applyToAText,
|
||||
builder, checkRep,
|
||||
compose,
|
||||
deserializeOps,
|
||||
numToString, Op,
|
||||
opAssembler, pack, splitAttributionLines, splitTextLines, stringAssembler,
|
||||
unpack
|
||||
} from '../../static/js/Changeset';
|
||||
import {attribsFromString} from '../../static/js/attributes';
|
||||
import {getHTMLFromAtext} from './ExportHtml';
|
||||
// @ts-ignore
|
||||
import {PadDiffModel} from "ep_etherpad-lite/node/models/PadDiffModel";
|
||||
|
||||
export const PadDiff = (pad, fromRev, toRev)=> {
|
||||
|
@ -30,7 +39,7 @@ export const PadDiff = (pad, fromRev, toRev)=> {
|
|||
|
||||
PadDiff.prototype._isClearAuthorship = function (changeset) {
|
||||
// unpack
|
||||
const unpacked = Changeset.unpack(changeset);
|
||||
const unpacked = unpack(changeset);
|
||||
|
||||
// check if there is nothing in the charBank
|
||||
if (unpacked.charBank !== '') {
|
||||
|
@ -42,7 +51,7 @@ PadDiff.prototype._isClearAuthorship = function (changeset) {
|
|||
return false;
|
||||
}
|
||||
|
||||
const [clearOperator, anotherOp] = Changeset.deserializeOps(unpacked.ops);
|
||||
const [clearOperator, anotherOp] = deserializeOps(unpacked.ops);
|
||||
|
||||
// check if there is only one operator
|
||||
if (anotherOp != null) return false;
|
||||
|
@ -59,7 +68,7 @@ PadDiff.prototype._isClearAuthorship = function (changeset) {
|
|||
}
|
||||
|
||||
const [appliedAttribute, anotherAttribute] =
|
||||
attributes.attribsFromString(clearOperator.attribs, this._pad.pool);
|
||||
attribsFromString(clearOperator.attribs, this._pad.pool);
|
||||
|
||||
// Check that the operation has exactly one attribute.
|
||||
if (appliedAttribute == null || anotherAttribute != null) return false;
|
||||
|
@ -76,9 +85,9 @@ PadDiff.prototype._createClearAuthorship = async function (rev) {
|
|||
const atext = await this._pad.getInternalRevisionAText(rev);
|
||||
|
||||
// build clearAuthorship changeset
|
||||
const builder = Changeset.builder(atext.text.length);
|
||||
builder.keepText(atext.text, [['author', '']], this._pad.pool);
|
||||
const changeset = builder.toString();
|
||||
const builder2 = builder(atext.text.length);
|
||||
builder2.keepText(atext.text, [['author', '']], this._pad.pool);
|
||||
const changeset = builder2.toString();
|
||||
|
||||
return changeset;
|
||||
};
|
||||
|
@ -91,7 +100,7 @@ PadDiff.prototype._createClearStartAtext = async function (rev) {
|
|||
const changeset = await this._createClearAuthorship(rev);
|
||||
|
||||
// apply the clearAuthorship changeset
|
||||
const newAText = Changeset.applyToAText(changeset, atext, this._pad.pool);
|
||||
const newAText = applyToAText(changeset, atext, this._pad.pool);
|
||||
|
||||
return newAText;
|
||||
};
|
||||
|
@ -160,7 +169,7 @@ PadDiff.prototype._createDiffAtext = async function () {
|
|||
if (superChangeset == null) {
|
||||
superChangeset = changeset;
|
||||
} else {
|
||||
superChangeset = Changeset.compose(superChangeset, changeset, this._pad.pool);
|
||||
superChangeset = compose(superChangeset, changeset, this._pad.pool);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,10 +183,10 @@ PadDiff.prototype._createDiffAtext = async function () {
|
|||
const deletionChangeset = this._createDeletionChangeset(superChangeset, atext, this._pad.pool);
|
||||
|
||||
// apply the superChangeset, which includes all addings
|
||||
atext = Changeset.applyToAText(superChangeset, atext, this._pad.pool);
|
||||
atext = applyToAText(superChangeset, atext, this._pad.pool);
|
||||
|
||||
// apply the deletionChangeset, which adds a deletions
|
||||
atext = Changeset.applyToAText(deletionChangeset, atext, this._pad.pool);
|
||||
atext = applyToAText(deletionChangeset, atext, this._pad.pool);
|
||||
}
|
||||
|
||||
return atext;
|
||||
|
@ -217,22 +226,22 @@ PadDiff.prototype.getAuthors = async function () {
|
|||
|
||||
PadDiff.prototype._extendChangesetWithAuthor = (changeset, author, apool) => {
|
||||
// unpack
|
||||
const unpacked = Changeset.unpack(changeset);
|
||||
const unpacked = unpack(changeset);
|
||||
|
||||
const assem = Changeset.opAssembler();
|
||||
const assem = opAssembler();
|
||||
|
||||
// create deleted attribs
|
||||
const authorAttrib = apool.putAttrib(['author', author || '']);
|
||||
const deletedAttrib = apool.putAttrib(['removed', true]);
|
||||
const attribs = `*${Changeset.numToString(authorAttrib)}*${Changeset.numToString(deletedAttrib)}`;
|
||||
const attribs = `*${numToString(authorAttrib)}*${numToString(deletedAttrib)}`;
|
||||
|
||||
for (const operator of Changeset.deserializeOps(unpacked.ops)) {
|
||||
for (const operator of deserializeOps(unpacked.ops)) {
|
||||
if (operator.opcode === '-') {
|
||||
// this is a delete operator, extend it with the author
|
||||
operator.attribs = attribs;
|
||||
} else if (operator.opcode === '=' && operator.attribs) {
|
||||
// this is operator changes only attributes, let's mark which author did that
|
||||
operator.attribs += `*${Changeset.numToString(authorAttrib)}`;
|
||||
operator.attribs += `*${numToString(authorAttrib)}`;
|
||||
}
|
||||
|
||||
// append the new operator to our assembler
|
||||
|
@ -240,14 +249,14 @@ PadDiff.prototype._extendChangesetWithAuthor = (changeset, author, apool) => {
|
|||
}
|
||||
|
||||
// return the modified changeset
|
||||
return Changeset.pack(unpacked.oldLen, unpacked.newLen, assem.toString(), unpacked.charBank);
|
||||
return pack(unpacked.oldLen, unpacked.newLen, assem.toString(), unpacked.charBank);
|
||||
};
|
||||
|
||||
// this method is 80% like Changeset.inverse. I just changed so instead of reverting,
|
||||
// it adds deletions and attribute changes to to the atext.
|
||||
PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
||||
const lines = Changeset.splitTextLines(startAText.text);
|
||||
const alines = Changeset.splitAttributionLines(startAText.attribs, startAText.text);
|
||||
const lines = splitTextLines(startAText.text);
|
||||
const alines = splitAttributionLines(startAText.attribs, startAText.text);
|
||||
|
||||
// lines and alines are what the exports is meant to apply to.
|
||||
// They may be arrays or objects with .get(i) and .length methods.
|
||||
|
@ -274,14 +283,14 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
|||
let curLineOps = null;
|
||||
let curLineOpsNext = null;
|
||||
let curLineOpsLine;
|
||||
let curLineNextOp = new Changeset.Op('+');
|
||||
let curLineNextOp = new Op('+');
|
||||
|
||||
const unpacked = Changeset.unpack(cs);
|
||||
const builder = Changeset.builder(unpacked.newLen);
|
||||
const unpacked = unpack(cs);
|
||||
const builder2 = builder(unpacked.newLen);
|
||||
|
||||
const consumeAttribRuns = (numChars, func /* (len, attribs, endsLine)*/) => {
|
||||
if (!curLineOps || curLineOpsLine !== curLine) {
|
||||
curLineOps = Changeset.deserializeOps(aLinesGet(curLine));
|
||||
curLineOps = deserializeOps(aLinesGet(curLine));
|
||||
curLineOpsNext = curLineOps.next();
|
||||
curLineOpsLine = curLine;
|
||||
let indexIntoLine = 0;
|
||||
|
@ -302,13 +311,13 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
|||
curChar = 0;
|
||||
curLineOpsLine = curLine;
|
||||
curLineNextOp.chars = 0;
|
||||
curLineOps = Changeset.deserializeOps(aLinesGet(curLine));
|
||||
curLineOps = deserializeOps(aLinesGet(curLine));
|
||||
curLineOpsNext = curLineOps.next();
|
||||
}
|
||||
|
||||
if (!curLineNextOp.chars) {
|
||||
if (curLineOpsNext.done) {
|
||||
curLineNextOp = new Changeset.Op();
|
||||
curLineNextOp = new Op();
|
||||
} else {
|
||||
curLineNextOp = curLineOpsNext.value;
|
||||
curLineOpsNext = curLineOps.next();
|
||||
|
@ -343,7 +352,7 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
|||
|
||||
const nextText = (numChars) => {
|
||||
let len = 0;
|
||||
const assem = Changeset.stringAssembler();
|
||||
const assem = stringAssembler();
|
||||
const firstString = linesGet(curLine).substring(curChar);
|
||||
len += firstString.length;
|
||||
assem.append(firstString);
|
||||
|
@ -371,7 +380,7 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
|||
};
|
||||
};
|
||||
|
||||
for (const csOp of Changeset.deserializeOps(unpacked.ops)) {
|
||||
for (const csOp of deserializeOps(unpacked.ops)) {
|
||||
if (csOp.opcode === '=') {
|
||||
const textBank = nextText(csOp.chars);
|
||||
|
||||
|
@ -417,7 +426,7 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
|||
textLeftToProcess = textLeftToProcess.substr(lengthToProcess);
|
||||
|
||||
if (lineBreak) {
|
||||
builder.keep(1, 1); // just skip linebreaks, don't do a insert + keep for a linebreak
|
||||
builder2.keep(1, 1); // just skip linebreaks, don't do a insert + keep for a linebreak
|
||||
|
||||
// consume the attributes of this linebreak
|
||||
consumeAttribRuns(1, () => {});
|
||||
|
@ -429,31 +438,31 @@ PadDiff.prototype._createDeletionChangeset = function (cs, startAText, apool) {
|
|||
// get the old attributes back
|
||||
const oldAttribs = undoBackToAttribs(attribs);
|
||||
|
||||
builder.insert(processText.substr(textBankIndex, len), oldAttribs);
|
||||
builder2.insert(processText.substr(textBankIndex, len), oldAttribs);
|
||||
textBankIndex += len;
|
||||
});
|
||||
|
||||
builder.keep(lengthToProcess, 0);
|
||||
builder2.keep(lengthToProcess, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
skip(csOp.chars, csOp.lines);
|
||||
builder.keep(csOp.chars, csOp.lines);
|
||||
builder2.keep(csOp.chars, csOp.lines);
|
||||
}
|
||||
} else if (csOp.opcode === '+') {
|
||||
builder.keep(csOp.chars, csOp.lines);
|
||||
builder2.keep(csOp.chars, csOp.lines);
|
||||
} else if (csOp.opcode === '-') {
|
||||
const textBank = nextText(csOp.chars);
|
||||
let textBankIndex = 0;
|
||||
|
||||
consumeAttribRuns(csOp.chars, (len, attribs, endsLine) => {
|
||||
builder.insert(textBank.substr(textBankIndex, len), attribs + csOp.attribs);
|
||||
builder2.insert(textBank.substr(textBankIndex, len), attribs + csOp.attribs);
|
||||
textBankIndex += len;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Changeset.checkRep(builder.toString());
|
||||
return checkRep(builder.toString());
|
||||
};
|
||||
|
||||
// export the constructor
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue