@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/dist/index.js CHANGED
@@ -1,17 +1,9 @@
1
- 'use strict';
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
- Object.defineProperty(exports, '__esModule', { value: true });
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
- })(exports.TrackChangesAction || (exports.TrackChangesAction = {}));
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
- exports.CHANGE_OPERATION = void 0;
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
- })(exports.CHANGE_OPERATION || (exports.CHANGE_OPERATION = {}));
96
- exports.CHANGE_STATUS = void 0;
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
- })(exports.CHANGE_STATUS || (exports.CHANGE_STATUS = {}));
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 = debug__default["default"]('track');
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
- debug__default["default"].enable('track');
143
+ debug.enable('track');
152
144
  }
153
145
  else {
154
- debug__default["default"].disable();
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 === exports.CHANGE_STATUS.pending);
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 === exports.CHANGE_STATUS.accepted);
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 === exports.CHANGE_STATUS.rejected);
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 === exports.CHANGE_OPERATION.insert && status === exports.CHANGE_STATUS.accepted) ||
275
- (operation === exports.CHANGE_OPERATION.delete && status === exports.CHANGE_STATUS.rejected));
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 === exports.CHANGE_OPERATION.insert && status === exports.CHANGE_STATUS.rejected) ||
284
- (operation === exports.CHANGE_OPERATION.delete && status === exports.CHANGE_STATUS.accepted));
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 && prosemirrorTransform.liftTarget(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
- const canMergeToNodeAbove = (resPos.parent !== tr.doc || resPos.nodeBefore) && ((_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.isText);
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, prosemirrorModel.Fragment.empty);
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 (prosemirrorTransform.canJoin(tr.doc, pos)) {
373
+ if (canJoin(tr.doc, pos)) {
380
374
  return tr.join(pos);
381
375
  }
382
- else if (prosemirrorTransform.canJoin(tr.doc, pos + node.nodeSize)) {
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, prosemirrorModel.Fragment.empty);
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
- ? exports.CHANGE_OPERATION.insert
434
- : exports.CHANGE_OPERATION.delete;
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 prosemirrorTransform.Mapping()) {
503
+ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mapping()) {
509
504
  changes.forEach((change) => {
510
- if (change.attrs.status === exports.CHANGE_STATUS.pending) {
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: exports.CHANGE_OPERATION.insert }),
633
- ...(!status && { status: exports.CHANGE_STATUS.pending }),
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 === exports.CHANGE_OPERATION.insert
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
- }, prosemirrorModel.Fragment.fromArray(updatedChildren), node.marks);
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 : prosemirrorModel.Fragment.fromArray(updatedInserted);
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: exports.CHANGE_OPERATION.insert,
711
+ operation: CHANGE_OPERATION.insert,
717
712
  };
718
713
  }
719
714
  function createNewDeleteAttrs(attrs) {
720
715
  return {
721
716
  ...attrs,
722
- operation: exports.CHANGE_OPERATION.delete,
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 = prosemirrorModel.Fragment.empty;
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 ? prosemirrorModel.Fragment.fromArray(result) : undefined,
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, prosemirrorModel.Fragment.empty);
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) === exports.CHANGE_OPERATION.insert && dataTracked.userID === deleteAttrs.userID;
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 prosemirrorTransform.Mapping();
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
- ? prosemirrorModel.Fragment.fromArray(updatedSliceNodes)
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 prosemirrorModel.Slice(setFragmentAsInserted(newSliceContent, createNewInsertAttrs(attrs), oldState.schema), openStart, openEnd);
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 prosemirrorTransform.ReplaceStep(deleteMap.map(gapFrom), deleteMap.map(gapTo), insertedSlice, false);
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: new steps after applying delete', [...newTr.steps]);
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 prosemirrorModel.Slice(setFragmentAsInserted(newSliceContent, createNewInsertAttrs(attrs), oldState.schema), openStart, openEnd);
1196
- const newStep = new prosemirrorTransform.ReplaceStep(adjustedInsertPos, adjustedInsertPos, insertedSlice);
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: exports.CHANGE_STATUS.pending,
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 prosemirrorTransform.ReplaceStep) && step.constructor.name === 'ReplaceStep') {
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 prosemirrorTransform.ReplaceStep) {
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 prosemirrorTransform.ReplaceAroundStep) {
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 that need it to activate the selector pop-up
1299
+ // These are required by at least cross-references and links to activate their selector pop-ups
1293
1300
  if (wasNodeSelection) {
1294
- const mappedPos = newTr.mapping.map(tr.selection.from);
1295
- const resPos = newTr.doc.resolve(mappedPos);
1296
- const nodePos = mappedPos - (((_a = resPos.nodeBefore) === null || _a === void 0 ? void 0 : _a.nodeSize) || 0);
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, nodePos));
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
- exports.TrackChangesStatus = void 0;
1311
+ var TrackChangesStatus;
1305
1312
  (function (TrackChangesStatus) {
1306
1313
  TrackChangesStatus["enabled"] = "enabled";
1307
1314
  TrackChangesStatus["viewSnapshots"] = "view-snapshots";
1308
1315
  TrackChangesStatus["disabled"] = "disabled";
1309
- })(exports.TrackChangesStatus || (exports.TrackChangesStatus = {}));
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 prosemirrorState.PluginKey('track-changes');
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 prosemirrorState.Plugin({
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) !== exports.TrackChangesStatus.viewSnapshots;
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: exports.TrackChangesStatus.enabled,
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, exports.TrackChangesAction.setUserID);
1362
- const setStatus = getAction(tr, exports.TrackChangesAction.setPluginStatus);
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 === exports.TrackChangesStatus.disabled) {
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, exports.TrackChangesAction.updateChanges);
1378
- if (updatedChangeIds || getAction(tr, exports.TrackChangesAction.refreshChanges)) {
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 === exports.TrackChangesStatus.disabled ||
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, exports.TrackChangesAction.skipTrack) ||
1416
- (wasAppended && getAction(wasAppended, exports.TrackChangesAction.skipTrack));
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, exports.TrackChangesAction.setChangeStatuses);
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, exports.TrackChangesAction.updateChanges, [change.id]);
1422
+ setAction(createdTr, TrackChangesAction.updateChanges, [change.id]);
1430
1423
  }
1431
1424
  });
1432
1425
  }
1433
- else if (getAction(tr, exports.TrackChangesAction.applyAndRemoveChanges)) {
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, exports.TrackChangesAction.refreshChanges, true);
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, exports.TrackChangesAction.refreshChanges, true);
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 === exports.TrackChangesStatus.enabled
1485
- ? exports.TrackChangesStatus.disabled
1486
- : exports.TrackChangesStatus.enabled;
1477
+ currentStatus === TrackChangesStatus.enabled
1478
+ ? TrackChangesStatus.disabled
1479
+ : TrackChangesStatus.enabled;
1487
1480
  }
1488
- dispatch && dispatch(setAction(state.tr, exports.TrackChangesAction.setPluginStatus, newStatus));
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, exports.TrackChangesAction.setChangeStatuses, {
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, exports.TrackChangesAction.setUserID, userID));
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, exports.TrackChangesAction.applyAndRemoveChanges, true));
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, exports.TrackChangesAction.updateChanges, []));
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
- exports.ChangeSet = ChangeSet;
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<any> | undefined;
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<any> | undefined;
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.1.1",
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.js",
8
- "module": "dist/index.es.js",
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.es.js"
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.1",
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",