@manuscripts/track-changes-plugin 0.4.2 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +0 -2
- package/dist/change-steps/diffChangeSteps.d.ts +1 -18
- package/dist/change-steps/matchInserted.d.ts +10 -0
- package/dist/changes/findChanges.d.ts +3 -3
- package/dist/commands.d.ts +1 -5
- package/dist/index.cjs +78 -102
- package/dist/index.js +78 -102
- package/dist/mutate/deleteText.d.ts +1 -0
- package/package.json +16 -13
package/dist/actions.d.ts
CHANGED
|
@@ -21,7 +21,6 @@ export declare enum TrackChangesAction {
|
|
|
21
21
|
setUserID = "track-changes-set-user-id",
|
|
22
22
|
setPluginStatus = "track-changes-set-track-status",
|
|
23
23
|
setChangeStatuses = "track-changes-set-change-statuses",
|
|
24
|
-
updateChanges = "track-changes-update-changes",
|
|
25
24
|
refreshChanges = "track-changes-refresh-changes",
|
|
26
25
|
applyAndRemoveChanges = "track-changes-apply-remove-changes"
|
|
27
26
|
}
|
|
@@ -33,7 +32,6 @@ export declare type TrackChangesActionParams = {
|
|
|
33
32
|
status: CHANGE_STATUS;
|
|
34
33
|
ids: string[];
|
|
35
34
|
};
|
|
36
|
-
[TrackChangesAction.updateChanges]: string[];
|
|
37
35
|
[TrackChangesAction.refreshChanges]: boolean;
|
|
38
36
|
[TrackChangesAction.applyAndRemoveChanges]: boolean;
|
|
39
37
|
};
|
|
@@ -1,19 +1,2 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* © 2021 Atypon Systems LLC
|
|
3
|
-
*
|
|
4
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
* you may not use this file except in compliance with the License.
|
|
6
|
-
* You may obtain a copy of the License at
|
|
7
|
-
*
|
|
8
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
*
|
|
10
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
* See the License for the specific language governing permissions and
|
|
14
|
-
* limitations under the License.
|
|
15
|
-
*/
|
|
16
|
-
import { Schema } from 'prosemirror-model';
|
|
17
|
-
import type { Transaction } from 'prosemirror-state';
|
|
18
1
|
import { ChangeStep, InsertSliceStep } from '../types/step';
|
|
19
|
-
export declare function diffChangeSteps(deleted: ChangeStep[], inserted: InsertSliceStep[]
|
|
2
|
+
export declare function diffChangeSteps(deleted: ChangeStep[], inserted: InsertSliceStep[]): ChangeStep[];
|
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
import { ExposedFragment } from '../types/pm';
|
|
2
2
|
import { ChangeStep } from '../types/step';
|
|
3
|
+
/**
|
|
4
|
+
* Matches deleted to inserted content and returns the first pos they differ and the updated
|
|
5
|
+
* ChangeStep list.
|
|
6
|
+
*
|
|
7
|
+
* Based on https://github.com/ProseMirror/prosemirror-model/blob/master/src/diff.ts
|
|
8
|
+
* @param matchedDeleted
|
|
9
|
+
* @param deleted
|
|
10
|
+
* @param inserted
|
|
11
|
+
* @returns
|
|
12
|
+
*/
|
|
3
13
|
export declare function matchInserted(matchedDeleted: number, deleted: ChangeStep[], inserted: ExposedFragment): [number, ChangeStep[]];
|
|
@@ -18,9 +18,9 @@ import { ChangeSet } from '../ChangeSet';
|
|
|
18
18
|
/**
|
|
19
19
|
* Finds all changes (basically text marks or node attributes) from document
|
|
20
20
|
*
|
|
21
|
-
* This could be possibly made more efficient by only iterating the sections of doc
|
|
22
|
-
*
|
|
23
|
-
*
|
|
21
|
+
* This could be possibly made more efficient by only iterating the sections of doc where changes have
|
|
22
|
+
* been applied. This could attempted with eg findDiffStart but it might be less robust than just using
|
|
23
|
+
* doc.descendants
|
|
24
24
|
* @param state
|
|
25
25
|
* @returns
|
|
26
26
|
*/
|
package/dist/commands.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { TrackChangesStatus } from './types/track';
|
|
|
25
25
|
* to the document.
|
|
26
26
|
* @param status
|
|
27
27
|
*/
|
|
28
|
-
export declare const setTrackingStatus: (status?: TrackChangesStatus
|
|
28
|
+
export declare const setTrackingStatus: (status?: TrackChangesStatus) => Command;
|
|
29
29
|
/**
|
|
30
30
|
* Appends a transaction to set change attributes/marks' statuses to any of: 'pending' 'accepted' 'rejected'.
|
|
31
31
|
* @param status
|
|
@@ -45,7 +45,3 @@ export declare const applyAndRemoveChanges: () => Command;
|
|
|
45
45
|
* Runs `findChanges` to iterate over the document to collect changes into a new ChangeSet.
|
|
46
46
|
*/
|
|
47
47
|
export declare const refreshChanges: () => Command;
|
|
48
|
-
/**
|
|
49
|
-
* Adds track attributes for a block node. For testing puroses
|
|
50
|
-
*/
|
|
51
|
-
export declare const setParagraphTestAttribute: (val?: string) => Command;
|
package/dist/index.cjs
CHANGED
|
@@ -17,7 +17,6 @@ var TrackChangesAction;
|
|
|
17
17
|
TrackChangesAction["setUserID"] = "track-changes-set-user-id";
|
|
18
18
|
TrackChangesAction["setPluginStatus"] = "track-changes-set-track-status";
|
|
19
19
|
TrackChangesAction["setChangeStatuses"] = "track-changes-set-change-statuses";
|
|
20
|
-
TrackChangesAction["updateChanges"] = "track-changes-update-changes";
|
|
21
20
|
TrackChangesAction["refreshChanges"] = "track-changes-refresh-changes";
|
|
22
21
|
TrackChangesAction["applyAndRemoveChanges"] = "track-changes-apply-remove-changes";
|
|
23
22
|
})(TrackChangesAction || (TrackChangesAction = {}));
|
|
@@ -373,7 +372,7 @@ function getTextNodeTrackedMarkData(node, schema) {
|
|
|
373
372
|
return marksTrackedData[0] || undefined;
|
|
374
373
|
}
|
|
375
374
|
function getBlockInlineTrackedData(node) {
|
|
376
|
-
|
|
375
|
+
const { dataTracked } = node.attrs;
|
|
377
376
|
if (dataTracked && !Array.isArray(dataTracked)) {
|
|
378
377
|
return [dataTracked];
|
|
379
378
|
}
|
|
@@ -635,9 +634,9 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prose
|
|
|
635
634
|
/**
|
|
636
635
|
* Finds all changes (basically text marks or node attributes) from document
|
|
637
636
|
*
|
|
638
|
-
* This could be possibly made more efficient by only iterating the sections of doc
|
|
639
|
-
*
|
|
640
|
-
*
|
|
637
|
+
* This could be possibly made more efficient by only iterating the sections of doc where changes have
|
|
638
|
+
* been applied. This could attempted with eg findDiffStart but it might be less robust than just using
|
|
639
|
+
* doc.descendants
|
|
641
640
|
* @param state
|
|
642
641
|
* @returns
|
|
643
642
|
*/
|
|
@@ -1021,7 +1020,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
1021
1020
|
// @TODO ATM 20.7.2022 there doesn't seem to be tests that capture this.
|
|
1022
1021
|
const wasWithinGap = gap &&
|
|
1023
1022
|
((!node.isText && pos >= gap.start) ||
|
|
1024
|
-
(node.isText && pos
|
|
1023
|
+
(node.isText && pos >= gap.start && nodeEnd <= gap.end));
|
|
1025
1024
|
// nodeEnd > offsetFrom -> delete touches this node
|
|
1026
1025
|
// eg (del 6 10) <p 5>|<t 6>cdf</t 9></p 10>| -> <p> nodeEnd 10 > from 6
|
|
1027
1026
|
if (nodeEnd > from && !wasWithinGap) {
|
|
@@ -1122,41 +1121,6 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
1122
1121
|
};
|
|
1123
1122
|
}
|
|
1124
1123
|
|
|
1125
|
-
/**
|
|
1126
|
-
* Merges tracked marks between text nodes at a position
|
|
1127
|
-
*
|
|
1128
|
-
* Will work for any nodes that use tracked_insert or tracked_delete marks which may not be preferrable
|
|
1129
|
-
* if used for block nodes (since we possibly want to show the individual changed nodes).
|
|
1130
|
-
* Merging is done based on the userID, operation type and status.
|
|
1131
|
-
* @param pos
|
|
1132
|
-
* @param doc
|
|
1133
|
-
* @param newTr
|
|
1134
|
-
* @param schema
|
|
1135
|
-
*/
|
|
1136
|
-
function mergeTrackedMarks(pos, doc, newTr, schema) {
|
|
1137
|
-
const resolved = doc.resolve(pos);
|
|
1138
|
-
const { nodeAfter, nodeBefore } = resolved;
|
|
1139
|
-
const leftMark = nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1140
|
-
const rightMark = nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1141
|
-
if (!nodeAfter || !nodeBefore || !leftMark || !rightMark || leftMark.type !== rightMark.type) {
|
|
1142
|
-
return;
|
|
1143
|
-
}
|
|
1144
|
-
const leftDataTracked = leftMark.attrs.dataTracked;
|
|
1145
|
-
const rightDataTracked = rightMark.attrs.dataTracked;
|
|
1146
|
-
if (!shouldMergeTrackedAttributes(leftDataTracked, rightDataTracked)) {
|
|
1147
|
-
return;
|
|
1148
|
-
}
|
|
1149
|
-
const isLeftOlder = (leftDataTracked.createdAt || 0) < (rightDataTracked.createdAt || 0);
|
|
1150
|
-
const ancestorAttrs = isLeftOlder ? leftDataTracked : rightDataTracked;
|
|
1151
|
-
const dataTracked = {
|
|
1152
|
-
...ancestorAttrs,
|
|
1153
|
-
updatedAt: Date.now(),
|
|
1154
|
-
};
|
|
1155
|
-
const fromStartOfMark = pos - nodeBefore.nodeSize;
|
|
1156
|
-
const toEndOfMark = pos + nodeAfter.nodeSize;
|
|
1157
|
-
newTr.addMark(fromStartOfMark, toEndOfMark, leftMark.type.create({ ...leftMark.attrs, dataTracked }));
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
1124
|
/*!
|
|
1161
1125
|
* © 2021 Atypon Systems LLC
|
|
1162
1126
|
*
|
|
@@ -1176,27 +1140,6 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1176
1140
|
log.info('###### ReplaceAroundStep ######');
|
|
1177
1141
|
// @ts-ignore
|
|
1178
1142
|
const { from, to, gapFrom, gapTo, insert, slice, structure, } = step;
|
|
1179
|
-
if (from === gapFrom && to === gapTo) {
|
|
1180
|
-
log.info('WRAPPED IN SOMETHING');
|
|
1181
|
-
}
|
|
1182
|
-
else if (!slice.size || slice.content.content.length === 2) {
|
|
1183
|
-
log.info('UNWRAPPED FROM SOMETHING');
|
|
1184
|
-
}
|
|
1185
|
-
else if (slice.size === 2 && gapFrom - from === 1 && to - gapTo === 1) {
|
|
1186
|
-
log.info('REPLACED WRAPPING');
|
|
1187
|
-
}
|
|
1188
|
-
else {
|
|
1189
|
-
log.info('????');
|
|
1190
|
-
}
|
|
1191
|
-
if (gapFrom - from > to - gapTo) {
|
|
1192
|
-
log.info('DELETED BEFORE GAP FROM');
|
|
1193
|
-
}
|
|
1194
|
-
else if (gapFrom - from < to - gapTo) {
|
|
1195
|
-
log.info('DELETED AFTER GAP TO');
|
|
1196
|
-
}
|
|
1197
|
-
else {
|
|
1198
|
-
log.info('EQUAL REPLACE BETWEEN GAPS');
|
|
1199
|
-
}
|
|
1200
1143
|
// Invert the transaction step to prevent it from actually deleting or inserting anything
|
|
1201
1144
|
const newStep = step.invert(oldState.doc);
|
|
1202
1145
|
const stepResult = newTr.maybeStep(newStep);
|
|
@@ -1209,7 +1152,7 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1209
1152
|
// First apply the deleted range and update the insert slice to not include content that was deleted,
|
|
1210
1153
|
// eg partial nodes in an open-ended slice
|
|
1211
1154
|
const { sliceWasSplit, newSliceContent, steps: deleteSteps, } = deleteAndMergeSplitNodes(from, to, { start: gapFrom, end: gapTo }, newTr.doc, newTr, oldState.schema, attrs, slice);
|
|
1212
|
-
|
|
1155
|
+
const steps = deleteSteps;
|
|
1213
1156
|
log.info('TR: new steps after applying delete', [...newTr.steps]);
|
|
1214
1157
|
log.info('DELETE STEPS: ', deleteSteps);
|
|
1215
1158
|
// We only want to insert when there something inside the gap (actually would this be always true?)
|
|
@@ -1234,11 +1177,6 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1234
1177
|
sliceWasSplit,
|
|
1235
1178
|
});
|
|
1236
1179
|
}
|
|
1237
|
-
else {
|
|
1238
|
-
// Incase only deletion was applied, check whether tracked marks around deleted content can be merged
|
|
1239
|
-
mergeTrackedMarks(gapFrom, newTr.doc, newTr, oldState.schema);
|
|
1240
|
-
mergeTrackedMarks(gapTo, newTr.doc, newTr, oldState.schema);
|
|
1241
|
-
}
|
|
1242
1180
|
return steps;
|
|
1243
1181
|
}
|
|
1244
1182
|
|
|
@@ -1277,7 +1215,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1277
1215
|
changeSteps.push(...deleteSteps);
|
|
1278
1216
|
log.info('TR: steps after applying delete', [...newTr.steps]);
|
|
1279
1217
|
log.info('DELETE STEPS: ', changeSteps);
|
|
1280
|
-
const adjustedInsertPos = toA;
|
|
1218
|
+
const adjustedInsertPos = toA;
|
|
1281
1219
|
if (newSliceContent.size > 0) {
|
|
1282
1220
|
log.info('newSliceContent', newSliceContent);
|
|
1283
1221
|
// Since deleteAndMergeSplitBlockNodes modified the slice to not to contain any merged nodes,
|
|
@@ -1294,7 +1232,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1294
1232
|
}
|
|
1295
1233
|
else {
|
|
1296
1234
|
// Incase only deletion was applied, check whether tracked marks around deleted content can be merged
|
|
1297
|
-
mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1235
|
+
// mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1298
1236
|
selectionPos = fromA;
|
|
1299
1237
|
}
|
|
1300
1238
|
});
|
|
@@ -1328,6 +1266,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1328
1266
|
* @param deleteAttrs
|
|
1329
1267
|
* @param from
|
|
1330
1268
|
* @param to
|
|
1269
|
+
* @returns position at the end of the possibly deleted text
|
|
1331
1270
|
*/
|
|
1332
1271
|
function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
1333
1272
|
const start = from ? Math.max(pos, from) : pos;
|
|
@@ -1361,6 +1300,41 @@ function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
|
1361
1300
|
}
|
|
1362
1301
|
}
|
|
1363
1302
|
|
|
1303
|
+
/**
|
|
1304
|
+
* Merges tracked marks between text nodes at a position
|
|
1305
|
+
*
|
|
1306
|
+
* Will work for any nodes that use tracked_insert or tracked_delete marks which may not be preferrable
|
|
1307
|
+
* if used for block nodes (since we possibly want to show the individual changed nodes).
|
|
1308
|
+
* Merging is done based on the userID, operation type and status.
|
|
1309
|
+
* @param pos
|
|
1310
|
+
* @param doc
|
|
1311
|
+
* @param newTr
|
|
1312
|
+
* @param schema
|
|
1313
|
+
*/
|
|
1314
|
+
function mergeTrackedMarks(pos, doc, newTr, schema) {
|
|
1315
|
+
const resolved = doc.resolve(pos);
|
|
1316
|
+
const { nodeAfter, nodeBefore } = resolved;
|
|
1317
|
+
const leftMark = nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1318
|
+
const rightMark = nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1319
|
+
if (!nodeAfter || !nodeBefore || !leftMark || !rightMark || leftMark.type !== rightMark.type) {
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const leftDataTracked = leftMark.attrs.dataTracked;
|
|
1323
|
+
const rightDataTracked = rightMark.attrs.dataTracked;
|
|
1324
|
+
if (!shouldMergeTrackedAttributes(leftDataTracked, rightDataTracked)) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
const isLeftOlder = (leftDataTracked.createdAt || 0) < (rightDataTracked.createdAt || 0);
|
|
1328
|
+
const ancestorAttrs = isLeftOlder ? leftDataTracked : rightDataTracked;
|
|
1329
|
+
const dataTracked = {
|
|
1330
|
+
...ancestorAttrs,
|
|
1331
|
+
updatedAt: Date.now(),
|
|
1332
|
+
};
|
|
1333
|
+
const fromStartOfMark = pos - nodeBefore.nodeSize;
|
|
1334
|
+
const toEndOfMark = pos + nodeAfter.nodeSize;
|
|
1335
|
+
newTr.addMark(fromStartOfMark, toEndOfMark, leftMark.type.create({ ...leftMark.attrs, dataTracked }));
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1364
1338
|
function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
1365
1339
|
const mapping = new prosemirrorTransform.Mapping();
|
|
1366
1340
|
const deleteAttrs = createNewDeleteAttrs(emptyAttrs);
|
|
@@ -1448,6 +1422,19 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
|
1448
1422
|
return [mapping, selectionPos];
|
|
1449
1423
|
}
|
|
1450
1424
|
|
|
1425
|
+
/**
|
|
1426
|
+
* Matches deleted-text recursively to inserted text
|
|
1427
|
+
*
|
|
1428
|
+
* This is needed as text containing various marks is split into multiple parts even though it's
|
|
1429
|
+
* continously deleted. Therefore, we need to find the next part if there is any and keep going until
|
|
1430
|
+
* we've reached the end of the deleted text or inserted content.
|
|
1431
|
+
* @param adjDeleted
|
|
1432
|
+
* @param insNode
|
|
1433
|
+
* @param offset
|
|
1434
|
+
* @param matchedDeleted
|
|
1435
|
+
* @param deleted
|
|
1436
|
+
* @returns
|
|
1437
|
+
*/
|
|
1451
1438
|
function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
1452
1439
|
const { pos, from, to, node: delNode } = adjDeleted;
|
|
1453
1440
|
let j = offset, d = from - pos, maxSteps = to - Math.max(pos, from);
|
|
@@ -1480,15 +1467,26 @@ function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
|
1480
1467
|
}
|
|
1481
1468
|
return [matchedDeleted, deleted];
|
|
1482
1469
|
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Matches deleted to inserted content and returns the first pos they differ and the updated
|
|
1472
|
+
* ChangeStep list.
|
|
1473
|
+
*
|
|
1474
|
+
* Based on https://github.com/ProseMirror/prosemirror-model/blob/master/src/diff.ts
|
|
1475
|
+
* @param matchedDeleted
|
|
1476
|
+
* @param deleted
|
|
1477
|
+
* @param inserted
|
|
1478
|
+
* @returns
|
|
1479
|
+
*/
|
|
1483
1480
|
function matchInserted(matchedDeleted, deleted, inserted) {
|
|
1484
1481
|
var _a;
|
|
1485
1482
|
let matched = [matchedDeleted, deleted];
|
|
1486
1483
|
for (let i = 0;; i += 1) {
|
|
1487
|
-
if (inserted.childCount === i)
|
|
1484
|
+
if (inserted.childCount === i) {
|
|
1488
1485
|
return matched;
|
|
1486
|
+
}
|
|
1489
1487
|
const insNode = inserted.child(i);
|
|
1490
1488
|
// @ts-ignore
|
|
1491
|
-
|
|
1489
|
+
const adjDeleted = matched[1].find((d) => (d.type === 'delete-text' && Math.max(d.pos, d.from) === matched[0]) ||
|
|
1492
1490
|
(d.type === 'delete-node' && d.pos === matched[0]));
|
|
1493
1491
|
if (insNode.type !== ((_a = adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
1494
1492
|
return matched;
|
|
@@ -1533,16 +1531,13 @@ function matchInserted(matchedDeleted, deleted, inserted) {
|
|
|
1533
1531
|
/**
|
|
1534
1532
|
* Cuts a fragment similar to Fragment.cut but also removes the parent node.
|
|
1535
1533
|
*
|
|
1536
|
-
* @TODO there is however, some silly calculation mistake so that I need to use matched - deleted + 1 > 0
|
|
1537
|
-
* inside it to check whether to actually cut a text node. The offset might be cascading, therefore it should
|
|
1538
|
-
* be fixed at some point.
|
|
1539
1534
|
* @param matched
|
|
1540
1535
|
* @param deleted
|
|
1541
1536
|
* @param content
|
|
1542
1537
|
* @returns
|
|
1543
1538
|
*/
|
|
1544
1539
|
function cutFragment(matched, deleted, content) {
|
|
1545
|
-
|
|
1540
|
+
const newContent = [];
|
|
1546
1541
|
for (let i = 0; matched <= deleted && i < content.childCount; i += 1) {
|
|
1547
1542
|
const child = content.child(i);
|
|
1548
1543
|
if (!child.isText && child.content.size > 0) {
|
|
@@ -1565,7 +1560,7 @@ function cutFragment(matched, deleted, content) {
|
|
|
1565
1560
|
}
|
|
1566
1561
|
return [matched, prosemirrorModel.Fragment.fromArray(newContent)];
|
|
1567
1562
|
}
|
|
1568
|
-
function diffChangeSteps(deleted, inserted
|
|
1563
|
+
function diffChangeSteps(deleted, inserted) {
|
|
1569
1564
|
const updated = [];
|
|
1570
1565
|
let updatedDeleted = [...deleted];
|
|
1571
1566
|
inserted.forEach((ins) => {
|
|
@@ -1670,7 +1665,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1670
1665
|
// deleted and merged really...
|
|
1671
1666
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1672
1667
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1673
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1668
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1674
1669
|
log.info('DIFFED STEPS: ', steps);
|
|
1675
1670
|
const [mapping, selectionPos] = processChangeSteps(steps, startPos || tr.selection.head, // Incase startPos is it's default value 0, use the old selection head
|
|
1676
1671
|
newTr, emptyAttrs, oldState.schema);
|
|
@@ -1688,7 +1683,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1688
1683
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1689
1684
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1690
1685
|
log.info('INSERT STEPS: ', inserted);
|
|
1691
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1686
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1692
1687
|
log.info('DIFFED STEPS: ', steps);
|
|
1693
1688
|
processChangeSteps(steps, tr.selection.from, newTr, emptyAttrs, oldState.schema);
|
|
1694
1689
|
}
|
|
@@ -1778,15 +1773,14 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1778
1773
|
return {
|
|
1779
1774
|
...pluginState,
|
|
1780
1775
|
status: setStatus,
|
|
1781
|
-
changeSet: findChanges(newState),
|
|
1776
|
+
changeSet: setStatus === exports.TrackChangesStatus.disabled ? new ChangeSet() : findChanges(newState),
|
|
1782
1777
|
};
|
|
1783
1778
|
}
|
|
1784
1779
|
else if (pluginState.status === exports.TrackChangesStatus.disabled) {
|
|
1785
1780
|
return { ...pluginState, changeSet: new ChangeSet() };
|
|
1786
1781
|
}
|
|
1787
1782
|
let { changeSet, ...rest } = pluginState;
|
|
1788
|
-
|
|
1789
|
-
if (updatedChangeIds || getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1783
|
+
if (getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1790
1784
|
changeSet = findChanges(newState);
|
|
1791
1785
|
}
|
|
1792
1786
|
return {
|
|
@@ -1830,7 +1824,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1830
1824
|
createdTr = updateChangeAttrs(createdTr, change, { ...change.dataTracked, status, reviewedByID: userID }, oldState.schema);
|
|
1831
1825
|
}
|
|
1832
1826
|
});
|
|
1833
|
-
setAction(createdTr, TrackChangesAction.updateChanges, ids);
|
|
1834
1827
|
}
|
|
1835
1828
|
else if (getAction(tr, TrackChangesAction.applyAndRemoveChanges)) {
|
|
1836
1829
|
const mapping = applyAcceptedRejectedChanges(createdTr, oldState.schema, changeSet.bothNodeChanges);
|
|
@@ -1909,24 +1902,8 @@ const applyAndRemoveChanges = () => (state, dispatch) => {
|
|
|
1909
1902
|
* Runs `findChanges` to iterate over the document to collect changes into a new ChangeSet.
|
|
1910
1903
|
*/
|
|
1911
1904
|
const refreshChanges = () => (state, dispatch) => {
|
|
1912
|
-
dispatch && dispatch(setAction(state.tr, TrackChangesAction.
|
|
1905
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.refreshChanges, true));
|
|
1913
1906
|
return true;
|
|
1914
|
-
};
|
|
1915
|
-
/**
|
|
1916
|
-
* Adds track attributes for a block node. For testing puroses
|
|
1917
|
-
*/
|
|
1918
|
-
const setParagraphTestAttribute = (val = 'changed') => (state, dispatch) => {
|
|
1919
|
-
var _a;
|
|
1920
|
-
const cursor = state.selection.head;
|
|
1921
|
-
const blockNodePos = state.doc.resolve(cursor).start(1) - 1;
|
|
1922
|
-
if (((_a = state.doc.resolve(blockNodePos).nodeAfter) === null || _a === void 0 ? void 0 : _a.type) === state.schema.nodes.paragraph &&
|
|
1923
|
-
dispatch) {
|
|
1924
|
-
dispatch(state.tr.setNodeMarkup(blockNodePos, undefined, {
|
|
1925
|
-
testAttribute: val,
|
|
1926
|
-
}));
|
|
1927
|
-
return true;
|
|
1928
|
-
}
|
|
1929
|
-
return false;
|
|
1930
1907
|
};
|
|
1931
1908
|
|
|
1932
1909
|
var commands = /*#__PURE__*/Object.freeze({
|
|
@@ -1935,8 +1912,7 @@ var commands = /*#__PURE__*/Object.freeze({
|
|
|
1935
1912
|
setChangeStatuses: setChangeStatuses,
|
|
1936
1913
|
setUserID: setUserID,
|
|
1937
1914
|
applyAndRemoveChanges: applyAndRemoveChanges,
|
|
1938
|
-
refreshChanges: refreshChanges
|
|
1939
|
-
setParagraphTestAttribute: setParagraphTestAttribute
|
|
1915
|
+
refreshChanges: refreshChanges
|
|
1940
1916
|
});
|
|
1941
1917
|
|
|
1942
1918
|
exports.ChangeSet = ChangeSet;
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,6 @@ var TrackChangesAction;
|
|
|
9
9
|
TrackChangesAction["setUserID"] = "track-changes-set-user-id";
|
|
10
10
|
TrackChangesAction["setPluginStatus"] = "track-changes-set-track-status";
|
|
11
11
|
TrackChangesAction["setChangeStatuses"] = "track-changes-set-change-statuses";
|
|
12
|
-
TrackChangesAction["updateChanges"] = "track-changes-update-changes";
|
|
13
12
|
TrackChangesAction["refreshChanges"] = "track-changes-refresh-changes";
|
|
14
13
|
TrackChangesAction["applyAndRemoveChanges"] = "track-changes-apply-remove-changes";
|
|
15
14
|
})(TrackChangesAction || (TrackChangesAction = {}));
|
|
@@ -365,7 +364,7 @@ function getTextNodeTrackedMarkData(node, schema) {
|
|
|
365
364
|
return marksTrackedData[0] || undefined;
|
|
366
365
|
}
|
|
367
366
|
function getBlockInlineTrackedData(node) {
|
|
368
|
-
|
|
367
|
+
const { dataTracked } = node.attrs;
|
|
369
368
|
if (dataTracked && !Array.isArray(dataTracked)) {
|
|
370
369
|
return [dataTracked];
|
|
371
370
|
}
|
|
@@ -627,9 +626,9 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mappi
|
|
|
627
626
|
/**
|
|
628
627
|
* Finds all changes (basically text marks or node attributes) from document
|
|
629
628
|
*
|
|
630
|
-
* This could be possibly made more efficient by only iterating the sections of doc
|
|
631
|
-
*
|
|
632
|
-
*
|
|
629
|
+
* This could be possibly made more efficient by only iterating the sections of doc where changes have
|
|
630
|
+
* been applied. This could attempted with eg findDiffStart but it might be less robust than just using
|
|
631
|
+
* doc.descendants
|
|
633
632
|
* @param state
|
|
634
633
|
* @returns
|
|
635
634
|
*/
|
|
@@ -1013,7 +1012,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
1013
1012
|
// @TODO ATM 20.7.2022 there doesn't seem to be tests that capture this.
|
|
1014
1013
|
const wasWithinGap = gap &&
|
|
1015
1014
|
((!node.isText && pos >= gap.start) ||
|
|
1016
|
-
(node.isText && pos
|
|
1015
|
+
(node.isText && pos >= gap.start && nodeEnd <= gap.end));
|
|
1017
1016
|
// nodeEnd > offsetFrom -> delete touches this node
|
|
1018
1017
|
// eg (del 6 10) <p 5>|<t 6>cdf</t 9></p 10>| -> <p> nodeEnd 10 > from 6
|
|
1019
1018
|
if (nodeEnd > from && !wasWithinGap) {
|
|
@@ -1114,41 +1113,6 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
1114
1113
|
};
|
|
1115
1114
|
}
|
|
1116
1115
|
|
|
1117
|
-
/**
|
|
1118
|
-
* Merges tracked marks between text nodes at a position
|
|
1119
|
-
*
|
|
1120
|
-
* Will work for any nodes that use tracked_insert or tracked_delete marks which may not be preferrable
|
|
1121
|
-
* if used for block nodes (since we possibly want to show the individual changed nodes).
|
|
1122
|
-
* Merging is done based on the userID, operation type and status.
|
|
1123
|
-
* @param pos
|
|
1124
|
-
* @param doc
|
|
1125
|
-
* @param newTr
|
|
1126
|
-
* @param schema
|
|
1127
|
-
*/
|
|
1128
|
-
function mergeTrackedMarks(pos, doc, newTr, schema) {
|
|
1129
|
-
const resolved = doc.resolve(pos);
|
|
1130
|
-
const { nodeAfter, nodeBefore } = resolved;
|
|
1131
|
-
const leftMark = nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1132
|
-
const rightMark = nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1133
|
-
if (!nodeAfter || !nodeBefore || !leftMark || !rightMark || leftMark.type !== rightMark.type) {
|
|
1134
|
-
return;
|
|
1135
|
-
}
|
|
1136
|
-
const leftDataTracked = leftMark.attrs.dataTracked;
|
|
1137
|
-
const rightDataTracked = rightMark.attrs.dataTracked;
|
|
1138
|
-
if (!shouldMergeTrackedAttributes(leftDataTracked, rightDataTracked)) {
|
|
1139
|
-
return;
|
|
1140
|
-
}
|
|
1141
|
-
const isLeftOlder = (leftDataTracked.createdAt || 0) < (rightDataTracked.createdAt || 0);
|
|
1142
|
-
const ancestorAttrs = isLeftOlder ? leftDataTracked : rightDataTracked;
|
|
1143
|
-
const dataTracked = {
|
|
1144
|
-
...ancestorAttrs,
|
|
1145
|
-
updatedAt: Date.now(),
|
|
1146
|
-
};
|
|
1147
|
-
const fromStartOfMark = pos - nodeBefore.nodeSize;
|
|
1148
|
-
const toEndOfMark = pos + nodeAfter.nodeSize;
|
|
1149
|
-
newTr.addMark(fromStartOfMark, toEndOfMark, leftMark.type.create({ ...leftMark.attrs, dataTracked }));
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
1116
|
/*!
|
|
1153
1117
|
* © 2021 Atypon Systems LLC
|
|
1154
1118
|
*
|
|
@@ -1168,27 +1132,6 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1168
1132
|
log.info('###### ReplaceAroundStep ######');
|
|
1169
1133
|
// @ts-ignore
|
|
1170
1134
|
const { from, to, gapFrom, gapTo, insert, slice, structure, } = step;
|
|
1171
|
-
if (from === gapFrom && to === gapTo) {
|
|
1172
|
-
log.info('WRAPPED IN SOMETHING');
|
|
1173
|
-
}
|
|
1174
|
-
else if (!slice.size || slice.content.content.length === 2) {
|
|
1175
|
-
log.info('UNWRAPPED FROM SOMETHING');
|
|
1176
|
-
}
|
|
1177
|
-
else if (slice.size === 2 && gapFrom - from === 1 && to - gapTo === 1) {
|
|
1178
|
-
log.info('REPLACED WRAPPING');
|
|
1179
|
-
}
|
|
1180
|
-
else {
|
|
1181
|
-
log.info('????');
|
|
1182
|
-
}
|
|
1183
|
-
if (gapFrom - from > to - gapTo) {
|
|
1184
|
-
log.info('DELETED BEFORE GAP FROM');
|
|
1185
|
-
}
|
|
1186
|
-
else if (gapFrom - from < to - gapTo) {
|
|
1187
|
-
log.info('DELETED AFTER GAP TO');
|
|
1188
|
-
}
|
|
1189
|
-
else {
|
|
1190
|
-
log.info('EQUAL REPLACE BETWEEN GAPS');
|
|
1191
|
-
}
|
|
1192
1135
|
// Invert the transaction step to prevent it from actually deleting or inserting anything
|
|
1193
1136
|
const newStep = step.invert(oldState.doc);
|
|
1194
1137
|
const stepResult = newTr.maybeStep(newStep);
|
|
@@ -1201,7 +1144,7 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1201
1144
|
// First apply the deleted range and update the insert slice to not include content that was deleted,
|
|
1202
1145
|
// eg partial nodes in an open-ended slice
|
|
1203
1146
|
const { sliceWasSplit, newSliceContent, steps: deleteSteps, } = deleteAndMergeSplitNodes(from, to, { start: gapFrom, end: gapTo }, newTr.doc, newTr, oldState.schema, attrs, slice);
|
|
1204
|
-
|
|
1147
|
+
const steps = deleteSteps;
|
|
1205
1148
|
log.info('TR: new steps after applying delete', [...newTr.steps]);
|
|
1206
1149
|
log.info('DELETE STEPS: ', deleteSteps);
|
|
1207
1150
|
// We only want to insert when there something inside the gap (actually would this be always true?)
|
|
@@ -1226,11 +1169,6 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1226
1169
|
sliceWasSplit,
|
|
1227
1170
|
});
|
|
1228
1171
|
}
|
|
1229
|
-
else {
|
|
1230
|
-
// Incase only deletion was applied, check whether tracked marks around deleted content can be merged
|
|
1231
|
-
mergeTrackedMarks(gapFrom, newTr.doc, newTr, oldState.schema);
|
|
1232
|
-
mergeTrackedMarks(gapTo, newTr.doc, newTr, oldState.schema);
|
|
1233
|
-
}
|
|
1234
1172
|
return steps;
|
|
1235
1173
|
}
|
|
1236
1174
|
|
|
@@ -1269,7 +1207,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1269
1207
|
changeSteps.push(...deleteSteps);
|
|
1270
1208
|
log.info('TR: steps after applying delete', [...newTr.steps]);
|
|
1271
1209
|
log.info('DELETE STEPS: ', changeSteps);
|
|
1272
|
-
const adjustedInsertPos = toA;
|
|
1210
|
+
const adjustedInsertPos = toA;
|
|
1273
1211
|
if (newSliceContent.size > 0) {
|
|
1274
1212
|
log.info('newSliceContent', newSliceContent);
|
|
1275
1213
|
// Since deleteAndMergeSplitBlockNodes modified the slice to not to contain any merged nodes,
|
|
@@ -1286,7 +1224,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1286
1224
|
}
|
|
1287
1225
|
else {
|
|
1288
1226
|
// Incase only deletion was applied, check whether tracked marks around deleted content can be merged
|
|
1289
|
-
mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1227
|
+
// mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1290
1228
|
selectionPos = fromA;
|
|
1291
1229
|
}
|
|
1292
1230
|
});
|
|
@@ -1320,6 +1258,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1320
1258
|
* @param deleteAttrs
|
|
1321
1259
|
* @param from
|
|
1322
1260
|
* @param to
|
|
1261
|
+
* @returns position at the end of the possibly deleted text
|
|
1323
1262
|
*/
|
|
1324
1263
|
function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
1325
1264
|
const start = from ? Math.max(pos, from) : pos;
|
|
@@ -1353,6 +1292,41 @@ function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
|
1353
1292
|
}
|
|
1354
1293
|
}
|
|
1355
1294
|
|
|
1295
|
+
/**
|
|
1296
|
+
* Merges tracked marks between text nodes at a position
|
|
1297
|
+
*
|
|
1298
|
+
* Will work for any nodes that use tracked_insert or tracked_delete marks which may not be preferrable
|
|
1299
|
+
* if used for block nodes (since we possibly want to show the individual changed nodes).
|
|
1300
|
+
* Merging is done based on the userID, operation type and status.
|
|
1301
|
+
* @param pos
|
|
1302
|
+
* @param doc
|
|
1303
|
+
* @param newTr
|
|
1304
|
+
* @param schema
|
|
1305
|
+
*/
|
|
1306
|
+
function mergeTrackedMarks(pos, doc, newTr, schema) {
|
|
1307
|
+
const resolved = doc.resolve(pos);
|
|
1308
|
+
const { nodeAfter, nodeBefore } = resolved;
|
|
1309
|
+
const leftMark = nodeBefore === null || nodeBefore === void 0 ? void 0 : nodeBefore.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1310
|
+
const rightMark = nodeAfter === null || nodeAfter === void 0 ? void 0 : nodeAfter.marks.filter((m) => m.type === schema.marks.tracked_insert || m.type === schema.marks.tracked_delete)[0];
|
|
1311
|
+
if (!nodeAfter || !nodeBefore || !leftMark || !rightMark || leftMark.type !== rightMark.type) {
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
const leftDataTracked = leftMark.attrs.dataTracked;
|
|
1315
|
+
const rightDataTracked = rightMark.attrs.dataTracked;
|
|
1316
|
+
if (!shouldMergeTrackedAttributes(leftDataTracked, rightDataTracked)) {
|
|
1317
|
+
return;
|
|
1318
|
+
}
|
|
1319
|
+
const isLeftOlder = (leftDataTracked.createdAt || 0) < (rightDataTracked.createdAt || 0);
|
|
1320
|
+
const ancestorAttrs = isLeftOlder ? leftDataTracked : rightDataTracked;
|
|
1321
|
+
const dataTracked = {
|
|
1322
|
+
...ancestorAttrs,
|
|
1323
|
+
updatedAt: Date.now(),
|
|
1324
|
+
};
|
|
1325
|
+
const fromStartOfMark = pos - nodeBefore.nodeSize;
|
|
1326
|
+
const toEndOfMark = pos + nodeAfter.nodeSize;
|
|
1327
|
+
newTr.addMark(fromStartOfMark, toEndOfMark, leftMark.type.create({ ...leftMark.attrs, dataTracked }));
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1356
1330
|
function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
1357
1331
|
const mapping = new Mapping();
|
|
1358
1332
|
const deleteAttrs = createNewDeleteAttrs(emptyAttrs);
|
|
@@ -1440,6 +1414,19 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
|
1440
1414
|
return [mapping, selectionPos];
|
|
1441
1415
|
}
|
|
1442
1416
|
|
|
1417
|
+
/**
|
|
1418
|
+
* Matches deleted-text recursively to inserted text
|
|
1419
|
+
*
|
|
1420
|
+
* This is needed as text containing various marks is split into multiple parts even though it's
|
|
1421
|
+
* continously deleted. Therefore, we need to find the next part if there is any and keep going until
|
|
1422
|
+
* we've reached the end of the deleted text or inserted content.
|
|
1423
|
+
* @param adjDeleted
|
|
1424
|
+
* @param insNode
|
|
1425
|
+
* @param offset
|
|
1426
|
+
* @param matchedDeleted
|
|
1427
|
+
* @param deleted
|
|
1428
|
+
* @returns
|
|
1429
|
+
*/
|
|
1443
1430
|
function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
1444
1431
|
const { pos, from, to, node: delNode } = adjDeleted;
|
|
1445
1432
|
let j = offset, d = from - pos, maxSteps = to - Math.max(pos, from);
|
|
@@ -1472,15 +1459,26 @@ function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
|
1472
1459
|
}
|
|
1473
1460
|
return [matchedDeleted, deleted];
|
|
1474
1461
|
}
|
|
1462
|
+
/**
|
|
1463
|
+
* Matches deleted to inserted content and returns the first pos they differ and the updated
|
|
1464
|
+
* ChangeStep list.
|
|
1465
|
+
*
|
|
1466
|
+
* Based on https://github.com/ProseMirror/prosemirror-model/blob/master/src/diff.ts
|
|
1467
|
+
* @param matchedDeleted
|
|
1468
|
+
* @param deleted
|
|
1469
|
+
* @param inserted
|
|
1470
|
+
* @returns
|
|
1471
|
+
*/
|
|
1475
1472
|
function matchInserted(matchedDeleted, deleted, inserted) {
|
|
1476
1473
|
var _a;
|
|
1477
1474
|
let matched = [matchedDeleted, deleted];
|
|
1478
1475
|
for (let i = 0;; i += 1) {
|
|
1479
|
-
if (inserted.childCount === i)
|
|
1476
|
+
if (inserted.childCount === i) {
|
|
1480
1477
|
return matched;
|
|
1478
|
+
}
|
|
1481
1479
|
const insNode = inserted.child(i);
|
|
1482
1480
|
// @ts-ignore
|
|
1483
|
-
|
|
1481
|
+
const adjDeleted = matched[1].find((d) => (d.type === 'delete-text' && Math.max(d.pos, d.from) === matched[0]) ||
|
|
1484
1482
|
(d.type === 'delete-node' && d.pos === matched[0]));
|
|
1485
1483
|
if (insNode.type !== ((_a = adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
1486
1484
|
return matched;
|
|
@@ -1525,16 +1523,13 @@ function matchInserted(matchedDeleted, deleted, inserted) {
|
|
|
1525
1523
|
/**
|
|
1526
1524
|
* Cuts a fragment similar to Fragment.cut but also removes the parent node.
|
|
1527
1525
|
*
|
|
1528
|
-
* @TODO there is however, some silly calculation mistake so that I need to use matched - deleted + 1 > 0
|
|
1529
|
-
* inside it to check whether to actually cut a text node. The offset might be cascading, therefore it should
|
|
1530
|
-
* be fixed at some point.
|
|
1531
1526
|
* @param matched
|
|
1532
1527
|
* @param deleted
|
|
1533
1528
|
* @param content
|
|
1534
1529
|
* @returns
|
|
1535
1530
|
*/
|
|
1536
1531
|
function cutFragment(matched, deleted, content) {
|
|
1537
|
-
|
|
1532
|
+
const newContent = [];
|
|
1538
1533
|
for (let i = 0; matched <= deleted && i < content.childCount; i += 1) {
|
|
1539
1534
|
const child = content.child(i);
|
|
1540
1535
|
if (!child.isText && child.content.size > 0) {
|
|
@@ -1557,7 +1552,7 @@ function cutFragment(matched, deleted, content) {
|
|
|
1557
1552
|
}
|
|
1558
1553
|
return [matched, Fragment.fromArray(newContent)];
|
|
1559
1554
|
}
|
|
1560
|
-
function diffChangeSteps(deleted, inserted
|
|
1555
|
+
function diffChangeSteps(deleted, inserted) {
|
|
1561
1556
|
const updated = [];
|
|
1562
1557
|
let updatedDeleted = [...deleted];
|
|
1563
1558
|
inserted.forEach((ins) => {
|
|
@@ -1662,7 +1657,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1662
1657
|
// deleted and merged really...
|
|
1663
1658
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1664
1659
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1665
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1660
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1666
1661
|
log.info('DIFFED STEPS: ', steps);
|
|
1667
1662
|
const [mapping, selectionPos] = processChangeSteps(steps, startPos || tr.selection.head, // Incase startPos is it's default value 0, use the old selection head
|
|
1668
1663
|
newTr, emptyAttrs, oldState.schema);
|
|
@@ -1680,7 +1675,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1680
1675
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1681
1676
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1682
1677
|
log.info('INSERT STEPS: ', inserted);
|
|
1683
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1678
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1684
1679
|
log.info('DIFFED STEPS: ', steps);
|
|
1685
1680
|
processChangeSteps(steps, tr.selection.from, newTr, emptyAttrs, oldState.schema);
|
|
1686
1681
|
}
|
|
@@ -1770,15 +1765,14 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1770
1765
|
return {
|
|
1771
1766
|
...pluginState,
|
|
1772
1767
|
status: setStatus,
|
|
1773
|
-
changeSet: findChanges(newState),
|
|
1768
|
+
changeSet: setStatus === TrackChangesStatus.disabled ? new ChangeSet() : findChanges(newState),
|
|
1774
1769
|
};
|
|
1775
1770
|
}
|
|
1776
1771
|
else if (pluginState.status === TrackChangesStatus.disabled) {
|
|
1777
1772
|
return { ...pluginState, changeSet: new ChangeSet() };
|
|
1778
1773
|
}
|
|
1779
1774
|
let { changeSet, ...rest } = pluginState;
|
|
1780
|
-
|
|
1781
|
-
if (updatedChangeIds || getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1775
|
+
if (getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1782
1776
|
changeSet = findChanges(newState);
|
|
1783
1777
|
}
|
|
1784
1778
|
return {
|
|
@@ -1822,7 +1816,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1822
1816
|
createdTr = updateChangeAttrs(createdTr, change, { ...change.dataTracked, status, reviewedByID: userID }, oldState.schema);
|
|
1823
1817
|
}
|
|
1824
1818
|
});
|
|
1825
|
-
setAction(createdTr, TrackChangesAction.updateChanges, ids);
|
|
1826
1819
|
}
|
|
1827
1820
|
else if (getAction(tr, TrackChangesAction.applyAndRemoveChanges)) {
|
|
1828
1821
|
const mapping = applyAcceptedRejectedChanges(createdTr, oldState.schema, changeSet.bothNodeChanges);
|
|
@@ -1901,24 +1894,8 @@ const applyAndRemoveChanges = () => (state, dispatch) => {
|
|
|
1901
1894
|
* Runs `findChanges` to iterate over the document to collect changes into a new ChangeSet.
|
|
1902
1895
|
*/
|
|
1903
1896
|
const refreshChanges = () => (state, dispatch) => {
|
|
1904
|
-
dispatch && dispatch(setAction(state.tr, TrackChangesAction.
|
|
1897
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.refreshChanges, true));
|
|
1905
1898
|
return true;
|
|
1906
|
-
};
|
|
1907
|
-
/**
|
|
1908
|
-
* Adds track attributes for a block node. For testing puroses
|
|
1909
|
-
*/
|
|
1910
|
-
const setParagraphTestAttribute = (val = 'changed') => (state, dispatch) => {
|
|
1911
|
-
var _a;
|
|
1912
|
-
const cursor = state.selection.head;
|
|
1913
|
-
const blockNodePos = state.doc.resolve(cursor).start(1) - 1;
|
|
1914
|
-
if (((_a = state.doc.resolve(blockNodePos).nodeAfter) === null || _a === void 0 ? void 0 : _a.type) === state.schema.nodes.paragraph &&
|
|
1915
|
-
dispatch) {
|
|
1916
|
-
dispatch(state.tr.setNodeMarkup(blockNodePos, undefined, {
|
|
1917
|
-
testAttribute: val,
|
|
1918
|
-
}));
|
|
1919
|
-
return true;
|
|
1920
|
-
}
|
|
1921
|
-
return false;
|
|
1922
1899
|
};
|
|
1923
1900
|
|
|
1924
1901
|
var commands = /*#__PURE__*/Object.freeze({
|
|
@@ -1927,8 +1904,7 @@ var commands = /*#__PURE__*/Object.freeze({
|
|
|
1927
1904
|
setChangeStatuses: setChangeStatuses,
|
|
1928
1905
|
setUserID: setUserID,
|
|
1929
1906
|
applyAndRemoveChanges: applyAndRemoveChanges,
|
|
1930
|
-
refreshChanges: refreshChanges
|
|
1931
|
-
setParagraphTestAttribute: setParagraphTestAttribute
|
|
1907
|
+
refreshChanges: refreshChanges
|
|
1932
1908
|
});
|
|
1933
1909
|
|
|
1934
1910
|
export { CHANGE_OPERATION, CHANGE_STATUS, ChangeSet, TrackChangesStatus, enableDebug, skipTracking, trackChangesPlugin, trackChangesPluginKey, commands as trackCommands };
|
|
@@ -28,5 +28,6 @@ import { NewDeleteAttrs } from '../types/track';
|
|
|
28
28
|
* @param deleteAttrs
|
|
29
29
|
* @param from
|
|
30
30
|
* @param to
|
|
31
|
+
* @returns position at the end of the possibly deleted text
|
|
31
32
|
*/
|
|
32
33
|
export declare function deleteTextIfInserted(node: PMNode, pos: number, newTr: Transaction, schema: Schema, deleteAttrs: NewDeleteAttrs, from?: number, to?: number): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manuscripts/track-changes-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"author": "Atypon Systems LLC",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/Atypon-OpenSource/manuscripts-quarterback/tree/main/quarterback-packages/track-changes-plugin",
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
"exports": {
|
|
12
12
|
"./package.json": "./package.json",
|
|
13
13
|
"./src/styles.css": "./src/styles.css",
|
|
14
|
-
".":
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
15
18
|
},
|
|
16
19
|
"files": [
|
|
17
20
|
"dist",
|
|
@@ -21,28 +24,28 @@
|
|
|
21
24
|
"access": "public"
|
|
22
25
|
},
|
|
23
26
|
"devDependencies": {
|
|
24
|
-
"@manuscripts/manuscript-transform": "^0.
|
|
25
|
-
"@rollup/plugin-commonjs": "^22.0.
|
|
27
|
+
"@manuscripts/manuscript-transform": "^0.54.0",
|
|
28
|
+
"@rollup/plugin-commonjs": "^22.0.2",
|
|
26
29
|
"@types/debug": "^4.1.7",
|
|
27
30
|
"@types/jest": "27.5.1",
|
|
28
|
-
"@types/node": "^
|
|
31
|
+
"@types/node": "^18.7.18",
|
|
29
32
|
"jest": "27.5.1",
|
|
30
33
|
"jest-environment-jsdom": "27.5.1",
|
|
31
|
-
"jsdom": "^
|
|
32
|
-
"prosemirror-commands": "^1.3.
|
|
34
|
+
"jsdom": "^20.0.0",
|
|
35
|
+
"prosemirror-commands": "^1.3.1",
|
|
33
36
|
"prosemirror-example-setup": "^1.2.1",
|
|
34
37
|
"prosemirror-history": "^1.3.0",
|
|
35
38
|
"prosemirror-keymap": "^1.2.0",
|
|
36
39
|
"prosemirror-model": "^1.18.1",
|
|
37
|
-
"prosemirror-schema-list": "^1.2.
|
|
40
|
+
"prosemirror-schema-list": "^1.2.2",
|
|
38
41
|
"prosemirror-state": "^1.4.1",
|
|
39
|
-
"prosemirror-transform": "^1.
|
|
40
|
-
"prosemirror-view": "^1.
|
|
41
|
-
"rollup": "^2.
|
|
42
|
-
"rollup-plugin-typescript2": "^0.
|
|
42
|
+
"prosemirror-transform": "^1.7.0",
|
|
43
|
+
"prosemirror-view": "^1.28.1",
|
|
44
|
+
"rollup": "^2.79.0",
|
|
45
|
+
"rollup-plugin-typescript2": "^0.34.0",
|
|
43
46
|
"ts-jest": "27.1.4",
|
|
44
47
|
"tslib": "^2.4.0",
|
|
45
|
-
"typescript": "^4.
|
|
48
|
+
"typescript": "^4.8.3"
|
|
46
49
|
},
|
|
47
50
|
"peerDependencies": {
|
|
48
51
|
"prosemirror-model": ">=1.14.0",
|