@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
@@ -1,20 +1,32 @@
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 { Docx4JException } from '../../opc/exceptions.mjs';
4
+ import { NotSupportedError } from '../../office-js/errors.mjs';
5
+ import { GeneralException, InvalidArgument } from './generalException.mjs';
4
6
  import { marshalString, deepCopy } from '@docx4j/generated-objects-ts';
5
7
  // CR-002 phase E: the mapping and the typed kinds live in src/model/customxml/; they import
6
8
  // nothing from here at run time (types only), so this direction is the only one.
7
9
  import { XmlMapping } from '../customxml/XmlMapping.mjs';
8
10
  import { CheckboxContentControl, DatePickerContentControl, ListContentControl, PictureContentControl, RepeatingSectionContentControl, GroupContentControl, checkboxRun, CHECKBOX_FONT, } from '../customxml/kinds.mjs';
9
- import { runsForValue, updateFromControl, PLACEHOLDER_TEXT, PLACEHOLDER_STYLE } from '../customxml/bindings.mjs';
10
- import { declareIgnorable } from './tracking.mjs';
11
- import { sdtProperty, sdtKindOf, t as textItem } from '@docx4j/generated-objects-ts/builders/wml';
12
- import { typeNameOf, childrenOf, textOf, runItemsOf, segmentsOf, linkParents, runOf, SDT_TYPES } from './tree.mjs';
11
+ import { updateFromControl, holdsFlatOpc, placeholderRun, PLACEHOLDER_STYLE } from '../customxml/bindings.mjs';
12
+ import { dropExcluded, forWriter, officeItems } from './officeText.mjs';
13
+ import { declareIgnorable, markHolderDeleted } from './tracking.mjs';
14
+ import { placeholderEntryOf, namePlaceholderEntry, newEntryName, entryContentOf, defaultEntryFor, DEFAULT_ENTRIES } from './placeholders.mjs';
15
+ import { relationshipIdsIn, queueRelationshipRemovals } from './relationships.mjs';
16
+ import { commentReferencesIn } from './TrackedChange.mjs';
17
+ import { wrappingCellOf, paragraphEndOf, endsWithParagraph, endWithParagraph } from './tableRules.mjs';
18
+ import { sdtProperty, sdtKindOf } from '@docx4j/generated-objects-ts/builders/wml';
19
+ import { typeNameOf, childrenOf, runItemsOf, runsOf, linkParents, runOf, SDT_TYPES, ALTERNATE_CONTENT, BLOCK_LEVEL_TYPES, branchListsOf, inBranch, assertOutsideBranch } from './tree.mjs';
13
20
  import { Range } from './Range.mjs';
14
21
  import { Table } from './Table.mjs';
22
+ import { assignParaIds } from './paraIds.mjs';
15
23
  /** The namespaces of the Word 2010 and 2012 content-control properties. */
16
24
  export const W14_NS = 'http://schemas.microsoft.com/office/word/2010/wordml';
17
25
  export const W15_NS = 'http://schemas.microsoft.com/office/word/2012/wordml';
26
+ /** The markers of a control inserted or deleted under tracking (`markHolderInserted`, `markHolderDeleted`). */
27
+ const TRACKED_HOLDER_MARKER = /^customXml(Ins|Del)Range(Start|End)$/;
28
+ /** What a block, row or cell control's content ends with, for its range's end: a paragraph, a table or a row. */
29
+ const BLOCK_ITEMS = new Set(['org_docx4j_wml.P', 'org_docx4j_wml.Tbl', 'org_docx4j_wml.Tr', 'org_docx4j_wml.Tc']);
18
30
  /** A subset of Office JS `Word.ContentControl` over a `w:sdt`. A view, as Paragraph is. */
