@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.
Files changed (207) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +92 -4
  3. package/dist/html/convert.mjs +2 -1
  4. package/dist/html/elements.mjs +2 -1
  5. package/dist/model/color/ColorMath.d.mts +29 -0
  6. package/dist/model/color/ColorMath.mjs +146 -0
  7. package/dist/model/color/ColorTables.d.mts +6 -0
  8. package/dist/model/color/ColorTables.mjs +83 -0
  9. package/dist/model/color/DrawingMLColors.d.mts +52 -0
  10. package/dist/model/color/DrawingMLColors.mjs +374 -0
  11. package/dist/model/color/ResolvedColor.d.mts +36 -0
  12. package/dist/model/color/ResolvedColor.mjs +65 -0
  13. package/dist/model/color/SpreadsheetColors.d.mts +36 -0
  14. package/dist/model/color/SpreadsheetColors.mjs +84 -0
  15. package/dist/model/color/StyleFill.d.mts +28 -0
  16. package/dist/model/color/StyleFill.mjs +21 -0
  17. package/dist/model/color/ThemeColors.d.mts +86 -0
  18. package/dist/model/color/ThemeColors.mjs +304 -0
  19. package/dist/model/color/WordColors.d.mts +71 -0
  20. package/dist/model/color/WordColors.mjs +121 -0
  21. package/dist/model/color/index.d.mts +6 -0
  22. package/dist/model/color/index.mjs +30 -0
  23. package/dist/model/content/Body.d.mts +145 -23
  24. package/dist/model/content/Body.mjs +507 -150
  25. package/dist/model/content/Comment.d.mts +23 -5
  26. package/dist/model/content/Comment.mjs +207 -26
  27. package/dist/model/content/ContentControl.d.mts +198 -19
  28. package/dist/model/content/ContentControl.mjs +672 -99
  29. package/dist/model/content/Font.d.mts +70 -17
  30. package/dist/model/content/Font.mjs +119 -36
  31. package/dist/model/content/InlinePicture.d.mts +11 -0
  32. package/dist/model/content/InlinePicture.mjs +21 -1
  33. package/dist/model/content/List.d.mts +6 -3
  34. package/dist/model/content/List.mjs +18 -8
  35. package/dist/model/content/Paragraph.d.mts +200 -14
  36. package/dist/model/content/Paragraph.mjs +898 -82
  37. package/dist/model/content/Range.d.mts +227 -12
  38. package/dist/model/content/Range.mjs +785 -59
  39. package/dist/model/content/ResolvedView.d.mts +104 -0
  40. package/dist/model/content/ResolvedView.mjs +596 -0
  41. package/dist/model/content/Table.d.mts +29 -3
  42. package/dist/model/content/Table.mjs +135 -49
  43. package/dist/model/content/TrackedChange.d.mts +174 -15
  44. package/dist/model/content/TrackedChange.mjs +734 -170
  45. package/dist/model/content/comments.d.mts +20 -6
  46. package/dist/model/content/comments.mjs +67 -57
  47. package/dist/model/content/generalException.d.mts +18 -0
  48. package/dist/model/content/generalException.mjs +24 -0
  49. package/dist/model/content/index.d.mts +10 -3
  50. package/dist/model/content/index.mjs +10 -2
  51. package/dist/model/content/mathText.d.mts +21 -0
  52. package/dist/model/content/mathText.mjs +267 -0
  53. package/dist/model/content/officeText.d.mts +27 -0
  54. package/dist/model/content/officeText.mjs +74 -0
  55. package/dist/model/content/ooxml.mjs +12 -1
  56. package/dist/model/content/outline.d.mts +5 -0
  57. package/dist/model/content/outline.mjs +13 -0
  58. package/dist/model/content/paraIds.d.mts +5 -0
  59. package/dist/model/content/paraIds.mjs +54 -0
  60. package/dist/model/content/placeholders.d.mts +110 -0
  61. package/dist/model/content/placeholders.mjs +253 -0
  62. package/dist/model/content/search.d.mts +74 -0
  63. package/dist/model/content/search.mjs +255 -9
  64. package/dist/model/content/spanEdits.d.mts +159 -0
  65. package/dist/model/content/spanEdits.mjs +728 -0
  66. package/dist/model/content/story.d.mts +47 -0
  67. package/dist/model/content/story.mjs +95 -0
  68. package/dist/model/content/tableColumns.d.mts +1 -1
  69. package/dist/model/content/tableColumns.mjs +108 -80
  70. package/dist/model/content/tableRevisions.d.mts +11 -3
  71. package/dist/model/content/tableRevisions.mjs +72 -42
  72. package/dist/model/content/tableRules.d.mts +30 -0
  73. package/dist/model/content/tableRules.mjs +102 -0
  74. package/dist/model/content/textBoxes.d.mts +18 -0
  75. package/dist/model/content/textBoxes.mjs +105 -0
  76. package/dist/model/content/trackedChangeFilter.d.mts +39 -0
  77. package/dist/model/content/trackedChangeFilter.mjs +81 -0
  78. package/dist/model/content/tracking.d.mts +63 -6
  79. package/dist/model/content/tracking.mjs +242 -22
  80. package/dist/model/content/tree.d.mts +172 -24
  81. package/dist/model/content/tree.mjs +328 -54
  82. package/dist/model/content/wordRange.d.mts +48 -0
  83. package/dist/model/content/wordRange.mjs +97 -0
  84. package/dist/model/customxml/CustomXmlPartCollection.d.mts +30 -1
  85. package/dist/model/customxml/CustomXmlPartCollection.mjs +81 -12
  86. package/dist/model/customxml/XmlMapping.d.mts +32 -8
  87. package/dist/model/customxml/XmlMapping.mjs +64 -10
  88. package/dist/model/customxml/bindings.d.mts +33 -4
  89. package/dist/model/customxml/bindings.mjs +171 -45
  90. package/dist/model/customxml/index.d.mts +1 -0
  91. package/dist/model/customxml/index.mjs +1 -0
  92. package/dist/model/customxml/kinds.d.mts +8 -3
  93. package/dist/model/customxml/kinds.mjs +26 -5
  94. package/dist/model/customxml/opendope.d.mts +4 -1
  95. package/dist/model/customxml/opendope.mjs +9 -6
  96. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  97. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  98. package/dist/model/customxml/pictures.d.mts +4 -3
  99. package/dist/model/customxml/pictures.mjs +22 -8
  100. package/dist/model/customxml/storeItems.d.mts +57 -0
  101. package/dist/model/customxml/storeItems.mjs +122 -0
  102. package/dist/model/customxml/xhtml.mjs +23 -22
  103. package/dist/model/dateZone.d.mts +25 -0
  104. package/dist/model/dateZone.mjs +57 -0
  105. package/dist/model/index.d.mts +3 -0
  106. package/dist/model/index.mjs +5 -0
  107. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  108. package/dist/model/listnumbering/Emulator.mjs +63 -9
  109. package/dist/model/properties/PropertyResolver.d.mts +74 -2
  110. package/dist/model/properties/PropertyResolver.mjs +133 -5
  111. package/dist/model/properties/catalogue.d.mts +19 -5
  112. package/dist/model/properties/catalogue.mjs +41 -15
  113. package/dist/model/properties/index.d.mts +1 -1
  114. package/dist/model/properties/log.d.mts +1 -1
  115. package/dist/model/properties/log.mjs +5 -5
  116. package/dist/model/properties/styleUtil.d.mts +3 -1
  117. package/dist/model/properties/styleUtil.mjs +20 -24
  118. package/dist/model/properties/table.mjs +4 -2
  119. package/dist/model/text/CaseMapping.d.mts +38 -0
  120. package/dist/model/text/CaseMapping.mjs +86 -0
  121. package/dist/model/text/Extractor.d.mts +349 -0
  122. package/dist/model/text/Extractor.mjs +2406 -0
  123. package/dist/model/text/LinkTargets.d.mts +45 -0
  124. package/dist/model/text/LinkTargets.mjs +170 -0
  125. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  126. package/dist/model/text/MarkdownExporter.mjs +255 -0
  127. package/dist/model/text/PlainText.d.mts +29 -0
  128. package/dist/model/text/PlainText.mjs +542 -0
  129. package/dist/model/text/TextContext.d.mts +256 -0
  130. package/dist/model/text/TextContext.mjs +600 -0
  131. package/dist/model/text/TextOptions.d.mts +233 -0
  132. package/dist/model/text/TextOptions.mjs +419 -0
  133. package/dist/model/text/TextResult.d.mts +621 -0
  134. package/dist/model/text/TextResult.mjs +629 -0
  135. package/dist/model/text/Texts.d.mts +99 -0
  136. package/dist/model/text/Texts.mjs +187 -0
  137. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  138. package/dist/model/text/WmlToMarkdown.mjs +936 -0
  139. package/dist/model/text/caseMapping.generated.d.mts +7 -0
  140. package/dist/model/text/caseMapping.generated.mjs +214 -0
  141. package/dist/model/text/commonmark.d.mts +121 -0
  142. package/dist/model/text/commonmark.mjs +655 -0
  143. package/dist/model/text/index.d.mts +8 -0
  144. package/dist/model/text/index.mjs +9 -0
  145. package/dist/model/text/normalize.d.mts +8 -0
  146. package/dist/model/text/normalize.mjs +13 -0
  147. package/dist/model/text/outline.d.mts +4 -0
  148. package/dist/model/text/outline.mjs +71 -0
  149. package/dist/model/wordIntegers.d.mts +29 -0
  150. package/dist/model/wordIntegers.mjs +78 -0
  151. package/dist/office-js/document.mjs +15 -1
  152. package/dist/office-js/fragment.d.mts +7 -5
  153. package/dist/office-js/fragment.mjs +63 -14
  154. package/dist/office-js/proxy.d.mts +8 -0
  155. package/dist/office-js/proxy.mjs +29 -0
  156. package/dist/office-js/run.mjs +2 -0
  157. package/dist/office-js/supported.generated.mjs +16 -0
  158. package/dist/office-js/toApiScript.mjs +29 -12
  159. package/dist/opc/DirectoryPartStore.d.mts +6 -2
  160. package/dist/opc/DirectoryPartStore.mjs +11 -4
  161. package/dist/opc/FlatOpcPartStore.d.mts +4 -2
  162. package/dist/opc/FlatOpcPartStore.mjs +11 -8
  163. package/dist/opc/Load.d.mts +32 -0
  164. package/dist/opc/Load.mjs +115 -5
  165. package/dist/opc/PartStore.d.mts +34 -1
  166. package/dist/opc/PartStore.mjs +71 -8
  167. package/dist/opc/Save.d.mts +32 -0
  168. package/dist/opc/Save.mjs +110 -4
  169. package/dist/opc/ZipPartStore.d.mts +4 -2
  170. package/dist/opc/ZipPartStore.mjs +12 -7
  171. package/dist/opc/exceptions.d.mts +140 -0
  172. package/dist/opc/exceptions.mjs +108 -0
  173. package/dist/opc/index.d.mts +8 -5
  174. package/dist/opc/index.mjs +5 -3
  175. package/dist/opc/mce/preprocessor.d.mts +141 -5
  176. package/dist/opc/mce/preprocessor.mjs +119 -18
  177. package/dist/opc/mce/understood.d.mts +3 -11
  178. package/dist/opc/mce/understood.mjs +27 -23
  179. package/dist/opc/repair/breaks.d.mts +23 -0
  180. package/dist/opc/repair/breaks.mjs +288 -0
  181. package/dist/opc/repair/hosts.d.mts +12 -0
  182. package/dist/opc/repair/hosts.mjs +33 -0
  183. package/dist/opc/repair/mainRoot.d.mts +19 -0
  184. package/dist/opc/repair/mainRoot.mjs +168 -0
  185. package/dist/opc/repair/unknownElements.d.mts +8 -0
  186. package/dist/opc/repair/unknownElements.mjs +180 -0
  187. package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
  188. package/dist/opc/repair/wmlNames.generated.mjs +80 -0
  189. package/dist/opc/skipped.d.mts +50 -0
  190. package/dist/opc/skipped.mjs +140 -0
  191. package/dist/packages/OpcPackage.d.mts +110 -4
  192. package/dist/packages/OpcPackage.mjs +123 -7
  193. package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
  194. package/dist/packages/WordprocessingMLPackage.mjs +158 -21
  195. package/dist/packages/index.d.mts +1 -1
  196. package/dist/parts/DefaultXmlPart.mjs +2 -2
  197. package/dist/parts/Part.d.mts +14 -2
  198. package/dist/parts/RelationshipsPart.d.mts +15 -0
  199. package/dist/parts/RelationshipsPart.mjs +66 -1
  200. package/dist/parts/XmlPart.d.mts +63 -32
  201. package/dist/parts/XmlPart.mjs +240 -96
  202. package/dist/parts/wml/comments.mjs +30 -0
  203. package/dist/parts/wml/index.d.mts +12 -1
  204. package/dist/parts/wml/index.mjs +37 -1
  205. package/dist/xml/dom.d.mts +7 -0
  206. package/dist/xml/dom.mjs +18 -0
  207. package/package.json +2 -2
