Skip to content

Commit 65201df

Browse files
committed
track changes and comments fixes
1 parent 0959c13 commit 65201df

7 files changed

Lines changed: 121 additions & 49 deletions

File tree

packages/super-editor/src/core/super-converter/v2/exporter/commentsExporter.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ export const getCommentDefinition = (comment, commentId, allComments) => {
100100
'w15:paraId': comment.commentParaId,
101101
'custom:internalId': comment.commentId || comment.internalId,
102102
'custom:trackedChange': comment.trackedChange,
103-
'custom:trackedChangeText': comment.trackedChangeText,
103+
'custom:trackedChangeText': comment.trackedChangeText || null,
104104
'custom:trackedChangeType': comment.trackedChangeType,
105+
'custom:trackedDeletedText': comment.deletedText || null,
105106
};
106107

107108
// Add the w15:paraIdParent attribute if the comment has a parent
@@ -173,6 +174,7 @@ export const updateCommentsXml = (commentDefs = [], commentsXml) => {
173174
'custom:trackedChange': commentDef.attributes['custom:trackedChange'],
174175
'custom:trackedChangeText': commentDef.attributes['custom:trackedChangeText'],
175176
'custom:trackedChangeType': commentDef.attributes['custom:trackedChangeType'],
177+
'custom:trackedDeletedText': commentDef.attributes['custom:trackedDeletedText'],
176178
'xmlns:custom': 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
177179
};
178180
});

packages/super-editor/src/core/super-converter/v2/importer/documentCommentsImporter.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@ export function importCommentData({ docx }) {
3030
const createdDate = attributes['w:date'];
3131
const internalId = attributes['custom:internalId'];
3232
const trackedChange = attributes['custom:trackedChange'] === 'true';
33-
const trackedChangeText = attributes['custom:trackedChangeText'];
3433
const trackedChangeType = attributes['custom:trackedChangeType'];
34+
const trackedChangeText = attributes['custom:trackedChangeText'] !== 'null'
35+
? attributes['custom:trackedChangeText']
36+
: null;
37+
const trackedDeletedText = attributes['custom:trackedDeletedText'] !== 'null'
38+
? attributes['custom:trackedDeletedText']
39+
: null;
3540

3641
const date = new Date(createdDate);
3742
const unixTimestampMs = date.getTime();
@@ -59,6 +64,7 @@ export function importCommentData({ docx }) {
5964
trackedChange,
6065
trackedChangeText,
6166
trackedChangeType,
67+
trackedDeletedText,
6268
};
6369
});
6470

packages/super-editor/src/extensions/comment/comments-plugin.js

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ const getActiveCommentId = (doc, selection) => {
344344
// If we have a tracked change, we can return it right away
345345
const trackedChangeNode = getTrackedChangeNode(nodeAtPos);
346346
if (trackedChangeNode) {
347-
return trackedChangeNode.attrs.wid;
347+
return trackedChangeNode.attrs.id;
348348
}
349349

350350
// Otherwise, we need to check for comment nodes
@@ -408,19 +408,30 @@ const getActiveCommentId = (doc, selection) => {
408408
const getTrackedChangeNode = (node) => {
409409
if (!node) return;
410410
const nodeMarks = node.marks;
411-
const trackedChangeMark = nodeMarks?.find((mark) => mark.type.name === TrackInsertMarkName);
411+
const trackedInsertMark = nodeMarks?.find((mark) => mark.type.name === TrackInsertMarkName);
412412
const trackedDeleteMark = nodeMarks?.find((mark) => mark.type.name === TrackDeleteMarkName);
413413
const trackedFormatMark = nodeMarks?.find((mark) => mark.type.name === TrackFormatMarkName);
414-
return trackedChangeMark || trackedDeleteMark || trackedFormatMark;
414+
return trackedInsertMark || trackedDeleteMark || trackedFormatMark;
415415
};
416416

417417
const handleTrackedChangeTransaction = (trackedChangeMeta, trackedChanges, newEditorState, editor) => {
418-
const { deletionMark, insertedMark, formatMark, deletionNodes } = trackedChangeMeta;
419-
if (!deletionMark && !insertedMark && !formatMark) return;
418+
const {
419+
insertedMark,
420+
deletionMark,
421+
formatMark,
422+
deletionNodes,
423+
} = trackedChangeMeta;
424+
425+
if (!insertedMark && !deletionMark && !formatMark) {
426+
return;
427+
}
420428

421429
const newTrackedChanges = { ...trackedChanges };
422430
let id = insertedMark?.attrs?.id || deletionMark?.attrs?.id || formatMark?.attrs?.id;
423-
if (!id) return trackedChanges;
431+
432+
if (!id) {
433+
return trackedChanges;
434+
}
424435

425436
// Maintain a map of tracked changes with their inserted/deleted ids
426437
let isNewChange = false;
@@ -446,6 +457,7 @@ const handleTrackedChangeTransaction = (trackedChangeMeta, trackedChanges, newEd
446457
};
447458
});
448459
}
460+
449461
const emitParams = createOrUpdateTrackedChangeComment({
450462
documentId: editor.options.documentId,
451463
event: isNewChange ? 'add' : 'update',
@@ -455,7 +467,7 @@ const handleTrackedChangeTransaction = (trackedChangeMeta, trackedChanges, newEd
455467
formatMark,
456468
},
457469
deletionNodes,
458-
nodes: nodes,
470+
nodes,
459471
newEditorState,
460472
});
461473

