@manuscripts/track-changes-plugin 1.7.0-LEAN-2850 → 1.7.0-LEAN-2752

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.cjs CHANGED
@@ -162,14 +162,13 @@ const enableDebug = (enabled) => {
162
162
  }
163
163
  };
164
164
 
165
- var _ChangeSet_instances, _ChangeSet_changes, _ChangeSet_isSameNodeChange, _ChangeSet_isNotPendingOrDeleted;
165
+ var _ChangeSet_changes;
166
166
  /**
167
167
  * ChangeSet is a data structure to contain the tracked changes with some utility methods and computed
168
168
  * values to allow easier operability.
169
169
  */
170
170
  class ChangeSet {
171
171
  constructor(changes = []) {
172
- _ChangeSet_instances.add(this);
173
172
  _ChangeSet_changes.set(this, void 0);
174
173
  __classPrivateFieldSet(this, _ChangeSet_changes, changes, "f");
175
174
  }
@@ -200,10 +199,7 @@ class ChangeSet {
200
199
  rootNodes.push(currentNodeChange);
201
200
  currentNodeChange = undefined;
202
201
  }
203
- if (currentNodeChange &&
204
- c.from < currentNodeChange.to &&
205
- !(__classPrivateFieldGet(this, _ChangeSet_instances, "m", _ChangeSet_isSameNodeChange).call(this, currentNodeChange, c) &&
206
- __classPrivateFieldGet(this, _ChangeSet_instances, "m", _ChangeSet_isNotPendingOrDeleted).call(this, currentNodeChange))) {
202
+ if (currentNodeChange && c.from < currentNodeChange.to) {
207
203
  currentNodeChange.children.push(c);
208
204
  }
209
205
  else if (c.type === 'node-change') {
@@ -325,12 +321,7 @@ class ChangeSet {
325
321
  return change.type === 'node-attr-change';
326
322
  }
327
323
  }
328
- _ChangeSet_changes = new WeakMap(), _ChangeSet_instances = new WeakSet(), _ChangeSet_isSameNodeChange = function _ChangeSet_isSameNodeChange(currentChange, nextChange) {
329
- return currentChange.from === nextChange.from && currentChange.to === nextChange.to;
330
- }, _ChangeSet_isNotPendingOrDeleted = function _ChangeSet_isNotPendingOrDeleted(change) {
331
- return (change.dataTracked.operation !== exports.CHANGE_OPERATION.delete &&
332
- change.dataTracked.status !== exports.CHANGE_STATUS.pending);
333
- };
324
+ _ChangeSet_changes = new WeakMap();
334
325
 
335
326
  /*!
336
327
  * © 2021 Atypon Systems LLC
@@ -540,9 +531,7 @@ function updateChangeAttrs(tr, change, trackedAttrs, schema) {
540
531
  return tr;
541
532
  }
542
533
  const { operation } = trackedAttrs;
543
- const oldTrackData = change.type === 'text-change'
544
- ? getTextNodeTrackedMarkData(node, schema)
545
- : getBlockInlineTrackedData(node);
534
+ const oldTrackData = change.type === 'text-change' ? getTextNodeTrackedMarkData(node, schema) : getBlockInlineTrackedData(node);
546
535
  if (!operation) {
547
536
  log.warn('updateChangeAttrs: unable to determine operation of change ', change);
548
537
  }
@@ -563,7 +552,15 @@ function updateChangeAttrs(tr, change, trackedAttrs, schema) {
563
552
  tr.setNodeMarkup(change.from, undefined, { ...node.attrs, dataTracked: null }, node.marks);
564
553
  }
565
554
  else if (change.type === 'node-change' || change.type === 'node-attr-change') {
566
- const newDataTracked = (getBlockInlineTrackedData(node) || []).map((oldTrack) => {
555
+ const trackedDataSource = getBlockInlineTrackedData(node) || [];
556
+ const targetDataTracked = trackedDataSource.find((t) => change.id === t.id);
557
+ const newDataTracked = trackedDataSource.map((oldTrack) => {
558
+ if (targetDataTracked) {
559
+ if (oldTrack.id === targetDataTracked.id) {
560
+ return { ...oldTrack, ...trackedAttrs };
561
+ }
562
+ return oldTrack;
563
+ }
567
564
  if (oldTrack.operation === operation) {
568
565
  return { ...oldTrack, ...trackedAttrs };
569
566
  }
@@ -587,6 +584,13 @@ function updateChangeChildrenAttributes(changes, tr, mapping) {
587
584
  });
588
585
  }
589
586
 
587
+ function getUpdatedDataTracked(dataTracked, changeId) {
588
+ if (!dataTracked) {
589
+ return null;
590
+ }
591
+ const newDataTracked = dataTracked.filter((c) => c.id !== changeId);
592
+ return newDataTracked.length ? newDataTracked : null;
593
+ }
590
594
  /**
591
595
  * Applies the accepted/rejected changes in the current document and sets them untracked
592
596
  *
@@ -596,10 +600,12 @@ function updateChangeChildrenAttributes(changes, tr, mapping) {
596
600
  * @param deleteMap
597
601
  */
598
602
  function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prosemirrorTransform.Mapping()) {
603
+ const attrsChangesLog = new Map(); // map of node ids and applied change updatedAt timestamp
604
+ function addAttrLog(nodeId, changeId) {
605
+ const arr = attrsChangesLog.get(nodeId) || attrsChangesLog.set(nodeId, []).get(nodeId);
606
+ arr.push(changeId);
607
+ }
599
608
  changes.forEach((change) => {
600
- if (change.dataTracked.status === exports.CHANGE_STATUS.pending) {
601
- return;
602
- }
603
609
  // Map change.from and skip those which dont need to be applied
604
610
  // or were already deleted by an applied block delete
605
611
  const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || !ChangeSet.shouldDeleteChange(change);
@@ -607,6 +613,24 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prose
607
613
  !deleted && log.warn('no node found to update for change', change);
608
614
  return;
609
615
  }
616
+ if (change.dataTracked.status === exports.CHANGE_STATUS.pending) {
617
+ if (ChangeSet.isNodeAttrChange(change)) {
618
+ /*
619
+ Apply pending changes for attributes as well because applying accepted/rejected changes may override
620
+ pending because we store the most recent change directly on the node attributes. But in case of pending attributes
621
+ we don't need to remove dataTracked record. We need, however, to make sure we don't restore dataTracked records for
622
+ the previously applied changes. To check for already applied changes we log them into "attrsChangesLog" Map.
623
+ */
624
+ const { dataTracked, attrs } = change.newAttrs;
625
+ const changeLog = attrsChangesLog.get(node.attrs.id);
626
+ const newDataTracked = (changeLog === null || changeLog === void 0 ? void 0 : changeLog.length)
627
+ ? dataTracked.filter((c) => !changeLog.includes(c.id))
628
+ : dataTracked;
629
+ tr.setNodeMarkup(from, undefined, { ...attrs, dataTracked: newDataTracked.length ? newDataTracked : null }, node.marks);
630
+ // default is "null" for dataTracked in attrs in pm schema, so codebase generally relies on it being null when empty
631
+ }
632
+ return;
633
+ }
610
634
  if (ChangeSet.isTextChange(change) && noChangeNeeded) {
611
635
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_insert);
612
636
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_delete);
@@ -630,13 +654,13 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prose
630
654
  }
631
655
  deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
632
656
  }
