@manuscripts/track-changes-plugin 1.10.7 → 1.10.8-LEAN-4160.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.
@@ -91,7 +91,8 @@ class ChangeSet {
91
91
  }
92
92
  rootNodes.push([change]);
93
93
  });
94
- return rootNodes.filter((changes) => changes.filter((c) => c.dataTracked.operation !== change_1.CHANGE_OPERATION.reference).length);
94
+ return rootNodes.filter((changes) => changes.filter((c) => c.dataTracked.operation !== change_1.CHANGE_OPERATION.reference &&
95
+ !(c.dataTracked.moveNodeId && c.dataTracked.operation === change_1.CHANGE_OPERATION.delete)).length);
95
96
  }
96
97
  get pending() {
97
98
  return this.changes.filter((c) => c.dataTracked.status === change_1.CHANGE_STATUS.pending);
@@ -167,7 +168,8 @@ class ChangeSet {
167
168
  const { status, operation } = change.dataTracked;
168
169
  return (((operation === change_1.CHANGE_OPERATION.insert ||
169
170
  operation === change_1.CHANGE_OPERATION.node_split ||
170
- operation === change_1.CHANGE_OPERATION.wrap_with_node) &&
171
+ operation === change_1.CHANGE_OPERATION.wrap_with_node ||
172
+ operation === change_1.CHANGE_OPERATION.move) &&
171
173
  status === change_1.CHANGE_STATUS.rejected) ||
172
174
  (operation === change_1.CHANGE_OPERATION.delete && status === change_1.CHANGE_STATUS.accepted));
173
175
  }
@@ -20,13 +20,8 @@ exports.getUpdatedDataTracked = getUpdatedDataTracked;
20
20
  function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap = new prosemirror_transform_1.Mapping()) {
21
21
  changes.sort((c1, c2) => c1.dataTracked.updatedAt - c2.dataTracked.updatedAt);
22
22
  changes.forEach((change) => {
23
- if (change.dataTracked.status == change_1.CHANGE_STATUS.rejected) {
24
- if (change.dataTracked.operation === change_1.CHANGE_OPERATION.node_split) {
25
- return (0, revertChange_1.revertSplitNodeChange)(tr, change, changeSet);
26
- }
27
- if (change.dataTracked.operation === change_1.CHANGE_OPERATION.wrap_with_node) {
28
- return (0, revertChange_1.revertWrapNodeChange)(tr, change);
29
- }
23
+ if (change.dataTracked.operation === change_1.CHANGE_OPERATION.move) {
24
+ return;
30
25
  }
31
26
  const { pos: from, deleted } = deleteMap.mapResult(change.from);
32
27
  const node = tr.doc.nodeAt(from);
@@ -35,9 +30,17 @@ function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap
35
30
  return;
36
31
  }
37
32
  if (!node) {
38
- !deleted && logger_1.log.warn('no node found to update for change', change);
33
+ !deleted && logger_1.log.warn('No node found to update for change', change);
39
34
  return;
40
35
  }
36
+ if (change.dataTracked.status === change_1.CHANGE_STATUS.rejected) {
37
+ if (change.dataTracked.operation === change_1.CHANGE_OPERATION.node_split) {
38
+ return (0, revertChange_1.revertSplitNodeChange)(tr, change, changeSet);
39
+ }
40
+ if (change.dataTracked.operation === change_1.CHANGE_OPERATION.wrap_with_node) {
41
+ return (0, revertChange_1.revertWrapNodeChange)(tr, change);
42
+ }
43
+ }
41
44
  if (ChangeSet_1.ChangeSet.isTextChange(change) && noChangeNeeded) {
42
45
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_insert);
43
46
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_delete);
@@ -72,6 +75,40 @@ function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap
72
75
  tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
73
76
  }
74
77
  });
78
+ changes.forEach((change) => {
79
+ if (change.dataTracked.operation !== change_1.CHANGE_OPERATION.move) {
80
+ return;
81
+ }
82
+ const { pos: from, deleted } = deleteMap.mapResult(change.from);
83
+ const node = tr.doc.nodeAt(from);
84
+ if (deleted || !node) {
85
+ if (!deleted && !node) {
86
+ logger_1.log.warn('No node found for move change', { change });
87
+ }
88
+ return;
89
+ }
90
+ if (change.dataTracked.status === change_1.CHANGE_STATUS.accepted) {
91
+ const originalChange = changeSet.changes.find((c) => c.dataTracked.moveNodeId === change.dataTracked.moveNodeId &&
92
+ c.dataTracked.operation === change_1.CHANGE_OPERATION.delete);
93
+ if (originalChange) {
94
+ const { pos: originalFrom } = deleteMap.mapResult(originalChange.from);
95
+ const originalNode = tr.doc.nodeAt(originalFrom);
96
+ const attrs = Object.assign(Object.assign({}, node.attrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) });
97
+ tr.setNodeMarkup(from, undefined, attrs, node.marks);
98
+ if (originalNode) {
99
+ tr.delete(originalFrom, originalFrom + originalNode.nodeSize);
100
+ deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
101
+ }
102
+ }
103
+ else {
104
+ logger_1.log.warn('No original change found for move operation', { change });
105
+ }
106
+ }
107
+ else if (change.dataTracked.status === change_1.CHANGE_STATUS.rejected) {
108
+ tr.delete(from, from + node.nodeSize);
109
+ deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
110
+ }
111
+ });
75
112
  return deleteMap;
76
113
  }
77
114
  exports.applyAcceptedRejectedChanges = applyAcceptedRejectedChanges;
@@ -23,6 +23,7 @@ const applyChanges_1 = require("./applyChanges");
23
23
  const updateChangeAttrs_1 = require("./updateChangeAttrs");
24
24
  function updateChangesStatus(createdTr, changeSet, ids, status, userID, oldState) {
25
25
  const change = changeSet.get(ids[0]);
26
+ const changeTime = new Date().getTime();
26
27
  if (change && status !== change_1.CHANGE_STATUS.pending) {
27
28
  const textChanges = [];
28
29
  const nonTextChanges = [];
@@ -40,6 +41,24 @@ function updateChangesStatus(createdTr, changeSet, ids, status, userID, oldState
40
41
  nonTextChanges.push(relatedRefChange);
41
42
  }
42
43
  }
44
+ if (c.dataTracked.operation === change_1.CHANGE_OPERATION.move) {
45
+ const oldChange = changeSet.changeTree.find((c) => ChangeSet_1.ChangeSet.isNodeChange(c) &&
46
+ c.dataTracked.operation === 'delete' &&
47
+ c.dataTracked.moveNodeId === change.dataTracked.moveNodeId);
48
+ if (oldChange && ChangeSet_1.ChangeSet.isNodeChange(oldChange)) {
49
+ createdTr = (0, updateChangeAttrs_1.updateChangeAttrs)(createdTr, oldChange, Object.assign(Object.assign({}, oldChange.dataTracked), { status, statusUpdateAt: changeTime, reviewedByID: userID }), oldState.schema);
50
+ oldChange.children.forEach((child) => {
51
+ createdTr = (0, updateChangeAttrs_1.updateChangeAttrs)(createdTr, child, Object.assign(Object.assign({}, child.dataTracked), { status, statusUpdateAt: changeTime, reviewedByID: userID }), oldState.schema);
52
+ if (ChangeSet_1.ChangeSet.isTextChange(child)) {
53
+ textChanges.push(child);
54
+ }
55
+ else {
56
+ nonTextChanges.push(child);
57
+ }
58
+ });
59
+ nonTextChanges.push(oldChange);
60
+ }
61
+ }
43
62
  }
