Skip to content

Commit 32e525c

Browse files
authored
Merge pull request #413 from Harbour-Enterprises/nick/floating-comments2
Comments plugin fixes
2 parents 8f907ac + 26bcb32 commit 32e525c

5 files changed

Lines changed: 65 additions & 65 deletions

File tree

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export function translateCommentNode(params, type) {
1818

1919
// Check if the comment is resolved
2020
const originalComment = params.comments.find((comment) => {
21-
return comment.commentId == nodeId || comment.importedId == nodeId;
21+
return comment.commentId == nodeId;
2222
});
2323

2424
if (!originalComment) return;
@@ -93,8 +93,8 @@ export const getCommentDefinition = (comment, commentId, allComments) => {
9393

9494
const attributes = {
9595
'w:id': String(commentId),
96-
'w:author': comment.creatorName,
97-
'w:email': comment.creatorEmail,
96+
'w:author': comment.creatorName || comment.importedAuthor?.name,
97+
'w:email': comment.creatorEmail || comment.importedAuthor?.email,
9898
'w:date': toIsoNoFractional(comment.createdTime),
9999
'w:initials': getInitials(comment.creatorName),
100100
'w:done': comment.resolvedTime ? '1' : '0',

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export function importCommentData({ docx }) {
2424
const extractedComments = allComments.map((el) => {
2525

2626
const { attributes } = el;
27-
const commentId = attributes['w:id'];
27+
const importedId = attributes['w:id'];
2828
const authorName = attributes['w:author'];
2929
const authorEmail = attributes['w:email'];
3030
const initials = attributes['w:initials'];
@@ -44,8 +44,8 @@ export function importCommentData({ docx }) {
4444
const paraId = attrs['w14:paraId'];
4545

4646
return {
47-
id: uuidv4(),
48-
importedId: commentId,
47+
commentId: uuidv4(),
48+
importedId,
4949
creatorName: authorName,
5050
creatorEmail: authorEmail,
5151
createdTime: unixTimestampMs,
@@ -88,7 +88,7 @@ const generateCommentsWithExtendedData = ({ docx, comments }) => {
8888

8989
const newComment = {
9090
...comment,
91-
commentId: superdocCommentId,
91+
commentId: superdocCommentId || uuidv4(),
9292
isDone,
9393
parentCommentId: parentComment?.id,
9494
};

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

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import { CommentsPluginKey } from './comments-plugin.js';
77
*
88
* @param {Object} param0
99
* @param {string} param0.commentId The comment ID
10-
* @param {string} param0.importedId The imported ID
1110
* @param {import('prosemirror-state').EditorState} state The current editor state
1211
* @param {import('prosemirror-state').Transaction} tr The current transaction
1312
* @param {Function} param0.dispatch The dispatch function
1413
* @returns {void}
1514
*/
16-
export const removeCommentsById = ({ commentId, importedId, state, tr, dispatch }) => {
17-
const positions = getCommentPositionsById(commentId, importedId, state.doc);
15+
export const removeCommentsById = ({ commentId, state, tr, dispatch }) => {
16+
const positions = getCommentPositionsById(commentId, state.doc);
1817

1918
// Remove the mark
2019
positions.forEach(({ from, to }) => {
@@ -28,21 +27,19 @@ export const removeCommentsById = ({ commentId, importedId, state, tr, dispatch
2827
* Get the positions of a comment by ID
2928
*
3029
* @param {String} commentId The comment ID
31-
* @param {String} importedId The imported ID
3230
* @param {import('prosemirror-model').Node} doc The prosemirror document
3331
* @returns {Array} The positions of the comment
3432
*/
35-
export const getCommentPositionsById = (commentId, importedId, doc) => {
33+
export const getCommentPositionsById = (commentId, doc) => {
3634
const positions = [];
3735
doc.descendants((node, pos) => {
3836
const { marks } = node;
3937
const commentMark = marks.find((mark) => mark.type.name === CommentMarkName);
4038

4139
if (commentMark) {
4240
const { attrs } = commentMark;
43-
const { commentId: currentCommentId, importedId: currentImportedId } = attrs;
44-
const wid = currentCommentId || currentImportedId;
45-
if (wid == commentId || wid == importedId) {
41+
const { commentId: currentCommentId, } = attrs;
42+
if (commentId === currentCommentId) {
4643
positions.push({ from: pos, to: pos + node.nodeSize });
4744
}
4845
}
@@ -71,11 +68,11 @@ export const prepareCommentsForExport = (doc, tr, schema, comments = []) => {
7168
if (commentMark) {
7269

7370
const { attrs = {} } = commentMark;
74-
const { commentId, importedId } = attrs;
71+
const { commentId } = attrs;
7572

7673
if (commentId === 'pending') return;
77-
if (seen.has(commentId || importedId)) return;
78-
seen.add(commentId || importedId);
74+
if (seen.has(commentId)) return;
75+
seen.add(commentId);
7976

8077
const commentStartNodeAttrs = getPreparedComment(commentMark.attrs);
8178
const startNode = schema.nodes.commentRangeStart.create(commentStartNodeAttrs);
@@ -90,7 +87,7 @@ export const prepareCommentsForExport = (doc, tr, schema, comments = []) => {
9087
node: endNode,
9188
});
9289

93-
const parentId = commentId || importedId;
90+
const parentId = commentId;
9491
if (parentId) {
9592
const childComments = comments
9693
.filter((c) => c.parentCommentId == parentId || c.parentCommentId == parentId)
@@ -140,10 +137,9 @@ export const prepareCommentsForExport = (doc, tr, schema, comments = []) => {
140137
* @returns {Object} The prepared comment attributes
141138
*/
142139
export const getPreparedComment = (attrs) => {
143-
const { commentId, importedId, internal } = attrs;
144-
const wid = commentId ? commentId : importedId;
140+
const { commentId, internal } = attrs;
145141
return {
146-
'w:id': wid,
142+
'w:id': commentId,
147143
internal: internal,
148144
};
149145
}
@@ -163,27 +159,36 @@ export const prepareCommentsForImport = (doc, tr, schema, converter) => {
163159

164160
doc.descendants((node, pos) => {
165161
const { type } = node;
162+
163+
const commentNodes = ['commentRangeStart', 'commentRangeEnd', 'commentReference'];
164+
if (!commentNodes.includes(type.name)) return;
165+
166+
const matchingImportedComment = converter.comments?.find((c) => c.importedId == node.attrs['w:id']) || {};
167+
const { commentId } = matchingImportedComment;
168+
if (!commentId) return;
166169

167170
// If the node is a commentRangeStart, record it so we can place a mark once we find the end.
168171
if (type.name === 'commentRangeStart') {
169172
toMark.push({
170-
'w:id': node.attrs['w:id'],
173+
'w:id': commentId,
174+
importedId: node.attrs['w:id'],
171175
internal: false,
172176
start: pos,
173177
});
174-
178+
175179
// We'll remove this node from the final doc
176180
toDelete.push({ start: pos, end: pos + 1 });
177181
}
178182

179183
// When we reach the commentRangeEnd, add a mark spanning from start to current pos,
180184
// then mark it for deletion as well.
181185
else if (type.name === 'commentRangeEnd') {
182-
const itemToMark = toMark.find((p) => p['w:id'] === node.attrs['w:id']);
186+
const itemToMark = toMark.find((p) => p.importedId === node.attrs['w:id']);
183187
if (!itemToMark) return; // No matching start? just skip
184188

185189
const { start } = itemToMark;
186190
const markAttrs = {
191+
commentId,
187192
importedId: node.attrs['w:id'],
188193
internal: itemToMark.internal,
189194
};

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

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -43,48 +43,45 @@ export const CommentsPlugin = Extension.create({
4343
)
4444

4545
dispatch(tr)
46-
return true
46+
return true;
4747
},
4848

4949
removeComment:
5050
({ commentId, importedId }) =>
5151
({ tr, dispatch, state }) => {
52-
tr.setMeta(CommentsPluginKey, { event: 'deleted' })
53-
removeCommentsById({ commentId, importedId, state, tr, dispatch })
52+
tr.setMeta(CommentsPluginKey, { event: 'deleted' });
53+
removeCommentsById({ commentId, importedId, state, tr, dispatch });
5454
},
5555

5656
setActiveComment:
57-
({ commentId, importedId }) =>
57+
({ commentId }) =>
5858
({ tr, dispatch }) => {
59-
let activeThreadId = importedId
60-
if (importedId === undefined || importedId === null) {
61-
activeThreadId = commentId
62-
}
63-
tr.setMeta(CommentsPluginKey, { type: 'setActiveComment', activeThreadId })
64-
return true
59+
let activeThreadId = commentId;
60+
tr.setMeta(CommentsPluginKey, { type: 'setActiveComment', activeThreadId });
61+
return true;
6562
},
6663

6764
setCommentInternal:
68-
({ commentId, importedId, isInternal }) =>
65+
({ commentId, isInternal }) =>
6966
({ tr, dispatch, state }) => {
70-
const { doc } = state
71-
let foundStartNode
72-
let foundPos
67+
const { doc } = state;
68+
let foundStartNode;
69+
let foundPos;
7370

7471
// Find the commentRangeStart node that matches the comment ID
7572
tr.setMeta(CommentsPluginKey, { event: 'update' })
7673
doc.descendants((node, pos) => {
77-
if (foundStartNode) return
74+
if (foundStartNode) return;
7875

79-
const { marks = [] } = node
80-
const commentMark = marks.find((mark) => mark.type.name === CommentMarkName)
76+
const { marks = [] } = node;
77+
const commentMark = marks.find((mark) => mark.type.name === CommentMarkName);
8178

8279
if (commentMark) {
83-
const { attrs } = commentMark
84-
const wid = attrs.commentId || attrs.importedId
85-
if (wid == commentId || wid == importedId) {
86-
foundStartNode = node
87-
foundPos = pos
80+
const { attrs } = commentMark;
81+
const wid = attrs.commentId;
82+
if (wid === commentId) {
83+
foundStartNode = node;
84+
foundPos = pos;
8885
}
8986
}
9087
})
@@ -108,17 +105,18 @@ export const CommentsPlugin = Extension.create({
108105
},
109106

110107
resolveComment:
111-
({ commentId, importedId }) =>
108+
({ commentId }) =>
112109
({ tr, dispatch, state }) => {
113110
tr.setMeta(CommentsPluginKey, { event: 'update' })
114-
removeCommentsById({ commentId, importedId, state, tr, dispatch })
111+
removeCommentsById({ commentId, state, tr, dispatch })
115112
},
116113
}
117114
},
118115

119116
addPmPlugins() {
120117
const editor = this.editor
121118
let shouldUpdate;
119+
let activeThreadId;
122120

123121
const commentsPlugin = new Plugin({
124122
key: CommentsPluginKey,
@@ -164,26 +162,24 @@ export const CommentsPlugin = Extension.create({
164162
);
165163
};
166164

165+
// Check for changes in the actively selected comment
167166
const trChangedActiveComment = meta?.type === 'setActiveComment';
168167
if ((!tr.docChanged && tr.selectionSet) || trChangedActiveComment) {
169-
170168
const { selection } = tr;
171-
let activeThreadId = getActiveCommentId(newEditorState.doc, selection);
169+
const currentActiveThread = getActiveCommentId(newEditorState.doc, selection);
172170
if (trChangedActiveComment) activeThreadId = meta.activeThreadId;
173171

174-
const previousSelectionId = pluginState.activeThreadId;
175-
if (previousSelectionId !== activeThreadId || trChangedActiveComment) {
176-
pluginState.activeThreadId = activeThreadId;
172+
const previousSelectionId = activeThreadId;
173+
if (previousSelectionId !== currentActiveThread) {
174+
activeThreadId = currentActiveThread;
177175
const update = {
178176
type: comments_module_events.SELECTED,
179177
activeCommentId: activeThreadId ? activeThreadId : null
180178
};
181179

180+
shouldUpdate = true;
182181
editor.emit('commentsUpdate', update);
183-
pluginState.changedActiveThread = true;
184-
} else {
185-
pluginState.changedActiveThread = false;
186-
}
182+
};
187183
};
188184

189185
const { allCommentIds, allCommentPositions } = pluginState;
@@ -207,11 +203,8 @@ export const CommentsPlugin = Extension.create({
207203
update(view, prevState) {
208204
const { state } = view
209205
const { doc, tr } = state
210-
211-
const pluginState = CommentsPluginKey.getState(state)
212-
const { activeThreadId} = pluginState;
213206

214-
if (prevDoc && prevDoc.eq(doc) || !shouldUpdate) return;
207+
if (prevDoc && prevDoc.eq(doc) && !shouldUpdate) return;
215208
prevDoc = doc;
216209

217210
const decorations = []
@@ -237,6 +230,7 @@ export const CommentsPlugin = Extension.create({
237230
});
238231

239232
const isInternal = attrs.internal;
233+
240234
const color = getHighlightColor({ activeThreadId, threadId, isInternal, editor });
241235
const deco = Decoration.inline(pos, pos + node.nodeSize, {
242236
style: `background-color: ${color}`,
@@ -263,6 +257,7 @@ export const CommentsPlugin = Extension.create({
263257
const decorationSet = DecorationSet.create(doc, decorations)
264258

265259
// Compare new decorations with the old state to avoid infinite loop
260+
const pluginState = CommentsPluginKey.getState(state)
266261
const oldDecorations = pluginState.decorations
267262

268263
// We only dispatch if something actually changed
@@ -280,6 +275,7 @@ export const CommentsPlugin = Extension.create({
280275

281276
// Remember the new decorations for next time
282277
prevDecorations = decorationSet
278+
shouldUpdate = false;
283279
},
284280
}
285281
},

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -445,14 +445,13 @@ export const useCommentsStore = defineStore('comments', () => {
445445
const document = superdocStore.getDocument(documentId);
446446

447447
if (__IS_DEBUG__) console.debug('[processLoadedDocxComments] processing comments...', comments);
448-
448+
449449
comments.forEach((comment) => {
450450
const importedName = `${comment.creatorName.replace('(imported)', '')} (imported)`
451451
const newComment = useComment({
452452
fileId: documentId,
453453
fileType: document.type,
454-
importedId: comment.importedId ? Number(comment.importedId): null,
455-
commentId: comment.id,
454+
commentId: comment.commentId,
456455
isInternal: false,
457456
parentCommentId: comment.parentCommentId,
458457
importedAuthor: {

0 commit comments

Comments
 (0)