633
- else if (ChangeSet.isNodeAttrChange(change) &&
634
- change.dataTracked.status === exports.CHANGE_STATUS.accepted) {
635
- tr.setNodeMarkup(from, undefined, { ...node.attrs, dataTracked: null }, node.marks);
657
+ else if (ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === exports.CHANGE_STATUS.accepted) {
658
+ tr.setNodeMarkup(from, undefined, { ...change.newAttrs, dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }, node.marks);
659
+ addAttrLog(node.attrs.id, change.dataTracked.id);
636
660
  }
637
- else if (ChangeSet.isNodeAttrChange(change) &&
638
- change.dataTracked.status === exports.CHANGE_STATUS.rejected) {
639
- tr.setNodeMarkup(from, undefined, { ...change.oldAttrs, dataTracked: null }, node.marks);
661
+ else if (ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === exports.CHANGE_STATUS.rejected) {
662
+ tr.setNodeMarkup(from, undefined, { ...change.oldAttrs, dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }, node.marks);
663
+ addAttrLog(node.attrs.id, change.dataTracked.id);
640
664
  }
641
665
  });
642
666
  return deleteMap;
@@ -961,7 +985,7 @@ function createNewUpdateAttrs(attrs, oldAttrs) {
961
985
  return {
962
986
  ...attrs,
963
987
  operation: exports.CHANGE_OPERATION.set_node_attributes,
964
- oldAttrs: restAttrs,
988
+ oldAttrs: JSON.parse(JSON.stringify(restAttrs)),
965
989
  };
966
990
  }
