@docx4j/core-ts 0.5.0 → 0.6.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 (155) hide show
  1. package/NOTICE +4 -0
  2. package/README.md +32 -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 +509 -141
  25. package/dist/model/content/Comment.d.mts +21 -3
  26. package/dist/model/content/Comment.mjs +195 -19
  27. package/dist/model/content/ContentControl.d.mts +197 -18
  28. package/dist/model/content/ContentControl.mjs +664 -95
  29. package/dist/model/content/Font.d.mts +67 -17
  30. package/dist/model/content/Font.mjs +114 -35
  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.mjs +3 -0
  34. package/dist/model/content/Paragraph.d.mts +189 -13
  35. package/dist/model/content/Paragraph.mjs +870 -74
  36. package/dist/model/content/Range.d.mts +227 -12
  37. package/dist/model/content/Range.mjs +785 -59
  38. package/dist/model/content/ResolvedView.d.mts +104 -0
  39. package/dist/model/content/ResolvedView.mjs +596 -0
  40. package/dist/model/content/Table.d.mts +29 -3
  41. package/dist/model/content/Table.mjs +109 -33
  42. package/dist/model/content/TrackedChange.d.mts +172 -13
  43. package/dist/model/content/TrackedChange.mjs +728 -167
  44. package/dist/model/content/comments.d.mts +20 -6
  45. package/dist/model/content/comments.mjs +67 -57
  46. package/dist/model/content/generalException.d.mts +18 -0
  47. package/dist/model/content/generalException.mjs +24 -0
  48. package/dist/model/content/index.d.mts +8 -3
  49. package/dist/model/content/index.mjs +7 -2
  50. package/dist/model/content/mathText.d.mts +21 -0
  51. package/dist/model/content/mathText.mjs +267 -0
  52. package/dist/model/content/officeText.d.mts +27 -0
  53. package/dist/model/content/officeText.mjs +74 -0
  54. package/dist/model/content/outline.d.mts +5 -0
  55. package/dist/model/content/outline.mjs +13 -0
  56. package/dist/model/content/placeholders.d.mts +110 -0
  57. package/dist/model/content/placeholders.mjs +253 -0
  58. package/dist/model/content/search.d.mts +72 -0
  59. package/dist/model/content/search.mjs +204 -2
  60. package/dist/model/content/spanEdits.d.mts +159 -0
  61. package/dist/model/content/spanEdits.mjs +728 -0
  62. package/dist/model/content/story.d.mts +44 -0
  63. package/dist/model/content/story.mjs +92 -0
  64. package/dist/model/content/tableColumns.d.mts +1 -1
  65. package/dist/model/content/tableColumns.mjs +108 -80
  66. package/dist/model/content/tableRevisions.d.mts +11 -3
  67. package/dist/model/content/tableRevisions.mjs +72 -42
  68. package/dist/model/content/tableRules.d.mts +30 -0
  69. package/dist/model/content/tableRules.mjs +100 -0
  70. package/dist/model/content/textBoxes.d.mts +18 -0
  71. package/dist/model/content/textBoxes.mjs +105 -0
  72. package/dist/model/content/trackedChangeFilter.d.mts +39 -0
  73. package/dist/model/content/trackedChangeFilter.mjs +81 -0
  74. package/dist/model/content/tracking.d.mts +28 -0
  75. package/dist/model/content/tracking.mjs +149 -10
  76. package/dist/model/content/tree.d.mts +171 -22
  77. package/dist/model/content/tree.mjs +329 -53
  78. package/dist/model/customxml/CustomXmlPartCollection.d.mts +8 -0
  79. package/dist/model/customxml/CustomXmlPartCollection.mjs +34 -11
  80. package/dist/model/customxml/XmlMapping.d.mts +1 -1
  81. package/dist/model/customxml/XmlMapping.mjs +11 -0
  82. package/dist/model/customxml/bindings.d.mts +21 -2
  83. package/dist/model/customxml/bindings.mjs +76 -32
  84. package/dist/model/customxml/kinds.d.mts +8 -3
  85. package/dist/model/customxml/kinds.mjs +26 -5
  86. package/dist/model/customxml/picturePlaceholder.d.mts +17 -0
  87. package/dist/model/customxml/picturePlaceholder.mjs +32 -0
  88. package/dist/model/customxml/pictures.d.mts +4 -3
  89. package/dist/model/customxml/pictures.mjs +18 -6
  90. package/dist/model/customxml/xhtml.mjs +8 -2
  91. package/dist/model/index.d.mts +2 -0
  92. package/dist/model/index.mjs +4 -0
  93. package/dist/model/listnumbering/Emulator.d.mts +37 -5
  94. package/dist/model/listnumbering/Emulator.mjs +63 -9
  95. package/dist/model/properties/PropertyResolver.d.mts +60 -1
  96. package/dist/model/properties/PropertyResolver.mjs +115 -2
  97. package/dist/model/properties/catalogue.d.mts +19 -5
  98. package/dist/model/properties/catalogue.mjs +41 -15
  99. package/dist/model/properties/log.d.mts +1 -1
  100. package/dist/model/properties/log.mjs +5 -5
  101. package/dist/model/properties/table.mjs +4 -2
  102. package/dist/model/text/Extractor.d.mts +289 -0
  103. package/dist/model/text/Extractor.mjs +2162 -0
  104. package/dist/model/text/LinkTargets.d.mts +45 -0
  105. package/dist/model/text/LinkTargets.mjs +170 -0
  106. package/dist/model/text/MarkdownExporter.d.mts +140 -0
  107. package/dist/model/text/MarkdownExporter.mjs +255 -0
  108. package/dist/model/text/PlainText.d.mts +29 -0
  109. package/dist/model/text/PlainText.mjs +539 -0
  110. package/dist/model/text/TextContext.d.mts +161 -0
  111. package/dist/model/text/TextContext.mjs +425 -0
  112. package/dist/model/text/TextOptions.d.mts +150 -0
  113. package/dist/model/text/TextOptions.mjs +278 -0
  114. package/dist/model/text/TextResult.d.mts +504 -0
  115. package/dist/model/text/TextResult.mjs +526 -0
  116. package/dist/model/text/Texts.d.mts +99 -0
  117. package/dist/model/text/Texts.mjs +187 -0
  118. package/dist/model/text/WmlToMarkdown.d.mts +120 -0
  119. package/dist/model/text/WmlToMarkdown.mjs +911 -0
  120. package/dist/model/text/commonmark.d.mts +121 -0
  121. package/dist/model/text/commonmark.mjs +655 -0
  122. package/dist/model/text/index.d.mts +7 -0
  123. package/dist/model/text/index.mjs +8 -0
  124. package/dist/model/text/normalize.d.mts +8 -0
  125. package/dist/model/text/normalize.mjs +13 -0
  126. package/dist/model/text/outline.d.mts +4 -0
  127. package/dist/model/text/outline.mjs +71 -0
  128. package/dist/office-js/fragment.d.mts +7 -5
  129. package/dist/office-js/fragment.mjs +63 -14
  130. package/dist/office-js/proxy.d.mts +8 -0
  131. package/dist/office-js/proxy.mjs +29 -0
  132. package/dist/office-js/run.mjs +2 -0
  133. package/dist/office-js/supported.generated.mjs +16 -0
  134. package/dist/office-js/toApiScript.mjs +21 -5
  135. package/dist/opc/Save.d.mts +17 -0
  136. package/dist/opc/Save.mjs +12 -2
  137. package/dist/opc/index.d.mts +3 -3
  138. package/dist/opc/index.mjs +1 -1
  139. package/dist/opc/mce/preprocessor.d.mts +28 -3
  140. package/dist/opc/mce/preprocessor.mjs +4 -4
  141. package/dist/opc/mce/understood.d.mts +30 -6
  142. package/dist/opc/mce/understood.mjs +37 -7
  143. package/dist/packages/OpcPackage.d.mts +13 -0
  144. package/dist/packages/OpcPackage.mjs +1 -0
  145. package/dist/packages/WordprocessingMLPackage.d.mts +45 -8
  146. package/dist/packages/WordprocessingMLPackage.mjs +155 -20
  147. package/dist/parts/DefaultXmlPart.mjs +2 -2
  148. package/dist/parts/Part.d.mts +10 -2
  149. package/dist/parts/XmlPart.d.mts +12 -30
  150. package/dist/parts/XmlPart.mjs +44 -93
  151. package/dist/parts/wml/comments.mjs +30 -0
  152. package/dist/parts/wml/index.mjs +12 -0
  153. package/dist/xml/dom.d.mts +7 -0
  154. package/dist/xml/dom.mjs +18 -0
  155. package/package.json +2 -2
