@docx4j/core-ts 0.5.0 → 0.7.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/NOTICE +4 -0
- package/README.md +92 -4
- package/dist/html/convert.mjs +2 -1
- package/dist/html/elements.mjs +2 -1
- package/dist/model/color/ColorMath.d.mts +29 -0
- package/dist/model/color/ColorMath.mjs +146 -0
- package/dist/model/color/ColorTables.d.mts +6 -0
- package/dist/model/color/ColorTables.mjs +83 -0
- package/dist/model/color/DrawingMLColors.d.mts +52 -0
- package/dist/model/color/DrawingMLColors.mjs +374 -0
- package/dist/model/color/ResolvedColor.d.mts +36 -0
- package/dist/model/color/ResolvedColor.mjs +65 -0
- package/dist/model/color/SpreadsheetColors.d.mts +36 -0
- package/dist/model/color/SpreadsheetColors.mjs +84 -0
- package/dist/model/color/StyleFill.d.mts +28 -0
- package/dist/model/color/StyleFill.mjs +21 -0
- package/dist/model/color/ThemeColors.d.mts +86 -0
- package/dist/model/color/ThemeColors.mjs +304 -0
- package/dist/model/color/WordColors.d.mts +71 -0
- package/dist/model/color/WordColors.mjs +121 -0
- package/dist/model/color/index.d.mts +6 -0
- package/dist/model/color/index.mjs +30 -0
- package/dist/model/content/Body.d.mts +145 -23
- package/dist/model/content/Body.mjs +507 -150
- package/dist/model/content/Comment.d.mts +23 -5
- package/dist/model/content/Comment.mjs +207 -26
- package/dist/model/content/ContentControl.d.mts +198 -19
- package/dist/model/content/ContentControl.mjs +672 -99
- package/dist/model/content/Font.d.mts +70 -17
- package/dist/model/content/Font.mjs +119 -36
- package/dist/model/content/InlinePicture.d.mts +11 -0
- package/dist/model/content/InlinePicture.mjs +21 -1
- package/dist/model/content/List.d.mts +6 -3
- package/dist/model/content/List.mjs +18 -8
- package/dist/model/content/Paragraph.d.mts +200 -14
- package/dist/model/content/Paragraph.mjs +898 -82
- package/dist/model/content/Range.d.mts +227 -12
- package/dist/model/content/Range.mjs +785 -59
- package/dist/model/content/ResolvedView.d.mts +104 -0
- package/dist/model/content/ResolvedView.mjs +596 -0
- package/dist/model/content/Table.d.mts +29 -3
- package/dist/model/content/Table.mjs +135 -49
- package/dist/model/content/TrackedChange.d.mts +174 -15
- package/dist/model/content/TrackedChange.mjs +734 -170
- package/dist/model/content/comments.d.mts +20 -6
- package/dist/model/content/comments.mjs +67 -57
- package/dist/model/content/generalException.d.mts +18 -0
- package/dist/model/content/generalException.mjs +24 -0
- package/dist/model/content/index.d.mts +10 -3
- package/dist/model/content/index.mjs +10 -2
- package/dist/model/content/mathText.d.mts +21 -0
- package/dist/model/content/mathText.mjs +267 -0
- package/dist/model/content/officeText.d.mts +27 -0
- package/dist/model/content/officeText.mjs +74 -0
- package/dist/model/content/ooxml.mjs +12 -1
- package/dist/model/content/outline.d.mts +5 -0
- package/dist/model/content/outline.mjs +13 -0
- package/dist/model/content/paraIds.d.mts +5 -0
- package/dist/model/content/paraIds.mjs +54 -0
- package/dist/model/content/placeholders.d.mts +110 -0
- package/dist/model/content/placeholders.mjs +253 -0
- package/dist/model/content/search.d.mts +74 -0
- package/dist/model/content/search.mjs +255 -9
- package/dist/model/content/spanEdits.d.mts +159 -0
- package/dist/model/content/spanEdits.mjs +728 -0
- package/dist/model/content/story.d.mts +47 -0
- package/dist/model/content/story.mjs +95 -0
- package/dist/model/content/tableColumns.d.mts +1 -1
- package/dist/model/content/tableColumns.mjs +108 -80
- package/dist/model/content/tableRevisions.d.mts +11 -3
- package/dist/model/content/tableRevisions.mjs +72 -42
- package/dist/model/content/tableRules.d.mts +30 -0
- package/dist/model/content/tableRules.mjs +102 -0
- package/dist/model/content/textBoxes.d.mts +18 -0
- package/dist/model/content/textBoxes.mjs +105 -0
- package/dist/model/content/trackedChangeFilter.d.mts +39 -0
- package/dist/model/content/trackedChangeFilter.mjs +81 -0
- package/dist/model/content/tracking.d.mts +63 -6
- package/dist/model/content/tracking.mjs +242 -22
- package/dist/model/content/tree.d.mts +172 -24
- package/dist/model/content/tree.mjs +328 -54
- package/dist/model/content/wordRange.d.mts +48 -0
- package/dist/model/content/wordRange.mjs +97 -0
- package/dist/model/customxml/CustomXmlPartCollection.d.mts +30 -1
- package/dist/model/customxml/CustomXmlPartCollection.mjs +81 -12
- package/dist/model/customxml/XmlMapping.d.mts +32 -8
- package/dist/model/customxml/XmlMapping.mjs +64 -10
- package/dist/model/customxml/bindings.d.mts +33 -4
- package/dist/model/customxml/bindings.mjs +171 -45
- package/dist/model/customxml/index.d.mts +1 -0
- package/dist/model/customxml/index.mjs +1 -0
- package/dist/model/customxml/kinds.d.mts +8 -3
- package/dist/model/customxml/kinds.mjs +26 -5
- package/dist/model/customxml/opendope.d.mts +4 -1
- package/dist/model/customxml/opendope.mjs +9 -6
- package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
- package/dist/model/customxml/picturePlaceholder.mjs +32 -0
- package/dist/model/customxml/pictures.d.mts +4 -3
- package/dist/model/customxml/pictures.mjs +22 -8
- package/dist/model/customxml/storeItems.d.mts +57 -0
- package/dist/model/customxml/storeItems.mjs +122 -0
- package/dist/model/customxml/xhtml.mjs +23 -22
- package/dist/model/dateZone.d.mts +25 -0
- package/dist/model/dateZone.mjs +57 -0
- package/dist/model/index.d.mts +3 -0
- package/dist/model/index.mjs +5 -0
- package/dist/model/listnumbering/Emulator.d.mts +37 -5
- package/dist/model/listnumbering/Emulator.mjs +63 -9
- package/dist/model/properties/PropertyResolver.d.mts +74 -2
- package/dist/model/properties/PropertyResolver.mjs +133 -5
- package/dist/model/properties/catalogue.d.mts +19 -5
- package/dist/model/properties/catalogue.mjs +41 -15
- package/dist/model/properties/index.d.mts +1 -1
- package/dist/model/properties/log.d.mts +1 -1
- package/dist/model/properties/log.mjs +5 -5
- package/dist/model/properties/styleUtil.d.mts +3 -1
- package/dist/model/properties/styleUtil.mjs +20 -24
- package/dist/model/properties/table.mjs +4 -2
- package/dist/model/text/CaseMapping.d.mts +38 -0
- package/dist/model/text/CaseMapping.mjs +86 -0
- package/dist/model/text/Extractor.d.mts +349 -0
- package/dist/model/text/Extractor.mjs +2406 -0
- package/dist/model/text/LinkTargets.d.mts +45 -0
- package/dist/model/text/LinkTargets.mjs +170 -0
- package/dist/model/text/MarkdownExporter.d.mts +140 -0
- package/dist/model/text/MarkdownExporter.mjs +255 -0
- package/dist/model/text/PlainText.d.mts +29 -0
- package/dist/model/text/PlainText.mjs +542 -0
- package/dist/model/text/TextContext.d.mts +256 -0
- package/dist/model/text/TextContext.mjs +600 -0
- package/dist/model/text/TextOptions.d.mts +233 -0
- package/dist/model/text/TextOptions.mjs +419 -0
- package/dist/model/text/TextResult.d.mts +621 -0
- package/dist/model/text/TextResult.mjs +629 -0
- package/dist/model/text/Texts.d.mts +99 -0
- package/dist/model/text/Texts.mjs +187 -0
- package/dist/model/text/WmlToMarkdown.d.mts +120 -0
- package/dist/model/text/WmlToMarkdown.mjs +936 -0
- package/dist/model/text/caseMapping.generated.d.mts +7 -0
- package/dist/model/text/caseMapping.generated.mjs +214 -0
- package/dist/model/text/commonmark.d.mts +121 -0
- package/dist/model/text/commonmark.mjs +655 -0
- package/dist/model/text/index.d.mts +8 -0
- package/dist/model/text/index.mjs +9 -0
- package/dist/model/text/normalize.d.mts +8 -0
- package/dist/model/text/normalize.mjs +13 -0
- package/dist/model/text/outline.d.mts +4 -0
- package/dist/model/text/outline.mjs +71 -0
- package/dist/model/wordIntegers.d.mts +29 -0
- package/dist/model/wordIntegers.mjs +78 -0
- package/dist/office-js/document.mjs +15 -1
- package/dist/office-js/fragment.d.mts +7 -5
- package/dist/office-js/fragment.mjs +63 -14
- package/dist/office-js/proxy.d.mts +8 -0
- package/dist/office-js/proxy.mjs +29 -0
- package/dist/office-js/run.mjs +2 -0
- package/dist/office-js/supported.generated.mjs +16 -0
- package/dist/office-js/toApiScript.mjs +29 -12
- package/dist/opc/DirectoryPartStore.d.mts +6 -2
- package/dist/opc/DirectoryPartStore.mjs +11 -4
- package/dist/opc/FlatOpcPartStore.d.mts +4 -2
- package/dist/opc/FlatOpcPartStore.mjs +11 -8
- package/dist/opc/Load.d.mts +32 -0
- package/dist/opc/Load.mjs +115 -5
- package/dist/opc/PartStore.d.mts +34 -1
- package/dist/opc/PartStore.mjs +71 -8
- package/dist/opc/Save.d.mts +32 -0
- package/dist/opc/Save.mjs +110 -4
- package/dist/opc/ZipPartStore.d.mts +4 -2
- package/dist/opc/ZipPartStore.mjs +12 -7
- package/dist/opc/exceptions.d.mts +140 -0
- package/dist/opc/exceptions.mjs +108 -0
- package/dist/opc/index.d.mts +8 -5
- package/dist/opc/index.mjs +5 -3
- package/dist/opc/mce/preprocessor.d.mts +141 -5
- package/dist/opc/mce/preprocessor.mjs +119 -18
- package/dist/opc/mce/understood.d.mts +3 -11
- package/dist/opc/mce/understood.mjs +27 -23
- package/dist/opc/repair/breaks.d.mts +23 -0
- package/dist/opc/repair/breaks.mjs +288 -0
- package/dist/opc/repair/hosts.d.mts +12 -0
- package/dist/opc/repair/hosts.mjs +33 -0
- package/dist/opc/repair/mainRoot.d.mts +19 -0
- package/dist/opc/repair/mainRoot.mjs +168 -0
- package/dist/opc/repair/unknownElements.d.mts +8 -0
- package/dist/opc/repair/unknownElements.mjs +180 -0
- package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
- package/dist/opc/repair/wmlNames.generated.mjs +80 -0
- package/dist/opc/skipped.d.mts +50 -0
- package/dist/opc/skipped.mjs +140 -0
- package/dist/packages/OpcPackage.d.mts +110 -4
- package/dist/packages/OpcPackage.mjs +123 -7
- package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
- package/dist/packages/WordprocessingMLPackage.mjs +158 -21
- package/dist/packages/index.d.mts +1 -1
- package/dist/parts/DefaultXmlPart.mjs +2 -2
- package/dist/parts/Part.d.mts +14 -2
- package/dist/parts/RelationshipsPart.d.mts +15 -0
- package/dist/parts/RelationshipsPart.mjs +66 -1
- package/dist/parts/XmlPart.d.mts +63 -32
- package/dist/parts/XmlPart.mjs +240 -96
- package/dist/parts/wml/comments.mjs +30 -0
- package/dist/parts/wml/index.d.mts +12 -1
- package/dist/parts/wml/index.mjs +37 -1
- package/dist/xml/dom.d.mts +7 -0
- package/dist/xml/dom.mjs +18 -0
- package/package.json +2 -2
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ImagePart } from '../../parts/BinaryPart.mjs';
|
|
2
|
+
import { addImagePart, imageRunOf } from '../content/InlinePicture.mjs';
|
|
3
|
+
/** docx4j's placeholder picture, a PNG, as base64. */
|
|
4
|
+
export const PICTURE_PLACEHOLDER_BASE64 = 'iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAACXBIWXMAABYlAAAWJQFJUiTwAAACVklEQVR42u3cwU3jYBCGYRtx50gDNOUOckwDOaWBHNOBm6IAuEEBSByQIkv5B1njgGLP8xx3vasVeuVh82m3f/v46uDWHnwJEBbCQlggLISFsEBYCAthgbAQFsICYSEshAXCQlgU87jkF59Px+indvuDx9b+2PTH/y+sX/6gXdd9vr/O+U08ds+PnU/HdFtOIX+iT/8rncsbaxgGX8eNGcdx4TX0xsLfChEWwgJhISwq65f8pyAzP39jpZ6eX7yxcAoRFuTcYIQ26WyPSQenEGGBsBAWwgJhISxqMEITMkLjFCIsSDNC02CExilEWCAshIWwQFgIixqM0ISM0DiFCAvSjNA0GKFxChEWCAthISwQFsKiBiM0ISM0TiHCgjQjNA1GaJxChAXCQlgIC4SFsKjBCE3ICI1TiLAgzQhNgxEapxBhgbAQFsICYSEsajBCEzJC4xQiLEgzQtNghMYpRFggLISFsEBYCIsajNCEjNA4hQgL0ozQNBihcQoRFggLYSEsEBbCogYjNCEjNE4hwoI0IzQNRmicQoQFwkJYCAuEhbCowQhNyAiNU4iwIM0ITYMRGqcQYYGwEBbCAmEhLGowQhMyQuMUIixIM0LTYITGKURYICyEhbBAWAiLGozQhIzQOIUIC9KM0DQYoXEKERYIC2EhLBAWwqIGIzQhIzROIcKCNCM0DUZoNvfGuq57avoaaz7gsdU95o3Fmt9Yu/3h8m3WtZkfgXjsnh9Lf4PVLfyAFJxChIWwQFgIC2GBsBAWwgJhISyEBcJCWAgLhIWwEBb8+AbsaRgh6xNNrAAAAABJRU5ErkJggg==';
|
|
5
|
+
/** The drawing's extent, Word's: 1270000 EMU (100 points) square. */
|
|
6
|
+
export const PICTURE_PLACEHOLDER_EMU = 1270000;
|
|
7
|
+
/** The relationship each source part's placeholder image was added under, so that every control shares one part. */
|
|
8
|
+
const added = new WeakMap();
|
|
9
|
+
/** The run holding the placeholder drawing in `source` (`scope` its drawing ids'), the image part added once per part. */
|
|
10
|
+
export function picturePlaceholderRun(source, scope) {
|
|
11
|
+
var _a;
|
|
12
|
+
let relId = added.get(source);
|
|
13
|
+
if (relId === undefined || !(((_a = source.relationshipsPart) === null || _a === void 0 ? void 0 : _a.getPart(relId)) instanceof ImagePart)) {
|
|
14
|
+
relId = addImagePart(source, PICTURE_PLACEHOLDER_BASE64).relId;
|
|
15
|
+
added.set(source, relId);
|
|
16
|
+
}
|
|
17
|
+
return imageRunOf(relId, scope, PICTURE_PLACEHOLDER_EMU, PICTURE_PLACEHOLDER_EMU);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Word's form for a picture control (`w:picture`): the flag, and its content one run holding the placeholder drawing, in
|
|
21
|
+
* a paragraph where the control is block-level. What a mapped control whose node is empty shows (CR-005 section 10, D1
|
|
22
|
+
* (a2)) and what `insertContentControl('Picture')` makes (D2), as Word's do. False, and nothing changed, where the
|
|
23
|
+
* control's body has no part to hold the image.
|
|
24
|
+
*/
|
|
25
|
+
export function showPicturePlaceholder(control) {
|
|
26
|
+
const source = control.parentBody.part;
|
|
27
|
+
if (!source)
|
|
28
|
+
return false;
|
|
29
|
+
control.setBoundContent([picturePlaceholderRun(source, control.parentBody.container)]);
|
|
30
|
+
control.isShowingPlaceholder = true;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
@@ -33,9 +33,10 @@ export declare function pictureWidthOf(params: Map<string, string>): PictureWidt
|
|
|
33
33
|
* fallback), a tag-bound control holding none is left and noted. Otherwise the control's content
|
|
34
34
|
* becomes one run holding a new inline picture, sized as `PictureWidth` says, in the first
|
|
35
35
|
* paragraph of a block-level control (its properties kept) or as a run-level control's content.
|
|
36
|
-
* An empty value
|
|
37
|
-
*
|
|
38
|
-
*
|
|
36
|
+
* An empty value gives a picture control Word's form, the flag and a placeholder picture (`picturePlaceholderRun`;
|
|
37
|
+
* CR-005 section 10, D1 (a2)), unless it shows one already; a tag-bound control it leaves, with a note. A value that is
|
|
38
|
+
* not an image this package reads (PNG, JPEG, GIF, BMP; SVG where the drawing is kept, since it has no pixel size to
|
|
39
|
+
* place a new picture at), and a body with no part each leave the control as it was, with a note. The image part the control showed before
|
|
39
40
|
* stays in the package, as docx4j leaves it.
|
|
40
41
|
*/
|
|
41
42
|
export declare function bindPicture(control: ContentControl, value: string, width: PictureWidth, label: string): PictureOutcome;
|
|
@@ -5,6 +5,7 @@ import { ImagePart } from '../../parts/BinaryPart.mjs';
|
|
|
5
5
|
import { base64Decode, base64Encode } from '../../xml/dom.mjs';
|
|
6
6
|
import { enclosingCellOf } from '../properties/table.mjs';
|
|
7
7
|
import { tagParamsOf, selectEntryNode, PICTURE_HANDLER } from './opendope.mjs';
|
|
8
|
+
import { showPicturePlaceholder } from './picturePlaceholder.mjs';
|
|
8
9
|
const EMU_PER_TWIP = 635;
|
|
9
10
|
const BLIP = 'org_docx4j_dml.CTBlip';
|
|
10
11
|
/** Whether a control is bound to a picture through its tag (`od:Handler=picture` with an `od:xpath`). */
|
|
@@ -81,16 +82,26 @@ function maxWidthEmu(control, width) {
|
|
|
81
82
|
* fallback), a tag-bound control holding none is left and noted. Otherwise the control's content
|
|
82
83
|
* becomes one run holding a new inline picture, sized as `PictureWidth` says, in the first
|
|
83
84
|
* paragraph of a block-level control (its properties kept) or as a run-level control's content.
|
|
84
|
-
* An empty value
|
|
85
|
-
*
|
|
86
|
-
*
|
|
85
|
+
* An empty value gives a picture control Word's form, the flag and a placeholder picture (`picturePlaceholderRun`;
|
|
86
|
+
* CR-005 section 10, D1 (a2)), unless it shows one already; a tag-bound control it leaves, with a note. A value that is
|
|
87
|
+
* not an image this package reads (PNG, JPEG, GIF, BMP; SVG where the drawing is kept, since it has no pixel size to
|
|
88
|
+
* place a new picture at), and a body with no part each leave the control as it was, with a note. The image part the control showed before
|
|
87
89
|
* stays in the package, as docx4j leaves it.
|
|
88
90
|
*/
|
|
89
91
|
export function bindPicture(control, value, width, label) {
|
|
90
92
|
const base64 = base64Of(value);
|
|
91
|
-
if (base64 === '')
|
|
92
|
-
return { done: false, note: `${label}: the node is empty; the control is left as it is` };
|
|
93
93
|
const source = control.parentBody.part;
|
|
94
|
+
if (base64 === '') {
|
|
95
|
+
// a picture control's empty node: Word's form, the flag and a placeholder picture (CR-005 section 10, D1 (a2));
|
|
96
|
+
// one already showing a placeholder picture is left as it is, a tag-bound control left as before
|
|
97
|
+
if (control.type !== 'Picture')
|
|
98
|
+
return { done: false, note: `${label}: the node is empty; the control is left as it is` };
|
|
99
|
+
if (control.isShowingPlaceholder && firstBlipOf(control))
|
|
100
|
+
return { done: false };
|
|
101
|
+
if (!showPicturePlaceholder(control))
|
|
102
|
+
return { done: false, note: `${label}: the control's body has no part to hold an image` };
|
|
103
|
+
return { done: true };
|
|
104
|
+
}
|
|
94
105
|
if (!source)
|
|
95
106
|
return { done: false, note: `${label}: the control's body has no part to hold an image` };
|
|
96
107
|
if (width.kind === 'keep') {
|
|
@@ -128,7 +139,9 @@ export function applyPictureHandlerTo(control, parts) {
|
|
|
128
139
|
const selected = selectEntryNode(entryId, parts);
|
|
129
140
|
if ('note' in selected)
|
|
130
141
|
return { done: false, note: selected.note };
|
|
131
|
-
|
|
142
|
+
const outcome = bindPicture(control, selected.node.text, pictureWidthOf(params), `od:xpath=${entryId}`);
|
|
143
|
+
// a stale storeItemID resolved as Word would (CR-020): said where the outcome has nothing else to say
|
|
144
|
+
return selected.repair && outcome.done && !outcome.note ? { ...outcome, note: selected.repair } : outcome;
|
|
132
145
|
}
|
|
133
146
|
/** The picture pass over the tag-bound controls, after the text bindings: counted into the result, what was left said in its notes. */
|
|
134
147
|
export function applyPictureHandlersTo(controls, parts, result) {
|
|
@@ -158,7 +171,8 @@ export function applyPictureHandlersTo(controls, parts, result) {
|
|
|
158
171
|
export async function updateFromPictureControl(control) {
|
|
159
172
|
var _a, _b;
|
|
160
173
|
const mapping = control.xmlMapping;
|
|
161
|
-
|
|
174
|
+
// a control showing its placeholder picture holds no picture of its node's (CR-005 section 10)
|
|
175
|
+
if (!mapping.dataBinding || control.type !== 'Picture' || control.isShowingPlaceholder)
|
|
162
176
|
return false;
|
|
163
177
|
const node = mapping.customXmlNode;
|
|
164
178
|
if (!node)
|
|
@@ -181,7 +195,7 @@ export async function updateFromPictureControl(control) {
|
|
|
181
195
|
/** `updateFromContentControls`' picture pass: the mapped picture controls, counted into the result. */
|
|
182
196
|
export async function updateFromPictureControls(controls, result) {
|
|
183
197
|
for (const control of controls) {
|
|
184
|
-
if (control.type !== 'Picture' || !control.xmlMapping.
|
|
198
|
+
if (control.type !== 'Picture' || !control.xmlMapping.dataBinding)
|
|
185
199
|
continue;
|
|
186
200
|
result.bound++;
|
|
187
201
|
if (await updateFromPictureControl(control))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** The `w:storeItemID`s of the core and application properties (docx4j `BindingHandler`): not custom XML parts, never repaired. */
|
|
2
|
+
export declare const CORE_PROPERTIES_STOREITEMID = "{6C3C8BC8-F283-45AE-878A-BAB7291924A1}";
|
|
3
|
+
export declare const EXTENDED_PROPERTIES_STOREITEMID = "{6668398D-A668-4E3E-A5EB-62B293D839F1}";
|
|
4
|
+
/** An itemID without braces, lower-cased: how `getItem` compares ids, and so how a binding's names its part. */
|
|
5
|
+
export declare function normaliseStoreItemId(id: string): string;
|
|
6
|
+
/** Whether an ID is the core or the application properties'. */
|
|
7
|
+
export declare function isPropertiesStoreItem(id: string): boolean;
|
|
8
|
+
/** One custom XML part as the resolver sees it. */
|
|
9
|
+
export interface StoreItemCandidate<P> {
|
|
10
|
+
readonly part: P;
|
|
11
|
+
/** Its itemID, as its properties part spells it. */
|
|
12
|
+
readonly id: string;
|
|
13
|
+
/** Its part name: the order among several that fit. */
|
|
14
|
+
readonly partName: string;
|
|
15
|
+
/** Its document element; none where the part can't be read, which then fits nothing. */
|
|
16
|
+
readonly root: Element | null | undefined;
|
|
17
|
+
/** Whether the XPath, with these prefix mappings, selects a node in it. */
|
|
18
|
+
selects(xpath: string, prefixMappings: string | undefined): boolean;
|
|
19
|
+
}
|
|
20
|
+
/** The part a binding is evaluated against. */
|
|
21
|
+
export interface StoreItemResolution<P> {
|
|
22
|
+
readonly part: P;
|
|
23
|
+
/** True where the binding's ID names no part and this one fits its XPath: Word's repair. */
|
|
24
|
+
readonly repaired: boolean;
|
|
25
|
+
/** Where repaired, how many parts fit the XPath's first step; this one is the first, in part-name order, that selects a node. */
|
|
26
|
+
readonly fitting: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* docx4j's `StoreItemResolver.resolve` rule over a package's custom XML parts:
|
|
30
|
+
* - the part the ID names, the comparison `getItem`'s (case and braces ignored); the core and application properties'
|
|
31
|
+
* IDs are left to the caller, and never repaired;
|
|
32
|
+
* - else the parts whose document element's namespace and local name match the XPath's first step, its prefix read with
|
|
33
|
+
* the binding's `w:prefixMappings`, else the objects package's `NAMESPACE_PREFIXES` (docx4j reads its own table); an
|
|
34
|
+
* XPath with no named first step (`//`, `*`, an axis, an attribute) fits every part. In part-name order: one fitting part
|
|
35
|
+
* is taken; of several, the first whose XPath selects a node, else the first (Word's choice in every fresh session,
|
|
36
|
+
* check 73b; CR-020 D7); none, and the binding is unresolved.
|
|
37
|
+
*
|
|
38
|
+
* What a stale ID resolves to is remembered per (ID, XPath, prefix mappings), since one stale ID fits different parts for
|
|
39
|
+
* different XPaths (the two-parts probe: B7 part 1, B11 part 2), and forgotten when the parts change (an add, a delete).
|
|
40
|
+
*/
|
|
41
|
+
export declare class StoreItemResolver<P> {
|
|
42
|
+
private readonly candidates;
|
|
43
|
+
private readonly memo;
|
|
44
|
+
private signature;
|
|
45
|
+
constructor(candidates: () => readonly StoreItemCandidate<P>[]);
|
|
46
|
+
/** The part for a binding: named by its ID, else the one its XPath fits; undefined where none is named and none fits. */
|
|
47
|
+
resolve(storeItemId: string | undefined, xpath: string | undefined, prefixMappings: string | undefined): StoreItemResolution<P> | undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The XPath's first step as its namespace and local name, with the binding's prefix mappings (`/p:root[1]/p:b7[1]` with
|
|
51
|
+
* `xmlns:p='urn:x'` is `urn:x` and `root`); undefined where the XPath does not start with a named step, when every part
|
|
52
|
+
* fits. docx4j's `StoreItemResolver.firstStep`.
|
|
53
|
+
*/
|
|
54
|
+
export declare function firstStep(xpath: string | undefined, prefixMappings: string | undefined): {
|
|
55
|
+
namespaceURI: string;
|
|
56
|
+
localName: string;
|
|
57
|
+
} | undefined;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// CR-020: docx4j's StoreItemResolver (its CR-058 D4, `35cdeaee6`, released in 17.3.5): the custom XML part a binding is
|
|
2
|
+
// evaluated against. The part its `w:storeItemID` names, or, where that names no part, the one its XPath fits, as Word
|
|
3
|
+
// repairs such a binding on open (Word 365, 22 and 23 October 2026, and checks 73 and 73b: the control shows the part's
|
|
4
|
+
// value, Office JS's `customXmlPart` is that part, and the save writes its ID into `w:storeItemID`). Shared by every
|
|
5
|
+
// reader and the bind (CR-020 D1): the text model's bound values, `XmlMapping.customXmlPart` and `customXmlNode`,
|
|
6
|
+
// `applyBindings`, `updateFromContentControls` and the `od:xpath` passes, so they all name the part Word binds.
|
|
7
|
+
import { NAMESPACE_PREFIXES } from '@docx4j/generated-objects-ts';
|
|
8
|
+
import { parsePrefixMappings } from './xpath.mjs';
|
|
9
|
+
/** The `w:storeItemID`s of the core and application properties (docx4j `BindingHandler`): not custom XML parts, never repaired. */
|
|
10
|
+
export const CORE_PROPERTIES_STOREITEMID = '{6C3C8BC8-F283-45AE-878A-BAB7291924A1}';
|
|
11
|
+
export const EXTENDED_PROPERTIES_STOREITEMID = '{6668398D-A668-4E3E-A5EB-62B293D839F1}';
|
|
12
|
+
/** An itemID without braces, lower-cased: how `getItem` compares ids, and so how a binding's names its part. */
|
|
13
|
+
export function normaliseStoreItemId(id) {
|
|
14
|
+
return id.trim().replace(/[{}]/g, '').toLowerCase();
|
|
15
|
+
}
|
|
16
|
+
/** Whether an ID is the core or the application properties'. */
|
|
17
|
+
export function isPropertiesStoreItem(id) {
|
|
18
|
+
const key = normaliseStoreItemId(id);
|
|
19
|
+
return key === normaliseStoreItemId(CORE_PROPERTIES_STOREITEMID) || key === normaliseStoreItemId(EXTENDED_PROPERTIES_STOREITEMID);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* docx4j's `StoreItemResolver.resolve` rule over a package's custom XML parts:
|
|
23
|
+
* - the part the ID names, the comparison `getItem`'s (case and braces ignored); the core and application properties'
|
|
24
|
+
* IDs are left to the caller, and never repaired;
|
|
25
|
+
* - else the parts whose document element's namespace and local name match the XPath's first step, its prefix read with
|
|
26
|
+
* the binding's `w:prefixMappings`, else the objects package's `NAMESPACE_PREFIXES` (docx4j reads its own table); an
|
|
27
|
+
* XPath with no named first step (`//`, `*`, an axis, an attribute) fits every part. In part-name order: one fitting part
|
|
28
|
+
* is taken; of several, the first whose XPath selects a node, else the first (Word's choice in every fresh session,
|
|
29
|
+
* check 73b; CR-020 D7); none, and the binding is unresolved.
|
|
30
|
+
*
|
|
31
|
+
* What a stale ID resolves to is remembered per (ID, XPath, prefix mappings), since one stale ID fits different parts for
|
|
32
|
+
* different XPaths (the two-parts probe: B7 part 1, B11 part 2), and forgotten when the parts change (an add, a delete).
|
|
33
|
+
*/
|
|
34
|
+
export class StoreItemResolver {
|
|
35
|
+
constructor(candidates) {
|
|
36
|
+
this.candidates = candidates;
|
|
37
|
+
this.memo = new Map();
|
|
38
|
+
this.signature = '';
|
|
39
|
+
}
|
|
40
|
+
/** The part for a binding: named by its ID, else the one its XPath fits; undefined where none is named and none fits. */
|
|
41
|
+
resolve(storeItemId, xpath, prefixMappings) {
|
|
42
|
+
var _a;
|
|
43
|
+
if (!storeItemId)
|
|
44
|
+
return undefined;
|
|
45
|
+
const all = this.candidates();
|
|
46
|
+
const key = normaliseStoreItemId(storeItemId);
|
|
47
|
+
const named = all.find((candidate) => normaliseStoreItemId(candidate.id) === key);
|
|
48
|
+
if (named)
|
|
49
|
+
return { part: named.part, repaired: false, fitting: 0 };
|
|
50
|
+
if (isPropertiesStoreItem(storeItemId))
|
|
51
|
+
return undefined;
|
|
52
|
+
const signature = all.map((candidate) => `${normaliseStoreItemId(candidate.id)} ${candidate.partName}`).join('|');
|
|
53
|
+
if (signature !== this.signature) {
|
|
54
|
+
this.memo.clear();
|
|
55
|
+
this.signature = signature;
|
|
56
|
+
}
|
|
57
|
+
const memoKey = `${key}|${xpath !== null && xpath !== void 0 ? xpath : ''}|${prefixMappings !== null && prefixMappings !== void 0 ? prefixMappings : ''}`;
|
|
58
|
+
let resolved = this.memo.get(memoKey);
|
|
59
|
+
if (resolved === undefined) {
|
|
60
|
+
resolved = (_a = repair(all, xpath !== null && xpath !== void 0 ? xpath : '', prefixMappings)) !== null && _a !== void 0 ? _a : null;
|
|
61
|
+
this.memo.set(memoKey, resolved);
|
|
62
|
+
}
|
|
63
|
+
return resolved !== null && resolved !== void 0 ? resolved : undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function repair(all, xpath, prefixMappings) {
|
|
67
|
+
const step = firstStep(xpath, prefixMappings);
|
|
68
|
+
const fitting = all.filter((candidate) => {
|
|
69
|
+
var _a, _b;
|
|
70
|
+
const root = candidate.root;
|
|
71
|
+
if (!root)
|
|
72
|
+
return false;
|
|
73
|
+
return step === undefined || (((_a = root.namespaceURI) !== null && _a !== void 0 ? _a : '') === step.namespaceURI && ((_b = root.localName) !== null && _b !== void 0 ? _b : root.nodeName) === step.localName);
|
|
74
|
+
}).sort((a, b) => (a.partName < b.partName ? -1 : a.partName > b.partName ? 1 : 0));
|
|
75
|
+
if (fitting.length === 0)
|
|
76
|
+
return undefined;
|
|
77
|
+
if (fitting.length === 1)
|
|
78
|
+
return { part: fitting[0].part, repaired: true, fitting: 1 };
|
|
79
|
+
const selecting = fitting.find((candidate) => {
|
|
80
|
+
try {
|
|
81
|
+
return candidate.selects(xpath, prefixMappings);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
return { part: (selecting !== null && selecting !== void 0 ? selecting : fitting[0]).part, repaired: true, fitting: fitting.length };
|
|
88
|
+
}
|
|
89
|
+
/** The objects package's prefixes, prefix to namespace: what a prefix the binding doesn't map reads as. */
|
|
90
|
+
const NAMESPACES_BY_PREFIX = (() => {
|
|
91
|
+
const out = {};
|
|
92
|
+
for (const [uri, prefix] of Object.entries(NAMESPACE_PREFIXES))
|
|
93
|
+
if (prefix !== '' && !(prefix in out))
|
|
94
|
+
out[prefix] = uri;
|
|
95
|
+
return out;
|
|
96
|
+
})();
|
|
97
|
+
/**
|
|
98
|
+
* The XPath's first step as its namespace and local name, with the binding's prefix mappings (`/p:root[1]/p:b7[1]` with
|
|
99
|
+
* `xmlns:p='urn:x'` is `urn:x` and `root`); undefined where the XPath does not start with a named step, when every part
|
|
100
|
+
* fits. docx4j's `StoreItemResolver.firstStep`.
|
|
101
|
+
*/
|
|
102
|
+
export function firstStep(xpath, prefixMappings) {
|
|
103
|
+
var _a, _b;
|
|
104
|
+
if (xpath === undefined)
|
|
105
|
+
return undefined;
|
|
106
|
+
let s = xpath.trim();
|
|
107
|
+
if (s.startsWith('//'))
|
|
108
|
+
return undefined;
|
|
109
|
+
if (s.startsWith('/'))
|
|
110
|
+
s = s.slice(1);
|
|
111
|
+
const end = s.search(/[/[(\s]/);
|
|
112
|
+
const step = end < 0 ? s : s.slice(0, end);
|
|
113
|
+
if (step === '' || step === '*' || step === '.' || step === '..' || step.includes('::') || step.startsWith('@'))
|
|
114
|
+
return undefined;
|
|
115
|
+
const colon = step.indexOf(':');
|
|
116
|
+
const prefix = colon < 0 ? '' : step.slice(0, colon);
|
|
117
|
+
const localName = colon < 0 ? step : step.slice(colon + 1);
|
|
118
|
+
if (localName === '' || localName === '*')
|
|
119
|
+
return undefined;
|
|
120
|
+
const namespaceURI = prefix === '' ? '' : ((_b = (_a = parsePrefixMappings(prefixMappings)[prefix]) !== null && _a !== void 0 ? _a : NAMESPACES_BY_PREFIX[prefix]) !== null && _b !== void 0 ? _b : '');
|
|
121
|
+
return { namespaceURI, localName };
|
|
122
|
+
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { deepCopy } from '@docx4j/generated-objects-ts';
|
|
2
2
|
import { Namespaces } from '../../parts/Namespaces.mjs';
|
|
3
|
-
import { typeNameOf, linkParents, childrenOf } from '../content/tree.mjs';
|
|
3
|
+
import { typeNameOf, linkParents, childrenOf, writingEveryBranch } from '../content/tree.mjs';
|
|
4
4
|
import { contentOf } from '../content/ooxml.mjs';
|
|
5
|
+
import { wrappingCellOf, endWithParagraph } from '../content/tableRules.mjs';
|
|
5
6
|
import { convertHtml, styleLookupOf } from '../../html/convert.mjs';
|
|
6
7
|
import { blocksToXml, needsOf, HYPERLINK_STYLE } from '../../html/elements.mjs';
|
|
7
|
-
import { tagParamsOf,
|
|
8
|
+
import { tagParamsOf, selectEntryNode, XHTML_CONTENT_TYPE } from './opendope.mjs';
|
|
8
9
|
/** Whether a control is bound to XHTML through its tag. */
|
|
9
10
|
export function isXhtmlBound(control) {
|
|
10
11
|
const params = tagParamsOf(control.tag);
|
|
@@ -67,20 +68,15 @@ function inlineContentOf(paragraph) {
|
|
|
67
68
|
* `dropped` (a run-level control's blocks after the first, and what the converter dropped).
|
|
68
69
|
*/
|
|
69
70
|
export async function applyXhtmlBindingTo(control, parts, host, options = {}) {
|
|
70
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
71
|
-
var
|
|
71
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
72
|
+
var _h;
|
|
72
73
|
const params = tagParamsOf(control.tag);
|
|
73
74
|
const entryId = params.get('od:xpath');
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
return { done: false, note:
|
|
77
|
-
const
|
|
78
|
-
|
|
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);
|
|
75
|
+
const selected = selectEntryNode(entryId, parts);
|
|
76
|
+
if ('note' in selected)
|
|
77
|
+
return { done: false, note: selected.note };
|
|
78
|
+
const { node, repair } = selected;
|
|
79
|
+
const parser = (_a = options.parser) !== null && _a !== void 0 ? _a : (typeof DOMParser === 'function' ? (h) => new DOMParser().parseFromString(h, 'text/html') : undefined);
|
|
84
80
|
if (!parser)
|
|
85
81
|
return { done: false, note: `od:xpath=${entryId}: XHTML needs an HTML parser (applyBindings({ html: { parser } }))` };
|
|
86
82
|
const converted = convertHtml(node.text, await lookupFor(host), { parser });
|
|
@@ -92,7 +88,7 @@ export async function applyXhtmlBindingTo(control, parts, host, options = {}) {
|
|
|
92
88
|
await host.styles.ensure(converted.report.stylesWanted);
|
|
93
89
|
}
|
|
94
90
|
catch {
|
|
95
|
-
dropped['styles the defaults lack'] = ((
|
|
91
|
+
dropped['styles the defaults lack'] = ((_b = dropped['styles the defaults lack']) !== null && _b !== void 0 ? _b : 0) + converted.report.stylesWanted.length;
|
|
96
92
|
}
|
|
97
93
|
}
|
|
98
94
|
const needs = needsOf(blocks);
|
|
@@ -109,26 +105,26 @@ export async function applyXhtmlBindingTo(control, parts, host, options = {}) {
|
|
|
109
105
|
lists.set(key, host.numbering.restart(firstNumbered));
|
|
110
106
|
}
|
|
111
107
|
const links = new Map();
|
|
112
|
-
const rels = needs.links.length > 0 ? (
|
|
108
|
+
const rels = needs.links.length > 0 ? (_c = control.parentBody.part) === null || _c === void 0 ? void 0 : _c.getRelationshipsPart(true) : undefined;
|
|
113
109
|
if (rels) {
|
|
114
110
|
for (const address of needs.links)
|
|
115
111
|
links.set(address, rels.addExternalRelationship(Namespaces.HYPERLINK, address).id);
|
|
116
112
|
host.requireStyles([HYPERLINK_STYLE]);
|
|
117
113
|
}
|
|
118
114
|
else if (needs.links.length > 0)
|
|
119
|
-
dropped['links'] = ((
|
|
115
|
+
dropped['links'] = ((_d = dropped['links']) !== null && _d !== void 0 ? _d : 0) + needs.links.length;
|
|
120
116
|
const elements = await contentOf(blocksToXml(blocks, { numId: (key) => lists.get(key), relId: (address) => links.get(address) }));
|
|
121
117
|
applyRunProperties(elements, control.runProperties);
|
|
122
118
|
const sdt = control.sdt;
|
|
123
|
-
(
|
|
124
|
-
const content = ((
|
|
119
|
+
(_e = sdt.sdtContent) !== null && _e !== void 0 ? _e : (sdt.sdtContent = {});
|
|
120
|
+
const content = ((_f = (_h = sdt.sdtContent).content) !== null && _f !== void 0 ? _f : (_h.content = []));
|
|
125
121
|
if (control.form === 'Run') {
|
|
126
122
|
// A run-level control holds inline content: the first paragraph's, the rest reported.
|
|
127
123
|
const first = elements.find((e) => typeNameOf(e) === 'org_docx4j_wml.P');
|
|
128
124
|
const inlines = first ? inlineContentOf(first) : [];
|
|
129
125
|
const rest = elements.length - (first ? 1 : 0);
|
|
130
126
|
if (rest > 0)
|
|
131
|
-
dropped['blocks after the first, in a run-level control'] = ((
|
|
127
|
+
dropped['blocks after the first, in a run-level control'] = ((_g = dropped['blocks after the first, in a run-level control']) !== null && _g !== void 0 ? _g : 0) + rest;
|
|
132
128
|
content.length = 0;
|
|
133
129
|
content.push(...inlines);
|
|
134
130
|
linkParents(content, sdt.sdtContent);
|
|
@@ -137,9 +133,14 @@ export async function applyXhtmlBindingTo(control, parts, host, options = {}) {
|
|
|
137
133
|
content.length = 0;
|
|
138
134
|
content.push(...elements);
|
|
139
135
|
linkParents(content, sdt.sdtContent);
|
|
136
|
+
// markup ending in a table, in a cell's control: the cell ends with a paragraph after it, docx4j's repair (CR-002 section 55)
|
|
137
|
+
const cell = wrappingCellOf(sdt.PARENT);
|
|
138
|
+
if (cell)
|
|
139
|
+
endWithParagraph(cell);
|
|
140
140
|
}
|
|
141
|
-
control
|
|
142
|
-
|
|
141
|
+
// a control in a branch of a kept mc:AlternateContent too: the pass reaches every branch (CR-013 phase 3)
|
|
142
|
+
writingEveryBranch(() => { control.isShowingPlaceholder = false; });
|
|
143
|
+
return { done: true, ...(repair ? { note: repair } : {}), ...(Object.keys(dropped).length > 0 ? { dropped } : {}) };
|
|
143
144
|
}
|
|
144
145
|
/** The XHTML pass over the controls, after the text bindings: counted into the result, what was left said in its notes. */
|
|
145
146
|
export async function applyXhtmlBindingsTo(controls, parts, host, result, options = {}) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** The fields a wall clock shows: `month` 1 to 12, `hour` 0 to 23. */
|
|
2
|
+
export interface WallClock {
|
|
3
|
+
readonly year: number;
|
|
4
|
+
readonly month: number;
|
|
5
|
+
readonly day: number;
|
|
6
|
+
readonly hour: number;
|
|
7
|
+
readonly minute: number;
|
|
8
|
+
readonly second: number;
|
|
9
|
+
}
|
|
10
|
+
/** The runtime's zone, an IANA id (`Australia/Sydney`; `UTC` where the runtime has no better answer). */
|
|
11
|
+
export declare function runtimeTimeZone(): string;
|
|
12
|
+
/**
|
|
13
|
+
* `id` when the runtime's `Intl` knows it as a zone, else a `RangeError` naming it: a package's
|
|
14
|
+
* `dateTimeZone` is refused at the set, never ignored, since a wrong zone shifts every stamp.
|
|
15
|
+
*/
|
|
16
|
+
export declare function assertTimeZone(id: string): string;
|
|
17
|
+
/** The wall clock `date` shows in `zone`; the runtime's zone where `zone` is undefined. */
|
|
18
|
+
export declare function wallClockIn(date: Date, zone: string | undefined): WallClock;
|
|
19
|
+
/**
|
|
20
|
+
* The instant at which a wall clock in `zone` shows `clock`; the runtime's zone where `zone` is
|
|
21
|
+
* undefined. Found by offset: the clock taken as UTC, corrected by what the zone shows for that
|
|
22
|
+
* guess, twice, which settles across a daylight-saving step; a clock time that does not exist on a
|
|
23
|
+
* spring-forward day gives the instant an hour on, as `Date` does for the runtime's zone.
|
|
24
|
+
*/
|
|
25
|
+
export declare function instantOf(clock: WallClock, zone: string | undefined): Date;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// The package's time zone (CR-018; the portfolio's date rule of 2026-10-28, docx4j CR-067 D12): an instant a document
|
|
2
|
+
// holds (a revision's or a comment's stamp, a date field) is shown, and a `w:date` without `dateUtc` read, in the zone
|
|
3
|
+
// the caller sets on the package it is working on, else the runtime's. Word writes such a `w:date` as the author's local
|
|
4
|
+
// wall-clock time labelled `Z` (CR-002 section 29, check 23), so the zone is what turns it into an instant and back.
|
|
5
|
+
// Under Office JS the runtime's zone is the client's; under Node on a server it is the server's, hence the option.
|
|
6
|
+
// Nothing here reaches a saved file as such: the zone decides which wall-clock fields are written for an instant.
|
|
7
|
+
/** The runtime's zone, an IANA id (`Australia/Sydney`; `UTC` where the runtime has no better answer). */
|
|
8
|
+
export function runtimeTimeZone() {
|
|
9
|
+
return new Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `id` when the runtime's `Intl` knows it as a zone, else a `RangeError` naming it: a package's
|
|
13
|
+
* `dateTimeZone` is refused at the set, never ignored, since a wrong zone shifts every stamp.
|
|
14
|
+
*/
|
|
15
|
+
export function assertTimeZone(id) {
|
|
16
|
+
try {
|
|
17
|
+
new Intl.DateTimeFormat('en-US', { timeZone: id });
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
throw new RangeError(`Not a time zone this runtime knows: ${JSON.stringify(id)} (an IANA id, such as "Australia/Sydney")`);
|
|
21
|
+
}
|
|
22
|
+
return id;
|
|
23
|
+
}
|
|
24
|
+
/** The wall clock `date` shows in `zone`; the runtime's zone where `zone` is undefined. */
|
|
25
|
+
export function wallClockIn(date, zone) {
|
|
26
|
+
if (zone === undefined) {
|
|
27
|
+
return {
|
|
28
|
+
year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate(),
|
|
29
|
+
hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const parts = new Intl.DateTimeFormat('en-US', {
|
|
33
|
+
timeZone: zone, hour12: false, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit',
|
|
34
|
+
}).formatToParts(date);
|
|
35
|
+
const field = (type) => { var _a, _b; return Number((_b = (_a = parts.find((p) => p.type === type)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : NaN); };
|
|
36
|
+
return {
|
|
37
|
+
year: field('year'), month: field('month'), day: field('day'),
|
|
38
|
+
hour: field('hour') % 24, minute: field('minute'), second: field('second'), // hour12: false gives 24 at midnight on some engines
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The instant at which a wall clock in `zone` shows `clock`; the runtime's zone where `zone` is
|
|
43
|
+
* undefined. Found by offset: the clock taken as UTC, corrected by what the zone shows for that
|
|
44
|
+
* guess, twice, which settles across a daylight-saving step; a clock time that does not exist on a
|
|
45
|
+
* spring-forward day gives the instant an hour on, as `Date` does for the runtime's zone.
|
|
46
|
+
*/
|
|
47
|
+
export function instantOf(clock, zone) {
|
|
48
|
+
if (zone === undefined)
|
|
49
|
+
return new Date(clock.year, clock.month - 1, clock.day, clock.hour, clock.minute, clock.second);
|
|
50
|
+
const asUtc = Date.UTC(clock.year, clock.month - 1, clock.day, clock.hour, clock.minute, clock.second);
|
|
51
|
+
let guess = asUtc;
|
|
52
|
+
for (let i = 0; i < 2; i++) {
|
|
53
|
+
const shown = wallClockIn(new Date(guess), zone);
|
|
54
|
+
guess -= Date.UTC(shown.year, shown.month - 1, shown.day, shown.hour, shown.minute, shown.second) - asUtc;
|
|
55
|
+
}
|
|
56
|
+
return new Date(guess);
|
|
57
|
+
}
|
package/dist/model/index.d.mts
CHANGED
|
@@ -2,5 +2,8 @@ export * from './content/index.mjs';
|
|
|
2
2
|
export * from './properties/index.mjs';
|
|
3
3
|
export * from './listnumbering/index.mjs';
|
|
4
4
|
export * from './fonts/index.mjs';
|
|
5
|
+
export * from './color/index.mjs';
|
|
5
6
|
export * from './customxml/index.mjs';
|
|
7
|
+
export * from './text/index.mjs';
|
|
6
8
|
export { toApiScript, type ApiScriptOptions, type ApiScriptTarget } from '../office-js/toApiScript.mjs';
|
|
9
|
+
export { keptRange, rangeOf, describeReading, isUnmeasured, UNMEASURED_RANGE, type KeptRange } from './wordIntegers.mjs';
|
package/dist/model/index.mjs
CHANGED
|
@@ -7,8 +7,13 @@ export * from './properties/index.mjs';
|
|
|
7
7
|
export * from './listnumbering/index.mjs';
|
|
8
8
|
// CR-001 Phase B step 4: RunFontSelector, the Mapper and the default theme.
|
|
9
9
|
export * from './fonts/index.mjs';
|
|
10
|
+
// CR-008 phase 2: colours as Office draws them (ThemeColors, WordColors, DrawingMLColors, SpreadsheetColors).
|
|
11
|
+
export * from './color/index.mjs';
|
|
10
12
|
// CR-002 phase E: custom XML parts, XML mapping, the XPath engine, the typed content controls.
|
|
11
13
|
export * from './customxml/index.mjs';
|
|
14
|
+
// CR-012: the text model (Texts, the block model, plain text).
|
|
15
|
+
export * from './text/index.mjs';
|
|
12
16
|
// The source generator of CR-002 phase I: the content-API calls that reproduce a paragraph, a
|
|
13
17
|
// range or a table. The `Word` shim it lives next to stays on the ./office-js subpath.
|
|
14
18
|
export { toApiScript } from '../office-js/toApiScript.mjs';
|
|
19
|
+
export { keptRange, rangeOf, describeReading, isUnmeasured, UNMEASURED_RANGE } from './wordIntegers.mjs';
|
|
@@ -64,7 +64,8 @@ export interface NumberingResult {
|
|
|
64
64
|
ilvl: string | undefined;
|
|
65
65
|
/** The level definition, merged. Not docx4j's: a port convenience for CR-002 phase H. */
|
|
66
66
|
level: LevelDefinition | undefined;
|
|
67
|
-
/** The
|
|
67
|
+
/** The count this paragraph's level shows (the 3 of "1.3."), its counter once this paragraph is
|
|
68
|
+
* counted. docx4j `getValue()` (17.3.4), which this preceded. */
|
|
68
69
|
count: number | undefined;
|
|
69
70
|
/** No label was produced. docx4j returns an *empty* `ResultTriple` where a `w:num` or its
|
|
70
71
|
* level has no definition; this flags that case rather than leaving every member undefined
|
|
@@ -117,8 +118,32 @@ export declare class Emulator {
|
|
|
117
118
|
* to. The style itself, or any style it is based on, counts as the level's own. Direct
|
|
118
119
|
* formatting is never suppressed: a paragraph whose *own* `w:numPr` names such a level is
|
|
119
120
|
* numbered.
|
|
121
|
+
*
|
|
122
|
+
* A level which names no style belongs to one all the same: the first paragraph style in
|
|
123
|
+
* styles.xml whose own `w:numPr` names it ({@link levelStyleId}, docx4j 17.3.4, measured in
|
|
124
|
+
* Word 365 on the three documents of docx4j's `LevelOwnerTest`). Of two styles carrying such
|
|
125
|
+
* a level Word numbers the first in styles.xml - whatever their names, whichever the document
|
|
126
|
+
* uses first, whether or not it uses that style at all - and gives the other style's paragraphs
|
|
127
|
+
* no label and no count. They keep the level's indent, which the effective indent already
|
|
128
|
+
* gives them. A paragraph naming no style is the default paragraph style's in this check.
|
|
120
129
|
*/
|
|
121
130
|
styleLinkedElsewhere(numId: string, ilvl: string, pStyleVal: string | undefined): boolean;
|
|
131
|
+
/**
|
|
132
|
+
* The paragraph style a numbering level belongs to: the one its `w:lvl/w:pStyle` names (the
|
|
133
|
+
* `w:num`'s override level's first, as {@link NumberingDefinitions.getLinkedStyleId} reads it),
|
|
134
|
+
* else the first paragraph style in styles.xml whose own `w:numPr` names a `w:num` on the same
|
|
135
|
+
* `w:abstractNum` at that level (its `w:ilvl`, 0 where it states none). Undefined where neither:
|
|
136
|
+
* no style carries the level, so a paragraph reaches it only through its own `w:numPr`.
|
|
137
|
+
*
|
|
138
|
+
* The level is the `w:abstractNum`'s, not a `w:num`'s: a style reaching it through a second
|
|
139
|
+
* `w:num` is on the same level, even where that `w:num` overrides it with a `w:lvl` of its own.
|
|
140
|
+
* A style's level is its `w:numPr`'s `w:ilvl`, not the level whose `w:pStyle` names it, as Word
|
|
141
|
+
* reads it (ECMA-376 17.9.24 has the naming level). docx4j `Emulator.levelStyleId` (17.3.4).
|
|
142
|
+
*
|
|
143
|
+
* @param numId a `w:numId` (not 0)
|
|
144
|
+
* @param ilvl a `w:ilvl`; undefined or empty for 0
|
|
145
|
+
*/
|
|
146
|
+
levelStyleId(numId: string, ilvl: string | undefined): string | undefined;
|
|
122
147
|
/**
|
|
123
148
|
* The one resolution of numId and ilvl for a paragraph. docx4j `Emulator.resolve`
|
|
124
149
|
* (CR-014 phase 3, which collapsed `getNumber`'s and `getInd`'s two copies onto it).
|
|
@@ -135,13 +160,18 @@ export declare class Emulator {
|
|
|
135
160
|
resolve(pStyleVal: string | undefined, numId: string | undefined, ilvl: string | undefined, directNumPr: boolean): NumRef;
|
|
136
161
|
/**
|
|
137
162
|
* The numbering reference a paragraph resolves to, without taking a number and without
|
|
138
|
-
* touching any state. docx4j `Emulator.numRefFor` (17.1.1); never undefined.
|
|
163
|
+
* touching any state. docx4j `Emulator.numRefFor` (17.1.1); never undefined. A paragraph with
|
|
164
|
+
* no `w:pPr` resolves as an empty one, against the default paragraph style, as
|
|
165
|
+
* {@link getNumber} resolves it (docx4j `c283dffdb`, 17.3.4).
|
|
139
166
|
*/
|
|
140
167
|
numRefFor(pPr: wml.PPr | undefined): NumRef;
|
|
141
168
|
/**
|
|
142
169
|
* The next number for a paragraph, from its `w:pPr` (its own `w:numPr`, else its style's),
|
|
143
170
|
* counted in `state` or in this emulator's default state.
|
|
144
171
|
*
|
|
172
|
+
* A paragraph with no `w:pPr` resolves as one with an empty `w:pPr` does, against the default
|
|
173
|
+
* paragraph style, which may be numbered (docx4j 17.3.4; before, it was not numbered).
|
|
174
|
+
*
|
|
145
175
|
* @returns undefined where the paragraph is not numbered
|
|
146
176
|
*/
|
|
147
177
|
getNumber(pPr: wml.PPr | undefined, state?: NumberingState): NumberingResult | undefined;
|
|
@@ -176,11 +206,13 @@ export declare class Emulator {
|
|
|
176
206
|
static peek(pkg: NumberedPackageLike, pPr: wml.PPr | undefined, state?: NumberingState): NumberingResult | undefined;
|
|
177
207
|
/**
|
|
178
208
|
* docx4j `Emulator.numRefFor(wmlPackage, pPr)`: where this paragraph's numbering resolves to,
|
|
179
|
-
* before any counting. Never undefined; a package with no numbering part
|
|
180
|
-
*
|
|
181
|
-
*
|
|
209
|
+
* before any counting. Never undefined; a package with no numbering part or a package whose
|
|
210
|
+
* `PropertyResolver` has not been built each answer {@link NumRef.notNumbered} with the reason.
|
|
211
|
+
* A null `w:pPr` resolves as an empty one (docx4j `c283dffdb`, 17.3.4).
|
|
182
212
|
*/
|
|
183
213
|
static numRefFor(pkg: NumberedPackageLike | undefined, pPr: wml.PPr | undefined): NumRef;
|
|
214
|
+
/** docx4j `Emulator.levelStyleId(numberingPart, numId, levelId)`: the paragraph style a level belongs to. */
|
|
215
|
+
static levelStyleId(part: NumberingPartLike, numId: string, ilvl: string | undefined): string | undefined;
|
|
184
216
|
/** docx4j `Emulator.getInd(wmlPackage, pStyleVal, numId, levelId)`. */
|
|
185
217
|
static getInd(pkg: NumberedPackageLike, pStyleVal: string | undefined, numId: string | undefined, ilvl: string | undefined): wml.PPrBase.Ind | undefined;
|
|
186
218
|
toString(): string;
|