@manuscripts/track-changes-plugin 0.4.2 → 0.4.3
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 -81
- package/dist/index.js +78 -81
- package/dist/mutate/deleteText.d.ts +1 -0
- package/package.json +12 -12
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
|
*
|
|
@@ -1209,7 +1173,7 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1209
1173
|
// First apply the deleted range and update the insert slice to not include content that was deleted,
|
|
1210
1174
|
// eg partial nodes in an open-ended slice
|
|
1211
1175
|
const { sliceWasSplit, newSliceContent, steps: deleteSteps, } = deleteAndMergeSplitNodes(from, to, { start: gapFrom, end: gapTo }, newTr.doc, newTr, oldState.schema, attrs, slice);
|
|
1212
|
-
|
|
1176
|
+
const steps = deleteSteps;
|
|
1213
1177
|
log.info('TR: new steps after applying delete', [...newTr.steps]);
|
|
1214
1178
|
log.info('DELETE STEPS: ', deleteSteps);
|
|
1215
1179
|
// We only want to insert when there something inside the gap (actually would this be always true?)
|
|
@@ -1234,11 +1198,6 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1234
1198
|
sliceWasSplit,
|
|
1235
1199
|
});
|
|
1236
1200
|
}
|
|
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
1201
|
return steps;
|
|
1243
1202
|
}
|
|
1244
1203
|
|
|
@@ -1277,7 +1236,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1277
1236
|
changeSteps.push(...deleteSteps);
|
|
1278
1237
|
log.info('TR: steps after applying delete', [...newTr.steps]);
|
|
1279
1238
|
log.info('DELETE STEPS: ', changeSteps);
|
|
1280
|
-
const adjustedInsertPos = toA;
|
|
1239
|
+
const adjustedInsertPos = toA;
|
|
1281
1240
|
if (newSliceContent.size > 0) {
|
|
1282
1241
|
log.info('newSliceContent', newSliceContent);
|
|
1283
1242
|
// Since deleteAndMergeSplitBlockNodes modified the slice to not to contain any merged nodes,
|
|
@@ -1294,7 +1253,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1294
1253
|
}
|
|
1295
1254
|
else {
|
|
1296
1255
|
// Incase only deletion was applied, check whether tracked marks around deleted content can be merged
|
|
1297
|
-
mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1256
|
+
// mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1298
1257
|
selectionPos = fromA;
|
|
1299
1258
|
}
|
|
1300
1259
|
});
|
|
@@ -1328,6 +1287,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1328
1287
|
* @param deleteAttrs
|
|
1329
1288
|
* @param from
|
|
1330
1289
|
* @param to
|
|
1290
|
+
* @returns position at the end of the possibly deleted text
|
|
1331
1291
|
*/
|
|
1332
1292
|
function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
1333
1293
|
const start = from ? Math.max(pos, from) : pos;
|
|
@@ -1361,6 +1321,41 @@ function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
|
1361
1321
|
}
|
|
1362
1322
|
}
|
|
1363
1323
|
|
|
1324
|
+
/**
|
|
1325
|
+
* Merges tracked marks between text nodes at a position
|
|
1326
|
+
*
|
|
1327
|
+
* Will work for any nodes that use tracked_insert or tracked_delete marks which may not be preferrable
|
|
1328
|
+
* if used for block nodes (since we possibly want to show the individual changed nodes).
|
|
1329
|
+
* Merging is done based on the userID, operation type and status.
|
|
1330
|
+
* @param pos
|
|
1331
|
+
* @param doc
|
|
1332
|
+
* @param newTr
|
|
1333
|
+
* @param schema
|
|
1334
|
+
*/
|
|
1335
|
+
function mergeTrackedMarks(pos, doc, newTr, schema) {
|
|
1336
|
+
const resolved = doc.resolve(pos);
|
|
1337
|
+
const { nodeAfter, nodeBefore } = resolved;
|
|
1338
|
+
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];
|
|
1339
|
+
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];
|
|
1340
|
+
if (!nodeAfter || !nodeBefore || !leftMark || !rightMark || leftMark.type !== rightMark.type) {
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
const leftDataTracked = leftMark.attrs.dataTracked;
|
|
1344
|
+
const rightDataTracked = rightMark.attrs.dataTracked;
|
|
1345
|
+
if (!shouldMergeTrackedAttributes(leftDataTracked, rightDataTracked)) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
const isLeftOlder = (leftDataTracked.createdAt || 0) < (rightDataTracked.createdAt || 0);
|
|
1349
|
+
const ancestorAttrs = isLeftOlder ? leftDataTracked : rightDataTracked;
|
|
1350
|
+
const dataTracked = {
|
|
1351
|
+
...ancestorAttrs,
|
|
1352
|
+
updatedAt: Date.now(),
|
|
1353
|
+
};
|
|
1354
|
+
const fromStartOfMark = pos - nodeBefore.nodeSize;
|
|
1355
|
+
const toEndOfMark = pos + nodeAfter.nodeSize;
|
|
1356
|
+
newTr.addMark(fromStartOfMark, toEndOfMark, leftMark.type.create({ ...leftMark.attrs, dataTracked }));
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1364
1359
|
function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
1365
1360
|
const mapping = new prosemirrorTransform.Mapping();
|
|
1366
1361
|
const deleteAttrs = createNewDeleteAttrs(emptyAttrs);
|
|
@@ -1448,6 +1443,19 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
|
1448
1443
|
return [mapping, selectionPos];
|
|
1449
1444
|
}
|
|
1450
1445
|
|
|
1446
|
+
/**
|
|
1447
|
+
* Matches deleted-text recursively to inserted text
|
|
1448
|
+
*
|
|
1449
|
+
* This is needed as text containing various marks is split into multiple parts even though it's
|
|
1450
|
+
* continously deleted. Therefore, we need to find the next part if there is any and keep going until
|
|
1451
|
+
* we've reached the end of the deleted text or inserted content.
|
|
1452
|
+
* @param adjDeleted
|
|
1453
|
+
* @param insNode
|
|
1454
|
+
* @param offset
|
|
1455
|
+
* @param matchedDeleted
|
|
1456
|
+
* @param deleted
|
|
1457
|
+
* @returns
|
|
1458
|
+
*/
|
|
1451
1459
|
function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
1452
1460
|
const { pos, from, to, node: delNode } = adjDeleted;
|
|
1453
1461
|
let j = offset, d = from - pos, maxSteps = to - Math.max(pos, from);
|
|
@@ -1480,15 +1488,26 @@ function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
|
1480
1488
|
}
|
|
1481
1489
|
return [matchedDeleted, deleted];
|
|
1482
1490
|
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Matches deleted to inserted content and returns the first pos they differ and the updated
|
|
1493
|
+
* ChangeStep list.
|
|
1494
|
+
*
|
|
1495
|
+
* Based on https://github.com/ProseMirror/prosemirror-model/blob/master/src/diff.ts
|
|
1496
|
+
* @param matchedDeleted
|
|
1497
|
+
* @param deleted
|
|
1498
|
+
* @param inserted
|
|
1499
|
+
* @returns
|
|
1500
|
+
*/
|
|
1483
1501
|
function matchInserted(matchedDeleted, deleted, inserted) {
|
|
1484
1502
|
var _a;
|
|
1485
1503
|
let matched = [matchedDeleted, deleted];
|
|
1486
1504
|
for (let i = 0;; i += 1) {
|
|
1487
|
-
if (inserted.childCount === i)
|
|
1505
|
+
if (inserted.childCount === i) {
|
|
1488
1506
|
return matched;
|
|
1507
|
+
}
|
|
1489
1508
|
const insNode = inserted.child(i);
|
|
1490
1509
|
// @ts-ignore
|
|
1491
|
-
|
|
1510
|
+
const adjDeleted = matched[1].find((d) => (d.type === 'delete-text' && Math.max(d.pos, d.from) === matched[0]) ||
|
|
1492
1511
|
(d.type === 'delete-node' && d.pos === matched[0]));
|
|
1493
1512
|
if (insNode.type !== ((_a = adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
1494
1513
|
return matched;
|
|
@@ -1533,16 +1552,13 @@ function matchInserted(matchedDeleted, deleted, inserted) {
|
|
|
1533
1552
|
/**
|
|
1534
1553
|
* Cuts a fragment similar to Fragment.cut but also removes the parent node.
|
|
1535
1554
|
*
|
|
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
1555
|
* @param matched
|
|
1540
1556
|
* @param deleted
|
|
1541
1557
|
* @param content
|
|
1542
1558
|
* @returns
|
|
1543
1559
|
*/
|
|
1544
1560
|
function cutFragment(matched, deleted, content) {
|
|
1545
|
-
|
|
1561
|
+
const newContent = [];
|
|
1546
1562
|
for (let i = 0; matched <= deleted && i < content.childCount; i += 1) {
|
|
1547
1563
|
const child = content.child(i);
|
|
1548
1564
|
if (!child.isText && child.content.size > 0) {
|
|
@@ -1565,7 +1581,7 @@ function cutFragment(matched, deleted, content) {
|
|
|
1565
1581
|
}
|
|
1566
1582
|
return [matched, prosemirrorModel.Fragment.fromArray(newContent)];
|
|
1567
1583
|
}
|
|
1568
|
-
function diffChangeSteps(deleted, inserted
|
|
1584
|
+
function diffChangeSteps(deleted, inserted) {
|
|
1569
1585
|
const updated = [];
|
|
1570
1586
|
let updatedDeleted = [...deleted];
|
|
1571
1587
|
inserted.forEach((ins) => {
|
|
@@ -1670,7 +1686,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1670
1686
|
// deleted and merged really...
|
|
1671
1687
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1672
1688
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1673
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1689
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1674
1690
|
log.info('DIFFED STEPS: ', steps);
|
|
1675
1691
|
const [mapping, selectionPos] = processChangeSteps(steps, startPos || tr.selection.head, // Incase startPos is it's default value 0, use the old selection head
|
|
1676
1692
|
newTr, emptyAttrs, oldState.schema);
|
|
@@ -1688,7 +1704,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1688
1704
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1689
1705
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1690
1706
|
log.info('INSERT STEPS: ', inserted);
|
|
1691
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1707
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1692
1708
|
log.info('DIFFED STEPS: ', steps);
|
|
1693
1709
|
processChangeSteps(steps, tr.selection.from, newTr, emptyAttrs, oldState.schema);
|
|
1694
1710
|
}
|
|
@@ -1778,15 +1794,14 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1778
1794
|
return {
|
|
1779
1795
|
...pluginState,
|
|
1780
1796
|
status: setStatus,
|
|
1781
|
-
changeSet: findChanges(newState),
|
|
1797
|
+
changeSet: setStatus === exports.TrackChangesStatus.disabled ? new ChangeSet() : findChanges(newState),
|
|
1782
1798
|
};
|
|
1783
1799
|
}
|
|
1784
1800
|
else if (pluginState.status === exports.TrackChangesStatus.disabled) {
|
|
1785
1801
|
return { ...pluginState, changeSet: new ChangeSet() };
|
|
1786
1802
|
}
|
|
1787
1803
|
let { changeSet, ...rest } = pluginState;
|
|
1788
|
-
|
|
1789
|
-
if (updatedChangeIds || getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1804
|
+
if (getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1790
1805
|
changeSet = findChanges(newState);
|
|
1791
1806
|
}
|
|
1792
1807
|
return {
|
|
@@ -1830,7 +1845,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1830
1845
|
createdTr = updateChangeAttrs(createdTr, change, { ...change.dataTracked, status, reviewedByID: userID }, oldState.schema);
|
|
1831
1846
|
}
|
|
1832
1847
|
});
|
|
1833
|
-
setAction(createdTr, TrackChangesAction.updateChanges, ids);
|
|
1834
1848
|
}
|
|
1835
1849
|
else if (getAction(tr, TrackChangesAction.applyAndRemoveChanges)) {
|
|
1836
1850
|
const mapping = applyAcceptedRejectedChanges(createdTr, oldState.schema, changeSet.bothNodeChanges);
|
|
@@ -1909,24 +1923,8 @@ const applyAndRemoveChanges = () => (state, dispatch) => {
|
|
|
1909
1923
|
* Runs `findChanges` to iterate over the document to collect changes into a new ChangeSet.
|
|
1910
1924
|
*/
|
|
1911
1925
|
const refreshChanges = () => (state, dispatch) => {
|
|
1912
|
-
dispatch && dispatch(setAction(state.tr, TrackChangesAction.
|
|
1926
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.refreshChanges, true));
|
|
1913
1927
|
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
1928
|
};
|
|
1931
1929
|
|
|
1932
1930
|
var commands = /*#__PURE__*/Object.freeze({
|
|
@@ -1935,8 +1933,7 @@ var commands = /*#__PURE__*/Object.freeze({
|
|
|
1935
1933
|
setChangeStatuses: setChangeStatuses,
|
|
1936
1934
|
setUserID: setUserID,
|
|
1937
1935
|
applyAndRemoveChanges: applyAndRemoveChanges,
|
|
1938
|
-
refreshChanges: refreshChanges
|
|
1939
|
-
setParagraphTestAttribute: setParagraphTestAttribute
|
|
1936
|
+
refreshChanges: refreshChanges
|
|
1940
1937
|
});
|
|
1941
1938
|
|
|
1942
1939
|
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
|
*
|
|
@@ -1201,7 +1165,7 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1201
1165
|
// First apply the deleted range and update the insert slice to not include content that was deleted,
|
|
1202
1166
|
// eg partial nodes in an open-ended slice
|
|
1203
1167
|
const { sliceWasSplit, newSliceContent, steps: deleteSteps, } = deleteAndMergeSplitNodes(from, to, { start: gapFrom, end: gapTo }, newTr.doc, newTr, oldState.schema, attrs, slice);
|
|
1204
|
-
|
|
1168
|
+
const steps = deleteSteps;
|
|
1205
1169
|
log.info('TR: new steps after applying delete', [...newTr.steps]);
|
|
1206
1170
|
log.info('DELETE STEPS: ', deleteSteps);
|
|
1207
1171
|
// We only want to insert when there something inside the gap (actually would this be always true?)
|
|
@@ -1226,11 +1190,6 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1226
1190
|
sliceWasSplit,
|
|
1227
1191
|
});
|
|
1228
1192
|
}
|
|
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
1193
|
return steps;
|
|
1235
1194
|
}
|
|
1236
1195
|
|
|
@@ -1269,7 +1228,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1269
1228
|
changeSteps.push(...deleteSteps);
|
|
1270
1229
|
log.info('TR: steps after applying delete', [...newTr.steps]);
|
|
1271
1230
|
log.info('DELETE STEPS: ', changeSteps);
|
|
1272
|
-
const adjustedInsertPos = toA;
|
|
1231
|
+
const adjustedInsertPos = toA;
|
|
1273
1232
|
if (newSliceContent.size > 0) {
|
|
1274
1233
|
log.info('newSliceContent', newSliceContent);
|
|
1275
1234
|
// Since deleteAndMergeSplitBlockNodes modified the slice to not to contain any merged nodes,
|
|
@@ -1286,7 +1245,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1286
1245
|
}
|
|
1287
1246
|
else {
|
|
1288
1247
|
// Incase only deletion was applied, check whether tracked marks around deleted content can be merged
|
|
1289
|
-
mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1248
|
+
// mergeTrackedMarks(adjustedInsertPos, newTr.doc, newTr, oldState.schema)
|
|
1290
1249
|
selectionPos = fromA;
|
|
1291
1250
|
}
|
|
1292
1251
|
});
|
|
@@ -1320,6 +1279,7 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1320
1279
|
* @param deleteAttrs
|
|
1321
1280
|
* @param from
|
|
1322
1281
|
* @param to
|
|
1282
|
+
* @returns position at the end of the possibly deleted text
|
|
1323
1283
|
*/
|
|
1324
1284
|
function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
1325
1285
|
const start = from ? Math.max(pos, from) : pos;
|
|
@@ -1353,6 +1313,41 @@ function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
|
1353
1313
|
}
|
|
1354
1314
|
}
|
|
1355
1315
|
|
|
1316
|
+
/**
|
|
1317
|
+
* Merges tracked marks between text nodes at a position
|
|
1318
|
+
*
|
|
1319
|
+
* Will work for any nodes that use tracked_insert or tracked_delete marks which may not be preferrable
|
|
1320
|
+
* if used for block nodes (since we possibly want to show the individual changed nodes).
|
|
1321
|
+
* Merging is done based on the userID, operation type and status.
|
|
1322
|
+
* @param pos
|
|
1323
|
+
* @param doc
|
|
1324
|
+
* @param newTr
|
|
1325
|
+
* @param schema
|
|
1326
|
+
*/
|
|
1327
|
+
function mergeTrackedMarks(pos, doc, newTr, schema) {
|
|
1328
|
+
const resolved = doc.resolve(pos);
|
|
1329
|
+
const { nodeAfter, nodeBefore } = resolved;
|
|
1330
|
+
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];
|
|
1331
|
+
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];
|
|
1332
|
+
if (!nodeAfter || !nodeBefore || !leftMark || !rightMark || leftMark.type !== rightMark.type) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
const leftDataTracked = leftMark.attrs.dataTracked;
|
|
1336
|
+
const rightDataTracked = rightMark.attrs.dataTracked;
|
|
1337
|
+
if (!shouldMergeTrackedAttributes(leftDataTracked, rightDataTracked)) {
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
const isLeftOlder = (leftDataTracked.createdAt || 0) < (rightDataTracked.createdAt || 0);
|
|
1341
|
+
const ancestorAttrs = isLeftOlder ? leftDataTracked : rightDataTracked;
|
|
1342
|
+
const dataTracked = {
|
|
1343
|
+
...ancestorAttrs,
|
|
1344
|
+
updatedAt: Date.now(),
|
|
1345
|
+
};
|
|
1346
|
+
const fromStartOfMark = pos - nodeBefore.nodeSize;
|
|
1347
|
+
const toEndOfMark = pos + nodeAfter.nodeSize;
|
|
1348
|
+
newTr.addMark(fromStartOfMark, toEndOfMark, leftMark.type.create({ ...leftMark.attrs, dataTracked }));
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1356
1351
|
function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
1357
1352
|
const mapping = new Mapping();
|
|
1358
1353
|
const deleteAttrs = createNewDeleteAttrs(emptyAttrs);
|
|
@@ -1440,6 +1435,19 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
|
|
|
1440
1435
|
return [mapping, selectionPos];
|
|
1441
1436
|
}
|
|
1442
1437
|
|
|
1438
|
+
/**
|
|
1439
|
+
* Matches deleted-text recursively to inserted text
|
|
1440
|
+
*
|
|
1441
|
+
* This is needed as text containing various marks is split into multiple parts even though it's
|
|
1442
|
+
* continously deleted. Therefore, we need to find the next part if there is any and keep going until
|
|
1443
|
+
* we've reached the end of the deleted text or inserted content.
|
|
1444
|
+
* @param adjDeleted
|
|
1445
|
+
* @param insNode
|
|
1446
|
+
* @param offset
|
|
1447
|
+
* @param matchedDeleted
|
|
1448
|
+
* @param deleted
|
|
1449
|
+
* @returns
|
|
1450
|
+
*/
|
|
1443
1451
|
function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
1444
1452
|
const { pos, from, to, node: delNode } = adjDeleted;
|
|
1445
1453
|
let j = offset, d = from - pos, maxSteps = to - Math.max(pos, from);
|
|
@@ -1472,15 +1480,26 @@ function matchText(adjDeleted, insNode, offset, matchedDeleted, deleted) {
|
|
|
1472
1480
|
}
|
|
1473
1481
|
return [matchedDeleted, deleted];
|
|
1474
1482
|
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Matches deleted to inserted content and returns the first pos they differ and the updated
|
|
1485
|
+
* ChangeStep list.
|
|
1486
|
+
*
|
|
1487
|
+
* Based on https://github.com/ProseMirror/prosemirror-model/blob/master/src/diff.ts
|
|
1488
|
+
* @param matchedDeleted
|
|
1489
|
+
* @param deleted
|
|
1490
|
+
* @param inserted
|
|
1491
|
+
* @returns
|
|
1492
|
+
*/
|
|
1475
1493
|
function matchInserted(matchedDeleted, deleted, inserted) {
|
|
1476
1494
|
var _a;
|
|
1477
1495
|
let matched = [matchedDeleted, deleted];
|
|
1478
1496
|
for (let i = 0;; i += 1) {
|
|
1479
|
-
if (inserted.childCount === i)
|
|
1497
|
+
if (inserted.childCount === i) {
|
|
1480
1498
|
return matched;
|
|
1499
|
+
}
|
|
1481
1500
|
const insNode = inserted.child(i);
|
|
1482
1501
|
// @ts-ignore
|
|
1483
|
-
|
|
1502
|
+
const adjDeleted = matched[1].find((d) => (d.type === 'delete-text' && Math.max(d.pos, d.from) === matched[0]) ||
|
|
1484
1503
|
(d.type === 'delete-node' && d.pos === matched[0]));
|
|
1485
1504
|
if (insNode.type !== ((_a = adjDeleted === null || adjDeleted === void 0 ? void 0 : adjDeleted.node) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
1486
1505
|
return matched;
|
|
@@ -1525,16 +1544,13 @@ function matchInserted(matchedDeleted, deleted, inserted) {
|
|
|
1525
1544
|
/**
|
|
1526
1545
|
* Cuts a fragment similar to Fragment.cut but also removes the parent node.
|
|
1527
1546
|
*
|
|
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
1547
|
* @param matched
|
|
1532
1548
|
* @param deleted
|
|
1533
1549
|
* @param content
|
|
1534
1550
|
* @returns
|
|
1535
1551
|
*/
|
|
1536
1552
|
function cutFragment(matched, deleted, content) {
|
|
1537
|
-
|
|
1553
|
+
const newContent = [];
|
|
1538
1554
|
for (let i = 0; matched <= deleted && i < content.childCount; i += 1) {
|
|
1539
1555
|
const child = content.child(i);
|
|
1540
1556
|
if (!child.isText && child.content.size > 0) {
|
|
@@ -1557,7 +1573,7 @@ function cutFragment(matched, deleted, content) {
|
|
|
1557
1573
|
}
|
|
1558
1574
|
return [matched, Fragment.fromArray(newContent)];
|
|
1559
1575
|
}
|
|
1560
|
-
function diffChangeSteps(deleted, inserted
|
|
1576
|
+
function diffChangeSteps(deleted, inserted) {
|
|
1561
1577
|
const updated = [];
|
|
1562
1578
|
let updatedDeleted = [...deleted];
|
|
1563
1579
|
inserted.forEach((ins) => {
|
|
@@ -1662,7 +1678,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1662
1678
|
// deleted and merged really...
|
|
1663
1679
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1664
1680
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1665
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1681
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1666
1682
|
log.info('DIFFED STEPS: ', steps);
|
|
1667
1683
|
const [mapping, selectionPos] = processChangeSteps(steps, startPos || tr.selection.head, // Incase startPos is it's default value 0, use the old selection head
|
|
1668
1684
|
newTr, emptyAttrs, oldState.schema);
|
|
@@ -1680,7 +1696,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
|
|
|
1680
1696
|
const deleted = steps.filter((s) => s.type !== 'insert-slice');
|
|
1681
1697
|
const inserted = steps.filter((s) => s.type === 'insert-slice');
|
|
1682
1698
|
log.info('INSERT STEPS: ', inserted);
|
|
1683
|
-
steps = diffChangeSteps(deleted, inserted
|
|
1699
|
+
steps = diffChangeSteps(deleted, inserted);
|
|
1684
1700
|
log.info('DIFFED STEPS: ', steps);
|
|
1685
1701
|
processChangeSteps(steps, tr.selection.from, newTr, emptyAttrs, oldState.schema);
|
|
1686
1702
|
}
|
|
@@ -1770,15 +1786,14 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1770
1786
|
return {
|
|
1771
1787
|
...pluginState,
|
|
1772
1788
|
status: setStatus,
|
|
1773
|
-
changeSet: findChanges(newState),
|
|
1789
|
+
changeSet: setStatus === TrackChangesStatus.disabled ? new ChangeSet() : findChanges(newState),
|
|
1774
1790
|
};
|
|
1775
1791
|
}
|
|
1776
1792
|
else if (pluginState.status === TrackChangesStatus.disabled) {
|
|
1777
1793
|
return { ...pluginState, changeSet: new ChangeSet() };
|
|
1778
1794
|
}
|
|
1779
1795
|
let { changeSet, ...rest } = pluginState;
|
|
1780
|
-
|
|
1781
|
-
if (updatedChangeIds || getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1796
|
+
if (getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1782
1797
|
changeSet = findChanges(newState);
|
|
1783
1798
|
}
|
|
1784
1799
|
return {
|
|
@@ -1822,7 +1837,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1822
1837
|
createdTr = updateChangeAttrs(createdTr, change, { ...change.dataTracked, status, reviewedByID: userID }, oldState.schema);
|
|
1823
1838
|
}
|
|
1824
1839
|
});
|
|
1825
|
-
setAction(createdTr, TrackChangesAction.updateChanges, ids);
|
|
1826
1840
|
}
|
|
1827
1841
|
else if (getAction(tr, TrackChangesAction.applyAndRemoveChanges)) {
|
|
1828
1842
|
const mapping = applyAcceptedRejectedChanges(createdTr, oldState.schema, changeSet.bothNodeChanges);
|
|
@@ -1901,24 +1915,8 @@ const applyAndRemoveChanges = () => (state, dispatch) => {
|
|
|
1901
1915
|
* Runs `findChanges` to iterate over the document to collect changes into a new ChangeSet.
|
|
1902
1916
|
*/
|
|
1903
1917
|
const refreshChanges = () => (state, dispatch) => {
|
|
1904
|
-
dispatch && dispatch(setAction(state.tr, TrackChangesAction.
|
|
1918
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.refreshChanges, true));
|
|
1905
1919
|
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
1920
|
};
|
|
1923
1921
|
|
|
1924
1922
|
var commands = /*#__PURE__*/Object.freeze({
|
|
@@ -1927,8 +1925,7 @@ var commands = /*#__PURE__*/Object.freeze({
|
|
|
1927
1925
|
setChangeStatuses: setChangeStatuses,
|
|
1928
1926
|
setUserID: setUserID,
|
|
1929
1927
|
applyAndRemoveChanges: applyAndRemoveChanges,
|
|
1930
|
-
refreshChanges: refreshChanges
|
|
1931
|
-
setParagraphTestAttribute: setParagraphTestAttribute
|
|
1928
|
+
refreshChanges: refreshChanges
|
|
1932
1929
|
});
|
|
1933
1930
|
|
|
1934
1931
|
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.3",
|
|
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",
|
|
@@ -21,28 +21,28 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@manuscripts/manuscript-transform": "^0.
|
|
25
|
-
"@rollup/plugin-commonjs": "^22.0.
|
|
24
|
+
"@manuscripts/manuscript-transform": "^0.54.0",
|
|
25
|
+
"@rollup/plugin-commonjs": "^22.0.2",
|
|
26
26
|
"@types/debug": "^4.1.7",
|
|
27
27
|
"@types/jest": "27.5.1",
|
|
28
|
-
"@types/node": "^
|
|
28
|
+
"@types/node": "^18.7.18",
|
|
29
29
|
"jest": "27.5.1",
|
|
30
30
|
"jest-environment-jsdom": "27.5.1",
|
|
31
|
-
"jsdom": "^
|
|
32
|
-
"prosemirror-commands": "^1.3.
|
|
31
|
+
"jsdom": "^20.0.0",
|
|
32
|
+
"prosemirror-commands": "^1.3.1",
|
|
33
33
|
"prosemirror-example-setup": "^1.2.1",
|
|
34
34
|
"prosemirror-history": "^1.3.0",
|
|
35
35
|
"prosemirror-keymap": "^1.2.0",
|
|
36
36
|
"prosemirror-model": "^1.18.1",
|
|
37
|
-
"prosemirror-schema-list": "^1.2.
|
|
37
|
+
"prosemirror-schema-list": "^1.2.2",
|
|
38
38
|
"prosemirror-state": "^1.4.1",
|
|
39
|
-
"prosemirror-transform": "^1.
|
|
40
|
-
"prosemirror-view": "^1.
|
|
41
|
-
"rollup": "^2.
|
|
42
|
-
"rollup-plugin-typescript2": "^0.
|
|
39
|
+
"prosemirror-transform": "^1.7.0",
|
|
40
|
+
"prosemirror-view": "^1.28.1",
|
|
41
|
+
"rollup": "^2.79.0",
|
|
42
|
+
"rollup-plugin-typescript2": "^0.34.0",
|
|
43
43
|
"ts-jest": "27.1.4",
|
|
44
44
|
"tslib": "^2.4.0",
|
|
45
|
-
"typescript": "^4.
|
|
45
|
+
"typescript": "^4.8.3"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"prosemirror-model": ">=1.14.0",
|