@manuscripts/track-changes-plugin 1.7.1 → 1.7.2-LEAN-3046

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 (3) hide show
  1. package/dist/index.cjs +102 -82
  2. package/dist/index.js +102 -82
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -162,13 +162,14 @@ const enableDebug = (enabled) => {
162
162
  }
163
163
  };
164
164
 
165
- var _ChangeSet_changes;
165
+ var _ChangeSet_instances, _ChangeSet_changes, _ChangeSet_isSameNodeChange, _ChangeSet_isNotPendingOrDeleted;
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);
172
173
  _ChangeSet_changes.set(this, void 0);
173
174
  __classPrivateFieldSet(this, _ChangeSet_changes, changes, "f");
174
175
  }
@@ -199,7 +200,10 @@ class ChangeSet {
199
200
  rootNodes.push(currentNodeChange);
200
201
  currentNodeChange = undefined;
201
202
  }
202
- if (currentNodeChange && c.from < currentNodeChange.to) {
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))) {
203
207
  currentNodeChange.children.push(c);
204
208
  }
205
209
  else if (c.type === 'node-change') {
@@ -321,7 +325,12 @@ class ChangeSet {
321
325
  return change.type === 'node-attr-change';
322
326
  }
323
327
  }
324
- _ChangeSet_changes = new WeakMap();
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
+ };
325
334
 
