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/Table.ts
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { Paragraph } from './Paragraph.js';
|
|
6
|
+
import { Run } from './Run.js';
|
|
6
7
|
import { TableRow, RowFormatting } from './TableRow.js';
|
|
7
8
|
import { TableCell, CellFormatting } from './TableCell.js';
|
|
8
9
|
import { Revision } from './Revision.js';
|
|
9
10
|
import { XMLBuilder, XMLElement } from '../xml/XMLBuilder.js';
|
|
10
11
|
import { deepClone } from '../utils/deepClone.js';
|
|
12
|
+
import { formatDateForXml } from '../utils/dateFormatting.js';
|
|
11
13
|
import { TableGridChange } from './TableGridChange.js';
|
|
12
14
|
import {
|
|
13
15
|
TableAlignment as CommonTableAlignment,
|
|
@@ -2069,22 +2071,10 @@ export class Table {
|
|
|
2069
2071
|
if (this.rows.length <= 1 && !this.trackingContext?.isEnabled()) {
|
|
2070
2072
|
return false;
|
|
2071
2073
|
}
|
|
2072
|
-
// When tracking enabled,
|
|
2074
|
+
// When tracking enabled, record the whole-row tracked deletion instead
|
|
2075
|
+
// of removing the row
|
|
2073
2076
|
if (this.trackingContext?.isEnabled()) {
|
|
2074
|
-
|
|
2075
|
-
const row = this.rows[index]!;
|
|
2076
|
-
for (const cell of row.getCells()) {
|
|
2077
|
-
const cellDelRevision = Revision.createTableCellDelete(author, []);
|
|
2078
|
-
cell.setCellRevision(cellDelRevision);
|
|
2079
|
-
// Wrap paragraph runs in w:del so content appears as deleted
|
|
2080
|
-
for (const para of cell.getParagraphs()) {
|
|
2081
|
-
const runs = para.getRuns();
|
|
2082
|
-
if (runs.length > 0) {
|
|
2083
|
-
const deletion = Revision.createDeletion(author, runs);
|
|
2084
|
-
para.addRevision(deletion);
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2077
|
+
this.markRowAsTrackedDeletion(this.rows[index]!);
|
|
2088
2078
|
return true;
|
|
2089
2079
|
}
|
|
2090
2080
|
this.rows.splice(index, 1);
|
|
@@ -2109,6 +2099,47 @@ export class Table {
|
|
|
2109
2099
|
return true;
|
|
2110
2100
|
}
|
|
2111
2101
|
|
|
2102
|
+
/**
|
|
2103
|
+
* Marks a row as a tracked deletion. Per ECMA-376 §17.13.5.14 a tracked
|
|
2104
|
+
* whole-row deletion is recorded as `w:del` inside `w:trPr` — not as
|
|
2105
|
+
* per-cell `w:cellDel`, which tracks cell-structure changes and is never
|
|
2106
|
+
* resolved into a row removal by the revision acceptor. The cell text is
|
|
2107
|
+
* additionally wrapped in `w:del` so Word renders it struck through until
|
|
2108
|
+
* the revision is resolved.
|
|
2109
|
+
*/
|
|
2110
|
+
private markRowAsTrackedDeletion(row: TableRow): void {
|
|
2111
|
+
const author = this.trackingContext!.getAuthor();
|
|
2112
|
+
const manager = this.trackingContext!.getRevisionManager();
|
|
2113
|
+
row.setRowDeletion({
|
|
2114
|
+
id: String(manager.consumeNextId()),
|
|
2115
|
+
author,
|
|
2116
|
+
date: formatDateForXml(new Date()),
|
|
2117
|
+
});
|
|
2118
|
+
for (const cell of row.getCells()) {
|
|
2119
|
+
for (const para of cell.getParagraphs()) {
|
|
2120
|
+
this.wrapParagraphRunsInTrackedDeletion(para, author);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* Replaces each live run in the paragraph with a delete revision wrapping
|
|
2127
|
+
* it. Replacement (not append) matters: appending the revision would leave
|
|
2128
|
+
* the original run live alongside its `w:del` copy, so the text would
|
|
2129
|
+
* serialize twice and survive an accept. Items already inside revisions
|
|
2130
|
+
* are left alone to avoid double-wrapping.
|
|
2131
|
+
*/
|
|
2132
|
+
private wrapParagraphRunsInTrackedDeletion(para: Paragraph, author: string): void {
|
|
2133
|
+
const manager = this.trackingContext!.getRevisionManager();
|
|
2134
|
+
for (const item of para.getContent()) {
|
|
2135
|
+
if (item instanceof Run) {
|
|
2136
|
+
const deletion = Revision.createDeletion(author, item);
|
|
2137
|
+
manager.register(deletion);
|
|
2138
|
+
para.replaceContent(item, [deletion]);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2112
2143
|
/**
|
|
2113
2144
|
* Inserts a row at a specific position
|
|
2114
2145
|
*
|
|
@@ -2146,13 +2177,16 @@ export class Table {
|
|
|
2146
2177
|
// Insert the row
|
|
2147
2178
|
this.rows.splice(index, 0, row);
|
|
2148
2179
|
|
|
2149
|
-
// When tracking enabled, mark
|
|
2180
|
+
// When tracking enabled, mark the row as a tracked insertion. Per
|
|
2181
|
+
// ECMA-376 §17.13.5.19 a whole-row insertion is recorded as w:ins inside
|
|
2182
|
+
// w:trPr — per-cell w:cellIns tracks cell-structure changes and would not
|
|
2183
|
+
// let Word or the revision acceptor resolve the row as inserted.
|
|
2150
2184
|
if (this.trackingContext?.isEnabled()) {
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
}
|
|
2185
|
+
row.setRowInsertion({
|
|
2186
|
+
id: String(this.trackingContext.getRevisionManager().consumeNextId()),
|
|
2187
|
+
author: this.trackingContext.getAuthor(),
|
|
2188
|
+
date: formatDateForXml(new Date()),
|
|
2189
|
+
});
|
|
2156
2190
|
}
|
|
2157
2191
|
|
|
2158
2192
|
return row;
|
|
@@ -2198,6 +2232,26 @@ export class Table {
|
|
|
2198
2232
|
row.insertCellAt(idx, cell);
|
|
2199
2233
|
}
|
|
2200
2234
|
}
|
|
2235
|
+
|
|
2236
|
+
// Keep w:tblGrid in sync — toXML() trusts formatting.tableGrid for the
|
|
2237
|
+
// gridCol count whenever it is set (every loaded table has one), so a
|
|
2238
|
+
// stale grid makes rows consume more columns than the grid defines and
|
|
2239
|
+
// Word misassigns fixed-layout widths (ECMA-376 §17.4.49)
|
|
2240
|
+
const grid = this.formatting.tableGrid;
|
|
2241
|
+
if (grid) {
|
|
2242
|
+
const at = index === undefined || index >= grid.length ? grid.length : Math.max(0, index);
|
|
2243
|
+
const left = at > 0 ? grid[at - 1] : undefined;
|
|
2244
|
+
const right = at < grid.length ? grid[at] : undefined;
|
|
2245
|
+
// Mirror a neighbor's width; fall back to 1 inch when the grid has no
|
|
2246
|
+
// usable neighbor (e.g. an empty w:tblGrid) so a numeric width is always
|
|
2247
|
+
// inserted rather than `undefined`.
|
|
2248
|
+
const width =
|
|
2249
|
+
left !== undefined && right !== undefined
|
|
2250
|
+
? Math.round((left + right) / 2)
|
|
2251
|
+
: (left ?? right ?? 1440);
|
|
2252
|
+
grid.splice(at, 0, width);
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2201
2255
|
return this;
|
|
2202
2256
|
}
|
|
2203
2257
|
|
|
@@ -2220,15 +2274,25 @@ export class Table {
|
|
|
2220
2274
|
return false;
|
|
2221
2275
|
}
|
|
2222
2276
|
|
|
2223
|
-
// When tracking enabled, mark cells with cellDel instead of removing
|
|
2277
|
+
// When tracking enabled, mark cells with cellDel instead of removing.
|
|
2278
|
+
// Column deletions keep the cell-level marker (w:cellDel §17.13.5.1) —
|
|
2279
|
+
// a row-level w:del would claim entire rows were deleted.
|
|
2224
2280
|
if (this.trackingContext?.isEnabled()) {
|
|
2225
2281
|
const author = this.trackingContext.getAuthor();
|
|
2282
|
+
const manager = this.trackingContext.getRevisionManager();
|
|
2226
2283
|
let marked = false;
|
|
2227
2284
|
for (const row of this.rows) {
|
|
2228
2285
|
const cells = row.getCells();
|
|
2229
2286
|
if (index < cells.length) {
|
|
2287
|
+
const cell = cells[index]!;
|
|
2230
2288
|
const revision = Revision.createTableCellDelete(author, []);
|
|
2231
|
-
|
|
2289
|
+
// Register so each marker gets a unique w:id — unregistered
|
|
2290
|
+
// revisions all serialize as w:id="0", which fails validation
|
|
2291
|
+
manager.register(revision);
|
|
2292
|
+
cell.setCellRevision(revision);
|
|
2293
|
+
for (const para of cell.getParagraphs()) {
|
|
2294
|
+
this.wrapParagraphRunsInTrackedDeletion(para, author);
|
|
2295
|
+
}
|
|
2232
2296
|
marked = true;
|
|
2233
2297
|
}
|
|
2234
2298
|
}
|
|
@@ -2244,6 +2308,14 @@ export class Table {
|
|
|
2244
2308
|
}
|
|
2245
2309
|
}
|
|
2246
2310
|
|
|
2311
|
+
// Keep w:tblGrid in sync — leaving the deleted column's width in
|
|
2312
|
+
// formatting.tableGrid shifts every surviving column onto the wrong
|
|
2313
|
+
// gridCol width in fixed-layout tables (ECMA-376 §17.4.49). The tracked
|
|
2314
|
+
// branch above keeps cells in place, so the grid must not shrink there.
|
|
2315
|
+
if (removed && this.formatting.tableGrid && index < this.formatting.tableGrid.length) {
|
|
2316
|
+
this.formatting.tableGrid.splice(index, 1);
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2247
2319
|
return removed;
|
|
2248
2320
|
}
|
|
2249
2321
|
|
|
@@ -2738,6 +2810,28 @@ export class Table {
|
|
|
2738
2810
|
}
|
|
2739
2811
|
}
|
|
2740
2812
|
}
|
|
2813
|
+
} else if (endCol > startCol) {
|
|
2814
|
+
// Per ECMA-376 §17.4.17 a gridSpan cell consumes the columns it spans,
|
|
2815
|
+
// so the absorbed w:tc elements must leave the row — keeping them
|
|
2816
|
+
// widens the table grid and misaligns every other row. Their content
|
|
2817
|
+
// moves into the surviving cell first, matching Word's merge behavior.
|
|
2818
|
+
// vMerge 'continue' cells at startCol stay (required by §17.4.84), and
|
|
2819
|
+
// the tracked branch above keeps cells so w:cellMerge markers survive.
|
|
2820
|
+
const absorbedCount = endCol - startCol;
|
|
2821
|
+
for (let row = startRow; row <= endRow; row++) {
|
|
2822
|
+
const tableRow = this.rows[row];
|
|
2823
|
+
if (!tableRow) continue;
|
|
2824
|
+
for (let i = 0; i < absorbedCount; i++) {
|
|
2825
|
+
const absorbed = tableRow.removeCellAt(startCol + 1);
|
|
2826
|
+
if (!absorbed) break;
|
|
2827
|
+
for (const para of absorbed.getParagraphs()) {
|
|
2828
|
+
// Placeholder-empty paragraphs would only pad the merged cell
|
|
2829
|
+
// with blank lines Word's merge does not create
|
|
2830
|
+
if (para.getContent().length === 0) continue;
|
|
2831
|
+
cell.addParagraph(para);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2741
2835
|
}
|
|
2742
2836
|
|
|
2743
2837
|
return this;
|
|
@@ -2848,12 +2942,13 @@ export class Table {
|
|
|
2848
2942
|
const fromCell = this.getCell(fromRow, fromCol);
|
|
2849
2943
|
const toCell = this.getCell(toRow, toCol);
|
|
2850
2944
|
|
|
2851
|
-
if (!fromCell || !toCell) {
|
|
2945
|
+
if (!fromCell || !toCell || fromCell === toCell) {
|
|
2852
2946
|
return this;
|
|
2853
2947
|
}
|
|
2854
2948
|
|
|
2855
|
-
//
|
|
2856
|
-
|
|
2949
|
+
// Detach paragraphs from the source before re-homing them so the same
|
|
2950
|
+
// Paragraph instances never live in two cells at once
|
|
2951
|
+
const paragraphs = fromCell._detachAllParagraphs();
|
|
2857
2952
|
for (const para of paragraphs) {
|
|
2858
2953
|
toCell.addParagraph(para);
|
|
2859
2954
|
}
|
|
@@ -2865,11 +2960,11 @@ export class Table {
|
|
|
2865
2960
|
if (formatting.width) toCell.setWidth(formatting.width);
|
|
2866
2961
|
if (formatting.verticalAlignment) toCell.setVerticalAlignment(formatting.verticalAlignment);
|
|
2867
2962
|
|
|
2868
|
-
// Clear source cell
|
|
2963
|
+
// Clear source cell by writing an empty cell into the row's live array —
|
|
2964
|
+
// getCells() returns a defensive copy, so assigning into it never persists
|
|
2869
2965
|
const row = this.getRow(fromRow);
|
|
2870
2966
|
if (row) {
|
|
2871
|
-
|
|
2872
|
-
cells[fromCol] = new TableCell();
|
|
2967
|
+
row.setCellAt(fromCol, new TableCell());
|
|
2873
2968
|
}
|
|
2874
2969
|
|
|
2875
2970
|
return this;
|
|
@@ -2895,17 +2990,18 @@ export class Table {
|
|
|
2895
2990
|
return this;
|
|
2896
2991
|
}
|
|
2897
2992
|
|
|
2898
|
-
const
|
|
2899
|
-
const
|
|
2993
|
+
const cell1 = row1Obj.getCell(col1);
|
|
2994
|
+
const cell2 = row2Obj.getCell(col2);
|
|
2900
2995
|
|
|
2901
|
-
if (
|
|
2996
|
+
if (!cell1 || !cell2 || cell1 === cell2) {
|
|
2902
2997
|
return this;
|
|
2903
2998
|
}
|
|
2904
2999
|
|
|
2905
|
-
// Swap
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3000
|
+
// Swap through the rows' live cell arrays — getCells() returns a
|
|
3001
|
+
// defensive copy, so swapping inside it never persists. setCellAt also
|
|
3002
|
+
// re-points each cell's parent-row reference.
|
|
3003
|
+
row1Obj.setCellAt(col1, cell2);
|
|
3004
|
+
row2Obj.setCellAt(col2, cell1);
|
|
2909
3005
|
|
|
2910
3006
|
return this;
|
|
2911
3007
|
}
|
|
@@ -2976,22 +3072,10 @@ export class Table {
|
|
|
2976
3072
|
|
|
2977
3073
|
const actualCount = Math.min(count, this.rows.length - startIndex);
|
|
2978
3074
|
|
|
2979
|
-
// When tracking enabled,
|
|
3075
|
+
// When tracking enabled, record each row as a whole-row tracked deletion
|
|
2980
3076
|
if (this.trackingContext?.isEnabled()) {
|
|
2981
|
-
const author = this.trackingContext.getAuthor();
|
|
2982
3077
|
for (let i = startIndex; i < startIndex + actualCount; i++) {
|
|
2983
|
-
|
|
2984
|
-
for (const cell of row.getCells()) {
|
|
2985
|
-
const cellDelRevision = Revision.createTableCellDelete(author, []);
|
|
2986
|
-
cell.setCellRevision(cellDelRevision);
|
|
2987
|
-
for (const para of cell.getParagraphs()) {
|
|
2988
|
-
const runs = para.getRuns();
|
|
2989
|
-
if (runs.length > 0) {
|
|
2990
|
-
const deletion = Revision.createDeletion(author, runs);
|
|
2991
|
-
para.addRevision(deletion);
|
|
2992
|
-
}
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
3078
|
+
this.markRowAsTrackedDeletion(this.rows[i]!);
|
|
2995
3079
|
}
|
|
2996
3080
|
return true;
|
|
2997
3081
|
}
|
|
@@ -3322,6 +3406,23 @@ export class Table {
|
|
|
3322
3406
|
clonedTable.addRow(row.clone());
|
|
3323
3407
|
}
|
|
3324
3408
|
|
|
3409
|
+
// Tracked revision history (w:tblPrChange / w:tblGridChange) lives outside
|
|
3410
|
+
// formatting, so deepClone above cannot carry it — copy explicitly for
|
|
3411
|
+
// parity with TableRow.clone()/TableCell.clone().
|
|
3412
|
+
if (this.tblPrChange) {
|
|
3413
|
+
clonedTable.setTblPrChange(deepClone(this.tblPrChange));
|
|
3414
|
+
}
|
|
3415
|
+
if (this.tblGridChange) {
|
|
3416
|
+
clonedTable.setTblGridChange(
|
|
3417
|
+
new TableGridChange({
|
|
3418
|
+
id: this.tblGridChange.getId(),
|
|
3419
|
+
author: this.tblGridChange.getAuthor(),
|
|
3420
|
+
date: deepClone(this.tblGridChange.getDate()),
|
|
3421
|
+
previousGrid: deepClone(this.tblGridChange.getPreviousGrid()),
|
|
3422
|
+
})
|
|
3423
|
+
);
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3325
3426
|
return clonedTable;
|
|
3326
3427
|
}
|
|
3327
3428
|
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
import { deepClone } from '../utils/deepClone.js';
|
|
6
6
|
import { formatDateForXml } from '../utils/dateFormatting.js';
|
|
7
7
|
import { XMLBuilder, XMLElement } from '../xml/XMLBuilder.js';
|
|
8
|
+
import { Hyperlink } from './Hyperlink.js';
|
|
8
9
|
import { Paragraph, TextDirection } from './Paragraph.js';
|
|
9
10
|
import { Revision } from './Revision.js';
|
|
11
|
+
import { Run } from './Run.js';
|
|
10
12
|
import {
|
|
11
13
|
BorderStyle as CommonBorderStyle,
|
|
12
14
|
FullBorderStyle as CommonFullBorderStyle,
|
|
@@ -242,19 +244,32 @@ export class TableCell {
|
|
|
242
244
|
return false;
|
|
243
245
|
}
|
|
244
246
|
|
|
245
|
-
// When tracking enabled, wrap content in w:del instead of removing
|
|
247
|
+
// When tracking enabled, wrap content in w:del instead of removing.
|
|
248
|
+
// Each run is REPLACED by its delete revision — appending the revision
|
|
249
|
+
// would leave the original run live alongside its w:del copy, so the
|
|
250
|
+
// text would serialize twice and survive an accept.
|
|
246
251
|
if (this.trackingContext?.isEnabled()) {
|
|
247
252
|
const paragraph = this.paragraphs[index]!;
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
253
|
+
const author = this.trackingContext.getAuthor();
|
|
254
|
+
const manager = this.trackingContext.getRevisionManager();
|
|
255
|
+
for (const item of paragraph.getContent()) {
|
|
256
|
+
if (item instanceof Run || item instanceof Hyperlink) {
|
|
257
|
+
const deletion = Revision.createDeletion(author, item);
|
|
258
|
+
manager.register(deletion);
|
|
259
|
+
paragraph.replaceContent(item, [deletion]);
|
|
260
|
+
}
|
|
254
261
|
}
|
|
255
262
|
return true;
|
|
256
263
|
}
|
|
257
264
|
|
|
265
|
+
// Word repairs files where a nested table is the final child of w:tc —
|
|
266
|
+
// every cell must end with w:p. Refuse to remove the last paragraph when
|
|
267
|
+
// raw block content sits immediately before it and nothing would follow.
|
|
268
|
+
const isLastParagraph = index === this.paragraphs.length - 1;
|
|
269
|
+
if (isLastParagraph && this.rawNestedContent.some((item) => item.position === index)) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
|
|
258
273
|
const removed = this.paragraphs.splice(index, 1);
|
|
259
274
|
const removedPara = removed[0];
|
|
260
275
|
if (removedPara) {
|
|
@@ -309,14 +324,20 @@ export class TableCell {
|
|
|
309
324
|
paragraph._setStylesManager(stylesManager);
|
|
310
325
|
}
|
|
311
326
|
|
|
312
|
-
// When tracking enabled, wrap paragraph content in w:ins
|
|
327
|
+
// When tracking enabled, wrap paragraph content in w:ins revisions.
|
|
328
|
+
// Each top-level Run/Hyperlink is REPLACED by its insert revision in
|
|
329
|
+
// place — wrapping paragraph.getRuns() and appending the revision would
|
|
330
|
+
// leave the originals live alongside the w:ins copy, so the text would
|
|
331
|
+
// serialize twice and survive a reject.
|
|
313
332
|
if (this.trackingContext?.isEnabled()) {
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
333
|
+
const author = this.trackingContext.getAuthor();
|
|
334
|
+
const manager = this.trackingContext.getRevisionManager();
|
|
335
|
+
for (const item of paragraph.getContent()) {
|
|
336
|
+
if (item instanceof Run || item instanceof Hyperlink) {
|
|
337
|
+
const insertion = Revision.createInsertion(author, item);
|
|
338
|
+
manager.register(insertion);
|
|
339
|
+
paragraph.replaceContent(item, [insertion]);
|
|
340
|
+
}
|
|
320
341
|
}
|
|
321
342
|
}
|
|
322
343
|
|
|
@@ -1288,6 +1309,22 @@ export class TableCell {
|
|
|
1288
1309
|
return this._parentRow;
|
|
1289
1310
|
}
|
|
1290
1311
|
|
|
1312
|
+
/**
|
|
1313
|
+
* Removes every paragraph from this cell and returns them, bypassing
|
|
1314
|
+
* tracked-change wrapping. Used when content is moved wholesale to another
|
|
1315
|
+
* cell — the paragraphs must leave this cell's array first so the same
|
|
1316
|
+
* Paragraph instances never live in two cells at once.
|
|
1317
|
+
* @internal
|
|
1318
|
+
*/
|
|
1319
|
+
_detachAllParagraphs(): Paragraph[] {
|
|
1320
|
+
const detached = this.paragraphs;
|
|
1321
|
+
this.paragraphs = [];
|
|
1322
|
+
for (const para of detached) {
|
|
1323
|
+
para._setParentCell(undefined);
|
|
1324
|
+
}
|
|
1325
|
+
return detached;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1291
1328
|
/**
|
|
1292
1329
|
* Gets the table style ID by traversing up the parent chain.
|
|
1293
1330
|
* @returns Table style ID or undefined if not in a table or no style set
|
|
@@ -1707,6 +1744,7 @@ export class TableCell {
|
|
|
1707
1744
|
}
|
|
1708
1745
|
|
|
1709
1746
|
// Insert any remaining raw content after all paragraphs
|
|
1747
|
+
const rawContentEndsCell = rawIndex < sortedRaw.length;
|
|
1710
1748
|
while (rawIndex < sortedRaw.length) {
|
|
1711
1749
|
const rawItem = sortedRaw[rawIndex];
|
|
1712
1750
|
if (rawItem) {
|
|
@@ -1718,9 +1756,11 @@ export class TableCell {
|
|
|
1718
1756
|
rawIndex++;
|
|
1719
1757
|
}
|
|
1720
1758
|
|
|
1721
|
-
//
|
|
1722
|
-
//
|
|
1723
|
-
|
|
1759
|
+
// Word requires every cell to end with w:p (it repairs files where a
|
|
1760
|
+
// nested w:tbl is the final child of w:tc), so close with an empty
|
|
1761
|
+
// paragraph whenever raw block content ended up last — this also covers
|
|
1762
|
+
// cells that have raw content but no paragraphs at all
|
|
1763
|
+
if (rawContentEndsCell) {
|
|
1724
1764
|
cellChildren.push(new Paragraph().toXML());
|
|
1725
1765
|
}
|
|
1726
1766
|
} else {
|
|
@@ -247,11 +247,10 @@ export class TableOfContents {
|
|
|
247
247
|
|
|
248
248
|
// Add specific styles switch OR heading levels switch
|
|
249
249
|
if (this.includeStyles && this.includeStyles.length > 0) {
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
250
|
+
// Per ECMA-376 §17.16.5.68, \t takes a single field-argument with all
|
|
251
|
+
// StyleName,Level doublets — Word honors only one \t instance
|
|
252
|
+
const doublets = this.includeStyles.map((s) => `${s.styleName},${s.level}`).join(',');
|
|
253
|
+
instruction += ` \\t "${doublets}"`;
|
|
255
254
|
} else {
|
|
256
255
|
// Use \o switch for heading levels
|
|
257
256
|
instruction += ` \\o "1-${this.levels}"`;
|
|
@@ -273,11 +272,13 @@ export class TableOfContents {
|
|
|
273
272
|
}
|
|
274
273
|
|
|
275
274
|
// Add tab leader switch
|
|
276
|
-
|
|
275
|
+
// Per ECMA-376 §17.16.5.68, \p takes the literal separator character(s)
|
|
276
|
+
// between entry and page number, not an ST_TabTlc letter code.
|
|
277
|
+
// 'none' omits the switch so Word uses its default separator.
|
|
278
|
+
if (this.tabLeader !== 'dot' && this.tabLeader !== 'none') {
|
|
277
279
|
const leaderMap = {
|
|
278
|
-
hyphen: '
|
|
279
|
-
underscore: '
|
|
280
|
-
none: 'n',
|
|
280
|
+
hyphen: '-',
|
|
281
|
+
underscore: '_',
|
|
281
282
|
};
|
|
282
283
|
instruction += ` \\p "${leaderMap[this.tabLeader]}"`;
|
|
283
284
|
}
|
package/src/elements/TableRow.ts
CHANGED
|
@@ -250,6 +250,32 @@ export class TableRow {
|
|
|
250
250
|
cell._setParentRow(this);
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Replaces the cell at the specified index in the row's live cell array.
|
|
255
|
+
* getCells() returns a defensive copy, so callers cannot persist a
|
|
256
|
+
* replacement by writing into that copy — this is the write-through path.
|
|
257
|
+
* @param index - Position to replace (0-based)
|
|
258
|
+
* @returns The replaced cell, or undefined if index is out of bounds
|
|
259
|
+
*/
|
|
260
|
+
setCellAt(index: number, cell: TableCell): TableCell | undefined {
|
|
261
|
+
if (index < 0 || index >= this.cells.length) return undefined;
|
|
262
|
+
const previous = this.cells[index];
|
|
263
|
+
this.cells[index] = cell;
|
|
264
|
+
cell._setParentRow(this);
|
|
265
|
+
// During a swap the outgoing cell may already have been re-homed to
|
|
266
|
+
// another row (or re-inserted elsewhere in this row) — only orphan it
|
|
267
|
+
// when it genuinely left the table.
|
|
268
|
+
if (
|
|
269
|
+
previous &&
|
|
270
|
+
previous !== cell &&
|
|
271
|
+
previous._getParentRow() === this &&
|
|
272
|
+
!this.cells.includes(previous)
|
|
273
|
+
) {
|
|
274
|
+
previous._setParentRow(undefined);
|
|
275
|
+
}
|
|
276
|
+
return previous;
|
|
277
|
+
}
|
|
278
|
+
|
|
253
279
|
/**
|
|
254
280
|
* Removes and returns the cell at the specified index
|
|
255
281
|
* @param index - Position to remove (0-based)
|
|
@@ -283,9 +309,14 @@ export class TableRow {
|
|
|
283
309
|
* Calculates the total grid span of the row (considering column spans)
|
|
284
310
|
*
|
|
285
311
|
* For tables with merged cells, this returns the number of logical columns
|
|
286
|
-
* this row spans based on the columnSpan values of each cell.
|
|
312
|
+
* this row spans based on the columnSpan values of each cell. Per ECMA-376
|
|
313
|
+
* §17.4.14/§17.4.15, w:gridBefore/w:gridAfter consume grid columns before
|
|
314
|
+
* the first and after the last cell, so they count toward the row's grid
|
|
315
|
+
* footprint — otherwise auto-generated w:tblGrid would declare fewer
|
|
316
|
+
* columns than offset rows actually occupy.
|
|
287
317
|
*
|
|
288
|
-
* @returns Total grid span (sum of all cell spans
|
|
318
|
+
* @returns Total grid span (gridBefore + sum of all cell spans + gridAfter,
|
|
319
|
+
* where unspanned cells count as 1)
|
|
289
320
|
*
|
|
290
321
|
* @example
|
|
291
322
|
* ```typescript
|
|
@@ -298,11 +329,12 @@ export class TableRow {
|
|
|
298
329
|
* ```
|
|
299
330
|
*/
|
|
300
331
|
getTotalGridSpan(): number {
|
|
301
|
-
let totalSpan = 0;
|
|
332
|
+
let totalSpan = this.formatting.gridBefore ?? 0;
|
|
302
333
|
for (const cell of this.cells) {
|
|
303
334
|
const formatting = cell.getFormatting();
|
|
304
335
|
totalSpan += formatting.columnSpan || 1;
|
|
305
336
|
}
|
|
337
|
+
totalSpan += this.formatting.gridAfter ?? 0;
|
|
306
338
|
return totalSpan;
|
|
307
339
|
}
|
|
308
340
|
|
package/src/elements/TextBox.ts
CHANGED
|
@@ -390,58 +390,73 @@ export class TextBox {
|
|
|
390
390
|
relativeHeight: 251658240,
|
|
391
391
|
};
|
|
392
392
|
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
posHChildren.push({
|
|
400
|
-
name: 'wp:posOffset',
|
|
401
|
-
children: [posH.offset.toString()],
|
|
402
|
-
});
|
|
403
|
-
} else if (posH.alignment) {
|
|
404
|
-
posHChildren.push({
|
|
405
|
-
name: 'wp:align',
|
|
406
|
-
children: [posH.alignment],
|
|
407
|
-
});
|
|
408
|
-
}
|
|
393
|
+
// simplePos (required first child per CT_Anchor)
|
|
394
|
+
children.push({
|
|
395
|
+
name: 'wp:simplePos',
|
|
396
|
+
attributes: { x: '0', y: '0' },
|
|
397
|
+
selfClosing: true,
|
|
398
|
+
});
|
|
409
399
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
400
|
+
// Position H (horizontal) — required child of wp:anchor per CT_Anchor
|
|
401
|
+
// (minOccurs=1), so fall back to a zero page offset when no explicit
|
|
402
|
+
// position is configured (anchor-only floating text boxes)
|
|
403
|
+
const posH = this.position?.horizontal;
|
|
404
|
+
const posHChildren: XMLElement[] = [];
|
|
405
|
+
|
|
406
|
+
if (posH?.offset !== undefined) {
|
|
407
|
+
posHChildren.push({
|
|
408
|
+
name: 'wp:posOffset',
|
|
409
|
+
children: [posH.offset.toString()],
|
|
410
|
+
});
|
|
411
|
+
} else if (posH?.alignment) {
|
|
412
|
+
posHChildren.push({
|
|
413
|
+
name: 'wp:align',
|
|
414
|
+
children: [posH.alignment],
|
|
415
|
+
});
|
|
416
|
+
} else {
|
|
417
|
+
posHChildren.push({
|
|
418
|
+
name: 'wp:posOffset',
|
|
419
|
+
children: ['0'],
|
|
416
420
|
});
|
|
417
421
|
}
|
|
418
422
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
+
children.push({
|
|
424
|
+
name: 'wp:positionH',
|
|
425
|
+
attributes: {
|
|
426
|
+
relativeFrom: posH?.anchor ?? 'page',
|
|
427
|
+
},
|
|
428
|
+
children: posHChildren,
|
|
429
|
+
});
|
|
423
430
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
children: [posV.offset.toString()],
|
|
428
|
-
});
|
|
429
|
-
} else if (posV.alignment) {
|
|
430
|
-
posVChildren.push({
|
|
431
|
-
name: 'wp:align',
|
|
432
|
-
children: [posV.alignment],
|
|
433
|
-
});
|
|
434
|
-
}
|
|
431
|
+
// Position V (vertical) — required child of wp:anchor per CT_Anchor
|
|
432
|
+
const posV = this.position?.vertical;
|
|
433
|
+
const posVChildren: XMLElement[] = [];
|
|
435
434
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
435
|
+
if (posV?.offset !== undefined) {
|
|
436
|
+
posVChildren.push({
|
|
437
|
+
name: 'wp:posOffset',
|
|
438
|
+
children: [posV.offset.toString()],
|
|
439
|
+
});
|
|
440
|
+
} else if (posV?.alignment) {
|
|
441
|
+
posVChildren.push({
|
|
442
|
+
name: 'wp:align',
|
|
443
|
+
children: [posV.alignment],
|
|
444
|
+
});
|
|
445
|
+
} else {
|
|
446
|
+
posVChildren.push({
|
|
447
|
+
name: 'wp:posOffset',
|
|
448
|
+
children: ['0'],
|
|
442
449
|
});
|
|
443
450
|
}
|
|
444
451
|
|
|
452
|
+
children.push({
|
|
453
|
+
name: 'wp:positionV',
|
|
454
|
+
attributes: {
|
|
455
|
+
relativeFrom: posV?.anchor ?? 'page',
|
|
456
|
+
},
|
|
457
|
+
children: posVChildren,
|
|
458
|
+
});
|
|
459
|
+
|
|
445
460
|
// Extent (size)
|
|
446
461
|
children.push({
|
|
447
462
|
name: 'wp:extent',
|
|
@@ -357,8 +357,10 @@ export class AbstractNumbering {
|
|
|
357
357
|
children.push(level.toXML());
|
|
358
358
|
});
|
|
359
359
|
|
|
360
|
-
// If no levels defined, add a default level 0
|
|
361
|
-
|
|
360
|
+
// If no levels defined, add a default level 0 — except for numStyleLink
|
|
361
|
+
// definitions, which are pure style references per ECMA-376 §17.9.21 and
|
|
362
|
+
// must carry no w:lvl children (the linked style supplies the levels)
|
|
363
|
+
if (sortedLevels.length === 0 && !this.numStyleLink) {
|
|
362
364
|
children.push(NumberingLevel.createDecimalLevel(0).toXML());
|
|
363
365
|
}
|
|
364
366
|
|