@@ -464,21 +476,47 @@ const handleTrackedChangeTransaction = (trackedChangeMeta, trackedChanges, newEd
464476
return newTrackedChanges;
465477
};
466478

467-
const getTrackedChangeText = ({ node, mark, trackedChangeType, isDeletionInsertion, deletionNodes = [] }) => {
468-
const deletionText = deletionNodes.length ? deletionNodes[0].text : null;
479+
const getTrackedChangeText = ({
480+
state,
481+
node,
482+
mark,
483+
marks,
484+
trackedChangeType,
485+
isDeletionInsertion,
486+
deletionNodes = [],
487+
}) => {
488+
let trackedChangeText = '';
489+
let deletionText = '';
469490

470-
let nextNode = null; //
471-
let trackedChangeText = isDeletionInsertion ? nextNode?.text : node?.text;
472-
if (!trackedChangeText) trackedChangeText = '';
491+
if (trackedChangeType === TrackInsertMarkName) {
492+
trackedChangeText = node?.text ?? '';
493+
}
473494

474495
// If this is a format change, let's get the string of what changes were made
475-
const isFormatChange = trackedChangeType === TrackFormatMarkName;
476-
if (isFormatChange) trackedChangeText = translateFormatChangesToEnglish(mark.attrs)
496+
if (trackedChangeType === TrackFormatMarkName) {
497+
trackedChangeText = translateFormatChangesToEnglish(mark.attrs);
498+
}
499+
500+
if (trackedChangeType === TrackDeleteMarkName || isDeletionInsertion) {
501+
deletionText = node?.text ?? '';
502+
503+
if (isDeletionInsertion) {
504+
let { id } = marks.deletionMark.attrs;
505+
let deletionNode = findNode(state.doc, (node) => {
506+
const { marks = [] } = node;
507+
const changeMarks = marks.filter((mark) => TRACK_CHANGE_MARKS.includes(mark.type.name));
508+
if (!changeMarks.length) return false;
509+
const hasMatchingId = changeMarks.find((mark) => mark.attrs.id === id);
510+
if (hasMatchingId) return true;
511+
});
512+
deletionText = deletionNode?.node.text ?? '';
513+
}
514+
}
477515

478516
return {
479517
deletionText,
480518
trackedChangeText,
481-
}
519+
};
482520
};
483521