967
991
 
@@ -1212,7 +1236,8 @@ function trackReplaceAroundStep(step, oldState, tr, newTr, attrs) {
1212
1236
  */
1213
1237
  function trackReplaceStep(step, oldState, newTr, attrs, stepResult, currentStepDoc) {
1214
1238
  log.info('###### ReplaceStep ######');
1215
- let selectionPos = 0, changeSteps = [];
1239
+ let selectionPos = 0;
1240
+ const changeSteps = [];
1216
1241
  // Invert the transaction step to prevent it from actually deleting or inserting anything
1217
1242
  step.getMap().forEach((fromA, toA, fromB, toB) => {
1218
1243
  var _a, _b;
@@ -1436,21 +1461,32 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
1436
1461
  }
1437
1462
  else if (c.type === 'update-node-attrs') {
1438
1463
  const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
1439
- const oldUpdate = oldDataTracked.find((d) => d.operation === exports.CHANGE_OPERATION.set_node_attributes && d.status === exports.CHANGE_STATUS.pending);
1440
- const { dataTracked, ...oldAttrs } = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1441
- const newDataTracked = [...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id)];
1442
- const newUpdate = oldUpdate
1464
+ const oldUpdate = oldDataTracked.reverse().find((d) => {
1465
+ // reversing to start from the most recent change
1466
+ if (d.operation === exports.CHANGE_OPERATION.set_node_attributes &&
1467
+ (d.status === exports.CHANGE_STATUS.pending || d.status === exports.CHANGE_STATUS.rejected)) {
1468
+ return true;
1469
+ }
1470
+ return false;
1471
+ });
1472
+ // if the selected last change is with status "rejected" we need to use oldAttrs from it because
1473
+ // node's actual attributes represent the "rejected" values
1474
+ const lastChangeRejected = oldUpdate && oldUpdate.status === exports.CHANGE_STATUS.rejected;
1475
+ const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1476
+ const { dataTracked, ...restAttrs } = sourceAttrs;
1477
+ const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
1478
+ const newDataTracked = [
1479
+ ...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
1480
+ ];
1481
+ const newUpdate = oldUpdate && oldUpdate.status !== exports.CHANGE_STATUS.rejected
1443
1482
  ? {
1444
1483
  ...oldUpdate,
1445
1484
  updatedAt: emptyAttrs.updatedAt,
1446
1485
  }
1447
- : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, c.node.attrs));
1486
+ : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
1448
1487
  // Dont add update changes if there exists already an insert change for this node
1449
- if ((JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) ||
1450
- c.node.type === c.node.type.schema.nodes.citation) &&
1451
- !oldDataTracked.find((d) => (d.operation === exports.CHANGE_OPERATION.insert ||
1452
- d.operation === exports.CHANGE_OPERATION.set_node_attributes) &&
1453
- d.status === exports.CHANGE_STATUS.pending)) {
1488
+ if (JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) &&
1489
+ !oldDataTracked.find((d) => d.operation === exports.CHANGE_OPERATION.insert)) {
1454
1490
  newDataTracked.push(newUpdate);
1455
1491
  }
