@manuscripts/track-changes-plugin 2.0.13 → 2.1.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.
Files changed (37) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/ChangeSet.js +27 -8
  3. package/dist/cjs/changes/applyChanges.js +26 -12
  4. package/dist/cjs/changes/findChanges.js +16 -0
  5. package/dist/cjs/changes/revertChange.js +2 -2
  6. package/dist/cjs/changes/updateChangeAttrs.js +27 -0
  7. package/dist/cjs/compute/nodeHelpers.js +11 -0
  8. package/dist/cjs/mutate/deleteAndMergeSplitNodes.js +2 -1
  9. package/dist/cjs/steps/trackMarkSteps.js +140 -0
  10. package/dist/cjs/steps/trackReplaceAroundStep.js +3 -3
  11. package/dist/cjs/steps/trackReplaceStep.js +3 -3
  12. package/dist/cjs/steps/trackTransaction.js +14 -2
  13. package/dist/cjs/steps/utils.js +70 -0
  14. package/dist/cjs/utils/track-utils.js +28 -51
  15. package/dist/cjs/utils/uuidv4.js +3 -0
  16. package/dist/es/ChangeSet.js +27 -8
  17. package/dist/es/changes/applyChanges.js +26 -11
  18. package/dist/es/changes/findChanges.js +17 -1
  19. package/dist/es/changes/revertChange.js +2 -2
  20. package/dist/es/changes/updateChangeAttrs.js +27 -0
  21. package/dist/es/compute/nodeHelpers.js +10 -0
  22. package/dist/es/mutate/deleteAndMergeSplitNodes.js +2 -1
  23. package/dist/es/steps/trackMarkSteps.js +134 -0
  24. package/dist/es/steps/trackReplaceAroundStep.js +1 -1
  25. package/dist/es/steps/trackReplaceStep.js +1 -1
  26. package/dist/es/steps/trackTransaction.js +14 -2
  27. package/dist/es/steps/utils.js +62 -0
  28. package/dist/es/utils/track-utils.js +24 -45
  29. package/dist/es/utils/uuidv4.js +3 -0
  30. package/dist/types/ChangeSet.d.ts +5 -2
  31. package/dist/types/changes/applyChanges.d.ts +1 -2
  32. package/dist/types/compute/nodeHelpers.d.ts +2 -1
  33. package/dist/types/steps/trackMarkSteps.d.ts +8 -0
  34. package/dist/types/steps/utils.d.ts +28 -0
  35. package/dist/types/types/change.d.ts +4 -1
  36. package/dist/types/utils/track-utils.d.ts +7 -14
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -17,8 +17,8 @@ ProseMirror plugin designed to track changes within a document, similar to the t
17
17
  Transactions are intercepted and reverted using default plugins lifecycle, unless transaction has meta commanding to skip tracking.
18
18
 
19
19
  - Annotate changes with metadata using node attributes and marks.
20
- Before transaction is reverted the changes in each step of transaction are processed and created metadata that described the changes are stored in the dataTracked attributes. For text changes, dataTracked attributes are added to marks,
21
- with which the inline change is marked on the document. For node changes the dataTracked metadata are assigned to nodes.
20
+ Before transaction is reverted the changes in each step of transaction are processed and metadata are created that describe the changes stored in the dataTracked attributes. For text changes, dataTracked attributes are added to marks,
21
+ with which the inline change is marked on the document. For node changes the dataTracked metadata are assigned to nodes via attributes.
22
22
 
23
23
  - ChangeSet class handles changes interpretation to create a more meaningful representation:
24
24
  - Creates a list of top level changes out of a list of nested changed.
@@ -48,7 +48,7 @@ Nodes that change are extended with dataTracked attributes:
48
48
 
49
49
  ## Requirements
50
50
 
51
- Node schema needs to have { dataTracked: null } attribute declared. Otherwise the node will not be tracked.
51
+ Node or mark schema needs to have { dataTracked: null } attribute declared. Otherwise the node will not be tracked. Plugin also expects schema to support marks for highlighting current changes.
52
52
 
53
53
  ## Best practices and caveats
54
54
 
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.ChangeSet = void 0;
16
16
  const change_1 = require("./types/change");
17
17
  const logger_1 = require("./utils/logger");
18
+ const track_utils_1 = require("./utils/track-utils");
18
19
  class ChangeSet {
19
20
  constructor(changes = []) {
20
21
  _ChangeSet_instances.add(this);
@@ -150,19 +151,34 @@ class ChangeSet {
150
151
  }
151
152
  }
152
153
  }