@@ -6,6 +6,7 @@ import type { CustomXmlPartLookup } from './XmlMapping.mjs';
6
6
  import type { XPathEngine } from './xpath.mjs';
7
7
  import { type BindingResult } from './bindings.mjs';
8
8
  import { type XhtmlHost, type XhtmlBindingOptions } from './xhtml.mjs';
9
+ import { type StoreItemResolution } from './storeItems.mjs';
9
10
  /**
10
11
  * What the collection needs of its package. A structural interface, so that this module does not
11
12
  * import `WordprocessingMLPackage` (which imports it): the package hands itself in.
@@ -21,24 +22,44 @@ export interface CustomXmlHost {
21
22
  customXmlRelationshipSource(): Part;
22
23
  /** The package, for the XHTML pass (list definitions, styles, relationships); absent, XHTML controls are left and noted. */
23
24
  readonly xhtmlHost?: XhtmlHost;
25
+ /** The package's property resolver, made if need be: a date control without `w:lid` is shown in its document default language (CR-020 D5). */
26
+ getPropertyResolver?(): Promise<unknown>;
24
27
  }
25
28
  /** A subset of Office JS `Word.CustomXmlPartCollection`. */
26
29
  export declare class CustomXmlPartCollection implements CustomXmlPartOwner, CustomXmlPartLookup {
27
30
  private readonly host;
28
31
  private readonly views;
32
+ /** The parts `load()` could not parse, with the parser's error: each read as absent (`notRead`). */
33
+ private readonly unread;
34
+ private readonly storeItems;
29
35
  constructor(host: CustomXmlHost);
30
36
  get xpathEngine(): XPathEngine;
31
37
  /**
32
38
  * Parses every custom XML part's DOM and its properties part, and warms the XPath engine. One
33
39
  * await, and the collection and the node views are synchronous from then on (section 3.6).
40
+ * A part that cannot be parsed is read as absent (`notRead`), not refused for the whole collection.
34
41
  */
35
42
  load(): Promise<CustomXmlPart[]>;
36
- /** The parts, in the order they were registered. Call `load()` once first: a DOM has to be parsed. */
43
+ /**
44
+ * The custom XML parts the last `load()` could not parse (not well formed), by part name, with the parser's error. Each
45
+ * is read as absent, as Word reads such a store when it repairs the document (CR-012 section 28's D3, WD 0.69; CR-020
46
+ * section 8.2): it is in no `items`, `getItem` does not find it, and a binding naming it resolves as one naming no part,
47
+ * to the part its XPath fits, else to none. The part stays in the package, and an untouched save copies its bytes.
48
+ */
49
+ get notRead(): ReadonlyMap<string, unknown>;
50
+ /** The parts, in the order they were registered, but those `load()` could not parse. Call `load()` once first: a DOM has to be parsed. */
37
51
  get items(): CustomXmlPart[];
38
52
  /** The parts whose document element is in that namespace (Office JS getByNamespace). */
39
53
  getByNamespace(namespaceUri: string): CustomXmlPart[];
40
54
  /** The part with that itemID; the comparison ignores case and accepts the id with or without braces. */
41
55
  getItem(id: string): CustomXmlPart | undefined;
56
+ /**
57
+ * The part a binding is evaluated against (CR-020, docx4j's `StoreItemResolver`): the one its `w:storeItemID` names,
58
+ * else, where that names no part, the one its XPath fits, as Word repairs such a binding on open; undefined where none
59
+ * is named and none fits, and for the core and application properties' IDs, which name no part here. `repaired` says
60
+ * which. Call `load()` once first, as for `items`.
61
+ */
62
+ resolveStoreItem(storeItemID: string, xpath: string, prefixMappings?: string): StoreItemResolution<CustomXmlPart> | undefined;
42
63
  /**
43
64
  * A new custom XML part holding this XML, with its properties part and a fresh itemID, related
44
65
  * from the main document part (docx4j's `AbstractMigrator.addPropertiesPart` recipe: Word
@@ -68,13 +89,21 @@ export declare class CustomXmlPartCollection implements CustomXmlPartOwner, Cust
68
89
  applyBindings(options?: {
69
90
  html?: XhtmlBindingOptions;
70
91
  }): Promise<BindingResult>;
92
+ /** The three passes over some controls: the text bindings, the pictures, the XHTML. */
93
+ private bind;
71
94
  /**
72
95
  * docx4j `UpdateXmlFromDocumentSurface.updateCustomXmlParts`: writes what the controls now show
73
96
  * back into the custom XML. The reverse of `applyBindings`, and what makes an edit to a bound
74
97
  * control show in Word (CR-002 section 12).
75
98
  */
76
99
  updateFromContentControls(): Promise<BindingResult>;
100
+ /**
101
+ * The controls the binding passes take, in every branch of a kept `mc:AlternateContent` (CR-013 phase 3):
102
+ * those a reader sees (`read`: outside the elements and in their selected branches) and the others.
103
+ */
77
104
  private controlsOf;
78
105
  /** The view of a part: its itemID and schema references, read from the properties part's DOM. */
79
106
  private viewFor;
80
107
  }