326
335
  /*!
327
336
  * © 2021 Atypon Systems LLC
@@ -1403,94 +1412,105 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
1403
1412
  const deleteAttrs = createNewDeleteAttrs(emptyAttrs);
1404
1413
  let selectionPos = startPos;
1405
1414
  // @TODO add custom handler / condition?
1415
+ let deletesCounter = 0; // counter for deletion
1406
1416
  changes.forEach((c) => {
1407
1417
  let step = newTr.steps[newTr.steps.length - 1];
1408
- log.info('process change: ', c);
1409
- // const handled = customStepHandler(changes, newTr, emptyAttrs) // ChangeStep[] | undefined
1410
- if (c.type === 'delete-node') {
1411
- deleteOrSetNodeDeleted(c.node, mapping.map(c.pos), newTr, deleteAttrs);
1412
- const newestStep = newTr.steps[newTr.steps.length - 1];
1413
- if (step !== newestStep) {
1414
- mapping.appendMap(newestStep.getMap());
1415
- step = newestStep;
1416
- }
1417
- mergeTrackedMarks(mapping.map(c.pos), newTr.doc, newTr, schema);
1418
- }
1419
- else if (c.type === 'delete-text') {
1420
- const node = newTr.doc.nodeAt(mapping.map(c.pos));
1421
- if (!node) {
1422
- log.error(`processChangeSteps: no text node found for text-change`, c);
1423
- return;
1424
- }
1425
- const where = deleteTextIfInserted(node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1426
- mergeTrackedMarks(where, newTr.doc, newTr, schema);
1427
- }
1428
- else if (c.type === 'merge-fragment') {
1429
- let insertPos = mapping.map(c.mergePos);
1430
- // The default insert position for block nodes is either the start of the merged content or the end.
1431
- // Incase text was merged, this must be updated as the start or end of the node doesn't map to the
1432
- // actual position of the merge. Currently the inserted content is inserted at the start or end
1433
- // of the merged content, TODO reverse the start/end when end/start token?
1434
- if (c.node.isText) {
1435
- // When merging text we must delete text in the same go as well, as the from/to boundary goes through
1436
- // the text node.
1437
- insertPos = deleteTextIfInserted(c.node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1418
+ switch (c.type) {
1419
+ case "delete-node":
1420
+ deletesCounter++; // increase the counter for deleted nodes
1421
+ let trackedData = getBlockInlineTrackedData(c.node);
1422
+ const inserted = trackedData === null || trackedData === void 0 ? void 0 : trackedData.find((d) => d.operation === exports.CHANGE_OPERATION.insert);
1423
+ // For inserted node: the top node and its content (children nodes) is deleted in the first step
1424
+ if (inserted && deletesCounter > 1)
1425
+ return false;
1426
+ deleteOrSetNodeDeleted(c.node, mapping.map(c.pos), newTr, deleteAttrs);
1438
1427
  const newestStep = newTr.steps[newTr.steps.length - 1];
1439
1428
  if (step !== newestStep) {
1440
1429
  mapping.appendMap(newestStep.getMap());
1441
1430
  step = newestStep;
1442
1431
  }
1443
- }
1444
- if (c.fragment.size > 0) {
1445
- newTr.insert(insertPos, c.fragment);
1446
- }
1447
- }
1448
- else if (c.type === 'insert-slice') {
1449
- const newStep = new prosemirrorTransform.ReplaceStep(mapping.map(c.from), mapping.map(c.to), c.slice, false);
1450
- const stepResult = newTr.maybeStep(newStep);
1451
- if (stepResult.failed) {
1452
- log.error(`processChangeSteps: insert-slice ReplaceStep failed "${stepResult.failed}"`, newStep);
1453
- return;
1454
- }
1455
- mergeTrackedMarks(mapping.map(c.from), newTr.doc, newTr, schema);
1456
- const to = mapping.map(c.to) + c.slice.size;
1457
- mergeTrackedMarks(mapping.map(c.to) + (to < newTr.doc.nodeSize ? c.slice.size : 0), newTr.doc, newTr, schema);
1458
- selectionPos = mapping.map(c.to) + c.slice.size;
1459
- }
1460
- else if (c.type === 'update-node-attrs') {
1461
- const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
1462
- const oldUpdate = oldDataTracked.reverse().find((d) => {
1463
- // reversing to start from the most recent change
1464
- if (d.operation === exports.CHANGE_OPERATION.set_node_attributes &&
1465
- (d.status === exports.CHANGE_STATUS.pending || d.status === exports.CHANGE_STATUS.rejected)) {
1466
- return true;
1432
+ mergeTrackedMarks(mapping.map(c.pos), newTr.doc, newTr, schema);
1433
+ break;
1434
+ case "delete-text":
1435
+ const node = newTr.doc.nodeAt(mapping.map(c.pos));
1436
+ if (!node) {
1437
+ log.error(`processChangeSteps: no text node found for text-change`, c);
1438
+ return;
1467
1439
  }
1468
- return false;
1469
- });
1470
- // if the selected last change is with status "rejected" we need to use oldAttrs from it because
1471
- // node's actual attributes represent the "rejected" values
1472
- const lastChangeRejected = oldUpdate && oldUpdate.status === exports.CHANGE_STATUS.rejected;
1473
- const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1474
- const { dataTracked, ...restAttrs } = sourceAttrs;
1475
- const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
1476
- const newDataTracked = [
1477
- ...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
1478
- ];
1479
- const newUpdate = oldUpdate && oldUpdate.status !== exports.CHANGE_STATUS.rejected
1480
- ? {
1481
- ...oldUpdate,
1482
- updatedAt: emptyAttrs.updatedAt,
1440
+ const where = deleteTextIfInserted(node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1441
+ mergeTrackedMarks(where, newTr.doc, newTr, schema);
1442
+ break;
1443
+ case 'merge-fragment':
1444
+ let insertPos = mapping.map(c.mergePos);
1445
+ // The default insert position for block nodes is either the start of the merged content or the end.
1446
+ // Incase text was merged, this must be updated as the start or end of the node doesn't map to the
1447
+ // actual position of the merge. Currently the inserted content is inserted at the start or end
1448
+ // of the merged content, TODO reverse the start/end when end/start token?
1449
+ if (c.node.isText) {
1450
+ // When merging text we must delete text in the same go as well, as the from/to boundary goes through
1451
+ // the text node.
1452
+ insertPos = deleteTextIfInserted(c.node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1453
+ const newestStep = newTr.steps[newTr.steps.length - 1];
1454
+ if (step !== newestStep) {
1455
+ mapping.appendMap(newestStep.getMap());
1456
+ step = newestStep;
1457
+ }
1483
1458
  }
1484
- : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
1485
- // Dont add update changes if there exists already an insert change for this node
1486
- if (JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) &&
1487
- !oldDataTracked.find((d) => d.operation === exports.CHANGE_OPERATION.insert)) {
1488
- newDataTracked.push(newUpdate);
1489
- }
1490
- newTr.setNodeMarkup(mapping.map(c.pos), undefined, {
1491
- ...c.newAttrs,
1492
- dataTracked: newDataTracked.length > 0 ? newDataTracked : null,
1493
- }, c.node.marks);
1459
+ if (c.fragment.size > 0) {
1460
+ newTr.insert(insertPos, c.fragment);
1461
+ }
1462
+ break;
1463
+ case 'insert-slice':
1464
+ const newStep = new prosemirrorTransform.ReplaceStep(mapping.map(c.from), mapping.map(c.to), c.slice, false);
1465
+ const stepResult = newTr.maybeStep(newStep);
1466
+ if (stepResult.failed) {
1467
+ log.error(`processChangeSteps: insert-slice ReplaceStep failed "${stepResult.failed}"`, newStep);
1468
+ return;
1469
+ }
1470
+ mergeTrackedMarks(mapping.map(c.from), newTr.doc, newTr, schema);
1471
+ const to = mapping.map(c.to) + c.slice.size;
1472
+ mergeTrackedMarks(mapping.map(c.to) + (to < newTr.doc.nodeSize ? c.slice.size : 0), newTr.doc, newTr, schema);
1473
+ selectionPos = mapping.map(c.to) + c.slice.size;
1474
+ break;
1475
+ case 'update-node-attrs':
1476
+ const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
1477
+ const oldUpdate = oldDataTracked.reverse().find((d) => {
1478
+ // reversing to start from the most recent change
1479
+ if (d.operation === exports.CHANGE_OPERATION.set_node_attributes &&
1480
+ (d.status === exports.CHANGE_STATUS.pending || d.status === exports.CHANGE_STATUS.rejected)) {
1481
+ return true;
1482
+ }
1483
+ return false;
1484
+ });
1485
+ // if the selected last change is with status "rejected" we need to use oldAttrs from it because
1486
+ // node's actual attributes represent the "rejected" values
1487
+ const lastChangeRejected = oldUpdate && oldUpdate.status === exports.CHANGE_STATUS.rejected;
1488
+ const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1489
+ const { dataTracked, ...restAttrs } = sourceAttrs;
1490
+ const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
1491
+ const newDataTracked = [
1492
+ ...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
1493
+ ];
1494
+ const newUpdate = oldUpdate && oldUpdate.status !== exports.CHANGE_STATUS.rejected
1495
+ ? {
1496
+ ...oldUpdate,
1497
+ updatedAt: emptyAttrs.updatedAt,
1498
+ }
1499
+ : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
1500
+ // Dont add update changes if there exists already an insert change for this node
1501
+ if ((JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) ||
1502
+ c.node.type === c.node.type.schema.nodes.citation) &&
1503
+ !oldDataTracked.find((d) => d.operation === exports.CHANGE_OPERATION.insert && d.status === exports.CHANGE_STATUS.pending)) {
1504
+ newDataTracked.push(newUpdate);
1505
+ }
1506
+ newTr.setNodeMarkup(mapping.map(c.pos), undefined, {
1507
+ ...c.newAttrs,
1508
+ dataTracked: newDataTracked.length > 0 ? newDataTracked : null,
1509
+ }, c.node.marks);
1510
+ break;
1511
+ default:
1512
+ log.error(`processChangeSteps: unknown change type`, c);
1513
+ return;
1494
1514
  }
1495
1515
  const newestStep = newTr.steps[newTr.steps.length - 1];
1496
1516
  if (step !== newestStep) {
package/dist/index.js CHANGED
@@ -154,13 +154,14 @@ const enableDebug = (enabled) => {
154
154
  }
155
155
  };
156
156
 
157
- var _ChangeSet_changes;
157
+ var _ChangeSet_instances, _ChangeSet_changes, _ChangeSet_isSameNodeChange, _ChangeSet_isNotPendingOrDeleted;
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);
164
165
  _ChangeSet_changes.set(this, void 0);
165
166
  __classPrivateFieldSet(this, _ChangeSet_changes, changes, "f");
166
167
  }
@@ -191,7 +192,10 @@ class ChangeSet {
191
192
  rootNodes.push(currentNodeChange);
192
193
  currentNodeChange = undefined;
193
194
  }
194
- if (currentNodeChange && c.from < currentNodeChange.to) {
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))) {
195
199
  currentNodeChange.children.push(c);
196
200
  }
197
201
  else if (c.type === 'node-change') {
@@ -313,7 +317,12 @@ class ChangeSet {
313
317
  return change.type === 'node-attr-change';
314
318
  }
315
319
  }
316
- _ChangeSet_changes = new WeakMap();
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
+ };
317
326
 
318
327
  /*!
319
328
  * © 2021 Atypon Systems LLC
@@ -1395,94 +1404,105 @@ function processChangeSteps(changes, startPos, newTr, emptyAttrs, schema) {
1395
1404
  const deleteAttrs = createNewDeleteAttrs(emptyAttrs);
1396
1405
  let selectionPos = startPos;
1397
1406
  // @TODO add custom handler / condition?
1407
+ let deletesCounter = 0; // counter for deletion
1398
1408
  changes.forEach((c) => {
1399
1409
  let step = newTr.steps[newTr.steps.length - 1];
1400
- log.info('process change: ', c);
1401
- // const handled = customStepHandler(changes, newTr, emptyAttrs) // ChangeStep[] | undefined
1402
- if (c.type === 'delete-node') {
1403
- deleteOrSetNodeDeleted(c.node, mapping.map(c.pos), newTr, deleteAttrs);
1404
- const newestStep = newTr.steps[newTr.steps.length - 1];
1405
- if (step !== newestStep) {
1406
- mapping.appendMap(newestStep.getMap());
1407
- step = newestStep;
1408
- }
1409
- mergeTrackedMarks(mapping.map(c.pos), newTr.doc, newTr, schema);
1410
- }
1411
- else if (c.type === 'delete-text') {
1412
- const node = newTr.doc.nodeAt(mapping.map(c.pos));
1413
- if (!node) {
1414
- log.error(`processChangeSteps: no text node found for text-change`, c);
1415
- return;
1416
- }
1417
- const where = deleteTextIfInserted(node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1418
- mergeTrackedMarks(where, newTr.doc, newTr, schema);
1419
- }
1420
- else if (c.type === 'merge-fragment') {
1421
- let insertPos = mapping.map(c.mergePos);
1422
- // The default insert position for block nodes is either the start of the merged content or the end.
1423
- // Incase text was merged, this must be updated as the start or end of the node doesn't map to the
1424
- // actual position of the merge. Currently the inserted content is inserted at the start or end
1425
- // of the merged content, TODO reverse the start/end when end/start token?
1426
- if (c.node.isText) {
1427
- // When merging text we must delete text in the same go as well, as the from/to boundary goes through
1428
- // the text node.
1429
- insertPos = deleteTextIfInserted(c.node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1410
+ switch (c.type) {
1411
+ case "delete-node":
1412
+ deletesCounter++; // increase the counter for deleted nodes
1413
+ let trackedData = getBlockInlineTrackedData(c.node);
1414
+ const inserted = trackedData === null || trackedData === void 0 ? void 0 : trackedData.find((d) => d.operation === CHANGE_OPERATION.insert);
1415
+ // For inserted node: the top node and its content (children nodes) is deleted in the first step
1416
+ if (inserted && deletesCounter > 1)
1417
+ return false;
1418
+ deleteOrSetNodeDeleted(c.node, mapping.map(c.pos), newTr, deleteAttrs);
1430
1419
  const newestStep = newTr.steps[newTr.steps.length - 1];
1431
1420
  if (step !== newestStep) {
1432
1421
  mapping.appendMap(newestStep.getMap());
1433
1422
  step = newestStep;
1434
1423
  }
1435
- }
1436
- if (c.fragment.size > 0) {
1437
- newTr.insert(insertPos, c.fragment);
1438
- }
1439
- }
1440
- else if (c.type === 'insert-slice') {
1441
- const newStep = new ReplaceStep(mapping.map(c.from), mapping.map(c.to), c.slice, false);
1442
- const stepResult = newTr.maybeStep(newStep);
1443
- if (stepResult.failed) {
1444
- log.error(`processChangeSteps: insert-slice ReplaceStep failed "${stepResult.failed}"`, newStep);
1445
- return;
1446
- }
1447
- mergeTrackedMarks(mapping.map(c.from), newTr.doc, newTr, schema);
1448
- const to = mapping.map(c.to) + c.slice.size;
1449
- mergeTrackedMarks(mapping.map(c.to) + (to < newTr.doc.nodeSize ? c.slice.size : 0), newTr.doc, newTr, schema);
1450
- selectionPos = mapping.map(c.to) + c.slice.size;
1451
- }
1452
- else if (c.type === 'update-node-attrs') {
1453
- const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
1454
- const oldUpdate = oldDataTracked.reverse().find((d) => {
1455
- // reversing to start from the most recent change
1456
- if (d.operation === CHANGE_OPERATION.set_node_attributes &&
1457
- (d.status === CHANGE_STATUS.pending || d.status === CHANGE_STATUS.rejected)) {
1458
- return true;
1424
+ mergeTrackedMarks(mapping.map(c.pos), newTr.doc, newTr, schema);
1425
+ break;
1426
+ case "delete-text":
1427
+ const node = newTr.doc.nodeAt(mapping.map(c.pos));
1428
+ if (!node) {
1429
+ log.error(`processChangeSteps: no text node found for text-change`, c);
1430
+ return;
1459
1431
  }
1460
- return false;
1461
- });
1462
- // if the selected last change is with status "rejected" we need to use oldAttrs from it because
1463
- // node's actual attributes represent the "rejected" values
1464
- const lastChangeRejected = oldUpdate && oldUpdate.status === CHANGE_STATUS.rejected;
1465
- const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1466
- const { dataTracked, ...restAttrs } = sourceAttrs;
1467
- const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
1468
- const newDataTracked = [
1469
- ...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
1470
- ];
1471
- const newUpdate = oldUpdate && oldUpdate.status !== CHANGE_STATUS.rejected
1472
- ? {
1473
- ...oldUpdate,
1474
- updatedAt: emptyAttrs.updatedAt,
1432
+ const where = deleteTextIfInserted(node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1433
+ mergeTrackedMarks(where, newTr.doc, newTr, schema);
1434
+ break;
1435
+ case 'merge-fragment':
1436
+ let insertPos = mapping.map(c.mergePos);
1437
+ // The default insert position for block nodes is either the start of the merged content or the end.
1438
+ // Incase text was merged, this must be updated as the start or end of the node doesn't map to the
1439
+ // actual position of the merge. Currently the inserted content is inserted at the start or end
1440
+ // of the merged content, TODO reverse the start/end when end/start token?
1441
+ if (c.node.isText) {
1442
+ // When merging text we must delete text in the same go as well, as the from/to boundary goes through
1443
+ // the text node.
1444
+ insertPos = deleteTextIfInserted(c.node, mapping.map(c.pos), newTr, schema, deleteAttrs, mapping.map(c.from), mapping.map(c.to));
1445
+ const newestStep = newTr.steps[newTr.steps.length - 1];
1446
+ if (step !== newestStep) {
1447
+ mapping.appendMap(newestStep.getMap());
1448
+ step = newestStep;
1449
+ }
1475
1450
  }
1476
- : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
1477
- // Dont add update changes if there exists already an insert change for this node
1478
- if (JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) &&
1479
- !oldDataTracked.find((d) => d.operation === CHANGE_OPERATION.insert)) {
1480
- newDataTracked.push(newUpdate);
1481
- }
1482
- newTr.setNodeMarkup(mapping.map(c.pos), undefined, {
1483
- ...c.newAttrs,
1484
- dataTracked: newDataTracked.length > 0 ? newDataTracked : null,
1485
- }, c.node.marks);
1451
+ if (c.fragment.size > 0) {
1452
+ newTr.insert(insertPos, c.fragment);
1453
+ }
1454
+ break;
1455
+ case 'insert-slice':
1456
+ const newStep = new ReplaceStep(mapping.map(c.from), mapping.map(c.to), c.slice, false);
1457
+ const stepResult = newTr.maybeStep(newStep);
1458
+ if (stepResult.failed) {
1459
+ log.error(`processChangeSteps: insert-slice ReplaceStep failed "${stepResult.failed}"`, newStep);
1460
+ return;
1461
+ }
1462
+ mergeTrackedMarks(mapping.map(c.from), newTr.doc, newTr, schema);
1463
+ const to = mapping.map(c.to) + c.slice.size;
1464
+ mergeTrackedMarks(mapping.map(c.to) + (to < newTr.doc.nodeSize ? c.slice.size : 0), newTr.doc, newTr, schema);
1465
+ selectionPos = mapping.map(c.to) + c.slice.size;
1466
+ break;
1467
+ case 'update-node-attrs':
1468
+ const oldDataTracked = getBlockInlineTrackedData(c.node) || [];
1469
+ const oldUpdate = oldDataTracked.reverse().find((d) => {
1470
+ // reversing to start from the most recent change
1471
+ if (d.operation === CHANGE_OPERATION.set_node_attributes &&
1472
+ (d.status === CHANGE_STATUS.pending || d.status === CHANGE_STATUS.rejected)) {
1473
+ return true;
1474
+ }
1475
+ return false;
1476
+ });
1477
+ // if the selected last change is with status "rejected" we need to use oldAttrs from it because
1478
+ // node's actual attributes represent the "rejected" values
1479
+ const lastChangeRejected = oldUpdate && oldUpdate.status === CHANGE_STATUS.rejected;
1480
+ const sourceAttrs = (oldUpdate === null || oldUpdate === void 0 ? void 0 : oldUpdate.oldAttrs) || c.node.attrs;
1481
+ const { dataTracked, ...restAttrs } = sourceAttrs;
1482
+ const oldAttrs = lastChangeRejected ? oldUpdate.oldAttrs : restAttrs;
1483
+ const newDataTracked = [
1484
+ ...oldDataTracked.filter((d) => !oldUpdate || d.id !== oldUpdate.id || lastChangeRejected),
1485
+ ];
1486
+ const newUpdate = oldUpdate && oldUpdate.status !== CHANGE_STATUS.rejected
1487
+ ? {
1488
+ ...oldUpdate,
1489
+ updatedAt: emptyAttrs.updatedAt,
1490
+ }
1491
+ : addTrackIdIfDoesntExist(createNewUpdateAttrs(emptyAttrs, lastChangeRejected ? oldAttrs : c.node.attrs));
1492
+ // Dont add update changes if there exists already an insert change for this node
1493
+ if ((JSON.stringify(oldAttrs) !== JSON.stringify(c.newAttrs) ||
1494
+ c.node.type === c.node.type.schema.nodes.citation) &&
1495
+ !oldDataTracked.find((d) => d.operation === CHANGE_OPERATION.insert && d.status === CHANGE_STATUS.pending)) {
1496
+ newDataTracked.push(newUpdate);
1497
+ }
1498
+ newTr.setNodeMarkup(mapping.map(c.pos), undefined, {
1499
+ ...c.newAttrs,
1500
+ dataTracked: newDataTracked.length > 0 ? newDataTracked : null,
1501
+ }, c.node.marks);
1502
+ break;
1503
+ default:
1504
+ log.error(`processChangeSteps: unknown change type`, c);
1505
+ return;
1486
1506
  }
1487
1507
  const newestStep = newTr.steps[newTr.steps.length - 1];
1488
1508
  if (step !== newestStep) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manuscripts/track-changes-plugin",
3
- "version": "1.7.1",
3
+ "version": "1.7.2-LEAN-3046",
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",