docxmlater 11.0.10 → 12.1.0
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/README.md +53 -13
- package/dist/core/Document.d.ts +29 -3
- package/dist/core/Document.d.ts.map +1 -1
- package/dist/core/Document.js +733 -170
- package/dist/core/Document.js.map +1 -1
- package/dist/core/DocumentGenerator.d.ts +1 -0
- package/dist/core/DocumentGenerator.d.ts.map +1 -1
- package/dist/core/DocumentGenerator.js +77 -25
- package/dist/core/DocumentGenerator.js.map +1 -1
- package/dist/core/DocumentParser.d.ts +7 -3
- package/dist/core/DocumentParser.d.ts.map +1 -1
- package/dist/core/DocumentParser.js +427 -81
- package/dist/core/DocumentParser.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +2 -2
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/elements/Comment.d.ts +15 -1
- package/dist/elements/Comment.d.ts.map +1 -1
- package/dist/elements/Comment.js +67 -12
- package/dist/elements/Comment.js.map +1 -1
- package/dist/elements/CommentManager.d.ts +4 -0
- package/dist/elements/CommentManager.d.ts.map +1 -1
- package/dist/elements/CommentManager.js +74 -16
- package/dist/elements/CommentManager.js.map +1 -1
- package/dist/elements/EndnoteManager.d.ts.map +1 -1
- package/dist/elements/EndnoteManager.js.map +1 -1
- package/dist/elements/Field.d.ts +10 -1
- package/dist/elements/Field.d.ts.map +1 -1
- package/dist/elements/Field.js +76 -34
- package/dist/elements/Field.js.map +1 -1
- package/dist/elements/FieldHelpers.d.ts +1 -0
- package/dist/elements/FieldHelpers.d.ts.map +1 -1
- package/dist/elements/FieldHelpers.js +8 -4
- package/dist/elements/FieldHelpers.js.map +1 -1
- package/dist/elements/Footer.d.ts +3 -1
- package/dist/elements/Footer.d.ts.map +1 -1
- package/dist/elements/Footer.js +39 -53
- package/dist/elements/Footer.js.map +1 -1
- package/dist/elements/FootnoteManager.d.ts.map +1 -1
- package/dist/elements/FootnoteManager.js.map +1 -1
- package/dist/elements/Header.d.ts +3 -1
- package/dist/elements/Header.d.ts.map +1 -1
- package/dist/elements/Header.js +39 -53
- package/dist/elements/Header.js.map +1 -1
- package/dist/elements/HeaderFooterManager.d.ts +4 -2
- package/dist/elements/HeaderFooterManager.d.ts.map +1 -1
- package/dist/elements/HeaderFooterManager.js +36 -6
- package/dist/elements/HeaderFooterManager.js.map +1 -1
- package/dist/elements/Hyperlink.d.ts +6 -1
- package/dist/elements/Hyperlink.d.ts.map +1 -1
- package/dist/elements/Hyperlink.js +69 -44
- package/dist/elements/Hyperlink.js.map +1 -1
- package/dist/elements/Image.d.ts.map +1 -1
- package/dist/elements/Image.js +33 -6
- package/dist/elements/Image.js.map +1 -1
- package/dist/elements/ImageManager.d.ts +1 -0
- package/dist/elements/ImageManager.d.ts.map +1 -1
- package/dist/elements/ImageManager.js +11 -0
- package/dist/elements/ImageManager.js.map +1 -1
- package/dist/elements/Paragraph.d.ts +3 -0
- package/dist/elements/Paragraph.d.ts.map +1 -1
- package/dist/elements/Paragraph.js +91 -26
- package/dist/elements/Paragraph.js.map +1 -1
- package/dist/elements/Revision.d.ts +4 -0
- package/dist/elements/Revision.d.ts.map +1 -1
- package/dist/elements/Revision.js +369 -29
- package/dist/elements/Revision.js.map +1 -1
- package/dist/elements/Run.d.ts +1 -0
- package/dist/elements/Run.d.ts.map +1 -1
- package/dist/elements/Run.js +24 -4
- package/dist/elements/Run.js.map +1 -1
- package/dist/elements/Section.d.ts.map +1 -1
- package/dist/elements/Section.js +17 -7
- package/dist/elements/Section.js.map +1 -1
- package/dist/elements/Shape.d.ts.map +1 -1
- package/dist/elements/Shape.js +50 -42
- package/dist/elements/Shape.js.map +1 -1
- package/dist/elements/StructuredDocumentTag.d.ts +9 -1
- package/dist/elements/StructuredDocumentTag.d.ts.map +1 -1
- package/dist/elements/StructuredDocumentTag.js +46 -6
- package/dist/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/elements/Table.d.ts +2 -0
- package/dist/elements/Table.d.ts.map +1 -1
- package/dist/elements/Table.js +90 -42
- package/dist/elements/Table.js.map +1 -1
- package/dist/elements/TableCell.d.ts +1 -0
- package/dist/elements/TableCell.d.ts.map +1 -1
- package/dist/elements/TableCell.js +32 -13
- package/dist/elements/TableCell.js.map +1 -1
- package/dist/elements/TableOfContents.d.ts.map +1 -1
- package/dist/elements/TableOfContents.js +5 -7
- package/dist/elements/TableOfContents.js.map +1 -1
- package/dist/elements/TableRow.d.ts +1 -0
- package/dist/elements/TableRow.d.ts.map +1 -1
- package/dist/elements/TableRow.js +16 -1
- package/dist/elements/TableRow.js.map +1 -1
- package/dist/elements/TextBox.d.ts.map +1 -1
- package/dist/elements/TextBox.js +55 -42
- package/dist/elements/TextBox.js.map +1 -1
- package/dist/esm/core/Document.js +735 -172
- package/dist/esm/core/Document.js.map +1 -1
- package/dist/esm/core/DocumentGenerator.js +77 -25
- package/dist/esm/core/DocumentGenerator.js.map +1 -1
- package/dist/esm/core/DocumentParser.js +427 -81
- package/dist/esm/core/DocumentParser.js.map +1 -1
- package/dist/esm/core/RelationshipManager.js +2 -2
- package/dist/esm/core/RelationshipManager.js.map +1 -1
- package/dist/esm/elements/Comment.js +67 -12
- package/dist/esm/elements/Comment.js.map +1 -1
- package/dist/esm/elements/CommentManager.js +74 -16
- package/dist/esm/elements/CommentManager.js.map +1 -1
- package/dist/esm/elements/EndnoteManager.js.map +1 -1
- package/dist/esm/elements/Field.js +77 -35
- package/dist/esm/elements/Field.js.map +1 -1
- package/dist/esm/elements/FieldHelpers.js +7 -4
- package/dist/esm/elements/FieldHelpers.js.map +1 -1
- package/dist/esm/elements/Footer.js +39 -53
- package/dist/esm/elements/Footer.js.map +1 -1
- package/dist/esm/elements/FootnoteManager.js.map +1 -1
- package/dist/esm/elements/Header.js +39 -53
- package/dist/esm/elements/Header.js.map +1 -1
- package/dist/esm/elements/HeaderFooterManager.js +36 -6
- package/dist/esm/elements/HeaderFooterManager.js.map +1 -1
- package/dist/esm/elements/Hyperlink.js +69 -44
- package/dist/esm/elements/Hyperlink.js.map +1 -1
- package/dist/esm/elements/Image.js +33 -6
- package/dist/esm/elements/Image.js.map +1 -1
- package/dist/esm/elements/ImageManager.js +11 -0
- package/dist/esm/elements/ImageManager.js.map +1 -1
- package/dist/esm/elements/Paragraph.js +91 -26
- package/dist/esm/elements/Paragraph.js.map +1 -1
- package/dist/esm/elements/Revision.js +369 -29
- package/dist/esm/elements/Revision.js.map +1 -1
- package/dist/esm/elements/Run.js +24 -4
- package/dist/esm/elements/Run.js.map +1 -1
- package/dist/esm/elements/Section.js +17 -7
- package/dist/esm/elements/Section.js.map +1 -1
- package/dist/esm/elements/Shape.js +50 -42
- package/dist/esm/elements/Shape.js.map +1 -1
- package/dist/esm/elements/StructuredDocumentTag.js +46 -6
- package/dist/esm/elements/StructuredDocumentTag.js.map +1 -1
- package/dist/esm/elements/Table.js +90 -42
- package/dist/esm/elements/Table.js.map +1 -1
- package/dist/esm/elements/TableCell.js +32 -13
- package/dist/esm/elements/TableCell.js.map +1 -1
- package/dist/esm/elements/TableOfContents.js +5 -7
- package/dist/esm/elements/TableOfContents.js.map +1 -1
- package/dist/esm/elements/TableRow.js +16 -1
- package/dist/esm/elements/TableRow.js.map +1 -1
- package/dist/esm/elements/TextBox.js +55 -42
- package/dist/esm/elements/TextBox.js.map +1 -1
- package/dist/esm/formatting/AbstractNumbering.js +1 -1
- package/dist/esm/formatting/AbstractNumbering.js.map +1 -1
- package/dist/esm/formatting/NumberingLevel.js +8 -6
- package/dist/esm/formatting/NumberingLevel.js.map +1 -1
- package/dist/esm/formatting/NumberingManager.js +16 -1
- package/dist/esm/formatting/NumberingManager.js.map +1 -1
- package/dist/esm/formatting/Style.js +14 -0
- package/dist/esm/formatting/Style.js.map +1 -1
- package/dist/esm/formatting/StylesManager.js +14 -2
- package/dist/esm/formatting/StylesManager.js.map +1 -1
- package/dist/esm/helpers/CleanupHelper.js +103 -26
- package/dist/esm/helpers/CleanupHelper.js.map +1 -1
- package/dist/esm/images/ImageOptimizer.js +52 -4
- package/dist/esm/images/ImageOptimizer.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal.js +1 -1
- package/dist/esm/internal.js.map +1 -1
- package/dist/esm/processors/CompatibilityUpgrader.js +7 -1
- package/dist/esm/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/esm/processors/InMemoryRevisionAcceptor.js +134 -13
- package/dist/esm/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/RevisionWalker.js +223 -39
- package/dist/esm/processors/RevisionWalker.js.map +1 -1
- package/dist/esm/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/esm/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/esm/processors/acceptRevisions.js +20 -11
- package/dist/esm/processors/acceptRevisions.js.map +1 -1
- package/dist/esm/processors/cnfStyleDecoder.js +7 -7
- package/dist/esm/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/esm/processors/stripTrackedChanges.js +16 -5
- package/dist/esm/processors/stripTrackedChanges.js.map +1 -1
- package/dist/esm/utils/deepClone.js +24 -11
- package/dist/esm/utils/deepClone.js.map +1 -1
- package/dist/esm/utils/units.js +1 -1
- package/dist/esm/utils/units.js.map +1 -1
- package/dist/esm/utils/validation.js +11 -23
- package/dist/esm/utils/validation.js.map +1 -1
- package/dist/esm/utils/xmlSanitization.js +131 -7
- package/dist/esm/utils/xmlSanitization.js.map +1 -1
- package/dist/esm/validation/RevisionAutoFixer.js +69 -55
- package/dist/esm/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/esm/validation/RevisionValidator.js +24 -20
- package/dist/esm/validation/RevisionValidator.js.map +1 -1
- package/dist/esm/xml/XMLBuilder.js +52 -20
- package/dist/esm/xml/XMLBuilder.js.map +1 -1
- package/dist/esm/xml/XMLParser.js +55 -13
- package/dist/esm/xml/XMLParser.js.map +1 -1
- package/dist/esm/zip/ZipHandler.js +37 -13
- package/dist/esm/zip/ZipHandler.js.map +1 -1
- package/dist/esm/zip/ZipReader.js +53 -6
- package/dist/esm/zip/ZipReader.js.map +1 -1
- package/dist/esm/zip/errors.js +7 -0
- package/dist/esm/zip/errors.js.map +1 -1
- package/dist/esm/zip/types.js +4 -0
- package/dist/esm/zip/types.js.map +1 -1
- package/dist/formatting/AbstractNumbering.d.ts.map +1 -1
- package/dist/formatting/AbstractNumbering.js +1 -1
- package/dist/formatting/AbstractNumbering.js.map +1 -1
- package/dist/formatting/NumberingLevel.d.ts +1 -1
- package/dist/formatting/NumberingLevel.d.ts.map +1 -1
- package/dist/formatting/NumberingLevel.js +8 -6
- package/dist/formatting/NumberingLevel.js.map +1 -1
- package/dist/formatting/NumberingManager.d.ts.map +1 -1
- package/dist/formatting/NumberingManager.js +16 -1
- package/dist/formatting/NumberingManager.js.map +1 -1
- package/dist/formatting/Style.d.ts.map +1 -1
- package/dist/formatting/Style.js +14 -0
- package/dist/formatting/Style.js.map +1 -1
- package/dist/formatting/StylesManager.d.ts +2 -0
- package/dist/formatting/StylesManager.d.ts.map +1 -1
- package/dist/formatting/StylesManager.js +14 -2
- package/dist/formatting/StylesManager.js.map +1 -1
- package/dist/helpers/CleanupHelper.d.ts.map +1 -1
- package/dist/helpers/CleanupHelper.js +103 -26
- package/dist/helpers/CleanupHelper.js.map +1 -1
- package/dist/images/ImageOptimizer.d.ts.map +1 -1
- package/dist/images/ImageOptimizer.js +52 -4
- package/dist/images/ImageOptimizer.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -1
- package/dist/internal.js.map +1 -1
- package/dist/processors/CompatibilityUpgrader.d.ts.map +1 -1
- package/dist/processors/CompatibilityUpgrader.js +7 -1
- package/dist/processors/CompatibilityUpgrader.js.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.d.ts +1 -0
- package/dist/processors/InMemoryRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/InMemoryRevisionAcceptor.js +135 -13
- package/dist/processors/InMemoryRevisionAcceptor.js.map +1 -1
- package/dist/processors/RevisionWalker.d.ts +9 -3
- package/dist/processors/RevisionWalker.d.ts.map +1 -1
- package/dist/processors/RevisionWalker.js +223 -39
- package/dist/processors/RevisionWalker.js.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.d.ts.map +1 -1
- package/dist/processors/SelectiveRevisionAcceptor.js +116 -17
- package/dist/processors/SelectiveRevisionAcceptor.js.map +1 -1
- package/dist/processors/acceptRevisions.d.ts +1 -0
- package/dist/processors/acceptRevisions.d.ts.map +1 -1
- package/dist/processors/acceptRevisions.js +21 -11
- package/dist/processors/acceptRevisions.js.map +1 -1
- package/dist/processors/cnfStyleDecoder.d.ts.map +1 -1
- package/dist/processors/cnfStyleDecoder.js +7 -7
- package/dist/processors/cnfStyleDecoder.js.map +1 -1
- package/dist/processors/stripTrackedChanges.d.ts.map +1 -1
- package/dist/processors/stripTrackedChanges.js +16 -5
- package/dist/processors/stripTrackedChanges.js.map +1 -1
- package/dist/utils/deepClone.d.ts.map +1 -1
- package/dist/utils/deepClone.js +24 -11
- package/dist/utils/deepClone.js.map +1 -1
- package/dist/utils/units.d.ts.map +1 -1
- package/dist/utils/units.js +1 -1
- package/dist/utils/units.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +11 -23
- package/dist/utils/validation.js.map +1 -1
- package/dist/utils/xmlSanitization.d.ts +2 -0
- package/dist/utils/xmlSanitization.d.ts.map +1 -1
- package/dist/utils/xmlSanitization.js +133 -7
- package/dist/utils/xmlSanitization.js.map +1 -1
- package/dist/validation/RevisionAutoFixer.d.ts +6 -2
- package/dist/validation/RevisionAutoFixer.d.ts.map +1 -1
- package/dist/validation/RevisionAutoFixer.js +68 -54
- package/dist/validation/RevisionAutoFixer.js.map +1 -1
- package/dist/validation/RevisionValidator.d.ts +2 -0
- package/dist/validation/RevisionValidator.d.ts.map +1 -1
- package/dist/validation/RevisionValidator.js +26 -21
- package/dist/validation/RevisionValidator.js.map +1 -1
- package/dist/xml/XMLBuilder.d.ts +1 -0
- package/dist/xml/XMLBuilder.d.ts.map +1 -1
- package/dist/xml/XMLBuilder.js +52 -20
- package/dist/xml/XMLBuilder.js.map +1 -1
- package/dist/xml/XMLParser.d.ts +1 -0
- package/dist/xml/XMLParser.d.ts.map +1 -1
- package/dist/xml/XMLParser.js +55 -13
- package/dist/xml/XMLParser.js.map +1 -1
- package/dist/zip/ZipHandler.d.ts.map +1 -1
- package/dist/zip/ZipHandler.js +37 -13
- package/dist/zip/ZipHandler.js.map +1 -1
- package/dist/zip/ZipReader.d.ts.map +1 -1
- package/dist/zip/ZipReader.js +52 -5
- package/dist/zip/ZipReader.js.map +1 -1
- package/dist/zip/errors.d.ts +3 -0
- package/dist/zip/errors.d.ts.map +1 -1
- package/dist/zip/errors.js +9 -1
- package/dist/zip/errors.js.map +1 -1
- package/dist/zip/types.d.ts +4 -0
- package/dist/zip/types.d.ts.map +1 -1
- package/dist/zip/types.js +4 -0
- package/dist/zip/types.js.map +1 -1
- package/package.json +2 -2
- package/src/core/Document.ts +1184 -242
- package/src/core/DocumentGenerator.ts +106 -26
- package/src/core/DocumentParser.ts +681 -114
- package/src/core/RelationshipManager.ts +446 -442
- package/src/elements/Comment.ts +123 -18
- package/src/elements/CommentManager.ts +121 -22
- package/src/elements/EndnoteManager.ts +4 -1
- package/src/elements/Field.ts +134 -43
- package/src/elements/FieldHelpers.ts +20 -4
- package/src/elements/Footer.ts +62 -67
- package/src/elements/FootnoteManager.ts +4 -1
- package/src/elements/Header.ts +62 -67
- package/src/elements/HeaderFooterManager.ts +56 -8
- package/src/elements/Hyperlink.ts +150 -55
- package/src/elements/Image.ts +51 -7
- package/src/elements/ImageManager.ts +24 -0
- package/src/elements/Paragraph.ts +161 -40
- package/src/elements/Revision.ts +446 -47
- package/src/elements/Run.ts +44 -6
- package/src/elements/Section.ts +25 -9
- package/src/elements/Shape.ts +52 -44
- package/src/elements/StructuredDocumentTag.ts +83 -8
- package/src/elements/Table.ts +151 -50
- package/src/elements/TableCell.ts +57 -17
- package/src/elements/TableOfContents.ts +10 -9
- package/src/elements/TableRow.ts +35 -3
- package/src/elements/TextBox.ts +58 -43
- package/src/formatting/AbstractNumbering.ts +4 -2
- package/src/formatting/NumberingLevel.ts +50 -12
- package/src/formatting/NumberingManager.ts +32 -3
- package/src/formatting/Style.ts +14 -0
- package/src/formatting/StylesManager.ts +29 -2
- package/src/helpers/CleanupHelper.ts +122 -30
- package/src/images/ImageOptimizer.ts +64 -5
- package/src/index.ts +7 -0
- package/src/internal.ts +1 -0
- package/src/processors/CompatibilityUpgrader.ts +15 -2
- package/src/processors/InMemoryRevisionAcceptor.ts +276 -17
- package/src/processors/RevisionWalker.ts +390 -46
- package/src/processors/SelectiveRevisionAcceptor.ts +164 -28
- package/src/processors/acceptRevisions.ts +67 -17
- package/src/processors/cnfStyleDecoder.ts +18 -12
- package/src/processors/stripTrackedChanges.ts +47 -10
- package/src/utils/deepClone.ts +48 -14
- package/src/utils/units.ts +3 -1
- package/src/utils/validation.ts +30 -32
- package/src/utils/xmlSanitization.ts +218 -22
- package/src/validation/RevisionAutoFixer.ts +109 -65
- package/src/validation/RevisionValidator.ts +48 -23
- package/src/xml/XMLBuilder.ts +82 -22
- package/src/xml/XMLParser.ts +87 -20
- package/src/zip/ZipHandler.ts +61 -21
- package/src/zip/ZipReader.ts +135 -13
- package/src/zip/errors.ts +15 -0
- package/src/zip/types.ts +44 -2
package/src/elements/Comment.ts
CHANGED
|
@@ -9,6 +9,34 @@ import { Run } from './Run.js';
|
|
|
9
9
|
import { XMLElement } from '../xml/XMLBuilder.js';
|
|
10
10
|
import { formatDateForXml } from '../utils/dateFormatting.js';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Inline comment content preserved as raw XML (e.g. w:hyperlink wrappers
|
|
14
|
+
* from a parsed comments.xml). The wrapper is re-emitted verbatim on
|
|
15
|
+
* regeneration so its r:id target survives; the runs parsed from inside
|
|
16
|
+
* it are kept alongside so text extraction still sees their text.
|
|
17
|
+
*/
|
|
18
|
+
export interface CommentPreservedContent {
|
|
19
|
+
/** Original XML emitted verbatim when comments.xml is regenerated */
|
|
20
|
+
rawXml: string;
|
|
21
|
+
/** Runs parsed from inside the preserved element (text extraction only) */
|
|
22
|
+
runs: Run[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Ordered item of comment paragraph content */
|
|
26
|
+
export type CommentContentItem = Run | CommentPreservedContent;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* One paragraph of comment content. CT_Comment accepts block-level content
|
|
30
|
+
* (ECMA-376 §17.13.4.2), so comments can span multiple paragraphs, each
|
|
31
|
+
* with its own paragraph properties (typically the CommentText style).
|
|
32
|
+
*/
|
|
33
|
+
export interface CommentParagraph {
|
|
34
|
+
/** Raw <w:pPr> XML preserved for round-trip */
|
|
35
|
+
pPr?: string;
|
|
36
|
+
/** Paragraph content in document order */
|
|
37
|
+
content: CommentContentItem[];
|
|
38
|
+
}
|
|
39
|
+
|
|
12
40
|
/**
|
|
13
41
|
* Comment properties
|
|
14
42
|
*/
|
|
@@ -37,9 +65,10 @@ export class Comment {
|
|
|
37
65
|
private author: string;
|
|
38
66
|
private initials: string;
|
|
39
67
|
private date: Date;
|
|
40
|
-
private
|
|
68
|
+
private paragraphs: CommentParagraph[];
|
|
41
69
|
private parentId?: number;
|
|
42
70
|
private done: boolean;
|
|
71
|
+
private onModified: (() => void) | null = null;
|
|
43
72
|
|
|
44
73
|
/**
|
|
45
74
|
* Creates a new Comment
|
|
@@ -53,14 +82,16 @@ export class Comment {
|
|
|
53
82
|
this.parentId = properties.parentId;
|
|
54
83
|
this.done = properties.done ?? false;
|
|
55
84
|
|
|
56
|
-
// Convert content to runs
|
|
85
|
+
// Convert content to runs in a single paragraph
|
|
86
|
+
let runs: Run[];
|
|
57
87
|
if (typeof properties.content === 'string') {
|
|
58
|
-
|
|
88
|
+
runs = [new Run(properties.content)];
|
|
59
89
|
} else if (Array.isArray(properties.content)) {
|
|
60
|
-
|
|
90
|
+
runs = properties.content;
|
|
61
91
|
} else {
|
|
62
|
-
|
|
92
|
+
runs = [properties.content];
|
|
63
93
|
}
|
|
94
|
+
this.paragraphs = [{ content: runs }];
|
|
64
95
|
}
|
|
65
96
|
|
|
66
97
|
/**
|
|
@@ -98,6 +129,23 @@ export class Comment {
|
|
|
98
129
|
this.id = id;
|
|
99
130
|
}
|
|
100
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Registers a callback invoked whenever this comment is mutated.
|
|
134
|
+
* Document wires this to its comments dirty flag so edits to parsed
|
|
135
|
+
* comments trigger regeneration of comments.xml instead of being
|
|
136
|
+
* silently discarded by the original-XML passthrough on save.
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
setModifiedCallback(callback: () => void): void {
|
|
140
|
+
this.onModified = callback;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private notifyModified(): void {
|
|
144
|
+
if (this.onModified) {
|
|
145
|
+
this.onModified();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
101
149
|
/**
|
|
102
150
|
* Gets the author
|
|
103
151
|
*/
|
|
@@ -110,6 +158,7 @@ export class Comment {
|
|
|
110
158
|
*/
|
|
111
159
|
setAuthor(author: string): this {
|
|
112
160
|
this.author = author;
|
|
161
|
+
this.notifyModified();
|
|
113
162
|
return this;
|
|
114
163
|
}
|
|
115
164
|
|
|
@@ -125,6 +174,7 @@ export class Comment {
|
|
|
125
174
|
*/
|
|
126
175
|
setInitials(initials: string): this {
|
|
127
176
|
this.initials = initials;
|
|
177
|
+
this.notifyModified();
|
|
128
178
|
return this;
|
|
129
179
|
}
|
|
130
180
|
|
|
@@ -140,6 +190,7 @@ export class Comment {
|
|
|
140
190
|
*/
|
|
141
191
|
setDate(date: Date): this {
|
|
142
192
|
this.date = date;
|
|
193
|
+
this.notifyModified();
|
|
143
194
|
return this;
|
|
144
195
|
}
|
|
145
196
|
|
|
@@ -167,42 +218,84 @@ export class Comment {
|
|
|
167
218
|
|
|
168
219
|
/**
|
|
169
220
|
* Marks the comment as resolved/done
|
|
170
|
-
*
|
|
221
|
+
* Persists as w15:done="1" in word/commentsExtended.xml on save
|
|
171
222
|
*/
|
|
172
223
|
resolve(): this {
|
|
173
224
|
this.done = true;
|
|
225
|
+
this.notifyModified();
|
|
174
226
|
return this;
|
|
175
227
|
}
|
|
176
228
|
|
|
177
229
|
/**
|
|
178
230
|
* Marks the comment as unresolved
|
|
179
|
-
*
|
|
231
|
+
* Drops the w15:done flag from word/commentsExtended.xml on save
|
|
180
232
|
*/
|
|
181
233
|
unresolve(): this {
|
|
182
234
|
this.done = false;
|
|
235
|
+
this.notifyModified();
|
|
183
236
|
return this;
|
|
184
237
|
}
|
|
185
238
|
|
|
186
239
|
/**
|
|
187
|
-
* Gets the runs in this comment
|
|
240
|
+
* Gets the runs in this comment (flattened across paragraphs,
|
|
241
|
+
* including runs inside preserved inline content)
|
|
188
242
|
*/
|
|
189
243
|
getRuns(): Run[] {
|
|
190
|
-
|
|
244
|
+
const runs: Run[] = [];
|
|
245
|
+
for (const paragraph of this.paragraphs) {
|
|
246
|
+
for (const item of paragraph.content) {
|
|
247
|
+
if (item instanceof Run) {
|
|
248
|
+
runs.push(item);
|
|
249
|
+
} else {
|
|
250
|
+
runs.push(...item.runs);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return runs;
|
|
191
255
|
}
|
|
192
256
|
|
|
193
257
|
/**
|
|
194
|
-
* Adds a run to this comment
|
|
258
|
+
* Adds a run to this comment (appended to the last paragraph)
|
|
195
259
|
*/
|
|
196
260
|
addRun(run: Run): this {
|
|
197
|
-
this.
|
|
261
|
+
let last = this.paragraphs[this.paragraphs.length - 1];
|
|
262
|
+
if (!last) {
|
|
263
|
+
last = { content: [] };
|
|
264
|
+
this.paragraphs.push(last);
|
|
265
|
+
}
|
|
266
|
+
last.content.push(run);
|
|
267
|
+
this.notifyModified();
|
|
198
268
|
return this;
|
|
199
269
|
}
|
|
200
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Gets the comment content grouped by paragraph
|
|
273
|
+
*/
|
|
274
|
+
getParagraphs(): CommentParagraph[] {
|
|
275
|
+
return this.paragraphs.map((paragraph) => ({
|
|
276
|
+
pPr: paragraph.pPr,
|
|
277
|
+
content: [...paragraph.content],
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Replaces the comment content with parsed paragraphs.
|
|
283
|
+
* Used by DocumentParser to preserve <w:p> boundaries, paragraph
|
|
284
|
+
* properties, and hyperlink wrappers of comments loaded from an
|
|
285
|
+
* existing comments.xml. Not a user mutation — no dirty notification.
|
|
286
|
+
* @internal
|
|
287
|
+
*/
|
|
288
|
+
setParagraphs(paragraphs: CommentParagraph[]): void {
|
|
289
|
+
this.paragraphs = paragraphs;
|
|
290
|
+
}
|
|
291
|
+
|
|
201
292
|
/**
|
|
202
293
|
* Gets the comment text (combines all runs)
|
|
203
294
|
*/
|
|
204
295
|
getText(): string {
|
|
205
|
-
return this.
|
|
296
|
+
return this.getRuns()
|
|
297
|
+
.map((run) => run.getText())
|
|
298
|
+
.join('');
|
|
206
299
|
}
|
|
207
300
|
|
|
208
301
|
/**
|
|
@@ -289,16 +382,28 @@ export class Comment {
|
|
|
289
382
|
attributes['w:done'] = '1';
|
|
290
383
|
}
|
|
291
384
|
|
|
292
|
-
//
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
385
|
+
// One <w:p> per stored paragraph — collapsing into a single paragraph
|
|
386
|
+
// concatenates words across the lost boundaries and drops the
|
|
387
|
+
// CommentText paragraph style of parsed comments
|
|
388
|
+
const commentParagraphs: XMLElement[] = this.paragraphs.map((paragraph) => {
|
|
389
|
+
const children: XMLElement[] = [];
|
|
390
|
+
if (paragraph.pPr) {
|
|
391
|
+
children.push({ name: '__rawXml', rawXml: paragraph.pPr });
|
|
392
|
+
}
|
|
393
|
+
for (const item of paragraph.content) {
|
|
394
|
+
if (item instanceof Run) {
|
|
395
|
+
children.push(item.toXML());
|
|
396
|
+
} else {
|
|
397
|
+
children.push({ name: '__rawXml', rawXml: item.rawXml });
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return { name: 'w:p', children };
|
|
401
|
+
});
|
|
297
402
|
|
|
298
403
|
return {
|
|
299
404
|
name: 'w:comment',
|
|
300
405
|
attributes,
|
|
301
|
-
children:
|
|
406
|
+
children: commentParagraphs,
|
|
302
407
|
};
|
|
303
408
|
}
|
|
304
409
|
|
|
@@ -42,6 +42,7 @@ export class CommentManager {
|
|
|
42
42
|
private nextId = 0;
|
|
43
43
|
private idProvider: IdProviderCallback | null = null;
|
|
44
44
|
private idExistsNotifier: IdExistsCallback | null = null;
|
|
45
|
+
private modifiedNotifier: (() => void) | null = null;
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* Sets the centralized ID provider callback.
|
|
@@ -56,6 +57,21 @@ export class CommentManager {
|
|
|
56
57
|
this.idExistsNotifier = existsNotifier || null;
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Sets the callback invoked when a registered comment is mutated.
|
|
62
|
+
* Document wires this to its comments dirty flag so instance-level edits
|
|
63
|
+
* (resolve, setAuthor, addRun, ...) force comments.xml regeneration
|
|
64
|
+
* instead of being silently discarded by the original-XML passthrough.
|
|
65
|
+
*
|
|
66
|
+
* @param notifier - Callback invoked on any comment mutation
|
|
67
|
+
*/
|
|
68
|
+
setModifiedNotifier(notifier: () => void): void {
|
|
69
|
+
this.modifiedNotifier = notifier;
|
|
70
|
+
for (const entry of this.comments.values()) {
|
|
71
|
+
entry.comment.setModifiedCallback(notifier);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
59
75
|
/**
|
|
60
76
|
* Registers a comment with the manager
|
|
61
77
|
* Assigns a unique ID
|
|
@@ -67,6 +83,10 @@ export class CommentManager {
|
|
|
67
83
|
const id = this.idProvider ? this.idProvider() : this.nextId++;
|
|
68
84
|
comment.setId(id);
|
|
69
85
|
|
|
86
|
+
if (this.modifiedNotifier) {
|
|
87
|
+
comment.setModifiedCallback(this.modifiedNotifier);
|
|
88
|
+
}
|
|
89
|
+
|
|
70
90
|
// Store comment
|
|
71
91
|
const entry: CommentEntry = {
|
|
72
92
|
comment,
|
|
@@ -99,6 +119,10 @@ export class CommentManager {
|
|
|
99
119
|
this.idExistsNotifier(id);
|
|
100
120
|
}
|
|
101
121
|
|
|
122
|
+
if (this.modifiedNotifier) {
|
|
123
|
+
comment.setModifiedCallback(this.modifiedNotifier);
|
|
124
|
+
}
|
|
125
|
+
|
|
102
126
|
// Store comment
|
|
103
127
|
const entry: CommentEntry = {
|
|
104
128
|
comment,
|
|
@@ -251,6 +275,16 @@ export class CommentManager {
|
|
|
251
275
|
this.comments.delete(reply.getId());
|
|
252
276
|
}
|
|
253
277
|
|
|
278
|
+
// A reply is also tracked in its parent's replies array — drop it there
|
|
279
|
+
// too so getReplies()/hasReplies()/getCommentThread() agree with the map
|
|
280
|
+
const parentId = entry.comment.getParentId();
|
|
281
|
+
if (parentId !== undefined) {
|
|
282
|
+
const parentEntry = this.comments.get(parentId);
|
|
283
|
+
if (parentEntry) {
|
|
284
|
+
parentEntry.replies = parentEntry.replies.filter((reply) => reply !== entry.comment);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
254
288
|
// Remove the comment itself
|
|
255
289
|
return this.comments.delete(id);
|
|
256
290
|
}
|
|
@@ -420,31 +454,88 @@ export class CommentManager {
|
|
|
420
454
|
|
|
421
455
|
// Build XML manually for comments
|
|
422
456
|
const hasReplies = comments.some((c) => c.isReply());
|
|
457
|
+
const hasResolved = comments.some((c) => c.isResolved());
|
|
423
458
|
let xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
|
|
424
459
|
xml += '<w:comments xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"';
|
|
425
460
|
xml += ' xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"';
|
|
461
|
+
if (hasResolved) {
|
|
462
|
+
xml += ' xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"';
|
|
463
|
+
}
|
|
426
464
|
if (hasReplies) {
|
|
427
465
|
xml += ' xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"';
|
|
428
|
-
|
|
429
|
-
|
|
466
|
+
}
|
|
467
|
+
if (hasReplies || hasResolved) {
|
|
468
|
+
const ignorable = [hasResolved ? 'w14' : '', hasReplies ? 'w15' : '']
|
|
469
|
+
.filter((ns) => ns.length > 0)
|
|
470
|
+
.join(' ');
|
|
471
|
+
xml += ` xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="${ignorable}"`;
|
|
430
472
|
}
|
|
431
473
|
xml += '>\n';
|
|
432
474
|
|
|
433
|
-
// Add each comment
|
|
475
|
+
// Add each comment. CT_Comment declares no resolved-state attribute —
|
|
476
|
+
// that lives in commentsExtended.xml keyed by the w14:paraId of each
|
|
477
|
+
// comment's last paragraph, so emit those anchors when any comment is
|
|
478
|
+
// resolved (see generateCommentsExtendedXml)
|
|
434
479
|
for (const comment of comments) {
|
|
435
|
-
xml += this.commentToXmlString(
|
|
480
|
+
xml += this.commentToXmlString(
|
|
481
|
+
comment,
|
|
482
|
+
hasResolved ? CommentManager.commentParaId(comment.getId()) : undefined
|
|
483
|
+
);
|
|
436
484
|
}
|
|
437
485
|
|
|
438
486
|
xml += '</w:comments>';
|
|
439
487
|
return xml;
|
|
440
488
|
}
|
|
441
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Derives the w14:paraId anchor for a comment's last paragraph.
|
|
492
|
+
* Deterministic so comments.xml and commentsExtended.xml agree without
|
|
493
|
+
* shared state. Values must be 8 hex digits, nonzero, and below
|
|
494
|
+
* 0x80000000 per ST_LongHexNumber conventions for paraId.
|
|
495
|
+
* @param commentId - Comment ID
|
|
496
|
+
* @returns 8-character uppercase hex paraId
|
|
497
|
+
*/
|
|
498
|
+
static commentParaId(commentId: number): string {
|
|
499
|
+
return ((commentId + 1) & 0x7fffffff).toString(16).toUpperCase().padStart(8, '0');
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Generates the word/commentsExtended.xml content carrying resolved
|
|
504
|
+
* state (w15:done) and reply threading (w15:paraIdParent).
|
|
505
|
+
* @returns XML string, or null when no comment is resolved (the part is
|
|
506
|
+
* only regenerated when it carries information)
|
|
507
|
+
*/
|
|
508
|
+
generateCommentsExtendedXml(): string | null {
|
|
509
|
+
const comments = this.getAllCommentsWithReplies();
|
|
510
|
+
if (!comments.some((c) => c.isResolved())) {
|
|
511
|
+
return null;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
let xml = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
|
|
515
|
+
xml += '<w15:commentsEx xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"';
|
|
516
|
+
xml +=
|
|
517
|
+
' xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w15">\n';
|
|
518
|
+
for (const comment of comments) {
|
|
519
|
+
xml += ` <w15:commentEx w15:paraId="${CommentManager.commentParaId(comment.getId())}"`;
|
|
520
|
+
const parentId = comment.getParentId();
|
|
521
|
+
if (parentId !== undefined && this.comments.has(parentId)) {
|
|
522
|
+
xml += ` w15:paraIdParent="${CommentManager.commentParaId(parentId)}"`;
|
|
523
|
+
}
|
|
524
|
+
xml += ` w15:done="${comment.isResolved() ? '1' : '0'}"/>\n`;
|
|
525
|
+
}
|
|
526
|
+
xml += '</w15:commentsEx>';
|
|
527
|
+
return xml;
|
|
528
|
+
}
|
|
529
|
+
|
|
442
530
|
/**
|
|
443
531
|
* Converts a comment to XML string
|
|
444
532
|
* @param comment - Comment to convert
|
|
533
|
+
* @param paraId - w14:paraId to anchor on the last paragraph (links the
|
|
534
|
+
* comment to its commentsExtended.xml entry), omitted when no comment
|
|
535
|
+
* in the document is resolved
|
|
445
536
|
* @returns XML string for the comment
|
|
446
537
|
*/
|
|
447
|
-
private commentToXmlString(comment: Comment): string {
|
|
538
|
+
private commentToXmlString(comment: Comment, paraId?: string): string {
|
|
448
539
|
let xml = ` <w:comment w:id="${comment.getId()}"`;
|
|
449
540
|
xml += ` w:author="${XMLBuilder.escapeXmlAttribute(comment.getAuthor())}"`;
|
|
450
541
|
xml += ` w:date="${formatDateForXml(comment.getDate())}"`;
|
|
@@ -454,19 +545,31 @@ export class CommentManager {
|
|
|
454
545
|
xml += ` w15:parentId="${comment.getParentId()}"`;
|
|
455
546
|
}
|
|
456
547
|
|
|
457
|
-
// Add done attribute for resolved comments (per ECMA-376)
|
|
458
|
-
if (comment.isResolved()) {
|
|
459
|
-
xml += ` w:done="1"`;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
548
|
xml += '>\n';
|
|
463
549
|
|
|
464
|
-
//
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
550
|
+
// One <w:p> per stored paragraph — collapsing into a single paragraph
|
|
551
|
+
// concatenates words across the lost boundaries and drops paragraph
|
|
552
|
+
// properties (CommentText pStyle) of parsed comments
|
|
553
|
+
const paragraphs = comment.getParagraphs();
|
|
554
|
+
for (let i = 0; i < paragraphs.length; i++) {
|
|
555
|
+
const paragraph = paragraphs[i]!;
|
|
556
|
+
// commentsExtended.xml entries reference the LAST paragraph's paraId
|
|
557
|
+
const isLast = i === paragraphs.length - 1;
|
|
558
|
+
xml += isLast && paraId ? ` <w:p w14:paraId="${paraId}">\n` : ' <w:p>\n';
|
|
559
|
+
if (paragraph.pPr) {
|
|
560
|
+
xml += ` ${paragraph.pPr}\n`;
|
|
561
|
+
}
|
|
562
|
+
for (const item of paragraph.content) {
|
|
563
|
+
if (item instanceof Run) {
|
|
564
|
+
xml += this.runToXmlString(item, 6);
|
|
565
|
+
} else {
|
|
566
|
+
// Preserved inline XML (e.g. w:hyperlink) re-emitted verbatim so
|
|
567
|
+
// its r:id target keeps pointing at word/_rels/comments.xml.rels
|
|
568
|
+
xml += ` ${item.rawXml}\n`;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
xml += ' </w:p>\n';
|
|
468
572
|
}
|
|
469
|
-
xml += ' </w:p>\n';
|
|
470
573
|
|
|
471
574
|
xml += ' </w:comment>\n';
|
|
472
575
|
return xml;
|
|
@@ -480,13 +583,9 @@ export class CommentManager {
|
|
|
480
583
|
*/
|
|
481
584
|
private runToXmlString(run: Run, indent: number): string {
|
|
482
585
|
const spaces = ' '.repeat(indent);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
xml += `${spaces} <w:t xml:space="preserve">${text}</w:t>\n`;
|
|
487
|
-
xml += `${spaces}</w:r>\n`;
|
|
488
|
-
|
|
489
|
-
return xml;
|
|
586
|
+
// Serialize through Run.toXML() so w:rPr formatting and non-text
|
|
587
|
+
// content (w:annotationRef, tabs, breaks) survive regeneration
|
|
588
|
+
return `${spaces}${XMLBuilder.elementToString(run.toXML())}\n`;
|
|
490
589
|
}
|
|
491
590
|
|
|
492
591
|
/**
|
|
@@ -130,7 +130,10 @@ export class EndnoteManager {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
|
-
* Removes an endnote
|
|
133
|
+
* Removes an endnote from the model only. Does not touch body
|
|
134
|
+
* w:endnoteReference runs or the document's dirty flags — callers going
|
|
135
|
+
* through a Document should use Document.removeEndnote(), which also
|
|
136
|
+
* strips the matching references and forces endnotes.xml regeneration.
|
|
134
137
|
* @param id Endnote ID
|
|
135
138
|
* @returns True if removed, false if not found or if it's a special type
|
|
136
139
|
*/
|