108
+ /** A version 4 UUID, as docx4j's `UUID.randomUUID()` gives (crypto when the runtime has it). */
109
+ export declare function uuid(): string;
@@ -16,11 +16,22 @@ import { CustomXmlPart } from './CustomXmlPart.mjs';
16
16
  import { applyBindingsTo, updateFromControls } from './bindings.mjs';
17
17
  import { applyXhtmlBindingsTo, isXhtmlBound } from './xhtml.mjs';
18
18
  import { applyPictureHandlersTo, updateFromPictureControls } from './pictures.mjs';
19
+ import { StoreItemResolver } from './storeItems.mjs';
20
+ import { inUnreadBranch, writingEveryBranch } from '../content/tree.mjs';
19
21
  /** A subset of Office JS `Word.CustomXmlPartCollection`. */
20
22
  export class CustomXmlPartCollection {
21
23
  constructor(host) {
22
24
  this.host = host;
23
25
  this.views = new Map();
26
+ /** The parts `load()` could not parse, with the parser's error: each read as absent (`notRead`). */
27
+ this.unread = new Map();
28
+ this.storeItems = new StoreItemResolver(() => this.items.map((view) => ({
29
+ part: view,
30
+ id: view.id,
31
+ partName: view.part.partName.name,
32
+ root: view.document.documentElement,
33
+ selects: (xpath, prefixMappings) => view.selectSingleNode(xpath, prefixMappings) !== undefined,
34
+ })));
24
35
  }
25
36
  get xpathEngine() {
26
37
  return this.host.xpathEngine;
@@ -28,10 +39,19 @@ export class CustomXmlPartCollection {
28
39
  /**
29
40
  * Parses every custom XML part's DOM and its properties part, and warms the XPath engine. One
30
41
  * await, and the collection and the node views are synchronous from then on (section 3.6).
42
+ * A part that cannot be parsed is read as absent (`notRead`), not refused for the whole collection.
31
43
  */
32
44
  async load() {
33
45
  for (const part of this.host.customXmlDataStorageParts.values()) {
34
- await part.parseDocument();
46
+ try {
47
+ await part.parseDocument();
48
+ }
49
+ catch (e) {
50
+ this.unread.set(part, e);
51
+ this.views.delete(part);
52
+ continue;
53
+ }
54
+ this.unread.delete(part);
35
55
  if (!this.views.has(part))
36
56
  this.views.set(part, await this.viewFor(part));
37
57
  }
@@ -41,10 +61,21 @@ export class CustomXmlPartCollection {
41
61
  await this.host.xpathEngine.ready(parsed);
42
62
  return this.items;
43
63
  }
44
- /** The parts, in the order they were registered. Call `load()` once first: a DOM has to be parsed. */
64
+ /**
65
+ * The custom XML parts the last `load()` could not parse (not well formed), by part name, with the parser's error. Each
66
+ * is read as absent, as Word reads such a store when it repairs the document (CR-012 section 28's D3, WD 0.69; CR-020
67
+ * section 8.2): it is in no `items`, `getItem` does not find it, and a binding naming it resolves as one naming no part,
68
+ * to the part its XPath fits, else to none. The part stays in the package, and an untouched save copies its bytes.
69
+ */
70
+ get notRead() {
71
+ return new Map([...this.unread].map(([part, error]) => [part.partName.name, error]));
72
+ }
73
+ /** The parts, in the order they were registered, but those `load()` could not parse. Call `load()` once first: a DOM has to be parsed. */
45
74
  get items() {
46
75
  const out = [];
47
76
  for (const part of this.host.customXmlDataStorageParts.values()) {
77
+ if (this.unread.has(part))
78
+ continue;
48
79
  const view = this.views.get(part);
49
80
  if (!view) {
50
81
  throw new Docx4JException(`Custom XML part ${part.partName} is not parsed yet: await pkg.customXmlParts.load() once`);
@@ -62,6 +93,15 @@ export class CustomXmlPartCollection {
62
93
  const key = normaliseId(id);
63
94
  return this.items.find((part) => normaliseId(part.id) === key);
64
95
  }
96
+ /**
97
+ * The part a binding is evaluated against (CR-020, docx4j's `StoreItemResolver`): the one its `w:storeItemID` names,
98
+ * else, where that names no part, the one its XPath fits, as Word repairs such a binding on open; undefined where none
99
+ * is named and none fits, and for the core and application properties' IDs, which name no part here. `repaired` says
100
+ * which. Call `load()` once first, as for `items`.
101
+ */
102
+ resolveStoreItem(storeItemID, xpath, prefixMappings) {
103
+ return this.storeItems.resolve(storeItemID, xpath, prefixMappings);
104
+ }
65
105
  /**
66
106
  * A new custom XML part holding this XML, with its properties part and a fresh itemID, related
67
107
  * from the main document part (docx4j's `AbstractMigrator.addPropertiesPart` recipe: Word
@@ -125,10 +165,14 @@ export class CustomXmlPartCollection {
125
165
  if (part.itemId)
126
166
  this.host.customXmlDataStorageParts.delete(part.itemId);
127
167
  this.views.delete(part);
128
- for (const control of this.controlsOf(this.host.boundBodies())) {
129
- if (normaliseId(control.xmlMapping.storeItemID) === normaliseId(view.id))
130
- control.xmlMapping.delete();
131
- }
168
+ // every branch's controls (CR-013 phase 3)
169
+ const { read, unread } = this.controlsOf(this.host.boundBodies());
170
+ writingEveryBranch(() => {
171
+ for (const control of [...read, ...unread]) {
172
+ if (normaliseId(control.xmlMapping.storeItemID) === normaliseId(view.id))
173
+ control.xmlMapping.delete();
174
+ }
175
+ });
132
176
  }
133
177
  /**
134
178
  * docx4j `BindingHandler.applyBindings`: pushes the custom XML values into the bound controls,
@@ -138,10 +182,26 @@ export class CustomXmlPartCollection {
138
182
  async applyBindings(options = {}) {
139
183
  var _a, _b;
140
184
  await this.load();
141
- const controls = this.controlsOf(await this.host.getBoundBodies());
142
- const result = applyBindingsTo(controls);
185
+ try {
186
+ await ((_b = (_a = this.host).getPropertyResolver) === null || _b === void 0 ? void 0 : _b.call(_a));
187
+ }
188
+ catch {
189
+ // a styles part that can't be read: a date control without w:lid is shown in en-US
190
+ }
191
+ // every branch of a kept mc:AlternateContent is bound, as Word binds what it reads; the result counts
192
+ // what a reader sees, the other branches' controls bound after them and not counted (CR-013 phase 3)
193
+ const { read, unread } = this.controlsOf(await this.host.getBoundBodies());
194
+ const result = await this.bind(read, options);
195
+ if (unread.length > 0)
196
+ await this.bind(unread, options);
197
+ return result;
198
+ }
199
+ /** The three passes over some controls: the text bindings, the pictures, the XHTML. */
200
+ async bind(controls, options) {
201
+ var _a, _b;
202
+ const result = writingEveryBranch(() => applyBindingsTo(controls));
143
203
  // od:Handler=picture through the tag's od:xpath entry (CR-005 section 9): after the text bindings, which took the picture controls.
144
- applyPictureHandlersTo(controls, this, result);
204
+ writingEveryBranch(() => applyPictureHandlersTo(controls, this, result));
145
205
  // Escaped XHTML through the tag's od:xpath entry (CR-005 section 8.2): after the text bindings, asynchronous.
146
206
  if (this.host.xhtmlHost)
147
207
  await applyXhtmlBindingsTo(controls, this, this.host.xhtmlHost, result, (_a = options.html) !== null && _a !== void 0 ? _a : {});
@@ -156,14 +216,23 @@ export class CustomXmlPartCollection {
156
216
  */
157
217
  async updateFromContentControls() {
158
218
  await this.load();
159
- const controls = this.controlsOf(await this.host.getBoundBodies());
219
+ // what a reader sees of the controls: the selected branch's, as Word writes back what it shows (CR-013 phase 3)
220
+ const controls = this.controlsOf(await this.host.getBoundBodies()).read;
160
221
  const result = updateFromControls(controls);
161
222
  // a mapped picture control's image back to its node, as Word 15 writes it (CR-005 section 9, check 38)
162
223
  await updateFromPictureControls(controls, result);
163
224
  return result;
164
225
  }
226
+ /**
227
+ * The controls the binding passes take, in every branch of a kept `mc:AlternateContent` (CR-013 phase 3):
228
+ * those a reader sees (`read`: outside the elements and in their selected branches) and the others.
229
+ */
165
230
  controlsOf(bodies) {
166
- return bodies.flatMap((body) => body.contentControls);
231
+ const read = [];
232
+ const unread = [];
233
+ for (const control of bodies.flatMap((body) => body.contentControlsIn('every')))
234
+ (inUnreadBranch(control.sdt) ? unread : read).push(control);
235
+ return { read, unread };
167
236
  }
168
237
  /** The view of a part: its itemID and schema references, read from the properties part's DOM. */
169
238
  async viewFor(part) {
@@ -212,7 +281,7 @@ function suffixOf(partName) {
212
281
  return (_a = m === null || m === void 0 ? void 0 : m[1]) !== null && _a !== void 0 ? _a : '';
213
282
  }
214
283
  /** A version 4 UUID, as docx4j's `UUID.randomUUID()` gives (crypto when the runtime has it). */
215
- function uuid() {
284
+ export function uuid() {
216
285
  const c = globalThis.crypto;
217
286
  if (c === null || c === void 0 ? void 0 : c.randomUUID)
218
287
  return c.randomUUID();
@@ -1,17 +1,22 @@
1
1
  import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
- import type { ContentControl } from '../content/ContentControl.mjs';
2
+ import { type ContentControl } from '../content/ContentControl.mjs';
3
3
  import type { CustomXmlPart, CustomXmlNode } from './CustomXmlPart.mjs';
4
+ import { type StoreItemResolution } from './storeItems.mjs';
4
5
  /** What `XmlMapping` needs of `pkg.customXmlParts`, so that this module does not import the package. */
5
6
  export interface CustomXmlPartLookup {
6
7
  readonly items: CustomXmlPart[];
7
8
  getItem(id: string): CustomXmlPart | undefined;
9
+ /** The part a binding is evaluated against: named by its ID, else the one its XPath fits (CR-020). */
10
+ resolveStoreItem(storeItemID: string, xpath: string, prefixMappings?: string): StoreItemResolution<CustomXmlPart> | undefined;
8
11
  }
9
12
  /**
10
- * A subset of Office JS `Word.XmlMapping`: the content control's data binding. `isMapped` is
11
- * whether the control has a `w:dataBinding` (or, on a rich text control or a repeating section,
12
- * the `w15:dataBinding` Word writes there, which is what `setMapping` writes on one: CR-002
13
- * section 40); `customXmlNode` evaluates the XPath now, so it needs
14
- * the XPath engine to be warm (`await pkg.customXmlParts.load()` once, CR-002 section 3.6).
13
+ * A subset of Office JS `Word.XmlMapping`: the content control's data binding, `w:dataBinding`
14
+ * (or, on a rich text control or a repeating section, the `w15:dataBinding` Word writes there,
15
+ * which is what `setMapping` writes on one: CR-002 section 40). `customXmlPart` is the part the
16
+ * binding is evaluated against, the one its `w:storeItemID` names or, where that names none, the
17
+ * one its XPath fits, as Word repairs it (CR-020); `customXmlNode` and `isMapped` evaluate the
18
+ * XPath there now, so they need the parts parsed and the XPath engine warm (`await
19
+ * pkg.customXmlParts.load()` once, CR-002 section 3.6).
15
20
  */
16
21
  export declare class XmlMapping {
17
22
  /** The control this mapping belongs to. */
@@ -22,15 +27,34 @@ export declare class XmlMapping {
22
27
  contentControl: ContentControl, lookup: CustomXmlPartLookup | undefined);
23
28
  /** The `w:dataBinding` value, or undefined when the control has none (extension). */
24
29
  get dataBinding(): wml.CTDataBinding | undefined;
30
+ /**
31
+ * Whether the binding names a node, as Office JS reports it (CR-020 D8, check 73b: a control bound to its part by ID
32
+ * with an XPath that selects nothing is not mapped): the node the XPath selects in the part the binding resolves to, so
33
+ * a stale `w:storeItemID` no part fits is not mapped either. A binding to the core or application properties, which are
34
+ * not custom XML parts here, is mapped. `dataBinding` says whether the control carries a binding at all.
35
+ */
25
36
  get isMapped(): boolean;
26
37
  get xpath(): string;
27
38
  get prefixMappings(): string;
28
- /** `w:storeItemID`, the itemID of the custom XML part (extension: Office JS reports the part). */
39
+ /**
40
+ * `w:storeItemID`, the itemID of the custom XML part, as stored (extension: Office JS reports the part). A stale ID stays
41
+ * as it is until `applyBindings` writes the resolved part's back, as Word's save does (CR-020 D2 and D3).
42
+ */
29
43
  get storeItemID(): string;
30
- /** The part the binding names, when the package has it. */
44
+ /**
45
+ * The part the binding is evaluated against: the one its `w:storeItemID` names, else the one its XPath fits, as Word
46
+ * binds it (CR-020; check 73b: Office JS's `customXmlPart` for a stale ID is the part Word repaired it to).
47
+ */
31
48
  get customXmlPart(): CustomXmlPart | undefined;
32
49
  /** The node the XPath selects now, or undefined when it selects nothing. */
33
50
  get customXmlNode(): CustomXmlNode | undefined;
51
+ /** @internal How the binding resolves (CR-020): its part, and whether that is Word's repair of a stale ID. */
52
+ get resolution(): StoreItemResolution<CustomXmlPart> | undefined;
53
+ /**
54
+ * @internal Writes a part's ID over a stale `w:storeItemID`, in `w:dataBinding` and `w15:dataBinding` alike, as Word's
55
+ * save writes the part it repaired the binding to (CR-020 D2): `applyBindings`' write-back, never a reader's.
56
+ */
57
+ repairStoreItemID(stale: string, id: string): void;
34
58
  /**
35
59
  * Binds the control to what the XPath selects, as Word's own mapping does: the part is the one
36
60
  * given, else the one the control is already bound to, else the first custom XML part (the
@@ -1,17 +1,22 @@
1
1
  import * as el from '@docx4j/generated-objects-ts/el/org_docx4j_wml';
2
2
  import * as w15el from '@docx4j/generated-objects-ts/el/org_docx4j_w15';
3
3
  import { sdtProperty } from '@docx4j/generated-objects-ts/builders/wml';
4
+ import { holdsOneParagraph } from '../content/ContentControl.mjs';
5
+ import { NotSupportedError } from '../../office-js/errors.mjs';
4
6
  import { canonicalXPathOf } from './xpath.mjs';
5
7
  import { applyBindingTo } from './bindings.mjs';
8
+ import { isPropertiesStoreItem, normaliseStoreItemId } from './storeItems.mjs';
6
9
  /** The Word 2012 (w15) namespace; not imported from `ContentControl`, which imports this module. */
7
10
  const W15_NS = 'http://schemas.microsoft.com/office/word/2012/wordml';
8
11
  const W_NS = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
9
12
  /**
10
- * A subset of Office JS `Word.XmlMapping`: the content control's data binding. `isMapped` is
11
- * whether the control has a `w:dataBinding` (or, on a rich text control or a repeating section,
12
- * the `w15:dataBinding` Word writes there, which is what `setMapping` writes on one: CR-002
13
- * section 40); `customXmlNode` evaluates the XPath now, so it needs
14
- * the XPath engine to be warm (`await pkg.customXmlParts.load()` once, CR-002 section 3.6).
13
+ * A subset of Office JS `Word.XmlMapping`: the content control's data binding, `w:dataBinding`
14
+ * (or, on a rich text control or a repeating section, the `w15:dataBinding` Word writes there,
15
+ * which is what `setMapping` writes on one: CR-002 section 40). `customXmlPart` is the part the
16
+ * binding is evaluated against, the one its `w:storeItemID` names or, where that names none, the
17
+ * one its XPath fits, as Word repairs it (CR-020); `customXmlNode` and `isMapped` evaluate the
18
+ * XPath there now, so they need the parts parsed and the XPath engine warm (`await
19
+ * pkg.customXmlParts.load()` once, CR-002 section 3.6).
15
20
  */
16
21
  export class XmlMapping {
17
22
  constructor(
@@ -29,8 +34,20 @@ export class XmlMapping {
29
34
  const item = (_a = sdtProperty(pr, 'dataBinding')) !== null && _a !== void 0 ? _a : sdtProperty(pr, 'dataBinding', W15_NS);
30
35
  return item === null || item === void 0 ? void 0 : item.value;
31
36
  }
37
+ /**
38
+ * Whether the binding names a node, as Office JS reports it (CR-020 D8, check 73b: a control bound to its part by ID
39
+ * with an XPath that selects nothing is not mapped): the node the XPath selects in the part the binding resolves to, so
40
+ * a stale `w:storeItemID` no part fits is not mapped either. A binding to the core or application properties, which are
41
+ * not custom XML parts here, is mapped. `dataBinding` says whether the control carries a binding at all.
42
+ */
32
43
  get isMapped() {
33
- return this.dataBinding !== undefined;
44
+ var _a;
45
+ const binding = this.dataBinding;
46
+ if (!binding)
47
+ return false;
48
+ if (isPropertiesStoreItem((_a = binding.storeItemID) !== null && _a !== void 0 ? _a : ''))
49
+ return true;
50
+ return this.customXmlNode !== undefined;
34
51
  }
35
52
  get xpath() {
36
53
  var _a, _b;
@@ -40,16 +57,21 @@ export class XmlMapping {
40
57
  var _a, _b;
41
58
  return (_b = (_a = this.dataBinding) === null || _a === void 0 ? void 0 : _a.prefixMappings) !== null && _b !== void 0 ? _b : '';
42
59
  }
43
- /** `w:storeItemID`, the itemID of the custom XML part (extension: Office JS reports the part). */
60
+ /**
61
+ * `w:storeItemID`, the itemID of the custom XML part, as stored (extension: Office JS reports the part). A stale ID stays
62
+ * as it is until `applyBindings` writes the resolved part's back, as Word's save does (CR-020 D2 and D3).
63
+ */
44
64
  get storeItemID() {
45
65
  var _a, _b;
46
66
  return (_b = (_a = this.dataBinding) === null || _a === void 0 ? void 0 : _a.storeItemID) !== null && _b !== void 0 ? _b : '';
47
67
  }
48
- /** The part the binding names, when the package has it. */
68
+ /**
69
+ * The part the binding is evaluated against: the one its `w:storeItemID` names, else the one its XPath fits, as Word
70
+ * binds it (CR-020; check 73b: Office JS's `customXmlPart` for a stale ID is the part Word repaired it to).
71
+ */
49
72
  get customXmlPart() {
50
73
  var _a;
51
- const id = this.storeItemID;
52
- return id === '' ? undefined : (_a = this.lookup) === null || _a === void 0 ? void 0 : _a.getItem(id);
74
+ return (_a = this.resolution) === null || _a === void 0 ? void 0 : _a.part;
53
75
  }
54
76
  /** The node the XPath selects now, or undefined when it selects nothing. */
55
77
  get customXmlNode() {
@@ -59,6 +81,29 @@ export class XmlMapping {
59
81
  return undefined;
60
82
  return part.selectSingleNode(binding.xpath, binding.prefixMappings);
61
83
  }
84
+ /** @internal How the binding resolves (CR-020): its part, and whether that is Word's repair of a stale ID. */
85
+ get resolution() {
86
+ var _a;
87
+ const binding = this.dataBinding;
88
+ if (!(binding === null || binding === void 0 ? void 0 : binding.storeItemID))
89
+ return undefined;
90
+ return (_a = this.lookup) === null || _a === void 0 ? void 0 : _a.resolveStoreItem(binding.storeItemID, binding.xpath, binding.prefixMappings);
91
+ }
92
+ /**
93
+ * @internal Writes a part's ID over a stale `w:storeItemID`, in `w:dataBinding` and `w15:dataBinding` alike, as Word's
94
+ * save writes the part it repaired the binding to (CR-020 D2): `applyBindings`' write-back, never a reader's.
95
+ */
96
+ repairStoreItemID(stale, id) {
97
+ var _a, _b, _c;
98
+ const key = normaliseStoreItemId(stale);
99
+ for (const item of ((_b = (_a = this.contentControl.sdt.sdtPr) === null || _a === void 0 ? void 0 : _a.rPrOrAliasOrLock) !== null && _b !== void 0 ? _b : [])) {
100
+ if (item.name.localPart !== 'dataBinding')
101
+ continue;
102
+ const binding = item.value;
103
+ if (normaliseStoreItemId((_c = binding.storeItemID) !== null && _c !== void 0 ? _c : '') === key)
104
+ binding.storeItemID = id;
105
+ }
106
+ }
62
107
  /**
63
108
  * Binds the control to what the XPath selects, as Word's own mapping does: the part is the one
64
109
  * given, else the one the control is already bound to, else the first custom XML part (the
@@ -112,6 +157,15 @@ export class XmlMapping {
112
157
  if (prefixMappings !== '')
113
158
  binding.prefixMappings = prefixMappings;
114
159
  const w15 = this.usesW15;
160
+ // w:dataBinding makes a block control plain text to Word, which holds it to one paragraph: binding one that holds
161
+ // more is refused before anything changes, since Word couldn't open the file (CR-002 section 61.6, check 56;
162
+ // docx4j-python's review). w15:dataBinding, Word's rich-text binding, may hold blocks.
163
+ const control = this.contentControl;
164
+ if (!w15 && control.form === 'Block' && (control.type === 'PlainText' || control.type === 'RichText') && !holdsOneParagraph(control)) {
165
+ throw new NotSupportedError('XmlMapping', 'setMapping', 'this block content control holds more than one paragraph, and a control '
166
+ + "bound by w:dataBinding is plain text to Word, which can't open a file where one holds more (CR-002 section 61, check 56); "
167
+ + 'leave it one paragraph first');
168
+ }
115
169
  const element = (w15 ? w15el.dataBinding(binding) : el.dataBinding(binding));
116
170
  const items = (_a = this.contentControl.sdt.sdtPr) === null || _a === void 0 ? void 0 : _a.rPrOrAliasOrLock;
117
171
  const other = w15 ? W_NS : W15_NS;
@@ -1,9 +1,12 @@
1
1
  import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
2
  import type { Element } from '../content/tree.mjs';
3
3
  import type { ContentControl } from '../content/ContentControl.mjs';
4
- /** The style Word gives placeholder text, and the text docx4j's placeholder.xml carries. */
4
+ /**
5
+ * The style Word gives placeholder text, and the text docx4j's placeholder.xml carries: Word 365's since docx4j's CR-063
6
+ * D5 (CR-002 section 63.22), where it was Word 2010's "Click here to enter text.".
7
+ */
5
8
  export declare const PLACEHOLDER_STYLE = "PlaceholderText";
6
- export declare const PLACEHOLDER_TEXT = "Click here to enter text.";
9
+ export declare const PLACEHOLDER_TEXT = "Click or tap here to enter text.";
7
10
  /** What `applyBindings` and `updateFromContentControls` report. */
8
11
  export interface BindingResult {
9
12
  /** Controls carrying a `w:dataBinding`. */
@@ -12,7 +15,11 @@ export interface BindingResult {
12
15
  updated: number;
13
16
  /** Controls left alone: the part is missing, the XPath selects nothing, or the kind is not handled. */
14
17
  skipped: number;
15
- /** What the XHTML and picture passes left or dropped, one line each (CR-005 sections 8.2 and 9; REQ-076). */
18
+ /**
19
+ * What the XHTML and picture passes left or dropped, one line each (CR-005 sections 8.2 and 9; REQ-076), and each
20
+ * control whose `w:storeItemID` names no part: bound to the part its XPath fits, as Word repairs it, or left as it is
21
+ * where none fits (CR-020 D4).
22
+ */
16
23
  notes?: string[];
17
24
  }
18
25
  /**
@@ -22,13 +29,31 @@ export interface BindingResult {
22
29
  * control bound to the same node - so neither direction moves it as text (CR-002 section 40).
23
30
  */
24
31
  export declare function holdsFlatOpc(value: string): boolean;
32
+ /**
33
+ * A control's text as its node takes it (CR-002 section 60 D4, F1, F2): `textOf`'s characters, as before CR-012 phase 4
34
+ * moved `ContentControl.text` to Office JS's, its paragraphs and breaks a line feed each, a non-breaking hyphen `-` as
35
+ * Word writes it (check 55b), an optional hyphen U+00AD, a note reference nothing. Office JS's U+000B and U+001E are no
36
+ * XML characters.
37
+ */
38
+ export declare function boundValueOf(control: ContentControl): string;
25
39
  /** docx4j ValueInserterPlainTextImpl: the runs for a value, with the w:sdtPr run properties. */
26
40
  export declare function runsForValue(value: string, rPr: wml.RPr | undefined, multiLine: boolean): Element[];
41
+ /**
42
+ * docx4j's placeholder.xml: a PlaceholderText-styled run over the control's own run properties, which goes with
43
+ * w:showingPlcHdr; its text docx4j's, or a glossary entry's (CR-002 section 63, D8).
44
+ */
45
+ export declare function placeholderRun(rPr: wml.RPr | undefined, text?: string): Element;
27
46
  /**
28
47
  * A date in Word's `w:dateFormat` pattern (the .NET forms Word writes: `d MMMM yyyy`,
29
48
  * `dddd, d MMMM yyyy`, `d/MM/yyyy`), in the control's `w:lid` locale. Month and day names come
30
49
  * from `Intl`; text inside single or double quotes is literal. docx4j uses Java's
31
- * `SimpleDateFormat` with `dddd` mapped to `EEEE`; this is the same vocabulary.
50
+ * `SimpleDateFormat` with `dddd` mapped to `EEEE`; this is the same vocabulary. `am/pm` and
51
+ * `AM/PM` (any mix of cases, as docx4j's `isAMPM`) are the locale's day-period names upper-cased,
52
+ * as Word shows both (CR-020 D5, docx4j CR-058's `wordAmPm`): `h:mm am/pm` at 15:05 is `3:05 PM`.
53
+ *
54
+ * The date's **UTC fields** are formatted: a bound date is its nominal date, the fields as written,
55
+ * which `w:fullDate` keeps with a `Z` and `DatePickerContentControl.fullDate` returns as a `Date` in
56
+ * UTC, so the day shown is the same whatever the machine's time zone (CR-002 section 56).
32
57
  */
33
58
  export declare function formatDate(pattern: string, date: Date, locale?: string): string;
34
59
  /**
@@ -36,6 +61,10 @@ export declare function formatDate(pattern: string, date: Date, locale?: string)
36
61
  * false when nothing was written: no binding, no part, an XPath that selects nothing, a kind
37
62
  * this phase does not handle (explicit rich text), a node holding a Flat OPC package, or a
38
63
  * picture control whose node holds no image (`notes` says which; CR-005 section 9).
64
+ *
65
+ * The part is the one the binding resolves to (CR-020): where its `w:storeItemID` names no part,
66
+ * the one its XPath fits, as Word repairs it on open; a control so bound gets that part's ID in
67
+ * its binding, as Word's save writes it (D2), and a note, as does a stale ID no part fits (D4).
39
68
  */
40
69
  export declare function applyBindingTo(control: ContentControl, notes?: string[]): boolean;
41
70
  /** `applyBindings` over a list of controls. */