documentation-hub 5.7.2
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/.eslintrc.json +43 -0
- package/.github/workflows/build.yml +64 -0
- package/.github/workflows/ci.yml +39 -0
- package/.vscode/extensions.json +3 -0
- package/Current.md +97 -0
- package/DocHub_Image.png +0 -0
- package/README.md +666 -0
- package/USER_GUIDE.md +1173 -0
- package/Updater.md +311 -0
- package/build/256x256.png +0 -0
- package/build/512x512.png +0 -0
- package/build/app-update.yml +4 -0
- package/build/create-icon.js +208 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon_1024x1024.png +0 -0
- package/dist/assets/Analytics-BpsG9895.js +1 -0
- package/dist/assets/Card-IAZin8kp.js +1 -0
- package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
- package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
- package/dist/assets/Documents-CqZ25axS.js +1 -0
- package/dist/assets/Input-l89xwXBi.js +1 -0
- package/dist/assets/Reporting-DqdHJY_a.js +1 -0
- package/dist/assets/Search-XNbu5z_3.js +1 -0
- package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
- package/dist/assets/Sessions-ClZOPYNc.js +1 -0
- package/dist/assets/Settings-DUEHGURa.js +11 -0
- package/dist/assets/index-8xUe8ptc.js +24 -0
- package/dist/assets/index-RYyJqF7O.css +1 -0
- package/dist/assets/path-BkOl0AGO.js +1 -0
- package/dist/assets/promises-ID_B9S-h.js +1 -0
- package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
- package/dist/assets/useToast-yRSO1dkm.js +1 -0
- package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
- package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
- package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
- package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
- package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
- package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
- package/dist/electron/main-CXkNtyv-.js +19789 -0
- package/dist/electron/main.js +5 -0
- package/dist/electron/preload.js +1 -0
- package/dist/icon.png +0 -0
- package/dist/index.html +27 -0
- package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
- package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
- package/docs/README.md +115 -0
- package/docs/TOC_WIRING_GUIDE.md +344 -0
- package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
- package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
- package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
- package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
- package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
- package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
- package/docs/analysis/List_Implementation.md +206 -0
- package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
- package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
- package/docs/analysis/RefactorStyles.md +852 -0
- package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
- package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
- package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
- package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
- package/docs/analysis/github-issues-to-create.md +237 -0
- package/docs/api/API_README.md +538 -0
- package/docs/api/API_REFERENCE.md +751 -0
- package/docs/api/TYPE_DEFINITIONS.md +869 -0
- package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
- package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
- package/docs/docxmlater-readme.md +1341 -0
- package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
- package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
- package/docs/fixes/README.md +37 -0
- package/docs/github-issues/issue-1-body.md +125 -0
- package/docs/github-issues/issue-10-body.md +850 -0
- package/docs/github-issues/issue-2-body.md +200 -0
- package/docs/github-issues/issue-3-body.md +270 -0
- package/docs/github-issues/issue-4-body.md +169 -0
- package/docs/github-issues/issue-5-body.md +173 -0
- package/docs/github-issues/issue-6-body.md +158 -0
- package/docs/github-issues/issue-7-body.md +171 -0
- package/docs/github-issues/issue-8-body.md +407 -0
- package/docs/github-issues/issue-9-body.md +515 -0
- package/docs/github-issues/issue-tracker.md +274 -0
- package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
- package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
- package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
- package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
- package/docs/implementation/RefactorStyles.md +588 -0
- package/docs/implementation/implement-plan.md +489 -0
- package/docs/implementation/missing-helpers-implementation.md +391 -0
- package/docs/implementation/refactor-plan.md +520 -0
- package/docs/implementation/session-implementation-complete.md +233 -0
- package/docs/implementation/session-management-plan.md +250 -0
- package/docs/setup-checklist.md +77 -0
- package/docs/versions/changelog.md +345 -0
- package/electron/customUpdater.ts +656 -0
- package/electron/main.ts +2441 -0
- package/electron/memoryConfig.ts +187 -0
- package/electron/preload.ts +394 -0
- package/electron/proxyConfig.ts +340 -0
- package/electron/services/BackupService.ts +452 -0
- package/electron/services/DictionaryService.ts +402 -0
- package/electron/services/LocalDictionaryLookupService.ts +147 -0
- package/electron/services/PowerAutomateApiService.ts +231 -0
- package/electron/services/SharePointSyncService.ts +474 -0
- package/electron/windowsCertStore.ts +427 -0
- package/electron/zscalerConfig.ts +381 -0
- package/eslint.config.js +92 -0
- package/jest.config.js +52 -0
- package/package.json +214 -0
- package/postcss.config.mjs +6 -0
- package/public/icon.png +0 -0
- package/publish-release.ps1 +5 -0
- package/renovate.json +30 -0
- package/src/App.tsx +216 -0
- package/src/__mocks__/p-limit.js +12 -0
- package/src/__mocks__/styleMock.js +1 -0
- package/src/components/common/BugReportButton.tsx +44 -0
- package/src/components/common/BugReportDialog.tsx +193 -0
- package/src/components/common/Button.tsx +153 -0
- package/src/components/common/Card.tsx +86 -0
- package/src/components/common/ColorPickerDialog.tsx +177 -0
- package/src/components/common/ConfirmDialog.tsx +96 -0
- package/src/components/common/DebugConsole.tsx +275 -0
- package/src/components/common/EmptyState.tsx +183 -0
- package/src/components/common/ErrorBoundary.tsx +98 -0
- package/src/components/common/ErrorDetailsDialog.tsx +153 -0
- package/src/components/common/ErrorFallback.tsx +218 -0
- package/src/components/common/Input.tsx +109 -0
- package/src/components/common/Skeleton.tsx +184 -0
- package/src/components/common/SplashScreen.tsx +81 -0
- package/src/components/common/Toast.tsx +155 -0
- package/src/components/common/Tooltip.tsx +79 -0
- package/src/components/common/UpdateNotification.tsx +320 -0
- package/src/components/comparison/ComparisonWindow.tsx +374 -0
- package/src/components/comparison/SideBySideDiff.tsx +486 -0
- package/src/components/comparison/index.ts +8 -0
- package/src/components/document/DocumentUploader.tsx +288 -0
- package/src/components/document/HyperlinkPreview.tsx +430 -0
- package/src/components/document/HyperlinkService.md +1484 -0
- package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
- package/src/components/document/InlineChangesView.tsx +707 -0
- package/src/components/document/ProcessingProgress.tsx +303 -0
- package/src/components/document/ProcessingResults.tsx +256 -0
- package/src/components/document/TrackedChangesDetail.tsx +530 -0
- package/src/components/document/TrackedChangesPanel.tsx +546 -0
- package/src/components/document/VirtualDocumentList.tsx +240 -0
- package/src/components/editor/DocumentEditor.tsx +723 -0
- package/src/components/editor/DocumentEditorModal.tsx +640 -0
- package/src/components/editor/EditorQuickActions.tsx +502 -0
- package/src/components/editor/EditorToolbar.tsx +312 -0
- package/src/components/editor/TableEditor.tsx +926 -0
- package/src/components/editor/index.ts +18 -0
- package/src/components/layout/Header.tsx +190 -0
- package/src/components/layout/Sidebar.tsx +313 -0
- package/src/components/layout/TitleBar.tsx +190 -0
- package/src/components/navigation/CommandPalette.tsx +233 -0
- package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
- package/src/components/sessions/ChangeItem.tsx +408 -0
- package/src/components/sessions/ChangeViewer.tsx +1155 -0
- package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
- package/src/components/sessions/ProcessingOptions.tsx +297 -0
- package/src/components/sessions/ReplacementsTab.tsx +438 -0
- package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
- package/src/components/sessions/SessionManager.tsx +188 -0
- package/src/components/sessions/StylesEditor.tsx +1335 -0
- package/src/components/sessions/TabContainer.tsx +151 -0
- package/src/components/sessions/VirtualSessionList.tsx +157 -0
- package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
- package/src/components/settings/CertificateManager.tsx +410 -0
- package/src/components/settings/SegmentedControl.tsx +88 -0
- package/src/components/settings/SettingRow.tsx +52 -0
- package/src/contexts/GlobalStatsContext.tsx +396 -0
- package/src/contexts/SessionContext.tsx +2129 -0
- package/src/contexts/ThemeContext.tsx +428 -0
- package/src/contexts/UserSettingsContext.tsx +290 -0
- package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
- package/src/global.d.ts +273 -0
- package/src/hooks/useDocumentQueue.tsx +210 -0
- package/src/hooks/useToast.tsx +55 -0
- package/src/main.tsx +10 -0
- package/src/pages/Analytics.tsx +386 -0
- package/src/pages/CurrentSession.tsx +1174 -0
- package/src/pages/Dashboard.tsx +319 -0
- package/src/pages/Documents.tsx +317 -0
- package/src/pages/Projects.tsx +250 -0
- package/src/pages/Reporting.tsx +386 -0
- package/src/pages/Search.tsx +349 -0
- package/src/pages/Sessions.tsx +285 -0
- package/src/pages/Settings.tsx +2662 -0
- package/src/services/HyperlinkService.ts +1085 -0
- package/src/services/document/DocXMLaterProcessor.ts +617 -0
- package/src/services/document/DocumentProcessingComparison.ts +856 -0
- package/src/services/document/DocumentSnapshotService.ts +575 -0
- package/src/services/document/WordDocumentProcessor.ts +10509 -0
- package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
- package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
- package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
- package/src/services/document/blanklines/BlankLineManager.ts +658 -0
- package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
- package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
- package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
- package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
- package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
- package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
- package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
- package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
- package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
- package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
- package/src/services/document/blanklines/index.ts +67 -0
- package/src/services/document/blanklines/rules/additionRules.ts +337 -0
- package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
- package/src/services/document/blanklines/rules/removalRules.ts +362 -0
- package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
- package/src/services/document/blanklines/types.ts +29 -0
- package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
- package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
- package/src/services/document/helpers/whitespace.ts +117 -0
- package/src/services/document/list/ListNormalizer.ts +947 -0
- package/src/services/document/list/index.ts +45 -0
- package/src/services/document/list/list-detection.ts +275 -0
- package/src/services/document/list/list-types.ts +162 -0
- package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
- package/src/services/document/processors/ListProcessor.ts +257 -0
- package/src/services/document/processors/StructureProcessor.ts +176 -0
- package/src/services/document/processors/StyleProcessor.ts +389 -0
- package/src/services/document/processors/TableProcessor.ts +2238 -0
- package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
- package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
- package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
- package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
- package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
- package/src/services/document/processors/index.ts +28 -0
- package/src/services/document/types/docx-processing.ts +310 -0
- package/src/services/editor/EditorActionHandlers.ts +901 -0
- package/src/services/editor/index.ts +13 -0
- package/src/setupTests.ts +47 -0
- package/src/styles/global.css +782 -0
- package/src/types/backup.ts +132 -0
- package/src/types/dictionary.ts +125 -0
- package/src/types/document-processing.ts +331 -0
- package/src/types/docxmlater-augments.d.ts +142 -0
- package/src/types/editor.ts +280 -0
- package/src/types/electron.ts +340 -0
- package/src/types/globalStats.ts +155 -0
- package/src/types/hyperlink.ts +471 -0
- package/src/types/operations.ts +354 -0
- package/src/types/session.ts +427 -0
- package/src/types/settings.ts +112 -0
- package/src/utils/MemoryMonitor.ts +248 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/colorConvert.ts +306 -0
- package/src/utils/diffUtils.ts +347 -0
- package/src/utils/documentUtils.ts +202 -0
- package/src/utils/electronGuard.ts +62 -0
- package/src/utils/indexedDB.ts +915 -0
- package/src/utils/logger.ts +717 -0
- package/src/utils/pathSecurity.ts +232 -0
- package/src/utils/pathValidator.ts +236 -0
- package/src/utils/processingTimeEstimator.ts +153 -0
- package/src/utils/safeJsonParse.ts +62 -0
- package/src/utils/textSanitizer.ts +162 -0
- package/src/utils/urlHelpers.ts +304 -0
- package/src/utils/urlPatterns.ts +198 -0
- package/src/utils/urlSanitizer.ts +152 -0
- package/src/vite-env.d.ts +11 -0
- package/tsconfig.electron.json +19 -0
- package/tsconfig.json +36 -0
- package/tsconfig.node.json +12 -0
- package/typedoc.json +45 -0
- package/vite.config.ts +152 -0
|
@@ -0,0 +1,1341 @@
|
|
|
1
|
+
# docXMLater - Professional DOCX Framework
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/docxmlater)
|
|
4
|
+
[](https://github.com/ItMeDiaTech/docXMLater)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
A comprehensive, production-ready TypeScript/JavaScript library for creating, reading, and manipulating Microsoft Word (.docx) documents programmatically. Full OpenXML compliance with extensive API coverage and **100% test pass rate**.
|
|
9
|
+
|
|
10
|
+
Built for professional documentation work, docXMLater provides a complete solution for programmatic DOCX manipulation with an intuitive API and helper functions for all aspects of document creation and modification.
|
|
11
|
+
|
|
12
|
+
## Latest Updates - v1.16.0
|
|
13
|
+
|
|
14
|
+
**Production Release!** All major features complete:
|
|
15
|
+
|
|
16
|
+
### What's New in v1.16.0
|
|
17
|
+
|
|
18
|
+
- **Complete Feature Set:** All 102 major features implemented across 5 phases
|
|
19
|
+
- **Table Styles:** Full support with 12 conditional formatting types
|
|
20
|
+
- **Content Controls:** 9 control types (rich text, plain text, combo box, dropdown, date picker, checkbox, picture, building block, group)
|
|
21
|
+
- **Field Types:** 11 field types (PAGE, NUMPAGES, DATE, TIME, FILENAME, AUTHOR, TITLE, REF, HYPERLINK, SEQ, TC/XE)
|
|
22
|
+
- **Drawing Elements:** Shapes and textboxes with full positioning
|
|
23
|
+
- **Document Properties:** Core, extended, and custom properties
|
|
24
|
+
- **Production Ready:** Full ECMA-376 compliance, zero regressions
|
|
25
|
+
|
|
26
|
+
**Test Results:** 2,073/2,073 tests passing (100% - comprehensive test coverage)
|
|
27
|
+
|
|
28
|
+
### Implementation Phases - All Complete ✅
|
|
29
|
+
|
|
30
|
+
| Phase | Status | Features |
|
|
31
|
+
| -------------------------------- | ----------- | ----------------------------------------------------- |
|
|
32
|
+
| **Phase 1: Foundation** | ✅ Complete | ZIP handling, XML generation, validation |
|
|
33
|
+
| **Phase 2: Core Elements** | ✅ Complete | Paragraph, Run, text formatting |
|
|
34
|
+
| **Phase 3: Advanced Formatting** | ✅ Complete | Styles, tables, sections, lists |
|
|
35
|
+
| **Phase 4: Rich Content** | ✅ Complete | Images, headers, footers, hyperlinks |
|
|
36
|
+
| **Phase 5: Polish** | ✅ Complete | Track changes, comments, TOC, hyperlink defragmentation |
|
|
37
|
+
|
|
38
|
+
### Phase 4 & 5 Highlights (v1.13.0 - v1.16.0)
|
|
39
|
+
|
|
40
|
+
#### Phase 4: Rich Content Features
|
|
41
|
+
- **Images**: PNG, JPEG, GIF support with positioning and sizing
|
|
42
|
+
- **Headers & Footers**: Different first/odd/even pages with dynamic fields
|
|
43
|
+
- **Hyperlinks**: External, internal, and email links with full relationship management
|
|
44
|
+
- **Hyperlink Extraction**: Comprehensive API covering main content, tables, headers, and footers
|
|
45
|
+
- **Batch URL Updates**: Efficient bulk hyperlink URL modification with error tracking
|
|
46
|
+
|
|
47
|
+
#### Phase 5: Polish & Advanced Features
|
|
48
|
+
- **Hyperlink Defragmentation** (v1.15.0): Fix fragmented hyperlinks from Google Docs imports
|
|
49
|
+
- **List Formatting Helpers** (v1.14.0): Smart bullet and numbering with proper indentation
|
|
50
|
+
- **Special Character Support** (v1.14.0): Tabs, newlines, non-breaking hyphens serialize correctly
|
|
51
|
+
- **Track Changes**: Insertions and deletions with author attribution
|
|
52
|
+
- **Comments**: Threading and replies for collaboration
|
|
53
|
+
- **Table of Contents**: Multiple TOC styles with customization
|
|
54
|
+
- **XML Corruption Prevention**: Automatic sanitization of XML patterns in text
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install docxmlater
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { Document } from "docxmlater";
|
|
64
|
+
|
|
65
|
+
// Create document
|
|
66
|
+
const doc = Document.create();
|
|
67
|
+
doc.createParagraph("Hello World").setStyle("Title");
|
|
68
|
+
|
|
69
|
+
// Save document
|
|
70
|
+
await doc.save("output.docx");
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Complete API Reference
|
|
74
|
+
|
|
75
|
+
### Document Operations
|
|
76
|
+
|
|
77
|
+
| Method | Description | Example |
|
|
78
|
+
| --------------------------------- | ----------------------- | ------------------------------------------------ |
|
|
79
|
+
| `Document.create(options?)` | Create new document | `const doc = Document.create()` |
|
|
80
|
+
| `Document.createEmpty()` | Create minimal document | `const doc = Document.createEmpty()` |
|
|
81
|
+
| `Document.load(path)` | Load from file | `const doc = await Document.load('file.docx')` |
|
|
82
|
+
| `Document.loadFromBuffer(buffer)` | Load from buffer | `const doc = await Document.loadFromBuffer(buf)` |
|
|
83
|
+
| `save(path)` | Save to file | `await doc.save('output.docx')` |
|
|
84
|
+
| `toBuffer()` | Export as buffer | `const buffer = await doc.toBuffer()` |
|
|
85
|
+
| `dispose()` | Clean up resources | `doc.dispose()` |
|
|
86
|
+
|
|
87
|
+
### Content Creation
|
|
88
|
+
|
|
89
|
+
| Method | Description | Example |
|
|
90
|
+
| -------------------------------- | ------------------------ | -------------------------------- |
|
|
91
|
+
| `createParagraph(text?)` | Add paragraph | `doc.createParagraph('Text')` |
|
|
92
|
+
| `createTable(rows, cols)` | Add table | `doc.createTable(3, 4)` |
|
|
93
|
+
| `addParagraph(para)` | Add existing paragraph | `doc.addParagraph(myPara)` |
|
|
94
|
+
| `addTable(table)` | Add existing table | `doc.addTable(myTable)` |
|
|
95
|
+
| `addImage(image)` | Add image | `doc.addImage(myImage)` |
|
|
96
|
+
| `addTableOfContents(toc?)` | Add TOC | `doc.addTableOfContents()` |
|
|
97
|
+
| `insertParagraphAt(index, para)` | Insert at position | `doc.insertParagraphAt(0, para)` |
|
|
98
|
+
| `insertTableAt(index, table)` | Insert table at position | `doc.insertTableAt(5, table)` |
|
|
99
|
+
| `insertTocAt(index, toc)` | Insert TOC at position | `doc.insertTocAt(0, toc)` |
|
|
100
|
+
|
|
101
|
+
### Content Manipulation
|
|
102
|
+
|
|
103
|
+
| Method | Description | Returns |
|
|
104
|
+
| --------------------------------- | ---------------------------- | --------- |
|
|
105
|
+
| `replaceParagraphAt(index, para)` | Replace paragraph | `boolean` |
|
|
106
|
+
| `replaceTableAt(index, table)` | Replace table | `boolean` |
|
|
107
|
+
| `moveElement(fromIndex, toIndex)` | Move element to new position | `boolean` |
|
|
108
|
+
| `swapElements(index1, index2)` | Swap two elements | `boolean` |
|
|
109
|
+
| `removeTocAt(index)` | Remove TOC element | `boolean` |
|
|
110
|
+
|
|
111
|
+
### Content Retrieval
|
|
112
|
+
|
|
113
|
+
| Method | Description | Returns |
|
|
114
|
+
| --------------------- | --------------------- | ------------------------------------------ |
|
|
115
|
+
| `getParagraphs()` | Get all paragraphs | `Paragraph[]` |
|
|
116
|
+
| `getTables()` | Get all tables | `Table[]` |
|
|
117
|
+
| `getBodyElements()` | Get all body elements | `BodyElement[]` |
|
|
118
|
+
| `getParagraphCount()` | Count paragraphs | `number` |
|
|
119
|
+
| `getTableCount()` | Count tables | `number` |
|
|
120
|
+
| `getHyperlinks()` | Get all links | `Array<{hyperlink, paragraph}>` |
|
|
121
|
+
| `getBookmarks()` | Get all bookmarks | `Array<{bookmark, paragraph}>` |
|
|
122
|
+
| `getImages()` | Get all images | `Array<{image, relationshipId, filename}>` |
|
|
123
|
+
|
|
124
|
+
### Content Removal
|
|
125
|
+
|
|
126
|
+
| Method | Description | Returns |
|
|
127
|
+
| ------------------------------ | ------------------ | --------- |
|
|
128
|
+
| `removeParagraph(paraOrIndex)` | Remove paragraph | `boolean` |
|
|
129
|
+
| `removeTable(tableOrIndex)` | Remove table | `boolean` |
|
|
130
|
+
| `clearParagraphs()` | Remove all content | `this` |
|
|
131
|
+
|
|
132
|
+
### Search & Replace
|
|
133
|
+
|
|
134
|
+
| Method | Description | Options |
|
|
135
|
+
| -------------------------------------- | --------------------- | ------------------------------ |
|
|
136
|
+
| `findText(text, options?)` | Find text occurrences | `{caseSensitive?, wholeWord?}` |
|
|
137
|
+
| `replaceText(find, replace, options?)` | Replace all text | `{caseSensitive?, wholeWord?}` |
|
|
138
|
+
| `updateHyperlinkUrls(urlMap)` | Update hyperlink URLs | `Map<oldUrl, newUrl>` |
|
|
139
|
+
|
|
140
|
+
### Style Application
|
|
141
|
+
|
|
142
|
+
| Method | Description | Returns |
|
|
143
|
+
| ------------------------------------- | -------------------------------- | ------------------- |
|
|
144
|
+
| `applyStyleToAll(styleId, predicate)` | Apply style to matching elements | `number` |
|
|
145
|
+
| `findElementsByStyle(styleId)` | Find all elements using a style | `Array<Para\|Cell>` |
|
|
146
|
+
|
|
147
|
+
**Example:**
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// Apply Heading1 to all paragraphs containing "Chapter"
|
|
151
|
+
const count = doc.applyStyleToAll("Heading1", (el) => {
|
|
152
|
+
return el instanceof Paragraph && el.getText().includes("Chapter");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Find all Heading1 elements
|
|
156
|
+
const headings = doc.findElementsByStyle("Heading1");
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Document Statistics
|
|
160
|
+
|
|
161
|
+
| Method | Description | Returns |
|
|
162
|
+
| ----------------------------------- | ------------------- | ------------------------------ |
|
|
163
|
+
| `getWordCount()` | Total word count | `number` |
|
|
164
|
+
| `getCharacterCount(includeSpaces?)` | Character count | `number` |
|
|
165
|
+
| `estimateSize()` | Size estimation | `{totalEstimatedMB, warning?}` |
|
|
166
|
+
| `getSizeStats()` | Detailed size stats | `{elements, size, warnings}` |
|
|
167
|
+
|
|
168
|
+
### Text Formatting
|
|
169
|
+
|
|
170
|
+
| Property | Values | Example |
|
|
171
|
+
| ------------- | -------------------------------- | ----------------------- |
|
|
172
|
+
| `bold` | `true/false` | `{bold: true}` |
|
|
173
|
+
| `italic` | `true/false` | `{italic: true}` |
|
|
174
|
+
| `underline` | `'single'/'double'/'dotted'/etc` | `{underline: 'single'}` |
|
|
175
|
+
| `strike` | `true/false` | `{strike: true}` |
|
|
176
|
+
| `font` | Font name | `{font: 'Arial'}` |
|
|
177
|
+
| `size` | Points | `{size: 12}` |
|
|
178
|
+
| `color` | Hex color | `{color: 'FF0000'}` |
|
|
179
|
+
| `highlight` | Color name | `{highlight: 'yellow'}` |
|
|
180
|
+
| `subscript` | `true/false` | `{subscript: true}` |
|
|
181
|
+
| `superscript` | `true/false` | `{superscript: true}` |
|
|
182
|
+
| `smallCaps` | `true/false` | `{smallCaps: true}` |
|
|
183
|
+
| `allCaps` | `true/false` | `{allCaps: true}` |
|
|
184
|
+
|
|
185
|
+
### Paragraph Operations
|
|
186
|
+
|
|
187
|
+
#### Creating Detached Paragraphs
|
|
188
|
+
|
|
189
|
+
Create paragraphs independently before adding to a document:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Create empty paragraph
|
|
193
|
+
const para1 = Paragraph.create();
|
|
194
|
+
|
|
195
|
+
// Create with text
|
|
196
|
+
const para2 = Paragraph.create("Hello World");
|
|
197
|
+
|
|
198
|
+
// Create with text and formatting
|
|
199
|
+
const para3 = Paragraph.create("Centered text", { alignment: "center" });
|
|
200
|
+
|
|
201
|
+
// Create with just formatting
|
|
202
|
+
const para4 = Paragraph.create({
|
|
203
|
+
alignment: "right",
|
|
204
|
+
spacing: { before: 240 },
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Create with style
|
|
208
|
+
const heading = Paragraph.createWithStyle("Chapter 1", "Heading1");
|
|
209
|
+
|
|
210
|
+
// Create with both run and paragraph formatting
|
|
211
|
+
const important = Paragraph.createFormatted(
|
|
212
|
+
"Important Text",
|
|
213
|
+
{ bold: true, color: "FF0000" },
|
|
214
|
+
{ alignment: "center" }
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// Add to document later
|
|
218
|
+
doc.addParagraph(para1);
|
|
219
|
+
doc.addParagraph(heading);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Paragraph Factory Methods
|
|
223
|
+
|
|
224
|
+
| Method | Description | Example |
|
|
225
|
+
| --------------------------------------------------- | --------------------------- | --------------------------------------- |
|
|
226
|
+
| `Paragraph.create(text?, formatting?)` | Create detached paragraph | `Paragraph.create('Text')` |
|
|
227
|
+
| `Paragraph.create(formatting?)` | Create with formatting only | `Paragraph.create({alignment: 'left'})` |
|
|
228
|
+
| `Paragraph.createWithStyle(text, styleId)` | Create with style | `Paragraph.createWithStyle('', 'H1')` |
|
|
229
|
+
| `Paragraph.createEmpty()` | Create empty paragraph | `Paragraph.createEmpty()` |
|
|
230
|
+
| `Paragraph.createFormatted(text, run?, paragraph?)` | Create with dual formatting | See example above |
|
|
231
|
+
|
|
232
|
+
#### Paragraph Formatting Methods
|
|
233
|
+
|
|
234
|
+
| Method | Description | Values |
|
|
235
|
+
| ------------------------------ | ------------------- | ----------------------------------- |
|
|
236
|
+
| `setAlignment(align)` | Text alignment | `'left'/'center'/'right'/'justify'` |
|
|
237
|
+
| `setLeftIndent(twips)` | Left indentation | Twips value |
|
|
238
|
+
| `setRightIndent(twips)` | Right indentation | Twips value |
|
|
239
|
+
| `setFirstLineIndent(twips)` | First line indent | Twips value |
|
|
240
|
+
| `setSpaceBefore(twips)` | Space before | Twips value |
|
|
241
|
+
| `setSpaceAfter(twips)` | Space after | Twips value |
|
|
242
|
+
| `setLineSpacing(twips, rule?)` | Line spacing | Twips + rule |
|
|
243
|
+
| `setStyle(styleId)` | Apply style | Style ID |
|
|
244
|
+
| `setKeepNext()` | Keep with next | - |
|
|
245
|
+
| `setKeepLines()` | Keep lines together | - |
|
|
246
|
+
| `setPageBreakBefore()` | Page break before | - |
|
|
247
|
+
|
|
248
|
+
#### Paragraph Manipulation Methods
|
|
249
|
+
|
|
250
|
+
| Method | Description | Returns |
|
|
251
|
+
| -------------------------------------- | ----------------------- | ----------- |
|
|
252
|
+
| `insertRunAt(index, run)` | Insert run at position | `this` |
|
|
253
|
+
| `removeRunAt(index)` | Remove run at position | `boolean` |
|
|
254
|
+
| `replaceRunAt(index, run)` | Replace run at position | `boolean` |
|
|
255
|
+
| `findText(text, options?)` | Find text in runs | `number[]` |
|
|
256
|
+
| `replaceText(find, replace, options?)` | Replace text in runs | `number` |
|
|
257
|
+
| `mergeWith(otherPara)` | Merge another paragraph | `this` |
|
|
258
|
+
| `clone()` | Clone paragraph | `Paragraph` |
|
|
259
|
+
|
|
260
|
+
**Example:**
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
const para = doc.createParagraph("Hello World");
|
|
264
|
+
|
|
265
|
+
// Find and replace
|
|
266
|
+
const indices = para.findText("World"); // [1]
|
|
267
|
+
const count = para.replaceText("World", "Universe", { caseSensitive: true });
|
|
268
|
+
|
|
269
|
+
// Manipulate runs
|
|
270
|
+
para.insertRunAt(0, new Run("Start: ", { bold: true }));
|
|
271
|
+
para.replaceRunAt(1, new Run("HELLO", { allCaps: true }));
|
|
272
|
+
|
|
273
|
+
// Merge paragraphs
|
|
274
|
+
const para2 = Paragraph.create(" More text");
|
|
275
|
+
para.mergeWith(para2); // Combines runs
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Run (Text Span) Operations
|
|
279
|
+
|
|
280
|
+
| Method | Description | Returns |
|
|
281
|
+
| ------------------------------- | ------------------------- | ------- |
|
|
282
|
+
| `clone()` | Clone run with formatting | `Run` |
|
|
283
|
+
| `insertText(index, text)` | Insert text at position | `this` |
|
|
284
|
+
| `appendText(text)` | Append text to end | `this` |
|
|
285
|
+
| `replaceText(start, end, text)` | Replace text range | `this` |
|
|
286
|
+
|
|
287
|
+
**Example:**
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
const run = new Run("Hello World", { bold: true });
|
|
291
|
+
|
|
292
|
+
// Text manipulation
|
|
293
|
+
run.insertText(6, "Beautiful "); // "Hello Beautiful World"
|
|
294
|
+
run.appendText("!"); // "Hello Beautiful World!"
|
|
295
|
+
run.replaceText(0, 5, "Hi"); // "Hi Beautiful World!"
|
|
296
|
+
|
|
297
|
+
// Clone for reuse
|
|
298
|
+
const copy = run.clone();
|
|
299
|
+
copy.setColor("FF0000"); // Original unchanged
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Table Operations
|
|
303
|
+
|
|
304
|
+
| Method | Description | Example |
|
|
305
|
+
| ----------------------- | -------------------- | ---------------------------------------- |
|
|
306
|
+
| `getRow(index)` | Get table row | `table.getRow(0)` |
|
|
307
|
+
| `getCell(row, col)` | Get table cell | `table.getCell(0, 1)` |
|
|
308
|
+
| `addRow()` | Add new row | `table.addRow()` |
|
|
309
|
+
| `removeRow(index)` | Remove row | `table.removeRow(2)` |
|
|
310
|
+
| `insertColumn(index)` | Insert column | `table.insertColumn(1)` |
|
|
311
|
+
| `removeColumn(index)` | Remove column | `table.removeColumn(3)` |
|
|
312
|
+
| `setWidth(twips)` | Set table width | `table.setWidth(8640)` |
|
|
313
|
+
| `setAlignment(align)` | Table alignment | `table.setAlignment('center')` |
|
|
314
|
+
| `setAllBorders(border)` | Set all borders | `table.setAllBorders({style: 'single'})` |
|
|
315
|
+
| `setBorders(borders)` | Set specific borders | `table.setBorders({top: {...}})` |
|
|
316
|
+
|
|
317
|
+
#### Advanced Table Operations
|
|
318
|
+
|
|
319
|
+
| Method | Description | Returns |
|
|
320
|
+
| ------------------------------------------------ | ------------------------- | ------------ |
|
|
321
|
+
| `mergeCells(startRow, startCol, endRow, endCol)` | Merge cells | `this` |
|
|
322
|
+
| `splitCell(row, col)` | Remove cell spanning | `this` |
|
|
323
|
+
| `moveCell(fromRow, fromCol, toRow, toCol)` | Move cell contents | `this` |
|
|
324
|
+
| `swapCells(row1, col1, row2, col2)` | Swap two cells | `this` |
|
|
325
|
+
| `setColumnWidth(index, width)` | Set specific column width | `this` |
|
|
326
|
+
| `setColumnWidths(widths)` | Set all column widths | `this` |
|
|
327
|
+
| `insertRows(startIndex, count)` | Insert multiple rows | `TableRow[]` |
|
|
328
|
+
| `removeRows(startIndex, count)` | Remove multiple rows | `boolean` |
|
|
329
|
+
| `clone()` | Clone entire table | `Table` |
|
|
330
|
+
|
|
331
|
+
**Example:**
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const table = doc.createTable(3, 3);
|
|
335
|
+
|
|
336
|
+
// Merge cells horizontally (row 0, columns 0-2)
|
|
337
|
+
table.mergeCells(0, 0, 0, 2);
|
|
338
|
+
|
|
339
|
+
// Move cell contents
|
|
340
|
+
table.moveCell(1, 1, 2, 2);
|
|
341
|
+
|
|
342
|
+
// Swap cells
|
|
343
|
+
table.swapCells(0, 0, 2, 2);
|
|
344
|
+
|
|
345
|
+
// Batch row operations
|
|
346
|
+
table.insertRows(1, 3); // Insert 3 rows at position 1
|
|
347
|
+
table.removeRows(4, 2); // Remove 2 rows starting at position 4
|
|
348
|
+
|
|
349
|
+
// Set column widths
|
|
350
|
+
table.setColumnWidth(0, 2000); // First column = 2000 twips
|
|
351
|
+
table.setColumnWidths([2000, 3000, 2000]); // All columns
|
|
352
|
+
|
|
353
|
+
// Clone table for reuse
|
|
354
|
+
const tableCopy = table.clone();
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Table Cell Operations
|
|
358
|
+
|
|
359
|
+
| Method | Description | Example |
|
|
360
|
+
| ----------------------------- | --------------------- | ------------------------------------- |
|
|
361
|
+
| `createParagraph(text?)` | Add paragraph to cell | `cell.createParagraph('Text')` |
|
|
362
|
+
| `setShading(shading)` | Cell background | `cell.setShading({fill: 'E0E0E0'})` |
|
|
363
|
+
| `setVerticalAlignment(align)` | Vertical align | `cell.setVerticalAlignment('center')` |
|
|
364
|
+
| `setColumnSpan(cols)` | Merge columns | `cell.setColumnSpan(3)` |
|
|
365
|
+
| `setRowSpan(rows)` | Merge rows | `cell.setRowSpan(2)` |
|
|
366
|
+
| `setBorders(borders)` | Cell borders | `cell.setBorders({top: {...}})` |
|
|
367
|
+
| `setWidth(width, type?)` | Cell width | `cell.setWidth(2000, 'dxa')` |
|
|
368
|
+
|
|
369
|
+
### Style Management
|
|
370
|
+
|
|
371
|
+
| Method | Description | Example |
|
|
372
|
+
| ----------------------------- | ------------------ | ---------------------------------- |
|
|
373
|
+
| `addStyle(style)` | Add custom style | `doc.addStyle(myStyle)` |
|
|
374
|
+
| `getStyle(styleId)` | Get style by ID | `doc.getStyle('Heading1')` |
|
|
375
|
+
| `hasStyle(styleId)` | Check style exists | `doc.hasStyle('CustomStyle')` |
|
|
376
|
+
| `getStyles()` | Get all styles | `doc.getStyles()` |
|
|
377
|
+
| `removeStyle(styleId)` | Remove style | `doc.removeStyle('OldStyle')` |
|
|
378
|
+
| `updateStyle(styleId, props)` | Update style | `doc.updateStyle('Normal', {...})` |
|
|
379
|
+
|
|
380
|
+
#### Style Manipulation
|
|
381
|
+
|
|
382
|
+
| Method | Description | Returns |
|
|
383
|
+
| ------------------------ | ----------------------------------- | ------- |
|
|
384
|
+
| `style.clone()` | Clone style | `Style` |
|
|
385
|
+
| `style.mergeWith(other)` | Merge properties from another style | `this` |
|
|
386
|
+
|
|
387
|
+
**Example:**
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
// Clone a style
|
|
391
|
+
const heading1 = doc.getStyle("Heading1");
|
|
392
|
+
const customHeading = heading1.clone();
|
|
393
|
+
customHeading.setRunFormatting({ color: "FF0000" });
|
|
394
|
+
|
|
395
|
+
// Merge styles
|
|
396
|
+
const baseStyle = Style.createNormalStyle();
|
|
397
|
+
const overrideStyle = Style.create({
|
|
398
|
+
styleId: "Override",
|
|
399
|
+
name: "Override",
|
|
400
|
+
type: "paragraph",
|
|
401
|
+
runFormatting: { bold: true, color: "FF0000" },
|
|
402
|
+
});
|
|
403
|
+
baseStyle.mergeWith(overrideStyle); // baseStyle now has bold red text
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
#### Built-in Styles
|
|
407
|
+
|
|
408
|
+
- `Normal` - Default paragraph
|
|
409
|
+
- `Title` - Document title
|
|
410
|
+
- `Subtitle` - Document subtitle
|
|
411
|
+
- `Heading1` through `Heading9` - Section headings
|
|
412
|
+
- `ListParagraph` - List items
|
|
413
|
+
|
|
414
|
+
### List Management
|
|
415
|
+
|
|
416
|
+
| Method | Description | Returns |
|
|
417
|
+
| --------------------------------------- | ----------------------- | ------- |
|
|
418
|
+
| `createBulletList(levels?, bullets?)` | Create bullet list | `numId` |
|
|
419
|
+
| `createNumberedList(levels?, formats?)` | Create numbered list | `numId` |
|
|
420
|
+
| `createMultiLevelList()` | Create multi-level list | `numId` |
|
|
421
|
+
|
|
422
|
+
### Table of Contents (TOC)
|
|
423
|
+
|
|
424
|
+
#### Basic TOC Creation
|
|
425
|
+
|
|
426
|
+
| Method | Description | Example |
|
|
427
|
+
| -------------------------- | ---------------------- | -------------------------- |
|
|
428
|
+
| `addTableOfContents(toc?)` | Add TOC to document | `doc.addTableOfContents()` |
|
|
429
|
+
| `insertTocAt(index, toc)` | Insert TOC at position | `doc.insertTocAt(0, toc)` |
|
|
430
|
+
| `removeTocAt(index)` | Remove TOC at position | `doc.removeTocAt(0)` |
|
|
431
|
+
|
|
432
|
+
#### TOC Factory Methods
|
|
433
|
+
|
|
434
|
+
| Method | Description | Example |
|
|
435
|
+
| -------------------------------------------------------- | ------------------------ | ---------------------------------------------------- |
|
|
436
|
+
| `TableOfContents.createStandard(title?)` | Standard TOC (3 levels) | `TableOfContents.createStandard()` |
|
|
437
|
+
| `TableOfContents.createSimple(title?)` | Simple TOC (2 levels) | `TableOfContents.createSimple()` |
|
|
438
|
+
| `TableOfContents.createDetailed(title?)` | Detailed TOC (4 levels) | `TableOfContents.createDetailed()` |
|
|
439
|
+
| `TableOfContents.createHyperlinked(title?)` | Hyperlinked TOC | `TableOfContents.createHyperlinked()` |
|
|
440
|
+
| `TableOfContents.createWithStyles(styles, opts?)` | TOC with specific styles | `TableOfContents.createWithStyles(['H1','H3'])` |
|
|
441
|
+
| `TableOfContents.createFlat(title?, styles?)` | Flat TOC (no indent) | `TableOfContents.createFlat()` |
|
|
442
|
+
| `TableOfContents.createNumbered(title?, format?)` | Numbered TOC | `TableOfContents.createNumbered('TOC', 'roman')` |
|
|
443
|
+
| `TableOfContents.createWithSpacing(spacing, opts?)` | TOC with custom spacing | `TableOfContents.createWithSpacing(120)` |
|
|
444
|
+
| `TableOfContents.createWithHyperlinkColor(color, opts?)` | Custom hyperlink color | `TableOfContents.createWithHyperlinkColor('FF0000')` |
|
|
445
|
+
|
|
446
|
+
#### TOC Configuration Methods
|
|
447
|
+
|
|
448
|
+
| Method | Description | Values |
|
|
449
|
+
| --------------------------------- | ------------------------------ | -------------------------- |
|
|
450
|
+
| `setIncludeStyles(styles)` | Select specific heading styles | `['Heading1', 'Heading3']` |
|
|
451
|
+
| `setNumbered(numbered, format?)` | Enable/disable numbering | `(true, 'roman')` |
|
|
452
|
+
| `setNoIndent(noIndent)` | Remove indentation | `true/false` |
|
|
453
|
+
| `setCustomIndents(indents)` | Custom indents per level | `[0, 200, 400]` (twips) |
|
|
454
|
+
| `setSpaceBetweenEntries(spacing)` | Spacing between entries | `120` (twips) |
|
|
455
|
+
| `setHyperlinkColor(color)` | Hyperlink color | `'0000FF'` (default blue) |
|
|
456
|
+
| `configure(options)` | Bulk configuration | See example below |
|
|
457
|
+
|
|
458
|
+
#### TOC Properties
|
|
459
|
+
|
|
460
|
+
| Property | Type | Default | Description |
|
|
461
|
+
| --------------------- | ------------------------------------ | --------------------- | ---------------------------------- |
|
|
462
|
+
| `title` | `string` | `'Table of Contents'` | TOC title |
|
|
463
|
+
| `levels` | `number` (1-9) | `3` | Heading levels to include |
|
|
464
|
+
| `includeStyles` | `string[]` | `undefined` | Specific styles (overrides levels) |
|
|
465
|
+
| `showPageNumbers` | `boolean` | `true` | Show page numbers |
|
|
466
|
+
| `useHyperlinks` | `boolean` | `false` | Use hyperlinks instead of page #s |
|
|
467
|
+
| `numbered` | `boolean` | `false` | Number TOC entries |
|
|
468
|
+
| `numberingFormat` | `'decimal'/'roman'/'alpha'` | `'decimal'` | Numbering format |
|
|
469
|
+
| `noIndent` | `boolean` | `false` | Remove all indentation |
|
|
470
|
+
| `customIndents` | `number[]` | `undefined` | Custom indents in twips |
|
|
471
|
+
| `spaceBetweenEntries` | `number` | `0` | Spacing in twips |
|
|
472
|
+
| `hyperlinkColor` | `string` | `'0000FF'` | Hyperlink color (hex without #) |
|
|
473
|
+
| `tabLeader` | `'dot'/'hyphen'/'underscore'/'none'` | `'dot'` | Tab leader character |
|
|
474
|
+
|
|
475
|
+
**Example:**
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
// Basic TOC
|
|
479
|
+
const simpleToc = TableOfContents.createStandard();
|
|
480
|
+
doc.addTableOfContents(simpleToc);
|
|
481
|
+
|
|
482
|
+
// Select specific styles (e.g., only Heading1 and Heading3)
|
|
483
|
+
const customToc = TableOfContents.createWithStyles(["Heading1", "Heading3"]);
|
|
484
|
+
|
|
485
|
+
// Flat TOC with no indentation
|
|
486
|
+
const flatToc = TableOfContents.createFlat("Contents");
|
|
487
|
+
|
|
488
|
+
// Numbered TOC with roman numerals
|
|
489
|
+
const numberedToc = TableOfContents.createNumbered(
|
|
490
|
+
"Table of Contents",
|
|
491
|
+
"roman"
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
// Custom hyperlink color (red instead of blue)
|
|
495
|
+
const coloredToc = TableOfContents.createWithHyperlinkColor("FF0000");
|
|
496
|
+
|
|
497
|
+
// Advanced configuration
|
|
498
|
+
const toc = TableOfContents.create()
|
|
499
|
+
.setIncludeStyles(["Heading1", "Heading2", "Heading3"])
|
|
500
|
+
.setNumbered(true, "decimal")
|
|
501
|
+
.setSpaceBetweenEntries(120) // 6pt spacing
|
|
502
|
+
.setHyperlinkColor("0000FF")
|
|
503
|
+
.setNoIndent(false);
|
|
504
|
+
|
|
505
|
+
// Or use configure() for bulk settings
|
|
506
|
+
toc.configure({
|
|
507
|
+
title: "Table of Contents",
|
|
508
|
+
includeStyles: ["Heading1", "CustomHeader"],
|
|
509
|
+
numbered: true,
|
|
510
|
+
numberingFormat: "alpha",
|
|
511
|
+
spaceBetweenEntries: 100,
|
|
512
|
+
hyperlinkColor: "FF0000",
|
|
513
|
+
noIndent: true,
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Insert at specific position
|
|
517
|
+
doc.insertTocAt(0, toc);
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Image Handling
|
|
521
|
+
|
|
522
|
+
| Method | Description | Example |
|
|
523
|
+
| --------------------------------------- | ------------------ | -------------------------------- |
|
|
524
|
+
| `Image.fromFile(path, width?, height?)` | Load from file | `Image.fromFile('pic.jpg')` |
|
|
525
|
+
| `Image.fromBuffer(buffer, ext, w?, h?)` | Load from buffer | `Image.fromBuffer(buf, 'png')` |
|
|
526
|
+
| `setWidth(emus, maintainRatio?)` | Set width | `img.setWidth(inchesToEmus(3))` |
|
|
527
|
+
| `setHeight(emus, maintainRatio?)` | Set height | `img.setHeight(inchesToEmus(2))` |
|
|
528
|
+
| `setSize(width, height)` | Set dimensions | `img.setSize(w, h)` |
|
|
529
|
+
| `setRotation(degrees)` | Rotate image | `img.setRotation(90)` |
|
|
530
|
+
| `setAltText(text)` | Accessibility text | `img.setAltText('Description')` |
|
|
531
|
+
|
|
532
|
+
### Hyperlinks
|
|
533
|
+
|
|
534
|
+
#### Creating Hyperlinks
|
|
535
|
+
|
|
536
|
+
| Method | Description | Example |
|
|
537
|
+
| ------------------------------------------------- | ---------------- | ---------------------------------------------------------- |
|
|
538
|
+
| `Hyperlink.createExternal(url, text, format?)` | Web link | `Hyperlink.createExternal('https://example.com', 'Click')` |
|
|
539
|
+
| `Hyperlink.createEmail(email, text?, format?)` | Email link | `Hyperlink.createEmail('user@example.com')` |
|
|
540
|
+
| `Hyperlink.createInternal(anchor, text, format?)` | Internal link | `Hyperlink.createInternal('Section1', 'Go to')` |
|
|
541
|
+
| `para.addHyperlink(hyperlink)` | Add to paragraph | `para.addHyperlink(link)` |
|
|
542
|
+
|
|
543
|
+
#### Hyperlink Defragmentation (v1.15.0+)
|
|
544
|
+
|
|
545
|
+
Fix fragmented hyperlinks caused by Google Docs imports or formatting changes:
|
|
546
|
+
|
|
547
|
+
| Method | Description | Example |
|
|
548
|
+
| ------------------------------------------ | ------------------------------------ | -------------------------------------------------- |
|
|
549
|
+
| `doc.defragmentHyperlinks(options?)` | Merge fragmented hyperlinks by URL | `doc.defragmentHyperlinks({ resetFormatting: true })` |
|
|
550
|
+
| `hyperlink.resetToStandardFormatting()` | Reset to standard blue underlined | `hyperlink.resetToStandardFormatting()` |
|
|
551
|
+
|
|
552
|
+
**Options:**
|
|
553
|
+
- `resetFormatting?: boolean` - Reset hyperlinks to standard style (Calibri, blue, underline)
|
|
554
|
+
- `cleanupRelationships?: boolean` - Remove orphaned relationship entries
|
|
555
|
+
|
|
556
|
+
**Example:**
|
|
557
|
+
```typescript
|
|
558
|
+
// Load document with fragmented hyperlinks from Google Docs
|
|
559
|
+
const doc = await Document.load('google-docs-export.docx');
|
|
560
|
+
|
|
561
|
+
// Fix fragmented hyperlinks and reset corrupted formatting
|
|
562
|
+
doc.defragmentHyperlinks({
|
|
563
|
+
resetFormatting: true, // Fix Caveat font and other issues
|
|
564
|
+
cleanupRelationships: true // Clean up relationship table
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// Save cleaned document
|
|
568
|
+
await doc.save('fixed.docx');
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Headers & Footers
|
|
572
|
+
|
|
573
|
+
| Method | Description | Example |
|
|
574
|
+
| ---------------------------- | ------------------ | -------------------------------- |
|
|
575
|
+
| `setHeader(header)` | Set default header | `doc.setHeader(myHeader)` |
|
|
576
|
+
| `setFooter(footer)` | Set default footer | `doc.setFooter(myFooter)` |
|
|
577
|
+
| `setFirstPageHeader(header)` | First page header | `doc.setFirstPageHeader(header)` |
|
|
578
|
+
| `setFirstPageFooter(footer)` | First page footer | `doc.setFirstPageFooter(footer)` |
|
|
579
|
+
| `setEvenPageHeader(header)` | Even page header | `doc.setEvenPageHeader(header)` |
|
|
580
|
+
| `setEvenPageFooter(footer)` | Even page footer | `doc.setEvenPageFooter(footer)` |
|
|
581
|
+
|
|
582
|
+
### Page Setup
|
|
583
|
+
|
|
584
|
+
| Method | Description | Example |
|
|
585
|
+
| ------------------------------------- | ----------------- | ------------------------------------- |
|
|
586
|
+
| `setPageSize(width, height, orient?)` | Page dimensions | `doc.setPageSize(12240, 15840)` |
|
|
587
|
+
| `setPageOrientation(orientation)` | Page orientation | `doc.setPageOrientation('landscape')` |
|
|
588
|
+
| `setMargins(margins)` | Page margins | `doc.setMargins({top: 1440, ...})` |
|
|
589
|
+
| `setLanguage(language)` | Document language | `doc.setLanguage('en-US')` |
|
|
590
|
+
|
|
591
|
+
### Document Properties
|
|
592
|
+
|
|
593
|
+
| Method | Description | Properties |
|
|
594
|
+
| ---------------------- | ------------ | ------------------------------------- |
|
|
595
|
+
| `setProperties(props)` | Set metadata | `{title, subject, creator, keywords}` |
|
|
596
|
+
| `getProperties()` | Get metadata | Returns all properties |
|
|
597
|
+
|
|
598
|
+
### Advanced Features
|
|
599
|
+
|
|
600
|
+
#### Bookmarks
|
|
601
|
+
|
|
602
|
+
| Method | Description |
|
|
603
|
+
| ---------------------------------------- | ------------------- |
|
|
604
|
+
| `createBookmark(name)` | Create bookmark |
|
|
605
|
+
| `createHeadingBookmark(text)` | Auto-named bookmark |
|
|
606
|
+
| `getBookmark(name)` | Get by name |
|
|
607
|
+
| `hasBookmark(name)` | Check existence |
|
|
608
|
+
| `addBookmarkToParagraph(para, bookmark)` | Add to paragraph |
|
|
609
|
+
|
|
610
|
+
#### Comments
|
|
611
|
+
|
|
612
|
+
| Method | Description |
|
|
613
|
+
| ------------------------------------------- | ----------------- |
|
|
614
|
+
| `createComment(author, content, initials?)` | Add comment |
|
|
615
|
+
| `createReply(parentId, author, content)` | Reply to comment |
|
|
616
|
+
| `getComment(id)` | Get by ID |
|
|
617
|
+
| `getAllComments()` | Get all top-level |
|
|
618
|
+
| `addCommentToParagraph(para, comment)` | Add to paragraph |
|
|
619
|
+
|
|
620
|
+
#### Track Changes
|
|
621
|
+
|
|
622
|
+
| Method | Description |
|
|
623
|
+
| ------------------------------------ | ----------------- |
|
|
624
|
+
| `trackInsertion(para, author, text)` | Track insertion |
|
|
625
|
+
| `trackDeletion(para, author, text)` | Track deletion |
|
|
626
|
+
| `isTrackingChanges()` | Check if tracking |
|
|
627
|
+
| `getRevisionStats()` | Get statistics |
|
|
628
|
+
|
|
629
|
+
#### Footnotes & Endnotes
|
|
630
|
+
|
|
631
|
+
| Method | Description |
|
|
632
|
+
| -------------------------- | ---------------- |
|
|
633
|
+
| `FootnoteManager.create()` | Manage footnotes |
|
|
634
|
+
| `EndnoteManager.create()` | Manage endnotes |
|
|
635
|
+
|
|
636
|
+
### Low-Level Document Parts
|
|
637
|
+
|
|
638
|
+
| Method | Description | Example |
|
|
639
|
+
| ---------------------------- | --------------------- | ------------------------------------------------- |
|
|
640
|
+
| `getPart(partName)` | Get document part | `doc.getPart('word/document.xml')` |
|
|
641
|
+
| `setPart(partName, content)` | Set document part | `doc.setPart('custom.xml', data)` |
|
|
642
|
+
| `removePart(partName)` | Remove part | `doc.removePart('custom.xml')` |
|
|
643
|
+
| `listParts()` | List all parts | `const parts = await doc.listParts()` |
|
|
644
|
+
| `partExists(partName)` | Check part exists | `if (await doc.partExists('...'))` |
|
|
645
|
+
| `getContentTypes()` | Get content types | `const types = await doc.getContentTypes()` |
|
|
646
|
+
| `addContentType(part, type)` | Register content type | `doc.addContentType('.json', 'application/json')` |
|
|
647
|
+
|
|
648
|
+
### Unit Conversion Utilities
|
|
649
|
+
|
|
650
|
+
#### Twips Conversions
|
|
651
|
+
| Function | Description | Example |
|
|
652
|
+
| ------------------------- | ------------------- | --------------------------- |
|
|
653
|
+
| `twipsToPoints(twips)` | Twips to points | `twipsToPoints(240)` // 12 |
|
|
654
|
+
| `twipsToInches(twips)` | Twips to inches | `twipsToInches(1440)` // 1 |
|
|
655
|
+
| `twipsToCm(twips)` | Twips to cm | `twipsToCm(1440)` // 2.54 |
|
|
656
|
+
| `twipsToEmus(twips)` | Twips to EMUs | `twipsToEmus(1440)` |
|
|
657
|
+
|
|
658
|
+
#### EMUs (English Metric Units) Conversions
|
|
659
|
+
| Function | Description | Example |
|
|
660
|
+
| --------------------------- | -------------------- | ----------------------------- |
|
|
661
|
+
| `emusToTwips(emus)` | EMUs to twips | `emusToTwips(914400)` // 1440 |
|
|
662
|
+
| `emusToInches(emus)` | EMUs to inches | `emusToInches(914400)` // 1 |
|
|
663
|
+
| `emusToCm(emus)` | EMUs to cm | `emusToCm(914400)` // 2.54 |
|
|
664
|
+
| `emusToPoints(emus)` | EMUs to points | `emusToPoints(914400)` // 72 |
|
|
665
|
+
| `emusToPixels(emus, dpi?)` | EMUs to pixels | `emusToPixels(914400)` // 96 |
|
|
666
|
+
|
|
667
|
+
#### Points Conversions
|
|
668
|
+
| Function | Description | Example |
|
|
669
|
+
| ------------------------ | ------------------ | -------------------------- |
|
|
670
|
+
| `pointsToTwips(points)` | Points to twips | `pointsToTwips(12)` // 240 |
|
|
671
|
+
| `pointsToEmus(points)` | Points to EMUs | `pointsToEmus(72)` |
|
|
672
|
+
| `pointsToInches(points)` | Points to inches | `pointsToInches(72)` // 1 |
|
|
673
|
+
| `pointsToCm(points)` | Points to cm | `pointsToCm(72)` // 2.54 |
|
|
674
|
+
|
|
675
|
+
#### Inches Conversions
|
|
676
|
+
| Function | Description | Example |
|
|
677
|
+
| ----------------------------- | ------------------- | ----------------------------- |
|
|
678
|
+
| `inchesToTwips(inches)` | Inches to twips | `inchesToTwips(1)` // 1440 |
|
|
679
|
+
| `inchesToEmus(inches)` | Inches to EMUs | `inchesToEmus(1)` // 914400 |
|
|
680
|
+
| `inchesToPoints(inches)` | Inches to points | `inchesToPoints(1)` // 72 |
|
|
681
|
+
| `inchesToCm(inches)` | Inches to cm | `inchesToCm(1)` // 2.54 |
|
|
682
|
+
| `inchesToPixels(inches, dpi)` | Inches to pixels | `inchesToPixels(1, 96)` // 96 |
|
|
683
|
+
|
|
684
|
+
#### Centimeters Conversions
|
|
685
|
+
| Function | Description | Example |
|
|
686
|
+
| ----------------------- | ---------------- | --------------------------- |
|
|
687
|
+
| `cmToTwips(cm)` | cm to twips | `cmToTwips(2.54)` // 1440 |
|
|
688
|
+
| `cmToEmus(cm)` | cm to EMUs | `cmToEmus(2.54)` // 914400 |
|
|
689
|
+
| `cmToInches(cm)` | cm to inches | `cmToInches(2.54)` // 1 |
|
|
690
|
+
| `cmToPoints(cm)` | cm to points | `cmToPoints(2.54)` // 72 |
|
|
691
|
+
| `cmToPixels(cm, dpi?)` | cm to pixels | `cmToPixels(2.54, 96)` // 96|
|
|
692
|
+
|
|
693
|
+
#### Pixels Conversions
|
|
694
|
+
| Function | Description | Example |
|
|
695
|
+
| ---------------------------- | ------------------- | ------------------------------ |
|
|
696
|
+
| `pixelsToEmus(pixels, dpi?)` | Pixels to EMUs | `pixelsToEmus(96)` // 914400 |
|
|
697
|
+
| `pixelsToInches(pixels, dpi?)`| Pixels to inches | `pixelsToInches(96, 96)` // 1 |
|
|
698
|
+
| `pixelsToTwips(pixels, dpi?)`| Pixels to twips | `pixelsToTwips(96, 96)` // 1440|
|
|
699
|
+
| `pixelsToCm(pixels, dpi?)` | Pixels to cm | `pixelsToCm(96, 96)` // 2.54 |
|
|
700
|
+
| `pixelsToPoints(pixels, dpi?)`| Pixels to points | `pixelsToPoints(96, 96)` // 72 |
|
|
701
|
+
|
|
702
|
+
**Note:** Default DPI is 96 for pixel conversions
|
|
703
|
+
|
|
704
|
+
### ZIP Archive Helper Methods
|
|
705
|
+
|
|
706
|
+
#### File Operations
|
|
707
|
+
| Method | Description | Example |
|
|
708
|
+
| ------------------------------- | ------------------------- | -------------------------------------------- |
|
|
709
|
+
| `addFile(path, content)` | Add file to archive | `handler.addFile('doc.xml', xmlContent)` |
|
|
710
|
+
| `updateFile(path, content)` | Update existing file | `handler.updateFile('doc.xml', newContent)` |
|
|
711
|
+
| `removeFile(path)` | Remove file from archive | `handler.removeFile('old.xml')` |
|
|
712
|
+
| `renameFile(oldPath, newPath)` | Rename file | `handler.renameFile('a.xml', 'b.xml')` |
|
|
713
|
+
| `copyFile(srcPath, destPath)` | Copy file | `handler.copyFile('a.xml', 'copy-a.xml')` |
|
|
714
|
+
| `moveFile(srcPath, destPath)` | Move file | `handler.moveFile('a.xml', 'folder/a.xml')` |
|
|
715
|
+
|
|
716
|
+
#### File Retrieval
|
|
717
|
+
| Method | Description | Returns |
|
|
718
|
+
| ------------------------- | ---------------------- | --------------- |
|
|
719
|
+
| `getFile(path)` | Get file object | `ZipFile` |
|
|
720
|
+
| `getFileAsString(path)` | Get file as string | `string` |
|
|
721
|
+
| `getFileAsBuffer(path)` | Get file as buffer | `Buffer` |
|
|
722
|
+
| `hasFile(path)` | Check if file exists | `boolean` |
|
|
723
|
+
| `getFilePaths()` | Get all file paths | `string[]` |
|
|
724
|
+
| `getAllFiles()` | Get all files | `FileMap` |
|
|
725
|
+
|
|
726
|
+
#### Batch Operations
|
|
727
|
+
| Method | Description | Returns |
|
|
728
|
+
| ------------------------------- | ---------------------------- | -------------- |
|
|
729
|
+
| `removeFiles(paths[])` | Remove multiple files | `number` |
|
|
730
|
+
| `getFilesByExtension(ext)` | Get files by extension | `ZipFile[]` |
|
|
731
|
+
| `getTextFiles()` | Get all text files | `ZipFile[]` |
|
|
732
|
+
| `getBinaryFiles()` | Get all binary files | `ZipFile[]` |
|
|
733
|
+
| `getMediaFiles()` | Get media files | `ZipFile[]` |
|
|
734
|
+
|
|
735
|
+
#### Archive Information
|
|
736
|
+
| Method | Description | Returns |
|
|
737
|
+
| ------------------ | ------------------------- | ------------------------ |
|
|
738
|
+
| `getFileCount()` | Count files in archive | `number` |
|
|
739
|
+
| `getTotalSize()` | Get total size in bytes | `number` |
|
|
740
|
+
| `getStats()` | Get detailed statistics | `{fileCount, size, ...}` |
|
|
741
|
+
| `isEmpty()` | Check if archive is empty | `boolean` |
|
|
742
|
+
|
|
743
|
+
#### Import/Export
|
|
744
|
+
| Method | Description | Returns |
|
|
745
|
+
| -------------------------------- | ------------------------ | -------------------- |
|
|
746
|
+
| `exportFile(internal, external)` | Export file from archive | `Promise<void>` |
|
|
747
|
+
| `importFile(external, internal)` | Import file to archive | `Promise<void>` |
|
|
748
|
+
|
|
749
|
+
## Common Recipes
|
|
750
|
+
|
|
751
|
+
### Create a Simple Document
|
|
752
|
+
|
|
753
|
+
```typescript
|
|
754
|
+
const doc = Document.create();
|
|
755
|
+
doc.createParagraph("Title").setStyle("Title");
|
|
756
|
+
doc.createParagraph("This is a simple document.");
|
|
757
|
+
await doc.save("simple.docx");
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### Add Formatted Text
|
|
761
|
+
|
|
762
|
+
```typescript
|
|
763
|
+
const para = doc.createParagraph();
|
|
764
|
+
para.addText("Bold", { bold: true });
|
|
765
|
+
para.addText(" and ");
|
|
766
|
+
para.addText("Colored", { color: "FF0000" });
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### Create a Table with Borders
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
const table = doc.createTable(3, 3);
|
|
773
|
+
table.setAllBorders({ style: "single", size: 8, color: "000000" });
|
|
774
|
+
table.getCell(0, 0)?.createParagraph("Header 1");
|
|
775
|
+
table.getRow(0)?.getCell(0)?.setShading({ fill: "4472C4" });
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
### Insert an Image
|
|
779
|
+
|
|
780
|
+
```typescript
|
|
781
|
+
import { Image, inchesToEmus } from "docxmlater";
|
|
782
|
+
|
|
783
|
+
const image = Image.fromFile("./photo.jpg");
|
|
784
|
+
image.setWidth(inchesToEmus(4), true); // 4 inches, maintain ratio
|
|
785
|
+
doc.addImage(image);
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
### Add a Hyperlink
|
|
789
|
+
|
|
790
|
+
```typescript
|
|
791
|
+
const para = doc.createParagraph();
|
|
792
|
+
para.addText("Visit ");
|
|
793
|
+
para.addHyperlink(
|
|
794
|
+
Hyperlink.createExternal("https://example.com", "our website")
|
|
795
|
+
);
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### Search and Replace Text
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
// Find all occurrences
|
|
802
|
+
const results = doc.findText("old text", { caseSensitive: true });
|
|
803
|
+
console.log(`Found ${results.length} occurrences`);
|
|
804
|
+
|
|
805
|
+
// Replace all
|
|
806
|
+
const count = doc.replaceText("old text", "new text", { wholeWord: true });
|
|
807
|
+
console.log(`Replaced ${count} occurrences`);
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
### Load and Modify Existing Document
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
const doc = await Document.load("existing.docx");
|
|
814
|
+
doc.createParagraph("Added paragraph");
|
|
815
|
+
|
|
816
|
+
// Update all hyperlinks
|
|
817
|
+
const urlMap = new Map([["https://old-site.com", "https://new-site.com"]]);
|
|
818
|
+
doc.updateHyperlinkUrls(urlMap);
|
|
819
|
+
|
|
820
|
+
await doc.save("modified.docx");
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### Create Lists
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
// Bullet list
|
|
827
|
+
const bulletId = doc.createBulletList(3);
|
|
828
|
+
doc.createParagraph("First item").setNumbering(bulletId, 0);
|
|
829
|
+
doc.createParagraph("Second item").setNumbering(bulletId, 0);
|
|
830
|
+
|
|
831
|
+
// Numbered list
|
|
832
|
+
const numberId = doc.createNumberedList(3);
|
|
833
|
+
doc.createParagraph("Step 1").setNumbering(numberId, 0);
|
|
834
|
+
doc.createParagraph("Step 2").setNumbering(numberId, 0);
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Apply Custom Styles
|
|
838
|
+
|
|
839
|
+
```typescript
|
|
840
|
+
import { Style } from "docxmlater";
|
|
841
|
+
|
|
842
|
+
const customStyle = Style.create({
|
|
843
|
+
styleId: "CustomHeading",
|
|
844
|
+
name: "Custom Heading",
|
|
845
|
+
basedOn: "Normal",
|
|
846
|
+
runFormatting: { bold: true, size: 14, color: "2E74B5" },
|
|
847
|
+
paragraphFormatting: { alignment: "center", spaceAfter: 240 },
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
doc.addStyle(customStyle);
|
|
851
|
+
doc.createParagraph("Custom Styled Text").setStyle("CustomHeading");
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
### Build Content with Detached Paragraphs
|
|
855
|
+
|
|
856
|
+
Create paragraphs independently and add them conditionally:
|
|
857
|
+
|
|
858
|
+
```typescript
|
|
859
|
+
import { Paragraph } from "docxmlater";
|
|
860
|
+
|
|
861
|
+
// Create reusable paragraph templates
|
|
862
|
+
const warningTemplate = Paragraph.createFormatted(
|
|
863
|
+
"WARNING: ",
|
|
864
|
+
{ bold: true, color: "FF6600" },
|
|
865
|
+
{ spacing: { before: 120, after: 120 } }
|
|
866
|
+
);
|
|
867
|
+
|
|
868
|
+
// Clone and customize
|
|
869
|
+
const warning1 = warningTemplate.clone();
|
|
870
|
+
warning1.addText("Please read the documentation before proceeding.");
|
|
871
|
+
|
|
872
|
+
// Build content from data
|
|
873
|
+
const items = [
|
|
874
|
+
{ title: "First Item", description: "Description here" },
|
|
875
|
+
{ title: "Second Item", description: "Another description" },
|
|
876
|
+
];
|
|
877
|
+
|
|
878
|
+
items.forEach((item, index) => {
|
|
879
|
+
const titlePara = Paragraph.create(`${index + 1}. `);
|
|
880
|
+
titlePara.addText(item.title, { bold: true });
|
|
881
|
+
|
|
882
|
+
const descPara = Paragraph.create(item.description, {
|
|
883
|
+
indentation: { left: 360 },
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
doc.addParagraph(titlePara);
|
|
887
|
+
doc.addParagraph(descPara);
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
// See examples/advanced/detached-paragraphs.ts for more patterns
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
### Add Headers and Footers
|
|
894
|
+
|
|
895
|
+
```typescript
|
|
896
|
+
import { Header, Footer, Field } from "docxmlater";
|
|
897
|
+
|
|
898
|
+
// Header with page numbers
|
|
899
|
+
const header = Header.create();
|
|
900
|
+
header.addParagraph("Document Title").setAlignment("center");
|
|
901
|
+
|
|
902
|
+
// Footer with page numbers
|
|
903
|
+
const footer = Footer.create();
|
|
904
|
+
const footerPara = footer.addParagraph();
|
|
905
|
+
footerPara.addText("Page ");
|
|
906
|
+
footerPara.addField(Field.create({ type: "PAGE" }));
|
|
907
|
+
footerPara.addText(" of ");
|
|
908
|
+
footerPara.addField(Field.create({ type: "NUMPAGES" }));
|
|
909
|
+
|
|
910
|
+
doc.setHeader(header);
|
|
911
|
+
doc.setFooter(footer);
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
### Work with Document Statistics
|
|
915
|
+
|
|
916
|
+
```typescript
|
|
917
|
+
// Get word and character counts
|
|
918
|
+
console.log("Words:", doc.getWordCount());
|
|
919
|
+
console.log("Characters:", doc.getCharacterCount());
|
|
920
|
+
console.log("Characters (no spaces):", doc.getCharacterCount(false));
|
|
921
|
+
|
|
922
|
+
// Check document size
|
|
923
|
+
const size = doc.estimateSize();
|
|
924
|
+
if (size.warning) {
|
|
925
|
+
console.warn(size.warning);
|
|
926
|
+
}
|
|
927
|
+
console.log(`Estimated size: ${size.totalEstimatedMB} MB`);
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
### Handle Large Documents Efficiently
|
|
931
|
+
|
|
932
|
+
```typescript
|
|
933
|
+
const doc = Document.create({
|
|
934
|
+
maxMemoryUsagePercent: 80,
|
|
935
|
+
maxRssMB: 2048,
|
|
936
|
+
maxImageCount: 50,
|
|
937
|
+
maxTotalImageSizeMB: 100,
|
|
938
|
+
});
|
|
939
|
+
|
|
940
|
+
// Process document...
|
|
941
|
+
|
|
942
|
+
// Clean up resources after saving
|
|
943
|
+
await doc.save("large-document.docx");
|
|
944
|
+
doc.dispose(); // Free memory
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
### Direct XML Access (Advanced)
|
|
948
|
+
|
|
949
|
+
```typescript
|
|
950
|
+
// Get raw XML
|
|
951
|
+
const documentXml = await doc.getPart("word/document.xml");
|
|
952
|
+
console.log(documentXml?.content);
|
|
953
|
+
|
|
954
|
+
// Modify raw XML (use with caution)
|
|
955
|
+
await doc.setPart("word/custom.xml", "<custom>data</custom>");
|
|
956
|
+
await doc.addContentType("/word/custom.xml", "application/xml");
|
|
957
|
+
|
|
958
|
+
// List all parts
|
|
959
|
+
const parts = await doc.listParts();
|
|
960
|
+
console.log("Document contains:", parts.length, "parts");
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
### Fix Fragmented Hyperlinks from Google Docs
|
|
964
|
+
|
|
965
|
+
**Problem:** Documents exported from Google Docs often have fragmented hyperlinks where a single URL appears multiple times as separate hyperlinks, sometimes with corrupted fonts (e.g., Caveat instead of Calibri).
|
|
966
|
+
|
|
967
|
+
**Solution:** Use the hyperlink defragmentation API to automatically merge and fix these issues.
|
|
968
|
+
|
|
969
|
+
```typescript
|
|
970
|
+
import { Document } from "docxmlater";
|
|
971
|
+
|
|
972
|
+
async function fixGoogleDocsHyperlinks(inputPath: string, outputPath: string) {
|
|
973
|
+
// Load document
|
|
974
|
+
const doc = await Document.load(inputPath);
|
|
975
|
+
|
|
976
|
+
// Get hyperlinks before defragmentation
|
|
977
|
+
const hyperlinksBefore = doc.getHyperlinks();
|
|
978
|
+
console.log(`Found ${hyperlinksBefore.length} hyperlinks before defragmentation`);
|
|
979
|
+
|
|
980
|
+
// Defragment hyperlinks and reset formatting
|
|
981
|
+
doc.defragmentHyperlinks({
|
|
982
|
+
resetFormatting: true, // Fix corrupted fonts (Caveat → Calibri)
|
|
983
|
+
cleanupRelationships: true // Remove orphaned relationships
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
// Check results
|
|
987
|
+
const hyperlinksAfter = doc.getHyperlinks();
|
|
988
|
+
console.log(`Reduced to ${hyperlinksAfter.length} hyperlinks after defragmentation`);
|
|
989
|
+
console.log(`Merged ${hyperlinksBefore.length - hyperlinksAfter.length} duplicate hyperlinks`);
|
|
990
|
+
|
|
991
|
+
// Save fixed document
|
|
992
|
+
await doc.save(outputPath);
|
|
993
|
+
doc.dispose();
|
|
994
|
+
|
|
995
|
+
console.log(`✅ Fixed document saved to ${outputPath}`);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// Example usage
|
|
999
|
+
await fixGoogleDocsHyperlinks('input.docx', 'output.docx');
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
**What it fixes:**
|
|
1003
|
+
- Merges hyperlinks with the same URL across paragraphs and tables
|
|
1004
|
+
- Handles non-consecutive fragments (hyperlinks separated by other content)
|
|
1005
|
+
- Resets corrupted fonts to standard Calibri
|
|
1006
|
+
- Applies standard hyperlink style (blue, underlined)
|
|
1007
|
+
- Removes orphaned relationship entries
|
|
1008
|
+
|
|
1009
|
+
**Advanced usage - Manual control:**
|
|
1010
|
+
```typescript
|
|
1011
|
+
// Get all hyperlinks grouped by URL
|
|
1012
|
+
const hyperlinks = doc.getHyperlinks();
|
|
1013
|
+
const urlGroups = new Map<string, typeof hyperlinks>();
|
|
1014
|
+
|
|
1015
|
+
hyperlinks.forEach(({ hyperlink, paragraph }) => {
|
|
1016
|
+
const url = hyperlink.getUrl();
|
|
1017
|
+
if (!urlGroups.has(url)) {
|
|
1018
|
+
urlGroups.set(url, []);
|
|
1019
|
+
}
|
|
1020
|
+
urlGroups.get(url)!.push({ hyperlink, paragraph });
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Identify fragmented hyperlinks (URLs appearing multiple times)
|
|
1024
|
+
urlGroups.forEach((group, url) => {
|
|
1025
|
+
if (group.length > 1) {
|
|
1026
|
+
console.log(`URL "${url}" is fragmented into ${group.length} hyperlinks`);
|
|
1027
|
+
|
|
1028
|
+
// Manually reset formatting for each fragment
|
|
1029
|
+
group.forEach(({ hyperlink }) => {
|
|
1030
|
+
hyperlink.resetToStandardFormatting();
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
|
|
1035
|
+
await doc.save('manually-fixed.docx');
|
|
1036
|
+
```
|
|
1037
|
+
|
|
1038
|
+
## Features
|
|
1039
|
+
|
|
1040
|
+
- **Full OpenXML Compliance** - Follows ECMA-376 standard
|
|
1041
|
+
- **TypeScript First** - Complete type definitions
|
|
1042
|
+
- **Memory Efficient** - Handles large documents with streaming
|
|
1043
|
+
- **Atomic Saves** - Prevents corruption with temp file pattern
|
|
1044
|
+
- **Rich Formatting** - Complete text and paragraph formatting
|
|
1045
|
+
- **Tables** - Full support with borders, shading, merging
|
|
1046
|
+
- **Images** - PNG, JPEG, GIF with sizing and positioning
|
|
1047
|
+
- **Hyperlinks** - External, internal, and email links
|
|
1048
|
+
- **Hyperlink Defragmentation** - Fix fragmented hyperlinks from Google Docs imports (v1.15.0+)
|
|
1049
|
+
- **Styles** - 13 built-in styles + custom style creation
|
|
1050
|
+
- **Lists** - Bullets, numbering, multi-level with smart indentation
|
|
1051
|
+
- **Special Characters** - Tabs, newlines, non-breaking hyphens (v1.14.0+)
|
|
1052
|
+
- **Headers/Footers** - Different first/even/odd pages with dynamic fields
|
|
1053
|
+
- **Search & Replace** - With case and whole word options
|
|
1054
|
+
- **Document Stats** - Word count, character count, size estimation
|
|
1055
|
+
- **Track Changes** - Insertions and deletions with authors
|
|
1056
|
+
- **Comments** - With replies and threading
|
|
1057
|
+
- **Bookmarks** - For internal navigation
|
|
1058
|
+
- **Table of Contents** - Multiple TOC styles with customization
|
|
1059
|
+
- **Content Controls** - 9 control types for interactive documents
|
|
1060
|
+
- **Fields** - 11 field types including page numbers and cross-references
|
|
1061
|
+
- **Low-level Access** - Direct ZIP and XML manipulation
|
|
1062
|
+
|
|
1063
|
+
## Performance
|
|
1064
|
+
|
|
1065
|
+
- Process 100+ page documents efficiently
|
|
1066
|
+
- Atomic save pattern prevents corruption
|
|
1067
|
+
- Memory management for large files
|
|
1068
|
+
- Lazy loading of document parts
|
|
1069
|
+
- Resource cleanup with `dispose()`
|
|
1070
|
+
|
|
1071
|
+
## Testing
|
|
1072
|
+
|
|
1073
|
+
```bash
|
|
1074
|
+
npm test # Run all tests
|
|
1075
|
+
npm run test:watch # Watch mode
|
|
1076
|
+
npm run test:coverage # Coverage report
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1079
|
+
**Current:** 2,073 tests passing | 100% pass rate | 100% core functionality covered
|
|
1080
|
+
|
|
1081
|
+
## Development
|
|
1082
|
+
|
|
1083
|
+
```bash
|
|
1084
|
+
# Install dependencies
|
|
1085
|
+
npm install
|
|
1086
|
+
|
|
1087
|
+
# Build TypeScript
|
|
1088
|
+
npm run build
|
|
1089
|
+
|
|
1090
|
+
# Run examples
|
|
1091
|
+
npx ts-node examples/simple-document.ts
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
## Project Structure
|
|
1095
|
+
|
|
1096
|
+
```text
|
|
1097
|
+
src/
|
|
1098
|
+
├── core/ # Document, Parser, Generator, Validator
|
|
1099
|
+
├── elements/ # Paragraph, Run, Table, Image, Hyperlink
|
|
1100
|
+
├── formatting/ # Style, NumberingManager
|
|
1101
|
+
├── xml/ # XMLBuilder, XMLParser
|
|
1102
|
+
├── zip/ # ZipHandler for DOCX manipulation
|
|
1103
|
+
└── utils/ # Validation, Units conversion
|
|
1104
|
+
|
|
1105
|
+
examples/
|
|
1106
|
+
├── 01-basic/ # Simple document creation
|
|
1107
|
+
├── 02-text/ # Text formatting examples
|
|
1108
|
+
├── 03-tables/ # Table examples
|
|
1109
|
+
├── 04-styles/ # Style examples
|
|
1110
|
+
├── 05-images/ # Image handling
|
|
1111
|
+
├── 06-complete/ # Full document examples
|
|
1112
|
+
└── 07-hyperlinks/ # Link examples
|
|
1113
|
+
```
|
|
1114
|
+
|
|
1115
|
+
## Hierarchy
|
|
1116
|
+
|
|
1117
|
+
```text
|
|
1118
|
+
w:document (root)
|
|
1119
|
+
└── w:body (body container)
|
|
1120
|
+
├── w:p (paragraph) [1..n]
|
|
1121
|
+
│ ├── w:pPr (paragraph properties) [0..1]
|
|
1122
|
+
│ │ ├── w:pStyle (style reference)
|
|
1123
|
+
│ │ ├── w:jc (justification/alignment)
|
|
1124
|
+
│ │ ├── w:ind (indentation)
|
|
1125
|
+
│ │ └── w:spacing (spacing before/after)
|
|
1126
|
+
│ ├── w:r (run) [1..n]
|
|
1127
|
+
│ │ ├── w:rPr (run properties) [0..1]
|
|
1128
|
+
│ │ │ ├── w:b (bold)
|
|
1129
|
+
│ │ │ ├── w:i (italic)
|
|
1130
|
+
│ │ │ ├── w:u (underline)
|
|
1131
|
+
│ │ │ ├── w:sz (font size)
|
|
1132
|
+
│ │ │ └── w:color (text color)
|
|
1133
|
+
│ │ └── w:t (text content) [1]
|
|
1134
|
+
│ ├── w:hyperlink (hyperlink) [0..n]
|
|
1135
|
+
│ │ └── w:r (run with hyperlink text)
|
|
1136
|
+
│ └── w:drawing (embedded image/shape) [0..n]
|
|
1137
|
+
├── w:tbl (table) [1..n]
|
|
1138
|
+
│ ├── w:tblPr (table properties)
|
|
1139
|
+
│ └── w:tr (table row) [1..n]
|
|
1140
|
+
│ └── w:tc (table cell) [1..n]
|
|
1141
|
+
│ └── w:p (paragraph in cell)
|
|
1142
|
+
└── w:sectPr (section properties) [1] (must be last child of w:body)
|
|
1143
|
+
```
|
|
1144
|
+
|
|
1145
|
+
## Requirements
|
|
1146
|
+
|
|
1147
|
+
- Node.js 16+
|
|
1148
|
+
- TypeScript 5.0+ (for development)
|
|
1149
|
+
|
|
1150
|
+
## Installation Options
|
|
1151
|
+
|
|
1152
|
+
```bash
|
|
1153
|
+
# NPM
|
|
1154
|
+
npm install docxmlater
|
|
1155
|
+
|
|
1156
|
+
# Yarn
|
|
1157
|
+
yarn add docxmlater
|
|
1158
|
+
|
|
1159
|
+
# PNPM
|
|
1160
|
+
pnpm add docxmlater
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
## Troubleshooting
|
|
1164
|
+
|
|
1165
|
+
### XML Corruption in Text
|
|
1166
|
+
|
|
1167
|
+
**Problem**: Text displays with XML tags like `Important Information<w:t xml:space="preserve">1` in Word.
|
|
1168
|
+
|
|
1169
|
+
**Cause**: Passing XML-like strings to text methods instead of using the API properly.
|
|
1170
|
+
|
|
1171
|
+
```typescript
|
|
1172
|
+
// WRONG - Will display escaped XML as literal text
|
|
1173
|
+
paragraph.addText("Important Information<w:t>1</w:t>");
|
|
1174
|
+
// Displays as: "Important Information<w:t>1</w:t>"
|
|
1175
|
+
|
|
1176
|
+
// CORRECT - Use separate text runs
|
|
1177
|
+
paragraph.addText("Important Information");
|
|
1178
|
+
paragraph.addText("1");
|
|
1179
|
+
// Displays as: "Important Information1"
|
|
1180
|
+
|
|
1181
|
+
// Or combine in one call
|
|
1182
|
+
paragraph.addText("Important Information 1");
|
|
1183
|
+
```
|
|
1184
|
+
|
|
1185
|
+
**Detection**: Use the corruption detection utility to find issues:
|
|
1186
|
+
|
|
1187
|
+
```typescript
|
|
1188
|
+
import { detectCorruptionInDocument } from "docxmlater";
|
|
1189
|
+
|
|
1190
|
+
const doc = await Document.load("file.docx");
|
|
1191
|
+
const report = detectCorruptionInDocument(doc);
|
|
1192
|
+
|
|
1193
|
+
if (report.isCorrupted) {
|
|
1194
|
+
console.log(report.summary);
|
|
1195
|
+
report.locations.forEach((loc) => {
|
|
1196
|
+
console.log(`Paragraph ${loc.paragraphIndex}, Run ${loc.runIndex}:`);
|
|
1197
|
+
console.log(` Original: ${loc.text}`);
|
|
1198
|
+
console.log(` Fixed: ${loc.suggestedFix}`);
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
```
|
|
1202
|
+
|
|
1203
|
+
**Auto-Cleaning**: XML patterns are automatically removed by default for defensive data handling:
|
|
1204
|
+
|
|
1205
|
+
```typescript
|
|
1206
|
+
// Default behavior - auto-clean enabled
|
|
1207
|
+
const run = new Run("Text<w:t>value</w:t>");
|
|
1208
|
+
// Result: "Textvalue" (XML tags removed automatically)
|
|
1209
|
+
|
|
1210
|
+
// Disable auto-cleaning (for debugging)
|
|
1211
|
+
const run = new Run("Text<w:t>value</w:t>", { cleanXmlFromText: false });
|
|
1212
|
+
// Result: "Text<w:t>value</w:t>" (XML tags preserved, will display in Word)
|
|
1213
|
+
```
|
|
1214
|
+
|
|
1215
|
+
**Why This Happens**: The framework correctly escapes XML special characters per the XML specification. When you pass XML tags as text, they are properly escaped (`<` becomes `<`) and Word displays them as literal text, not as markup.
|
|
1216
|
+
|
|
1217
|
+
**The Right Approach**: Use the framework's API methods instead of embedding XML:
|
|
1218
|
+
|
|
1219
|
+
- Use `paragraph.addText()` multiple times for separate text runs
|
|
1220
|
+
- Use formatting options: `{bold: true}`, `{italic: true}`, etc.
|
|
1221
|
+
- Use `paragraph.addHyperlink()` for links
|
|
1222
|
+
- Don't pass XML strings to text methods
|
|
1223
|
+
- Don't try to embed `<w:t>` or other XML tags in your text
|
|
1224
|
+
|
|
1225
|
+
For more details, see the [corruption detection examples](examples/troubleshooting/).
|
|
1226
|
+
|
|
1227
|
+
### Layout Conflicts (Massive Whitespace)
|
|
1228
|
+
|
|
1229
|
+
**Problem**: Documents show massive whitespace between paragraphs when opened in Word, even though the XML looks correct.
|
|
1230
|
+
|
|
1231
|
+
**Cause**: The `pageBreakBefore` property conflicting with `keepNext`/`keepLines` properties. When a paragraph has both `pageBreakBefore` and keep properties set to true, Word's layout engine tries to satisfy contradictory constraints (insert break vs. keep together), resulting in massive whitespace as it struggles to resolve the conflict.
|
|
1232
|
+
|
|
1233
|
+
**Why This Causes Problems**:
|
|
1234
|
+
|
|
1235
|
+
- `pageBreakBefore` tells Word to insert a page break before the paragraph
|
|
1236
|
+
- `keepNext` tells Word to keep the paragraph with the next one (no break)
|
|
1237
|
+
- `keepLines` tells Word to keep all lines together (no break)
|
|
1238
|
+
- The combination creates layout conflicts that manifest as massive whitespace
|
|
1239
|
+
|
|
1240
|
+
**Automatic Conflict Resolution** (v0.28.2+):
|
|
1241
|
+
|
|
1242
|
+
The framework now automatically prevents these conflicts by **prioritizing keep properties over page breaks**:
|
|
1243
|
+
|
|
1244
|
+
```typescript
|
|
1245
|
+
// When setting keepNext or keepLines, pageBreakBefore is automatically cleared
|
|
1246
|
+
const para = new Paragraph()
|
|
1247
|
+
.addText("Content")
|
|
1248
|
+
.setPageBreakBefore(true) // Set to true
|
|
1249
|
+
.setKeepNext(true); // Automatically clears pageBreakBefore
|
|
1250
|
+
|
|
1251
|
+
// Result: keepNext=true, pageBreakBefore=false (conflict resolved)
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
**Why This Priority?**
|
|
1255
|
+
|
|
1256
|
+
- Keep properties (`keepNext`/`keepLines`) represent explicit user intent to keep content together
|
|
1257
|
+
- Page breaks are often layout hints that may conflict with document flow
|
|
1258
|
+
- Removing `pageBreakBefore` eliminates whitespace while preserving the user's intention
|
|
1259
|
+
|
|
1260
|
+
**Parsing Documents**:
|
|
1261
|
+
|
|
1262
|
+
When loading existing DOCX files with conflicts, they are automatically resolved:
|
|
1263
|
+
|
|
1264
|
+
```typescript
|
|
1265
|
+
// Load document with conflicts
|
|
1266
|
+
const doc = await Document.load("document-with-conflicts.docx");
|
|
1267
|
+
|
|
1268
|
+
// Conflicts are automatically resolved during parsing
|
|
1269
|
+
// keepNext/keepLines take priority, pageBreakBefore is removed
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
**How It Works**:
|
|
1273
|
+
|
|
1274
|
+
1. When `setKeepNext(true)` is called, `pageBreakBefore` is automatically set to `false`
|
|
1275
|
+
2. When `setKeepLines(true)` is called, `pageBreakBefore` is automatically set to `false`
|
|
1276
|
+
3. When parsing documents, if both properties exist, `pageBreakBefore` is cleared
|
|
1277
|
+
4. Keep properties win because they represent explicit user intent
|
|
1278
|
+
|
|
1279
|
+
**Manual Override**:
|
|
1280
|
+
|
|
1281
|
+
If you need a page break despite keep properties, set it after:
|
|
1282
|
+
|
|
1283
|
+
```typescript
|
|
1284
|
+
const para = new Paragraph()
|
|
1285
|
+
.setKeepNext(true) // Set first
|
|
1286
|
+
.setPageBreakBefore(true); // Override - you explicitly want this conflict
|
|
1287
|
+
|
|
1288
|
+
// But note: This will cause layout issues (whitespace) in Word
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
## Contributing
|
|
1292
|
+
|
|
1293
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md).
|
|
1294
|
+
|
|
1295
|
+
1. Fork the repository
|
|
1296
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
1297
|
+
3. Commit changes (`git commit -m 'Add amazing feature'`)
|
|
1298
|
+
4. Push to branch (`git push origin feature/amazing-feature`)
|
|
1299
|
+
5. Open a Pull Request
|
|
1300
|
+
|
|
1301
|
+
## Recent Updates (v0.20.1)
|
|
1302
|
+
|
|
1303
|
+
**Critical Bug Fix Release:**
|
|
1304
|
+
|
|
1305
|
+
- **Fixed Paragraph.getText()** - Now includes hyperlink text content (critical data loss bug)
|
|
1306
|
+
- **Added hyperlink integration tests** - 6 new comprehensive test cases
|
|
1307
|
+
- **Enhanced test suite** - 474/478 tests passing (98.1% pass rate)
|
|
1308
|
+
- **Fixed type safety** - XMLElement handling improvements across test files
|
|
1309
|
+
- **Improved StylesManager** - XML corruption detection moved before parser
|
|
1310
|
+
- **Hyperlink management** - Proper relationship ID clearing on URL updates
|
|
1311
|
+
|
|
1312
|
+
**What This Fixes:**
|
|
1313
|
+
When using `para.addText('foo') + para.addHyperlink(link)`, the hyperlink text is now properly included in `paragraph.getText()`, preventing silent text loss.
|
|
1314
|
+
|
|
1315
|
+
## License
|
|
1316
|
+
|
|
1317
|
+
MIT © DiaTech
|
|
1318
|
+
|
|
1319
|
+
## Acknowledgments
|
|
1320
|
+
|
|
1321
|
+
- Built with [JSZip](https://stuk.github.io/jszip/) for ZIP handling
|
|
1322
|
+
- Follows [ECMA-376](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/) Office Open XML standard
|
|
1323
|
+
- Inspired by [python-docx](https://python-docx.readthedocs.io/) and [docx](https://github.com/dolanmiu/docx)
|
|
1324
|
+
|
|
1325
|
+
## Support
|
|
1326
|
+
|
|
1327
|
+
- **Documentation**: [Full Docs](https://github.com/ItMeDiaTech/docXMLater/tree/main/docs)
|
|
1328
|
+
- **Examples**: [Example Code](https://github.com/ItMeDiaTech/docXMLater/tree/main/examples)
|
|
1329
|
+
- **Issues**: [GitHub Issues](https://github.com/ItMeDiaTech/docXMLater/issues)
|
|
1330
|
+
- **Discussions**: [GitHub Discussions](https://github.com/ItMeDiaTech/docXMLater/discussions)
|
|
1331
|
+
|
|
1332
|
+
## Quick Links
|
|
1333
|
+
|
|
1334
|
+
- [NPM Package](https://www.npmjs.com/package/docxmlater)
|
|
1335
|
+
- [GitHub Repository](https://github.com/ItMeDiaTech/docXMLater)
|
|
1336
|
+
- [API Reference](https://github.com/ItMeDiaTech/docXMLater/tree/main/docs/api)
|
|
1337
|
+
- [Change Log](https://github.com/ItMeDiaTech/docXMLater/blob/main/CHANGELOG.md)
|
|
1338
|
+
|
|
1339
|
+
---
|
|
1340
|
+
|
|
1341
|
+
**Ready to create amazing Word documents?** Start with our [examples](https://github.com/ItMeDiaTech/docXMLater/tree/main/examples) or dive into the [API Reference](#complete-api-reference) above!
|