@docx4j/core-ts 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +410 -10
- package/dist/model/content/Body.d.mts +109 -4
- package/dist/model/content/Body.mjs +300 -29
- package/dist/model/content/Comment.d.mts +78 -0
- package/dist/model/content/Comment.mjs +429 -0
- package/dist/model/content/ContentControl.d.mts +173 -0
- package/dist/model/content/ContentControl.mjs +638 -0
- package/dist/model/content/Font.d.mts +48 -8
- package/dist/model/content/Font.mjs +55 -13
- package/dist/model/content/InlinePicture.d.mts +103 -0
- package/dist/model/content/InlinePicture.mjs +361 -0
- package/dist/model/content/List.d.mts +253 -0
- package/dist/model/content/List.mjs +778 -0
- package/dist/model/content/Paragraph.d.mts +213 -16
- package/dist/model/content/Paragraph.mjs +611 -57
- package/dist/model/content/Range.d.mts +48 -4
- package/dist/model/content/Range.mjs +161 -4
- package/dist/model/content/Table.d.mts +130 -0
- package/dist/model/content/Table.mjs +429 -0
- package/dist/model/content/TrackedChange.d.mts +96 -0
- package/dist/model/content/TrackedChange.mjs +352 -0
- package/dist/model/content/comments.d.mts +122 -0
- package/dist/model/content/comments.mjs +248 -0
- package/dist/model/content/index.d.mts +13 -3
- package/dist/model/content/index.mjs +15 -3
- package/dist/model/content/ooxml.d.mts +17 -0
- package/dist/model/content/ooxml.mjs +214 -0
- package/dist/model/content/styles.d.mts +21 -0
- package/dist/model/content/styles.mjs +86 -0
- package/dist/model/content/tracking.d.mts +104 -0
- package/dist/model/content/tracking.mjs +313 -0
- package/dist/model/content/tree.d.mts +56 -9
- package/dist/model/content/tree.mjs +104 -31
- package/dist/model/customxml/CustomXmlPart.d.mts +158 -0
- package/dist/model/customxml/CustomXmlPart.mjs +415 -0
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +68 -0
- package/dist/model/customxml/CustomXmlPartCollection.mjs +183 -0
- package/dist/model/customxml/XmlMapping.d.mts +46 -0
- package/dist/model/customxml/XmlMapping.mjs +98 -0
- package/dist/model/customxml/bindings.d.mts +41 -0
- package/dist/model/customxml/bindings.mjs +230 -0
- package/dist/model/customxml/index.d.mts +7 -0
- package/dist/model/customxml/index.mjs +9 -0
- package/dist/model/customxml/insert.d.mts +20 -0
- package/dist/model/customxml/insert.mjs +22 -0
- package/dist/model/customxml/kinds.d.mts +103 -0
- package/dist/model/customxml/kinds.mjs +267 -0
- package/dist/model/customxml/xpath.d.mts +52 -0
- package/dist/model/customxml/xpath.mjs +205 -0
- package/dist/model/fonts/CJKToEnglish.d.mts +2 -0
- package/dist/model/fonts/CJKToEnglish.mjs +16 -0
- package/dist/model/fonts/FontFallback.d.mts +58 -0
- package/dist/model/fonts/FontFallback.mjs +219 -0
- package/dist/model/fonts/IdentityPlusMapper.d.mts +7 -0
- package/dist/model/fonts/IdentityPlusMapper.mjs +19 -0
- package/dist/model/fonts/LanguageTagToScriptMapping.d.mts +7 -0
- package/dist/model/fonts/LanguageTagToScriptMapping.mjs +67 -0
- package/dist/model/fonts/Mapper.d.mts +190 -0
- package/dist/model/fonts/Mapper.mjs +481 -0
- package/dist/model/fonts/PhysicalFont.d.mts +34 -0
- package/dist/model/fonts/PhysicalFont.mjs +62 -0
- package/dist/model/fonts/RunFontSelector.d.mts +194 -0
- package/dist/model/fonts/RunFontSelector.mjs +441 -0
- package/dist/model/fonts/ThemeFonts.d.mts +17 -0
- package/dist/model/fonts/ThemeFonts.mjs +76 -0
- package/dist/model/fonts/defaultTheme.d.mts +37 -0
- package/dist/model/fonts/defaultTheme.mjs +57 -0
- package/dist/model/fonts/families.generated.d.mts +11 -0
- package/dist/model/fonts/families.generated.mjs +17 -0
- package/dist/model/fonts/fontsInUse.d.mts +39 -0
- package/dist/model/fonts/fontsInUse.mjs +183 -0
- package/dist/model/fonts/index.d.mts +14 -0
- package/dist/model/fonts/index.mjs +29 -0
- package/dist/model/fonts/lookup.d.mts +5 -0
- package/dist/model/fonts/lookup.mjs +12 -0
- package/dist/model/fonts/registry.d.mts +31 -0
- package/dist/model/fonts/registry.mjs +103 -0
- package/dist/model/fonts/scripts.d.mts +2 -0
- package/dist/model/fonts/scripts.mjs +78 -0
- package/dist/model/fonts/substitutions.generated.d.mts +30 -0
- package/dist/model/fonts/substitutions.generated.mjs +12 -0
- package/dist/model/fonts/themes.generated.d.mts +6 -0
- package/dist/model/fonts/themes.generated.mjs +11 -0
- package/dist/model/index.d.mts +5 -0
- package/dist/model/index.mjs +13 -1
- package/dist/model/listnumbering/Emulator.d.mts +187 -0
- package/dist/model/listnumbering/Emulator.mjs +332 -0
- package/dist/model/listnumbering/definitions.d.mts +251 -0
- package/dist/model/listnumbering/definitions.mjs +571 -0
- package/dist/model/listnumbering/formats.d.mts +25 -0
- package/dist/model/listnumbering/formats.mjs +320 -0
- package/dist/model/listnumbering/index.d.mts +4 -0
- package/dist/model/listnumbering/index.mjs +15 -0
- package/dist/model/listnumbering/state.d.mts +97 -0
- package/dist/model/listnumbering/state.mjs +179 -0
- package/dist/model/properties/PropertyResolver.d.mts +216 -0
- package/dist/model/properties/PropertyResolver.mjs +524 -0
- package/dist/model/properties/catalogue.d.mts +179 -0
- package/dist/model/properties/catalogue.mjs +860 -0
- package/dist/model/properties/index.d.mts +4 -0
- package/dist/model/properties/index.mjs +9 -0
- package/dist/model/properties/log.d.mts +7 -0
- package/dist/model/properties/log.mjs +25 -0
- package/dist/model/properties/styleUtil.d.mts +112 -0
- package/dist/model/properties/styleUtil.mjs +359 -0
- package/dist/node/index.d.mts +1 -0
- package/dist/node/index.mjs +12 -0
- package/dist/office-js/document.d.mts +111 -0
- package/dist/office-js/document.mjs +267 -0
- package/dist/office-js/enums.d.mts +187 -0
- package/dist/office-js/enums.mjs +176 -0
- package/dist/office-js/errors.d.mts +29 -0
- package/dist/office-js/errors.mjs +39 -0
- package/dist/office-js/extras.d.mts +5 -0
- package/dist/office-js/extras.mjs +29 -0
- package/dist/office-js/fragment.d.mts +10 -0
- package/dist/office-js/fragment.mjs +23 -0
- package/dist/office-js/index.d.mts +183 -0
- package/dist/office-js/index.mjs +54 -0
- package/dist/office-js/proxy.d.mts +72 -0
- package/dist/office-js/proxy.mjs +279 -0
- package/dist/office-js/run.d.mts +32 -0
- package/dist/office-js/run.mjs +66 -0
- package/dist/office-js/supported.d.mts +7 -0
- package/dist/office-js/supported.generated.d.mts +1 -0
- package/dist/office-js/supported.generated.mjs +235 -0
- package/dist/office-js/supported.mjs +53 -0
- package/dist/office-js/toApiScript.d.mts +25 -0
- package/dist/office-js/toApiScript.mjs +394 -0
- package/dist/opc/ContentTypes.d.mts +1 -0
- package/dist/opc/ContentTypes.mjs +1 -0
- package/dist/opc/DirectoryPartStore.d.mts +47 -0
- package/dist/opc/DirectoryPartStore.mjs +123 -0
- package/dist/opc/exceptions.d.mts +30 -0
- package/dist/opc/exceptions.mjs +38 -0
- package/dist/opc/index.d.mts +1 -1
- package/dist/opc/index.mjs +1 -1
- package/dist/packages/OpcPackage.d.mts +19 -1
- package/dist/packages/OpcPackage.mjs +29 -0
- package/dist/packages/PresentationMLPackage.d.mts +71 -1
- package/dist/packages/PresentationMLPackage.mjs +179 -0
- package/dist/packages/SpreadsheetMLPackage.d.mts +30 -1
- package/dist/packages/SpreadsheetMLPackage.mjs +78 -0
- package/dist/packages/WordprocessingMLPackage.d.mts +124 -2
- package/dist/packages/WordprocessingMLPackage.mjs +309 -2
- package/dist/packages/index.d.mts +1 -1
- package/dist/packages/index.mjs +1 -1
- package/dist/parts/DefaultXmlPart.d.mts +18 -0
- package/dist/parts/DefaultXmlPart.mjs +34 -5
- package/dist/parts/PartRegistry.mjs +1 -0
- package/dist/parts/XmlPart.d.mts +33 -0
- package/dist/parts/XmlPart.mjs +105 -2
- package/dist/parts/pml/defaults.d.mts +6 -0
- package/dist/parts/pml/defaults.mjs +53 -0
- package/dist/parts/pml/index.d.mts +66 -3
- package/dist/parts/pml/index.mjs +206 -7
- package/dist/parts/pml/placeholders.d.mts +71 -0
- package/dist/parts/pml/placeholders.mjs +141 -0
- package/dist/parts/sml/index.d.mts +19 -1
- package/dist/parts/sml/index.mjs +60 -1
- package/dist/parts/wml/comments.d.mts +1 -0
- package/dist/parts/wml/comments.mjs +179 -0
- package/dist/parts/wml/defaultNumbering.d.mts +1 -0
- package/dist/parts/wml/defaultNumbering.mjs +216 -0
- package/dist/parts/wml/index.d.mts +121 -0
- package/dist/parts/wml/index.mjs +291 -0
- package/dist/xml/dom.mjs +1 -2
- package/package.json +25 -4
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
import { deepCopy } from '@docx4j/generated-objects-ts';
|
|
2
|
+
import { Docx4JException } from '../../opc/exceptions.mjs';
|
|
3
|
+
import { log } from './log.mjs';
|
|
4
|
+
import { NumberingDefinitions } from '../listnumbering/definitions.mjs';
|
|
5
|
+
import { applyPPrBase, applyRPr, applyStyle, applyStyleLevel, applyTblPr, hasDirectFormattingPPr, hasDirectFormattingRPr, isCyclic, } from './styleUtil.mjs';
|
|
6
|
+
/** The cache key for "no style" (a styles part with no default paragraph style). */
|
|
7
|
+
const NO_STYLE = '';
|
|
8
|
+
/** 108 twips (0.08in): the left and right cell margin of Word's built-in Normal Table. */
|
|
9
|
+
export const WORD_DEFAULT_CELL_MARGIN_TWIPS = 108;
|
|
10
|
+
const HEADING_NAME = /^heading ([1-9])$/i;
|
|
11
|
+
const HEADING_STYLE = 'Heading';
|
|
12
|
+
/**
|
|
13
|
+
* The outline level (1-9) of a built-in heading style, from its `w:name` ("heading 1" ...
|
|
14
|
+
* "heading 9"), or -1. Word identifies built-in styles by name, so this holds in every locale;
|
|
15
|
+
* {@link PropertyResolver.getLvlFromHeadingStyle} keys on the English style id.
|
|
16
|
+
*/
|
|
17
|
+
export function headingLevelByName(style) {
|
|
18
|
+
var _a;
|
|
19
|
+
const name = (_a = style === null || style === void 0 ? void 0 : style.name) === null || _a === void 0 ? void 0 : _a.val;
|
|
20
|
+
if (name === undefined)
|
|
21
|
+
return -1;
|
|
22
|
+
const match = HEADING_NAME.exec(name.trim());
|
|
23
|
+
return match ? Number(match[1]) : -1;
|
|
24
|
+
}
|
|
25
|
+
export class PropertyResolver {
|
|
26
|
+
constructor(provider,
|
|
27
|
+
/** Set when the styles tree the resolver holds is not the styles part's own. */
|
|
28
|
+
stylesArePrivate = () => false) {
|
|
29
|
+
this.provider = provider;
|
|
30
|
+
this.stylesArePrivate = stylesArePrivate;
|
|
31
|
+
this.documentDefaultPPr = { TYPE_NAME: 'org_docx4j_wml.PPr' };
|
|
32
|
+
this.documentDefaultRPr = { TYPE_NAME: 'org_docx4j_wml.RPr' };
|
|
33
|
+
/** All styles in the styles part, keyed by style id (docx4j's `liveStyles`). */
|
|
34
|
+
this.liveStyles = new Map();
|
|
35
|
+
/** How many styles the part held when `liveStyles` was last scanned; a miss rescans only when that has changed. */
|
|
36
|
+
this.scannedStyleCount = -1;
|
|
37
|
+
/** A style's `w:basedOn` chain merged root-first, WITHOUT the document defaults, per style id. */
|
|
38
|
+
this.chainPPrCache = new Map();
|
|
39
|
+
this.chainRPrCache = new Map();
|
|
40
|
+
/** The document defaults with the chain applied over them: what the style overloads return. */
|
|
41
|
+
this.effectivePPrByStyle = new Map();
|
|
42
|
+
this.effectiveRPrByStyle = new Map();
|
|
43
|
+
/** Missing styles are logged once each per resolver. */
|
|
44
|
+
this.missingLogged = new Set();
|
|
45
|
+
this.source = provider();
|
|
46
|
+
this.init();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Builds a resolver over a package's styles and numbering parts (docx4j's constructor,
|
|
50
|
+
* which can do this synchronously because JAXB is).
|
|
51
|
+
*
|
|
52
|
+
* The parts are read with `readContents()`, which does **not** mark them unmarshalled, so a
|
|
53
|
+
* document whose styles nobody has edited still saves byte for byte. Once something else
|
|
54
|
+
* unmarshals the part - the comment styles, a caller's `getContents()` - `refresh()` picks
|
|
55
|
+
* up that live tree instead of the private copy.
|
|
56
|
+
*/
|
|
57
|
+
static async create(pkg) {
|
|
58
|
+
if (typeof pkg.getMainDocumentPart !== 'function') {
|
|
59
|
+
const source = pkg;
|
|
60
|
+
return new PropertyResolver(() => source);
|
|
61
|
+
}
|
|
62
|
+
let main;
|
|
63
|
+
try {
|
|
64
|
+
main = pkg.getMainDocumentPart();
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
throw new Docx4JException('A PropertyResolver needs a main document part', { cause: e });
|
|
68
|
+
}
|
|
69
|
+
const stylesPart = main.styleDefinitionsPart;
|
|
70
|
+
const numberingPart = main.numberingDefinitionsPart;
|
|
71
|
+
const privateStyles = stylesPart === undefined ? undefined : await stylesPart.readContents();
|
|
72
|
+
const privateNumbering = numberingPart === undefined ? undefined : await numberingPart.readContents();
|
|
73
|
+
return new PropertyResolver(() => ({
|
|
74
|
+
styles: (stylesPart === null || stylesPart === void 0 ? void 0 : stylesPart.isUnmarshalled) === true ? stylesPart.contents : privateStyles,
|
|
75
|
+
numbering: (numberingPart === null || numberingPart === void 0 ? void 0 : numberingPart.isUnmarshalled) === true ? numberingPart.contents : privateNumbering,
|
|
76
|
+
}), () => stylesPart !== undefined && !stylesPart.isUnmarshalled);
|
|
77
|
+
}
|
|
78
|
+
/** Builds a resolver over object trees directly (a test, or parts already in hand). */
|
|
79
|
+
static fromSource(source) {
|
|
80
|
+
return new PropertyResolver(() => source);
|
|
81
|
+
}
|
|
82
|
+
// ------------------------------------------------------------------ init
|
|
83
|
+
init() {
|
|
84
|
+
var _a, _b, _c, _d, _e, _f;
|
|
85
|
+
const styles = this.source.styles;
|
|
86
|
+
this.liveStyles.clear();
|
|
87
|
+
this.scannedStyleCount = -1;
|
|
88
|
+
this.defaultParagraphStyleId = undefined;
|
|
89
|
+
this.defaultCharacterStyleId = undefined;
|
|
90
|
+
this.defaultTableStyleId = undefined;
|
|
91
|
+
if (styles !== undefined) {
|
|
92
|
+
this.scanStyles();
|
|
93
|
+
for (const style of (_a = styles.style) !== null && _a !== void 0 ? _a : []) {
|
|
94
|
+
if (style._default !== true || style.styleId === undefined)
|
|
95
|
+
continue;
|
|
96
|
+
if (style.type === 'paragraph')
|
|
97
|
+
(_b = this.defaultParagraphStyleId) !== null && _b !== void 0 ? _b : (this.defaultParagraphStyleId = style.styleId);
|
|
98
|
+
else if (style.type === 'character')
|
|
99
|
+
(_c = this.defaultCharacterStyleId) !== null && _c !== void 0 ? _c : (this.defaultCharacterStyleId = style.styleId);
|
|
100
|
+
else if (style.type === 'table')
|
|
101
|
+
(_d = this.defaultTableStyleId) !== null && _d !== void 0 ? _d : (this.defaultTableStyleId = style.styleId);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (this.defaultParagraphStyleId === undefined)
|
|
105
|
+
log.warn('No default paragraph style!!');
|
|
106
|
+
// private copies: the resolver's defaults are its own, so nothing below writes into the
|
|
107
|
+
// styles part (until CR-015 phase 3 the w:sz 20 default went into the part, and a docx
|
|
108
|
+
// saved after an export carried it)
|
|
109
|
+
const docDefaults = styles === null || styles === void 0 ? void 0 : styles.docDefaults;
|
|
110
|
+
this.documentDefaultPPr = ((_e = docDefaults === null || docDefaults === void 0 ? void 0 : docDefaults.pPrDefault) === null || _e === void 0 ? void 0 : _e.pPr) === undefined
|
|
111
|
+
? { TYPE_NAME: 'org_docx4j_wml.PPr' } : deepCopy(docDefaults.pPrDefault.pPr);
|
|
112
|
+
this.documentDefaultRPr = ((_f = docDefaults === null || docDefaults === void 0 ? void 0 : docDefaults.rPrDefault) === null || _f === void 0 ? void 0 : _f.rPr) === undefined
|
|
113
|
+
? { TYPE_NAME: 'org_docx4j_wml.RPr' } : deepCopy(docDefaults.rPrDefault.rPr);
|
|
114
|
+
if (this.documentDefaultRPr.sz === undefined) {
|
|
115
|
+
// Word's default made explicit: 10pt where nothing states a size (measured, CR-015 probe
|
|
116
|
+
// styles-no-size-anywhere: identical to an explicit 10pt run)
|
|
117
|
+
this.documentDefaultRPr.sz = { TYPE_NAME: 'org_docx4j_wml.HpsMeasure', val: 20 };
|
|
118
|
+
}
|
|
119
|
+
this.numberingDefinitions = this.source.numbering === undefined
|
|
120
|
+
? undefined
|
|
121
|
+
: new NumberingDefinitions(this.source.numbering, (styleId) => this.getLiveStyle(styleId));
|
|
122
|
+
}
|
|
123
|
+
/** (Re)read the styles part into `liveStyles`. A style with no id is skipped. */
|
|
124
|
+
scanStyles() {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
const list = (_b = (_a = this.source.styles) === null || _a === void 0 ? void 0 : _a.style) !== null && _b !== void 0 ? _b : [];
|
|
127
|
+
for (const style of list) {
|
|
128
|
+
if (style.styleId === undefined)
|
|
129
|
+
continue;
|
|
130
|
+
this.liveStyles.set(style.styleId, style);
|
|
131
|
+
}
|
|
132
|
+
this.scannedStyleCount = list.length;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* The style with this id, rescanning the styles part on a miss - and only when the list's
|
|
136
|
+
* size has changed - so that a style *added* to the part after this resolver was built is
|
|
137
|
+
* still found. A style *modified* or *removed* needs {@link refresh}.
|
|
138
|
+
*/
|
|
139
|
+
getLiveStyle(styleId) {
|
|
140
|
+
var _a, _b, _c;
|
|
141
|
+
if (styleId === undefined)
|
|
142
|
+
return undefined;
|
|
143
|
+
let style = this.liveStyles.get(styleId);
|
|
144
|
+
if (style === undefined && ((_c = (_b = (_a = this.source.styles) === null || _a === void 0 ? void 0 : _a.style) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) !== this.scannedStyleCount) {
|
|
145
|
+
this.scanStyles();
|
|
146
|
+
style = this.liveStyles.get(styleId);
|
|
147
|
+
}
|
|
148
|
+
return style;
|
|
149
|
+
}
|
|
150
|
+
logMissing(styleId) {
|
|
151
|
+
if (this.missingLogged.has(styleId))
|
|
152
|
+
return;
|
|
153
|
+
this.missingLogged.add(styleId);
|
|
154
|
+
log.warn(`Style definition not found: ${styleId} (logged once)`);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Discard cached state and re-read the styles part. A style merely *added* is picked up
|
|
158
|
+
* automatically; call this when a style has been modified or removed, or the styles part's
|
|
159
|
+
* contents replaced. The content API calls it where it creates a style.
|
|
160
|
+
*/
|
|
161
|
+
refresh() {
|
|
162
|
+
this.chainPPrCache.clear();
|
|
163
|
+
this.chainRPrCache.clear();
|
|
164
|
+
this.effectivePPrByStyle.clear();
|
|
165
|
+
this.effectiveRPrByStyle.clear();
|
|
166
|
+
this.missingLogged.clear();
|
|
167
|
+
this.source = this.provider();
|
|
168
|
+
this.init();
|
|
169
|
+
}
|
|
170
|
+
// ------------------------------------------------------------------ defaults
|
|
171
|
+
getDocumentDefaultPPr() {
|
|
172
|
+
return this.documentDefaultPPr;
|
|
173
|
+
}
|
|
174
|
+
getDocumentDefaultRPr() {
|
|
175
|
+
return this.documentDefaultRPr;
|
|
176
|
+
}
|
|
177
|
+
/** The style id of the `w:default="1"` paragraph style, or undefined when the part declares none. */
|
|
178
|
+
getDefaultParagraphStyleId() {
|
|
179
|
+
return this.defaultParagraphStyleId;
|
|
180
|
+
}
|
|
181
|
+
/** The default paragraph style's effective `w:pPr`, as `getEffectivePPr(styleId)` gives it. */
|
|
182
|
+
getResolvedDefaultParagraphStyle() {
|
|
183
|
+
return this.getEffectivePPr(this.defaultParagraphStyleId);
|
|
184
|
+
}
|
|
185
|
+
/** The style with this id, or undefined (docx4j `getStyle`). */
|
|
186
|
+
getStyle(styleId) {
|
|
187
|
+
return this.getLiveStyle(styleId);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* The list definitions of the numbering part this resolver read (CR-001 Phase B step 3), or
|
|
191
|
+
* undefined where the package has none. The resolver builds them because the paragraph merge
|
|
192
|
+
* folds a numbering level's `w:ind` into every layer (`NumberingDefinitionsPart.getInd`);
|
|
193
|
+
* `NumberingDefinitionsPart.definitions` hands out this same object, so the counting and the
|
|
194
|
+
* indents read one set of definitions.
|
|
195
|
+
*/
|
|
196
|
+
getNumberingDefinitions() {
|
|
197
|
+
return this.numberingDefinitions;
|
|
198
|
+
}
|
|
199
|
+
// ------------------------------------------------------------------ the chains
|
|
200
|
+
/**
|
|
201
|
+
* The style and the styles it is based on, root first (the base of the chain at index 0, the
|
|
202
|
+
* style itself last); empty for an unknown id. A cycle, or a chain deeper than 32, ends the
|
|
203
|
+
* walk where it is detected (and throws `CyclicStylesException` when
|
|
204
|
+
* `throwOnCyclicStyles(true)` is set).
|
|
205
|
+
*/
|
|
206
|
+
ancestry(styleId) {
|
|
207
|
+
var _a;
|
|
208
|
+
const leafFirst = [];
|
|
209
|
+
const seen = [];
|
|
210
|
+
let id = styleId;
|
|
211
|
+
while (id !== undefined) {
|
|
212
|
+
if (isCyclic(id, seen))
|
|
213
|
+
break;
|
|
214
|
+
seen.push(id);
|
|
215
|
+
const style = this.getLiveStyle(id);
|
|
216
|
+
if (style === undefined) {
|
|
217
|
+
// "DocDefaults" is StyleTree's virtual style for the document defaults, which this
|
|
218
|
+
// resolver applies itself; anything else is a reference to nothing
|
|
219
|
+
if (id !== 'DocDefaults')
|
|
220
|
+
this.logMissing(id);
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
leafFirst.push(style);
|
|
224
|
+
id = (_a = style.basedOn) === null || _a === void 0 ? void 0 : _a.val;
|
|
225
|
+
}
|
|
226
|
+
return leafFirst.reverse();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* A paragraph style's `w:basedOn` chain merged root-first, WITHOUT the document defaults:
|
|
230
|
+
* what the style contributes on its own. A live, cached object: copy before changing.
|
|
231
|
+
*/
|
|
232
|
+
getChainPPr(styleId) {
|
|
233
|
+
if (styleId === undefined)
|
|
234
|
+
return { TYPE_NAME: 'org_docx4j_wml.PPr' };
|
|
235
|
+
const cached = this.chainPPrCache.get(styleId);
|
|
236
|
+
if (cached !== undefined)
|
|
237
|
+
return cached;
|
|
238
|
+
const chain = { TYPE_NAME: 'org_docx4j_wml.PPr' };
|
|
239
|
+
for (const style of this.ancestry(styleId)) {
|
|
240
|
+
this.applyPPrLayer(this.headingLayer(style), chain);
|
|
241
|
+
}
|
|
242
|
+
this.chainPPrCache.set(styleId, chain);
|
|
243
|
+
return chain;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* A style's `w:basedOn` chain merged root-first, WITHOUT the document defaults: for a
|
|
247
|
+
* character style, what it contributes over the paragraph's run properties. A live, cached
|
|
248
|
+
* object: copy before changing.
|
|
249
|
+
*/
|
|
250
|
+
getChainRPr(styleId) {
|
|
251
|
+
if (styleId === undefined)
|
|
252
|
+
return { TYPE_NAME: 'org_docx4j_wml.RPr' };
|
|
253
|
+
const cached = this.chainRPrCache.get(styleId);
|
|
254
|
+
if (cached !== undefined)
|
|
255
|
+
return cached;
|
|
256
|
+
const chain = { TYPE_NAME: 'org_docx4j_wml.RPr' };
|
|
257
|
+
for (const style of this.ancestry(styleId)) {
|
|
258
|
+
applyRPr(style.rPr, chain);
|
|
259
|
+
}
|
|
260
|
+
this.chainRPrCache.set(styleId, chain);
|
|
261
|
+
return chain;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* A style's own `w:pPr` as a layer of its chain. The built-in heading styles have a fixed
|
|
265
|
+
* outline level, which Word takes from the style's built-in NAME ("heading 1" ...
|
|
266
|
+
* "heading 9", the same in every locale; the style id is localised: "Überschrift1",
|
|
267
|
+
* "Titre1"), whatever `w:outlineLvl` the style declares: where they differ the layer is a
|
|
268
|
+
* copy with the level from the name, and the styles part is not touched.
|
|
269
|
+
*/
|
|
270
|
+
headingLayer(style) {
|
|
271
|
+
const layer = style.pPr;
|
|
272
|
+
const headingLevel = headingLevelByName(style);
|
|
273
|
+
if (headingLevel > 0 && layer !== undefined
|
|
274
|
+
&& layer.outlineLvl !== undefined && layer.outlineLvl.val !== undefined
|
|
275
|
+
&& layer.outlineLvl.val !== headingLevel - 1) {
|
|
276
|
+
const copy = deepCopy(layer);
|
|
277
|
+
copy.outlineLvl.val = headingLevel - 1;
|
|
278
|
+
return copy;
|
|
279
|
+
}
|
|
280
|
+
return layer;
|
|
281
|
+
}
|
|
282
|
+
applyPPrLayer(source, destination) {
|
|
283
|
+
if (source === undefined)
|
|
284
|
+
return;
|
|
285
|
+
applyPPrBase(source, destination, this.numberingDefinitions);
|
|
286
|
+
destination.rPr = applyRPr(source.rPr, destination.rPr, () => ({ TYPE_NAME: 'org_docx4j_wml.ParaRPr' }));
|
|
287
|
+
}
|
|
288
|
+
/** The paragraph's style: its `w:pStyle` where that names a style that exists, else the default paragraph style. */
|
|
289
|
+
paragraphStyleOf(pPr) {
|
|
290
|
+
if (pPr === undefined || pPr.pStyle === undefined)
|
|
291
|
+
return this.defaultParagraphStyleId;
|
|
292
|
+
const styleId = pPr.pStyle.val;
|
|
293
|
+
if (styleId === undefined)
|
|
294
|
+
return this.defaultParagraphStyleId;
|
|
295
|
+
return this.existingParagraphStyle(styleId);
|
|
296
|
+
}
|
|
297
|
+
/** `styleId` if it names a style that exists, else the default paragraph style's id (logged once). */
|
|
298
|
+
existingParagraphStyle(styleId) {
|
|
299
|
+
if (styleId === undefined)
|
|
300
|
+
return this.defaultParagraphStyleId;
|
|
301
|
+
if (this.getLiveStyle(styleId) === undefined) {
|
|
302
|
+
this.logMissing(styleId);
|
|
303
|
+
return this.defaultParagraphStyleId;
|
|
304
|
+
}
|
|
305
|
+
return styleId;
|
|
306
|
+
}
|
|
307
|
+
getEffectivePPr(arg) {
|
|
308
|
+
if (arg === undefined || typeof arg === 'string')
|
|
309
|
+
return this.effectivePPrOfStyle(arg);
|
|
310
|
+
const resolved = this.effectivePPrOfStyle(this.paragraphStyleOf(arg));
|
|
311
|
+
if (!hasDirectFormattingPPr(arg))
|
|
312
|
+
return resolved;
|
|
313
|
+
const effective = deepCopy(resolved);
|
|
314
|
+
this.applyPPrLayer(arg, effective);
|
|
315
|
+
return effective;
|
|
316
|
+
}
|
|
317
|
+
effectivePPrOfStyle(styleId) {
|
|
318
|
+
const existing = this.existingParagraphStyle(styleId);
|
|
319
|
+
const key = existing !== null && existing !== void 0 ? existing : NO_STYLE;
|
|
320
|
+
const cached = this.effectivePPrByStyle.get(key);
|
|
321
|
+
if (cached !== undefined)
|
|
322
|
+
return cached;
|
|
323
|
+
const resolved = deepCopy(this.documentDefaultPPr);
|
|
324
|
+
this.applyPPrLayer(this.getChainPPr(existing), resolved);
|
|
325
|
+
this.effectivePPrByStyle.set(key, resolved);
|
|
326
|
+
return resolved;
|
|
327
|
+
}
|
|
328
|
+
getEffectiveRPr(arg, pPr) {
|
|
329
|
+
if (typeof arg === 'string')
|
|
330
|
+
return this.effectiveRPrOfStyle(arg);
|
|
331
|
+
const effective = deepCopy(this.documentDefaultRPr);
|
|
332
|
+
applyRPr(this.getChainRPr(this.paragraphStyleOf(pPr)), effective);
|
|
333
|
+
this.applyCharacterStyleAndDirect(arg, effective);
|
|
334
|
+
return effective;
|
|
335
|
+
}
|
|
336
|
+
effectiveRPrOfStyle(styleId) {
|
|
337
|
+
const cached = this.effectiveRPrByStyle.get(styleId);
|
|
338
|
+
if (cached !== undefined)
|
|
339
|
+
return cached;
|
|
340
|
+
if (this.getLiveStyle(styleId) === undefined) {
|
|
341
|
+
this.logMissing(styleId);
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
const resolved = deepCopy(this.documentDefaultRPr);
|
|
345
|
+
applyRPr(this.getChainRPr(styleId), resolved);
|
|
346
|
+
this.effectiveRPrByStyle.set(styleId, resolved);
|
|
347
|
+
return resolved;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* The character style's chain, then the direct formatting.
|
|
351
|
+
*
|
|
352
|
+
* The character style is a **level** of the style hierarchy over the paragraph's, so its
|
|
353
|
+
* toggle properties are XORed with what is beneath rather than overriding it (ECMA-376-1
|
|
354
|
+
* §17.7.3). The direct formatting after it is not a level: an explicit value there is used
|
|
355
|
+
* as it stands.
|
|
356
|
+
*/
|
|
357
|
+
applyCharacterStyleAndDirect(rPr, effective) {
|
|
358
|
+
var _a;
|
|
359
|
+
const runStyleId = (_a = rPr === null || rPr === void 0 ? void 0 : rPr.rStyle) === null || _a === void 0 ? void 0 : _a.val;
|
|
360
|
+
if (runStyleId !== undefined) {
|
|
361
|
+
if (this.getLiveStyle(runStyleId) === undefined) {
|
|
362
|
+
this.logMissing(runStyleId);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
applyStyleLevel(this.getChainRPr(runStyleId), effective, this.documentDefaultRPr);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (hasDirectFormattingRPr(rPr))
|
|
369
|
+
applyRPr(rPr, effective);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* The run properties of the paragraph mark: document defaults, the paragraph style's run
|
|
373
|
+
* properties, then the `w:pPr`'s own `w:rPr`. What sizes an empty paragraph, and what a list
|
|
374
|
+
* label starts from.
|
|
375
|
+
*/
|
|
376
|
+
getEffectiveParagraphMarkRPr(pPr) {
|
|
377
|
+
const effective = deepCopy(this.documentDefaultRPr);
|
|
378
|
+
applyRPr(this.getChainRPr(this.paragraphStyleOf(pPr)), effective);
|
|
379
|
+
if ((pPr === null || pPr === void 0 ? void 0 : pPr.rPr) !== undefined)
|
|
380
|
+
applyRPr(pPr.rPr, effective);
|
|
381
|
+
return effective;
|
|
382
|
+
}
|
|
383
|
+
/** Whether the run states any formatting of its own (docx4j's deprecated `hasDirectRPrFormatting`). */
|
|
384
|
+
hasDirectRPrFormatting(rPr) {
|
|
385
|
+
return hasDirectFormattingRPr(rPr);
|
|
386
|
+
}
|
|
387
|
+
// ------------------------------------------------------------------ tables
|
|
388
|
+
/**
|
|
389
|
+
* The table style which applies, merged root-first down its `w:basedOn` chain, then the
|
|
390
|
+
* table's own `w:tblPr` over it.
|
|
391
|
+
*
|
|
392
|
+
* Word's built-in "Normal Table" (`w:tblInd` 0; cell margins 108 twips left and right, 0 top
|
|
393
|
+
* and bottom) underlies a table naming no style and a table whose chain reaches the
|
|
394
|
+
* document's default table style - and it is the built-in that applies, not the document's
|
|
395
|
+
* definition of that style (measured, CR-015 probe styles-table-default). So the default
|
|
396
|
+
* style's own layer is skipped in favour of the built-in, and a chain that does not reach it
|
|
397
|
+
* starts from nothing.
|
|
398
|
+
*
|
|
399
|
+
* A new `Style` each call, with a non-null `w:tblPr`.
|
|
400
|
+
*/
|
|
401
|
+
getEffectiveTableStyle(tblPr) {
|
|
402
|
+
var _a, _b;
|
|
403
|
+
const styleId = (_a = tblPr === null || tblPr === void 0 ? void 0 : tblPr.tblStyle) === null || _a === void 0 ? void 0 : _a.val;
|
|
404
|
+
const chain = styleId === undefined ? [] : this.ancestry(styleId);
|
|
405
|
+
const builtIn = chain.length === 0
|
|
406
|
+
|| (this.defaultTableStyleId !== undefined && chain.some((s) => s.styleId === this.defaultTableStyleId));
|
|
407
|
+
const result = builtIn ? this.builtInTableNormal() : emptyTableStyle();
|
|
408
|
+
for (const layer of chain) {
|
|
409
|
+
// the built-in stands in for the document's definition of the default table style
|
|
410
|
+
if (this.defaultTableStyleId !== undefined && layer.styleId === this.defaultTableStyleId)
|
|
411
|
+
continue;
|
|
412
|
+
applyStyle(layer, result);
|
|
413
|
+
}
|
|
414
|
+
if (tblPr !== undefined) {
|
|
415
|
+
result.tblPr = applyTblPr(tblPr, result.tblPr);
|
|
416
|
+
}
|
|
417
|
+
(_b = result.tblPr) !== null && _b !== void 0 ? _b : (result.tblPr = { TYPE_NAME: 'org_docx4j_wml.CTTblPrBase' });
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Whether a table's style chain reaches the document's default table style - the flag
|
|
422
|
+
* {@link getEffectiveTableStyle} decides Word's built-in Normal Table by (a table naming no
|
|
423
|
+
* style counts as reaching it).
|
|
424
|
+
*/
|
|
425
|
+
reachesDefaultTableStyle(tblPr) {
|
|
426
|
+
var _a;
|
|
427
|
+
const styleId = (_a = tblPr === null || tblPr === void 0 ? void 0 : tblPr.tblStyle) === null || _a === void 0 ? void 0 : _a.val;
|
|
428
|
+
const chain = styleId === undefined ? [] : this.ancestry(styleId);
|
|
429
|
+
return chain.length === 0
|
|
430
|
+
|| (this.defaultTableStyleId !== undefined && chain.some((s) => s.styleId === this.defaultTableStyleId));
|
|
431
|
+
}
|
|
432
|
+
/** Word's built-in Normal Table, as a style: what it applies whatever the document's own definition says. */
|
|
433
|
+
builtInTableNormal() {
|
|
434
|
+
var _a;
|
|
435
|
+
const style = emptyTableStyle();
|
|
436
|
+
style.styleId = (_a = this.defaultTableStyleId) !== null && _a !== void 0 ? _a : 'TableNormal';
|
|
437
|
+
style.name = { TYPE_NAME: 'org_docx4j_wml.Style.Name', val: 'Normal Table' };
|
|
438
|
+
const tblPr = style.tblPr;
|
|
439
|
+
tblPr.tblInd = twips(0);
|
|
440
|
+
tblPr.tblCellMar = {
|
|
441
|
+
TYPE_NAME: 'org_docx4j_wml.CTTblCellMar',
|
|
442
|
+
top: twips(0),
|
|
443
|
+
left: twips(WORD_DEFAULT_CELL_MARGIN_TWIPS),
|
|
444
|
+
bottom: twips(0),
|
|
445
|
+
right: twips(WORD_DEFAULT_CELL_MARGIN_TWIPS),
|
|
446
|
+
};
|
|
447
|
+
return style;
|
|
448
|
+
}
|
|
449
|
+
// ------------------------------------------------------------------ headings and known styles
|
|
450
|
+
/**
|
|
451
|
+
* The level of a heading style from its **id** ("Heading2" -> 2), or -1. docx4j keeps this
|
|
452
|
+
* because callers pass a style id; {@link headingLevelByName} is the rule Word applies, and
|
|
453
|
+
* is what resolution uses.
|
|
454
|
+
*/
|
|
455
|
+
getLvlFromHeadingStyle(styleId) {
|
|
456
|
+
if (!styleId.startsWith(HEADING_STYLE))
|
|
457
|
+
return -1;
|
|
458
|
+
const rest = styleId.slice(HEADING_STYLE.length).trim();
|
|
459
|
+
if (!/^\d+$/.test(rest))
|
|
460
|
+
return -1;
|
|
461
|
+
return Number(rest);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Make a style available for use in the document, adding it to the styles part - and,
|
|
465
|
+
* recursively, whatever it is `w:basedOn` and whatever it is linked to. Given a style id,
|
|
466
|
+
* the style must be one this package knows (there is no KnownStyles.xml here yet; a style id
|
|
467
|
+
* that is not already live and not supplied as an object returns false).
|
|
468
|
+
*/
|
|
469
|
+
activateStyle(style) {
|
|
470
|
+
if (typeof style !== 'string' && this.stylesArePrivate()) {
|
|
471
|
+
throw new Docx4JException('activateStyle writes into the styles part: await styleDefinitionsPart.getContents() and refresh() the resolver first');
|
|
472
|
+
}
|
|
473
|
+
if (typeof style === 'string') {
|
|
474
|
+
if (this.getLiveStyle(style) !== undefined)
|
|
475
|
+
return true;
|
|
476
|
+
log.warn(`Unknown style: ${style}`);
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
return this.activate(style, true);
|
|
480
|
+
}
|
|
481
|
+
activate(style, replace) {
|
|
482
|
+
var _a, _b, _c;
|
|
483
|
+
if (style.styleId === undefined)
|
|
484
|
+
return false;
|
|
485
|
+
const styles = this.source.styles;
|
|
486
|
+
if (styles === undefined)
|
|
487
|
+
return false;
|
|
488
|
+
const list = ((_a = styles.style) !== null && _a !== void 0 ? _a : (styles.style = []));
|
|
489
|
+
const existing = this.getLiveStyle(style.styleId);
|
|
490
|
+
if (existing !== undefined) {
|
|
491
|
+
if (!replace)
|
|
492
|
+
return false;
|
|
493
|
+
const index = list.indexOf(existing);
|
|
494
|
+
if (index >= 0)
|
|
495
|
+
list.splice(index, 1);
|
|
496
|
+
}
|
|
497
|
+
list.push(style);
|
|
498
|
+
this.liveStyles.set(style.styleId, style);
|
|
499
|
+
this.scannedStyleCount = list.length;
|
|
500
|
+
// resolution of this style (and of anything based on it) has to be recomputed
|
|
501
|
+
this.chainPPrCache.clear();
|
|
502
|
+
this.chainRPrCache.clear();
|
|
503
|
+
this.effectivePPrByStyle.clear();
|
|
504
|
+
this.effectiveRPrByStyle.clear();
|
|
505
|
+
let ok = true;
|
|
506
|
+
const basedOn = (_b = style.basedOn) === null || _b === void 0 ? void 0 : _b.val;
|
|
507
|
+
if (basedOn !== undefined)
|
|
508
|
+
ok = this.activateStyle(basedOn);
|
|
509
|
+
const link = (_c = style.link) === null || _c === void 0 ? void 0 : _c.val;
|
|
510
|
+
if (link !== undefined)
|
|
511
|
+
ok = this.activateStyle(link) && ok;
|
|
512
|
+
return ok;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function twips(w) {
|
|
516
|
+
return { TYPE_NAME: 'org_docx4j_wml.TblWidth', type: 'dxa', w };
|
|
517
|
+
}
|
|
518
|
+
function emptyTableStyle() {
|
|
519
|
+
return {
|
|
520
|
+
TYPE_NAME: 'org_docx4j_wml.Style',
|
|
521
|
+
type: 'table',
|
|
522
|
+
tblPr: { TYPE_NAME: 'org_docx4j_wml.CTTblPrBase' },
|
|
523
|
+
};
|
|
524
|
+
}
|