@docx4j/core-ts 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/html/convert.d.mts +116 -0
- package/dist/html/convert.mjs +541 -0
- package/dist/html/elements.d.mts +19 -0
- package/dist/html/elements.mjs +182 -0
- package/dist/html/index.d.mts +2 -0
- package/dist/html/index.mjs +4 -0
- package/dist/model/content/Body.mjs +9 -1
- package/dist/model/content/ContentControl.d.mts +5 -1
- package/dist/model/content/ContentControl.mjs +18 -5
- package/dist/model/content/InlinePicture.d.mts +18 -3
- package/dist/model/content/InlinePicture.mjs +44 -7
- package/dist/model/content/Paragraph.d.mts +11 -11
- package/dist/model/content/Paragraph.mjs +30 -43
- package/dist/model/content/Range.mjs +3 -2
- package/dist/model/content/Table.d.mts +38 -0
- package/dist/model/content/Table.mjs +80 -2
- package/dist/model/content/index.d.mts +2 -1
- package/dist/model/content/index.mjs +2 -1
- package/dist/model/content/stylesFacade.d.mts +4 -2
- package/dist/model/content/stylesFacade.mjs +23 -6
- package/dist/model/content/tableColumns.d.mts +48 -0
- package/dist/model/content/tableColumns.mjs +484 -0
- package/dist/model/content/tracking.d.mts +14 -0
- package/dist/model/content/tracking.mjs +19 -10
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +6 -1
- package/dist/model/customxml/CustomXmlPartCollection.mjs +19 -3
- package/dist/model/customxml/XmlMapping.d.mts +20 -4
- package/dist/model/customxml/XmlMapping.mjs +44 -6
- package/dist/model/customxml/bindings.d.mts +13 -3
- package/dist/model/customxml/bindings.mjs +38 -7
- package/dist/model/customxml/index.d.mts +4 -1
- package/dist/model/customxml/index.mjs +4 -1
- package/dist/model/customxml/insert.d.mts +10 -0
- package/dist/model/customxml/insert.mjs +13 -0
- package/dist/model/customxml/opendope.d.mts +32 -0
- package/dist/model/customxml/opendope.mjs +56 -0
- package/dist/model/customxml/pictures.d.mts +54 -0
- package/dist/model/customxml/pictures.mjs +186 -0
- package/dist/model/customxml/xhtml.d.mts +42 -0
- package/dist/model/customxml/xhtml.mjs +162 -0
- package/dist/model/fonts/RunFontSelector.d.mts +8 -1
- package/dist/model/fonts/RunFontSelector.mjs +6 -5
- package/dist/model/properties/PropertyResolver.d.mts +110 -10
- package/dist/model/properties/PropertyResolver.mjs +300 -31
- package/dist/model/properties/index.d.mts +3 -0
- package/dist/model/properties/index.mjs +2 -0
- package/dist/model/properties/table.d.mts +155 -0
- package/dist/model/properties/table.mjs +315 -0
- package/dist/model/properties/tableStyleConditions.d.mts +101 -0
- package/dist/model/properties/tableStyleConditions.mjs +296 -0
- package/dist/packages/WordprocessingMLPackage.mjs +1 -0
- package/dist/parts/wml/knownStyles.d.mts +1 -0
- package/dist/parts/wml/knownStyles.mjs +2233 -0
- package/dist/parts/wml/placeholderStyle.d.mts +3 -0
- package/dist/parts/wml/placeholderStyle.mjs +13 -0
- package/package.json +7 -2
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { find } from '../content/tree.mjs';
|
|
2
|
+
import { addImage, addImagePart, writableWidthEmu } from '../content/InlinePicture.mjs';
|
|
3
|
+
import { ImagePart } from '../../parts/BinaryPart.mjs';
|
|
4
|
+
import { base64Decode, base64Encode } from '../../xml/dom.mjs';
|
|
5
|
+
import { enclosingCellOf } from '../properties/table.mjs';
|
|
6
|
+
import { tagParamsOf, selectEntryNode, PICTURE_HANDLER } from './opendope.mjs';
|
|
7
|
+
const EMU_PER_TWIP = 635;
|
|
8
|
+
const BLIP = 'org_docx4j_dml.CTBlip';
|
|
9
|
+
/** Whether a control is bound to a picture through its tag (`od:Handler=picture` with an `od:xpath`). */
|
|
10
|
+
export function isPictureHandlerBound(control) {
|
|
11
|
+
const params = tagParamsOf(control.tag);
|
|
12
|
+
return params.get('od:Handler') === PICTURE_HANDLER && params.has('od:xpath');
|
|
13
|
+
}
|
|
14
|
+
/** The tag's `width` parameter, read as `PictureWidth` says. */
|
|
15
|
+
export function pictureWidthOf(params) {
|
|
16
|
+
const width = params.get('width');
|
|
17
|
+
if (width === undefined)
|
|
18
|
+
return { kind: 'keep' };
|
|
19
|
+
const twips = /^\d+$/.test(width.trim()) ? Number(width) : 0;
|
|
20
|
+
return twips > 0 ? { kind: 'twips', twips } : { kind: 'auto' };
|
|
21
|
+
}
|
|
22
|
+
/** The node's value as base64: a data URL's prefix dropped, whitespace left to the lenient decoder. */
|
|
23
|
+
function base64Of(value) {
|
|
24
|
+
return value.replace(/^\s*data:[^,]*,/, '').trim();
|
|
25
|
+
}
|
|
26
|
+
function messageOf(e) {
|
|
27
|
+
return e instanceof Error ? e.message : String(e);
|
|
28
|
+
}
|
|
29
|
+
/** The first `a:blip` anywhere in the control's content, whose `r:embed` is the image. */
|
|
30
|
+
function firstBlipOf(control) {
|
|
31
|
+
var _a;
|
|
32
|
+
for (const blip of find((_a = control.sdt.sdtContent) !== null && _a !== void 0 ? _a : {}, BLIP))
|
|
33
|
+
return blip;
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/** A width stated in twips (`dxa`, or no type), else undefined. */
|
|
37
|
+
function twipsOf(width) {
|
|
38
|
+
return width && typeof width.w === 'number' && width.w >= 0 && (width.type === undefined || width.type === 'dxa') ? width.w : undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Word's default cell margins, 108 twips left and right (the `Normal Table` style's
|
|
42
|
+
* `w:tblCellMar`, which every table inherits), taken where neither the cell nor the table states
|
|
43
|
+
* one; a table style stating other margins is not read.
|
|
44
|
+
*/
|
|
45
|
+
const DEFAULT_CELL_MARGIN_TWIPS = 108;
|
|
46
|
+
/** The cell's left and right margins together, in twips: `w:tcMar`, else the table's `w:tblCellMar`, else Word's defaults. */
|
|
47
|
+
function cellMarginsTwips(tc, tbl) {
|
|
48
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
49
|
+
const own = (_a = tc.tcPr) === null || _a === void 0 ? void 0 : _a.tcMar;
|
|
50
|
+
const table = (_b = tbl.tblPr) === null || _b === void 0 ? void 0 : _b.tblCellMar;
|
|
51
|
+
const left = (_e = (_c = twipsOf(own === null || own === void 0 ? void 0 : own.left)) !== null && _c !== void 0 ? _c : twipsOf((_d = table === null || table === void 0 ? void 0 : table.left) !== null && _d !== void 0 ? _d : table === null || table === void 0 ? void 0 : table.start)) !== null && _e !== void 0 ? _e : DEFAULT_CELL_MARGIN_TWIPS;
|
|
52
|
+
const right = (_h = (_f = twipsOf(own === null || own === void 0 ? void 0 : own.right)) !== null && _f !== void 0 ? _f : twipsOf((_g = table === null || table === void 0 ? void 0 : table.right) !== null && _g !== void 0 ? _g : table === null || table === void 0 ? void 0 : table.end)) !== null && _h !== void 0 ? _h : DEFAULT_CELL_MARGIN_TWIPS;
|
|
53
|
+
return left + right;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The width a new picture must fit, in EMU: the cell's `w:tcW` less its margins when the control
|
|
57
|
+
* is in a table cell and the width is stated in twips (a percentage or `auto` falls to the page),
|
|
58
|
+
* else the page's text width; narrowed to `width=N`. Undefined where nothing states a width (a
|
|
59
|
+
* header's body has no `w:sectPr`): the natural size then.
|
|
60
|
+
*/
|
|
61
|
+
function maxWidthEmu(control, width) {
|
|
62
|
+
var _a;
|
|
63
|
+
const cell = enclosingCellOf(control.element.value);
|
|
64
|
+
const tcW = cell ? twipsOf((_a = cell.tc.tcPr) === null || _a === void 0 ? void 0 : _a.tcW) : undefined;
|
|
65
|
+
const inner = cell && tcW !== undefined ? tcW - cellMarginsTwips(cell.tc, cell.tbl) : undefined;
|
|
66
|
+
const cellEmu = inner !== undefined && inner > 0 ? inner * EMU_PER_TWIP : undefined;
|
|
67
|
+
const text = cellEmu !== null && cellEmu !== void 0 ? cellEmu : writableWidthEmu(control.parentBody.container);
|
|
68
|
+
if (width.kind === 'twips') {
|
|
69
|
+
const wanted = width.twips * EMU_PER_TWIP;
|
|
70
|
+
return text === undefined ? wanted : Math.min(wanted, text);
|
|
71
|
+
}
|
|
72
|
+
return text;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Binds one control to a value: base64 image data (a data URL accepted). With `keep`, the first
|
|
76
|
+
* `a:blip`'s `r:embed` is pointed at a new image part and the drawing is left as it is; a picture
|
|
77
|
+
* control holding no picture gets a new inline one at its natural size instead (docx4j's pre-v3
|
|
78
|
+
* fallback), a tag-bound control holding none is left and noted. Otherwise the control's content
|
|
79
|
+
* becomes one run holding a new inline picture, sized as `PictureWidth` says, in the first
|
|
80
|
+
* paragraph of a block-level control (its properties kept) or as a run-level control's content.
|
|
81
|
+
* An empty value, a value that is not an image this package reads (PNG, JPEG, GIF, BMP; SVG where
|
|
82
|
+
* the drawing is kept, since it has no pixel size to place a new picture at), and a body with no
|
|
83
|
+
* part each leave the control as it was, with a note. The image part the control showed before
|
|
84
|
+
* stays in the package, as docx4j leaves it.
|
|
85
|
+
*/
|
|
86
|
+
export function bindPicture(control, value, width, label) {
|
|
87
|
+
const base64 = base64Of(value);
|
|
88
|
+
if (base64 === '')
|
|
89
|
+
return { done: false, note: `${label}: the node is empty; the control is left as it is` };
|
|
90
|
+
const source = control.parentBody.part;
|
|
91
|
+
if (!source)
|
|
92
|
+
return { done: false, note: `${label}: the control's body has no part to hold an image` };
|
|
93
|
+
if (width.kind === 'keep') {
|
|
94
|
+
const blip = firstBlipOf(control);
|
|
95
|
+
if (blip) {
|
|
96
|
+
try {
|
|
97
|
+
blip.embed = addImagePart(source, base64).relId;
|
|
98
|
+
}
|
|
99
|
+
catch (e) {
|
|
100
|
+
return { done: false, note: `${label}: not an image this package reads (${messageOf(e)})` };
|
|
101
|
+
}
|
|
102
|
+
control.isShowingPlaceholder = false;
|
|
103
|
+
return { done: true };
|
|
104
|
+
}
|
|
105
|
+
if (control.type !== 'Picture')
|
|
106
|
+
return { done: false, note: `${label}: the control holds no a:blip to point at the image (od:Handler=picture without width keeps the drawing)` };
|
|
107
|
+
width = { kind: 'auto' };
|
|
108
|
+
}
|
|
109
|
+
let run;
|
|
110
|
+
try {
|
|
111
|
+
run = addImage(source, base64, control.parentBody.container, maxWidthEmu(control, width)).run;
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
return { done: false, note: `${label}: not an image this package reads (${messageOf(e)})` };
|
|
115
|
+
}
|
|
116
|
+
control.setBoundContent([run]);
|
|
117
|
+
return { done: true };
|
|
118
|
+
}
|
|
119
|
+
/** Binds one tag-bound control (shape b): the entry's node, the tag's width. */
|
|
120
|
+
export function applyPictureHandlerTo(control, parts) {
|
|
121
|
+
var _a;
|
|
122
|
+
const params = tagParamsOf(control.tag);
|
|
123
|
+
const entryId = (_a = params.get('od:xpath')) !== null && _a !== void 0 ? _a : '';
|
|
124
|
+
const selected = selectEntryNode(entryId, parts);
|
|
125
|
+
if ('note' in selected)
|
|
126
|
+
return { done: false, note: selected.note };
|
|
127
|
+
return bindPicture(control, selected.node.text, pictureWidthOf(params), `od:xpath=${entryId}`);
|
|
128
|
+
}
|
|
129
|
+
/** The picture pass over the tag-bound controls, after the text bindings: counted into the result, what was left said in its notes. */
|
|
130
|
+
export function applyPictureHandlersTo(controls, parts, result) {
|
|
131
|
+
var _a;
|
|
132
|
+
for (const control of controls) {
|
|
133
|
+
if (!isPictureHandlerBound(control))
|
|
134
|
+
continue;
|
|
135
|
+
result.bound++;
|
|
136
|
+
const outcome = applyPictureHandlerTo(control, parts);
|
|
137
|
+
if (outcome.done)
|
|
138
|
+
result.updated++;
|
|
139
|
+
else
|
|
140
|
+
result.skipped++;
|
|
141
|
+
if (outcome.note)
|
|
142
|
+
((_a = result.notes) !== null && _a !== void 0 ? _a : (result.notes = [])).push(outcome.note);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The reverse direction for a mapped picture control (docx4j's `UpdateXmlFromDocumentSurface`
|
|
147
|
+
* skips pictures; Word 15 writes the picture back, check 38): the bytes of the image part the
|
|
148
|
+
* first `a:blip` embeds, as base64, into the node. Nothing is written when the node already holds
|
|
149
|
+
* those bytes (compared decoded, so Word's line-wrapped base64 counts as the same), when the
|
|
150
|
+
* control shows no picture, or when the blip's part is not an image part. Asynchronous, since a
|
|
151
|
+
* part's bytes may still be in the container.
|
|
152
|
+
*/
|
|
153
|
+
export async function updateFromPictureControl(control) {
|
|
154
|
+
var _a;
|
|
155
|
+
const mapping = control.xmlMapping;
|
|
156
|
+
if (!mapping.isMapped || control.type !== 'Picture')
|
|
157
|
+
return false;
|
|
158
|
+
const node = mapping.customXmlNode;
|
|
159
|
+
if (!node)
|
|
160
|
+
return false;
|
|
161
|
+
const blip = firstBlipOf(control);
|
|
162
|
+
const source = control.parentBody.part;
|
|
163
|
+
if (!(blip === null || blip === void 0 ? void 0 : blip.embed) || !source)
|
|
164
|
+
return false;
|
|
165
|
+
const part = (_a = source.relationshipsPart) === null || _a === void 0 ? void 0 : _a.getPart(blip.embed);
|
|
166
|
+
if (!(part instanceof ImagePart))
|
|
167
|
+
return false;
|
|
168
|
+
const bytes = await part.getBytes();
|
|
169
|
+
const held = base64Decode(node.text);
|
|
170
|
+
if (held.length === bytes.length && held.every((b, i) => b === bytes[i]))
|
|
171
|
+
return false;
|
|
172
|
+
node.text = base64Encode(bytes);
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
/** `updateFromContentControls`' picture pass: the mapped picture controls, counted into the result. */
|
|
176
|
+
export async function updateFromPictureControls(controls, result) {
|
|
177
|
+
for (const control of controls) {
|
|
178
|
+
if (control.type !== 'Picture' || !control.xmlMapping.isMapped)
|
|
179
|
+
continue;
|
|
180
|
+
result.bound++;
|
|
181
|
+
if (await updateFromPictureControl(control))
|
|
182
|
+
result.updated++;
|
|
183
|
+
else
|
|
184
|
+
result.skipped++;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
|
+
import type { PropertyResolver } from '../properties/index.mjs';
|
|
3
|
+
import type { ContentControl } from '../content/ContentControl.mjs';
|
|
4
|
+
import type { CustomXmlPartLookup } from './XmlMapping.mjs';
|
|
5
|
+
import type { BindingResult } from './bindings.mjs';
|
|
6
|
+
/** What the XHTML pass needs of the package. */
|
|
7
|
+
export interface XhtmlHost {
|
|
8
|
+
numbering: {
|
|
9
|
+
newList(options?: {
|
|
10
|
+
bullet?: boolean;
|
|
11
|
+
}): Promise<string>;
|
|
12
|
+
restart(numId: string): string;
|
|
13
|
+
};
|
|
14
|
+
styles: {
|
|
15
|
+
ensure(ids: readonly string[]): Promise<string[]>;
|
|
16
|
+
};
|
|
17
|
+
requireStyles(ids: Iterable<string>): void;
|
|
18
|
+
getPropertyResolver(): Promise<PropertyResolver>;
|
|
19
|
+
getMainDocumentPart(): {
|
|
20
|
+
styleDefinitionsPart?: {
|
|
21
|
+
readContents(): Promise<wml.Styles>;
|
|
22
|
+
} | undefined;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export interface XhtmlBindingOptions {
|
|
26
|
+
/** The HTML parser: a browser's `DOMParser` by default; jsdom's or linkedom's in Node. */
|
|
27
|
+
parser?: (html: string) => Document;
|
|
28
|
+
}
|
|
29
|
+
/** Whether a control is bound to XHTML through its tag. */
|
|
30
|
+
export declare function isXhtmlBound(control: ContentControl): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Binds one XHTML control. Returns what was done, or a note saying why not: no entry, no part, no
|
|
33
|
+
* node, no parser in this runtime. The content the markup gave that the control cannot hold is in
|
|
34
|
+
* `dropped` (a run-level control's blocks after the first, and what the converter dropped).
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyXhtmlBindingTo(control: ContentControl, parts: CustomXmlPartLookup, host: XhtmlHost, options?: XhtmlBindingOptions): Promise<{
|
|
37
|
+
done: boolean;
|
|
38
|
+
note?: string;
|
|
39
|
+
dropped?: Record<string, number>;
|
|
40
|
+
}>;
|
|
41
|
+
/** The XHTML pass over the controls, after the text bindings: counted into the result, what was left said in its notes. */
|
|
42
|
+
export declare function applyXhtmlBindingsTo(controls: ContentControl[], parts: CustomXmlPartLookup, host: XhtmlHost, result: BindingResult, options?: XhtmlBindingOptions): Promise<void>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { deepCopy } from '@docx4j/generated-objects-ts';
|
|
2
|
+
import { Namespaces } from '../../parts/Namespaces.mjs';
|
|
3
|
+
import { typeNameOf, linkParents, childrenOf } from '../content/tree.mjs';
|
|
4
|
+
import { contentOf } from '../content/ooxml.mjs';
|
|
5
|
+
import { convertHtml, styleLookupOf } from '../../html/convert.mjs';
|
|
6
|
+
import { blocksToXml, needsOf, HYPERLINK_STYLE } from '../../html/elements.mjs';
|
|
7
|
+
import { tagParamsOf, xpathsEntriesOf, XHTML_CONTENT_TYPE } from './opendope.mjs';
|
|
8
|
+
/** Whether a control is bound to XHTML through its tag. */
|
|
9
|
+
export function isXhtmlBound(control) {
|
|
10
|
+
const params = tagParamsOf(control.tag);
|
|
11
|
+
return params.get('od:ContentType') === XHTML_CONTENT_TYPE && params.has('od:xpath');
|
|
12
|
+
}
|
|
13
|
+
async function lookupFor(host) {
|
|
14
|
+
var _a, _b, _c;
|
|
15
|
+
const entries = [];
|
|
16
|
+
const part = host.getMainDocumentPart().styleDefinitionsPart;
|
|
17
|
+
if (part) {
|
|
18
|
+
const styles = await part.readContents();
|
|
19
|
+
for (const s of (_a = styles.style) !== null && _a !== void 0 ? _a : []) {
|
|
20
|
+
if (!s.styleId)
|
|
21
|
+
continue;
|
|
22
|
+
if (s.type !== undefined && s.type !== 'paragraph' && s.type !== 'character')
|
|
23
|
+
continue;
|
|
24
|
+
if (s.hidden !== undefined && s.hidden.val !== false)
|
|
25
|
+
continue;
|
|
26
|
+
entries.push({ id: s.styleId, name: (_c = (_b = s.name) === null || _b === void 0 ? void 0 : _b.val) !== null && _c !== void 0 ? _c : s.styleId });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const resolver = await host.getPropertyResolver();
|
|
30
|
+
return styleLookupOf(entries, resolver.getStyle('TableGrid') ? ['TableGrid'] : []);
|
|
31
|
+
}
|
|
32
|
+
/** The object behind an element: a parsed fragment's elements are wrapped (`{ name, value }`), the tree's own may not be. */
|
|
33
|
+
function innerOf(element) {
|
|
34
|
+
const e = element;
|
|
35
|
+
return e.name !== undefined && e.value !== undefined && typeof e.value === 'object' ? e.value : element;
|
|
36
|
+
}
|
|
37
|
+
/** The control's run properties onto every run the markup left without any (a hyperlink's runs included). */
|
|
38
|
+
function applyRunProperties(elements, rPr) {
|
|
39
|
+
if (!rPr)
|
|
40
|
+
return;
|
|
41
|
+
const visit = (items) => {
|
|
42
|
+
if (!items)
|
|
43
|
+
return;
|
|
44
|
+
for (const item of items) {
|
|
45
|
+
const name = typeNameOf(item);
|
|
46
|
+
const inner = innerOf(item);
|
|
47
|
+
if (name === 'org_docx4j_wml.R') {
|
|
48
|
+
const run = inner;
|
|
49
|
+
if (!run.rPr)
|
|
50
|
+
run.rPr = deepCopy(rPr);
|
|
51
|
+
}
|
|
52
|
+
else if (name !== undefined) {
|
|
53
|
+
visit(childrenOf(inner));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
visit(elements);
|
|
58
|
+
}
|
|
59
|
+
function inlineContentOf(paragraph) {
|
|
60
|
+
var _a;
|
|
61
|
+
const content = (_a = childrenOf(innerOf(paragraph))) !== null && _a !== void 0 ? _a : [];
|
|
62
|
+
return content.filter((item) => { const n = typeNameOf(item); return n === 'org_docx4j_wml.R' || n === 'org_docx4j_wml.P.Hyperlink'; });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Binds one XHTML control. Returns what was done, or a note saying why not: no entry, no part, no
|
|
66
|
+
* node, no parser in this runtime. The content the markup gave that the control cannot hold is in
|
|
67
|
+
* `dropped` (a run-level control's blocks after the first, and what the converter dropped).
|
|
68
|
+
*/
|
|
69
|
+
export async function applyXhtmlBindingTo(control, parts, host, options = {}) {
|
|
70
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
71
|
+
var _j;
|
|
72
|
+
const params = tagParamsOf(control.tag);
|
|
73
|
+
const entryId = params.get('od:xpath');
|
|
74
|
+
const entry = xpathsEntriesOf(parts).get(entryId);
|
|
75
|
+
if (!entry)
|
|
76
|
+
return { done: false, note: `od:xpath=${entryId}: no such entry in the XPaths part` };
|
|
77
|
+
const part = (_a = parts.getItem(entry.storeItemID)) !== null && _a !== void 0 ? _a : parts.items.find((p) => p.id.replace(/[{}]/g, '').toLowerCase() === entry.storeItemID.replace(/[{}]/g, '').toLowerCase());
|
|
78
|
+
if (!part)
|
|
79
|
+
return { done: false, note: `od:xpath=${entryId}: no custom XML part ${entry.storeItemID}` };
|
|
80
|
+
const node = part.selectSingleNode(entry.xpath, entry.prefixMappings);
|
|
81
|
+
if (!node)
|
|
82
|
+
return { done: false, note: `od:xpath=${entryId}: ${entry.xpath} selects nothing` };
|
|
83
|
+
const parser = (_b = options.parser) !== null && _b !== void 0 ? _b : (typeof DOMParser === 'function' ? (h) => new DOMParser().parseFromString(h, 'text/html') : undefined);
|
|
84
|
+
if (!parser)
|
|
85
|
+
return { done: false, note: `od:xpath=${entryId}: XHTML needs an HTML parser (applyBindings({ html: { parser } }))` };
|
|
86
|
+
const converted = convertHtml(node.text, await lookupFor(host), { parser });
|
|
87
|
+
const dropped = { ...converted.report.dropped };
|
|
88
|
+
const { blocks } = converted;
|
|
89
|
+
// What the document must give first: the styles the markup names, a definition per list, a relationship per link.
|
|
90
|
+
if (converted.report.stylesWanted.length > 0) {
|
|
91
|
+
try {
|
|
92
|
+
await host.styles.ensure(converted.report.stylesWanted);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
dropped['styles the defaults lack'] = ((_c = dropped['styles the defaults lack']) !== null && _c !== void 0 ? _c : 0) + converted.report.stylesWanted.length;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const needs = needsOf(blocks);
|
|
99
|
+
const lists = new Map();
|
|
100
|
+
let firstNumbered;
|
|
101
|
+
for (const { key, bullet } of needs.lists) {
|
|
102
|
+
if (bullet)
|
|
103
|
+
lists.set(key, await host.numbering.newList({ bullet: true }));
|
|
104
|
+
else if (firstNumbered === undefined) {
|
|
105
|
+
firstNumbered = await host.numbering.newList({ bullet: false });
|
|
106
|
+
lists.set(key, firstNumbered);
|
|
107
|
+
}
|
|
108
|
+
else
|
|
109
|
+
lists.set(key, host.numbering.restart(firstNumbered));
|
|
110
|
+
}
|
|
111
|
+
const links = new Map();
|
|
112
|
+
const rels = needs.links.length > 0 ? (_d = control.parentBody.part) === null || _d === void 0 ? void 0 : _d.getRelationshipsPart(true) : undefined;
|
|
113
|
+
if (rels) {
|
|
114
|
+
for (const address of needs.links)
|
|
115
|
+
links.set(address, rels.addExternalRelationship(Namespaces.HYPERLINK, address).id);
|
|
116
|
+
host.requireStyles([HYPERLINK_STYLE]);
|
|
117
|
+
}
|
|
118
|
+
else if (needs.links.length > 0)
|
|
119
|
+
dropped['links'] = ((_e = dropped['links']) !== null && _e !== void 0 ? _e : 0) + needs.links.length;
|
|
120
|
+
const elements = await contentOf(blocksToXml(blocks, { numId: (key) => lists.get(key), relId: (address) => links.get(address) }));
|
|
121
|
+
applyRunProperties(elements, control.runProperties);
|
|
122
|
+
const sdt = control.sdt;
|
|
123
|
+
(_f = sdt.sdtContent) !== null && _f !== void 0 ? _f : (sdt.sdtContent = {});
|
|
124
|
+
const content = ((_g = (_j = sdt.sdtContent).content) !== null && _g !== void 0 ? _g : (_j.content = []));
|
|
125
|
+
if (control.form === 'Run') {
|
|
126
|
+
// A run-level control holds inline content: the first paragraph's, the rest reported.
|
|
127
|
+
const first = elements.find((e) => typeNameOf(e) === 'org_docx4j_wml.P');
|
|
128
|
+
const inlines = first ? inlineContentOf(first) : [];
|
|
129
|
+
const rest = elements.length - (first ? 1 : 0);
|
|
130
|
+
if (rest > 0)
|
|
131
|
+
dropped['blocks after the first, in a run-level control'] = ((_h = dropped['blocks after the first, in a run-level control']) !== null && _h !== void 0 ? _h : 0) + rest;
|
|
132
|
+
content.length = 0;
|
|
133
|
+
content.push(...inlines);
|
|
134
|
+
linkParents(content, sdt.sdtContent);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
content.length = 0;
|
|
138
|
+
content.push(...elements);
|
|
139
|
+
linkParents(content, sdt.sdtContent);
|
|
140
|
+
}
|
|
141
|
+
control.isShowingPlaceholder = false;
|
|
142
|
+
return Object.keys(dropped).length > 0 ? { done: true, dropped } : { done: true };
|
|
143
|
+
}
|
|
144
|
+
/** The XHTML pass over the controls, after the text bindings: counted into the result, what was left said in its notes. */
|
|
145
|
+
export async function applyXhtmlBindingsTo(controls, parts, host, result, options = {}) {
|
|
146
|
+
var _a, _b;
|
|
147
|
+
for (const control of controls) {
|
|
148
|
+
if (!isXhtmlBound(control))
|
|
149
|
+
continue;
|
|
150
|
+
result.bound++;
|
|
151
|
+
const outcome = await applyXhtmlBindingTo(control, parts, host, options);
|
|
152
|
+
if (outcome.done)
|
|
153
|
+
result.updated++;
|
|
154
|
+
else
|
|
155
|
+
result.skipped++;
|
|
156
|
+
if (outcome.note)
|
|
157
|
+
((_a = result.notes) !== null && _a !== void 0 ? _a : (result.notes = [])).push(outcome.note);
|
|
158
|
+
if (outcome.dropped)
|
|
159
|
+
for (const [kind, n] of Object.entries(outcome.dropped))
|
|
160
|
+
((_b = result.notes) !== null && _b !== void 0 ? _b : (result.notes = [])).push(`${control.tag}: dropped ${kind} (${n})`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
2
|
import type { PropertyResolver } from '../properties/PropertyResolver.mjs';
|
|
3
|
+
import type { CellContext } from '../properties/table.mjs';
|
|
3
4
|
import { type ThemeFontLang, type ThemeSource } from './ThemeFonts.mjs';
|
|
4
5
|
import { type DefaultTheme } from './defaultTheme.mjs';
|
|
5
6
|
/** Word's built-in default where the document defaults name no font at all (docx4j CR-016
|
|
@@ -41,6 +42,11 @@ export interface RunFontSelectorSource {
|
|
|
41
42
|
export interface SpansOptions {
|
|
42
43
|
/** True where the caller has resolved the run's effective properties already. */
|
|
43
44
|
rPrIsEffective?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The paragraph's table context (`PropertyResolver.cellContextOf(p)`, or a tracker's), so a run
|
|
47
|
+
* in a table cell is resolved with its table style's formatting (CR-007; docx4j CR-030 phase 5).
|
|
48
|
+
*/
|
|
49
|
+
cellContext?: CellContext | undefined;
|
|
44
50
|
}
|
|
45
51
|
/** `w:cs` and `w:rtl` are `ST_OnOff`: present without `w:val` means true, `w:val="0"` false. */
|
|
46
52
|
export declare function isOn(value: wml.BooleanDefaultTrue | undefined): boolean;
|
|
@@ -149,8 +155,9 @@ export declare class RunFontSelector {
|
|
|
149
155
|
* at least.
|
|
150
156
|
*
|
|
151
157
|
* @param rPrIsEffective true where the caller has resolved the run's properties already
|
|
158
|
+
* @param cellContext the paragraph's table context, where it is in a table cell (CR-007)
|
|
152
159
|
*/
|
|
153
|
-
documentFontFor(pPr: wml.PPr | undefined, rPr: wml.RPr | undefined, codePoint: number, rPrIsEffective?: boolean): string;
|
|
160
|
+
documentFontFor(pPr: wml.PPr | undefined, rPr: wml.RPr | undefined, codePoint: number, rPrIsEffective?: boolean, cellContext?: CellContext | undefined): string;
|
|
154
161
|
/**
|
|
155
162
|
* The run's text folded into maximal stretches of one document font.
|
|
156
163
|
*
|
|
@@ -173,10 +173,10 @@ export class RunFontSelector {
|
|
|
173
173
|
return this.defaultFont;
|
|
174
174
|
}
|
|
175
175
|
/** The run's effective properties, never undefined. */
|
|
176
|
-
effectiveRPr(pPr, rPr, rPrIsEffective) {
|
|
176
|
+
effectiveRPr(pPr, rPr, rPrIsEffective, cellContext) {
|
|
177
177
|
var _a;
|
|
178
178
|
if (!rPrIsEffective && this.source.resolver !== undefined) {
|
|
179
|
-
return (_a = this.source.resolver.getEffectiveRPr(rPr, pPr)) !== null && _a !== void 0 ? _a : {};
|
|
179
|
+
return (_a = this.source.resolver.getEffectiveRPr(rPr, pPr, cellContext)) !== null && _a !== void 0 ? _a : {};
|
|
180
180
|
}
|
|
181
181
|
return rPr !== null && rPr !== void 0 ? rPr : {};
|
|
182
182
|
}
|
|
@@ -259,10 +259,11 @@ export class RunFontSelector {
|
|
|
259
259
|
* at least.
|
|
260
260
|
*
|
|
261
261
|
* @param rPrIsEffective true where the caller has resolved the run's properties already
|
|
262
|
+
* @param cellContext the paragraph's table context, where it is in a table cell (CR-007)
|
|
262
263
|
*/
|
|
263
|
-
documentFontFor(pPr, rPr, codePoint, rPrIsEffective = false) {
|
|
264
|
+
documentFontFor(pPr, rPr, codePoint, rPrIsEffective = false, cellContext) {
|
|
264
265
|
var _a;
|
|
265
|
-
const effective = this.effectiveRPr(pPr, rPr, rPrIsEffective);
|
|
266
|
+
const effective = this.effectiveRPr(pPr, rPr, rPrIsEffective, cellContext);
|
|
266
267
|
return (_a = this.fontOf(this.slotsOf(pPr, effective), codePoint)) !== null && _a !== void 0 ? _a : this.defaultFont;
|
|
267
268
|
}
|
|
268
269
|
/**
|
|
@@ -280,7 +281,7 @@ export class RunFontSelector {
|
|
|
280
281
|
const spans = [];
|
|
281
282
|
if (text === undefined || text === null || text.length === 0)
|
|
282
283
|
return spans;
|
|
283
|
-
const effective = this.effectiveRPr(pPr, rPr, options.rPrIsEffective === true);
|
|
284
|
+
const effective = this.effectiveRPr(pPr, rPr, options.rPrIsEffective === true, options.cellContext);
|
|
284
285
|
const bold = isOn(effective.b);
|
|
285
286
|
const italic = isOn(effective.i);
|
|
286
287
|
const cs = isOn(effective.cs);
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
|
|
2
2
|
import { NumberingDefinitions } from '../listnumbering/definitions.mjs';
|
|
3
|
+
import { CellContext, TableContext } from './table.mjs';
|
|
3
4
|
/** The parts the resolver reads. Structural, so this module imports no part class. */
|
|
4
5
|
export interface ResolverSource {
|
|
5
6
|
/** The styles part's `w:styles`, or undefined when the package has none. */
|
|
6
7
|
styles?: wml.Styles;
|
|
7
8
|
/** The numbering part's `w:numbering`, or undefined. */
|
|
8
9
|
numbering?: wml.Numbering;
|
|
10
|
+
/**
|
|
11
|
+
* The settings part's `w:settings`, or undefined: read for the compatibility mode and
|
|
12
|
+
* `overrideTableStyleFontSizeAndJustification` (CR-007). A document with none is in mode 12.
|
|
13
|
+
*/
|
|
14
|
+
settings?: wml.CTSettings;
|
|
9
15
|
}
|
|
10
16
|
/** As much of an `XmlPart<T>` as the resolver uses. */
|
|
11
17
|
interface ReadablePart<T> {
|
|
@@ -18,6 +24,7 @@ interface PackageLike {
|
|
|
18
24
|
getMainDocumentPart(): {
|
|
19
25
|
styleDefinitionsPart?: ReadablePart<wml.Styles>;
|
|
20
26
|
numberingDefinitionsPart?: ReadablePart<wml.Numbering>;
|
|
27
|
+
documentSettingsPart?: ReadablePart<wml.CTSettings>;
|
|
21
28
|
};
|
|
22
29
|
}
|
|
23
30
|
/** 108 twips (0.08in): the left and right cell margin of Word's built-in Normal Table. */
|
|
@@ -44,6 +51,17 @@ export declare class PropertyResolver {
|
|
|
44
51
|
/** The document defaults with the chain applied over them: what the style overloads return. */
|
|
45
52
|
private readonly effectivePPrByStyle;
|
|
46
53
|
private readonly effectiveRPrByStyle;
|
|
54
|
+
/** Each table style's `w:basedOn` chain merged, by id; styles only, so `refresh()` clears it. */
|
|
55
|
+
private readonly tableStyleChains;
|
|
56
|
+
/**
|
|
57
|
+
* A paragraph style composed over a table level, document defaults included; by (paragraph
|
|
58
|
+
* style, table level). What the overloads with a context start from, as
|
|
59
|
+
* `getEffectivePPr(styleId)` is what they start from without one.
|
|
60
|
+
*/
|
|
61
|
+
private readonly composedPPrCache;
|
|
62
|
+
private readonly composedRPrCache;
|
|
63
|
+
/** See {@link appliesTableStyleSizeJcException}; read once per `refresh()`. */
|
|
64
|
+
private tableStyleSizeJcException;
|
|
47
65
|
/** Missing styles are logged once each per resolver. */
|
|
48
66
|
private readonly missingLogged;
|
|
49
67
|
private numberingDefinitions;
|
|
@@ -142,6 +160,15 @@ export declare class PropertyResolver {
|
|
|
142
160
|
* naming no style resolves as the default paragraph style does.
|
|
143
161
|
*/
|
|
144
162
|
getEffectivePPr(styleId: string | undefined): wml.PPr;
|
|
163
|
+
/**
|
|
164
|
+
* The paragraph properties which apply to a paragraph in a table cell: as
|
|
165
|
+
* `getEffectivePPr(pPr)`, with the table style's contribution (its own `w:pPr`, then the
|
|
166
|
+
* conditional formats the paragraph is under) between the document defaults and the
|
|
167
|
+
* paragraph's style, and [MS-DOCX]'s justification exception where it applies. An undefined
|
|
168
|
+
* context - a paragraph in no table - resolves exactly as `getEffectivePPr(pPr)`. A live
|
|
169
|
+
* object where the paragraph has no direct formatting: copy it before changing it.
|
|
170
|
+
*/
|
|
171
|
+
getEffectivePPr(pPr: wml.PPr | undefined, cellContext: CellContext | undefined): wml.PPr;
|
|
145
172
|
private effectivePPrOfStyle;
|
|
146
173
|
/**
|
|
147
174
|
* The run properties which apply to a run, given its own `w:rPr` and the `w:pPr` of the
|
|
@@ -158,6 +185,14 @@ export declare class PropertyResolver {
|
|
|
158
185
|
* what it contributes with nothing under it. Undefined when no such style exists.
|
|
159
186
|
*/
|
|
160
187
|
getEffectiveRPr(styleId: string): wml.RPr | undefined;
|
|
188
|
+
/**
|
|
189
|
+
* The run properties which apply to a run in a table cell: as `getEffectiveRPr(rPr, pPr)`,
|
|
190
|
+
* with the table style's run properties (its own, then its conditional formats') as a level
|
|
191
|
+
* of the style hierarchy beneath the paragraph style's - the toggle properties combine across
|
|
192
|
+
* the two (ECMA-376-1 17.7.3) - and [MS-DOCX]'s size exception where it applies. An undefined
|
|
193
|
+
* context resolves exactly as `getEffectiveRPr(rPr, pPr)`. A new object each call.
|
|
194
|
+
*/
|
|
195
|
+
getEffectiveRPr(rPr: wml.RPr | undefined, pPr: wml.PPr | undefined, cellContext: CellContext | undefined): wml.RPr;
|
|
161
196
|
private effectiveRPrOfStyle;
|
|
162
197
|
/**
|
|
163
198
|
* The character style's chain, then the direct formatting.
|
|
@@ -173,29 +208,94 @@ export declare class PropertyResolver {
|
|
|
173
208
|
* properties, then the `w:pPr`'s own `w:rPr`. What sizes an empty paragraph, and what a list
|
|
174
209
|
* label starts from.
|
|
175
210
|
*/
|
|
176
|
-
getEffectiveParagraphMarkRPr(pPr: wml.PPr | undefined): wml.RPr;
|
|
211
|
+
getEffectiveParagraphMarkRPr(pPr: wml.PPr | undefined, cellContext?: CellContext | undefined): wml.RPr;
|
|
177
212
|
/** Whether the run states any formatting of its own (docx4j's deprecated `hasDirectRPrFormatting`). */
|
|
178
213
|
hasDirectRPrFormatting(rPr: wml.RPr | undefined): boolean;
|
|
179
214
|
/**
|
|
180
215
|
* The table style which applies, merged root-first down its `w:basedOn` chain, then the
|
|
181
216
|
* table's own `w:tblPr` over it.
|
|
182
217
|
*
|
|
183
|
-
* Word's
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
* starts from nothing
|
|
218
|
+
* Word goes by the style's **name** (measured, docx4j CR-030 probes T1, T2 and T7). A style
|
|
219
|
+
* named "Normal Table" is Word's built-in Normal Table (`w:tblInd` 0; cell margins 108 twips
|
|
220
|
+
* left and right, 0 top and bottom), whatever its own definition says and whether or not it is
|
|
221
|
+
* the document's default: the built-in stands in for it, and the walk up the chain ends there.
|
|
222
|
+
* Every other style applies as written, with nothing beneath it: a chain which reaches no style
|
|
223
|
+
* so named starts from nothing, and the document's default table style, where it is named
|
|
224
|
+
* otherwise, applies as written to a table naming no style. The built-in also stands in for a
|
|
225
|
+
* style which is missing, and where the document has no default table style. (Until CR-007 the
|
|
226
|
+
* built-in was decided by the default table style's *id*, as docx4j did until 17.3.1.)
|
|
189
227
|
*
|
|
190
228
|
* A new `Style` each call, with a non-null `w:tblPr`.
|
|
191
229
|
*/
|
|
192
230
|
getEffectiveTableStyle(tblPr: wml.CTTblPrBase | undefined): wml.Style;
|
|
193
231
|
/**
|
|
194
|
-
* Whether
|
|
195
|
-
* {@link getEffectiveTableStyle} decides
|
|
196
|
-
* style
|
|
232
|
+
* Whether Word's built-in Normal Table underlies a table - the flag
|
|
233
|
+
* {@link getEffectiveTableStyle} decides by: the table's style chain (its own `w:tblStyle`,
|
|
234
|
+
* else the default table style) reaches a style *named* "Normal Table", or the style is
|
|
235
|
+
* missing, or there is none. Decided by name since CR-007; the method keeps docx4j's name
|
|
236
|
+
* from when it was decided by the default style's id.
|
|
197
237
|
*/
|
|
198
238
|
reachesDefaultTableStyle(tblPr: wml.CTTblPrBase | undefined): boolean;
|
|
239
|
+
private builtInTableNormalUnderlies;
|
|
240
|
+
/**
|
|
241
|
+
* Whether [MS-DOCX]'s `overrideTableStyleFontSizeAndJustification` exception applies to this
|
|
242
|
+
* document: a default paragraph style's 12pt does not override the table style's size, nor its
|
|
243
|
+
* left justification the table style's, for paragraphs in tables. Measured with Word 365
|
|
244
|
+
* (docx4j CR-030 probes T5 and T6): it applies below compatibility mode 15 (a document stating
|
|
245
|
+
* no `compatibilityMode` is mode 12) where the setting is not on, and never in mode 15.
|
|
246
|
+
*/
|
|
247
|
+
appliesTableStyleSizeJcException(): boolean;
|
|
248
|
+
/**
|
|
249
|
+
* The id of the table style a table resolves to: its own `w:tblStyle`, else the document's
|
|
250
|
+
* `w:default` table style, whatever its name; undefined where the table names none and the
|
|
251
|
+
* document has no default. (Whether that style contributes anything is
|
|
252
|
+
* {@link getTableStyleChain}'s question.)
|
|
253
|
+
*/
|
|
254
|
+
getTableStyleIdOf(tblPr: wml.CTTblPrBase | undefined): string | undefined;
|
|
255
|
+
/**
|
|
256
|
+
* A table style's `w:basedOn` chain merged root-first, conditional formats merged per
|
|
257
|
+
* condition, as it gives the paragraphs of its tables their text formatting. Word goes by the
|
|
258
|
+
* style's *name*: a style named "Normal Table" is Word's built-in, which gives text nothing
|
|
259
|
+
* whatever its own definition says, so the walk up the chain ends below it; every other style
|
|
260
|
+
* applies as written, the default table style included.
|
|
261
|
+
*
|
|
262
|
+
* Cached per id, and shared: read it, do not change it. An empty style for undefined, for a
|
|
263
|
+
* missing style, and for a chain which is "Normal Table" all the way down.
|
|
264
|
+
*/
|
|
265
|
+
getTableStyleChain(styleId: string | undefined): wml.Style;
|
|
266
|
+
/**
|
|
267
|
+
* The context of a table, for the paragraphs in it: build one per table and hold it while
|
|
268
|
+
* walking the table (the resolver keeps none, since it reads the table's content).
|
|
269
|
+
*/
|
|
270
|
+
tableContext(tbl: wml.Tbl): TableContext;
|
|
271
|
+
/**
|
|
272
|
+
* The table context of one paragraph, found through its `PARENT` pointers: the nearest
|
|
273
|
+
* enclosing cell, its row and its table, through whatever lies between (`w:sdt`,
|
|
274
|
+
* `w:customXml`, `w:smartTag`). Undefined where the paragraph is in no table, where a story
|
|
275
|
+
* begins before a cell is reached (a text box, a footnote, endnote or comment, a header, a
|
|
276
|
+
* footer, the body), or where the pointers are not there (unmarshalled content, and content
|
|
277
|
+
* the content API inserted, has them: `linkParents`).
|
|
278
|
+
*
|
|
279
|
+
* Each call builds a {@link TableContext}, a walk of the table's rows. That is right for "what
|
|
280
|
+
* formatting does this paragraph have"; code resolving every paragraph of a document walks it
|
|
281
|
+
* with a `TableContextTracker` instead, since calling this for each paragraph of a large table
|
|
282
|
+
* is quadratic.
|
|
283
|
+
*/
|
|
284
|
+
cellContextOf(p: wml.P): CellContext | undefined;
|
|
285
|
+
private clearTableCaches;
|
|
286
|
+
/** The table level's `w:pPr`: the style's own, then its conditional formats'; undefined if none. */
|
|
287
|
+
private tableLevelPPr;
|
|
288
|
+
/** The table level's `w:rPr`: the style's own, then its conditional formats'; undefined if none. */
|
|
289
|
+
private tableLevelRPr;
|
|
290
|
+
private composedPPr;
|
|
291
|
+
private composedRPr;
|
|
292
|
+
/**
|
|
293
|
+
* [MS-DOCX]'s exception, for a paragraph in a table whose style states a size (or a
|
|
294
|
+
* justification): the paragraph's style gives way to it if the style is the default paragraph
|
|
295
|
+
* style, or states no size (justification) of its own, and resolves to 12pt (left). A style of
|
|
296
|
+
* the paragraph's own which states one keeps it.
|
|
297
|
+
*/
|
|
298
|
+
private paragraphStyleGivesWay;
|
|
199
299
|
/** Word's built-in Normal Table, as a style: what it applies whatever the document's own definition says. */
|
|
200
300
|
private builtInTableNormal;
|
|
201
301
|
/**
|