484522
const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes, newEditorState, documentId }) => {
@@ -487,39 +525,34 @@ const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes
487525

488526
const { name: trackedChangeType } = type;
489527
const { author, authorEmail, date } = attrs;
490-
491-
let id = attrs.id;
492-
493-
// if (!nodes.length) {
494-
// return;
495-
// }
528+
const id = attrs.id;
496529

497530
const node = nodes[0];
498-
const nextTrackedNode = null; //
499-
const isDeletionInsertion = (
500-
trackedChangeType === TrackDeleteMarkName && nextTrackedNode?.type?.name === TrackInsertMarkName
501-
);
531+
const isDeletionInsertion = !!(marks.insertedMark && marks.deletionMark);
502532

503533
let existingNode;
504534
newEditorState.doc.descendants((node, pos) => {
505535
const { marks = [] } = node;
506536
const changeMarks = marks.filter((mark) => TRACK_CHANGE_MARKS.includes(mark.type.name));
507537
if (!changeMarks.length) return;
508-
509538
const hasMatchingId = changeMarks.find((mark) => mark.attrs.id === id);
510539
if (hasMatchingId) existingNode = node;
511-
if (!existingNode) return false;
540+
if (existingNode) return false;
512541
});
513542

514543
const { deletionText, trackedChangeText } = getTrackedChangeText({
544+
state: newEditorState,
515545
node: existingNode || node,
516546
mark: trackedMark,
547+
marks,
517548
trackedChangeType,
518549
isDeletionInsertion,
519-
deletionNodes
550+
deletionNodes,
520551
});
521552

522-
if (!deletionText && !trackedChangeText) return;
553+
if (!deletionText && !trackedChangeText) {
554+
return;
555+
}
523556

524557
const params = {
525558
event: comments_module_events.ADD,
@@ -536,5 +569,15 @@ const createOrUpdateTrackedChangeComment = ({ event, marks, deletionNodes, nodes
536569

537570
if (event === 'add') params.event = comments_module_events.ADD;
538571
else if (event === 'update') params.event = comments_module_events.UPDATE;
572+
539573
return params;
540-
};
574+
};
575+
576+
function findNode(node, predicate) {
577+
let found = null;
578+
node.descendants((node, pos) => {
579+
if (predicate(node)) found = { node, pos };
580+
if (found) return false;
581+
});
582+
return found;
583+
}

packages/super-editor/src/extensions/track-changes/trackChangesHelpers/addMarkStep.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Node } from 'prosemirror-model';
44
import { TrackDeleteMarkName, TrackFormatMarkName } from '../constants.js';
55
import { v4 as uuidv4 } from 'uuid';
66
import { objectIncludes } from '@core/utilities/objectIncludes.js';
7-
import { TrackChangesBasePluginKey } from '../plugins/index.js';
7+
import { TrackChangesBasePluginKey } from '../plugins/trackChangesBasePlugin.js';
88

99
/**
1010
* Add mark step.
@@ -19,6 +19,7 @@ import { TrackChangesBasePluginKey } from '../plugins/index.js';
1919
*/
2020
export const addMarkStep = ({ state, tr, step, newTr, map, doc, user, date }) => {
2121
const meta = {};
22+
2223
doc.nodesBetween(step.from, step.to, (node, pos) => {
2324
if (!node.isInline) {
2425
return;
@@ -91,8 +92,10 @@ export const addMarkStep = ({ state, tr, step, newTr, map, doc, user, date }) =>
9192
step.to, // Math.min(step.to, pos + node.nodeSize),
9293
newFormatMark,
9394
);
95+
9496
meta.formatMark = newFormatMark;
9597
meta.step = step;
98+
9699
newTr.setMeta(TrackChangesBasePluginKey, meta);
97100
} else if (formatChangeMark) {
98101
newTr.removeMark(Math.max(step.from, pos), Math.min(step.to, pos + node.nodeSize), formatChangeMark);

packages/super-editor/src/extensions/track-changes/trackChangesHelpers/removeMarkStep.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Mapping, RemoveMarkStep } from 'prosemirror-transform';
33
import { Node } from 'prosemirror-model';
44
import { v4 as uuidv4 } from 'uuid';
55
import { TrackDeleteMarkName, TrackFormatMarkName } from '../constants.js';
6+
import { TrackChangesBasePluginKey } from '../plugins/trackChangesBasePlugin.js';
67

78
/**
89
* Remove mark step.
@@ -16,6 +17,8 @@ import { TrackDeleteMarkName, TrackFormatMarkName } from '../constants.js';
1617
* @param {string} options.date Date.
1718
*/
1819
export const removeMarkStep = ({ state, tr, step, newTr, map, doc, user, date }) => {
20+
const meta = {};
21+
1922
doc.nodesBetween(step.from, step.to, (node, pos) => {
2023
if (!node.isInline) {
2124
return true;
@@ -62,18 +65,25 @@ export const removeMarkStep = ({ state, tr, step, newTr, map, doc, user, date })
6265
}
6366

6467
if (after.length || before.length) {
68+
const newFormatMark = state.schema.marks[TrackFormatMarkName].create({
69+
id: uuidv4(),
70+
author: user.name,
71+
authorEmail: user.email,
72+
date,
73+
before,
74+
after,
75+
});
76+
6577
newTr.addMark(
6678
Math.max(step.from, pos),
6779
Math.min(step.to, pos + node.nodeSize),
68-
state.schema.marks[TrackFormatMarkName].create({
69-
id: uuidv4(),
70-
author: user.name,
71-
authorEmail: user.email,
72-
date,
73-
before,
74-
after,
75-
}),
80+
newFormatMark,
7681
);
82+
83+
meta.formatMark = newFormatMark;
84+
meta.step = step;
85+
86+
newTr.setMeta(TrackChangesBasePluginKey, meta);
7787
} else if (formatChangeMark) {
7888
newTr.removeMark(Math.max(step.from, pos), Math.min(step.to, pos + node.nodeSize), formatChangeMark);
7989
}

packages/super-editor/src/extensions/track-changes/trackChangesHelpers/replaceStep.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ export const replaceStep = ({ state, tr, step, newTr, map, doc, user, date, orig
6161
const mirrorIndex = map.maps.length - 1;
6262
map.appendMap(condensedStep.getMap(), mirrorIndex);
6363

64-
// Prepare meta for the transaction
65-
meta.insertedMark = insertedMark;
66-
meta.step = condensedStep;
64+
if (newStep.from !== mappedNewStepTo) {
65+
meta.insertedMark = insertedMark;
66+
meta.step = condensedStep;
67+
}
6768

6869
if (!newTr.selection.eq(trTemp.selection)) {
6970
newTr.setSelection(trTemp.selection);
@@ -78,8 +79,10 @@ export const replaceStep = ({ state, tr, step, newTr, map, doc, user, date, orig
7879
user,
7980
date,
8081
});
82+
8183
meta.deletionNodes = deletionNodes;
8284
meta.deletionMark = deletionMark;
85+
8386
map.appendMapping(deletionMap);
8487
}
8588

packages/superdoc/src/stores/comments-store.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,18 +130,22 @@ export const useCommentsStore = defineStore('comments', () => {
130130
}
131131
});
132132

133-
// If this is a new tracked change, add it to our comments
134133
if (event === 'add') {
134+
// If this is a new tracked change, add it to our comments
135135
addComment({ superdoc, comment });
136-
}
137-
138-
// If we have an update event, simply update the composable comment
139-
else if (event === 'update') {
136+
} else if (event === 'update') {
137+
// If we have an update event, simply update the composable comment
140138
const existingTrackedChange = commentsList.value.find(
141139
(comment) => comment.commentId === changeId
142140
);
143141
if (!existingTrackedChange) return;
142+
144143
existingTrackedChange.trackedChangeText = trackedChangeText;
144+
145+
if (deletedText) {
146+
existingTrackedChange.deletedText = deletedText;
147+
}
148+
145149
const emitData = {
146150
type: COMMENT_EVENTS.UPDATE,
147151
comment: existingTrackedChange.getValues(),
@@ -474,6 +478,7 @@ export const useCommentsStore = defineStore('comments', () => {
474478
trackedChange: comment.trackedChange || false,
475479
trackedChangeText: comment.trackedChangeText,
476480
trackedChangeType: comment.trackedChangeType,
481+
deletedText: comment.trackedDeletedText,
477482
});
478483

479484
addComment({ superdoc, comment: newComment });

0 commit comments

Comments
 (0)