@@ -64,10 +64,27 @@ export declare class Comment {
64
64
  /** Removes the comment and its replies: the markers, the reference runs and every side-part entry. */
65
65
  delete(): Promise<void>;
66
66
  /**
67
- * The commented range: a `Range` per paragraph the comment touches (extension; Office JS
68
- * returns one `Range`). Empty when the comment has no markers in this body.
67
+ * @internal `delete()` once the side parts it touches are loaded: public so that a resolution's
68
+ * removals (`flushPendingRemovals`), which load only the parts the document has, take a comment away
69
+ * without creating any (CR-002 section 54).
69
70
  */
70
- getRange(): Range[];
71
+ removeThread(): void;
72
+ /**
73
+ * The commented range: one `Range` from the comment's start to its end, across paragraphs where the comment
74
+ * spans them, as Office JS's `Comment.getRange()` (CR-014 phase 1, D2; check 52: a comment from one paragraph
75
+ * into the next reads `BODY1B\rLIST1A`). A start marker between blocks (Word writes one before a control's
76
+ * first paragraph) starts the range at the next paragraph, and an end marker between blocks ends it at the
77
+ * previous one's end. Undefined when the comment has no markers in this body. `getRanges()` gives the range a
78
+ * paragraph at a time, as this method did before.
79
+ */
80
+ getRange(): Range | undefined;
81
+ /** Where a range marker stands: its paragraph and offset, a block-level one's the next or the previous paragraph's edge. */
82
+ private anchor;
83
+ /**
84
+ * The commented range a paragraph at a time: a `Range` per paragraph the comment touches (extension; what
85
+ * `getRange()` returned until CR-014 phase 1). Empty when the comment has no markers in this body.
86
+ */
87
+ getRanges(): Range[];
71
88
  /** This comment and, depth first, its replies. */
72
89
  private thread;
73
90
  private removeSelf;
@@ -108,6 +125,7 @@ export declare function commentsOf(scope: Body | Paragraph | Range): Promise<Com
108
125
  * Comments whose anchored text went with a rejected insertion or an accepted deletion (check 32;
109
126
  * `TrackedChange`'s `removeRevision`) had their markers removed then; their entries go here, with
110
127
  * their replies, when the comments are next read or the package is saved (`WordprocessingMLPackage.saveTo`).
128
+ * With the last comment, the comment parts go too (`flushPendingRemovals`).
111
129
  */
112
130
  export declare function flushPendingCommentRemovals(body: Body): Promise<void>;
113
131
  export type { CommentParts, Author } from './comments.mjs';
@@ -2,12 +2,14 @@ import * as el from '@docx4j/generated-objects-ts/el/org_docx4j_wml';
2
2
  import * as wmlFactory from '@docx4j/generated-objects-ts/factory/org_docx4j_wml';
3
3
  import * as w15Factory from '@docx4j/generated-objects-ts/factory/org_docx4j_w15';
4
4
  import * as w16cidFactory from '@docx4j/generated-objects-ts/factory/org_docx4j_w16cid';
5
- import { r as textRun, applyRunOptions, linkParents } from '@docx4j/generated-objects-ts/builders/wml';
5
+ import { applyRunOptions, linkParents } from '@docx4j/generated-objects-ts/builders/wml';
6
+ import { oneParagraphRun } from './officeText.mjs';
6
7
  import { Docx4JException } from '../../opc/exceptions.mjs';
7
8
  import { Body } from './Body.mjs';
8
9
  import { Paragraph } from './Paragraph.mjs';
9
10
  import { Range } from './Range.mjs';
10
- import { runOf, paragraphOf, typeNameOf } from './tree.mjs';
11
+ import { runOf, paragraphOf, typeNameOf, selectedBranchOf, BRANCH_TYPES } from './tree.mjs';
12
+ import { storyLayout } from './story.mjs';
11
13
  import { revisionDateOf, wordCalendarOf, copyRPr } from './tracking.mjs';
12
14
  import { relationshipIdsIn, queueRelationshipRemovals } from './relationships.mjs';
13
15
  import { COMMENT_REFERENCE_STYLE, COMMENT_TEXT_STYLE, commentExOf, commentIdsOf, commentPartsAccess, commentParaId, initialsOf, isDone, markersOf, markersOfParagraph, nextCommentId, paraIdTaken, randomHexId, removeMarkers, setCommentApi, } from './comments.mjs';
@@ -78,11 +80,13 @@ export class Comment {
78
80
  }
79
81
  /** The comment's text, a paragraph per line; setting it replaces the paragraphs. */
80
82
  get content() {
83
+ // Office JS's comment.content: its body's text, the paragraphs a mark \r apart (check 51)
81
84
  return this.commentBody.text;
82
85
  }
83
86
  set content(text) {
84
87
  const paraId = commentParaId(this.element);
85
- const paragraphs = text.split('\n').map((line, i) => commentParagraph(line, i === 0));
88
+ // a paragraph per line, \r (as the getter gives it) or \n
89
+ const paragraphs = text.split(/\r\n|\r|\n/).map((line, i) => commentParagraph(line, i === 0));
86
90
  if (paraId)
87
91
  paragraphs[0].value.paraId = paraId;
88
92
  this.element.content = paragraphs;
@@ -136,6 +140,14 @@ export class Comment {
136
140
  /** Removes the comment and its replies: the markers, the reference runs and every side-part entry. */
137
141
  async delete() {
138
142
  await this.parts.ensureAll();
143
+ this.removeThread();
144
+ }
145
+ /**
146
+ * @internal `delete()` once the side parts it touches are loaded: public so that a resolution's
147
+ * removals (`flushPendingRemovals`), which load only the parts the document has, take a comment away
148
+ * without creating any (CR-002 section 54).
149
+ */
150
+ removeThread() {
139
151
  for (const comment of this.thread())
140
152
  comment.removeSelf();
141
153
  if (this.parentComment) {
@@ -146,12 +158,57 @@ export class Comment {
146
158
  }
147
159
  }
148
160
  /**
149
- * The commented range: a `Range` per paragraph the comment touches (extension; Office JS
150
- * returns one `Range`). Empty when the comment has no markers in this body.
161
+ * The commented range: one `Range` from the comment's start to its end, across paragraphs where the comment
162
+ * spans them, as Office JS's `Comment.getRange()` (CR-014 phase 1, D2; check 52: a comment from one paragraph
163
+ * into the next reads `BODY1B\rLIST1A`). A start marker between blocks (Word writes one before a control's
164
+ * first paragraph) starts the range at the next paragraph, and an end marker between blocks ends it at the
165
+ * previous one's end. Undefined when the comment has no markers in this body. `getRanges()` gives the range a
166
+ * paragraph at a time, as this method did before.
151
167
  */
152
168
  getRange() {
169
+ const markers = markersOf(this.body.container, (p) => this.body.hiddenRuns(p)).filter((m) => m.id === this.id);
170
+ const start = markers.find((m) => m.kind === 'start');
171
+ const end = [...markers].reverse().find((m) => m.kind === 'end');
172
+ const from = start && this.anchor(start, 'start');
173
+ const to = end && this.anchor(end, 'end');
174
+ if (!from || !to)
175
+ return this.getRanges()[0];
176
+ const paragraphs = this.body.paragraphs;
177
+ const a = paragraphs.findIndex((p) => p.element === from.paragraph.element);
178
+ const b = paragraphs.findIndex((p) => p.element === to.paragraph.element);
179
+ if (a < 0 || b < 0 || b < a || (a === b && to.offset < from.offset))
180
+ return this.getRanges()[0];
181
+ return a === b ? new Range(from.paragraph, from.offset, to.offset)
182
+ : new Range(from.paragraph, from.offset, to.offset, false, false, to.paragraph);
183
+ }
184
+ /** Where a range marker stands: its paragraph and offset, a block-level one's the next or the previous paragraph's edge. */
185
+ anchor(marker, side) {
186
+ var _a;
187
+ if (marker.paragraph && marker.paragraphContainer) {
188
+ const paragraph = new Paragraph(marker.paragraph, marker.paragraphContainer, this.body);
189
+ return { paragraph, offset: (_a = marker.offset) !== null && _a !== void 0 ? _a : (side === 'start' ? 0 : paragraph.text.length) };
190
+ }
191
+ const at = marker.owner.indexOf(marker.item);
192
+ if (at < 0)
193
+ return undefined;
194
+ const blocks = side === 'start' ? marker.owner.slice(at + 1) : marker.owner.slice(0, at).reverse();
195
+ for (const block of blocks) {
196
+ const found = storyLayout([block], () => '').paragraphs;
197
+ const sp = side === 'start' ? found[0] : found[found.length - 1];
198
+ if (!sp)
199
+ continue;
200
+ const paragraph = new Paragraph(sp.element, sp.container, this.body);
201
+ return { paragraph, offset: side === 'start' ? 0 : paragraph.text.length };
202
+ }
203
+ return undefined;
204
+ }
205
+ /**
206
+ * The commented range a paragraph at a time: a `Range` per paragraph the comment touches (extension; what
207
+ * `getRange()` returned until CR-014 phase 1). Empty when the comment has no markers in this body.
208
+ */
209
+ getRanges() {
153
210
  var _a, _b, _c, _d;
154
- const markers = markersOf(this.body.container).filter((m) => m.id === this.id && m.paragraph !== undefined);
211
+ const markers = markersOf(this.body.container, (p) => this.body.hiddenRuns(p)).filter((m) => m.id === this.id && m.paragraph !== undefined);
155
212
  if (markers.length === 0)
156
213
  return [];
157
214
  const paragraphs = this.body.paragraphs;
@@ -292,11 +349,14 @@ function nestedIndex(owner, index) {
292
349
  }
293
350
  /** A paragraph of a comment: the `CommentText` style, opened by the annotation reference run. */
294
351
  function commentParagraph(text, first) {
352
+ var _a;
295
353
  const runs = [];
296
354
  if (first)
297
355
  runs.push(annotationRefRun());
298
- if (text !== '')
299
- runs.push(textRun(text));
356
+ // its line's characters as they read (CR-002 section 60 D1, E3); a line break is a paragraph of its own (D5)
357
+ const run = oneParagraphRun(text);
358
+ if ((_a = run.value.content) === null || _a === void 0 ? void 0 : _a.length)
359
+ runs.push(run);
300
360
  return paragraphOf(runs, { TYPE_NAME: 'org_docx4j_wml.PPr', pStyle: { val: COMMENT_TEXT_STYLE } });
301
361
  }
302
362
  function insertAt(owner, index, items, parent) {
@@ -307,6 +367,18 @@ function insertAt(owner, index, items, parent) {
307
367
  function parentOf(element) {
308
368
  return element.value.PARENT;
309
369
  }
370
+ /** The innermost branch of a kept `mc:AlternateContent` no reader takes that holds a value, or undefined. */
371
+ function unreadBranchOf(value) {
372
+ for (let o = value.PARENT, guard = 0; o && guard < 256; o = o.PARENT, guard++) {
373
+ const tn = o.TYPE_NAME;
374
+ if (tn === undefined || !BRANCH_TYPES.has(tn))
375
+ continue;
376
+ const ac = o.PARENT;
377
+ if (ac && selectedBranchOf(ac) !== o.any)
378
+ return o;
379
+ }
380
+ return undefined;
381
+ }
310
382
  /**
311
383
  * Where a marker for this segment's run goes when it is not put inside the revision the run sits
312
384
  * in (`placeAround`): beside the run, but outside the `w:ins` or `w:del`, so that a comment made
@@ -323,10 +395,17 @@ function markerSite(seg, fallback, after) {
323
395
  function placeAround(range, id) {
324
396
  var _a;
325
397
  var _b;
398
+ if (range.spansParagraphs) {
399
+ placeAcross(range, id);
400
+ return;
401
+ }
326
402
  const paragraph = range.paragraph;
327
- paragraph.splitAt(range.start);
403
+ // a run holding the span holds nothing else, a tab or a break beside it moved out too, as `font` splits (until
404
+ // CR-014 phase 3 only the w:t were split, and a marker went beside the whole run, widening the anchor)
328
405
  if (range.end > range.start)
329
- paragraph.splitAt(range.end);
406
+ paragraph.splitRunsAround(range.start, range.end);
407
+ else
408
+ paragraph.splitAt(range.start);
330
409
  const covered = range.end > range.start ? paragraph.segments().filter((s) => s.end > range.start && s.start < range.end) : [];
331
410
  const start = el.commentRangeStart(wmlFactory.createCommentRangeStart({ id }));
332
411
  const end = el.commentRangeEnd(wmlFactory.createCommentRangeEnd({ id }));
@@ -369,16 +448,90 @@ function placeAround(range, id) {
369
448
  insertAt(before.owner, before.index, [start], before.parent);
370
449
  }
371
450
  }
451
+ /**
452
+ * The markers of a comment over a range across paragraphs, as Word writes them (check 52, cases 79 to 85; CR-014
453
+ * phase 3): the start before the range's first character, in its first paragraph, and the end and the reference
454
+ * run after its last character, in its last paragraph, before a mark the range holds. A table between, or a cell
455
+ * either end is in, stays as it is: the markers stand in the paragraphs. On a block control's content range Word
456
+ * put the start before the control's first paragraph, in `w:sdtContent` (case 82); here it is inside that
457
+ * paragraph, which reads the same (CR-014 section 9.2). An insertion at either end is treated as `placeAround`
458
+ * treats one: the start inside it, before the first commented run; the end after the last, the rest of the
459
+ * insertion split off.
460
+ */
461
+ function placeAcross(range, id) {
462
+ var _a, _b, _c, _d, _e;
463
+ var _f, _g;
464
+ const first = range.paragraph;
465
+ const last = range.endParagraph;
466
+ const start = el.commentRangeStart(wmlFactory.createCommentRangeStart({ id }));
467
+ const end = el.commentRangeEnd(wmlFactory.createCommentRangeEnd({ id }));
468
+ const reference = referenceRun(id);
469
+ // the end first; the two are in different paragraphs, so neither's offsets move with the other's markers. The
470
+ // runs are split as `font` splits them, so a marker never goes beside a run holding text outside the range
471
+ if (range.end > 0)
472
+ last.splitRunsAround(0, range.end);
473
+ const before = last.segments().filter((s) => s.start < range.end);
474
+ const lastSeg = before[before.length - 1];
475
+ if (((_a = lastSeg === null || lastSeg === void 0 ? void 0 : lastSeg.revision) === null || _a === void 0 ? void 0 : _a.kind) === 'ins') {
476
+ last.splitHolderAround(lastSeg.revision, lastSeg.runIndex + 1, [end, reference], () => last.nextAnnotationId());
477
+ }
478
+ else if (lastSeg) {
479
+ const site = markerSite(lastSeg, last.p, true);
480
+ insertAt(site.owner, site.index, [end, reference], site.parent);
481
+ }
482
+ else {
483
+ // nothing of the last paragraph in the range: the end at its start
484
+ const next = last.segments()[0];
485
+ const site = next ? markerSite(next, last.p, false) : { owner: ((_b = (_f = last.p).content) !== null && _b !== void 0 ? _b : (_f.content = [])), index: 0, parent: last.p };
486
+ insertAt(site.owner, site.index, [end, reference], site.parent);
487
+ }
488
+ if (range.start < first.text.length)
489
+ first.splitRunsAround(range.start, first.text.length);
490
+ const segments = first.segments();
491
+ const firstSeg = segments.find((s) => s.end > range.start);
492
+ if (((_c = firstSeg === null || firstSeg === void 0 ? void 0 : firstSeg.revision) === null || _c === void 0 ? void 0 : _c.kind) === 'ins')
493
+ insertAt(firstSeg.runOwner, firstSeg.runIndex, [start], firstSeg.revision.value);
494
+ else if (firstSeg) {
495
+ const site = markerSite(firstSeg, first.p, false);
496
+ insertAt(site.owner, site.index, [start], site.parent);
497
+ }
498
+ else {
499
+ // nothing of the first paragraph in the range: the start at its end
500
+ const previous = segments[segments.length - 1];
501
+ const site = previous ? markerSite(previous, first.p, true) : { owner: ((_d = (_g = first.p).content) !== null && _d !== void 0 ? _d : (_g.content = [])), index: ((_e = first.p.content) !== null && _e !== void 0 ? _e : []).length, parent: first.p };
502
+ insertAt(site.owner, site.index, [start], site.parent);
503
+ }
504
+ }
372
505
  /** Writes the markers of a reply next to its parent's, as Word nests them. */
373
506
  function placeAfter(body, parentId, id) {
374
- const markers = markersOf(body.container).filter((m) => m.id === parentId);
375
- const start = markers.find((m) => m.kind === 'start');
376
- const end = [...markers].reverse().find((m) => m.kind === 'end');
377
- const reference = [...markers].reverse().find((m) => m.kind === 'reference');
378
- if (!((reference === null || reference === void 0 ? void 0 : reference.run) && reference.runOwner) && !end) {
507
+ var _a;
508
+ // the parent's markers in every branch of a kept mc:AlternateContent, each branch no reader takes
509
+ // apart, so that the reply is anchored in each as its parent is (CR-013 phase 3)
510
+ const groups = new Map();
511
+ for (const marker of markersOf(body.container, undefined, 'every')) {
512
+ if (marker.id !== parentId)
513
+ continue;
514
+ const key = unreadBranchOf(marker.item.value);
515
+ let group = groups.get(key);
516
+ if (!group)
517
+ groups.set(key, group = []);
518
+ group.push(marker);
519
+ }
520
+ const read = (_a = groups.get(undefined)) !== null && _a !== void 0 ? _a : [];
521
+ if (!read.some((m) => (m.kind === 'reference' && m.run && m.runOwner) || m.kind === 'end')) {
379
522
  // refused before anything is written, so that no marker is left naming a comment never made
380
523
  throw new Docx4JException(`Comment ${parentId} has no markers in this body; cannot anchor a reply`);
381
524
  }
525
+ for (const markers of groups.values())
526
+ placeAfterIn(markers, id);
527
+ }
528
+ /** A reply's markers after its parent's, in one branch's markers (or those outside any no reader takes). */
529
+ function placeAfterIn(markers, id) {
530
+ const start = markers.find((m) => m.kind === 'start');
531
+ const end = [...markers].reverse().find((m) => m.kind === 'end');
532
+ const reference = [...markers].reverse().find((m) => m.kind === 'reference');
533
+ if (!((reference === null || reference === void 0 ? void 0 : reference.run) && reference.runOwner) && !end)
534
+ return;
382
535
  if (start)
383
536
  insertAt(start.owner, start.owner.indexOf(start.item) + 1, [el.commentRangeStart(wmlFactory.createCommentRangeStart({ id }))], parentOf(start.item));
384
537
  if (end)
@@ -513,8 +666,9 @@ function commentId(parts, body, options) {
513
666
  }
514
667
  /** The paragraphs of a comment's content: a string splits on newlines, elements are taken as they are. */
515
668
  function paragraphsOfContent(content) {
669
+ // a paragraph per line, at \r, \n or \r\n, as Word's comments take them (CR-002 section 60 D5, check 55)
516
670
  if (typeof content === 'string')
517
- return content.split('\n').map((line, i) => commentParagraph(line, i === 0));
671
+ return content.split(/\r\n|\r|\n/).map((line, i) => commentParagraph(line, i === 0));
518
672
  const paragraphs = [...content];
519
673
  if (paragraphs.length === 0)
520
674
  throw new Docx4JException('A comment needs at least one paragraph');
@@ -549,6 +703,7 @@ export async function commentsOf(scope) {
549
703
  * Comments whose anchored text went with a rejected insertion or an accepted deletion (check 32;
550
704
  * `TrackedChange`'s `removeRevision`) had their markers removed then; their entries go here, with
551
705
  * their replies, when the comments are next read or the package is saved (`WordprocessingMLPackage.saveTo`).
706
+ * With the last comment, the comment parts go too (`flushPendingRemovals`).
552
707
  */
553
708
  export async function flushPendingCommentRemovals(body) {
554
709
  var _a;
@@ -562,18 +717,39 @@ export async function flushPendingCommentRemovals(body) {
562
717
  }
563
718
  await flushPendingRemovals(body, parts);
564
719
  }
720
+ /**
721
+ * The entries of the comments a resolution took away, replies included. The side parts the document
722
+ * has are loaded for it and none is created: before section 54 a removal created the commentsExtended,
723
+ * commentsIds and people parts a document lacked, as `delete()` does.
724
+ *
725
+ * With the last comment a resolution takes away, the comment parts go, as Word 365 removed them
726
+ * (docx4j CR-043 section 15; docx4j-python's artefact 8 rejected, docx4j's U22, core-ts check 32): the
727
+ * comments part and its commentsExtended, commentsIds and commentsExtensible parts, with their
728
+ * relationships; and the people part where no tracked change is left to name an author (U22: Word kept
729
+ * it while a deletion was still tracked). docx4j decides when its resolution ends; this, when the
730
+ * entries go, so tracked changes made or resolved in between count.
731
+ */
565
732
  async function flushPendingRemovals(body, parts) {
733
+ var _a;
566
734
  const pkg = body.package_;
567
735
  const pending = pkg === null || pkg === void 0 ? void 0 : pkg.pendingCommentRemovals;
568
736
  if (!(pending === null || pending === void 0 ? void 0 : pending.size))
569
737
  return;
738
+ await parts.loadExisting();
570
739
  const views = viewsOf(parts, body);
740
+ let removed = false;
571
741
  for (const id of [...pending]) {
572
742
  const view = views.get(id);
573
- if (view)
574
- await view.delete();
743
+ if (view) {
744
+ view.removeThread();
745
+ removed = true;
746
+ }
575
747
  pending.delete(id);
576
748
  }
749
+ if (!removed || ((_a = parts.comments.comment) !== null && _a !== void 0 ? _a : []).length > 0)
750
+ return;
751
+ const people = parts.people !== undefined && (pkg === null || pkg === void 0 ? void 0 : pkg.getAllTrackedChanges) !== undefined && (await pkg.getAllTrackedChanges()).length === 0;
752
+ parts.drop(people);
577
753
  }
578
754
  /** A `Comment` view per entry in the parts, replies linked to their parents. */
579
755
  function viewsOf(parts, body) {
@@ -602,7 +778,7 @@ function idsInRange(range) {
602
778
  var _a;
603
779
  const spans = new Map();
604
780
  const order = [];
605
- for (const marker of markersOfParagraph(range.paragraph.element, range.paragraph.container)) {
781
+ for (const marker of markersOfParagraph(range.paragraph.element, range.paragraph.container, range.paragraph.hiddenRuns())) {
606
782
  const at = (_a = marker.offset) !== null && _a !== void 0 ? _a : 0;
607
783
  const span = spans.get(marker.id);
608
784
  if (span) {
@@ -1,8 +1,10 @@
1
1
  import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
2
  import { XmlMapping } from '../customxml/XmlMapping.mjs';
3
3
  import { CheckboxContentControl, DatePickerContentControl, ListContentControl, PictureContentControl, RepeatingSectionContentControl, GroupContentControl } from '../customxml/kinds.mjs';
4
+ import { type LineBreaks } from './officeText.mjs';
5
+ import { type DefaultEntry } from './placeholders.mjs';
4
6
  import { type SdtKind } from '@docx4j/generated-objects-ts/builders/wml';
5
- import { type Element } from './tree.mjs';
7
+ import { type Element, type BranchMode } from './tree.mjs';
6
8
  import type { Body } from './Body.mjs';
7
9
  import type { Paragraph } from './Paragraph.mjs';
8
10
  import { Range } from './Range.mjs';
@@ -56,7 +58,11 @@ export declare class ContentControl {
56
58
  set title(value: string);
57
59
  /** w:id, the number Word gives a control; 0 when it has none. */
58
60
  get id(): number;
59
- /** The control's text, a line per paragraph (docx4j TextUtils). */
61
+ /**
62
+ * The control's text as Office JS gives it (CR-012 phase 4): a run-level control's span of
63
+ * `Paragraph.text`; a block-level one's content as `Body.text` reads it, its paragraphs a mark `\r` apart
64
+ * (check 51); a row control's cells a `\t` apart and a cell control's paragraphs `\r` apart (check 53).
65
+ */
60
66
  get text(): string;
61
67
  /** Every paragraph in the control; for a run-level control, the paragraph it is in. */
62
68
  get paragraphs(): Paragraph[];
@@ -64,6 +70,12 @@ export declare class ContentControl {
64
70
  get tables(): Table[];
65
71
  /** The controls nested in this one, in document order. */
66
72
  get contentControls(): ContentControl[];
73
+ /**
74
+ * Office JS `getContentControls` (WordApi 1.5): the content controls `contentControls` lists, those of `options.types`
75
+ * where given. Word's `contentControls` lists rich-text controls only; this package's lists every kind, a recorded
76
+ * departure (CR-002 section 60 G1, check 55b), so this is how add-in code that asks for plain-text controls finds them.
77
+ */
78
+ getContentControls(options?: ContentControlOptions): ContentControl[];
67
79
  /**
68
80
  * Text at the start, the end, or replacing the control's text. On a **bound** control the value
69
81
  * is written through to the custom XML node as well when the mapping resolves (CR-002 phase E):
@@ -72,17 +84,112 @@ export declare class ContentControl {
72
84
  * write is left to `pkg.customXmlParts.updateFromContentControls()`.
73
85
  */
74
86
  insertText(text: string, location: 'Start' | 'End' | 'Replace'): Range;
87
+ /**
88
+ * The glossary entry the control's `w:placeholder` names, which makes it Word's form; undefined where it names none,
89
+ * the bare form, which has no entry to show once emptied, nor for `placeholderText` to read (CR-002 section 63; an
90
+ * extension). Writes are the same in both forms (check 63's run 2).
91
+ */
92
+ get placeholderEntry(): string | undefined;
93
+ /** @internal True for a block or run-level control showing its placeholder, which a text write replaces (section 63). */
94
+ get showsPlaceholderContent(): boolean;
95
+ /** The package's glossary entries, where the control is in a package. */
96
+ private get glossary();
97
+ /**
98
+ * @internal Text written into the content of this control while it shows its placeholder, by any route: its own
99
+ * `insertText`, its 'Content' range's, a block control's paragraph's (CR-002 section 63, D1, D2 (b), D5, D11). The
100
+ * placeholder is no content, in either form (checks 64 and 67, check 63's run 2): its runs go, untracked, the text takes
101
+ * their place in one paragraph, and the flag is cleared; under tracking only the insertion is recorded. The text takes
102
+ * the control's own run properties (`w:sdtPr/w:rPr`) and nothing of the placeholder's (check 68, cases 1 to 20).
103
+ */
104
+ writePlaceholder(text: string, options?: {
105
+ lineBreaks?: LineBreaks;
106
+ }): Range;
107
+ /** The control's first paragraph, made where its content has none. */
108
+ private firstParagraph;
109
+ /**
110
+ * Takes the placeholder's runs out of the content: a run-level control's, or a block control's paragraphs', the first
111
+ * paragraph kept, emptied, and any other going. What held them.
112
+ */
113
+ private takePlaceholderRuns;
114
+ /**
115
+ * Shows Word's filler for a control emptied in the bare form, where no glossary entry gives it a placeholder: the flag
116
+ * 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,
117
+ * 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
118
+ * on (CR-012 section 18).
119
+ */
120
+ private showFiller;
121
+ /**
122
+ * @internal A write through the control's 'Content' or 'Whole' range that the control takes (D3, D4): text into a
123
+ * control showing its placeholder, or into an empty run-level control, goes inside it; a 'Whole' range's Replace over
124
+ * a run-level control showing its placeholder takes the control, the text in its place. Undefined where the range's
125
+ * own write applies.
126
+ */
127
+ writeThrough(part: 'Content' | 'Whole', text: string, location: string): Range | undefined;
128
+ /**
129
+ * @internal A delete through the control's 'Content' or 'Whole' range that the control takes; false where the range's
130
+ * own delete applies. A 'Content' delete of a control showing its placeholder keeps the control and the flag: in the
131
+ * bare form over Word's filler, five spaces (D10; check 63's run 2, cases 6, 17, 32 and 43, nothing marked under
132
+ * tracking); in Word's form nothing changes, the placeholder being no content. A 'Whole' delete takes a run-level
133
+ * control showing its placeholder (D3).
134
+ */
135
+ deleteThrough(part: 'Content' | 'Whole'): boolean;
136
+ /**
137
+ * @internal After a 'Content' delete, untracked, that left the control holding no text: in Word's form it shows its
138
+ * 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
139
+ * Word gives no default entry, naming an entry the glossary lacks.
140
+ */
141
+ showEmptied(): void;
142
+ /**
143
+ * @internal Word's default placeholder entry for this control's kind (CR-002 section 63.22; docx4j CR-063's D8): the
144
+ * text kinds', the date picker's, the lists', a building block gallery's, a repeating section item's. Undefined for a
145
+ * kind Word gives none.
146
+ */
147
+ get defaultPlaceholderEntry(): DefaultEntry | undefined;
148
+ /**
149
+ * @internal Whether an empty control shows a placeholder in Word's form (D8; docx4j CR-063's D3 and D8): a kind Word
150
+ * gives a default entry, or one naming an entry the glossary holds.
151
+ */
152
+ get showsWordsFormPlaceholder(): boolean;
153
+ /**
154
+ * @internal Takes the control whole (D3): a Replace or delete over a control showing its placeholder, as Word takes one
155
+ * (check 63 cases 12, 18 to 20, 26, 38, 44 to 46 and 52). Untracked it goes, a block control leaving its paragraph,
156
+ * emptied, in its place; tracked it is marked deleted in Word's form (`markHolderDeleted`: `w:customXmlDelRange`
157
+ * markers around it and inside its content), its placeholder gone unmarked and the flag cleared (check 63's run 2,
158
+ * cases 38, 44 to 46 and 52). `text` goes where a run-level control stood, before it under tracking, as Word puts a
159
+ * Replace's insertion first.
160
+ */
161
+ takeWhole(text?: string): Range;
162
+ /** The control marked deleted with Word's markers, its placeholder gone, unmarked, and the flag cleared (`takeWhole`). */
163
+ private markWholeDeleted;
164
+ /**
165
+ * Shows the control's placeholder (CR-002 section 63, D8; section 63.18): a copy of the content of the entry its
166
+ * `w:placeholder` names, as the glossary holds it, the control's own run properties not over it, as Word shows it
167
+ * (check 68, section 63.21), with `w:showingPlcHdr`. A control naming no entry, or one the glossary lacks, is made to
168
+ * 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
169
+ * "Choose an item."), which is written into the glossary on save where it lacks it (D9), as docx4j's CR-063 has it:
170
+ * Word's save drops a reference no entry holds (check 65). A kind Word gives no default entry (a picture, a check box)
171
+ * keeps the name it has, and naming none shows docx4j's run, with no reference; any control keeps its name until the
172
+ * glossary is read (`getBody`, `Word.run`), showing its kind's default text. An extension.
173
+ */
174
+ showPlaceholder(): void;
75
175
  private insertTextInto;
76
176
  /** A paragraph at the start or end of a block control; before or after the paragraph of a run control. */
77
177
  insertParagraph(text: string, location: 'Start' | 'End' | 'Before' | 'After'): Paragraph;
78
178
  /** Matches within the control. */
79
179
  search(text: string, options?: SearchOptions): Range[];
80
180
  /**
81
- * The control's range. For a run-level control, exactly the text it holds; for the other forms,
82
- * the first paragraph (departure: a Range here is within one paragraph, CR-002 section 7).
181
+ * The control's range. For a run-level control, exactly the text it holds; for the other forms, its
182
+ * paragraphs: one `Range` from the first one's start to the last one's end (CR-014 phase 1), its 'Whole'
183
+ * ending with the last one's mark, as Office JS's does (check 51: `CCP1\rCCP2\rCCP3\r`, its 'Content'
184
+ * without the last `\r`).
83
185
  */
84
186
  getRange(location?: 'Whole' | 'Start' | 'End' | 'Content'): Range;
85
- /** Removes the control; `keepContent` puts what it held in its place, as Office JS. */
187
+ private rangeOf;
188
+ /**
189
+ * Removes the control; `keepContent` puts what it held in its place, as Office JS. Where the control held the
190
+ * paragraph a table cell ends with, that paragraph stays in its place, emptied, its properties kept, outside
191
+ * any control, as Word keeps a cell's last paragraph (check 52, case 95; CR-002 section 55.6).
192
+ */
86
193
  delete(keepContent?: boolean): void;
87
194
  /** The XML of the control (extension). */
88
195
  getXml(): Promise<string>;
@@ -103,14 +210,21 @@ export declare class ContentControl {
103
210
  /** The control's data binding (Office JS `xmlMapping`), backed by `w:dataBinding`. */
104
211
  get xmlMapping(): XmlMapping;
105
212
  /**
106
- * The placeholder Word shows for an empty control: the control's own text while it is showing
107
- * the placeholder (`w:showingPlcHdr`), else '' — Word keeps the text itself in a glossary
108
- * document part, which this phase does not create (CR-002 section 12). Setting writes the text
109
- * as the control's content and sets `w:showingPlcHdr`, which is refused when the control holds
110
- * content of its own, so that a value is never lost.
213
+ * The placeholder Word shows for an empty control: the text of the glossary entry the control's `w:placeholder` names,
214
+ * as Office JS reads it (CR-002 section 63, D8; check 65), `null` where the control names none (the bare form) or the
215
+ * glossary lacks the entry. The glossary is read when the body is (`getBody`, `Word.run`). Setting it names Word's
216
+ * default entry for Word's default text, else a new entry holding the text, named as Word names one (32 hex digits),
217
+ * which is written into the glossary on save, the entry named before left there; a control showing its placeholder,
218
+ * or holding nothing, shows the new text. A control's content is left alone. Until section 63 the text was written as
219
+ * the control's content in the bare form, and a control holding content refused it.
111
220
  */
112
- get placeholderText(): string;
221
+ get placeholderText(): string | null;
113
222
  set placeholderText(text: string);
223
+ /**
224
+ * Blocks taken out of the control's content: the relationships only they used (a picture's image) and the comments
225
+ * whose references they held go when the package is saved, as a deletion's do.
226
+ */
227
+ private removeBlocks;
114
228
  /** Office JS `appearance`: how Word draws the control (`w15:appearance`). */
115
229
  get appearance(): ContentControlAppearance;
116
230
  set appearance(value: ContentControlAppearance);
@@ -152,6 +266,8 @@ export declare class ContentControl {
152
266
  get runProperties(): wml.RPr | undefined;
153
267
  /** Whether a plain-text control accepts several lines (`w:text/@w:multiLine`). */
154
268
  get isMultiLine(): boolean;
269
+ /** Office JS's name for `isShowingPlaceholder` (`showingPlaceholderText`, WordApiDesktop 1.3, read-only there). */
270
+ get showingPlaceholderText(): boolean;
155
271
  /** Whether the control is showing its placeholder rather than a value (`w:showingPlcHdr`). */
156
272
  get isShowingPlaceholder(): boolean;
157
273
  set isShowingPlaceholder(value: boolean);
@@ -166,18 +282,81 @@ export declare class ContentControl {
166
282
  /** A copy of this control right after it, as Word's repeating-section + button does (extension). */
167
283
  insertCopyAfter(): ContentControl;
168
284
  /**
169
- * Writes the control's text into the node it is bound to, when there is one and the XPath engine
170
- * is warm. Silent when it is not: reading a custom XML part is `pkg.customXmlParts.load()`'s job,
285
+ * @internal Writes the control's text into the node it is bound to, when there is one and the XPath engine
286
+ * 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,
171
287
  * and `updateFromContentControls()` is the explicit form of this write.
172
288
  */
173
- private syncBoundNode;
174
- private firstRunOfContent;
289
+ syncBoundNode(): void;
175
290
  private lockValue;
176
291
  private setLock;
292
+ /**
293
+ * True for a control in the selected branch of a kept `mc:AlternateContent`, at any level, which the
294
+ * collectors list as Word reads it (CR-013 phase 2). Such a view is read-only (D4).
295
+ */
296
+ get inBranch(): boolean;
297
+ /** Refuses a write to a control in a branch (CR-013 D4). Internal: the control's mutators, and its kinds', call it first. */
298
+ assertWritable(): void;
177
299
  /** The table a row-level or cell-level control belongs to. */
178
300
  private ancestorTable;
179
301
  }
180
- /** Every content control under a list of block-level items, in document order, nested ones included. */
181
- export declare function collectControls(items: Element[], body: Body, out: ContentControl[]): void;
302
+ /**
303
+ * Every content control under a list of block-level items, in document order, nested ones included. In a
304
+ * kept `mc:AlternateContent` a reader's (`'read'`, the default) takes the selected branch's controls (CR-013
305
+ * phase 2), the binding passes (`'every'`) every branch's, each other branch's where the element stands
306
+ * (phase 3).
307
+ */
308
+ export declare function collectControls(items: Element[], body: Body, out: ContentControl[], mode?: BranchMode): void;
182
309
  /** The run-level controls in a paragraph (or any run holder), in order, nested ones included. */
183
- export declare function collectRunControls(holder: object, body: Body, out: ContentControl[]): void;
310
+ export declare function collectRunControls(holder: object, body: Body, out: ContentControl[], mode?: BranchMode): void;
311
+ /**
312
+ * 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
313
+ * blocks, a holder's items).
314
+ */
315
+ export declare function controlViewOf(sdt: object, body: Body): ContentControl;
316
+ /**
317
+ * A block-level control bound by `w:dataBinding`, untyped, `w:text` or `w:richText`, whose node doesn't hold flat OPC
318
+ * (CR-002 section 61 H1): Word holds its content to one paragraph, and can't open a file where it holds more (check 56,
319
+ * docx4j-python's file 3). A node not resolved (the custom XML parts not loaded) counts as not flat OPC. `w15:dataBinding`
320
+ * is Word's rich-text binding, and isn't this.
321
+ */
322
+ export declare function isBoundBlockControl(control: ContentControl): boolean;
323
+ /**
324
+ * How a control holds lines, as Word reads it: `multi` or `single` for a plain-text control (`w:text` and its
325
+ * `w:multiLine`), `single` for a bound block control Word reads as plain text (section 61 H4); undefined for any other.
326
+ */
327
+ export declare function plainTextLinesOf(control: ContentControl): 'multi' | 'single' | undefined;
328
+ /**
329
+ * Text for a run-level control: a line feed or carriage return there is refused before anything changes (CR-002
330
+ * section 60 F4: Word, given one, moved a bound plain-text control to block level), and a plain-text control's breaks
331
+ * go as its kind takes them (F3: dropped in a single-line one).
332
+ */
333
+ export declare function textForRunControl(control: ContentControl, text: string): string;
334
+ /** Word's error for a block write into a bound block control, where measured (CR-002 section 61 H3; check 56). */
335
+ export type BlockRefusal = 'InvalidArgument' | 'GeneralException';
336
+ /**
337
+ * Refuses, before anything changes, putting blocks into a block-level control bound by `w:dataBinding` (untyped,
338
+ * `w:text` or `w:richText`, its node not flat OPC) that would leave it holding anything but one paragraph: Word can't
339
+ * open such a file, and its repair loses the extra blocks (CR-002 section 61, check 56). Word's own error where
340
+ * measured (`insertTable` `InvalidArgument`, `insertOoxml` `GeneralException`), else `NotSupportedError` (H3).
341
+ */
342
+ export declare function assertControlHolds(body: Body, holder: object, container: Element[], elements: readonly Element[], refusal?: BlockRefusal, member?: [string, string]): void;
343
+ /** Office JS `Word.ContentControlOptions`: the types `getContentControls` lists. */
344
+ export interface ContentControlOptions {
345
+ /** `ContentControlType` values; Office JS takes the enum's strings. */
346
+ types?: readonly string[];
347
+ }
348
+ /** The controls of `options.types`, or all of them. */
349
+ export declare function controlsOfTypes(controls: ContentControl[], options?: ContentControlOptions): ContentControl[];
350
+ /**
351
+ * Whether a control of this kind made on an empty range shows its default placeholder, as Word's does (CR-002 section
352
+ * 63, D8; check 64; Jason's `placeholders.docx`, section 63.22): a text control, a date picker, a drop-down list or a
353
+ * combo box. The building block and repeating section kinds are made as before.
354
+ */
355
+ export declare function showsPlaceholderWhenMade(kind: ContentControlType | undefined): boolean;
356
+ /** A stand-in for a block-level control about to be made, for `assertControlHolds` before `sdtOf` takes its content. */
357
+ export declare const BLOCK_CONTROL: Element;
358
+ /**
359
+ * Whether a block-level control holds one paragraph and nothing else at block level, or nothing yet: what a bound
360
+ * block control may hold (CR-002 section 61).
361
+ */
362
+ export declare function holdsOneParagraph(control: ContentControl): boolean;