@manuscripts/track-changes-plugin 0.1.1 → 0.2.0
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/README.md +5 -3
- package/dist/actions.d.ts +1 -1
- package/dist/index.cjs +1562 -0
- package/dist/index.js +104 -117
- package/dist/track/mergeNode.d.ts +1 -1
- package/dist/track/node-utils.d.ts +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { PluginKey, Plugin } from 'prosemirror-state';
|
|
2
|
+
import debug from 'debug';
|
|
3
|
+
import { liftTarget, canJoin, Mapping, ReplaceStep, ReplaceAroundStep } from 'prosemirror-transform';
|
|
4
|
+
import { Fragment, Slice } from 'prosemirror-model';
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
var prosemirrorState = require('prosemirror-state');
|
|
6
|
-
var debug = require('debug');
|
|
7
|
-
var prosemirrorTransform = require('prosemirror-transform');
|
|
8
|
-
var prosemirrorModel = require('prosemirror-model');
|
|
9
|
-
|
|
10
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
11
|
-
|
|
12
|
-
var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug);
|
|
13
|
-
|
|
14
|
-
exports.TrackChangesAction = void 0;
|
|
6
|
+
var TrackChangesAction;
|
|
15
7
|
(function (TrackChangesAction) {
|
|
16
8
|
TrackChangesAction["skipTrack"] = "track-changes-skip-tracking";
|
|
17
9
|
TrackChangesAction["setUserID"] = "track-changes-set-user-id";
|
|
@@ -20,7 +12,7 @@ exports.TrackChangesAction = void 0;
|
|
|
20
12
|
TrackChangesAction["updateChanges"] = "track-changes-update-changes";
|
|
21
13
|
TrackChangesAction["refreshChanges"] = "track-changes-refresh-changes";
|
|
22
14
|
TrackChangesAction["applyAndRemoveChanges"] = "track-changes-apply-remove-changes";
|
|
23
|
-
})(
|
|
15
|
+
})(TrackChangesAction || (TrackChangesAction = {}));
|
|
24
16
|
/**
|
|
25
17
|
* Gets the value of a meta field, action payload, of a defined track-changes action.
|
|
26
18
|
* @param tr
|
|
@@ -83,7 +75,7 @@ function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
|
83
75
|
* See the License for the specific language governing permissions and
|
|
84
76
|
* limitations under the License.
|
|
85
77
|
*/
|
|
86
|
-
|
|
78
|
+
var CHANGE_OPERATION;
|
|
87
79
|
(function (CHANGE_OPERATION) {
|
|
88
80
|
CHANGE_OPERATION["insert"] = "insert";
|
|
89
81
|
CHANGE_OPERATION["delete"] = "delete";
|
|
@@ -92,13 +84,13 @@ exports.CHANGE_OPERATION = void 0;
|
|
|
92
84
|
CHANGE_OPERATION["unwrap_from_node"] = "unwrap_from_node";
|
|
93
85
|
CHANGE_OPERATION["add_mark"] = "add_mark";
|
|
94
86
|
CHANGE_OPERATION["remove_mark"] = "remove_mark";
|
|
95
|
-
})(
|
|
96
|
-
|
|
87
|
+
})(CHANGE_OPERATION || (CHANGE_OPERATION = {}));
|
|
88
|
+
var CHANGE_STATUS;
|
|
97
89
|
(function (CHANGE_STATUS) {
|
|
98
90
|
CHANGE_STATUS["accepted"] = "accepted";
|
|
99
91
|
CHANGE_STATUS["rejected"] = "rejected";
|
|
100
92
|
CHANGE_STATUS["pending"] = "pending";
|
|
101
|
-
})(
|
|
93
|
+
})(CHANGE_STATUS || (CHANGE_STATUS = {}));
|
|
102
94
|
|
|
103
95
|
/*!
|
|
104
96
|
* © 2021 Atypon Systems LLC
|
|
@@ -115,7 +107,7 @@ exports.CHANGE_STATUS = void 0;
|
|
|
115
107
|
* See the License for the specific language governing permissions and
|
|
116
108
|
* limitations under the License.
|
|
117
109
|
*/
|
|
118
|
-
const logger =
|
|
110
|
+
const logger = debug('track');
|
|
119
111
|
const log = {
|
|
120
112
|
info(str, obj) {
|
|
121
113
|
if (obj) {
|
|
@@ -148,10 +140,10 @@ const log = {
|
|
|
148
140
|
*/
|
|
149
141
|
const enableDebug = (enabled) => {
|
|
150
142
|
if (enabled) {
|
|
151
|
-
|
|
143
|
+
debug.enable('track');
|
|
152
144
|
}
|
|
153
145
|
else {
|
|
154
|
-
|
|
146
|
+
debug.disable();
|
|
155
147
|
}
|
|
156
148
|
};
|
|
157
149
|
|
|
@@ -211,13 +203,13 @@ class ChangeSet {
|
|
|
211
203
|
return rootNodes;
|
|
212
204
|
}
|
|
213
205
|
get pending() {
|
|
214
|
-
return this.changeTree.filter((c) => c.attrs.status ===
|
|
206
|
+
return this.changeTree.filter((c) => c.attrs.status === CHANGE_STATUS.pending);
|
|
215
207
|
}
|
|
216
208
|
get accepted() {
|
|
217
|
-
return this.changeTree.filter((c) => c.attrs.status ===
|
|
209
|
+
return this.changeTree.filter((c) => c.attrs.status === CHANGE_STATUS.accepted);
|
|
218
210
|
}
|
|
219
211
|
get rejected() {
|
|
220
|
-
return this.changeTree.filter((c) => c.attrs.status ===
|
|
212
|
+
return this.changeTree.filter((c) => c.attrs.status === CHANGE_STATUS.rejected);
|
|
221
213
|
}
|
|
222
214
|
get textChanges() {
|
|
223
215
|
return this.changes.filter((c) => c.type === 'text-change');
|
|
@@ -271,8 +263,8 @@ class ChangeSet {
|
|
|
271
263
|
*/
|
|
272
264
|
static shouldNotDelete(change) {
|
|
273
265
|
const { status, operation } = change.attrs;
|
|
274
|
-
return ((operation ===
|
|
275
|
-
(operation ===
|
|
266
|
+
return ((operation === CHANGE_OPERATION.insert && status === CHANGE_STATUS.accepted) ||
|
|
267
|
+
(operation === CHANGE_OPERATION.delete && status === CHANGE_STATUS.rejected));
|
|
276
268
|
}
|
|
277
269
|
/**
|
|
278
270
|
* Determines whether a change should be deleted when applying it to the document.
|
|
@@ -280,8 +272,8 @@ class ChangeSet {
|
|
|
280
272
|
*/
|
|
281
273
|
static shouldDeleteChange(change) {
|
|
282
274
|
const { status, operation } = change.attrs;
|
|
283
|
-
return ((operation ===
|
|
284
|
-
(operation ===
|
|
275
|
+
return ((operation === CHANGE_OPERATION.insert && status === CHANGE_STATUS.rejected) ||
|
|
276
|
+
(operation === CHANGE_OPERATION.delete && status === CHANGE_STATUS.accepted));
|
|
285
277
|
}
|
|
286
278
|
/**
|
|
287
279
|
* Checks whether change attributes contain all TrackedAttrs keys with non-undefined values
|
|
@@ -335,15 +327,17 @@ function deleteNode(node, pos, tr) {
|
|
|
335
327
|
var _a;
|
|
336
328
|
const startPos = tr.doc.resolve(pos + 1);
|
|
337
329
|
const range = startPos.blockRange(tr.doc.resolve(startPos.pos - 2 + node.nodeSize));
|
|
338
|
-
const targetDepth = range &&
|
|
330
|
+
const targetDepth = range && liftTarget(range);
|
|
339
331
|
// Check with typeof since with old prosemirror-transform targetDepth is undefined
|
|
340
332
|
if (range && typeof targetDepth === 'number') {
|
|
341
333
|
return tr.lift(range, targetDepth);
|
|
342
334
|
}
|
|
343
335
|
const resPos = tr.doc.resolve(pos);
|
|
344
|
-
|
|
336
|
+
// Block nodes can be deleted by just removing their start token which should then merge the text
|
|
337
|
+
// content to above node's content (if there is one)
|
|
338
|
+
const canMergeToNodeAbove = (resPos.parent !== tr.doc || resPos.nodeBefore) && node.isBlock && ((_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.isText);
|
|
345
339
|
if (canMergeToNodeAbove) {
|
|
346
|
-
return tr.replaceWith(pos - 1, pos + 1,
|
|
340
|
+
return tr.replaceWith(pos - 1, pos + 1, Fragment.empty);
|
|
347
341
|
}
|
|
348
342
|
else {
|
|
349
343
|
// NOTE: there's an edge case where moving content is not possible but because the immediate
|
|
@@ -376,17 +370,18 @@ function deleteNode(node, pos, tr) {
|
|
|
376
370
|
*/
|
|
377
371
|
function mergeNode(node, pos, tr) {
|
|
378
372
|
var _a;
|
|
379
|
-
if (
|
|
373
|
+
if (canJoin(tr.doc, pos)) {
|
|
380
374
|
return tr.join(pos);
|
|
381
375
|
}
|
|
382
|
-
else if (
|
|
376
|
+
else if (canJoin(tr.doc, pos + node.nodeSize)) {
|
|
377
|
+
// TODO should copy the attributes from the merged node below
|
|
383
378
|
return tr.join(pos + node.nodeSize);
|
|
384
379
|
}
|
|
385
|
-
// TODO is this the same thing as join?
|
|
380
|
+
// TODO is this the same thing as join to above?
|
|
386
381
|
const resPos = tr.doc.resolve(pos);
|
|
387
382
|
const canMergeToNodeAbove = (resPos.parent !== tr.doc || resPos.nodeBefore) && ((_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.isText);
|
|
388
383
|
if (canMergeToNodeAbove) {
|
|
389
|
-
return tr.replaceWith(pos - 1, pos + 1,
|
|
384
|
+
return tr.replaceWith(pos - 1, pos + 1, Fragment.empty);
|
|
390
385
|
}
|
|
391
386
|
return undefined;
|
|
392
387
|
}
|
|
@@ -430,8 +425,8 @@ function getInlineNodeTrackedMarkData(node, schema) {
|
|
|
430
425
|
node.marks.forEach((mark) => {
|
|
431
426
|
if (mark.type === schema.marks.tracked_insert || mark.type === schema.marks.tracked_delete) {
|
|
432
427
|
const operation = mark.type === schema.marks.tracked_insert
|
|
433
|
-
?
|
|
434
|
-
:
|
|
428
|
+
? CHANGE_OPERATION.insert
|
|
429
|
+
: CHANGE_OPERATION.delete;
|
|
435
430
|
marksTrackedData.push({ ...mark.attrs.dataTracked, operation });
|
|
436
431
|
}
|
|
437
432
|
});
|
|
@@ -505,9 +500,9 @@ function updateChangeChildrenAttributes(changes, tr, mapping) {
|
|
|
505
500
|
* @param changes
|
|
506
501
|
* @param deleteMap
|
|
507
502
|
*/
|
|
508
|
-
function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new
|
|
503
|
+
function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mapping()) {
|
|
509
504
|
changes.forEach((change) => {
|
|
510
|
-
if (change.attrs.status ===
|
|
505
|
+
if (change.attrs.status === CHANGE_STATUS.pending) {
|
|
511
506
|
return;
|
|
512
507
|
}
|
|
513
508
|
// Map change.from and skip those which dont need to be applied
|
|
@@ -629,8 +624,8 @@ function fixInconsistentChanges(changeSet, trackUserID, newTr, schema) {
|
|
|
629
624
|
const newAttrs = {
|
|
630
625
|
...((!id || iteratedIds.has(id) || id.length === 0) && { id: uuidv4() }),
|
|
631
626
|
...(!userID && { userID: trackUserID }),
|
|
632
|
-
...(!operation && { operation:
|
|
633
|
-
...(!status && { status:
|
|
627
|
+
...(!operation && { operation: CHANGE_OPERATION.insert }),
|
|
628
|
+
...(!status && { status: CHANGE_STATUS.pending }),
|
|
634
629
|
...(!createdAt && { createdAt: Date.now() }),
|
|
635
630
|
};
|
|
636
631
|
if (Object.keys(newAttrs).length > 0) {
|
|
@@ -659,7 +654,7 @@ function fixInconsistentChanges(changeSet, trackUserID, newTr, schema) {
|
|
|
659
654
|
*/
|
|
660
655
|
function markInlineNodeChange(node, newTrackAttrs, schema) {
|
|
661
656
|
const filtered = node.marks.filter((m) => m.type !== schema.marks.tracked_insert && m.type !== schema.marks.tracked_delete);
|
|
662
|
-
const mark = newTrackAttrs.operation ===
|
|
657
|
+
const mark = newTrackAttrs.operation === CHANGE_OPERATION.insert
|
|
663
658
|
? schema.marks.tracked_insert
|
|
664
659
|
: schema.marks.tracked_delete;
|
|
665
660
|
const createdMark = mark.create({
|
|
@@ -679,7 +674,7 @@ function recurseNodeContent(node, newTrackAttrs, schema) {
|
|
|
679
674
|
return node.type.create({
|
|
680
675
|
...node.attrs,
|
|
681
676
|
dataTracked: addTrackIdIfDoesntExist(newTrackAttrs),
|
|
682
|
-
},
|
|
677
|
+
}, Fragment.fromArray(updatedChildren), node.marks);
|
|
683
678
|
}
|
|
684
679
|
else {
|
|
685
680
|
log.error(`unhandled node type: "${node.type.name}"`, node);
|
|
@@ -692,7 +687,7 @@ function setFragmentAsInserted(inserted, insertAttrs, schema) {
|
|
|
692
687
|
inserted.forEach((n) => {
|
|
693
688
|
updatedInserted.push(recurseNodeContent(n, insertAttrs, schema));
|
|
694
689
|
});
|
|
695
|
-
return updatedInserted.length === 0 ? inserted :
|
|
690
|
+
return updatedInserted.length === 0 ? inserted : Fragment.fromArray(updatedInserted);
|
|
696
691
|
}
|
|
697
692
|
|
|
698
693
|
/*!
|
|
@@ -713,13 +708,13 @@ function setFragmentAsInserted(inserted, insertAttrs, schema) {
|
|
|
713
708
|
function createNewInsertAttrs(attrs) {
|
|
714
709
|
return {
|
|
715
710
|
...attrs,
|
|
716
|
-
operation:
|
|
711
|
+
operation: CHANGE_OPERATION.insert,
|
|
717
712
|
};
|
|
718
713
|
}
|
|
719
714
|
function createNewDeleteAttrs(attrs) {
|
|
720
715
|
return {
|
|
721
716
|
...attrs,
|
|
722
|
-
operation:
|
|
717
|
+
operation: CHANGE_OPERATION.delete,
|
|
723
718
|
};
|
|
724
719
|
}
|
|
725
720
|
|
|
@@ -762,7 +757,7 @@ function getMergedNode(node, currentDepth, depth, first) {
|
|
|
762
757
|
};
|
|
763
758
|
}
|
|
764
759
|
const result = [];
|
|
765
|
-
let merged =
|
|
760
|
+
let merged = Fragment.empty;
|
|
766
761
|
node.content.forEach((n, _, i) => {
|
|
767
762
|
if ((first && i === 0) || (!first && i === node.childCount - 1)) {
|
|
768
763
|
const { mergedNodeContent, unmergedContent } = getMergedNode(n, currentDepth + 1, depth, first);
|
|
@@ -777,7 +772,7 @@ function getMergedNode(node, currentDepth, depth, first) {
|
|
|
777
772
|
});
|
|
778
773
|
return {
|
|
779
774
|
mergedNodeContent: merged,
|
|
780
|
-
unmergedContent: result.length > 0 ?
|
|
775
|
+
unmergedContent: result.length > 0 ? Fragment.fromArray(result) : undefined,
|
|
781
776
|
};
|
|
782
777
|
}
|
|
783
778
|
/**
|
|
@@ -840,7 +835,7 @@ function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
|
840
835
|
// Math.max(pos, from) is for picking always the start of the node,
|
|
841
836
|
// not the start of the change (which might span multiple nodes).
|
|
842
837
|
// Pos can be less than from as nodesBetween iterates through all nodes starting from the top block node
|
|
843
|
-
newTr.replaceWith(start, end,
|
|
838
|
+
newTr.replaceWith(start, end, Fragment.empty);
|
|
844
839
|
return start;
|
|
845
840
|
}
|
|
846
841
|
else {
|
|
@@ -870,7 +865,7 @@ function deleteTextIfInserted(node, pos, newTr, schema, deleteAttrs, from, to) {
|
|
|
870
865
|
*/
|
|
871
866
|
function deleteOrSetNodeDeleted(node, pos, newTr, deleteAttrs) {
|
|
872
867
|
const dataTracked = node.attrs.dataTracked;
|
|
873
|
-
const wasInsertedBySameUser = (dataTracked === null || dataTracked === void 0 ? void 0 : dataTracked.operation) ===
|
|
868
|
+
const wasInsertedBySameUser = (dataTracked === null || dataTracked === void 0 ? void 0 : dataTracked.operation) === CHANGE_OPERATION.insert && dataTracked.userID === deleteAttrs.userID;
|
|
874
869
|
if (wasInsertedBySameUser) {
|
|
875
870
|
deleteNode(node, pos, newTr);
|
|
876
871
|
}
|
|
@@ -908,7 +903,7 @@ function deleteOrSetNodeDeleted(node, pos, newTr, deleteAttrs) {
|
|
|
908
903
|
* @returns mapping adjusted by the applied operations & modified insert slice
|
|
909
904
|
*/
|
|
910
905
|
function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackAttrs, insertSlice) {
|
|
911
|
-
const deleteMap = new
|
|
906
|
+
const deleteMap = new Mapping();
|
|
912
907
|
const mergedInsertPos = undefined;
|
|
913
908
|
// No deletion applied, return default values
|
|
914
909
|
if (from === to) {
|
|
@@ -926,10 +921,22 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
926
921
|
const { pos: offsetPos, deleted: nodeWasDeleted } = deleteMap.mapResult(pos, 1);
|
|
927
922
|
const offsetFrom = deleteMap.map(from, -1);
|
|
928
923
|
const offsetTo = deleteMap.map(to, 1);
|
|
929
|
-
const wasWithinGap = gap && offsetPos >= deleteMap.map(gap.start, -1);
|
|
930
924
|
const nodeEnd = offsetPos + node.nodeSize;
|
|
925
|
+
// So this insane boolean checks for ReplaceAroundStep gaps and whether the node should be skipped
|
|
926
|
+
// since the content inside gap should stay unchanged.
|
|
927
|
+
// All other nodes except text nodes consist of one start and end token (or just a single token for atoms).
|
|
928
|
+
// For them we can just check whether the start token is within the gap eg pos is 10 when gap (8, 18) to
|
|
929
|
+
// determine whether it should be skipped.
|
|
930
|
+
// For text nodes though, since they are continous, they might only partially be enclosed in the gap
|
|
931
|
+
// eg. pos 10 when gap is (8, 18) BUT if their nodeEnd goes past the gap's end eg nodeEnd 20 they actually
|
|
932
|
+
// are altered and should not be skipped.
|
|
933
|
+
// @TODO ATM 20.7.2022 there doesn't seem to be tests that capture this.
|
|
934
|
+
const wasWithinGap = gap &&
|
|
935
|
+
((!node.isText && offsetPos >= deleteMap.map(gap.start, -1)) ||
|
|
936
|
+
(node.isText &&
|
|
937
|
+
offsetPos <= deleteMap.map(gap.start, -1) &&
|
|
938
|
+
nodeEnd >= deleteMap.map(gap.end, -1)));
|
|
931
939
|
let step = newTr.steps[newTr.steps.length - 1];
|
|
932
|
-
// debugger
|
|
933
940
|
// nodeEnd > offsetFrom -> delete touches this node
|
|
934
941
|
// eg (del 6 10) <p 5>|<t 6>cdf</t 9></p 10>| -> <p> nodeEnd 10 > from 6
|
|
935
942
|
//
|
|
@@ -1031,7 +1038,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
1031
1038
|
deleteMap,
|
|
1032
1039
|
mergedInsertPos,
|
|
1033
1040
|
newSliceContent: updatedSliceNodes
|
|
1034
|
-
?
|
|
1041
|
+
? Fragment.fromArray(updatedSliceNodes)
|
|
1035
1042
|
: insertSlice.content,
|
|
1036
1043
|
};
|
|
1037
1044
|
}
|
|
@@ -1130,13 +1137,13 @@ function trackReplaceAroundStep(step, oldState, newTr, attrs) {
|
|
|
1130
1137
|
// the sides should be equal. TODO can they be other than 0?
|
|
1131
1138
|
const openStart = slice.openStart !== slice.openEnd || newSliceContent.size === 0 ? 0 : slice.openStart;
|
|
1132
1139
|
const openEnd = slice.openStart !== slice.openEnd || newSliceContent.size === 0 ? 0 : slice.openEnd;
|
|
1133
|
-
let insertedSlice = new
|
|
1140
|
+
let insertedSlice = new Slice(setFragmentAsInserted(newSliceContent, createNewInsertAttrs(attrs), oldState.schema), openStart, openEnd);
|
|
1134
1141
|
if (gap.size > 0) {
|
|
1135
1142
|
log.info('insertedSlice before inserted gap', insertedSlice);
|
|
1136
1143
|
insertedSlice = insertedSlice.insertAt(insertedSlice.size === 0 ? 0 : insert, gap.content);
|
|
1137
1144
|
log.info('insertedSlice after inserted gap', insertedSlice);
|
|
1138
1145
|
}
|
|
1139
|
-
const newStep = new
|
|
1146
|
+
const newStep = new ReplaceStep(deleteMap.map(gapFrom), deleteMap.map(gapTo), insertedSlice, false);
|
|
1140
1147
|
const stepResult = newTr.maybeStep(newStep);
|
|
1141
1148
|
if (stepResult.failed) {
|
|
1142
1149
|
log.error(`insert ReplaceStep failed: "${stepResult.failed}"`, newStep);
|
|
@@ -1181,10 +1188,11 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1181
1188
|
log.error(`invert ReplaceStep failed: "${stepResult.failed}"`, newStep);
|
|
1182
1189
|
return;
|
|
1183
1190
|
}
|
|
1191
|
+
log.info('TR: steps before applying delete', [...newTr.steps]);
|
|
1184
1192
|
// First apply the deleted range and update the insert slice to not include content that was deleted,
|
|
1185
1193
|
// eg partial nodes in an open-ended slice
|
|
1186
1194
|
const { deleteMap, mergedInsertPos, newSliceContent } = deleteAndMergeSplitNodes(fromA, toA, undefined, oldState.doc, newTr, oldState.schema, attrs, slice);
|
|
1187
|
-
log.info('TR:
|
|
1195
|
+
log.info('TR: steps after applying delete', [...newTr.steps]);
|
|
1188
1196
|
const adjustedInsertPos = mergedInsertPos !== null && mergedInsertPos !== void 0 ? mergedInsertPos : deleteMap.map(toA);
|
|
1189
1197
|
if (newSliceContent.size > 0) {
|
|
1190
1198
|
log.info('newSliceContent', newSliceContent);
|
|
@@ -1192,8 +1200,8 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1192
1200
|
// the sides should be equal. TODO can they be other than 0?
|
|
1193
1201
|
const openStart = slice.openStart !== slice.openEnd ? 0 : slice.openStart;
|
|
1194
1202
|
const openEnd = slice.openStart !== slice.openEnd ? 0 : slice.openEnd;
|
|
1195
|
-
const insertedSlice = new
|
|
1196
|
-
const newStep = new
|
|
1203
|
+
const insertedSlice = new Slice(setFragmentAsInserted(newSliceContent, createNewInsertAttrs(attrs), oldState.schema), openStart, openEnd);
|
|
1204
|
+
const newStep = new ReplaceStep(adjustedInsertPos, adjustedInsertPos, insertedSlice);
|
|
1197
1205
|
const stepResult = newTr.maybeStep(newStep);
|
|
1198
1206
|
if (stepResult.failed) {
|
|
1199
1207
|
log.error(`insert ReplaceStep failed: "${stepResult.failed}"`, newStep);
|
|
@@ -1238,11 +1246,10 @@ const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constr
|
|
|
1238
1246
|
* @returns newTr that inverts the initial tr and applies track attributes/marks
|
|
1239
1247
|
*/
|
|
1240
1248
|
function trackTransaction(tr, oldState, newTr, userID) {
|
|
1241
|
-
var _a;
|
|
1242
1249
|
const emptyAttrs = {
|
|
1243
1250
|
userID,
|
|
1244
1251
|
createdAt: tr.time,
|
|
1245
|
-
status:
|
|
1252
|
+
status: CHANGE_STATUS.pending,
|
|
1246
1253
|
};
|
|
1247
1254
|
// Must use constructor.name instead of instanceof as aliasing prosemirror-state is a lot more
|
|
1248
1255
|
// difficult than prosemirror-transform
|
|
@@ -1257,12 +1264,12 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1257
1264
|
'This is probably an error with the library, please report back to maintainers with a reproduction if possible', newTr);
|
|
1258
1265
|
return;
|
|
1259
1266
|
}
|
|
1260
|
-
else if (!(step instanceof
|
|
1267
|
+
else if (!(step instanceof ReplaceStep) && step.constructor.name === 'ReplaceStep') {
|
|
1261
1268
|
console.error('@manuscripts/track-changes-plugin: Multiple prosemirror-transform packages imported, alias/dedupe them ' +
|
|
1262
1269
|
'or instanceof checks fail as well as creating new steps');
|
|
1263
1270
|
return;
|
|
1264
1271
|
}
|
|
1265
|
-
else if (step instanceof
|
|
1272
|
+
else if (step instanceof ReplaceStep) {
|
|
1266
1273
|
const selectionPos = trackReplaceStep(step, oldState, newTr, emptyAttrs);
|
|
1267
1274
|
if (!wasNodeSelection) {
|
|
1268
1275
|
const sel = getSelectionStaticConstructor(tr.selection);
|
|
@@ -1273,7 +1280,7 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1273
1280
|
newTr.setSelection(near);
|
|
1274
1281
|
}
|
|
1275
1282
|
}
|
|
1276
|
-
else if (step instanceof
|
|
1283
|
+
else if (step instanceof ReplaceAroundStep) {
|
|
1277
1284
|
trackReplaceAroundStep(step, oldState, newTr, emptyAttrs);
|
|
1278
1285
|
// } else if (step instanceof AddMarkStep) {
|
|
1279
1286
|
// } else if (step instanceof RemoveMarkStep) {
|
|
@@ -1289,24 +1296,24 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1289
1296
|
tr.getMeta('uiEvent') && newTr.setMeta('uiEvent', tr.getMeta('uiEvent'));
|
|
1290
1297
|
});
|
|
1291
1298
|
// This is kinda hacky solution at the moment to maintain NodeSelections over transactions
|
|
1292
|
-
// These are required by at least cross-references
|
|
1299
|
+
// These are required by at least cross-references and links to activate their selector pop-ups
|
|
1293
1300
|
if (wasNodeSelection) {
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
const
|
|
1301
|
+
// And -1 here is necessary to keep the selection pointing at the start of the node
|
|
1302
|
+
// (or something, breaks with cross-references otherwise)
|
|
1303
|
+
const mappedPos = newTr.mapping.map(tr.selection.from, -1);
|
|
1297
1304
|
const sel = getSelectionStaticConstructor(tr.selection);
|
|
1298
|
-
newTr.setSelection(sel.create(newTr.doc,
|
|
1305
|
+
newTr.setSelection(sel.create(newTr.doc, mappedPos));
|
|
1299
1306
|
}
|
|
1300
1307
|
log.info('NEW transaction', newTr);
|
|
1301
1308
|
return newTr;
|
|
1302
1309
|
}
|
|
1303
1310
|
|
|
1304
|
-
|
|
1311
|
+
var TrackChangesStatus;
|
|
1305
1312
|
(function (TrackChangesStatus) {
|
|
1306
1313
|
TrackChangesStatus["enabled"] = "enabled";
|
|
1307
1314
|
TrackChangesStatus["viewSnapshots"] = "view-snapshots";
|
|
1308
1315
|
TrackChangesStatus["disabled"] = "disabled";
|
|
1309
|
-
})(
|
|
1316
|
+
})(TrackChangesStatus || (TrackChangesStatus = {}));
|
|
1310
1317
|
|
|
1311
1318
|
/*!
|
|
1312
1319
|
* © 2021 Atypon Systems LLC
|
|
@@ -1323,12 +1330,7 @@ exports.TrackChangesStatus = void 0;
|
|
|
1323
1330
|
* See the License for the specific language governing permissions and
|
|
1324
1331
|
* limitations under the License.
|
|
1325
1332
|
*/
|
|
1326
|
-
const trackChangesPluginKey = new
|
|
1327
|
-
// TODO remove
|
|
1328
|
-
const infiniteLoopCounter = {
|
|
1329
|
-
start: 0,
|
|
1330
|
-
iters: 0,
|
|
1331
|
-
};
|
|
1333
|
+
const trackChangesPluginKey = new PluginKey('track-changes');
|
|
1332
1334
|
/**
|
|
1333
1335
|
* The ProseMirror plugin needed to enable track-changes.
|
|
1334
1336
|
*
|
|
@@ -1341,25 +1343,25 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1341
1343
|
if (debug) {
|
|
1342
1344
|
enableDebug(true);
|
|
1343
1345
|
}
|
|
1344
|
-
return new
|
|
1346
|
+
return new Plugin({
|
|
1345
1347
|
key: trackChangesPluginKey,
|
|
1346
1348
|
props: {
|
|
1347
1349
|
editable(state) {
|
|
1348
1350
|
var _a;
|
|
1349
|
-
return ((_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status) !==
|
|
1351
|
+
return ((_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status) !== TrackChangesStatus.viewSnapshots;
|
|
1350
1352
|
},
|
|
1351
1353
|
},
|
|
1352
1354
|
state: {
|
|
1353
1355
|
init(_config, state) {
|
|
1354
1356
|
return {
|
|
1355
|
-
status:
|
|
1357
|
+
status: TrackChangesStatus.enabled,
|
|
1356
1358
|
userID,
|
|
1357
1359
|
changeSet: findChanges(state),
|
|
1358
1360
|
};
|
|
1359
1361
|
},
|
|
1360
1362
|
apply(tr, pluginState, _oldState, newState) {
|
|
1361
|
-
const setUserID = getAction(tr,
|
|
1362
|
-
const setStatus = getAction(tr,
|
|
1363
|
+
const setUserID = getAction(tr, TrackChangesAction.setUserID);
|
|
1364
|
+
const setStatus = getAction(tr, TrackChangesAction.setPluginStatus);
|
|
1363
1365
|
if (setUserID) {
|
|
1364
1366
|
return { ...pluginState, userID: setUserID };
|
|
1365
1367
|
}
|
|
@@ -1370,12 +1372,12 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1370
1372
|
changeSet: findChanges(newState),
|
|
1371
1373
|
};
|
|
1372
1374
|
}
|
|
1373
|
-
else if (pluginState.status ===
|
|
1375
|
+
else if (pluginState.status === TrackChangesStatus.disabled) {
|
|
1374
1376
|
return { ...pluginState, changeSet: new ChangeSet() };
|
|
1375
1377
|
}
|
|
1376
1378
|
let { changeSet, ...rest } = pluginState;
|
|
1377
|
-
const updatedChangeIds = getAction(tr,
|
|
1378
|
-
if (updatedChangeIds || getAction(tr,
|
|
1379
|
+
const updatedChangeIds = getAction(tr, TrackChangesAction.updateChanges);
|
|
1380
|
+
if (updatedChangeIds || getAction(tr, TrackChangesAction.refreshChanges)) {
|
|
1379
1381
|
changeSet = findChanges(newState);
|
|
1380
1382
|
}
|
|
1381
1383
|
return {
|
|
@@ -1394,46 +1396,37 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1394
1396
|
appendTransaction(trs, oldState, newState) {
|
|
1395
1397
|
const pluginState = trackChangesPluginKey.getState(newState);
|
|
1396
1398
|
if (!pluginState ||
|
|
1397
|
-
pluginState.status ===
|
|
1399
|
+
pluginState.status === TrackChangesStatus.disabled ||
|
|
1398
1400
|
!(editorView === null || editorView === void 0 ? void 0 : editorView.editable)) {
|
|
1399
1401
|
return null;
|
|
1400
1402
|
}
|
|
1401
|
-
if (infiniteLoopCounter.start < Date.now() - 10000) {
|
|
1402
|
-
infiniteLoopCounter.start = Date.now();
|
|
1403
|
-
infiniteLoopCounter.iters = 0;
|
|
1404
|
-
}
|
|
1405
|
-
if (infiniteLoopCounter.iters >= 100) {
|
|
1406
|
-
console.error('Detected probable infinite loop in track changes!');
|
|
1407
|
-
return null;
|
|
1408
|
-
}
|
|
1409
1403
|
const { userID, changeSet } = pluginState;
|
|
1410
1404
|
let createdTr = newState.tr, docChanged = false;
|
|
1411
1405
|
log.info('TRS', trs);
|
|
1412
1406
|
trs.forEach((tr) => {
|
|
1413
1407
|
const wasAppended = tr.getMeta('appendedTransaction');
|
|
1414
1408
|
const skipMetaUsed = skipTrsWithMetas.some((m) => tr.getMeta(m) || (wasAppended === null || wasAppended === void 0 ? void 0 : wasAppended.getMeta(m)));
|
|
1415
|
-
const skipTrackUsed = getAction(tr,
|
|
1416
|
-
(wasAppended && getAction(wasAppended,
|
|
1409
|
+
const skipTrackUsed = getAction(tr, TrackChangesAction.skipTrack) ||
|
|
1410
|
+
(wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
|
|
1417
1411
|
if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$')) {
|
|
1418
1412
|
createdTr = trackTransaction(tr, oldState, createdTr, userID);
|
|
1419
|
-
infiniteLoopCounter.iters += 1;
|
|
1420
1413
|
}
|
|
1421
1414
|
docChanged = docChanged || tr.docChanged;
|
|
1422
|
-
const setChangeStatuses = getAction(tr,
|
|
1415
|
+
const setChangeStatuses = getAction(tr, TrackChangesAction.setChangeStatuses);
|
|
1423
1416
|
if (setChangeStatuses) {
|
|
1424
1417
|
const { status, ids } = setChangeStatuses;
|
|
1425
1418
|
ids.forEach((changeId) => {
|
|
1426
1419
|
const change = changeSet === null || changeSet === void 0 ? void 0 : changeSet.get(changeId);
|
|
1427
1420
|
if (change) {
|
|
1428
1421
|
createdTr = updateChangeAttrs(createdTr, change, { status }, oldState.schema);
|
|
1429
|
-
setAction(createdTr,
|
|
1422
|
+
setAction(createdTr, TrackChangesAction.updateChanges, [change.id]);
|
|
1430
1423
|
}
|
|
1431
1424
|
});
|
|
1432
1425
|
}
|
|
1433
|
-
else if (getAction(tr,
|
|
1426
|
+
else if (getAction(tr, TrackChangesAction.applyAndRemoveChanges)) {
|
|
1434
1427
|
const mapping = applyAcceptedRejectedChanges(createdTr, oldState.schema, changeSet.nodeChanges);
|
|
1435
1428
|
applyAcceptedRejectedChanges(createdTr, oldState.schema, changeSet.textChanges, mapping);
|
|
1436
|
-
setAction(createdTr,
|
|
1429
|
+
setAction(createdTr, TrackChangesAction.refreshChanges, true);
|
|
1437
1430
|
}
|
|
1438
1431
|
});
|
|
1439
1432
|
const changed = pluginState.changeSet.hasInconsistentData &&
|
|
@@ -1443,7 +1436,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1443
1436
|
}
|
|
1444
1437
|
if (docChanged || createdTr.docChanged || changed) {
|
|
1445
1438
|
createdTr.setMeta('origin', trackChangesPluginKey);
|
|
1446
|
-
return setAction(createdTr,
|
|
1439
|
+
return setAction(createdTr, TrackChangesAction.refreshChanges, true);
|
|
1447
1440
|
}
|
|
1448
1441
|
return null;
|
|
1449
1442
|
},
|
|
@@ -1481,11 +1474,11 @@ const setTrackingStatus = (status) => (state, dispatch) => {
|
|
|
1481
1474
|
let newStatus = status;
|
|
1482
1475
|
if (newStatus === undefined) {
|
|
1483
1476
|
newStatus =
|
|
1484
|
-
currentStatus ===
|
|
1485
|
-
?
|
|
1486
|
-
:
|
|
1477
|
+
currentStatus === TrackChangesStatus.enabled
|
|
1478
|
+
? TrackChangesStatus.disabled
|
|
1479
|
+
: TrackChangesStatus.enabled;
|
|
1487
1480
|
}
|
|
1488
|
-
dispatch && dispatch(setAction(state.tr,
|
|
1481
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.setPluginStatus, newStatus));
|
|
1489
1482
|
return true;
|
|
1490
1483
|
}
|
|
1491
1484
|
return false;
|
|
@@ -1497,7 +1490,7 @@ const setTrackingStatus = (status) => (state, dispatch) => {
|
|
|
1497
1490
|
*/
|
|
1498
1491
|
const setChangeStatuses = (status, ids) => (state, dispatch) => {
|
|
1499
1492
|
dispatch &&
|
|
1500
|
-
dispatch(setAction(state.tr,
|
|
1493
|
+
dispatch(setAction(state.tr, TrackChangesAction.setChangeStatuses, {
|
|
1501
1494
|
status,
|
|
1502
1495
|
ids,
|
|
1503
1496
|
}));
|
|
@@ -1508,21 +1501,21 @@ const setChangeStatuses = (status, ids) => (state, dispatch) => {
|
|
|
1508
1501
|
* @param userID
|
|
1509
1502
|
*/
|
|
1510
1503
|
const setUserID = (userID) => (state, dispatch) => {
|
|
1511
|
-
dispatch && dispatch(setAction(state.tr,
|
|
1504
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.setUserID, userID));
|
|
1512
1505
|
return true;
|
|
1513
1506
|
};
|
|
1514
1507
|
/**
|
|
1515
1508
|
* Appends a transaction that applies all 'accepted' and 'rejected' changes to the document.
|
|
1516
1509
|
*/
|
|
1517
1510
|
const applyAndRemoveChanges = () => (state, dispatch) => {
|
|
1518
|
-
dispatch && dispatch(setAction(state.tr,
|
|
1511
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.applyAndRemoveChanges, true));
|
|
1519
1512
|
return true;
|
|
1520
1513
|
};
|
|
1521
1514
|
/**
|
|
1522
1515
|
* Runs `findChanges` to iterate over the document to collect changes into a new ChangeSet.
|
|
1523
1516
|
*/
|
|
1524
1517
|
const refreshChanges = () => (state, dispatch) => {
|
|
1525
|
-
dispatch && dispatch(setAction(state.tr,
|
|
1518
|
+
dispatch && dispatch(setAction(state.tr, TrackChangesAction.updateChanges, []));
|
|
1526
1519
|
return true;
|
|
1527
1520
|
};
|
|
1528
1521
|
/**
|
|
@@ -1552,10 +1545,4 @@ var commands = /*#__PURE__*/Object.freeze({
|
|
|
1552
1545
|
setParagraphTestAttribute: setParagraphTestAttribute
|
|
1553
1546
|
});
|
|
1554
1547
|
|
|
1555
|
-
|
|
1556
|
-
exports.enableDebug = enableDebug;
|
|
1557
|
-
exports.getAction = getAction;
|
|
1558
|
-
exports.setAction = setAction;
|
|
1559
|
-
exports.trackChangesPlugin = trackChangesPlugin;
|
|
1560
|
-
exports.trackChangesPluginKey = trackChangesPluginKey;
|
|
1561
|
-
exports.trackCommands = commands;
|
|
1548
|
+
export { CHANGE_OPERATION, CHANGE_STATUS, ChangeSet, TrackChangesAction, TrackChangesStatus, enableDebug, getAction, setAction, trackChangesPlugin, trackChangesPluginKey, commands as trackCommands };
|
|
@@ -22,4 +22,4 @@ import { Transaction } from 'prosemirror-state';
|
|
|
22
22
|
* @param tr
|
|
23
23
|
* @returns
|
|
24
24
|
*/
|
|
25
|
-
export declare function mergeNode(node: PMNode, pos: number, tr: Transaction): Transaction
|
|
25
|
+
export declare function mergeNode(node: PMNode, pos: number, tr: Transaction): Transaction | undefined;
|
|
@@ -22,7 +22,7 @@ export declare function addTrackIdIfDoesntExist(attrs: Partial<TrackedAttrs>): P
|
|
|
22
22
|
* @param pos
|
|
23
23
|
* @param tr
|
|
24
24
|
*/
|
|
25
|
-
export declare function liftNode(pos: number, tr: Transaction): Transaction
|
|
25
|
+
export declare function liftNode(pos: number, tr: Transaction): Transaction | undefined;
|
|
26
26
|
export declare function getInlineNodeTrackedMarkData(node: PMNode | undefined | null, schema: Schema): {
|
|
27
27
|
operation: CHANGE_OPERATION;
|
|
28
28
|
} | undefined;
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manuscripts/track-changes-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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",
|
|
7
|
-
"main": "dist/index.
|
|
8
|
-
"module": "dist/index.
|
|
7
|
+
"main": "dist/index.cjs",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
11
|
"exports": {
|
|
12
12
|
"./package.json": "./package.json",
|
|
13
13
|
"./src/styles.css": "./src/styles.css",
|
|
14
|
-
".": "./dist/index.
|
|
14
|
+
".": "./dist/index.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@manuscripts/manuscript-transform": "^0.49.
|
|
24
|
+
"@manuscripts/manuscript-transform": "^0.49.4",
|
|
25
25
|
"@rollup/plugin-commonjs": "^22.0.0",
|
|
26
26
|
"@types/debug": "^4.1.7",
|
|
27
27
|
"@types/jest": "27.5.1",
|