154
+ areMatchingWrapOperations(c1, c2) {
155
+ const op1 = c1.dataTracked.operation;
156
+ const op2 = c2.dataTracked.operation;
157
+ return ((op1 === 'wrap_with_node' && (op2 === 'insert' || op2 === 'set_attrs')) ||
158
+ (op2 === 'wrap_with_node' && (op1 === 'insert' || op1 === 'set_attrs')));
159
+ }
160
+ areMatchingMarkOperations(c1, c2) {
161
+ if (ChangeSet.isMarkChange(c1) && ChangeSet.isMarkChange(c2)) {
162
+ const op1 = c1.dataTracked.operation;
163
+ const op2 = c2.dataTracked.operation;
164
+ if (op1 == op2 && c1.mark.type === c2.mark.type) {
165
+ return true;
166
+ }
167
+ }
168
+ return false;
169
+ }
153
170
  canJoinAdjacentInlineChanges(change, index) {
154
171
  const nextChange = this.changeTree.at(index + 1);
155
- const isInline = (c) => c.type === 'text-change' || (c.type === 'node-change' && c.node.isInline);
156
- const hasMatchingOperation = (c1, c2) => c1.dataTracked.operation === c2.dataTracked.operation ||
157
- (c1.dataTracked.operation === 'wrap_with_node' &&
158
- (c2.dataTracked.operation === 'insert' || c2.dataTracked.operation === 'set_attrs')) ||
159
- (c2.dataTracked.operation === 'wrap_with_node' &&
160
- (c1.dataTracked.operation === 'insert' || c1.dataTracked.operation === 'set_attrs'));
172
+ if (!nextChange) {
173
+ return false;
174
+ }
175
+ const isInline = (c) => c.type === 'text-change' || (c.type === 'node-change' && c.node.isInline) || (0, track_utils_1.isInlineMarkChange)(c);
161
176
  return (isInline(change) &&
162
- nextChange &&
163
177
  isInline(nextChange) &&
164
178
  change.to === nextChange.from &&
165
- hasMatchingOperation(change, nextChange));
179
+ (change.dataTracked.operation === nextChange.dataTracked.operation ||
180
+ this.areMatchingWrapOperations(change, nextChange) ||
181
+ this.areMatchingMarkOperations(change, nextChange)));
166
182
  }
167
183
  joinRelatedStructuralChanges(rootNodes, change) {
168
184
  if (change.dataTracked.operation !== change_1.CHANGE_OPERATION.structure) {
@@ -213,6 +229,9 @@ class ChangeSet {
213
229
  static isTextChange(change) {
214
230
  return change.type === 'text-change';
215
231
  }
232
+ static isMarkChange(change) {
233
+ return change.type === 'mark-change';
234
+ }
216
235
  static isNodeChange(change) {
217
236
  return change.type === 'node-change';
218
237
  }
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUpdatedDataTracked = getUpdatedDataTracked;
4
3
  exports.applyAcceptedRejectedChanges = applyAcceptedRejectedChanges;
5
4
  const prosemirror_transform_1 = require("prosemirror-transform");
6
5
  const ChangeSet_1 = require("../ChangeSet");
@@ -8,6 +7,7 @@ const deleteNode_1 = require("../mutate/deleteNode");
8
7
  const mergeNode_1 = require("../mutate/mergeNode");
9
8
  const change_1 = require("../types/change");
10
9
  const logger_1 = require("../utils/logger");
10
+ const track_utils_1 = require("../utils/track-utils");
11
11
  const revertChange_1 = require("./revertChange");
12
12
  const updateChangeAttrs_1 = require("./updateChangeAttrs");
13
13
  function collectMoveNodeIds(containerNode, primaryMoveNodeId) {
@@ -25,13 +25,6 @@ function collectMoveNodeIds(containerNode, primaryMoveNodeId) {
25
25
  });
26
26
  return moveNodeIds;
27
27
  }
28
- function getUpdatedDataTracked(dataTracked, changeId) {
29
- if (!dataTracked) {
30
- return null;
31
- }
32
- const newDataTracked = dataTracked.filter((c) => c.id !== changeId);
33
- return newDataTracked.length ? newDataTracked : null;
34
- }
35
28
  function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap = new prosemirror_transform_1.Mapping()) {
36
29
  changes.sort((c1, c2) => {
37
30
  if ((c1.type === 'node-change' && c1.node.type === schema.nodes.list) ||
@@ -91,13 +84,34 @@ function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap
91
84
  deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
92
85
  }
93
86
  else if (ChangeSet_1.ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === change_1.CHANGE_STATUS.accepted) {
94
- tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, change.newAttrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
87
+ tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, change.newAttrs), { dataTracked: (0, track_utils_1.excludeFromTracked)(node.attrs.dataTracked, change.id) }), node.marks);
95
88
  }
96
89
  else if (ChangeSet_1.ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === change_1.CHANGE_STATUS.rejected) {
97
- tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, change.oldAttrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
90
+ tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, change.oldAttrs), { dataTracked: (0, track_utils_1.excludeFromTracked)(node.attrs.dataTracked, change.id) }), node.marks);
98
91
  }