19
31
  export class ContentControl {
20
32
  constructor(
@@ -54,7 +66,10 @@ export class ContentControl {
54
66
  }
55
67
  /** The type Word reports (w:sdtPr's kind element); RichText when none is given, as Word does. */
56
68
  get type() {
57
- return sdtKindOf(this.sdt.sdtPr);
69
+ const kind = sdtKindOf(this.sdt.sdtPr);
70
+ // Word reads a block control bound by w:dataBinding, untyped or w:richText, as single-line plain text, and saves it
71
+ // so (checks 35 and 56; CR-002 section 61 H4); the file is left as it is
72
+ return kind === 'RichText' && isBoundBlockControl(this) ? 'PlainText' : kind;
58
73
  }
59
74
  /** w:tag. */
60
75
  get tag() {
@@ -77,10 +92,20 @@ export class ContentControl {
77
92
  const val = (_c = item === null || item === void 0 ? void 0 : item.value) === null || _c === void 0 ? void 0 : _c.val;
78
93
  return typeof val === 'number' ? val : 0;
79
94
  }
80
- /** The control's text, a line per paragraph (docx4j TextUtils). */
95
+ /**
96
+ * The control's text as Office JS gives it (CR-012 phase 4): a run-level control's span of
97
+ * `Paragraph.text`; a block-level one's content as `Body.text` reads it, its paragraphs a mark `\r` apart
98
+ * (check 51); a row control's cells a `\t` apart and a cell control's paragraphs `\r` apart (check 53).
99
+ */
81
100
  get text() {
82
- var _a;
83
- return textOf((_a = this.sdt.sdtContent) !== null && _a !== void 0 ? _a : {});
101
+ if (this.form === 'Run') {
102
+ const span = this.runSpan();
103
+ return span ? span.paragraph.text.substring(span.start, span.end) : '';
104
+ }
105
+ // a row control's cells a \t apart (check 53: ROW15A\tROW15B), a cell control's paragraphs a \r apart; a
106
+ // control's content ending with a row (a row control, or a table last) leaves the row's end out (check 53)
107
+ const text = this.body().text;
108
+ return text.endsWith('\r\n') ? text.slice(0, -2) : text;
84
109
  }
85
110
  /** Every paragraph in the control; for a run-level control, the paragraph it is in. */
86
111
  get paragraphs() {
@@ -106,6 +131,14 @@ export class ContentControl {
106
131
  collectControls(this.content, this.parentBody, out);
107
132
  return out;
108
133
  }
134
+ /**
135
+ * Office JS `getContentControls` (WordApi 1.5): the content controls `contentControls` lists, those of `options.types`
136
+ * where given. Word's `contentControls` lists rich-text controls only; this package's lists every kind, a recorded
137
+ * departure (CR-002 section 60 G1, check 55b), so this is how add-in code that asks for plain-text controls finds them.
138
+ */
139
+ getContentControls(options) {
140
+ return controlsOfTypes(this.contentControls, options);
141
+ }
109
142
  /**
110
143
  * Text at the start, the end, or replacing the control's text. On a **bound** control the value
111
144
  * is written through to the custom XML node as well when the mapping resolves (CR-002 phase E):
@@ -114,10 +147,298 @@ export class ContentControl {
114
147
  * write is left to `pkg.customXmlParts.updateFromContentControls()`.
115
148
  */
116
149
  insertText(text, location) {
150
+ this.assertWritable();
151
+ // a control showing its placeholder takes the text in the placeholder's place, wherever it is put (check 58 cases 20
152
+ // to 22, CR-012 section 18; CR-002 section 63)
153
+ if (this.showsPlaceholderContent)
154
+ return this.writePlaceholder(text);
117
155
  const range = this.insertTextInto(text, location);
118
156
  this.syncBoundNode();
119
157
  return range;
120
158
  }
159
+ // --- CR-002 section 63: writing into a control showing its placeholder ---
160
+ /**
161
+ * The glossary entry the control's `w:placeholder` names, which makes it Word's form; undefined where it names none,
162
+ * the bare form, which has no entry to show once emptied, nor for `placeholderText` to read (CR-002 section 63; an
163
+ * extension). Writes are the same in both forms (check 63's run 2).
164
+ */
165
+ get placeholderEntry() {
166
+ return placeholderEntryOf(this.sdt.sdtPr);
167
+ }
168
+ /** @internal True for a block or run-level control showing its placeholder, which a text write replaces (section 63). */
169
+ get showsPlaceholderContent() {
170
+ return this.isShowingPlaceholder && (this.form === 'Block' || this.form === 'Run');
171
+ }
172
+ /** The package's glossary entries, where the control is in a package. */
173
+ get glossary() {
174
+ var _a;
175
+ return (_a = this.parentBody.package_) === null || _a === void 0 ? void 0 : _a.glossaryEntries;
176
+ }
177
+ /**
178
+ * @internal Text written into the content of this control while it shows its placeholder, by any route: its own
179
+ * `insertText`, its 'Content' range's, a block control's paragraph's (CR-002 section 63, D1, D2 (b), D5, D11). The
180
+ * placeholder is no content, in either form (checks 64 and 67, check 63's run 2): its runs go, untracked, the text takes
181
+ * their place in one paragraph, and the flag is cleared; under tracking only the insertion is recorded. The text takes
182
+ * the control's own run properties (`w:sdtPr/w:rPr`) and nothing of the placeholder's (check 68, cases 1 to 20).
183
+ */
184
+ writePlaceholder(text, options = {}) {
185
+ this.assertWritable();
186
+ const form = this.form;
187
+ // refused before anything changes: a line break into a run-level control (CR-002 section 60 F4)
188
+ if (form === 'Run')
189
+ textForRunControl(this, dropExcluded(text));
190
+ this.takePlaceholderRuns(form);
191
+ this.isShowingPlaceholder = false;
192
+ let range;
193
+ if (form === 'Run') {
194
+ const paragraph = this.parentParagraph();
195
+ if (!paragraph)
196
+ throw new Docx4JException('This content control is not in a paragraph');
197
+ range = this.insertIntoEmpty(paragraph, text);
198
+ }
199
+ else {
200
+ range = this.firstParagraph().splice(0, 0, text, 'before', undefined, options.lineBreaks);
201
+ }
202
+ // every run now in the control is the write's: each takes a copy of the control's run properties (D11)
203
+ const rPr = this.runProperties;
204
+ if (rPr) {
205
+ const holder = form === 'Run' ? this.sdt.sdtContent : undefined;
206
+ const runs = holder ? runsOf(holder) : this.body().paragraphs.flatMap((p) => runsOf(p.p));
207
+ for (const run of runs) {
208
+ run.value.rPr = deepCopy(rPr);
209
+ linkParents(run.value.rPr, run.value);
210
+ }
211
+ }
212
+ this.syncBoundNode();
213
+ return range;
214
+ }
215
+ /** The control's first paragraph, made where its content has none. */
216
+ firstParagraph() {
217
+ var _a;
218
+ var _b;
219
+ const body = this.body();
220
+ const first = body.paragraphs[0];
221
+ if (first)
222
+ return first;
223
+ const p = el.p({ content: [] });
224
+ const content = ((_a = (_b = this.sdt.sdtContent).content) !== null && _a !== void 0 ? _a : (_b.content = []));
225
+ content.push(p);
226
+ linkParents(p, this.sdt.sdtContent);
227
+ assignParaIds(this.sdt.sdtContent, [p]);
228
+ return body.paragraphs[0];
229
+ }
230
+ /**
231
+ * Takes the placeholder's runs out of the content: a run-level control's, or a block control's paragraphs', the first
232
+ * paragraph kept, emptied, and any other going. What held them.
233
+ */
234
+ takePlaceholderRuns(form) {
235
+ var _a, _b, _c, _d, _e, _f, _g;
236
+ var _h, _j, _k;
237
+ const runs = [];
238
+ const take = (items) => {
239
+ for (let i = 0; i < items.length; i++) {
240
+ if (typeNameOf(items[i]) !== 'org_docx4j_wml.R')
241
+ continue;
242
+ runs.push(items.splice(i, 1)[0]);
243
+ i--;
244
+ }
245
+ };
246
+ if (form === 'Run') {
247
+ const owner = ((_a = (_h = this.sdt).sdtContent) !== null && _a !== void 0 ? _a : (_h.sdtContent = {}));
248
+ const holder = ((_b = owner.content) !== null && _b !== void 0 ? _b : (owner.content = []));
249
+ take(holder);
250
+ return { runs, holder, owner };
251
+ }
252
+ const content = (_d = (_c = this.sdt.sdtContent) === null || _c === void 0 ? void 0 : _c.content) !== null && _d !== void 0 ? _d : [];
253
+ const paragraphs = content.filter((e) => typeNameOf(e) === 'org_docx4j_wml.P');
254
+ for (const p of paragraphs)
255
+ take(((_e = (_j = p.value).content) !== null && _e !== void 0 ? _e : (_j.content = [])));
256
+ for (const p of paragraphs.slice(1))
257
+ content.splice(content.indexOf(p), 1);
258
+ const first = (_f = paragraphs[0]) !== null && _f !== void 0 ? _f : this.firstParagraph().element;
259
+ return { runs, holder: ((_g = (_k = first.value).content) !== null && _g !== void 0 ? _g : (_k.content = [])), owner: first.value };
260
+ }
261
+ /**
262
+ * Shows Word's filler for a control emptied in the bare form, where no glossary entry gives it a placeholder: the flag
263
+ * on over a run of five spaces, in the control's own run properties (CR-002 section 63, D10; check 63's run 2, cases 6,
264
+ * 17, 32 and 43, and check 52's case 13). Nothing is marked under tracking. The spaces read as no text while the flag is
265
+ * on (CR-012 section 18).
266
+ */
267
+ showFiller() {
268
+ const { holder, owner } = this.takePlaceholderRuns(this.form);
269
+ const rPr = this.runProperties;
270
+ const run = el.r({ ...(rPr ? { rPr: deepCopy(rPr) } : {}), content: [el.t({ TYPE_NAME: 'org_docx4j_wml.Text', value: ' ', space: 'preserve' })] });
271
+ pushBeforeMarker(holder, run);
272
+ linkParents(run, owner);
273
+ this.isShowingPlaceholder = true;
274
+ }
275
+ /**
276
+ * @internal A write through the control's 'Content' or 'Whole' range that the control takes (D3, D4): text into a
277
+ * control showing its placeholder, or into an empty run-level control, goes inside it; a 'Whole' range's Replace over
278
+ * a run-level control showing its placeholder takes the control, the text in its place. Undefined where the range's
279
+ * own write applies.
280
+ */
281
+ writeThrough(part, text, location) {
282
+ var _a;
283
+ if (part === 'Content') {
284
+ if (this.showsPlaceholderContent)
285
+ return this.writePlaceholder(text);
286
+ if (this.form !== 'Run' || !((_a = this.runSpan()) === null || _a === void 0 ? void 0 : _a.empty))
287
+ return undefined;
288
+ this.assertWritable();
289
+ const range = this.insertTextInto(text, 'Replace');
290
+ this.syncBoundNode();
291
+ return range;
292
+ }
293
+ if (location !== 'Replace' || this.form !== 'Run' || !this.isShowingPlaceholder)
294
+ return undefined;
295
+ return this.takeWhole(text);
296
+ }
297
+ /**
298
+ * @internal A delete through the control's 'Content' or 'Whole' range that the control takes; false where the range's
299
+ * own delete applies. A 'Content' delete of a control showing its placeholder keeps the control and the flag: in the
300
+ * bare form over Word's filler, five spaces (D10; check 63's run 2, cases 6, 17, 32 and 43, nothing marked under
301
+ * tracking); in Word's form nothing changes, the placeholder being no content. A 'Whole' delete takes a run-level
302
+ * control showing its placeholder (D3).
303
+ */
304
+ deleteThrough(part) {
305
+ if (part === 'Whole') {
306
+ if (this.form !== 'Run' || !this.isShowingPlaceholder)
307
+ return false;
308
+ this.takeWhole('');
309
+ return true;
310
+ }
311
+ if (!this.showsPlaceholderContent)
312
+ return false;
313
+ this.assertWritable();
314
+ if (this.placeholderEntry === undefined)
315
+ this.showFiller();
316
+ return true;
317
+ }
318
+ /**
319
+ * @internal After a 'Content' delete, untracked, that left the control holding no text: in Word's form it shows its
320
+ * entry again (check 66 case 3); in the bare form Word's filler (D10; check 52's case 13), as for a control of a kind
321
+ * Word gives no default entry, naming an entry the glossary lacks.
322
+ */
323
+ showEmptied() {
324
+ var _a;
325
+ if (this.isShowingPlaceholder || this.text !== '' || (this.form !== 'Block' && this.form !== 'Run'))
326
+ return;
327
+ const name = this.placeholderEntry;
328
+ if (name !== undefined && (this.defaultPlaceholderEntry !== undefined || ((_a = this.glossary) === null || _a === void 0 ? void 0 : _a.has(name)) === true))
329
+ this.showPlaceholder();
330
+ else
331
+ this.showFiller();
332
+ }
333
+ /**
334
+ * @internal Word's default placeholder entry for this control's kind (CR-002 section 63.22; docx4j CR-063's D8): the
335
+ * text kinds', the date picker's, the lists', a building block gallery's, a repeating section item's. Undefined for a
336
+ * kind Word gives none.
337
+ */
338
+ get defaultPlaceholderEntry() {
339
+ return defaultEntryFor(this.sdt.sdtPr);
340
+ }
341
+ /**
342
+ * @internal Whether an empty control shows a placeholder in Word's form (D8; docx4j CR-063's D3 and D8): a kind Word
343
+ * gives a default entry, or one naming an entry the glossary holds.
344
+ */
345
+ get showsWordsFormPlaceholder() {
346
+ var _a;
347
+ if (this.defaultPlaceholderEntry !== undefined)
348
+ return true;
349
+ const name = this.placeholderEntry;
350
+ return name !== undefined && name !== '' && ((_a = this.glossary) === null || _a === void 0 ? void 0 : _a.has(name)) === true;
351
+ }
352
+ /**
353
+ * @internal Takes the control whole (D3): a Replace or delete over a control showing its placeholder, as Word takes one
354
+ * (check 63 cases 12, 18 to 20, 26, 38, 44 to 46 and 52). Untracked it goes, a block control leaving its paragraph,
355
+ * emptied, in its place; tracked it is marked deleted in Word's form (`markHolderDeleted`: `w:customXmlDelRange`
356
+ * markers around it and inside its content), its placeholder gone unmarked and the flag cleared (check 63's run 2,
357
+ * cases 38, 44 to 46 and 52). `text` goes where a run-level control stood, before it under tracking, as Word puts a
358
+ * Replace's insertion first.
359
+ */
360
+ takeWhole(text = '') {
361
+ var _a, _b;
362
+ this.assertWritable();
363
+ const form = this.form;
364
+ const tracker = this.parentBody.changeTracker;
365
+ if (form === 'Run') {
366
+ const span = this.runSpan();
367
+ if (!span)
368
+ throw new Docx4JException('This content control is not in a paragraph');
369
+ const { paragraph, start } = span;
370
+ if (!tracker) {
371
+ const at = this.container.indexOf(this.element);
372
+ if (at >= 0)
373
+ this.container.splice(at, 1);
374
+ return text === '' ? new Range(paragraph, start, start) : paragraph.splice(start, start, text);
375
+ }
376
+ const inserted = text === '' ? new Range(paragraph, start, start) : paragraph.splice(start, start, text);
377
+ this.markWholeDeleted(tracker, form);
378
+ return inserted;
379
+ }
380
+ const first = this.firstParagraph();
381
+ if (!tracker) {
382
+ const at = this.container.indexOf(this.element);
383
+ this.takePlaceholderRuns(form);
384
+ const paragraph = first.element;
385
+ const owner = (_a = this.element.value.PARENT) !== null && _a !== void 0 ? _a : ownerOf(this.container, this.parentBody);
386
+ this.container.splice(at, 1, paragraph);
387
+ linkParents(paragraph, owner);
388
+ return new Range((_b = this.parentBody.paragraphFor(paragraph.value)) !== null && _b !== void 0 ? _b : first, 0, 0);
389
+ }
390
+ this.markWholeDeleted(tracker, form);
391
+ return new Range(first, 0, 0);
392
+ }
393
+ /** The control marked deleted with Word's markers, its placeholder gone, unmarked, and the flag cleared (`takeWhole`). */
394
+ markWholeDeleted(tracker, form) {
395
+ markHolderDeleted(tracker, this.element, this.container, () => { this.takePlaceholderRuns(form); });
396
+ this.isShowingPlaceholder = false;
397
+ }
398
+ /**
399
+ * Shows the control's placeholder (CR-002 section 63, D8; section 63.18): a copy of the content of the entry its
400
+ * `w:placeholder` names, as the glossary holds it, the control's own run properties not over it, as Word shows it
401
+ * (check 68, section 63.21), with `w:showingPlcHdr`. A control naming no entry, or one the glossary lacks, is made to
402
+ * name Word's default entry for its kind (section 63.22: a date picker's is "Click or tap to enter a date.", a list's
403
+ * "Choose an item."), which is written into the glossary on save where it lacks it (D9), as docx4j's CR-063 has it:
404
+ * Word's save drops a reference no entry holds (check 65). A kind Word gives no default entry (a picture, a check box)
405
+ * keeps the name it has, and naming none shows docx4j's run, with no reference; any control keeps its name until the
406
+ * glossary is read (`getBody`, `Word.run`), showing its kind's default text. An extension.
407
+ */
408
+ showPlaceholder() {
409
+ var _a, _b, _c, _d;
410
+ var _e, _f;
411
+ this.assertWritable();
412
+ const sdtPr = ((_a = (_e = this.sdt).sdtPr) !== null && _a !== void 0 ? _a : (_e.sdtPr = {}));
413
+ const glossary = this.glossary;
414
+ const fallback = this.defaultPlaceholderEntry;
415
+ let name = (_b = this.placeholderEntry) !== null && _b !== void 0 ? _b : '';
416
+ const missing = name === '' || ((glossary === null || glossary === void 0 ? void 0 : glossary.loaded) === true && !glossary.has(name));
417
+ if (missing && fallback) {
418
+ name = fallback.name;
419
+ namePlaceholderEntry(sdtPr, name);
420
+ }
421
+ if (fallback && name === fallback.name)
422
+ glossary === null || glossary === void 0 ? void 0 : glossary.require(name, fallback.text);
423
+ const body = name === '' ? null : glossary === null || glossary === void 0 ? void 0 : glossary.bodyOf(name);
424
+ // no entry to copy: the kind's default text as its entry holds it, else docx4j's run (CR-063's D8 (a))
425
+ const paragraphs = body ? entryContentOf(body) : [[fallback ? placeholderRun(undefined, fallback.text) : placeholderRun(this.runProperties)]];
426
+ this.setBoundContent((_c = paragraphs[0]) !== null && _c !== void 0 ? _c : [], true);
427
+ // a block control shows an entry's further paragraphs too, where it may hold more than one (CR-002 section 61)
428
+ if (this.form !== 'Block' || paragraphs.length < 2 || isBoundBlockControl(this))
429
+ return;
430
+ const content = (_d = (_f = this.sdt.sdtContent).content) !== null && _d !== void 0 ? _d : (_f.content = []);
431
+ const first = content.find((e) => typeNameOf(e) === 'org_docx4j_wml.P');
432
+ let at = first ? content.indexOf(first) + 1 : content.length;
433
+ // the further paragraphs take a copy of the control's own paragraph's properties, as docx4j's binding gives them
434
+ const pPr = first === null || first === void 0 ? void 0 : first.value.pPr;
435
+ for (const runs of paragraphs.slice(1)) {
436
+ const p = el.p({ ...(pPr ? { pPr: deepCopy(pPr) } : {}), content: runs });
437
+ content.splice(at++, 0, p);
438
+ linkParents(p, this.sdt.sdtContent);
439
+ assignParaIds(this.sdt.sdtContent, [p]);
440
+ }
441
+ }
121
442
  insertTextInto(text, location) {
122
443
  const form = this.form;
123
444
  if ((form === 'Row' || form === 'Cell') && location === 'Replace') {
@@ -125,6 +446,7 @@ export class ContentControl {
125
446
  }
126
447
  if (form !== 'Run')
127
448
  return this.body().insertText(text, location);
449
+ text = textForRunControl(this, dropExcluded(text)); // CR-002 section 60: F4, F3
128
450
  const span = this.runSpan();
129
451
  if (!span)
130
452
  throw new Docx4JException('This content control is not in a paragraph');
@@ -139,7 +461,31 @@ export class ContentControl {
139
461
  }
140
462
  /** A paragraph at the start or end of a block control; before or after the paragraph of a run control. */
141
463
  insertParagraph(text, location) {
464
+ this.assertWritable();
142
465
  const form = this.form;
466
+ if ((location === 'Start' || location === 'End') && form === 'Block' && this.isShowingPlaceholder) {
467
+ // CR-002 section 63, D1: the placeholder goes, its paragraph left empty, the flag cleared, and the new paragraph
468
+ // follows, in either form (check 64 cases 6 and 27, check 63's run 2 cases 3 and 29)
469
+ this.takePlaceholderRuns(form);
470
+ this.isShowingPlaceholder = false;
471
+ }
472
+ if ((location === 'Start' || location === 'End') && isBoundBlockControl(this)) {
473
+ // Word holds a bound block control to one paragraph (CR-002 section 61): into a single-line one the text joins
474
+ // its paragraph, as Word's insertParagraph writes it; into a multi-line one Word's own second paragraph makes a
475
+ // file Word can't open, so it is refused (check 56, H2)
476
+ if (this.isMultiLine) {
477
+ throw new NotSupportedError('ContentControl', 'insertParagraph', 'this control is bound by w:dataBinding, and Word holds a bound '
478
+ + "block control to one paragraph: its own second paragraph in a multi-line one makes a file Word can't open (CR-002 section 61, check 56); "
479
+ + 'insertText with a line feed writes a line break');
480
+ }
481
+ const paragraphs = this.paragraphs;
482
+ const p = location === 'Start' ? paragraphs[0] : paragraphs[paragraphs.length - 1];
483
+ if (p) {
484
+ p.insertText(text, location);
485
+ this.syncBoundNode();
486
+ return p;
487
+ }
488
+ }
143
489
  if ((form === 'Row' || form === 'Cell') && (location === 'Start' || location === 'End')) {
144
490
  throw new Docx4JException(`A ${form.toLowerCase()}-level content control holds ${form === 'Row' ? 'rows' : 'cells'}, not paragraphs; insert into a cell's body`);
145
491
  }
@@ -159,10 +505,19 @@ export class ContentControl {
159
505
  return range ? range.search(text, options) : [];
160
506
  }
161
507
  /**
162
- * The control's range. For a run-level control, exactly the text it holds; for the other forms,
163
- * the first paragraph (departure: a Range here is within one paragraph, CR-002 section 7).
508
+ * The control's range. For a run-level control, exactly the text it holds; for the other forms, its
509
+ * paragraphs: one `Range` from the first one's start to the last one's end (CR-014 phase 1), its 'Whole'
510
+ * ending with the last one's mark, as Office JS's does (check 51: `CCP1\rCCP2\rCCP3\r`, its 'Content'
511
+ * without the last `\r`).
164
512
  */
165
513
  getRange(location = 'Whole') {
514
+ const range = this.rangeOf(location);
515
+ // its own 'Content' and 'Whole' ranges know the control, for a write into one with no width (CR-002 section 63, D4)
516
+ if ((location === 'Content' || location === 'Whole') && (this.form === 'Run' || this.form === 'Block'))
517
+ range.ofControl = { control: this, part: location };
518
+ return range;
519
+ }
520
+ rangeOf(location) {
166
521
  if (this.form === 'Run') {
167
522
  const span = this.runSpan();
168
523
  if (!span)
@@ -174,22 +529,51 @@ export class ContentControl {
174
529
  return new Range(paragraph, end, end);
175
530
  return new Range(paragraph, start, end);
176
531
  }
177
- const first = this.paragraphs[0];
532
+ const paragraphs = this.paragraphs;
533
+ const first = paragraphs[0];
178
534
  if (!first)
179
535
  throw new Docx4JException('This content control holds no paragraph');
180
- return first.getRange(location);
536
+ const last = paragraphs[paragraphs.length - 1];
537
+ if (location === 'End')
538
+ return last.getRange('End');
539
+ if (location === 'Start')
540
+ return first.getRange('Start');
541
+ // a row-level control, or one whose content ends with a table: 'Content' ends with the last cell's text, as
542
+ // the control's text does, and 'Whole' with \t\t, as Word 365 gives them (check 53)
543
+ const lastItem = [...this.content].reverse().find((item) => { var _a; return BLOCK_ITEMS.has((_a = typeNameOf(item)) !== null && _a !== void 0 ? _a : ''); });
544
+ if (this.form === 'Row' || (lastItem !== undefined && typeNameOf(lastItem) === 'org_docx4j_wml.Tbl')) {
545
+ return location === 'Whole' ? first.rangeTo(last, true, '\t\t') : first.rangeTo(last, false);
546
+ }
547
+ if (paragraphs.length === 1)
548
+ return first.getRange(location);
549
+ return new Range(first, 0, last.text.length, true, location === 'Whole', last);
181
550
  }
182
- /** Removes the control; `keepContent` puts what it held in its place, as Office JS. */
551
+ /**
552
+ * Removes the control; `keepContent` puts what it held in its place, as Office JS. Where the control held the
553
+ * paragraph a table cell ends with, that paragraph stays in its place, emptied, its properties kept, outside
554
+ * any control, as Word keeps a cell's last paragraph (check 52, case 95; CR-002 section 55.6).
555
+ */
183
556
  delete(keepContent = false) {
557
+ this.assertWritable();
184
558
  const at = this.container.indexOf(this.element);
185
559
  if (at < 0)
186
560
  return;
187
561
  const content = keepContent ? [...this.content] : [];
562
+ const owner = ownerOf(this.container, this.parentBody);
563
+ const cell = this.form === 'Block' ? wrappingCellOf(owner) : undefined;
564
+ const end = cell ? paragraphEndOf(cell.content) : undefined;
188
565
  this.container.splice(at, 1, ...content);
189
- if (keepContent) {
190
- const owner = ownerOf(this.container, this.parentBody);
566
+ if (keepContent)
191
567
  for (const item of content)
192
568
  linkParents(item, owner);
569
+ if (cell && !endsWithParagraph(cell.content)) {
570
+ if (end) {
571
+ end.element.value.content = [];
572
+ this.container.splice(at, 0, end.element);
573
+ linkParents(end.element, owner);
574
+ }
575
+ else
576
+ endWithParagraph(cell);
193
577
  }
194
578
  }
195
579
  /** The XML of the control (extension). */
@@ -213,6 +597,7 @@ export class ContentControl {
213
597
  setProperty(localPart, value, make) {
214
598
  var _a, _b;
215
599
  var _c;
600
+ this.assertWritable();
216
601
  const sdt = this.sdt;
217
602
  (_a = sdt.sdtPr) !== null && _a !== void 0 ? _a : (sdt.sdtPr = {});
218
603
  const items = ((_b = (_c = sdt.sdtPr).rPrOrAliasOrLock) !== null && _b !== void 0 ? _b : (_c.rPrOrAliasOrLock = []));
@@ -254,7 +639,11 @@ export class ContentControl {
254
639
  };
255
640
  let start;
256
641
  let end = 0;
257
- const segs = segmentsOf(paragraph.p);
642
+ // where the walk passes the control: a control holding no text stands there, after the text before it
643
+ // in the paragraph (before, it was reported at 0, and text put into it went to the paragraph's start)
644
+ let at = 0;
645
+ const segs = paragraph.segments({ visit: (el, offset) => { if (el === this.element)
646
+ at = offset; } });
258
647
  for (const seg of segs) {
259
648
  if (!inside(seg.run))
260
649
  continue;
@@ -262,34 +651,8 @@ export class ContentControl {
262
651
  start = seg.start;
263
652
  end = seg.end;
264
653
  }
265
- if (start === undefined) {
266
- // a control holding no text: its position is the end of the last text before it in the
267
- // paragraph (before, it was reported at 0, and text put into it went to the paragraph's start)
268
- let pos = 0;
269
- let found = false;
270
- const visit = (items) => {
271
- for (const el of items !== null && items !== void 0 ? items : []) {
272
- if (found)
273
- return;
274
- if (el === this.element) {
275
- found = true;
276
- return;
277
- }
278
- const v = el.value;
279
- if (typeof v !== 'object' || v === null)
280
- continue;
281
- if (typeNameOf(el) === 'org_docx4j_wml.R') {
282
- const last = segs.filter((seg) => seg.run === v).pop();
283
- if (last)
284
- pos = last.end;
285
- }
286
- else
287
- visit(runItemsOf(v));
288
- }
289
- };
290
- visit(paragraph.p.content);
291
- return { paragraph, start: pos, end: pos, empty: true };
292
- }
654
+ if (start === undefined)
655
+ return { paragraph, start: at, end: at, empty: true };
293
656
  return { paragraph, start, end };
294
657
  }
295
658
  /**
@@ -300,9 +663,10 @@ export class ContentControl {
300
663
  insertIntoEmpty(paragraph, text) {
301
664
  var _a, _b;
302
665
  var _c;
666
+ text = textForRunControl(this, dropExcluded(text));
303
667
  const sdt = this.sdt;
304
668
  const items = ((_b = (_c = ((_a = sdt.sdtContent) !== null && _a !== void 0 ? _a : (sdt.sdtContent = {}))).content) !== null && _b !== void 0 ? _b : (_c.content = []));
305
- const run = runOf([textItem(text)]);
669
+ const run = runOf(officeItems(text));
306
670
  const tracker = paragraph.changeTracker;
307
671
  const item = tracker ? tracker.ins([run]) : run;
308
672
  const at = items.findIndex((el) => { var _a; return ((_a = el.name) === null || _a === void 0 ? void 0 : _a.localPart) === 'customXmlInsRangeStart'; });
@@ -318,26 +682,52 @@ export class ContentControl {
318
682
  return new XmlMapping(this, pkg === null || pkg === void 0 ? void 0 : pkg.customXmlParts);
319
683
  }
320
684
  /**
321
- * The placeholder Word shows for an empty control: the control's own text while it is showing
322
- * the placeholder (`w:showingPlcHdr`), else '' — Word keeps the text itself in a glossary
323
- * document part, which this phase does not create (CR-002 section 12). Setting writes the text
324
- * as the control's content and sets `w:showingPlcHdr`, which is refused when the control holds
325
- * content of its own, so that a value is never lost.
685
+ * The placeholder Word shows for an empty control: the text of the glossary entry the control's `w:placeholder` names,
686
+ * as Office JS reads it (CR-002 section 63, D8; check 65), `null` where the control names none (the bare form) or the
687
+ * glossary lacks the entry. The glossary is read when the body is (`getBody`, `Word.run`). Setting it names Word's
688
+ * default entry for Word's default text, else a new entry holding the text, named as Word names one (32 hex digits),
689
+ * which is written into the glossary on save, the entry named before left there; a control showing its placeholder,
690
+ * or holding nothing, shows the new text. A control's content is left alone. Until section 63 the text was written as
691
+ * the control's content in the bare form, and a control holding content refused it.
326
692
  */
327
693
  get placeholderText() {
328
- return this.isShowingPlaceholder ? this.text : '';
694
+ var _a, _b;
695
+ const name = this.placeholderEntry;
696
+ if (name === undefined)
697
+ return null;
698
+ return (_b = (_a = this.glossary) === null || _a === void 0 ? void 0 : _a.textOf(name)) !== null && _b !== void 0 ? _b : null;
329
699
  }
330
700
  set placeholderText(text) {
331
- var _a;
332
- if (!this.isShowingPlaceholder && this.text !== '') {
333
- throw new Docx4JException('This content control holds content; clear it before setting its placeholder text');
334
- }
335
- this.setBoundContent(runsForValue('', this.runProperties, false), true);
336
- if (text !== '' && text !== PLACEHOLDER_TEXT) {
337
- const run = this.firstRunOfContent();
338
- const t = (_a = run === null || run === void 0 ? void 0 : run.content) === null || _a === void 0 ? void 0 : _a[0];
339
- if (t === null || t === void 0 ? void 0 : t.value)
340
- t.value.value = text;
701
+ var _a, _b, _c;
702
+ var _d;
703
+ this.assertWritable();
704
+ // the kind's default text, or '', names its default entry (section 63.22); any other text a new entry of its own
705
+ const fallback = (_a = this.defaultPlaceholderEntry) !== null && _a !== void 0 ? _a : DEFAULT_ENTRIES.text;
706
+ const own = text !== '' && text !== fallback.text;
707
+ const name = own ? newEntryName() : fallback.name;
708
+ const shown = own ? text : fallback.text;
709
+ namePlaceholderEntry(((_b = (_d = this.sdt).sdtPr) !== null && _b !== void 0 ? _b : (_d.sdtPr = {})), name);
710
+ (_c = this.glossary) === null || _c === void 0 ? void 0 : _c.require(name, shown);
711
+ // the entry's run, as the glossary will hold it: the control's own run properties aren't over it (check 68)
712
+ if (this.isShowingPlaceholder || this.text === '')
713
+ this.setBoundContent([placeholderRun(undefined, shown)], true);
714
+ }
715
+ /**
716
+ * Blocks taken out of the control's content: the relationships only they used (a picture's image) and the comments
717
+ * whose references they held go when the package is saved, as a deletion's do.
718
+ */
719
+ removeBlocks(content, blocks) {
720
+ const pkg = this.parentBody.package_;
721
+ const ids = new Set();
722
+ relationshipIdsIn(blocks, ids);
723
+ if (ids.size > 0)
724
+ queueRelationshipRemovals(pkg === null || pkg === void 0 ? void 0 : pkg.pendingRelationshipRemovals, this.parentBody.part, ids);
725
+ if (pkg === null || pkg === void 0 ? void 0 : pkg.pendingCommentRemovals)
726
+ commentReferencesIn(blocks, pkg.pendingCommentRemovals);
727
+ for (const block of blocks) {
728
+ const at = content.indexOf(block);
729
+ if (at >= 0)
730
+ content.splice(at, 1);
341
731
  }
342
732
  }
343
733
  /** Office JS `appearance`: how Word draws the control (`w15:appearance`). */
@@ -402,19 +792,19 @@ export class ContentControl {
402
792
  get datePickerContentControl() {
403
793
  var _a;
404
794
  const value = (_a = sdtProperty(this.sdt.sdtPr, 'date')) === null || _a === void 0 ? void 0 : _a.value;
405
- return value ? new DatePickerContentControl(value) : undefined;
795
+ return value ? new DatePickerContentControl(value, () => this.assertWritable()) : undefined;
406
796
  }
407
797
  /** The list view, for a `w:dropDownList` control. */
408
798
  get dropDownListContentControl() {
409
799
  var _a;
410
800
  const value = (_a = sdtProperty(this.sdt.sdtPr, 'dropDownList')) === null || _a === void 0 ? void 0 : _a.value;
411
- return value ? new ListContentControl(value) : undefined;
801
+ return value ? new ListContentControl(value, () => this.assertWritable()) : undefined;
412
802
  }
413
803
  /** The list view, for a `w:comboBox` control. */
414
804
  get comboBoxContentControl() {
415
805
  var _a;
416
806
  const value = (_a = sdtProperty(this.sdt.sdtPr, 'comboBox')) === null || _a === void 0 ? void 0 : _a.value;
417
- return value ? new ListContentControl(value) : undefined;
807
+ return value ? new ListContentControl(value, () => this.assertWritable()) : undefined;
418
808
  }
419
809
  /** The picture view, for a `w:picture` control. */
420
810
  get pictureContentControl() {
@@ -438,6 +828,7 @@ export class ContentControl {
438
828
  putProperty(element) {
439
829
  var _a, _b;
440
830
  var _c;
831
+ this.assertWritable();
441
832
  const sdt = this.sdt;
442
833
  (_a = sdt.sdtPr) !== null && _a !== void 0 ? _a : (sdt.sdtPr = {});
443
834
  const items = ((_b = (_c = sdt.sdtPr).rPrOrAliasOrLock) !== null && _b !== void 0 ? _b : (_c.rPrOrAliasOrLock = []));
@@ -452,6 +843,7 @@ export class ContentControl {
452
843
  /** Removes a `w:sdtPr` child (extension). */
453
844
  removeProperty(localPart, namespaceURI) {
454
845
  var _a;
846
+ this.assertWritable();
455
847
  const items = (_a = this.sdt.sdtPr) === null || _a === void 0 ? void 0 : _a.rPrOrAliasOrLock;
456
848
  if (!items)
457
849
  return;
@@ -469,6 +861,10 @@ export class ContentControl {
469
861
  var _a, _b;
470
862
  return ((_b = (_a = sdtProperty(this.sdt.sdtPr, 'text')) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.multiLine) === true;
471
863
  }
864
+ /** Office JS's name for `isShowingPlaceholder` (`showingPlaceholderText`, WordApiDesktop 1.3, read-only there). */
865
+ get showingPlaceholderText() {
866
+ return this.isShowingPlaceholder;
867
+ }
472
868
  /** Whether the control is showing its placeholder rather than a value (`w:showingPlcHdr`). */
473
869
  get isShowingPlaceholder() {
474
870
  var _a;
@@ -480,7 +876,7 @@ export class ContentControl {
480
876
  this.removeProperty('showingPlcHdr');
481
877
  return;
482
878
  }
483
- this.putProperty(el.showingPlcHdr({ val: true }));
879
+ this.putProperty(el.showingPlcHdr({})); // <w:showingPlcHdr/>, as Word writes it
484
880
  }
485
881
  /**
486
882
  * Replaces what the control shows with these runs (docx4j BindingHandler's applyBoundContent):
@@ -490,16 +886,22 @@ export class ContentControl {
490
886
  setBoundContent(runs, showingPlaceholder = false) {
491
887
  var _a, _b, _c, _d;
492
888
  var _e;
889
+ this.assertWritable();
493
890
  const sdt = this.sdt;
494
891
  (_a = sdt.sdtContent) !== null && _a !== void 0 ? _a : (sdt.sdtContent = {});
495
892
  const content = ((_b = (_e = sdt.sdtContent).content) !== null && _b !== void 0 ? _b : (_e.content = []));
496
893
  const first = content.find((e) => typeNameOf(e) !== undefined);
497
894
  if (this.form === 'Run' || (first && typeNameOf(first) === 'org_docx4j_wml.R')) {
895
+ // a tracked control's own markers stay where they are, its inner end first and its inner start last (check 30)
896
+ const ends = content.filter((e) => { var _a, _b; return TRACKED_HOLDER_MARKER.test((_b = (_a = e.name) === null || _a === void 0 ? void 0 : _a.localPart) !== null && _b !== void 0 ? _b : '') && e.name.localPart.endsWith('End'); });
897
+ const starts = content.filter((e) => { var _a, _b; return TRACKED_HOLDER_MARKER.test((_b = (_a = e.name) === null || _a === void 0 ? void 0 : _a.localPart) !== null && _b !== void 0 ? _b : '') && e.name.localPart.endsWith('Start'); });
498
898
  content.length = 0;
499
- content.push(...runs);
899
+ content.push(...ends, ...runs, ...starts);
500
900
  linkParents(content, sdt.sdtContent);
501
901
  }
502
- else {
902
+ else if (!isBoundBlockControl(this)) {
903
+ // a cell or row control, or a block control section 61's rule doesn't cover (a w15:dataBinding, Word's rich-text
904
+ // binding, or none): the value goes into its first paragraph, the rest as it is
503
905
  const paragraph = this.paragraphs[0];
504
906
  if (paragraph) {
505
907
  paragraph.p.content = runs;
@@ -509,8 +911,30 @@ export class ContentControl {
509
911
  const p = paragraphElementOf(runs);
510
912
  content.push(p);
511
913
  linkParents(p, sdt.sdtContent);
914
+ assignParaIds(sdt.sdtContent, [p]);
512
915
  }
513
916
  }
917
+ else {
918
+ // A bound block control holds one paragraph (CR-002 section 61): the value goes into its first paragraph and any
919
+ // other block it holds goes, as docx4j's bind.xslt writes one paragraph (section 61.6, docx4j-python's review).
920
+ // Before, the first paragraph took the value and the rest stayed, so a control holding two kept them, and Word
921
+ // still couldn't open the file.
922
+ const blocks = content.filter((e) => { var _a; return BLOCK_LEVEL_TYPES.has((_a = typeNameOf(e)) !== null && _a !== void 0 ? _a : ''); });
923
+ const paragraph = blocks.find((e) => typeNameOf(e) === 'org_docx4j_wml.P');
924
+ if (paragraph) {
925
+ paragraph.value.content = runs;
926
+ linkParents(paragraph.value.content, paragraph.value);
927
+ }
928
+ else {
929
+ const p = paragraphElementOf(runs);
930
+ content.push(p);
931
+ linkParents(p, sdt.sdtContent);
932
+ assignParaIds(sdt.sdtContent, [p]);
933
+ }
934
+ const others = blocks.filter((e) => e !== paragraph);
935
+ if (others.length > 0)
936
+ this.removeBlocks(content, others);
937
+ }
514
938
  this.isShowingPlaceholder = showingPlaceholder;
515
939
  // The placeholder run names the PlaceholderText style, which a document made here lacks: the
516
940
  // package splices the definition in when it is saved, as it does a new hyperlink's style. Word
@@ -527,6 +951,7 @@ export class ContentControl {
527
951
  }
528
952
  /** A copy of this control right after it, as Word's repeating-section + button does (extension). */
529
953
  insertCopyAfter() {
954
+ this.assertWritable();
530
955
  const at = this.container.indexOf(this.element);
531
956
  if (at < 0)
532
957
  throw new Docx4JException('This content control is not in its container any more');
@@ -536,27 +961,18 @@ export class ContentControl {
536
961
  return new ContentControl(copy, this.container, this.parentBody);
537
962
  }
538
963
  /**
539
- * Writes the control's text into the node it is bound to, when there is one and the XPath engine
540
- * is warm. Silent when it is not: reading a custom XML part is `pkg.customXmlParts.load()`'s job,
964
+ * @internal Writes the control's text into the node it is bound to, when there is one and the XPath engine
965
+ * is warm (CR-002 section 63, D7: every text write into a bound control). Silent when it is not: reading a custom XML part is `pkg.customXmlParts.load()`'s job,
541
966
  * and `updateFromContentControls()` is the explicit form of this write.
542
967
  */
543
968
  syncBoundNode() {
544
969
  try {
545
- if (this.xmlMapping.isMapped)
546
- updateFromControl(this);
970
+ updateFromControl(this);
547
971
  }
548
972
  catch {
549
973
  // the part is not parsed, or the engine is not ready: leave it to updateFromContentControls()
550
974
  }
551
975
  }
552
- firstRunOfContent() {
553
- var _a, _b, _c, _d;
554
- const runs = this.form === 'Run' ? (_b = runItemsOf((_a = this.sdt.sdtContent) !== null && _a !== void 0 ? _a : {})) !== null && _b !== void 0 ? _b : [] : (_d = (_c = this.paragraphs[0]) === null || _c === void 0 ? void 0 : _c.runs) !== null && _d !== void 0 ? _d : [];
555
- for (const item of runs)
556
- if (typeNameOf(item) === 'org_docx4j_wml.R')
557
- return item.value;
558
- return undefined;
559
- }
560
976
  lockValue() {
561
977
  var _a, _b;
562
978
  return (_b = (_a = sdtProperty(this.sdt.sdtPr, 'lock')) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.val;
@@ -572,11 +988,22 @@ export class ContentControl {
572
988
  }
573
989
  this.putProperty(el.lock({ val }));
574
990
  }
575
- /** The table a row-level or cell-level control belongs to. */
991
+ /**
992
+ * True for a control in the selected branch of a kept `mc:AlternateContent`, at any level, which the
993
+ * collectors list as Word reads it (CR-013 phase 2). Such a view is read-only (D4).
994
+ */
995
+ get inBranch() {
996
+ return inBranch(this.element.value);
997
+ }
998
+ /** Refuses a write to a control in a branch (CR-013 D4). Internal: the control's mutators, and its kinds', call it first. */
999
+ assertWritable() {
1000
+ assertOutsideBranch(this.element.value, 'ContentControl');
1001
+ }
1002
+ /** The table a row-level or cell-level control belongs to, through the row-level controls around it, nested to any depth. */
576
1003
  ancestorTable() {
577
1004
  var _a;
578
1005
  let current = this.element.value.PARENT;
579
- for (let guard = 0; current && guard < 8; guard++) {
1006
+ for (let guard = 0; current && guard < 256; guard++) {
580
1007
  if (typeNameOf(current) === 'org_docx4j_wml.Tbl') {
581
1008
  const tbl = current;
582
1009
  const container = childrenOf(((_a = tbl.PARENT) !== null && _a !== void 0 ? _a : {}));
@@ -588,8 +1015,13 @@ export class ContentControl {
588
1015
  return undefined;
589
1016
  }
590
1017
  }
591
- /** Every content control under a list of block-level items, in document order, nested ones included. */
592
- export function collectControls(items, body, out) {
1018
+ /**
1019
+ * Every content control under a list of block-level items, in document order, nested ones included. In a
1020
+ * kept `mc:AlternateContent` a reader's (`'read'`, the default) takes the selected branch's controls (CR-013
1021
+ * phase 2), the binding passes (`'every'`) every branch's, each other branch's where the element stands
1022
+ * (phase 3).
1023
+ */
1024
+ export function collectControls(items, body, out, mode = 'read') {
593
1025
  var _a;
594
1026
  for (const element of items) {
595
1027
  const tn = typeNameOf(element);
@@ -598,24 +1030,29 @@ export function collectControls(items, body, out) {
598
1030
  if (SDT_TYPES.has(tn)) {
599
1031
  const control = new ContentControl(element, items, body);
600
1032
  out.push(control);
601
- collectControls(control.content, body, out);
1033
+ collectControls(control.content, body, out, mode);
602
1034
  continue;
603
1035
  }
604
1036
  if (tn === 'org_docx4j_wml.P') {
605
- collectRunControls(element.value, body, out);
1037
+ collectRunControls(element.value, body, out, mode);
606
1038
  continue;
607
1039
  }
608
1040
  if (tn === 'org_docx4j_wml.Tbl') {
609
- collectInRows((_a = childrenOf(element.value)) !== null && _a !== void 0 ? _a : [], body, out);
1041
+ collectInRows((_a = childrenOf(element.value)) !== null && _a !== void 0 ? _a : [], body, out, mode);
1042
+ continue;
1043
+ }
1044
+ if (tn === ALTERNATE_CONTENT) {
1045
+ for (const branch of branchListsOf(element.value, mode))
1046
+ collectControls(branch, body, out, mode);
610
1047
  continue;
611
1048
  }
612
1049
  const children = childrenOf(element.value);
613
1050
  if (children)
614
- collectControls(children, body, out);
1051
+ collectControls(children, body, out, mode);
615
1052
  }
616
1053
  }
617
1054
  /** Row-level controls and the controls inside the rows of a table. */
618
- function collectInRows(items, body, out) {
1055
+ function collectInRows(items, body, out, mode) {
619
1056
  var _a;
620
1057
  for (const element of items) {
621
1058
  const tn = typeNameOf(element);
@@ -624,15 +1061,18 @@ function collectInRows(items, body, out) {
624
1061
  if (SDT_TYPES.has(tn)) {
625
1062
  const control = new ContentControl(element, items, body);
626
1063
  out.push(control);
627
- collectInRows(control.content, body, out);
1064
+ collectInRows(control.content, body, out, mode);
628
1065
  continue;
629
1066
  }
630
1067
  if (tn === 'org_docx4j_wml.Tr')
631
- collectInCells((_a = childrenOf(element.value)) !== null && _a !== void 0 ? _a : [], body, out);
1068
+ collectInCells((_a = childrenOf(element.value)) !== null && _a !== void 0 ? _a : [], body, out, mode);
1069
+ else if (tn === ALTERNATE_CONTENT)
1070
+ for (const branch of branchListsOf(element.value, mode))
1071
+ collectInRows(branch, body, out, mode);
632
1072
  }
633
1073
  }
634
1074
  /** Cell-level controls and the controls inside the cells of a row. */
635
- function collectInCells(items, body, out) {
1075
+ function collectInCells(items, body, out, mode) {
636
1076
  var _a;
637
1077
  for (const element of items) {
638
1078
  const tn = typeNameOf(element);
@@ -641,18 +1081,29 @@ function collectInCells(items, body, out) {
641
1081
  if (SDT_TYPES.has(tn)) {
642
1082
  const control = new ContentControl(element, items, body);
643
1083
  out.push(control);
644
- collectInCells(control.content, body, out);
1084
+ collectInCells(control.content, body, out, mode);
645
1085
  continue;
646
1086
  }
647
1087
  if (tn === 'org_docx4j_wml.Tc')
648
- collectControls((_a = childrenOf(element.value)) !== null && _a !== void 0 ? _a : [], body, out);
1088
+ collectControls((_a = childrenOf(element.value)) !== null && _a !== void 0 ? _a : [], body, out, mode);
1089
+ else if (tn === ALTERNATE_CONTENT)
1090
+ for (const branch of branchListsOf(element.value, mode))
1091
+ collectInCells(branch, body, out, mode);
649
1092
  }
650
1093
  }
651
1094
  /** The run-level controls in a paragraph (or any run holder), in order, nested ones included. */
652
- export function collectRunControls(holder, body, out) {
653
- const items = runItemsOf(holder);
654
- if (!items)
1095
+ export function collectRunControls(holder, body, out, mode = 'read') {
1096
+ // a kept mc:AlternateContent among runs: its selected branch's (CR-013 phase 2), or every branch's (phase 3)
1097
+ if (holder.TYPE_NAME === ALTERNATE_CONTENT) {
1098
+ for (const branch of branchListsOf(holder, mode))
1099
+ collectRunItems(branch, body, out, mode);
655
1100
  return;
1101
+ }
1102
+ const items = runItemsOf(holder);
1103
+ if (items)
1104
+ collectRunItems(items, body, out, mode);
1105
+ }
1106
+ function collectRunItems(items, body, out, mode) {
656
1107
  for (const element of items) {
657
1108
  const tn = typeNameOf(element);
658
1109
  if (tn === undefined)
@@ -660,15 +1111,84 @@ export function collectRunControls(holder, body, out) {
660
1111
  if (SDT_TYPES.has(tn)) {
661
1112
  const control = new ContentControl(element, items, body);
662
1113
  out.push(control);
663
- collectRunControls(element.value, body, out);
1114
+ collectRunControls(element.value, body, out, mode);
664
1115
  continue;
665
1116
  }
666
1117
  if (tn !== 'org_docx4j_wml.R')
667
- collectRunControls(element.value, body, out);
1118
+ collectRunControls(element.value, body, out, mode);
668
1119
  }
669
1120
  }
670
1121
  function paragraphElement(text) {
671
- return el.p({ content: text === '' ? [] : [el.r({ content: [el.t({ value: text })] })] });
1122
+ const items = officeItems(forWriter(dropExcluded(text), 'one-paragraph'));
1123
+ return el.p({ content: items.length === 0 ? [] : [el.r({ content: items })] });
1124
+ }
1125
+ /**
1126
+ * A view of the content control whose `w:sdt` value this is, found in its owner's list (a paragraph's runs, a body's
1127
+ * blocks, a holder's items).
1128
+ */
1129
+ export function controlViewOf(sdt, body) {
1130
+ const owner = sdt.PARENT;
1131
+ for (const value of Object.values(owner !== null && owner !== void 0 ? owner : {})) {
1132
+ if (!Array.isArray(value))
1133
+ continue;
1134
+ const element = value.find((e) => (e === null || e === void 0 ? void 0 : e.value) === sdt);
1135
+ if (element)
1136
+ return new ContentControl(element, value, body);
1137
+ }
1138
+ throw new Docx4JException('This content control is not in the document any more');
1139
+ }
1140
+ /**
1141
+ * A block-level control bound by `w:dataBinding`, untyped, `w:text` or `w:richText`, whose node doesn't hold flat OPC
1142
+ * (CR-002 section 61 H1): Word holds its content to one paragraph, and can't open a file where it holds more (check 56,
1143
+ * docx4j-python's file 3). A node not resolved (the custom XML parts not loaded) counts as not flat OPC. `w15:dataBinding`
1144
+ * is Word's rich-text binding, and isn't this.
1145
+ */
1146
+ export function isBoundBlockControl(control) {
1147
+ if (control.form !== 'Block')
1148
+ return false;
1149
+ const pr = control.sdt.sdtPr;
1150
+ if (sdtProperty(pr, 'dataBinding') === undefined)
1151
+ return false;
1152
+ const kind = sdtKindOf(pr);
1153
+ if (kind !== 'RichText' && kind !== 'PlainText')
1154
+ return false;
1155
+ let node;
1156
+ try {
1157
+ node = control.xmlMapping.customXmlNode;
1158
+ }
1159
+ catch {
1160
+ node = undefined; // the parts aren't parsed: the rule applies
1161
+ }
1162
+ return !(node && holdsFlatOpc(node.text));
1163
+ }
1164
+ /**
1165
+ * How a control holds lines, as Word reads it: `multi` or `single` for a plain-text control (`w:text` and its
1166
+ * `w:multiLine`), `single` for a bound block control Word reads as plain text (section 61 H4); undefined for any other.
1167
+ */
1168
+ export function plainTextLinesOf(control) {
1169
+ if (sdtProperty(control.sdt.sdtPr, 'text') !== undefined)
1170
+ return control.isMultiLine ? 'multi' : 'single';
1171
+ return isBoundBlockControl(control) ? 'single' : undefined;
1172
+ }
1173
+ /**
1174
+ * Text for a run-level control: a line feed or carriage return there is refused before anything changes (CR-002
1175
+ * section 60 F4: Word, given one, moved a bound plain-text control to block level), and a plain-text control's breaks
1176
+ * go as its kind takes them (F3: dropped in a single-line one).
1177
+ */
1178
+ export function textForRunControl(control, text) {
1179
+ if (/[\r\n]/.test(text)) {
1180
+ throw new NotSupportedError('ContentControl', 'insertText', 'a line feed or carriage return in a run-level content control would make a '
1181
+ + 'paragraph break inside it, which Word answers by moving the control to block level (CR-002 section 60, F4); write a line break (U+000B) instead');
1182
+ }
1183
+ const lines = plainTextLinesOf(control);
1184
+ return lines === 'single' ? forWriter(text, 'single-line') : text;
1185
+ }
1186
+ /** An item put last in a control's content, before the inner start marker a control tracked as inserted ends with (check 30). */
1187
+ function pushBeforeMarker(items, item) {
1188
+ var _a, _b;
1189
+ const last = items[items.length - 1];
1190
+ const marker = last !== undefined && TRACKED_HOLDER_MARKER.test((_b = (_a = last.name) === null || _a === void 0 ? void 0 : _a.localPart) !== null && _b !== void 0 ? _b : '') && last.name.localPart.endsWith('Start');
1191
+ items.splice(marker ? items.length - 1 : items.length, 0, item);
672
1192
  }
673
1193
  /** A `w:p` holding these run-level items (CR-002 phase E: the bound content of an empty control). */
674
1194
  function paragraphElementOf(runs) {
@@ -695,3 +1215,56 @@ function ownerOf(container, body) {
695
1215
  };
696
1216
  return (_a = seek(body.container)) !== null && _a !== void 0 ? _a : body.container;
697
1217
  }
1218
+ /**
1219
+ * Refuses, before anything changes, putting blocks into a block-level control bound by `w:dataBinding` (untyped,
1220
+ * `w:text` or `w:richText`, its node not flat OPC) that would leave it holding anything but one paragraph: Word can't
1221
+ * open such a file, and its repair loses the extra blocks (CR-002 section 61, check 56). Word's own error where
1222
+ * measured (`insertTable` `InvalidArgument`, `insertOoxml` `GeneralException`), else `NotSupportedError` (H3).
1223
+ */
1224
+ export function assertControlHolds(body, holder, container, elements, refusal, member = ['Body', 'insertElement']) {
1225
+ var _a;
1226
+ const owner = holder;
1227
+ if ((owner === null || owner === void 0 ? void 0 : owner.TYPE_NAME) !== 'org_docx4j_wml.SdtContentBlock' || ((_a = owner.PARENT) === null || _a === void 0 ? void 0 : _a.TYPE_NAME) !== 'org_docx4j_wml.SdtBlock')
1228
+ return;
1229
+ const control = controlViewOf(owner.PARENT, body);
1230
+ if (!isBoundBlockControl(control))
1231
+ return;
1232
+ const blocks = [...container, ...elements].filter((e) => { var _a; return BLOCK_LEVEL_TYPES.has((_a = typeNameOf(e)) !== null && _a !== void 0 ? _a : ''); });
1233
+ if (blocks.length === 1 && typeNameOf(blocks[0]) === 'org_docx4j_wml.P')
1234
+ return;
1235
+ const message = `this content control is bound by w:dataBinding, and Word holds a bound block control to one paragraph: it can't open `
1236
+ + `a file where one holds more, and its repair loses them (CR-002 section 61, check 56)`;
1237
+ if (refusal === 'InvalidArgument')
1238
+ throw new InvalidArgument(`Table: ${message}`);
1239
+ if (refusal === 'GeneralException')
1240
+ throw new GeneralException(`insertOoxml: ${message}`);
1241
+ throw new NotSupportedError(member[0], member[1], message);
1242
+ }
1243
+ /** The controls of `options.types`, or all of them. */
1244
+ export function controlsOfTypes(controls, options) {
1245
+ const types = options === null || options === void 0 ? void 0 : options.types;
1246
+ return types && types.length > 0 ? controls.filter((c) => types.includes(c.type)) : controls;
1247
+ }
1248
+ /**
1249
+ * Whether a control of this kind made on an empty range shows its default placeholder, as Word's does (CR-002 section
1250
+ * 63, D8; check 64; Jason's `placeholders.docx`, section 63.22): a text control, a date picker, a drop-down list or a
1251
+ * combo box. The building block and repeating section kinds are made as before.
1252
+ */
1253
+ export function showsPlaceholderWhenMade(kind) {
1254
+ return kind === undefined || kind === 'RichText' || kind === 'PlainText' || kind === 'DatePicker' || kind === 'DropDownList' || kind === 'ComboBox';
1255
+ }
1256
+ /** A stand-in for a block-level control about to be made, for `assertControlHolds` before `sdtOf` takes its content. */
1257
+ export const BLOCK_CONTROL = Object.freeze({
1258
+ name: { namespaceURI: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main', localPart: 'sdt' },
1259
+ value: { TYPE_NAME: 'org_docx4j_wml.SdtBlock' },
1260
+ });
1261
+ /**
1262
+ * Whether a block-level control holds one paragraph and nothing else at block level, or nothing yet: what a bound
1263
+ * block control may hold (CR-002 section 61).
1264
+ */
1265
+ export function holdsOneParagraph(control) {
1266
+ var _a, _b;
1267
+ const content = (_b = (_a = control.sdt.sdtContent) === null || _a === void 0 ? void 0 : _a.content) !== null && _b !== void 0 ? _b : [];
1268
+ const blocks = content.filter((e) => { var _a; return BLOCK_LEVEL_TYPES.has((_a = typeNameOf(e)) !== null && _a !== void 0 ? _a : ''); });
1269
+ return blocks.length === 0 || (blocks.length === 1 && typeNameOf(blocks[0]) === 'org_docx4j_wml.P');
1270
+ }