1456
1492
  newTr.setNodeMarkup(mapping.map(c.pos), undefined, {
@@ -1861,9 +1897,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1861
1897
  },
1862
1898
  appendTransaction(trs, oldState, newState) {
1863
1899
  const pluginState = trackChangesPluginKey.getState(newState);
1864
- if (!pluginState ||
1865
- pluginState.status === exports.TrackChangesStatus.disabled ||
1866
- !(editorView === null || editorView === void 0 ? void 0 : editorView.editable)) {
1900
+ if (!pluginState || pluginState.status === exports.TrackChangesStatus.disabled || !(editorView === null || editorView === void 0 ? void 0 : editorView.editable)) {
1867
1901
  return null;
1868
1902
  }
1869
1903
  const { userID, changeSet } = pluginState;
@@ -1872,13 +1906,8 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1872
1906
  trs.forEach((tr) => {
1873
1907
  const wasAppended = tr.getMeta('appendedTransaction');
1874
1908
  const skipMetaUsed = skipTrsWithMetas.some((m) => tr.getMeta(m) || (wasAppended === null || wasAppended === void 0 ? void 0 : wasAppended.getMeta(m)));
1875
- const skipTrackUsed = getAction(tr, TrackChangesAction.skipTrack) ||
1876
- (wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
1877
- if (tr.docChanged &&
1878
- !skipMetaUsed &&
1879
- !skipTrackUsed &&
1880
- !tr.getMeta('history$') &&
1881
- !(wasAppended && tr.getMeta('origin') === 'paragraphs')) {
1909
+ const skipTrackUsed = getAction(tr, TrackChangesAction.skipTrack) || (wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
1910
+ if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$') && !(wasAppended && tr.getMeta('origin') === 'paragraphs')) {
1882
1911
  createdTr = trackTransaction(tr, oldState, createdTr, userID);
1883
1912
  }
1884
1913
  docChanged = docChanged || tr.docChanged;
@@ -1898,8 +1927,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1898
1927
  setAction(createdTr, TrackChangesAction.refreshChanges, true);
1899
1928
  }
1900
1929
  });
1901
- const changed = pluginState.changeSet.hasInconsistentData &&
1902
- fixInconsistentChanges(pluginState.changeSet, userID, createdTr, oldState.schema);
1930
+ const changed = pluginState.changeSet.hasInconsistentData && fixInconsistentChanges(pluginState.changeSet, userID, createdTr, oldState.schema);
1903
1931
  if (changed) {
1904
1932
  log.warn('had to fix inconsistent changes in', createdTr);
1905
1933
  }
package/dist/index.js CHANGED
@@ -154,14 +154,13 @@ const enableDebug = (enabled) => {
154
154
  }
155
155
  };
156
156
 
157
- var _ChangeSet_instances, _ChangeSet_changes, _ChangeSet_isSameNodeChange, _ChangeSet_isNotPendingOrDeleted;
157
+ var _ChangeSet_changes;
158
158
  /**
159
159
  * ChangeSet is a data structure to contain the tracked changes with some utility methods and computed
160
160
  * values to allow easier operability.
161
161
  */
162
162
  class ChangeSet {
163
163
  constructor(changes = []) {
164
- _ChangeSet_instances.add(this);
165
164
  _ChangeSet_changes.set(this, void 0);
166
165
  __classPrivateFieldSet(this, _ChangeSet_changes, changes, "f");
167
166
  }
@@ -192,10 +191,7 @@ class ChangeSet {
192
191
  rootNodes.push(currentNodeChange);
193
192
  currentNodeChange = undefined;
194
193
  }
195
- if (currentNodeChange &&
196
- c.from < currentNodeChange.to &&
197
- !(__classPrivateFieldGet(this, _ChangeSet_instances, "m", _ChangeSet_isSameNodeChange).call(this, currentNodeChange, c) &&
198
- __classPrivateFieldGet(this, _ChangeSet_instances, "m", _ChangeSet_isNotPendingOrDeleted).call(this, currentNodeChange))) {
194
+ if (currentNodeChange && c.from < currentNodeChange.to) {
199
195
  currentNodeChange.children.push(c);
200
196
  }
201
197
  else if (c.type === 'node-change') {
@@ -317,12 +313,7 @@ class ChangeSet {
317
313
  return change.type === 'node-attr-change';
318
314
  }
319
315
  }
320
- _ChangeSet_changes = new WeakMap(), _ChangeSet_instances = new WeakSet(), _ChangeSet_isSameNodeChange = function _ChangeSet_isSameNodeChange(currentChange, nextChange) {
321
- return currentChange.from === nextChange.from && currentChange.to === nextChange.to;
322
- }, _ChangeSet_isNotPendingOrDeleted = function _ChangeSet_isNotPendingOrDeleted(change) {
323
- return (change.dataTracked.operation !== CHANGE_OPERATION.delete &&
324
- change.dataTracked.status !== CHANGE_STATUS.pending);
325
- };
316
+ _ChangeSet_changes = new WeakMap();
326
317
 
327
318
  /*!
328
319
  * © 2021 Atypon Systems LLC
@@ -532,9 +523,7 @@ function updateChangeAttrs(tr, change, trackedAttrs, schema) {
532
523
  return tr;
533
524
  }
534
525
  const { operation } = trackedAttrs;
535
- const oldTrackData = change.type === 'text-change'
536
- ? getTextNodeTrackedMarkData(node, schema)
537
- : getBlockInlineTrackedData(node);
526
+ const oldTrackData = change.type === 'text-change' ? getTextNodeTrackedMarkData(node, schema) : getBlockInlineTrackedData(node);
538
527
  if (!operation) {
539
528
  log.warn('updateChangeAttrs: unable to determine operation of change ', change);
540
529
  }
@@ -555,7 +544,15 @@ function updateChangeAttrs(tr, change, trackedAttrs, schema) {
555
544
  tr.setNodeMarkup(change.from, undefined, { ...node.attrs, dataTracked: null }, node.marks);
556
545
  }
557
546
  else if (change.type === 'node-change' || change.type === 'node-attr-change') {
558
- const newDataTracked = (getBlockInlineTrackedData(node) || []).map((oldTrack) => {
547
+ const trackedDataSource = getBlockInlineTrackedData(node) || [];
548
+ const targetDataTracked = trackedDataSource.find((t) => change.id === t.id);
549
+ const newDataTracked = trackedDataSource.map((oldTrack) => {
550
+ if (targetDataTracked) {
551
+ if (oldTrack.id === targetDataTracked.id) {
552
+ return { ...oldTrack, ...trackedAttrs };
553
+ }
554
+ return oldTrack;
555
+ }
559
556
  if (oldTrack.operation === operation) {
560
557
  return { ...oldTrack, ...trackedAttrs };
561
558
  }
@@ -579,6 +576,13 @@ function updateChangeChildrenAttributes(changes, tr, mapping) {
579
576
  });
580
577
  }
581
578
 
579
+ function getUpdatedDataTracked(dataTracked, changeId) {
580
+ if (!dataTracked) {
581
+ return null;
582
+ }
583
+ const newDataTracked = dataTracked.filter((c) => c.id !== changeId);
584
+ return newDataTracked.length ? newDataTracked : null;
585
+ }
582
586
  /**
583
587
  * Applies the accepted/rejected changes in the current document and sets them untracked
584
588
  *
@@ -588,10 +592,12 @@ function updateChangeChildrenAttributes(changes, tr, mapping) {
588
592
  * @param deleteMap
589
593
  */
590
594
  function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mapping()) {
595
+ const attrsChangesLog = new Map(); // map of node ids and applied change updatedAt timestamp
596
+ function addAttrLog(nodeId, changeId) {
597
+ const arr = attrsChangesLog.get(nodeId) || attrsChangesLog.set(nodeId, []).get(nodeId);
598
+ arr.push(changeId);
599
+ }
591
600
  changes.forEach((change) => {
592
- if (change.dataTracked.status === CHANGE_STATUS.pending) {
593
- return;
594
- }
595
601
  // Map change.from and skip those which dont need to be applied
596
602
  // or were already deleted by an applied block delete
597
603
  const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || !ChangeSet.shouldDeleteChange(change);
@@ -599,6 +605,24 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mappi
599
605
  !deleted && log.warn('no node found to update for change', change);
600
606
  return;
601
607
  }
608
+ if (change.dataTracked.status === CHANGE_STATUS.pending) {
609
+ if (ChangeSet.isNodeAttrChange(change)) {
610
+ /*
611
+ Apply pending changes for attributes as well because applying accepted/rejected changes may override
612
+ pending because we store the most recent change directly on the node attributes. But in case of pending attributes
613
+ we don't need to remove dataTracked record. We need, however, to make sure we don't restore dataTracked records for
614
+ the previously applied changes. To check for already applied changes we log them into "attrsChangesLog" Map.
615
+ */
616
+ const { dataTracked, attrs } = change.newAttrs;
617
+ const changeLog = attrsChangesLog.get(node.attrs.id);
618
+ const newDataTracked = (changeLog === null || changeLog === void 0 ? void 0 : changeLog.length)
619
+ ? dataTracked.filter((c) => !changeLog.includes(c.id))
620
+ : dataTracked;
621
+ tr.setNodeMarkup(from, undefined, { ...attrs, dataTracked: newDataTracked.length ? newDataTracked : null }, node.marks);
622
+ // default is "null" for dataTracked in attrs in pm schema, so codebase generally relies on it being null when empty
623
+ }
624
+ return;
625
+ }
602
626
  if (ChangeSet.isTextChange(change) && noChangeNeeded) {
603
627
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_insert);
604
628
  tr.removeMark(from, deleteMap.map(change.to), schema.marks.tracked_delete);
@@ -622,13 +646,13 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mappi
622
646
  }
623
647
  deleteMap.appendMap(tr.steps[tr.steps.length - 1].getMap());
624
648
  }
625
- else if (ChangeSet.isNodeAttrChange(change) &&
626
- change.dataTracked.status === CHANGE_STATUS.accepted) {
627
- tr.setNodeMarkup(from, undefined, { ...node.attrs, dataTracked: null }, node.marks);
649
+ else if (ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === CHANGE_STATUS.accepted) {
650
+ tr.setNodeMarkup(from, undefined, { ...change.newAttrs, dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }, node.marks);
651
+ addAttrLog(node.attrs.id, change.dataTracked.id);
628
652
  }
629
- else if (ChangeSet.isNodeAttrChange(change) &&
630
- change.dataTracked.status === CHANGE_STATUS.rejected) {
631
- tr.setNodeMarkup(from, undefined, { ...change.oldAttrs, dataTracked: null }, node.marks);
653
+ else if (ChangeSet.isNodeAttrChange(change) && change.dataTracked.status === CHANGE_STATUS.rejected) {
654
+ tr.setNodeMarkup(from, undefined, { ...change.oldAttrs, dataTracked: getUpdatedDataTracked(node.attrs.dataTracked, change.id) }, node.marks);
655
+ addAttrLog(node.attrs.id, change.dataTracked.id);
632
656
  }
633
657
  });
634
658
  return deleteMap;
@@ -953,7 +977,7 @@ function createNewUpdateAttrs(attrs, oldAttrs) {
953
977
  return {
954
978
  ...attrs,
955
979
  operation: CHANGE_OPERATION.set_node_attributes,
956
- oldAttrs: restAttrs,
980
+ oldAttrs: JSON.parse(JSON.stringify(restAttrs)),
957
981
  };
958
982
  }
959
983
 
@@ -1204,7 +1228,8 @@ function trackReplaceAroundStep(step, oldState, tr, newTr, attrs) {
1204
1228
  */
1205
1229
  function trackReplaceStep(step, oldState, newTr, attrs, stepResult, currentStepDoc) {
1206
1230
  log.info('###### ReplaceStep ######');
1207
- let selectionPos = 0, changeSteps = [];
1231
+ let selectionPos = 0;
1232
+ const changeSteps = [];
1208
1233
  // Invert the transaction step to prevent it from actually deleting or inserting anything
1209
1234
  step.getMap().forEach((fromA, toA, fromB, toB) => {
1210
1235
  var _a, _b;
@@ -1428,21 +1453,32 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
1428
1453
  }
1429
1454
  else if (c.type === 'update-node-attrs') {
1430
1455
  const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
1431
- const oldUpdate = oldDataTracked.find((d) => d.operation === CHANGE_OPERATION.set_node_attributes && d.status === CHANGE_STATUS.pending);
1432
- const { dataTracked, ...oldAttrs } = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1433
- const newDataTracked = [...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id)];
1434
- const newUpdate = oldUpdate
1456
+ const oldUpdate = oldDataTracked.reverse().find((d) => {
1457
+ // reversing to start from the most recent change
1458
+ if (d.operation === CHANGE_OPERATION.set_node_attributes &&
1459
+ (d.status === CHANGE_STATUS.pending || d.status === CHANGE_STATUS.rejected)) {
1460
+ return true;
1461
+ }
1462
+ return false;
1463
+ });
1464
+ // if the selected last change is with status "rejected" we need to use oldAttrs from it because
1465
+ // node's actual attributes represent the "rejected" values
1466
+ const lastChangeRejected = oldUpdate && oldUpdate.status === CHANGE_STATUS.rejected;
1467
+ const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1468
+ const { dataTracked, ...restAttrs } = sourceAttrs;
1469
+ const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
1470
+ const newDataTracked = [
1471
+ ...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
1472
+ ];
1473
+ const newUpdate = oldUpdate && oldUpdate.status !== CHANGE_STATUS.rejected
1435
1474
  ? {
1436
1475
  ...oldUpdate,
1437
1476
  updatedAt: emptyAttrs.updatedAt,
1438
1477
  }
1439
- : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, c.node.attrs));
1478
+ : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
1440
1479
  // Dont add update changes if there exists already an insert change for this node
1441
- if ((JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) ||
1442
- c.node.type === c.node.type.schema.nodes.citation) &&
1443
- !oldDataTracked.find((d) => (d.operation === CHANGE_OPERATION.insert ||
1444
- d.operation === CHANGE_OPERATION.set_node_attributes) &&
1445
- d.status === CHANGE_STATUS.pending)) {
1480
+ if (JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) &&
1481
+ !oldDataTracked.find((d) => d.operation === CHANGE_OPERATION.insert)) {
1446
1482
  newDataTracked.push(newUpdate);
1447
1483
  }
1448
1484
  newTr.setNodeMarkup(mapping.map(c.pos), undefined, {
@@ -1853,9 +1889,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1853
1889
  },
1854
1890
  appendTransaction(trs, oldState, newState) {
1855
1891
  const pluginState = trackChangesPluginKey.getState(newState);
1856
- if (!pluginState ||
1857
- pluginState.status === TrackChangesStatus.disabled ||
1858
- !(editorView === null || editorView === void 0 ? void 0 : editorView.editable)) {
1892
+ if (!pluginState || pluginState.status === TrackChangesStatus.disabled || !(editorView === null || editorView === void 0 ? void 0 : editorView.editable)) {
1859
1893
  return null;
1860
1894
  }
1861
1895
  const { userID, changeSet } = pluginState;
@@ -1864,13 +1898,8 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1864
1898
  trs.forEach((tr) => {
1865
1899
  const wasAppended = tr.getMeta('appendedTransaction');
1866
1900
  const skipMetaUsed = skipTrsWithMetas.some((m) => tr.getMeta(m) || (wasAppended === null || wasAppended === void 0 ? void 0 : wasAppended.getMeta(m)));
1867
- const skipTrackUsed = getAction(tr, TrackChangesAction.skipTrack) ||
1868
- (wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
1869
- if (tr.docChanged &&
1870
- !skipMetaUsed &&
1871
- !skipTrackUsed &&
1872
- !tr.getMeta('history$') &&
1873
- !(wasAppended && tr.getMeta('origin') === 'paragraphs')) {
1901
+ const skipTrackUsed = getAction(tr, TrackChangesAction.skipTrack) || (wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
1902
+ if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$') && !(wasAppended && tr.getMeta('origin') === 'paragraphs')) {
1874
1903
  createdTr = trackTransaction(tr, oldState, createdTr, userID);
1875
1904
  }
1876
1905
  docChanged = docChanged || tr.docChanged;
@@ -1890,8 +1919,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
1890
1919
  setAction(createdTr, TrackChangesAction.refreshChanges, true);
1891
1920
  }
1892
1921
  });
1893
- const changed = pluginState.changeSet.hasInconsistentData &&
1894
- fixInconsistentChanges(pluginState.changeSet, userID, createdTr, oldState.schema);
1922
+ const changed = pluginState.changeSet.hasInconsistentData && fixInconsistentChanges(pluginState.changeSet, userID, createdTr, oldState.schema);
1895
1923
  if (changed) {
1896
1924
  log.warn('had to fix inconsistent changes in', createdTr);
1897
1925
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manuscripts/track-changes-plugin",
3
- "version": "1.7.0-LEAN-2850",
3
+ "version": "1.7.0-LEAN-2752",
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",