99
92
  else if (ChangeSet_1.ChangeSet.isReferenceChange(change)) {
100
- tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
93
+ tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: (0, track_utils_1.excludeFromTracked)(node.attrs.dataTracked, change.id) }), node.marks);
94
+ }
95
+ else if (ChangeSet_1.ChangeSet.isMarkChange(change)) {
96
+ const newMark = change.mark.type.create({
97
+ dataTracked: (0, track_utils_1.excludeFromTracked)(change.mark.attrs.dataTracked, change.id),
98
+ });
99
+ const isInsert = change.dataTracked.operation === change_1.CHANGE_OPERATION.insert;
100
+ const isDelete = change.dataTracked.operation === change_1.CHANGE_OPERATION.delete;
101
+ const toBeRestored = (change.dataTracked.status === change_1.CHANGE_STATUS.accepted && isInsert) ||
102
+ (change.dataTracked.status === change_1.CHANGE_STATUS.rejected && isDelete);
103
+ if ((0, track_utils_1.isInlineMarkChange)(change)) {
104
+ tr.removeMark(change.from, change.to, change.mark);
105
+ if (toBeRestored) {
106
+ tr.addMark(change.from, change.to, newMark);
107
+ }
108
+ }
109
+ else {
110
+ tr.removeNodeMark(change.from, change.mark);
111
+ if (toBeRestored) {
112
+ tr.addNodeMark(change.from, newMark);
113
+ }
114
+ }
101
115
  }
102
116
  });