44
63
  }
45
64
  });
@@ -47,7 +66,6 @@ function updateChangesStatus(createdTr, changeSet, ids, status, userID, oldState
47
66
  (0, applyChanges_1.applyAcceptedRejectedChanges)(createdTr, oldState.schema, textChanges, changeSet, mapping);
48
67
  }
49
68
  else {
50
- const changeTime = new Date().getTime();
51
69
  ids.forEach((changeId) => {
52
70
  const change = changeSet === null || changeSet === void 0 ? void 0 : changeSet.get(changeId);
53
71
  if (change) {
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.setFragmentAsNodeSplit = exports.setFragmentAsWrapChange = exports.setFragmentAsInserted = void 0;
26
+ exports.setFragmentAsNodeSplit = exports.setFragmentAsMoveChange = exports.setFragmentAsWrapChange = exports.setFragmentAsInserted = void 0;
27
27
  const prosemirror_model_1 = require("prosemirror-model");
28
28
  const change_1 = require("../types/change");
29
29
  const logger_1 = require("../utils/logger");
@@ -84,6 +84,14 @@ function setFragmentAsWrapChange(inserted, attrs, schema) {
84
84
  return prosemirror_model_1.Fragment.from(content);
85
85
  }
86
86
  exports.setFragmentAsWrapChange = setFragmentAsWrapChange;
87
+ function setFragmentAsMoveChange(fragment, attrs) {
88
+ const content = [];
89
+ fragment.forEach((node) => {
90
+ content.push(node.type.create(Object.assign(Object.assign({}, node.attrs), { dataTracked: [(0, nodeHelpers_1.addTrackIdIfDoesntExist)(trackUtils.createNewMoveAttrs(attrs))] }), node.content, node.marks));
91
+ });
92
+ return prosemirror_model_1.Fragment.from(content);
93
+ }
94
+ exports.setFragmentAsMoveChange = setFragmentAsMoveChange;
87
95
  function setFragmentAsNodeSplit($pos, newTr, inserted, attrs) {
88
96
  const lastChild = inserted.lastChild;
89
97
  const referenceId = (0, uuidv4_1.uuidv4)();
@@ -100,7 +100,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous', initialStatu
100
100
  !skipTrackUsed &&
101
101
  !(0, track_utils_1.trFromHistory)(tr) &&
102
102
  !(wasAppended && tr.getMeta('origin') === 'paragraphs')) {
103
- createdTr = (0, trackTransaction_1.trackTransaction)(tr, oldState, createdTr, userID);
103
+ createdTr = (0, trackTransaction_1.trackTransaction)(tr, oldState, createdTr, userID, changeSet);
104
104
  }
105
105
  docChanged = docChanged || tr.docChanged;
106
106
  if (setChangeStatuses) {
@@ -30,10 +30,15 @@ const deleteAndMergeSplitNodes_1 = require("../mutate/deleteAndMergeSplitNodes")
30
30
  const logger_1 = require("../utils/logger");
31
31
  const trackUtils = __importStar(require("../utils/track-utils"));
32
32
  const track_utils_1 = require("../utils/track-utils");
33
- function trackReplaceStep(step, oldState, newTr, attrs, stepResult, currentStepDoc, tr) {
33
+ function trackReplaceStep(step, oldState, newTr, attrsTemplate, stepResult, currentStepDoc, tr, moveID) {
34
34
  logger_1.log.info('###### ReplaceStep ######');
35
35
  let selectionPos = 0;
36
36
  const changeSteps = [];
37
+ const attrs = Object.assign({}, attrsTemplate);
38
+ if (moveID) {
39
+ console.log('Detected Node Moving ReplaceStep and assigning the following movenodeID: ' + moveID);
40
+ attrs.moveNodeId = moveID;
41
+ }
37
42
  step.getMap().forEach((fromA, toA, fromB, toB) => {
38
43
  var _a, _b;
39
44
  logger_1.log.info(`changed ranges: ${fromA} ${toA} ${fromB} ${toB}`);
@@ -60,13 +65,15 @@ function trackReplaceStep(step, oldState, newTr, attrs, stepResult, currentStepD
60
65
  changeSteps.splice(changeSteps.indexOf(backSpacedText));
61
66
  }
62
67
  const textWasDeleted = !!changeSteps.length && !(fromA === fromB);
63
- console.log(textWasDeleted);
64
68
  if (!backSpacedText && newSliceContent.size > 0) {
65
69
  logger_1.log.info('newSliceContent', newSliceContent);
66
70
  let fragment = (0, setFragmentAsInserted_1.setFragmentAsInserted)(newSliceContent, trackUtils.createNewInsertAttrs(attrs), oldState.schema);
67
71
  if ((0, track_utils_1.isSplitStep)(step, oldState.selection, tr.getMeta('uiEvent'))) {
68
72
  fragment = (0, setFragmentAsInserted_1.setFragmentAsNodeSplit)(newTr.doc.resolve(step.from), newTr, fragment, attrs);
69
73
  }
74
+ if (moveID) {
75
+ fragment = (0, setFragmentAsInserted_1.setFragmentAsMoveChange)(newSliceContent, trackUtils.createNewMoveAttrs(attrs));
76
+ }
70
77
  const openStart = slice.openStart !== slice.openEnd ? 0 : slice.openStart;
71
78
  const openEnd = slice.openStart !== slice.openEnd ? 0 : slice.openEnd;
72
79
  changeSteps.push({
@@ -13,13 +13,28 @@ const nodeHelpers_1 = require("../compute/nodeHelpers");
13
13
  const change_1 = require("../types/change");
14
14
  const logger_1 = require("../utils/logger");
15
15
  const mapChangeStep_1 = require("../utils/mapChangeStep");
16
+ const track_utils_1 = require("../utils/track-utils");
16
17
  const uuidv4_1 = require("../utils/uuidv4");
17
18
  const trackAttrsChange_1 = __importDefault(require("./trackAttrsChange"));
18
19
  const trackReplaceAroundStep_1 = require("./trackReplaceAroundStep");
19
20
  const trackReplaceStep_1 = require("./trackReplaceStep");
20
21
  const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
21
22
  const isHighlightMarkerNode = (node) => node && node.type === node.type.schema.nodes.highlight_marker;
22
- function trackTransaction(tr, oldState, newTr, authorID) {
23
+ function isSimplePendingMoveDeletion(step, doc, movingSteps) {
24
+ if (step.from === step.to || step.slice.content.size > 0) {
25
+ return false;
26
+ }
27
+ if (movingSteps.has(step)) {
28
+ return false;
29
+ }
30
+ const node = doc.nodeAt(step.from);
31
+ if (!node) {
32
+ return false;
33
+ }
34
+ const trackedAttrs = node.attrs.dataTracked;
35
+ return !!(trackedAttrs === null || trackedAttrs === void 0 ? void 0 : trackedAttrs.some((t) => t.operation === change_1.CHANGE_OPERATION.move && t.status === change_1.CHANGE_STATUS.pending));
36
+ }
37
+ function trackTransaction(tr, oldState, newTr, authorID, changeSet) {
23
38
  var _a, _b, _c, _d, _e;
24
39
  const emptyAttrs = {
25
40
  authorID,
@@ -35,7 +50,37 @@ function trackTransaction(tr, oldState, newTr, authorID) {
35
50
  let iters = 0;
36
51
  logger_1.log.info('ORIGINAL transaction', tr);
37
52
  let trContext = {};
38
- for (let i = tr.steps.length - 1; i >= 0; i--) {
53
+ const movingStepsAssociated = (0, track_utils_1.HasMoveOperations)(tr);
54
+ tr.steps.forEach((step) => {
55
+ var _a;
56
+ if (step instanceof prosemirror_transform_1.ReplaceStep) {
57
+ const doc = tr.docs[tr.steps.indexOf(step)];
58
+ if (isSimplePendingMoveDeletion(step, doc, movingStepsAssociated)) {
59
+ const node = doc.nodeAt(step.from);
60
+ (_a = node === null || node === void 0 ? void 0 : node.attrs.dataTracked) === null || _a === void 0 ? void 0 : _a.forEach((tracked) => {
61
+ if (tracked.operation === change_1.CHANGE_OPERATION.move && tracked.status === change_1.CHANGE_STATUS.pending) {
62
+ newTr.setNodeMarkup(step.from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: node.attrs.dataTracked.map((t) => t.id === tracked.id ? Object.assign(Object.assign({}, t), { status: change_1.CHANGE_STATUS.rejected }) : t) }));
63
+ }
64
+ });
65
+ }
66
+ }
67
+ });
68
+ const cleanSteps = [];
69
+ for (let i = 0; i < tr.steps.length; i++) {
70
+ const step = tr.steps[i];
71
+ const moveID = movingStepsAssociated.get(step);
72
+ const prevMoveID = (0, track_utils_1.isDeletingPendingMovedNode)(step, tr.docs[i]);
73
+ if (moveID && prevMoveID) {
74
+ movingStepsAssociated.forEach((replaceStepMoveID, replaceStep) => {
75
+ if (replaceStep !== step && moveID === replaceStepMoveID) {
76
+ movingStepsAssociated.set(replaceStep, prevMoveID);
77
+ }
78
+ });
79
+ continue;
80
+ }
81
+ cleanSteps.push(step);
82
+ }
83
+ for (let i = cleanSteps.length - 1; i >= 0; i--) {
39
84
  const step = tr.steps[i];
40
85
  logger_1.log.info('transaction step', step);
41
86
  iters += 1;
@@ -64,7 +109,7 @@ function trackTransaction(tr, oldState, newTr, authorID) {
64
109
  }
65
110
  const newStep = new prosemirror_transform_1.ReplaceStep(thisStepMapping.map(invertedStep.from), thisStepMapping.map(invertedStep.to), invertedStep.slice);
66
111
  const stepResult = newTr.maybeStep(newStep);
67
- let [steps, startPos] = (0, trackReplaceStep_1.trackReplaceStep)(step, oldState, newTr, emptyAttrs, stepResult, tr.docs[i], tr);
112
+ let [steps, startPos] = (0, trackReplaceStep_1.trackReplaceStep)(step, oldState, newTr, emptyAttrs, stepResult, tr.docs[i], tr, movingStepsAssociated.get(step));
68
113
  if (steps.length === 1) {
69
114
  const step = steps[0];
70
115
  if (isHighlightMarkerNode((step === null || step === void 0 ? void 0 : step.node) || ((_d = (_c = step === null || step === void 0 ? void 0 : step.slice) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.content[0]))) {
@@ -78,7 +123,8 @@ function trackTransaction(tr, oldState, newTr, authorID) {
78
123
  const inserted = steps.filter((s) => s.type === 'insert-slice');
79
124
  steps = (0, diffChangeSteps_1.diffChangeSteps)(deleted, inserted);
80
125
  logger_1.log.info('DIFFED STEPS: ', steps);
81
- const [mapping, selectionPos] = (0, processChangeSteps_1.processChangeSteps)(steps, startPos || tr.selection.head, newTr, emptyAttrs, oldState.schema, deletedNodeMapping);
126
+ const [mapping, selectionPos] = (0, processChangeSteps_1.processChangeSteps)(steps, startPos || tr.selection.head, newTr, movingStepsAssociated.has(step)
127
+ ? Object.assign(Object.assign({}, emptyAttrs), { moveNodeId: movingStepsAssociated.get(step) }) : emptyAttrs, oldState.schema, deletedNodeMapping);
82
128
  if (!wasNodeSelection && !setsNewSelection) {
83
129
  const sel = getSelectionStaticConstructor(tr.selection);
84
130
  const near = sel.near(newTr.doc.resolve(selectionPos), -1);
@@ -24,6 +24,7 @@ var CHANGE_OPERATION;
24
24
  CHANGE_OPERATION["wrap_with_node"] = "wrap_with_node";
25
25
  CHANGE_OPERATION["node_split"] = "node_split";
26
26
  CHANGE_OPERATION["reference"] = "reference";
27
+ CHANGE_OPERATION["move"] = "move";
27
28
  })(CHANGE_OPERATION = exports.CHANGE_OPERATION || (exports.CHANGE_OPERATION = {}));
28
29
  var CHANGE_STATUS;
29
30
  (function (CHANGE_STATUS) {
@@ -11,8 +11,9 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  return t;
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.trFromHistory = exports.stepIsLift = exports.isLiftStep = exports.isWrapStep = exports.isSplitStep = exports.createNewUpdateAttrs = exports.createNewDeleteAttrs = exports.createNewReferenceAttrs = exports.createNewSplitAttrs = exports.createNewWrapAttrs = exports.createNewInsertAttrs = void 0;
14
+ exports.isDeletingPendingMovedNode = exports.HasMoveOperations = exports.trFromHistory = exports.stepIsLift = exports.isLiftStep = exports.isWrapStep = exports.isSplitStep = exports.createNewUpdateAttrs = exports.createNewMoveAttrs = exports.createNewDeleteAttrs = exports.createNewReferenceAttrs = exports.createNewSplitAttrs = exports.createNewWrapAttrs = exports.createNewInsertAttrs = void 0;
15
15
  const change_1 = require("../types/change");
16
+ const uuidv4_1 = require("./uuidv4");
16
17
  function createNewInsertAttrs(attrs) {
17
18
  return Object.assign(Object.assign({}, attrs), { operation: change_1.CHANGE_OPERATION.insert });
18
19
  }
@@ -33,6 +34,10 @@ function createNewDeleteAttrs(attrs) {
33
34
  return Object.assign(Object.assign({}, attrs), { operation: change_1.CHANGE_OPERATION.delete });
34
35
  }
35
36
  exports.createNewDeleteAttrs = createNewDeleteAttrs;
37
+ function createNewMoveAttrs(attrs) {
38
+ return Object.assign(Object.assign({}, attrs), { operation: change_1.CHANGE_OPERATION.move });
39
+ }
40
+ exports.createNewMoveAttrs = createNewMoveAttrs;
36
41
  function createNewUpdateAttrs(attrs, oldAttrs) {
37
42
  const { dataTracked } = oldAttrs, restAttrs = __rest(oldAttrs, ["dataTracked"]);
38
43
  return Object.assign(Object.assign({}, attrs), { operation: change_1.CHANGE_OPERATION.set_node_attributes, oldAttrs: JSON.parse(JSON.stringify(restAttrs)) });
@@ -84,3 +89,71 @@ function stepIsLift(gap, node, to) {
84
89
  exports.stepIsLift = stepIsLift;
85
90
  const trFromHistory = (tr) => Object.keys(tr.meta).find((s) => s.startsWith('history$'));
86
91
  exports.trFromHistory = trFromHistory;
92
+ const HasMoveOperations = (tr) => {
93
+ const movingAssoc = new Map();
94
+ if (tr.steps.length < 2) {
95
+ return movingAssoc;
96
+ }
97
+ const matched = [];
98
+ for (let i = 0; i < tr.steps.length; i++) {
99
+ if (matched.includes(i)) {
100
+ continue;
101
+ }
102
+ const step = tr.steps[i];
103
+ const doc = tr.docs[i];
104
+ const stepDeletesContent = step.from !== step.to && step.slice.size === 0;
105
+ const stepInsertsContent = step.slice.size && step.slice.content.firstChild ? true : false;
106
+ console.log('stepDeletesContent', stepDeletesContent);
107
+ console.log('stepInsertsContent', stepInsertsContent);
108
+ for (let g = 0; g < tr.steps.length; g++) {
109
+ if (g === i || matched.includes(g)) {
110
+ continue;
111
+ }
112
+ const peerStep = tr.steps[g];
113
+ const peerStepInsertsContent = peerStep.slice.size && peerStep.slice.content.firstChild;
114
+ const peerStepDeletesContent = peerStep.from !== peerStep.to && peerStep.slice.size === 0;
115
+ if (stepDeletesContent) {
116
+ const deletedContent = doc.slice(step.from, step.to);
117
+ if (peerStepInsertsContent &&
118
+ deletedContent.content.firstChild &&
119
+ peerStep.slice.content.firstChild.toString() === deletedContent.content.firstChild.toString()) {
120
+ const commonID = (0, uuidv4_1.uuidv4)();
121
+ movingAssoc.set(peerStep, commonID);
122
+ movingAssoc.set(step, commonID);
123
+ matched.push(i, g);
124
+ }
125
+ continue;
126
+ }
127
+ if (stepInsertsContent && peerStepDeletesContent) {
128
+ const insertedContent = step.slice;
129
+ const deletedPeerContent = tr.docs[g].slice(peerStep.from, peerStep.to);
130
+ if (insertedContent.content.firstChild &&
131
+ deletedPeerContent.content.firstChild &&
132
+ insertedContent.content.firstChild.toString() === deletedPeerContent.content.firstChild.toString()) {
133
+ const commonID = (0, uuidv4_1.uuidv4)();
134
+ movingAssoc.set(peerStep, commonID);
135
+ movingAssoc.set(step, commonID);
136
+ }
137
+ matched.push(i, g);
138
+ }
139
+ }
140
+ }
141
+ return movingAssoc;
142
+ };
143
+ exports.HasMoveOperations = HasMoveOperations;
144
+ const isDeletingPendingMovedNode = (step, doc) => {
145
+ if (!step.slice || step.from === step.to || step.slice.content.size > 0) {
146
+ return undefined;
147
+ }
148
+ const node = doc.nodeAt(step.from);
149
+ if (!node) {
150
+ return undefined;
151
+ }
152
+ const trackedAttrs = node.attrs.dataTracked;
153
+ const found = trackedAttrs === null || trackedAttrs === void 0 ? void 0 : trackedAttrs.find((tracked) => tracked.operation === change_1.CHANGE_OPERATION.move && tracked.status === change_1.CHANGE_STATUS.pending);
154
+ if (found === null || found === void 0 ? void 0 : found.moveNodeId) {
155
+ return found.moveNodeId;
156
+ }
157
+ return undefined;
158
+ };
159
+ exports.isDeletingPendingMovedNode = isDeletingPendingMovedNode;
@@ -88,7 +88,8 @@ export class ChangeSet {
88
88
  }
89
89
  rootNodes.push([change]);
90
90
  });
91
- return rootNodes.filter((changes) => changes.filter((c) => c.dataTracked.operation !== CHANGE_OPERATION.reference).length);
91
+ return rootNodes.filter((changes) => changes.filter((c) => c.dataTracked.operation !== CHANGE_OPERATION.reference &&
92
+ !(c.dataTracked.moveNodeId && c.dataTracked.operation === CHANGE_OPERATION.delete)).length);
92
93
  }
93
94
  get pending() {
94
95
  return this.changes.filter((c) => c.dataTracked.status === CHANGE_STATUS.pending);
@@ -164,7 +165,8 @@ export class ChangeSet {
164
165
  const { status, operation } = change.dataTracked;
165
166
  return (((operation === CHANGE_OPERATION.insert ||
166
167
  operation === CHANGE_OPERATION.node_split ||
167
- operation === CHANGE_OPERATION.wrap_with_node) &&
168
+ operation === CHANGE_OPERATION.wrap_with_node ||
169
+ operation === CHANGE_OPERATION.move) &&
168
170
  status === CHANGE_STATUS.rejected) ||
169
171
  (operation === CHANGE_OPERATION.delete && status === CHANGE_STATUS.accepted));
170
172
  }
@@ -16,13 +16,8 @@ export function getUpdatedDataTracked(dataTracked, changeId) {
16
16
  export function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, deleteMap = new Mapping()) {
17
17
  changes.sort((c1, c2) => c1.dataTracked.updatedAt - c2.dataTracked.updatedAt);
18
18
  changes.forEach((change) => {
19
- if (change.dataTracked.status == CHANGE_STATUS.rejected) {
20
- if (change.dataTracked.operation === CHANGE_OPERATION.node_split) {
21
- return revertSplitNodeChange(tr, change, changeSet);
22
- }
23
- if (change.dataTracked.operation === CHANGE_OPERATION.wrap_with_node) {
24
- return revertWrapNodeChange(tr, change);
25
- }
19
+ if (change.dataTracked.operation === CHANGE_OPERATION.move) {
20
+ return;
26
21
  }
27
22
  const { pos: from, deleted } = deleteMap.mapResult(change.from);
28
23
  const node = tr.doc.nodeAt(from);
@@ -31,9 +26,17 @@ export function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, del
31
26
  return;
32
27
  }
33
28
  if (!node) {
34
- !deleted && log.warn('no node found to update for change', change);
29
+ !deleted && log.warn('No node found to update for change', change);
35
30
  return;
36
31
  }
32
+ if (change.dataTracked.status === CHANGE_STATUS.rejected) {
33
+ if (change.dataTracked.operation === CHANGE_OPERATION.node_split) {
34
+ return revertSplitNodeChange(tr, change, changeSet);
35
+ }
36
+ if (change.dataTracked.operation === CHANGE_OPERATION.wrap_with_node) {
37
+ return revertWrapNodeChange(tr, change);
38
+ }
39
+ }
37
40
  if (ChangeSet.isTextChange(change) && noChangeNeeded) {
38
41
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_insert);
39
42
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_delete);
@@ -68,5 +71,39 @@ export function applyAcceptedRejectedChanges(tr, schema, changes, changeSet, del
68
71
  tr.setNodeMarkup(from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }), node.marks);
69
72
  }
70
73
  });
74
+ changes.forEach((change) => {
75
+ if (change.dataTracked.operation !== CHANGE_OPERATION.move) {
76
+ return;
77
+ }
78
+ const { pos: from, deleted } = deleteMap.mapResult(change.from);
79
+ const node = tr.doc.nodeAt(from);
80
+ if (deleted || !node) {
81
+ if (!deleted && !node) {
82
+ log.warn('No node found for move change', { change });
83
+ }
84
+ return;
85
+ }
86
+ if (change.dataTracked.status === CHANGE_STATUS.accepted) {
87
+ const originalChange = changeSet.changes.find((c) => c.dataTracked.moveNodeId === change.dataTracked.moveNodeId &&
88
+ c.dataTracked.operation === CHANGE_OPERATION.delete);
89
+ if (originalChange) {
90
+ const { pos: originalFrom } = deleteMap.mapResult(originalChange.from);
91
+ const originalNode = tr.doc.nodeAt(originalFrom);
92
+ const attrs = Object.assign(Object.assign({}, node.attrs), { dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) });
93
+ tr.setNodeMarkup(from, undefined, attrs, node.marks);
94
+ if (originalNode) {
95
+ tr.delete(originalFrom, originalFrom + originalNode.nodeSize);
96
+ deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
97
+ }
98
+ }
99
+ else {
100
+ log.warn('No original change found for move operation', { change });
101
+ }
102
+ }
103
+ else if (change.dataTracked.status === CHANGE_STATUS.rejected) {
104
+ tr.delete(from, from + node.nodeSize);
105
+ deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
106
+ }
107
+ });
71
108
  return deleteMap;
72
109
  }
@@ -20,6 +20,7 @@ import { applyAcceptedRejectedChanges } from './applyChanges';
20
20
  import { updateChangeAttrs } from './updateChangeAttrs';
21
21
  export function updateChangesStatus(createdTr, changeSet, ids, status, userID, oldState) {
22
22
  const change = changeSet.get(ids[0]);
23
+ const changeTime = new Date().getTime();
23
24
  if (change && status !== CHANGE_STATUS.pending) {
24
25
  const textChanges = [];
25
26
  const nonTextChanges = [];
@@ -37,6 +38,24 @@ export function updateChangesStatus(createdTr, changeSet, ids, status, userID, o
37
38
  nonTextChanges.push(relatedRefChange);
38
39
  }
39
40
  }
41
+ if (c.dataTracked.operation === CHANGE_OPERATION.move) {
42
+ const oldChange = changeSet.changeTree.find((c) => ChangeSet.isNodeChange(c) &&
43
+ c.dataTracked.operation === 'delete' &&
44
+ c.dataTracked.moveNodeId === change.dataTracked.moveNodeId);
45
+ if (oldChange && ChangeSet.isNodeChange(oldChange)) {
46
+ createdTr = updateChangeAttrs(createdTr, oldChange, Object.assign(Object.assign({}, oldChange.dataTracked), { status, statusUpdateAt: changeTime, reviewedByID: userID }), oldState.schema);
47
+ oldChange.children.forEach((child) => {
48
+ createdTr = updateChangeAttrs(createdTr, child, Object.assign(Object.assign({}, child.dataTracked), { status, statusUpdateAt: changeTime, reviewedByID: userID }), oldState.schema);
49
+ if (ChangeSet.isTextChange(child)) {
50
+ textChanges.push(child);
51
+ }
52
+ else {
53
+ nonTextChanges.push(child);
54
+ }
55
+ });
56
+ nonTextChanges.push(oldChange);
57
+ }
58
+ }
40
59
  }
41
60
  }
42
61
  });
@@ -44,7 +63,6 @@ export function updateChangesStatus(createdTr, changeSet, ids, status, userID, o
44
63
  applyAcceptedRejectedChanges(createdTr, oldState.schema, textChanges, changeSet, mapping);
45
64
  }
46
65
  else {
47
- const changeTime = new Date().getTime();
48
66
  ids.forEach((changeId) => {
49
67
  const change = changeSet === null || changeSet === void 0 ? void 0 : changeSet.get(changeId);
50
68
  if (change) {
@@ -56,6 +56,13 @@ export function setFragmentAsWrapChange(inserted, attrs, schema) {
56
56
  });
57
57
  return Fragment.from(content);
58
58
  }
59
+ export function setFragmentAsMoveChange(fragment, attrs) {
60
+ const content = [];
61
+ fragment.forEach((node) => {
62
+ content.push(node.type.create(Object.assign(Object.assign({}, node.attrs), { dataTracked: [addTrackIdIfDoesntExist(trackUtils.createNewMoveAttrs(attrs))] }), node.content, node.marks));
63
+ });
64
+ return Fragment.from(content);
65
+ }
59
66
  export function setFragmentAsNodeSplit($pos, newTr, inserted, attrs) {
60
67
  const lastChild = inserted.lastChild;
61
68
  const referenceId = uuidv4();
package/dist/es/plugin.js CHANGED
@@ -97,7 +97,7 @@ export const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous', initi
97
97
  !skipTrackUsed &&
98
98
  !trFromHistory(tr) &&
99
99
  !(wasAppended && tr.getMeta('origin') === 'paragraphs')) {
100
- createdTr = trackTransaction(tr, oldState, createdTr, userID);
100
+ createdTr = trackTransaction(tr, oldState, createdTr, userID, changeSet);
101
101
  }
102
102
  docChanged = docChanged || tr.docChanged;
103
103
  if (setChangeStatuses) {
@@ -1,13 +1,18 @@
1
1
  import { Slice } from 'prosemirror-model';
2
- import { setFragmentAsInserted, setFragmentAsNodeSplit } from '../compute/setFragmentAsInserted';
2
+ import { setFragmentAsInserted, setFragmentAsMoveChange, setFragmentAsNodeSplit, } from '../compute/setFragmentAsInserted';
3
3
  import { deleteAndMergeSplitNodes } from '../mutate/deleteAndMergeSplitNodes';
4
4
  import { log } from '../utils/logger';
5
5
  import * as trackUtils from '../utils/track-utils';
6
6
  import { isSplitStep } from '../utils/track-utils';
7
- export function trackReplaceStep(step, oldState, newTr, attrs, stepResult, currentStepDoc, tr) {
7
+ export function trackReplaceStep(step, oldState, newTr, attrsTemplate, stepResult, currentStepDoc, tr, moveID) {
8
8
  log.info('###### ReplaceStep ######');
9
9
  let selectionPos = 0;
10
10
  const changeSteps = [];
11
+ const attrs = Object.assign({}, attrsTemplate);
12
+ if (moveID) {
13
+ console.log('Detected Node Moving ReplaceStep and assigning the following movenodeID: ' + moveID);
14
+ attrs.moveNodeId = moveID;
15
+ }
11
16
  step.getMap().forEach((fromA, toA, fromB, toB) => {
12
17
  var _a, _b;
13
18
  log.info(`changed ranges: ${fromA} ${toA} ${fromB} ${toB}`);
@@ -34,13 +39,15 @@ export function trackReplaceStep(step, oldState, newTr, attrs, stepResult, curre
34
39
  changeSteps.splice(changeSteps.indexOf(backSpacedText));
35
40
  }
36
41
  const textWasDeleted = !!changeSteps.length && !(fromA === fromB);
37
- console.log(textWasDeleted);
38
42
  if (!backSpacedText && newSliceContent.size > 0) {
39
43
  log.info('newSliceContent', newSliceContent);
40
44
  let fragment = setFragmentAsInserted(newSliceContent, trackUtils.createNewInsertAttrs(attrs), oldState.schema);
41
45
  if (isSplitStep(step, oldState.selection, tr.getMeta('uiEvent'))) {
42
46
  fragment = setFragmentAsNodeSplit(newTr.doc.resolve(step.from), newTr, fragment, attrs);
43
47
  }
48
+ if (moveID) {
49
+ fragment = setFragmentAsMoveChange(newSliceContent, trackUtils.createNewMoveAttrs(attrs));
50
+ }
44
51
  const openStart = slice.openStart !== slice.openEnd ? 0 : slice.openStart;
45
52
  const openEnd = slice.openStart !== slice.openEnd ? 0 : slice.openEnd;
46
53
  changeSteps.push({
@@ -4,16 +4,31 @@ import { diffChangeSteps } from '../change-steps/diffChangeSteps';
4
4
  import { processChangeSteps } from '../change-steps/processChangeSteps';
5
5
  import { updateChangeAttrs } from '../changes/updateChangeAttrs';
6
6
  import { getNodeTrackedData } from '../compute/nodeHelpers';
7
- import { CHANGE_STATUS } from '../types/change';
7
+ import { CHANGE_OPERATION, CHANGE_STATUS } from '../types/change';
8
8
  import { log } from '../utils/logger';
9
9
  import { mapChangeSteps } from '../utils/mapChangeStep';
10
+ import { HasMoveOperations, isDeletingPendingMovedNode } from '../utils/track-utils';
10
11
  import { uuidv4 } from '../utils/uuidv4';
11
12
  import trackAttrsChange from './trackAttrsChange';
12
13
  import { trackReplaceAroundStep } from './trackReplaceAroundStep';
13
14
  import { trackReplaceStep } from './trackReplaceStep';
14
15
  const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
15
16
  const isHighlightMarkerNode = (node) => node && node.type === node.type.schema.nodes.highlight_marker;
16
- export function trackTransaction(tr, oldState, newTr, authorID) {
17
+ function isSimplePendingMoveDeletion(step, doc, movingSteps) {
18
+ if (step.from === step.to || step.slice.content.size > 0) {
19
+ return false;
20
+ }
21
+ if (movingSteps.has(step)) {
22
+ return false;
23
+ }
24
+ const node = doc.nodeAt(step.from);
25
+ if (!node) {
26
+ return false;
27
+ }
28
+ const trackedAttrs = node.attrs.dataTracked;
29
+ return !!(trackedAttrs === null || trackedAttrs === void 0 ? void 0 : trackedAttrs.some((t) => t.operation === CHANGE_OPERATION.move && t.status === CHANGE_STATUS.pending));
30
+ }
31
+ export function trackTransaction(tr, oldState, newTr, authorID, changeSet) {
17
32
  var _a, _b, _c, _d, _e;
18
33
  const emptyAttrs = {
19
34
  authorID,
@@ -29,7 +44,37 @@ export function trackTransaction(tr, oldState, newTr, authorID) {
29
44
  let iters = 0;
30
45
  log.info('ORIGINAL transaction', tr);
31
46
  let trContext = {};
32
- for (let i = tr.steps.length - 1; i >= 0; i--) {
47
+ const movingStepsAssociated = HasMoveOperations(tr);
48
+ tr.steps.forEach((step) => {
49
+ var _a;
50
+ if (step instanceof ReplaceStep) {
51
+ const doc = tr.docs[tr.steps.indexOf(step)];
52
+ if (isSimplePendingMoveDeletion(step, doc, movingStepsAssociated)) {
53
+ const node = doc.nodeAt(step.from);
54
+ (_a = node === null || node === void 0 ? void 0 : node.attrs.dataTracked) === null || _a === void 0 ? void 0 : _a.forEach((tracked) => {
55
+ if (tracked.operation === CHANGE_OPERATION.move && tracked.status === CHANGE_STATUS.pending) {
56
+ newTr.setNodeMarkup(step.from, undefined, Object.assign(Object.assign({}, node.attrs), { dataTracked: node.attrs.dataTracked.map((t) => t.id === tracked.id ? Object.assign(Object.assign({}, t), { status: CHANGE_STATUS.rejected }) : t) }));
57
+ }
58
+ });
59
+ }
60
+ }
61
+ });
62
+ const cleanSteps = [];
63
+ for (let i = 0; i < tr.steps.length; i++) {
64
+ const step = tr.steps[i];
65
+ const moveID = movingStepsAssociated.get(step);
66
+ const prevMoveID = isDeletingPendingMovedNode(step, tr.docs[i]);
67
+ if (moveID && prevMoveID) {
68
+ movingStepsAssociated.forEach((replaceStepMoveID, replaceStep) => {
69
+ if (replaceStep !== step && moveID === replaceStepMoveID) {
70
+ movingStepsAssociated.set(replaceStep, prevMoveID);
71
+ }
72
+ });
73
+ continue;
74
+ }
75
+ cleanSteps.push(step);
76
+ }
77
+ for (let i = cleanSteps.length - 1; i >= 0; i--) {
33
78
  const step = tr.steps[i];
34
79
  log.info('transaction step', step);
35
80
  iters += 1;
@@ -58,7 +103,7 @@ export function trackTransaction(tr, oldState, newTr, authorID) {
58
103
  }
59
104
  const newStep = new ReplaceStep(thisStepMapping.map(invertedStep.from), thisStepMapping.map(invertedStep.to), invertedStep.slice);
60
105
  const stepResult = newTr.maybeStep(newStep);
61
- let [steps, startPos] = trackReplaceStep(step, oldState, newTr, emptyAttrs, stepResult, tr.docs[i], tr);
106
+ let [steps, startPos] = trackReplaceStep(step, oldState, newTr, emptyAttrs, stepResult, tr.docs[i], tr, movingStepsAssociated.get(step));
62
107
  if (steps.length === 1) {
63
108
  const step = steps[0];
64
109
  if (isHighlightMarkerNode((step === null || step === void 0 ? void 0 : step.node) || ((_d = (_c = step === null || step === void 0 ? void 0 : step.slice) === null || _c === void 0 ? void 0 : _c.content) === null || _d === void 0 ? void 0 : _d.content[0]))) {
@@ -72,7 +117,8 @@ export function trackTransaction(tr, oldState, newTr, authorID) {
72
117
  const inserted = steps.filter((s) => s.type === 'insert-slice');
73
118
  steps = diffChangeSteps(deleted, inserted);
74
119
  log.info('DIFFED STEPS: ', steps);
75
- const [mapping, selectionPos] = processChangeSteps(steps, startPos || tr.selection.head, newTr, emptyAttrs, oldState.schema, deletedNodeMapping);
120
+ const [mapping, selectionPos] = processChangeSteps(steps, startPos || tr.selection.head, newTr, movingStepsAssociated.has(step)
121
+ ? Object.assign(Object.assign({}, emptyAttrs), { moveNodeId: movingStepsAssociated.get(step) }) : emptyAttrs, oldState.schema, deletedNodeMapping);
76
122
  if (!wasNodeSelection && !setsNewSelection) {
77
123
  const sel = getSelectionStaticConstructor(tr.selection);
78
124
  const near = sel.near(newTr.doc.resolve(selectionPos), -1);
@@ -21,6 +21,7 @@ export var CHANGE_OPERATION;
21
21
  CHANGE_OPERATION["wrap_with_node"] = "wrap_with_node";
22
22
  CHANGE_OPERATION["node_split"] = "node_split";
23
23
  CHANGE_OPERATION["reference"] = "reference";
24
+ CHANGE_OPERATION["move"] = "move";
24
25
  })(CHANGE_OPERATION || (CHANGE_OPERATION = {}));
25
26
  export var CHANGE_STATUS;
26
27
  (function (CHANGE_STATUS) {
@@ -9,7 +9,8 @@ var __rest = (this && this.__rest) || function (s, e) {
9
9
  }
10
10
  return t;
11
11
  };
12
- import { CHANGE_OPERATION } from '../types/change';
12
+ import { CHANGE_OPERATION, CHANGE_STATUS } from '../types/change';
13
+ import { uuidv4 } from './uuidv4';
13
14
  export function createNewInsertAttrs(attrs) {
14
15
  return Object.assign(Object.assign({}, attrs), { operation: CHANGE_OPERATION.insert });
15
16
  }
@@ -25,6 +26,9 @@ export function createNewReferenceAttrs(attrs, id) {
25
26
  export function createNewDeleteAttrs(attrs) {
26
27
  return Object.assign(Object.assign({}, attrs), { operation: CHANGE_OPERATION.delete });
27
28
  }
29
+ export function createNewMoveAttrs(attrs) {
30
+ return Object.assign(Object.assign({}, attrs), { operation: CHANGE_OPERATION.move });
31
+ }
28
32
  export function createNewUpdateAttrs(attrs, oldAttrs) {
29
33
  const { dataTracked } = oldAttrs, restAttrs = __rest(oldAttrs, ["dataTracked"]);
30
34
  return Object.assign(Object.assign({}, attrs), { operation: CHANGE_OPERATION.set_node_attributes, oldAttrs: JSON.parse(JSON.stringify(restAttrs)) });
@@ -70,3 +74,69 @@ export function stepIsLift(gap, node, to) {
70
74
  return gap.start < gap.end && gap.insert === 0 && gap.end === to && !node.isText;
71
75
  }
72
76
  export const trFromHistory = (tr) => Object.keys(tr.meta).find((s) => s.startsWith('history$'));
77
+ export const HasMoveOperations = (tr) => {
78
+ const movingAssoc = new Map();
79
+ if (tr.steps.length < 2) {
80
+ return movingAssoc;
81
+ }
82
+ const matched = [];
83
+ for (let i = 0; i < tr.steps.length; i++) {
84
+ if (matched.includes(i)) {
85
+ continue;
86
+ }
87
+ const step = tr.steps[i];
88
+ const doc = tr.docs[i];
89
+ const stepDeletesContent = step.from !== step.to && step.slice.size === 0;
90
+ const stepInsertsContent = step.slice.size && step.slice.content.firstChild ? true : false;
91
+ console.log('stepDeletesContent', stepDeletesContent);
92
+ console.log('stepInsertsContent', stepInsertsContent);
93
+ for (let g = 0; g < tr.steps.length; g++) {
94
+ if (g === i || matched.includes(g)) {
95
+ continue;
96
+ }
97
+ const peerStep = tr.steps[g];
98
+ const peerStepInsertsContent = peerStep.slice.size && peerStep.slice.content.firstChild;
99
+ const peerStepDeletesContent = peerStep.from !== peerStep.to && peerStep.slice.size === 0;
100
+ if (stepDeletesContent) {
101
+ const deletedContent = doc.slice(step.from, step.to);
102
+ if (peerStepInsertsContent &&
103
+ deletedContent.content.firstChild &&
104
+ peerStep.slice.content.firstChild.toString() === deletedContent.content.firstChild.toString()) {
105
+ const commonID = uuidv4();
106
+ movingAssoc.set(peerStep, commonID);
107
+ movingAssoc.set(step, commonID);
108
+ matched.push(i, g);
109
+ }
110
+ continue;
111
+ }
112
+ if (stepInsertsContent && peerStepDeletesContent) {
113
+ const insertedContent = step.slice;
114
+ const deletedPeerContent = tr.docs[g].slice(peerStep.from, peerStep.to);
115
+ if (insertedContent.content.firstChild &&
116
+ deletedPeerContent.content.firstChild &&
117
+ insertedContent.content.firstChild.toString() === deletedPeerContent.content.firstChild.toString()) {
118
+ const commonID = uuidv4();
119
+ movingAssoc.set(peerStep, commonID);
120
+ movingAssoc.set(step, commonID);
121
+ }
122
+ matched.push(i, g);
123
+ }
124
+ }
125
+ }
126
+ return movingAssoc;
127
+ };
128
+ export const isDeletingPendingMovedNode = (step, doc) => {
129
+ if (!step.slice || step.from === step.to || step.slice.content.size > 0) {
130
+ return undefined;
131
+ }
132
+ const node = doc.nodeAt(step.from);
133
+ if (!node) {
134
+ return undefined;
135
+ }
136
+ const trackedAttrs = node.attrs.dataTracked;
137
+ const found = trackedAttrs === null || trackedAttrs === void 0 ? void 0 : trackedAttrs.find((tracked) => tracked.operation === CHANGE_OPERATION.move && tracked.status === CHANGE_STATUS.pending);
138
+ if (found === null || found === void 0 ? void 0 : found.moveNodeId) {
139
+ return found.moveNodeId;
140
+ }
141
+ return undefined;
142
+ };
@@ -3,4 +3,5 @@ import { Transaction } from 'prosemirror-state';
3
3
  import { NewEmptyAttrs, NewInsertAttrs } from '../types/track';
4
4
  export declare function setFragmentAsInserted(inserted: Fragment, insertAttrs: NewInsertAttrs, schema: Schema): Fragment;
5
5
  export declare function setFragmentAsWrapChange(inserted: Fragment, attrs: NewEmptyAttrs, schema: Schema): Fragment;
6
+ export declare function setFragmentAsMoveChange(fragment: Fragment, attrs: NewEmptyAttrs): Fragment;
6
7
  export declare function setFragmentAsNodeSplit($pos: ResolvedPos, newTr: Transaction, inserted: Fragment, attrs: NewEmptyAttrs): Fragment;
@@ -3,4 +3,4 @@ import type { EditorState, Transaction } from 'prosemirror-state';
3
3
  import { ReplaceStep, StepResult } from 'prosemirror-transform';
4
4
  import { ChangeStep } from '../types/step';
5
5
  import { NewEmptyAttrs } from '../types/track';
6
- export declare function trackReplaceStep(step: ReplaceStep, oldState: EditorState, newTr: Transaction, attrs: NewEmptyAttrs, stepResult: StepResult, currentStepDoc: PMNode, tr: Transaction): [ChangeStep[], number];
6
+ export declare function trackReplaceStep(step: ReplaceStep, oldState: EditorState, newTr: Transaction, attrsTemplate: NewEmptyAttrs, stepResult: StepResult, currentStepDoc: PMNode, tr: Transaction, moveID?: string): [ChangeStep[], number];
@@ -1,2 +1,3 @@
1
1
  import { EditorState, Transaction } from 'prosemirror-state';
2
- export declare function trackTransaction(tr: Transaction, oldState: EditorState, newTr: Transaction, authorID: string): Transaction;
2
+ import { ChangeSet } from '../ChangeSet';
3
+ export declare function trackTransaction(tr: Transaction, oldState: EditorState, newTr: Transaction, authorID: string, changeSet: ChangeSet): Transaction;
@@ -20,7 +20,8 @@ export declare enum CHANGE_OPERATION {
20
20
  set_node_attributes = "set_attrs",
21
21
  wrap_with_node = "wrap_with_node",
22
22
  node_split = "node_split",
23
- reference = "reference"
23
+ reference = "reference",
24
+ move = "move"
24
25
  }
25
26
  export declare enum CHANGE_STATUS {
26
27
  accepted = "accepted",
@@ -36,6 +37,7 @@ type InsertDeleteAttrs = {
36
37
  statusUpdateAt: number;
37
38
  createdAt: number;
38
39
  updatedAt: number;
40
+ moveNodeId?: string;
39
41
  };
40
42
  export type UpdateAttrs = Omit<InsertDeleteAttrs, 'operation'> & {
41
43
  operation: CHANGE_OPERATION.set_node_attributes;
@@ -51,7 +53,10 @@ export type ReferenceAttrs = Omit<InsertDeleteAttrs, 'operation'> & {
51
53
  operation: CHANGE_OPERATION.reference;
52
54
  referenceId: string;
53
55
  };
54
- export type TrackedAttrs = InsertDeleteAttrs | UpdateAttrs | WrapAttrs | NodeSplitAttrs | ReferenceAttrs;
56
+ export type NodeMoveAttrs = Omit<InsertDeleteAttrs, 'operation'> & {
57
+ operation: CHANGE_OPERATION.move;
58
+ };
59
+ export type TrackedAttrs = InsertDeleteAttrs | UpdateAttrs | WrapAttrs | NodeSplitAttrs | ReferenceAttrs | NodeMoveAttrs;
55
60
  type Change = {
56
61
  id: string;
57
62
  from: number;
@@ -16,7 +16,7 @@ export interface TrackChangesState {
16
16
  }
17
17
  export type NewEmptyAttrs = Omit<TrackedAttrs, 'id' | 'operation'>;
18
18
  export type NewInsertAttrs = Omit<TrackedAttrs, 'id' | 'operation'> & {
19
- operation: CHANGE_OPERATION.insert | CHANGE_OPERATION.wrap_with_node;
19
+ operation: CHANGE_OPERATION.insert | CHANGE_OPERATION.wrap_with_node | CHANGE_OPERATION.move;
20
20
  };
21
21
  export type NewDeleteAttrs = Omit<TrackedAttrs, 'id' | 'operation'> & {
22
22
  operation: CHANGE_OPERATION.delete;
@@ -7,6 +7,7 @@ export declare function createNewWrapAttrs(attrs: NewEmptyAttrs): NewInsertAttrs
7
7
  export declare function createNewSplitAttrs(attrs: NewEmptyAttrs): NewSplitNodeAttrs;
8
8
  export declare function createNewReferenceAttrs(attrs: NewEmptyAttrs, id: string): NewReferenceAttrs;
9
9
  export declare function createNewDeleteAttrs(attrs: NewEmptyAttrs): NewDeleteAttrs;
10
+ export declare function createNewMoveAttrs(attrs: NewEmptyAttrs): NewInsertAttrs;
10
11
  export declare function createNewUpdateAttrs(attrs: NewEmptyAttrs, oldAttrs: Record<string, any>): NewUpdateAttrs;
11
12
  export declare const isSplitStep: (step: ReplaceStep, selection: Selection, uiEvent: string) => boolean;
12
13
  export declare const isWrapStep: (step: ReplaceAroundStep) => boolean;
@@ -18,3 +19,5 @@ export declare function stepIsLift(gap: {
18
19
  insert: number;
19
20
  }, node: PMNode, to: number): boolean;
20
21
  export declare const trFromHistory: (tr: Transaction) => string | undefined;
22
+ export declare const HasMoveOperations: (tr: Transaction) => Map<ReplaceStep, string>;
23
+ export declare const isDeletingPendingMovedNode: (step: ReplaceStep, doc: PMNode) => string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manuscripts/track-changes-plugin",
3
- "version": "1.10.7",
3
+ "version": "1.10.8-LEAN-4160.0",
4
4
  "author": "Atypon Systems LLC",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/Atypon-OpenSource/manuscripts-track-changes-plugin",