@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.
- package/dist/index.cjs +102 -82
- package/dist/index.js +102 -82
- 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 &&
|
|
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
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
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
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
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
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
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
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
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 &&
|
|
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
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
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
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
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
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
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
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
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.
|
|
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",
|