103
117
  changes.forEach((change) => {
@@ -114,7 +128,7 @@ function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap
114
128
  return;
115
129
  }
116
130
  if (change.dataTracked.status === change_1.CHANGE_STATUS.accepted) {
117
- const attrs = Object.assign(Object.assign({}, node.attrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) });
131
+ const attrs = Object.assign(Object.assign({}, node.attrs), { dataTracked: (0, track_utils_1.excludeFromTracked)(node.attrs.dataTracked, change.id) });
118
132
  tr.setNodeMarkup(from, undefined, attrs, node.marks);
119
133
  const originalChanges = changeSet.changes.filter((c) => c.dataTracked.moveNodeId === change.dataTracked.moveNodeId &&
120
134
  c.dataTracked.operation === change_1.CHANGE_OPERATION.delete);
@@ -9,6 +9,22 @@ function findChanges(state) {
9
9
  let current;
10
10
  state.doc.descendants((node, pos) => {
11
11
  const tracked = (0, nodeHelpers_1.getNodeTrackedData)(node, state.schema) || [];
12
+ const marksWithTrackChanges = (0, nodeHelpers_1.getMarkTrackedData)(node);
13
+ marksWithTrackChanges === null || marksWithTrackChanges === void 0 ? void 0 : marksWithTrackChanges.forEach((trackAttrs, mark) => {
14
+ trackAttrs.forEach((c) => {
15
+ const ch = {
16
+ id: c.id,
17
+ type: 'mark-change',
18
+ from: pos,
19
+ to: pos + node.nodeSize,
20
+ dataTracked: Object.assign({}, c),
21
+ nodeType: node.type,
22
+ node: node,
23
+ mark: mark,
24
+ };
25
+ changes.push(ch);
26
+ });
27
+ });
12
28
  for (let i = 0; i < tracked.length; i += 1) {
13
29
  const dataTracked = tracked[i];
14
30
  const id = dataTracked.id || '';
@@ -5,7 +5,7 @@ exports.revertWrapNodeChange = revertWrapNodeChange;
5
5
  const prosemirror_model_1 = require("prosemirror-model");
6
6
  const prosemirror_transform_1 = require("prosemirror-transform");
7
7
  const nodeHelpers_1 = require("../compute/nodeHelpers");
8
- const applyChanges_1 = require("./applyChanges");
8
+ const track_utils_1 = require("../utils/track-utils");
9
9
  function revertSplitNodeChange(tr, change, changeSet) {
10
10
  const sourceChange = changeSet.changes.find((c) => c.dataTracked.operation === 'reference' && c.dataTracked.referenceId === change.id);
11
11
  const node = tr.doc.nodeAt(tr.mapping.map(change.from));
@@ -24,7 +24,7 @@ function revertSplitNodeChange(tr, change, changeSet) {
24
24
  const deleteChange = changeSet.changes.find((c) => c.dataTracked.operation == 'delete' && c.from === sourceChange.from);
25
25
  if (deleteChange) {
26
26
  const node = tr.doc.nodeAt(tr.mapping.map(deleteChange.from));
27
- tr.setNodeMarkup(tr.mapping.map(deleteChange.from), undefined, (0, applyChanges_1.getUpdatedDataTracked)(node.attrs.dataTracked, deleteChange.id));
27
+ tr.setNodeMarkup(tr.mapping.map(deleteChange.from), undefined, (0, track_utils_1.excludeFromTracked)(node.attrs.dataTracked, deleteChange.id));
28
28
  }
29
29
  }
30
30
  function revertWrapNodeChange(tr, change, deleteMap) {
@@ -7,6 +7,7 @@ const ChangeSet_1 = require("../ChangeSet");
7
7
  const nodeHelpers_1 = require("../compute/nodeHelpers");
8
8
  const change_1 = require("../types/change");
9
9
  const logger_1 = require("../utils/logger");
10
+ const track_utils_1 = require("../utils/track-utils");
10
11
  function updateChangeAttrs(tr, change, trackedAttrs, schema) {
11
12
  const node = tr.doc.nodeAt(change.from);
12
13
  if (!node) {
@@ -69,6 +70,32 @@ function updateChangeAttrs(tr, change, trackedAttrs, schema) {
69
70
  .filter(Boolean);
70
71
  tr.setNodeMarkup(change.from, undefined, Object.assign(Object.assign({}, (restoredAttrs || node.attrs)), { dataTracked: newDataTracked.length === 0 ? null : newDataTracked }), node.marks);
71
72
  }
73
+ else if (change.type === 'mark-change') {
74
+ const markChange = change;
75
+ if (markChange.mark && markChange.from && markChange.to) {
76
+ const markDataTracked = Array.isArray(markChange.mark.attrs.dataTracked)
77
+ ? markChange.mark.attrs.dataTracked
78
+ : [];
79
+ const newDT = markDataTracked === null || markDataTracked === void 0 ? void 0 : markDataTracked.map((dt) => {
80
+ if (dt.createdAt === change.dataTracked.createdAt && dt.operation === change.dataTracked.operation) {
81
+ return Object.assign(Object.assign({}, dt), trackedAttrs);
82
+ }
83
+ return dt;
84
+ });
85
+ const newMark = markChange.mark.type.create(Object.assign(Object.assign({}, markChange.mark.attrs), { dataTracked: newDT }));
86
+ if ((0, track_utils_1.isInlineMarkChange)(markChange)) {
87
+ tr.removeMark(markChange.from, markChange.to, markChange.mark);
88
+ tr.addMark(markChange.from, markChange.to, newMark);
89
+ }
90
+ else {
91
+ tr.removeNodeMark(markChange.from, markChange.mark);
92
+ tr.addNodeMark(markChange.from, newMark);
93
+ }
94
+ }
95
+ else {
96
+ console.warn('Unable to update a mark change because the mark change data are incomplete');
97
+ }
98
+ }
72
99
  return tr;
73
100
  }
74
101
  function updateChangeChildrenAttributes(changes, tr, mapping) {
@@ -3,12 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addTrackIdIfDoesntExist = addTrackIdIfDoesntExist;
4
4
  exports.getTextNodeTrackedMarkData = getTextNodeTrackedMarkData;
5
5
  exports.getBlockInlineTrackedData = getBlockInlineTrackedData;
6
+ exports.getMarkTrackedData = getMarkTrackedData;
6
7
  exports.getNodeTrackedData = getNodeTrackedData;
7
8
  exports.equalMarks = equalMarks;
8
9
  exports.shouldMergeTrackedAttributes = shouldMergeTrackedAttributes;
9
10
  exports.getMergeableMarkTrackedAttrs = getMergeableMarkTrackedAttrs;
10
11
  const change_1 = require("../types/change");
11
12
  const logger_1 = require("../utils/logger");
13
+ const track_utils_1 = require("../utils/track-utils");
12
14
  const uuidv4_1 = require("../utils/uuidv4");
13
15
  function addTrackIdIfDoesntExist(attrs) {
14
16
  if (!attrs.id) {
@@ -39,6 +41,15 @@ function getBlockInlineTrackedData(node) {
39
41
  }
40
42
  return dataTracked || [];
41
43
  }
44
+ function getMarkTrackedData(node) {
45
+ const tracked = node === null || node === void 0 ? void 0 : node.marks.reduce((acc, current) => {
46
+ if ((0, track_utils_1.isValidTrackableMark)(current) && current.attrs.dataTracked) {
47
+ acc.set(current, current.attrs.dataTracked);
48
+ }
49
+ return acc;
50
+ }, new Map());
51
+ return tracked || new Map();
52
+ }
42
53
  function getNodeTrackedData(node, schema) {
43
54
  let tracked;
44
55
  if (node && !node.isText) {
@@ -37,6 +37,7 @@ exports.deleteAndMergeSplitNodes = deleteAndMergeSplitNodes;
37
37
  const prosemirror_model_1 = require("prosemirror-model");
38
38
  const setFragmentAsInserted_1 = require("../compute/setFragmentAsInserted");
39
39
  const splitSliceIntoMergedParts_1 = require("../compute/splitSliceIntoMergedParts");
40
+ const utils_1 = require("../steps/utils");
40
41
  const trackUtils = __importStar(require("../utils/track-utils"));
41
42
  function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackAttrs, insertSlice) {
42
43
  const steps = [];
@@ -69,7 +70,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
69
70
  const mergeEndNode = startTokenDeleted && openEnd > 0 && depth === openEnd && mergeContent;
70
71
  const mergeEndNodeNotEmpty = mergeEndNode && mergeContent.size;
71
72
  if (mergeEndNode && !mergeEndNodeNotEmpty && gap) {
72
- if (trackUtils.stepIsLift(gap, node, to)) {
73
+ if ((0, utils_1.stepIsLift)(gap, node, to)) {
73
74
  gap.slice.content.forEach((node, offset) => {
74
75
  steps.push({
75
76
  type: 'delete-node',
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trackRemoveMarkStep = trackRemoveMarkStep;
4
+ exports.trackRemoveNodeMarkStep = trackRemoveNodeMarkStep;
5
+ exports.trackAddMarkStep = trackAddMarkStep;
6
+ exports.trackAddNodeMarkStep = trackAddNodeMarkStep;
7
+ const prosemirror_transform_1 = require("prosemirror-transform");
8
+ const change_1 = require("../types/change");
9
+ const track_utils_1 = require("../utils/track-utils");
10
+ const uuidv4_1 = require("../utils/uuidv4");
11
+ function markHasOp(mark, operation) {
12
+ if (mark.attrs.dataTracked && Array.isArray(mark.attrs.dataTracked)) {
13
+ const dtAttrs = mark.attrs.dataTracked;
14
+ return dtAttrs.some((at) => at.operation === operation);
15
+ }
16
+ }
17
+ function trackRemoveMarkStep(step, emptyAttrs, newTr, doc) {
18
+ if ((0, track_utils_1.isValidTrackableMark)(step.mark)) {
19
+ const markName = step.mark.type.name;
20
+ const markSource = step.mark.type.schema.marks[step.mark.type.name];
21
+ let sameMark = null;
22
+ const targetNode = doc.nodeAt(step.from);
23
+ if (targetNode) {
24
+ let targetNodePos = -1;
25
+ doc.descendants((node, pos) => {
26
+ if (node === targetNode) {
27
+ targetNodePos = pos;
28
+ }
29
+ if (targetNodePos >= 0) {
30
+ return false;
31
+ }
32
+ });
33
+ const parentsSameMark = targetNode.marks.find((mark) => {
34
+ var _a;
35
+ if (mark.type.name === markName && ((_a = mark.attrs.dataTracked) === null || _a === void 0 ? void 0 : _a.length)) {
36
+ return mark;
37
+ }
38
+ });
39
+ const nodeEnd = targetNodePos + targetNode.nodeSize;
40
+ if (parentsSameMark && step.from <= nodeEnd && step.to <= nodeEnd) {
41
+ sameMark = parentsSameMark;
42
+ }
43
+ }
44
+ const newDataTracked = (0, track_utils_1.createNewDeleteAttrs)(emptyAttrs);
45
+ const newMark = markSource.create({
46
+ dataTracked: [Object.assign(Object.assign({}, newDataTracked), { id: (0, uuidv4_1.uuidv4)() })],
47
+ });
48
+ let newStep = new prosemirror_transform_1.AddMarkStep(step.from, step.to, newMark);
49
+ if (sameMark) {
50
+ if (markHasOp(step.mark, change_1.CHANGE_OPERATION.delete)) {
51
+ newStep = new prosemirror_transform_1.AddMarkStep(step.from, step.to, markSource.create({
52
+ dataTracked: [],
53
+ }));
54
+ }
55
+ if (markHasOp(step.mark, change_1.CHANGE_OPERATION.insert)) {
56
+ newStep = new prosemirror_transform_1.RemoveMarkStep(step.from, step.to, step.mark);
57
+ }
58
+ }
59
+ try {
60
+ newTr.step(newStep);
61
+ }
62
+ catch (e) {
63
+ console.error('Unable to record a RemoveMarkStep with error: ' + e);
64
+ }
65
+ }
66
+ }
67
+ function trackRemoveNodeMarkStep(step, emptyAttrs, newTr, doc) {
68
+ if ((0, track_utils_1.isValidTrackableMark)(step.mark)) {
69
+ const markName = step.mark.type.name;
70
+ const markSource = step.mark.type.schema.marks[markName];
71
+ let sameMark = null;
72
+ const targetNode = doc.nodeAt(step.pos);
73
+ if (targetNode) {
74
+ targetNode.marks.find((mark) => {
75
+ var _a;
76
+ if (mark.type.name === markName && ((_a = mark.attrs.dataTracked) === null || _a === void 0 ? void 0 : _a.length)) {
77
+ sameMark = mark;
78
+ }
79
+ });
80
+ }
81
+ const newDataTracked = (0, track_utils_1.createNewDeleteAttrs)(emptyAttrs);
82
+ const newMark = markSource.create({
83
+ dataTracked: [Object.assign(Object.assign({}, newDataTracked), { id: (0, uuidv4_1.uuidv4)() })],
84
+ });
85
+ let newStep = new prosemirror_transform_1.AddNodeMarkStep(step.pos, newMark);
86
+ if (sameMark) {
87
+ if (markHasOp(step.mark, change_1.CHANGE_OPERATION.delete)) {
88
+ newStep = new prosemirror_transform_1.AddNodeMarkStep(step.pos, markSource.create({
89
+ dataTracked: [],
90
+ }));
91
+ }
92
+ if (markHasOp(step.mark, change_1.CHANGE_OPERATION.insert)) {
93
+ newStep = new prosemirror_transform_1.AddNodeMarkStep(step.pos, step.mark);
94
+ }
95
+ }
96
+ try {
97
+ newTr.step(newStep);
98
+ }
99
+ catch (e) {
100
+ console.error('Unable to record a RemoveNodeMarkStep with error: ' + e);
101
+ }
102
+ }
103
+ }
104
+ function trackAddMarkStep(step, emptyAttrs, newTr, doc) {
105
+ if ((0, track_utils_1.isValidTrackableMark)(step.mark)) {
106
+ const markName = step.mark.type.name;
107
+ const markSource = step.mark.type.schema.marks[markName];
108
+ const newDataTracked = (0, track_utils_1.createNewInsertAttrs)(emptyAttrs);
109
+ const newMark = markSource.create({
110
+ dataTracked: [Object.assign(Object.assign({}, newDataTracked), { id: (0, uuidv4_1.uuidv4)() })],
111
+ });
112
+ const newStep = new prosemirror_transform_1.AddMarkStep(step.from, step.to, newMark);
113
+ try {
114
+ const inverted = step.invert();
115
+ newTr.step(inverted);
116
+ newTr.step(newStep);
117
+ }
118
+ catch (e) {
119
+ console.error('Unable to record a remove node mark step: ' + e);
120
+ }
121
+ }
122
+ }
123
+ function trackAddNodeMarkStep(step, emptyAttrs, newTr, stepDoc) {
124
+ if ((0, track_utils_1.isValidTrackableMark)(step.mark)) {
125
+ const newDataTracked = (0, track_utils_1.createNewInsertAttrs)(emptyAttrs);
126
+ const markSource = step.mark.type.schema.marks[step.mark.type.name];
127
+ const newMark = markSource.create({
128
+ dataTracked: [Object.assign(Object.assign({}, newDataTracked), { id: (0, uuidv4_1.uuidv4)() })],
129
+ });
130
+ const newStep = new prosemirror_transform_1.AddNodeMarkStep(step.pos, newMark);
131
+ try {
132
+ const inverted = step.invert(stepDoc);
133
+ newTr.step(inverted);
134
+ newTr.step(newStep);
135
+ }
136
+ catch (e) {
137
+ console.error('Unable to record an AddNodeMarkStep with error: ' + e);
138
+ }
139
+ }
140
+ }
@@ -40,7 +40,7 @@ const setFragmentAsInserted_1 = require("../compute/setFragmentAsInserted");
40
40
  const deleteAndMergeSplitNodes_1 = require("../mutate/deleteAndMergeSplitNodes");
41
41
  const logger_1 = require("../utils/logger");
42
42
  const trackUtils = __importStar(require("../utils/track-utils"));
43
- const track_utils_1 = require("../utils/track-utils");
43
+ const utils_1 = require("./utils");
44
44
  function preserveDataTrackedFromPreviousStep(newTr, step, newStep) {
45
45
  const prevDoc = newTr.docs[newTr.docs.length - 2];
46
46
  if (prevDoc && (step.slice.openEnd || step.slice.openStart)) {
@@ -68,7 +68,7 @@ function trackReplaceAroundStep(step, oldState, tr, newTr, attrs, currentStepDoc
68
68
  logger_1.log.info('RETAINED GAP CONTENT', gap);
69
69
  let { sliceWasSplit, newSliceContent, steps: deleteSteps, } = (0, deleteAndMergeSplitNodes_1.deleteAndMergeSplitNodes)(from, to, { start: gapFrom, end: gapTo, slice: gap, insert }, newTr.doc, newTr, oldState.schema, attrs, slice);
70
70
  let fragment;
71
- if ((0, track_utils_1.isWrapStep)(step)) {
71
+ if ((0, utils_1.isWrapStep)(step)) {
72
72
  fragment = (0, setFragmentAsInserted_1.setFragmentAsWrapChange)(newSliceContent, attrs, oldState.schema);
73
73
  }
74
74
  else {
@@ -77,7 +77,7 @@ function trackReplaceAroundStep(step, oldState, tr, newTr, attrs, currentStepDoc
77
77
  let steps = deleteSteps;
78
78
  logger_1.log.info('TR: new steps after applying delete', [...newTr.steps]);
79
79
  logger_1.log.info('DELETE STEPS: ', deleteSteps);
80
- let liftStep = (0, track_utils_1.isLiftStep)(step);
80
+ let liftStep = (0, utils_1.isLiftStep)(step);
81
81
  if (liftStep) {
82
82
  logger_1.log.info('DETECTING INIT LIFT STEP: ', step);
83
83
  trContext.prevLiftStep = step;
@@ -41,7 +41,7 @@ const deleteAndMergeSplitNodes_1 = require("../mutate/deleteAndMergeSplitNodes")
41
41
  const dropStructureChange_1 = require("../mutate/dropStructureChange");
42
42
  const logger_1 = require("../utils/logger");
43
43
  const trackUtils = __importStar(require("../utils/track-utils"));
44
- const track_utils_1 = require("../utils/track-utils");
44
+ const utils_1 = require("./utils");
45
45
  function trackReplaceStep(step, oldState, newTr, attrsTemplate, stepResult, currentStepDoc, tr, moveID) {
46
46
  logger_1.log.info('###### ReplaceStep ######');
47
47
  let selectionPos = 0;
@@ -78,10 +78,10 @@ function trackReplaceStep(step, oldState, newTr, attrsTemplate, stepResult, curr
78
78
  if (!backSpacedText && newSliceContent.size > 0) {
79
79
  logger_1.log.info('newSliceContent', newSliceContent);
80
80
  let fragment = (0, setFragmentAsInserted_1.setFragmentAsInserted)(newSliceContent, trackUtils.createNewInsertAttrs(attrs), oldState.schema);
81
- if ((0, track_utils_1.isStructureSteps)(tr)) {
81
+ if ((0, utils_1.isStructureSteps)(tr)) {
82
82
  fragment = (0, dropStructureChange_1.joinStructureChanges)(attrs, newSliceContent, fragment, tr, newTr);
83
83
  }
84
- else if ((0, track_utils_1.isSplitStep)(step, oldState.selection, tr.getMeta('uiEvent'))) {
84
+ else if ((0, utils_1.isSplitStep)(step, oldState.selection, tr.getMeta('uiEvent'))) {
85
85
  fragment = (0, setFragmentAsInserted_1.setFragmentAsNodeSplit)(newTr.doc.resolve(step.from), newTr, fragment, attrs);
86
86
  }
87
87
  else if (moveID) {
@@ -17,8 +17,10 @@ const mapChangeStep_1 = require("../utils/mapChangeStep");
17
17
  const track_utils_1 = require("../utils/track-utils");
18
18
  const uuidv4_1 = require("../utils/uuidv4");
19
19
  const trackAttrsChange_1 = __importDefault(require("./trackAttrsChange"));
20
+ const trackMarkSteps_1 = require("./trackMarkSteps");
20
21
  const trackReplaceAroundStep_1 = require("./trackReplaceAroundStep");
21
22
  const trackReplaceStep_1 = require("./trackReplaceStep");
23
+ const utils_1 = require("./utils");
22
24
  const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
23
25
  const isHighlightMarkerNode = (node) => node && node.type === node.type.schema.nodes.highlight_marker;
24
26
  function trackTransaction(tr, oldState, newTr, authorID, changeSet) {
@@ -74,7 +76,7 @@ function trackTransaction(tr, oldState, newTr, authorID, changeSet) {
74
76
  const invertedStep = step.invert(tr.docs[i]);
75
77
  const isDelete = step.from !== step.to && step.slice.content.size < invertedStep.slice.content.size;
76
78
  let thisStepMapping = tr.mapping.slice(i + 1, i + 1);
77
- if (isDelete || (0, track_utils_1.isStructureSteps)(tr)) {
79
+ if (isDelete || (0, utils_1.isStructureSteps)(tr)) {
78
80
  thisStepMapping = deletedNodeMapping;
79
81
  }
80
82
  const newStep = new prosemirror_transform_1.ReplaceStep(thisStepMapping.map(invertedStep.from), thisStepMapping.map(invertedStep.to), invertedStep.slice);
@@ -115,17 +117,27 @@ function trackTransaction(tr, oldState, newTr, authorID, changeSet) {
115
117
  const [mapping, selectionPos] = (0, processChangeSteps_1.processChangeSteps)(changeSteps, tr.selection.from, newTr, emptyAttrs, oldState.schema, deletedNodeMapping);
116
118
  }
117
119
  else if (step instanceof prosemirror_transform_1.AddMarkStep) {
120
+ (0, trackMarkSteps_1.trackAddMarkStep)(step, emptyAttrs, newTr, tr.docs[i]);
118
121
  const dataTracked = (_f = (0, nodeHelpers_1.getNodeTrackedData)(newTr.doc.nodeAt(step.from), oldState.schema)) === null || _f === void 0 ? void 0 : _f.pop();
119
122
  if (dataTracked) {
120
123
  (0, updateChangeAttrs_1.updateChangeAttrs)(newTr, { id: dataTracked.id, from: step.from, to: step.to, type: 'text-change', dataTracked }, Object.assign(Object.assign({}, dataTracked), { id: (0, uuidv4_1.uuidv4)() }), oldState.schema);
121
124
  }
122
125
  }
126
+ else if (step instanceof prosemirror_transform_1.RemoveMarkStep) {
127
+ (0, trackMarkSteps_1.trackRemoveMarkStep)(step, emptyAttrs, newTr, tr.docs[i]);
128
+ }
129
+ else if (step instanceof prosemirror_transform_1.RemoveNodeMarkStep) {
130
+ (0, trackMarkSteps_1.trackRemoveNodeMarkStep)(step, emptyAttrs, newTr, tr.docs[i]);
131
+ }
132
+ else if (step instanceof prosemirror_transform_1.AddNodeMarkStep) {
133
+ (0, trackMarkSteps_1.trackAddNodeMarkStep)(step, emptyAttrs, newTr, tr.docs[i]);
134
+ }
123
135
  tr.getMeta('inputType') && newTr.setMeta('inputType', tr.getMeta('inputType'));
124
136
  tr.getMeta('uiEvent') && newTr.setMeta('uiEvent', tr.getMeta('uiEvent'));
125
137
  }
126
138
  if (setsNewSelection && tr.selection instanceof prosemirror_state_1.TextSelection) {
127
139
  let from = tr.selection.from;
128
- if ((0, track_utils_1.isStructureSteps)(tr)) {
140
+ if ((0, utils_1.isStructureSteps)(tr)) {
129
141
  const selectionMapping = new prosemirror_transform_1.Mapping();
130
142
  tr.steps.map((step) => {
131
143
  const isDeleteStep = step instanceof prosemirror_transform_1.ReplaceStep && step.from !== step.to && step.slice.size === 0;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ /*!
3
+ * © 2023 Atypon Systems LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.isStructureSteps = exports.isLiftStep = exports.isWrapStep = exports.isSplitStep = void 0;
19
+ exports.stepIsLift = stepIsLift;
20
+ const prosemirror_transform_1 = require("prosemirror-transform");
21
+ const actions_1 = require("../actions");
22
+ const isSplitStep = (step, selection, uiEvent) => {
23
+ var _a, _b, _c, _d;
24
+ const { from, to, slice } = step;
25
+ if (from !== to ||
26
+ slice.content.childCount < 2 ||
27
+ (((_a = slice.content.firstChild) === null || _a === void 0 ? void 0 : _a.isInline) && ((_b = slice.content.lastChild) === null || _b === void 0 ? void 0 : _b.isInline))) {
28
+ return false;
29
+ }
30
+ const { $anchor: { parentOffset: startOffset }, $head: { parentOffset: endOffset }, $from, } = selection;
31
+ const parentSize = $from.node().content.size;
32
+ if (uiEvent === 'paste') {
33
+ return !((startOffset === 0 && endOffset === 0) ||
34
+ (startOffset === parentSize && endOffset === parentSize));
35
+ }
36
+ const { content: { firstChild, lastChild }, openStart, openEnd, } = slice;
37
+ if ((((_c = window.event) === null || _c === void 0 ? void 0 : _c.code) === 'Enter' || ((_d = window.event) === null || _d === void 0 ? void 0 : _d.code) === 'NumpadEnter') &&
38
+ (firstChild === null || firstChild === void 0 ? void 0 : firstChild.type.name) === 'list_item') {
39
+ return !(parentSize === startOffset && parentSize === endOffset) && (lastChild === null || lastChild === void 0 ? void 0 : lastChild.type.name) === 'list_item';
40
+ }
41
+ return (openStart === openEnd &&
42
+ firstChild.type === lastChild.type &&
43
+ firstChild.inlineContent &&
44
+ lastChild.inlineContent &&
45
+ !(startOffset === parentSize && endOffset === parentSize));
46
+ };
47
+ exports.isSplitStep = isSplitStep;
48
+ const isWrapStep = (step) => step.from === step.gapFrom &&
49
+ step.to === step.gapTo &&
50
+ step.slice.openStart === 0 &&
51
+ step.slice.openEnd === 0;
52
+ exports.isWrapStep = isWrapStep;
53
+ const isLiftStep = (step) => {
54
+ if (step.from < step.gapFrom &&
55
+ step.to > step.gapTo &&
56
+ step.slice.size === 0 &&
57
+ step.gapTo - step.gapFrom > 0) {
58
+ return true;
59
+ }
60
+ return false;
61
+ };
62
+ exports.isLiftStep = isLiftStep;
63
+ function stepIsLift(gap, node, to) {
64
+ return gap.start < gap.end && gap.insert === 0 && gap.end === to && !node.isText;
65
+ }
66
+ const isStructureSteps = (tr) => tr.getMeta(actions_1.TrackChangesAction.structuralChangeAction) &&
67
+ tr.steps.length === 2 &&
68
+ tr.steps[0] instanceof prosemirror_transform_1.ReplaceStep &&
69
+ tr.steps[1] instanceof prosemirror_transform_1.ReplaceStep;
70
+ exports.isStructureSteps = isStructureSteps;