@harbour-enterprises/superdoc 1.4.0 → 1.4.1-next.1

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.
@@ -11946,8 +11946,11 @@
11946
11946
  createAttributeHandler("w:authorEmail", "authorEmail")
11947
11947
  ];
11948
11948
  const encode$L = (params2, encodedAttrs = {}) => {
11949
- const { nodeListHandler, extraParams = {} } = params2;
11949
+ const { nodeListHandler, extraParams = {}, converter } = params2;
11950
11950
  const { node: node2 } = extraParams;
11951
+ if (encodedAttrs.id && converter?.trackedChangeIdMap?.has(encodedAttrs.id)) {
11952
+ encodedAttrs.id = converter.trackedChangeIdMap.get(encodedAttrs.id);
11953
+ }
11951
11954
  const subs = nodeListHandler.handler({
11952
11955
  ...params2,
11953
11956
  insideTrackChange: true,
@@ -11955,6 +11958,9 @@
11955
11958
  path: [...params2.path || [], node2]
11956
11959
  });
11957
11960
  encodedAttrs.importedAuthor = `${encodedAttrs.author} (imported)`;
11961
+ if (converter?.documentOrigin) {
11962
+ encodedAttrs.origin = converter.documentOrigin;
11963
+ }
11958
11964
  subs.forEach((subElement) => {
11959
11965
  subElement.marks = [];
11960
11966
  if (subElement?.content?.[0]) {
@@ -32897,8 +32903,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
32897
32903
  createAttributeHandler("w:authorEmail", "authorEmail")
32898
32904
  ];
32899
32905
  const encode$3 = (params2, encodedAttrs = {}) => {
32900
- const { nodeListHandler, extraParams = {} } = params2;
32906
+ const { nodeListHandler, extraParams = {}, converter } = params2;
32901
32907
  const { node: node2 } = extraParams;
32908
+ if (encodedAttrs.id && converter?.trackedChangeIdMap?.has(encodedAttrs.id)) {
32909
+ encodedAttrs.id = converter.trackedChangeIdMap.get(encodedAttrs.id);
32910
+ }
32902
32911
  const subs = nodeListHandler.handler({
32903
32912
  ...params2,
32904
32913
  insideTrackChange: true,
@@ -32906,6 +32915,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
32906
32915
  path: [...params2.path || [], node2]
32907
32916
  });
32908
32917
  encodedAttrs.importedAuthor = `${encodedAttrs.author} (imported)`;
32918
+ if (converter?.documentOrigin) {
32919
+ encodedAttrs.origin = converter.documentOrigin;
32920
+ }
32909
32921
  subs.forEach((subElement) => {
32910
32922
  subElement.marks = [];
32911
32923
  if (subElement?.content?.[0]) {
@@ -33625,6 +33637,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33625
33637
  });
33626
33638
  const lastElement = parsedElements[parsedElements.length - 1];
33627
33639
  const paraId = lastElement?.attrs?.["w14:paraId"];
33640
+ const commentsExtended = docx["word/commentsExtended.xml"];
33641
+ const threadingMethod = commentsExtended ? "commentsExtended" : "range-based";
33628
33642
  return {
33629
33643
  commentId: internalId || v4(),
33630
33644
  importedId,
@@ -33639,19 +33653,31 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33639
33653
  trackedChangeText,
33640
33654
  trackedChangeType,
33641
33655
  trackedDeletedText,
33642
- isDone: false
33656
+ isDone: false,
33657
+ origin: converter?.documentOrigin || "word",
33658
+ threadingMethod,
33659
+ originalXmlStructure: {
33660
+ hasCommentsExtended: !!commentsExtended,
33661
+ hasCommentsExtensible: !!docx["word/commentsExtensible.xml"],
33662
+ hasCommentsIds: !!docx["word/commentsIds.xml"]
33663
+ }
33643
33664
  };
33644
33665
  });
33645
- const extendedComments = generateCommentsWithExtendedData({ docx, comments: extractedComments });
33666
+ const extendedComments = generateCommentsWithExtendedData({ docx, comments: extractedComments, converter });
33646
33667
  return extendedComments;
33647
33668
  }
33648
- const generateCommentsWithExtendedData = ({ docx, comments }) => {
33669
+ const generateCommentsWithExtendedData = ({ docx, comments, converter }) => {
33649
33670
  if (!comments?.length) return [];
33671
+ const rangeData = extractCommentRangesFromDocument(docx, converter);
33672
+ const { commentsInTrackedChanges } = rangeData;
33673
+ const trackedChangeParentMap = detectThreadingFromTrackedChanges(comments, commentsInTrackedChanges);
33650
33674
  const commentsExtended = docx["word/commentsExtended.xml"];
33651
33675
  if (!commentsExtended) {
33652
- const commentRanges = extractCommentRangesFromDocument(docx);
33653
- const commentsWithThreading = detectThreadingFromRanges(comments, commentRanges);
33654
- return commentsWithThreading.map((comment2) => ({ ...comment2, isDone: comment2.isDone ?? false }));
33676
+ const commentsWithThreading = detectThreadingFromRanges(comments, rangeData);
33677
+ return commentsWithThreading.map((comment2) => ({
33678
+ ...comment2,
33679
+ isDone: comment2.isDone ?? false
33680
+ }));
33655
33681
  }
33656
33682
  const { elements: initialElements = [] } = commentsExtended;
33657
33683
  if (!initialElements?.length) return comments.map((comment2) => ({ ...comment2, isDone: comment2.isDone ?? false }));
@@ -33659,25 +33685,30 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33659
33685
  const commentEx = elements.filter((el) => el.name === "w15:commentEx");
33660
33686
  return comments.map((comment2) => {
33661
33687
  const extendedDef = commentEx.find((ce2) => {
33662
- const isIncludedInCommentElements = comment2.elements?.some(
33663
- (el) => el.attrs?.["w14:paraId"] === ce2.attributes["w15:paraId"]
33664
- );
33665
- return isIncludedInCommentElements;
33666
- });
33667
- if (!extendedDef) return { ...comment2, isDone: comment2.isDone ?? false };
33668
- const { isDone, paraIdParent } = getExtendedDetails(extendedDef);
33669
- let parentComment;
33670
- if (paraIdParent) {
33671
- parentComment = comments.find(
33672
- (c2) => c2.paraId === paraIdParent || c2.elements?.some((el) => el.attrs?.["w14:paraId"] === paraIdParent)
33673
- );
33688
+ return comment2.elements?.some((el) => el.attrs?.["w14:paraId"] === ce2.attributes["w15:paraId"]);
33689
+ });
33690
+ let isDone = comment2.isDone ?? false;
33691
+ let parentCommentId = void 0;
33692
+ const trackedChangeParent = trackedChangeParentMap.get(comment2.importedId);
33693
+ const isInsideTrackedChange = trackedChangeParent?.isTrackedChangeParent;
33694
+ if (extendedDef) {
33695
+ const details = getExtendedDetails(extendedDef);
33696
+ isDone = details.isDone ?? false;
33697
+ if (!isInsideTrackedChange && details.paraIdParent) {
33698
+ const parentComment = comments.find(
33699
+ (c2) => c2.paraId === details.paraIdParent || c2.elements?.some((el) => el.attrs?.["w14:paraId"] === details.paraIdParent)
33700
+ );
33701
+ parentCommentId = parentComment?.commentId;
33702
+ }
33703
+ }
33704
+ if (isInsideTrackedChange) {
33705
+ parentCommentId = trackedChangeParent.trackedChangeId;
33674
33706
  }
33675
- const newComment = {
33707
+ return {
33676
33708
  ...comment2,
33677
- isDone: isDone ?? false,
33678
- parentCommentId: parentComment?.commentId
33709
+ isDone,
33710
+ parentCommentId
33679
33711
  };
33680
- return newComment;
33681
33712
  });
33682
33713
  };
33683
33714
  const getExtendedDetails = (commentEx) => {
@@ -33687,34 +33718,117 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33687
33718
  const paraIdParent = attributes["w15:paraIdParent"];
33688
33719
  return { paraId, isDone, paraIdParent };
33689
33720
  };
33690
- const extractCommentRangesFromDocument = (docx) => {
33721
+ const extractCommentRangesFromDocument = (docx, converter) => {
33691
33722
  const documentXml = docx["word/document.xml"];
33692
33723
  if (!documentXml) {
33693
- return [];
33694
- }
33695
- const pendingComments = [];
33696
- const walkElements = (elements) => {
33724
+ return { rangeEvents: [], rangePositions: /* @__PURE__ */ new Map(), commentsInTrackedChanges: /* @__PURE__ */ new Map() };
33725
+ }
33726
+ const rangeEvents = [];
33727
+ const rangePositions = /* @__PURE__ */ new Map();
33728
+ const commentsInTrackedChanges = /* @__PURE__ */ new Map();
33729
+ let positionIndex = 0;
33730
+ let lastElementWasCommentMarker = false;
33731
+ const recentlyClosedComments = /* @__PURE__ */ new Set();
33732
+ let lastTrackedChange = null;
33733
+ const walkElements = (elements, currentTrackedChangeId = null) => {
33697
33734
  if (!elements || !Array.isArray(elements)) return;
33698
33735
  elements.forEach((element2) => {
33699
- if (element2.name === "w:commentRangeStart") {
33736
+ const isCommentStart = element2.name === "w:commentRangeStart";
33737
+ const isCommentEnd = element2.name === "w:commentRangeEnd";
33738
+ const isTrackedChange = element2.name === "w:ins" || element2.name === "w:del";
33739
+ if (isCommentStart) {
33700
33740
  const commentId = element2.attributes?.["w:id"];
33701
33741
  if (commentId !== void 0) {
33702
- pendingComments.push({
33742
+ const id = String(commentId);
33743
+ rangeEvents.push({
33703
33744
  type: "start",
33704
- commentId: String(commentId)
33745
+ commentId: id
33705
33746
  });
33747
+ if (!rangePositions.has(id)) {
33748
+ rangePositions.set(id, { startIndex: positionIndex, endIndex: -1 });
33749
+ } else {
33750
+ rangePositions.get(id).startIndex = positionIndex;
33751
+ }
33752
+ if (currentTrackedChangeId !== null) {
33753
+ commentsInTrackedChanges.set(id, currentTrackedChangeId);
33754
+ }
33706
33755
  }
33707
- } else if (element2.name === "w:commentRangeEnd") {
33756
+ lastElementWasCommentMarker = true;
33757
+ recentlyClosedComments.clear();
33758
+ } else if (isCommentEnd) {
33708
33759
  const commentId = element2.attributes?.["w:id"];
33709
33760
  if (commentId !== void 0) {
33710
- pendingComments.push({
33761
+ const id = String(commentId);
33762
+ rangeEvents.push({
33711
33763
  type: "end",
33712
- commentId: String(commentId)
33764
+ commentId: id
33713
33765
  });
33766
+ if (!rangePositions.has(id)) {
33767
+ rangePositions.set(id, { startIndex: -1, endIndex: positionIndex });
33768
+ } else {
33769
+ rangePositions.get(id).endIndex = positionIndex;
33770
+ }
33771
+ recentlyClosedComments.add(id);
33772
+ }
33773
+ lastElementWasCommentMarker = true;
33774
+ } else if (isTrackedChange) {
33775
+ const trackedChangeId = element2.attributes?.["w:id"];
33776
+ const author = element2.attributes?.["w:author"];
33777
+ const date = element2.attributes?.["w:date"];
33778
+ const elementType = element2.name;
33779
+ let mappedId = trackedChangeId;
33780
+ let isReplacement = false;
33781
+ if (trackedChangeId !== void 0 && converter) {
33782
+ if (!converter.trackedChangeIdMap) {
33783
+ converter.trackedChangeIdMap = /* @__PURE__ */ new Map();
33784
+ }
33785
+ if (lastTrackedChange && lastTrackedChange.type !== elementType && lastTrackedChange.author === author && lastTrackedChange.date === date) {
33786
+ mappedId = lastTrackedChange.mappedId;
33787
+ converter.trackedChangeIdMap.set(String(trackedChangeId), mappedId);
33788
+ isReplacement = true;
33789
+ } else {
33790
+ if (!converter.trackedChangeIdMap.has(String(trackedChangeId))) {
33791
+ converter.trackedChangeIdMap.set(String(trackedChangeId), v4());
33792
+ }
33793
+ mappedId = converter.trackedChangeIdMap.get(String(trackedChangeId));
33794
+ }
33795
+ }
33796
+ if (currentTrackedChangeId === null) {
33797
+ if (isReplacement) {
33798
+ lastTrackedChange = null;
33799
+ } else {
33800
+ lastTrackedChange = {
33801
+ type: elementType,
33802
+ author,
33803
+ date,
33804
+ mappedId,
33805
+ wordId: String(trackedChangeId)
33806
+ };
33807
+ }
33808
+ }
33809
+ if (mappedId && recentlyClosedComments.size > 0) {
33810
+ recentlyClosedComments.forEach((commentId) => {
33811
+ if (!commentsInTrackedChanges.has(commentId)) {
33812
+ commentsInTrackedChanges.set(commentId, String(mappedId));
33813
+ }
33814
+ });
33815
+ }
33816
+ recentlyClosedComments.clear();
33817
+ if (element2.elements && Array.isArray(element2.elements)) {
33818
+ walkElements(element2.elements, mappedId !== void 0 ? String(mappedId) : currentTrackedChangeId);
33819
+ }
33820
+ } else {
33821
+ if (lastElementWasCommentMarker) {
33822
+ positionIndex++;
33823
+ lastElementWasCommentMarker = false;
33824
+ }
33825
+ if (element2.name === "w:p") {
33826
+ recentlyClosedComments.clear();
33827
+ lastTrackedChange = null;
33828
+ }
33829
+ if (element2.elements && Array.isArray(element2.elements)) {
33830
+ walkElements(element2.elements, currentTrackedChangeId);
33714
33831
  }
33715
- }
33716
- if (element2.elements && Array.isArray(element2.elements)) {
33717
- walkElements(element2.elements);
33718
33832
  }
33719
33833
  });
33720
33834
  };
@@ -33724,19 +33838,20 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33724
33838
  walkElements(body.elements);
33725
33839
  }
33726
33840
  }
33727
- return pendingComments;
33841
+ return { rangeEvents, rangePositions, commentsInTrackedChanges };
33728
33842
  };
33729
- const detectThreadingFromRanges = (comments, rangeEvents) => {
33730
- if (!rangeEvents || rangeEvents.length === 0) {
33731
- return comments;
33732
- }
33843
+ const detectThreadingFromNestedRanges = (comments, rangeEvents, skipComments = /* @__PURE__ */ new Set()) => {
33733
33844
  const openRanges = [];
33734
33845
  const parentMap = /* @__PURE__ */ new Map();
33735
33846
  rangeEvents.forEach((event) => {
33736
33847
  if (event.type === "start") {
33737
- if (openRanges.length > 0) {
33738
- const parentCommentId = openRanges[openRanges.length - 1];
33739
- parentMap.set(event.commentId, parentCommentId);
33848
+ if (!skipComments.has(event.commentId) && openRanges.length > 0) {
33849
+ for (let i2 = openRanges.length - 1; i2 >= 0; i2--) {
33850
+ if (!skipComments.has(openRanges[i2])) {
33851
+ parentMap.set(event.commentId, openRanges[i2]);
33852
+ break;
33853
+ }
33854
+ }
33740
33855
  }
33741
33856
  openRanges.push(event.commentId);
33742
33857
  } else if (event.type === "end") {
@@ -33746,10 +33861,113 @@ Please report this to https://github.com/markedjs/marked.`, e) {
33746
33861
  }
33747
33862
  }
33748
33863
  });
33864
+ return parentMap;
33865
+ };
33866
+ const detectThreadingFromSharedPosition = (comments, rangePositions) => {
33867
+ const parentMap = /* @__PURE__ */ new Map();
33868
+ const commentsByStartPosition = /* @__PURE__ */ new Map();
33869
+ comments.forEach((comment2) => {
33870
+ const position2 = rangePositions.get(comment2.importedId);
33871
+ if (position2 && position2.startIndex >= 0) {
33872
+ const startKey = position2.startIndex;
33873
+ if (!commentsByStartPosition.has(startKey)) {
33874
+ commentsByStartPosition.set(startKey, []);
33875
+ }
33876
+ commentsByStartPosition.get(startKey).push(comment2);
33877
+ }
33878
+ });
33879
+ commentsByStartPosition.forEach((commentsAtPosition) => {
33880
+ if (commentsAtPosition.length <= 1) return;
33881
+ const sorted = [...commentsAtPosition].sort((a2, b2) => a2.createdTime - b2.createdTime);
33882
+ const parentComment = sorted[0];
33883
+ for (let i2 = 1; i2 < sorted.length; i2++) {
33884
+ parentMap.set(sorted[i2].importedId, parentComment.importedId);
33885
+ }
33886
+ });
33887
+ return parentMap;
33888
+ };
33889
+ const detectThreadingFromMissingRanges = (comments, rangePositions) => {
33890
+ const parentMap = /* @__PURE__ */ new Map();
33891
+ const commentsWithRanges = [];
33892
+ const commentsWithoutRanges = [];
33893
+ comments.forEach((comment2) => {
33894
+ const position2 = rangePositions.get(comment2.importedId);
33895
+ if (position2 && position2.startIndex >= 0) {
33896
+ commentsWithRanges.push(comment2);
33897
+ } else {
33898
+ commentsWithoutRanges.push(comment2);
33899
+ }
33900
+ });
33901
+ commentsWithoutRanges.forEach((comment2) => {
33902
+ const potentialParents = commentsWithRanges.filter((c2) => c2.createdTime < comment2.createdTime).sort((a2, b2) => b2.createdTime - a2.createdTime);
33903
+ if (potentialParents.length > 0) {
33904
+ parentMap.set(comment2.importedId, potentialParents[0].importedId);
33905
+ }
33906
+ });
33907
+ return parentMap;
33908
+ };
33909
+ const detectThreadingFromTrackedChanges = (comments, commentsInTrackedChanges) => {
33910
+ const parentMap = /* @__PURE__ */ new Map();
33911
+ if (!commentsInTrackedChanges || commentsInTrackedChanges.size === 0) {
33912
+ return parentMap;
33913
+ }
33914
+ comments.forEach((comment2) => {
33915
+ const trackedChangeId = commentsInTrackedChanges.get(comment2.importedId);
33916
+ if (trackedChangeId !== void 0) {
33917
+ parentMap.set(comment2.importedId, { trackedChangeId, isTrackedChangeParent: true });
33918
+ }
33919
+ });
33920
+ return parentMap;
33921
+ };
33922
+ const detectThreadingFromRanges = (comments, rangeData) => {
33923
+ const { rangeEvents, rangePositions, commentsInTrackedChanges } = Array.isArray(rangeData) ? { rangeEvents: rangeData, rangePositions: /* @__PURE__ */ new Map(), commentsInTrackedChanges: /* @__PURE__ */ new Map() } : rangeData;
33924
+ if (!rangeEvents || rangeEvents.length === 0) {
33925
+ if (comments.length > 1) {
33926
+ const parentMap = detectThreadingFromMissingRanges(comments, rangePositions);
33927
+ return applyParentRelationships(comments, parentMap);
33928
+ }
33929
+ return comments;
33930
+ }
33931
+ const commentsWithSharedPosition = findCommentsWithSharedStartPosition(comments, rangePositions);
33932
+ const nestedParentMap = detectThreadingFromNestedRanges(comments, rangeEvents, commentsWithSharedPosition);
33933
+ const sharedPositionParentMap = detectThreadingFromSharedPosition(comments, rangePositions);
33934
+ const missingRangeParentMap = detectThreadingFromMissingRanges(comments, rangePositions);
33935
+ const trackedChangeParentMap = detectThreadingFromTrackedChanges(comments, commentsInTrackedChanges);
33936
+ const mergedParentMap = new Map([...missingRangeParentMap, ...nestedParentMap, ...sharedPositionParentMap]);
33937
+ return applyParentRelationships(comments, mergedParentMap, trackedChangeParentMap);
33938
+ };
33939
+ const findCommentsWithSharedStartPosition = (comments, rangePositions) => {
33940
+ const sharedPositionComments = /* @__PURE__ */ new Set();
33941
+ const commentsByStartPosition = /* @__PURE__ */ new Map();
33942
+ comments.forEach((comment2) => {
33943
+ const position2 = rangePositions.get(comment2.importedId);
33944
+ if (position2 && position2.startIndex >= 0) {
33945
+ const startKey = position2.startIndex;
33946
+ if (!commentsByStartPosition.has(startKey)) {
33947
+ commentsByStartPosition.set(startKey, []);
33948
+ }
33949
+ commentsByStartPosition.get(startKey).push(comment2.importedId);
33950
+ }
33951
+ });
33952
+ commentsByStartPosition.forEach((commentIds) => {
33953
+ if (commentIds.length > 1) {
33954
+ commentIds.forEach((id) => sharedPositionComments.add(id));
33955
+ }
33956
+ });
33957
+ return sharedPositionComments;
33958
+ };
33959
+ const applyParentRelationships = (comments, parentMap, trackedChangeParentMap = /* @__PURE__ */ new Map()) => {
33749
33960
  return comments.map((comment2) => {
33750
- const parentCommentId = parentMap.get(comment2.importedId);
33751
- if (parentCommentId) {
33752
- const parentComment = comments.find((c2) => c2.importedId === parentCommentId);
33961
+ const trackedChangeParent = trackedChangeParentMap.get(comment2.importedId);
33962
+ if (trackedChangeParent && trackedChangeParent.isTrackedChangeParent) {
33963
+ return {
33964
+ ...comment2,
33965
+ parentCommentId: trackedChangeParent.trackedChangeId
33966
+ };
33967
+ }
33968
+ const parentImportedId = parentMap.get(comment2.importedId);
33969
+ if (parentImportedId) {
33970
+ const parentComment = comments.find((c2) => c2.importedId === parentImportedId);
33753
33971
  if (parentComment) {
33754
33972
  return {
33755
33973
  ...comment2,
@@ -34480,9 +34698,30 @@ Please report this to https://github.com/markedjs/marked.`, e) {
34480
34698
  );
34481
34699
  const permStartHandlerEntity = generateV2HandlerEntity("permStartHandler", translator$8);
34482
34700
  const permEndHandlerEntity = generateV2HandlerEntity("permEndHandler", translator$7);
34701
+ const detectDocumentOrigin = (docx) => {
34702
+ const commentsExtended = docx["word/commentsExtended.xml"];
34703
+ if (commentsExtended) {
34704
+ const { elements: initialElements = [] } = commentsExtended;
34705
+ if (initialElements?.length > 0) {
34706
+ const { elements = [] } = initialElements[0] ?? {};
34707
+ const commentEx = elements.filter((el) => el.name === "w15:commentEx");
34708
+ if (commentEx.length > 0) {
34709
+ return "word";
34710
+ }
34711
+ }
34712
+ }
34713
+ const comments = docx["word/comments.xml"];
34714
+ if (comments && !commentsExtended) {
34715
+ return "google-docs";
34716
+ }
34717
+ return "unknown";
34718
+ };
34483
34719
  const createDocumentJson = (docx, converter, editor) => {
34484
34720
  const json = carbonCopy(getInitialJSON(docx));
34485
34721
  if (!json) return null;
34722
+ if (converter) {
34723
+ converter.documentOrigin = detectDocumentOrigin(docx);
34724
+ }
34486
34725
  if (converter?.telemetry) {
34487
34726
  const files = Object.keys(docx).map((filePath) => {
34488
34727
  const parts = filePath.split("/");
@@ -36054,7 +36293,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36054
36293
  };
36055
36294
  if (comment2?.parentCommentId) {
36056
36295
  const parentComment = allComments.find((c2) => c2.commentId === comment2.parentCommentId);
36057
- attributes["w15:paraIdParent"] = parentComment.commentParaId;
36296
+ if (parentComment && !parentComment.trackedChange) {
36297
+ attributes["w15:paraIdParent"] = parentComment.commentParaId;
36298
+ }
36058
36299
  }
36059
36300
  return {
36060
36301
  type: "element",
@@ -36099,7 +36340,22 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36099
36340
  newCommentsXml.elements[0].elements = commentDefs;
36100
36341
  return newCommentsXml;
36101
36342
  };
36102
- const updateCommentsExtendedXml = (comments = [], commentsExtendedXml) => {
36343
+ const determineExportStrategy = (comments) => {
36344
+ if (!comments || comments.length === 0) {
36345
+ return "word";
36346
+ }
36347
+ const origins = new Set(comments.map((c2) => c2.origin || "word"));
36348
+ if (origins.size === 1) {
36349
+ const origin = origins.values().next().value;
36350
+ return origin === "google-docs" ? "google-docs" : "word";
36351
+ }
36352
+ return "word";
36353
+ };
36354
+ const updateCommentsExtendedXml = (comments = [], commentsExtendedXml, exportStrategy = "word") => {
36355
+ const shouldGenerateCommentsExtended = exportStrategy === "word" || comments.some((c2) => c2.originalXmlStructure?.hasCommentsExtended);
36356
+ if (!shouldGenerateCommentsExtended && exportStrategy === "google-docs") {
36357
+ return null;
36358
+ }
36103
36359
  const xmlCopy = carbonCopy(commentsExtendedXml);
36104
36360
  const commentsEx = comments.map((comment2) => {
36105
36361
  const isResolved = comment2.resolvedTime || comment2.isDone;
@@ -36108,9 +36364,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36108
36364
  "w15:done": isResolved ? "1" : "0"
36109
36365
  };
36110
36366
  const parentId = comment2.parentCommentId;
36111
- if (parentId) {
36367
+ if (parentId && (exportStrategy === "word" || comment2.originalXmlStructure?.hasCommentsExtended)) {
36112
36368
  const parentComment = comments.find((c2) => c2.commentId === parentId);
36113
- attributes["w15:paraIdParent"] = parentComment.commentParaId;
36369
+ if (parentComment && !parentComment.trackedChange) {
36370
+ attributes["w15:paraIdParent"] = parentComment.commentParaId;
36371
+ }
36114
36372
  }
36115
36373
  return {
36116
36374
  type: "element",
@@ -36180,14 +36438,21 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36180
36438
  const documentXml = removeCommentsFilesFromConvertedXml(convertedXml);
36181
36439
  return { documentXml, relationships };
36182
36440
  }
36441
+ const exportStrategy = determineExportStrategy(commentsWithParaIds);
36183
36442
  const updatedXml = generateConvertedXmlWithCommentFiles(convertedXml);
36184
36443
  updatedXml["word/comments.xml"] = updateCommentsXml(defs, updatedXml["word/comments.xml"]);
36185
36444
  relationships.push(generateRelationship("comments.xml"));
36186
- updatedXml["word/commentsExtended.xml"] = updateCommentsExtendedXml(
36445
+ const commentsExtendedXml = updateCommentsExtendedXml(
36187
36446
  commentsWithParaIds,
36188
- updatedXml["word/commentsExtended.xml"]
36447
+ updatedXml["word/commentsExtended.xml"],
36448
+ exportStrategy
36189
36449
  );
36190
- relationships.push(generateRelationship("commentsExtended.xml"));
36450
+ if (commentsExtendedXml !== null) {
36451
+ updatedXml["word/commentsExtended.xml"] = commentsExtendedXml;
36452
+ relationships.push(generateRelationship("commentsExtended.xml"));
36453
+ } else {
36454
+ delete updatedXml["word/commentsExtended.xml"];
36455
+ }
36191
36456
  const { documentIdsUpdated, extensibleUpdated } = updateCommentsIdsAndExtensible(
36192
36457
  commentsWithParaIds,
36193
36458
  updatedXml["word/commentsIds.xml"],
@@ -36696,7 +36961,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
36696
36961
  static getStoredSuperdocVersion(docx) {
36697
36962
  return SuperConverter.getStoredCustomProperty(docx, "SuperdocVersion");
36698
36963
  }
36699
- static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.4.0") {
36964
+ static setStoredSuperdocVersion(docx = this.convertedXml, version2 = "1.4.1-next.1") {
36700
36965
  return SuperConverter.setStoredCustomProperty(docx, "SuperdocVersion", version2, false);
36701
36966
  }
36702
36967
  /**
@@ -49228,11 +49493,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
49228
49493
  const matchingImportedComment = comments.find((c2) => c2.importedId == importedId);
49229
49494
  const resolvedCommentId = matchingImportedComment?.commentId ?? (importedId ? String(importedId) : v4());
49230
49495
  const internal = matchingImportedComment?.internal ?? matchingImportedComment?.isInternal ?? false;
49496
+ const parentCommentId = matchingImportedComment?.parentCommentId;
49497
+ const trackedChangeIds = converter?.trackedChangeIdMap ? new Set(Array.from(converter.trackedChangeIdMap.values()).map((id) => String(id))) : null;
49498
+ const isTrackedChangeParent = parentCommentId && trackedChangeIds ? trackedChangeIds.has(String(parentCommentId)) : false;
49231
49499
  return {
49232
49500
  resolvedCommentId,
49233
49501
  importedId,
49234
49502
  internal,
49235
- matchingImportedComment
49503
+ matchingImportedComment,
49504
+ trackedChange: matchingImportedComment?.trackedChange === true || isTrackedChangeParent
49236
49505
  };
49237
49506
  };
49238
49507
  const ensureFallbackComment = ({ converter, matchingImportedComment, commentId, importedId }) => {
@@ -49250,6 +49519,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
49250
49519
  isDone: false
49251
49520
  });
49252
49521
  };
49522
+ const TRACK_CHANGE_MARKS$1 = [TrackInsertMarkName$1, TrackDeleteMarkName$1, TrackFormatMarkName$1];
49253
49523
  const removeCommentsById = ({ commentId, state, tr, dispatch }) => {
49254
49524
  const positions = getCommentPositionsById(commentId, state.doc);
49255
49525
  positions.forEach(({ from: from2, to }) => {
@@ -49393,6 +49663,35 @@ Please report this to https://github.com/markedjs/marked.`, e) {
49393
49663
  });
49394
49664
  });
49395
49665
  });
49666
+ const trackedChangeMark = node2.marks?.find((mark2) => TRACK_CHANGE_MARKS$1.includes(mark2.type.name));
49667
+ if (trackedChangeMark) {
49668
+ const trackedChangeId = trackedChangeMark.attrs?.id;
49669
+ if (trackedChangeId) {
49670
+ const childComments = comments.filter((c2) => c2.parentCommentId === trackedChangeId && !c2.trackedChange).sort((a2, b2) => a2.createdTime - b2.createdTime);
49671
+ childComments.forEach((c2) => {
49672
+ if (seen.has(c2.commentId)) return;
49673
+ seen.add(c2.commentId);
49674
+ const childMark = getPreparedComment({
49675
+ commentId: c2.commentId,
49676
+ internal: c2.isInternal
49677
+ });
49678
+ const childStartNode = schema.nodes.commentRangeStart.create(childMark);
49679
+ startNodes.push({
49680
+ pos,
49681
+ node: childStartNode,
49682
+ commentId: c2.commentId,
49683
+ parentCommentId: c2.parentCommentId
49684
+ });
49685
+ const childEndNode = schema.nodes.commentRangeEnd.create(childMark);
49686
+ endNodes.push({
49687
+ pos: pos + node2.nodeSize,
49688
+ node: childEndNode,
49689
+ commentId: c2.commentId,
49690
+ parentCommentId: c2.parentCommentId
49691
+ });
49692
+ });
49693
+ }
49694
+ }
49396
49695
  });
49397
49696
  startNodes.sort((a2, b2) => {
49398
49697
  if (a2.pos !== b2.pos) return a2.pos - b2.pos;
@@ -49447,17 +49746,18 @@ Please report this to https://github.com/markedjs/marked.`, e) {
49447
49746
  const { type } = node2;
49448
49747
  const commentNodes = ["commentRangeStart", "commentRangeEnd", "commentReference"];
49449
49748
  if (!commentNodes.includes(type.name)) return;
49450
- const { resolvedCommentId, importedId, internal, matchingImportedComment } = resolveCommentMeta({
49749
+ const { resolvedCommentId, importedId, internal, matchingImportedComment, trackedChange } = resolveCommentMeta({
49451
49750
  converter,
49452
49751
  importedId: node2.attrs["w:id"]
49453
49752
  });
49454
49753
  const isDone = !!matchingImportedComment?.isDone;
49455
49754
  if (type.name === "commentRangeStart") {
49456
- if (!isDone) {
49755
+ if (!matchingImportedComment || !matchingImportedComment.isDone) {
49457
49756
  toMark.push({
49458
49757
  commentId: resolvedCommentId,
49459
49758
  importedId,
49460
49759
  internal,
49760
+ trackedChange,
49461
49761
  start: pos
49462
49762
  });
49463
49763
  }
@@ -49496,7 +49796,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
49496
49796
  const markAttrs = {
49497
49797
  commentId: itemToMark.commentId,
49498
49798
  importedId,
49499
- internal: itemToMark.internal
49799
+ internal: itemToMark.internal,
49800
+ trackedChange: itemToMark.trackedChange
49500
49801
  };
49501
49802
  tr.addMark(start2, pos + 1, schema.marks[CommentMarkName$1].create(markAttrs));
49502
49803
  toDelete.push({ start: pos, end: pos + 1 });
@@ -50058,26 +50359,30 @@ Please report this to https://github.com/markedjs/marked.`, e) {
50058
50359
  if (emitParams) editor.emit("commentsUpdate", emitParams);
50059
50360
  return newTrackedChanges;
50060
50361
  };
50061
- const getTrackedChangeText = ({ nodes, mark: mark2, trackedChangeType, isDeletionInsertion }) => {
50362
+ const getTrackedChangeText = ({ nodes, mark: mark2, trackedChangeType, isDeletionInsertion, marks }) => {
50062
50363
  let trackedChangeText = "";
50063
50364
  let deletionText = "";
50064
- if (trackedChangeType === TrackInsertMarkName$1) {
50365
+ if (trackedChangeType === TrackDeleteMarkName$1 || isDeletionInsertion) {
50366
+ deletionText = nodes.reduce((acc, node2) => {
50367
+ const hasDeleteMark = node2.marks.find((nodeMark) => nodeMark.type.name === TrackDeleteMarkName$1);
50368
+ if (!hasDeleteMark) return acc;
50369
+ const nodeText = node2?.text || node2?.textContent || "";
50370
+ acc += nodeText;
50371
+ return acc;
50372
+ }, "");
50373
+ }
50374
+ if (trackedChangeType === TrackInsertMarkName$1 || isDeletionInsertion) {
50065
50375
  trackedChangeText = nodes.reduce((acc, node2) => {
50066
- if (!node2.marks.find((nodeMark) => nodeMark.type.name === mark2.type.name)) return acc;
50067
- acc += node2?.text || node2?.textContent || "";
50376
+ const hasInsertMark = node2.marks.find((nodeMark) => nodeMark.type.name === TrackInsertMarkName$1);
50377
+ if (!hasInsertMark) return acc;
50378
+ const nodeText = node2?.text || node2?.textContent || "";
50379
+ acc += nodeText;
50068
50380
  return acc;
50069
50381
  }, "");
50070
50382
  }
50071
50383
  if (trackedChangeType === TrackFormatMarkName$1) {
50072
50384
  trackedChangeText = translateFormatChangesToEnglish(mark2.attrs);
50073
50385
  }
50074
- if (trackedChangeType === TrackDeleteMarkName$1 || isDeletionInsertion) {
50075
- deletionText = nodes.reduce((acc, node2) => {
50076
- if (!node2.marks.find((nodeMark) => nodeMark.type.name === TrackDeleteMarkName$1)) return acc;
50077
- acc += node2?.text || node2?.textContent || "";
50078
- return acc;
50079
- }, "");
50080
- }
50081
50386
  return {
50082
50387
  deletionText,
50083
50388
  trackedChangeText
@@ -50090,22 +50395,41 @@ Please report this to https://github.com/markedjs/marked.`, e) {
50090
50395
  const { author, authorEmail, authorImage, date, importedAuthor } = attrs;
50091
50396
  const id = attrs.id;
50092
50397
  const node2 = nodes[0];
50093
- const isDeletionInsertion = !!(marks.insertedMark && marks.deletionMark);
50398
+ const trackedChangesWithId = getTrackChanges(newEditorState, id);
50399
+ let isDeletionInsertion = !!(marks.insertedMark && marks.deletionMark);
50400
+ if (!isDeletionInsertion) {
50401
+ const hasInsertMark = trackedChangesWithId.some(({ mark: mark2 }) => mark2.type.name === TrackInsertMarkName$1);
50402
+ const hasDeleteMark = trackedChangesWithId.some(({ mark: mark2 }) => mark2.type.name === TrackDeleteMarkName$1);
50403
+ isDeletionInsertion = hasInsertMark && hasDeleteMark;
50404
+ }
50094
50405
  let nodesWithMark = [];
50095
- newEditorState.doc.descendants((node3) => {
50096
- const { marks: marks2 = [] } = node3;
50097
- const changeMarks = marks2.filter((mark2) => TRACK_CHANGE_MARKS.includes(mark2.type.name));
50098
- if (!changeMarks.length) return;
50099
- const hasMatchingId = changeMarks.find((mark2) => mark2.attrs.id === id);
50100
- if (hasMatchingId) nodesWithMark.push(node3);
50101
- });
50102
- const nodesToProcess = nodesWithMark.length ? nodesWithMark : node2 ? [node2] : [];
50103
- if (!nodesToProcess.length) {
50406
+ trackedChangesWithId.forEach(({ from: from2, to, mark: mark2 }) => {
50407
+ newEditorState.doc.nodesBetween(from2, to, (node3, pos) => {
50408
+ if (node3.isText) {
50409
+ const hasMatchingMark = node3.marks?.some((m2) => TRACK_CHANGE_MARKS.includes(m2.type.name) && m2.attrs.id === id);
50410
+ if (hasMatchingMark) {
50411
+ const alreadyAdded = nodesWithMark.some((n) => n === node3);
50412
+ if (!alreadyAdded) {
50413
+ nodesWithMark.push(node3);
50414
+ }
50415
+ }
50416
+ }
50417
+ });
50418
+ });
50419
+ let nodesToUse;
50420
+ if (isDeletionInsertion) {
50421
+ const allNodes = [...nodesWithMark, ...nodes, ...deletionNodes || []];
50422
+ nodesToUse = Array.from(new Set(allNodes));
50423
+ } else {
50424
+ nodesToUse = nodesWithMark.length ? nodesWithMark : node2 ? [node2] : [];
50425
+ }
50426
+ if (!nodesToUse.length) {
50104
50427
  return;
50105
50428
  }
50106
50429
  const { deletionText, trackedChangeText } = getTrackedChangeText({
50107
- nodes: nodesToProcess,
50430
+ nodes: nodesToUse,
50108
50431
  mark: trackedMark,
50432
+ marks,
50109
50433
  trackedChangeType,
50110
50434
  isDeletionInsertion
50111
50435
  });
@@ -62512,7 +62836,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
62512
62836
  return false;
62513
62837
  }
62514
62838
  };
62515
- const summaryVersion = "1.4.0";
62839
+ const summaryVersion = "1.4.1-next.1";
62516
62840
  const nodeKeys = ["group", "content", "marks", "inline", "atom", "defining", "code", "tableRole", "summary"];
62517
62841
  const markKeys = ["group", "inclusive", "excludes", "spanning", "code"];
62518
62842
  function mapAttributes(attrs) {
@@ -65145,7 +65469,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
65145
65469
  * Process collaboration migrations
65146
65470
  */
65147
65471
  processCollaborationMigrations() {
65148
- console.debug("[checkVersionMigrations] Current editor version", "1.4.0");
65472
+ console.debug("[checkVersionMigrations] Current editor version", "1.4.1-next.1");
65149
65473
  if (!this.options.ydoc) return;
65150
65474
  const metaMap = this.options.ydoc.getMap("meta");
65151
65475
  let docVersion = metaMap.get("version");
@@ -74255,12 +74579,15 @@ ${l}
74255
74579
  }
74256
74580
  }
74257
74581
  applyRunStyles(elem, run2, isActiveLink);
74258
- const commentColor = getCommentHighlight(run2);
74259
- if (commentColor && !run2.highlight) {
74582
+ const textRun = run2;
74583
+ const commentAnnotations = textRun.comments;
74584
+ const hasAnyComment = !!commentAnnotations?.length;
74585
+ const hasHighlightableComment = !!commentAnnotations?.some((c2) => !c2.trackedChange);
74586
+ const commentColor = getCommentHighlight(textRun);
74587
+ if (commentColor && !textRun.highlight && hasHighlightableComment) {
74260
74588
  elem.style.backgroundColor = commentColor;
74261
74589
  }
74262
- const commentAnnotations = run2.comments;
74263
- if (commentAnnotations?.length) {
74590
+ if (hasAnyComment) {
74264
74591
  elem.dataset.commentIds = commentAnnotations.map((c2) => c2.commentId).join(",");
74265
74592
  if (commentAnnotations.some((c2) => c2.internal)) {
74266
74593
  elem.dataset.commentInternal = "true";
@@ -88227,6 +88554,7 @@ ${l}
88227
88554
  const commentId = typeof attrs?.commentId === "string" ? attrs.commentId : void 0;
88228
88555
  const importedId = typeof attrs?.importedId === "string" ? attrs.importedId : void 0;
88229
88556
  const internal = attrs?.internal === true;
88557
+ const trackedChange = attrs?.trackedChange === true;
88230
88558
  if (!commentId && !importedId) return;
88231
88559
  const annotations = run2.comments ? [...run2.comments] : [];
88232
88560
  const key2 = `${commentId ?? ""}::${importedId ?? ""}`;
@@ -88235,7 +88563,8 @@ ${l}
88235
88563
  annotations.push({
88236
88564
  commentId: commentId ?? importedId,
88237
88565
  importedId,
88238
- internal
88566
+ internal,
88567
+ trackedChange
88239
88568
  });
88240
88569
  }
88241
88570
  run2.comments = annotations;
@@ -107132,6 +107461,10 @@ ${l}
107132
107461
  internal: {
107133
107462
  default: true,
107134
107463
  rendered: false
107464
+ },
107465
+ trackedChange: {
107466
+ default: false,
107467
+ rendered: false
107135
107468
  }
107136
107469
  };
107137
107470
  },
@@ -141843,11 +142176,14 @@ ${reason}`);
141843
142176
  trackFormat: "formatMark"
141844
142177
  };
141845
142178
  const grouped = [];
142179
+ const processed = /* @__PURE__ */ new Set();
141846
142180
  for (let i2 = 0; i2 < changes.length; i2++) {
142181
+ if (processed.has(i2)) continue;
141847
142182
  const c1 = changes[i2];
141848
- const c2 = changes[i2 + 1];
141849
142183
  const c1Key = markMetaKeys[c1.mark.type.name];
141850
- if (c1 && c2 && c1.to === c2.from && c1.mark.attrs.id === c2.mark.attrs.id) {
142184
+ const c1Id = c1.mark.attrs.id;
142185
+ const c2 = changes[i2 + 1];
142186
+ if (c2 && c1.to === c2.from && c1Id === c2.mark.attrs.id) {
141851
142187
  const c2Key = markMetaKeys[c2.mark.type.name];
141852
142188
  grouped.push({
141853
142189
  from: c1.from,
@@ -141855,13 +142191,35 @@ ${reason}`);
141855
142191
  [c1Key]: c1,
141856
142192
  [c2Key]: c2
141857
142193
  });
141858
- i2++;
141859
- } else {
142194
+ processed.add(i2);
142195
+ processed.add(i2 + 1);
142196
+ continue;
142197
+ }
142198
+ let foundMatch = false;
142199
+ for (let j2 = i2 + 1; j2 < changes.length; j2++) {
142200
+ if (processed.has(j2)) continue;
142201
+ const c22 = changes[j2];
142202
+ if (c1Id === c22.mark.attrs.id && c1.mark.type.name !== c22.mark.type.name) {
142203
+ const c2Key = markMetaKeys[c22.mark.type.name];
142204
+ grouped.push({
142205
+ from: Math.min(c1.from, c22.from),
142206
+ to: Math.max(c1.to, c22.to),
142207
+ [c1Key]: c1,
142208
+ [c2Key]: c22
142209
+ });
142210
+ processed.add(i2);
142211
+ processed.add(j2);
142212
+ foundMatch = true;
142213
+ break;
142214
+ }
142215
+ }
142216
+ if (!foundMatch) {
141860
142217
  grouped.push({
141861
142218
  from: c1.from,
141862
142219
  to: c1.to,
141863
142220
  [c1Key]: c1
141864
142221
  });
142222
+ processed.add(i2);
141865
142223
  }
141866
142224
  }
141867
142225
  return grouped;
@@ -142163,7 +142521,12 @@ ${reason}`);
142163
142521
  trackedChange: comment2.trackedChange || false,
142164
142522
  trackedChangeText: comment2.trackedChangeText,
142165
142523
  trackedChangeType: comment2.trackedChangeType,
142166
- deletedText: comment2.trackedDeletedText
142524
+ deletedText: comment2.trackedDeletedText,
142525
+ // Preserve origin metadata for export
142526
+ origin: comment2.origin || "word",
142527
+ // Default to 'word' for backward compatibility
142528
+ threadingMethod: comment2.threadingMethod,
142529
+ originalXmlStructure: comment2.originalXmlStructure
142167
142530
  });
142168
142531
  addComment({ superdoc, comment: newComment });
142169
142532
  });
@@ -142943,7 +143306,11 @@ ${reason}`);
142943
143306
  const isThreadedComment = c2.parentCommentId === parentComment.commentId;
142944
143307
  const isThisComment = c2.commentId === props.comment.commentId;
142945
143308
  return isThreadedComment || isThisComment;
142946
- }).sort((a2, b2) => a2.commentId === props.comment.commentId && a2.createdTime - b2.createdTime);
143309
+ }).sort((a2, b2) => {
143310
+ if (a2.commentId === props.comment.commentId) return -1;
143311
+ if (b2.commentId === props.comment.commentId) return 1;
143312
+ return a2.createdTime - b2.createdTime;
143313
+ });
142947
143314
  });
142948
143315
  const isInternalDropdownDisabled = computed(() => {
142949
143316
  if (props.comment.resolvedTime) return true;
@@ -143202,7 +143569,7 @@ ${reason}`);
143202
143569
  };
143203
143570
  }
143204
143571
  };
143205
- const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-d50fd675"]]);
143572
+ const CommentDialog = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["__scopeId", "data-v-f9956635"]]);
143206
143573
  const _hoisted_1$b = { class: "comments-list" };
143207
143574
  const _hoisted_2$5 = { key: 0 };
143208
143575
  const _hoisted_3$3 = { class: "comment-item" };
@@ -145163,7 +145530,7 @@ ${reason}`);
145163
145530
  this.config.colors = shuffleArray(this.config.colors);
145164
145531
  this.userColorMap = /* @__PURE__ */ new Map();
145165
145532
  this.colorIndex = 0;
145166
- this.version = "1.4.0";
145533
+ this.version = "1.4.1-next.1";
145167
145534
  this.#log("🦋 [superdoc] Using SuperDoc version:", this.version);
145168
145535
  this.superdocId = config2.superdocId || v4();
145169
145536
  this.colors = this.config.colors;