@docx4j/core-ts 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/content/Body.d.mts +15 -3
- package/dist/model/content/Body.mjs +93 -31
- package/dist/model/content/Comment.d.mts +27 -2
- package/dist/model/content/Comment.mjs +180 -41
- package/dist/model/content/ContentControl.d.mts +6 -0
- package/dist/model/content/ContentControl.mjs +51 -5
- package/dist/model/content/Font.mjs +2 -0
- package/dist/model/content/List.mjs +9 -6
- package/dist/model/content/Paragraph.d.mts +72 -2
- package/dist/model/content/Paragraph.mjs +308 -55
- package/dist/model/content/Range.d.mts +6 -4
- package/dist/model/content/Range.mjs +114 -13
- package/dist/model/content/Table.mjs +6 -8
- package/dist/model/content/TrackedChange.d.mts +125 -6
- package/dist/model/content/TrackedChange.mjs +847 -50
- package/dist/model/content/comments.d.mts +20 -3
- package/dist/model/content/comments.mjs +1 -9
- package/dist/model/content/index.d.mts +3 -3
- package/dist/model/content/index.mjs +2 -2
- package/dist/model/content/stylesFacade.mjs +5 -2
- package/dist/model/content/tableRevisions.d.mts +30 -0
- package/dist/model/content/tableRevisions.mjs +207 -0
- package/dist/model/content/tracking.d.mts +109 -13
- package/dist/model/content/tracking.mjs +267 -43
- package/dist/packages/WordprocessingMLPackage.d.mts +6 -0
- package/dist/packages/WordprocessingMLPackage.mjs +11 -0
- package/dist/parts/wml/commentStyles.d.mts +3 -0
- package/dist/parts/wml/commentStyles.mjs +25 -0
- package/dist/parts/wml/comments.mjs +51 -22
- package/package.json +1 -1
|
@@ -7,8 +7,8 @@ import { marshalString, deepCopy } from '@docx4j/generated-objects-ts';
|
|
|
7
7
|
import { XmlMapping } from '../customxml/XmlMapping.mjs';
|
|
8
8
|
import { CheckboxContentControl, DatePickerContentControl, ListContentControl, PictureContentControl, RepeatingSectionContentControl, GroupContentControl, checkboxRun, CHECKBOX_FONT, } from '../customxml/kinds.mjs';
|
|
9
9
|
import { runsForValue, updateFromControl, PLACEHOLDER_TEXT } from '../customxml/bindings.mjs';
|
|
10
|
-
import { sdtProperty, sdtKindOf } from '@docx4j/generated-objects-ts/builders/wml';
|
|
11
|
-
import { typeNameOf, childrenOf, textOf, runItemsOf, segmentsOf, linkParents, SDT_TYPES } from './tree.mjs';
|
|
10
|
+
import { sdtProperty, sdtKindOf, t as textItem } from '@docx4j/generated-objects-ts/builders/wml';
|
|
11
|
+
import { typeNameOf, childrenOf, textOf, runItemsOf, segmentsOf, linkParents, runOf, SDT_TYPES } from './tree.mjs';
|
|
12
12
|
import { Range } from './Range.mjs';
|
|
13
13
|
import { Table } from './Table.mjs';
|
|
14
14
|
/** The namespaces of the Word 2010 and 2012 content-control properties. */
|
|
@@ -128,6 +128,8 @@ export class ContentControl {
|
|
|
128
128
|
if (!span)
|
|
129
129
|
throw new Docx4JException('This content control is not in a paragraph');
|
|
130
130
|
const { paragraph, start, end } = span;
|
|
131
|
+
if (span.empty)
|
|
132
|
+
return this.insertIntoEmpty(paragraph, text);
|
|
131
133
|
if (location === 'Start')
|
|
132
134
|
return paragraph.splice(start, start, text);
|
|
133
135
|
if (location === 'End')
|
|
@@ -251,7 +253,8 @@ export class ContentControl {
|
|
|
251
253
|
};
|
|
252
254
|
let start;
|
|
253
255
|
let end = 0;
|
|
254
|
-
|
|
256
|
+
const segs = segmentsOf(paragraph.p);
|
|
257
|
+
for (const seg of segs) {
|
|
255
258
|
if (!inside(seg.run))
|
|
256
259
|
continue;
|
|
257
260
|
if (start === undefined)
|
|
@@ -259,11 +262,54 @@ export class ContentControl {
|
|
|
259
262
|
end = seg.end;
|
|
260
263
|
}
|
|
261
264
|
if (start === undefined) {
|
|
262
|
-
//
|
|
263
|
-
|
|
265
|
+
// a control holding no text: its position is the end of the last text before it in the
|
|
266
|
+
// paragraph (before, it was reported at 0, and text put into it went to the paragraph's start)
|
|
267
|
+
let pos = 0;
|
|
268
|
+
let found = false;
|
|
269
|
+
const visit = (items) => {
|
|
270
|
+
for (const el of items !== null && items !== void 0 ? items : []) {
|
|
271
|
+
if (found)
|
|
272
|
+
return;
|
|
273
|
+
if (el === this.element) {
|
|
274
|
+
found = true;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const v = el.value;
|
|
278
|
+
if (typeof v !== 'object' || v === null)
|
|
279
|
+
continue;
|
|
280
|
+
if (typeNameOf(el) === 'org_docx4j_wml.R') {
|
|
281
|
+
const last = segs.filter((seg) => seg.run === v).pop();
|
|
282
|
+
if (last)
|
|
283
|
+
pos = last.end;
|
|
284
|
+
}
|
|
285
|
+
else
|
|
286
|
+
visit(runItemsOf(v));
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
visit(paragraph.p.content);
|
|
290
|
+
return { paragraph, start: pos, end: pos, empty: true };
|
|
264
291
|
}
|
|
265
292
|
return { paragraph, start, end };
|
|
266
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Text into a run control that holds no run: a new run in its content, in a `w:ins` under
|
|
296
|
+
* tracking (Word: check 30, new-control-typed), placed before the control's trailing insertion
|
|
297
|
+
* marker when it is itself an insertion.
|
|
298
|
+
*/
|
|
299
|
+
insertIntoEmpty(paragraph, text) {
|
|
300
|
+
var _a, _b;
|
|
301
|
+
var _c;
|
|
302
|
+
const sdt = this.sdt;
|
|
303
|
+
const items = ((_b = (_c = ((_a = sdt.sdtContent) !== null && _a !== void 0 ? _a : (sdt.sdtContent = {}))).content) !== null && _b !== void 0 ? _b : (_c.content = []));
|
|
304
|
+
const run = runOf([textItem(text)]);
|
|
305
|
+
const tracker = paragraph.changeTracker;
|
|
306
|
+
const item = tracker ? tracker.ins([run]) : run;
|
|
307
|
+
const at = items.findIndex((el) => { var _a; return ((_a = el.name) === null || _a === void 0 ? void 0 : _a.localPart) === 'customXmlInsRangeStart'; });
|
|
308
|
+
items.splice(at < 0 ? items.length : at, 0, item);
|
|
309
|
+
linkParents(item, sdt.sdtContent);
|
|
310
|
+
const span = this.runSpan();
|
|
311
|
+
return new Range(paragraph, span.start, span.end);
|
|
312
|
+
}
|
|
267
313
|
// --- CR-002 phase E: the XML mapping, the typed kinds and the w:sdtPr properties ---
|
|
268
314
|
/** The control's data binding (Office JS `xmlMapping`), backed by `w:dataBinding`. */
|
|
269
315
|
get xmlMapping() {
|
|
@@ -511,6 +511,7 @@ export class ListItem {
|
|
|
511
511
|
}
|
|
512
512
|
numPr.ilvl = f.createPPrBaseNumPrIlvl({ val: value });
|
|
513
513
|
linkParents(numPr.ilvl, numPr);
|
|
514
|
+
this.paragraph.settleFormatting();
|
|
514
515
|
}
|
|
515
516
|
/**
|
|
516
517
|
* Office JS `listItem.listString`: the label Word paints in front of the paragraph.
|
|
@@ -628,6 +629,7 @@ export function attachToList(paragraph, listId, level = 0) {
|
|
|
628
629
|
numPr.numId = f.createPPrBaseNumPrNumId({ val: Number(listId) });
|
|
629
630
|
numPr.ilvl = f.createPPrBaseNumPrIlvl({ val: level });
|
|
630
631
|
linkParents(numPr, paragraph.p.pPr);
|
|
632
|
+
paragraph.settleFormatting();
|
|
631
633
|
return new List(String(listId), paragraph.parentBody);
|
|
632
634
|
}
|
|
633
635
|
/**
|
|
@@ -640,12 +642,13 @@ export function detachFromList(paragraph) {
|
|
|
640
642
|
if (((_a = paragraph.p.pPr) === null || _a === void 0 ? void 0 : _a.numPr) !== undefined) {
|
|
641
643
|
delete paragraph.pPr().numPr;
|
|
642
644
|
}
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
645
|
+
if (isListItem(paragraph)) {
|
|
646
|
+
const numPr = paragraph.numPr();
|
|
647
|
+
numPr.numId = f.createPPrBaseNumPrNumId({ val: 0 });
|
|
648
|
+
linkParents(numPr.numId, numPr);
|
|
649
|
+
delete numPr.ilvl;
|
|
650
|
+
}
|
|
651
|
+
paragraph.settleFormatting();
|
|
649
652
|
}
|
|
650
653
|
/**
|
|
651
654
|
* Office JS `paragraph.startNewList()`: a `w:abstractNum` copied from docx4j's default
|
|
@@ -9,7 +9,7 @@ import { ContentControl, type ContentControlType } from './ContentControl.mjs';
|
|
|
9
9
|
import { InlinePicture, type InlinePictureOptions } from './InlinePicture.mjs';
|
|
10
10
|
import { type CommentContent, type CommentOptions } from './comments.mjs';
|
|
11
11
|
import type { Comment } from './Comment.mjs';
|
|
12
|
-
import {
|
|
12
|
+
import { ChangeTracker } from './tracking.mjs';
|
|
13
13
|
import { TrackedChange } from './TrackedChange.mjs';
|
|
14
14
|
import { type List, type ListItem, type StartListOptions } from './List.mjs';
|
|
15
15
|
/**
|
|
@@ -106,6 +106,15 @@ export declare class Paragraph {
|
|
|
106
106
|
/** The effective alignment; an absent `w:jc` after resolution is `'Left'`, as Office JS. */
|
|
107
107
|
get alignment(): Alignment;
|
|
108
108
|
set alignment(v: AlignmentOrUnknown);
|
|
109
|
+
/**
|
|
110
|
+
* The alignment the paragraph resolves to with no `w:jc` of its own: its style's, else the
|
|
111
|
+
* defaults'. Word's Ctrl+L on a centred paragraph whose style is left-aligned removes the `w:jc`
|
|
112
|
+
* rather than writing `w:jc="left"`, with tracking on (check 26) and off (the editor's
|
|
113
|
+
* `measure-word2010.docx` and `measure-word15.docx`, 2026-09-30; CR-002 section 38), so a value the
|
|
114
|
+
* paragraph already inherits is not written. Measured for left over a left-aligned style; taken to
|
|
115
|
+
* hold for any value. Undefined without a resolver, where the value is written as asked.
|
|
116
|
+
*/
|
|
117
|
+
private inheritedAlignment;
|
|
109
118
|
/** Indents and spacing in points, as Office JS; the effective values (CR-001 Phase B step 2). */
|
|
110
119
|
get leftIndent(): number;
|
|
111
120
|
set leftIndent(pt: number);
|
|
@@ -186,6 +195,17 @@ export declare class Paragraph {
|
|
|
186
195
|
*/
|
|
187
196
|
delete(): void;
|
|
188
197
|
private trackedDelete;
|
|
198
|
+
/**
|
|
199
|
+
* A paragraph mark deleted under tracking gives the next paragraph this paragraph's properties,
|
|
200
|
+
* as a `w:pPrChange` on it recording its own: Word, at Delete at the end of a Heading 2 with a
|
|
201
|
+
* Normal paragraph after it, wrote the next paragraph `w:pStyle Heading2` with
|
|
202
|
+
* `<w:pPrChange><w:pPr/></w:pPrChange>`, and No Markup reads the joined line as a heading
|
|
203
|
+
* throughout (the editor's `measure-word15.docx`, 2026-09-30; CR-002 section 38). The Delete
|
|
204
|
+
* counterpart of check 29's Enter. Nothing where the two paragraphs' properties are the same
|
|
205
|
+
* (check 22's deleted marks). Accepting the mark then joins into a paragraph with these
|
|
206
|
+
* properties, and rejecting puts the next paragraph's back.
|
|
207
|
+
*/
|
|
208
|
+
private giveMarkPropertiesToNext;
|
|
189
209
|
/**
|
|
190
210
|
* The paragraph's content and its mark marked deleted, the paragraph element itself kept:
|
|
191
211
|
* what the cells of a deleted table row need (a `w:tc` must keep a block-level child, and Word
|
|
@@ -206,6 +226,20 @@ export declare class Paragraph {
|
|
|
206
226
|
* @internal public so that the list views (CR-002 phase H) write `w:numPr` the same way.
|
|
207
227
|
*/
|
|
208
228
|
pPr(): wml.PPr;
|
|
229
|
+
/**
|
|
230
|
+
* After a tracked write of the paragraph's properties: when the paragraph is as it was, its
|
|
231
|
+
* recorded properties go back as they were and the `w:pPrChange` goes, since Word keeps no
|
|
232
|
+
* formatting change that changes nothing, whoever changed it back (`test/README.md` check 26:
|
|
233
|
+
* centred then left again, by the same author and by another; Increase Indent then Decrease
|
|
234
|
+
* Indent; each left no `w:pPr`; CR-002 section 29). "As it was" is Office JS's paragraph
|
|
235
|
+
* formatting (alignment, indents, spacing, outline level) read resolved from both, the rest of the
|
|
236
|
+
* properties - the style, the list - written the same: Word's Ctrl+L and Decrease Indent removed
|
|
237
|
+
* the direct values where this package's setters write `w:jc="left"` and `w:ind w:left="0"`.
|
|
238
|
+
* Without the package's `PropertyResolver` only properties written the same count.
|
|
239
|
+
*
|
|
240
|
+
* @internal public so that the list views (CR-002 phase H) settle their `w:numPr` writes.
|
|
241
|
+
*/
|
|
242
|
+
settleFormatting(): void;
|
|
209
243
|
/**
|
|
210
244
|
* The paragraph's `w:numPr`, created when absent, through {@link pPr} so that a tracked
|
|
211
245
|
* write records `w:pPrChange` first.
|
|
@@ -227,7 +261,7 @@ export declare class Paragraph {
|
|
|
227
261
|
* is removed, a run left empty is removed. Text is inserted into the w:t at `start`,
|
|
228
262
|
* else into a new run with the formatting of the nearest run.
|
|
229
263
|
*/
|
|
230
|
-
splice(start: number, end: number, text: string): Range;
|
|
264
|
+
splice(start: number, end: number, text: string, prefer?: 'before' | 'after'): Range;
|
|
231
265
|
/**
|
|
232
266
|
* Inserts run-level items (runs, hyperlinks, content controls) at a text offset, splitting the
|
|
233
267
|
* run there when the offset falls inside one. PARENT is linked on what is inserted.
|
|
@@ -286,12 +320,47 @@ export declare class Paragraph {
|
|
|
286
320
|
* Returns the `w:del` elements it made, in document order.
|
|
287
321
|
*/
|
|
288
322
|
private deleteText;
|
|
323
|
+
/**
|
|
324
|
+
* Splits the revision that holds the text at `at` into two - the second half a copy of its
|
|
325
|
+
* attributes under a new `w:id` - and puts `item` between them. Word splits a revision so when
|
|
326
|
+
* text is typed inside it: around the typist's `w:ins` with tracking on, around plain text with it
|
|
327
|
+
* off (`test/README.md` checks 20 and 21). False, with nothing changed but a run split at `at`,
|
|
328
|
+
* where the text there is not directly in the revision (in a hyperlink inside it, say): the caller
|
|
329
|
+
* then does what it did before.
|
|
330
|
+
*/
|
|
331
|
+
private insertBetweenHalves;
|
|
332
|
+
/**
|
|
333
|
+
* Moves a revision's items from `index` on into a copy of it - its attributes, a new `w:id` - and
|
|
334
|
+
* puts `item` between the two; with nothing from `index` on, `item` just goes after the revision.
|
|
335
|
+
* False, with nothing changed, where the revision's items cannot be told apart from its attributes.
|
|
336
|
+
* Internal: `Range.insertContentControl` uses it to put a new control between the halves of the
|
|
337
|
+
* insertion it wraps part of (check 30).
|
|
338
|
+
*/
|
|
339
|
+
splitHolderAround(holder: RevisionHolderOf, index: number, item: Element | Element[], nextId: () => number): boolean;
|
|
340
|
+
/**
|
|
341
|
+
* Puts `item` beside a revision rather than in it: after it, or before it - and then before the
|
|
342
|
+
* range start of a move whose range opens just there, so that text typed at the start of moved
|
|
343
|
+
* text is not inside the move (`test/README.md` check 20 case 03).
|
|
344
|
+
*/
|
|
345
|
+
private insertBesideRevision;
|
|
346
|
+
/**
|
|
347
|
+
* A fresh annotation id for markup this paragraph writes itself: the package's counter when there
|
|
348
|
+
* is a package that keeps one, since a document has one id space; else one above every id in the
|
|
349
|
+
* story.
|
|
350
|
+
*/
|
|
351
|
+
/** @internal `Comment` uses it to split an insertion at a comment's end. */
|
|
352
|
+
nextAnnotationId(): number;
|
|
289
353
|
/**
|
|
290
354
|
* Text inserted at `at` as a `w:ins`. A run of this author's own that is already inside a
|
|
291
355
|
* `w:ins` is extended rather than nested in another one, as Word does. `anchor` is the `w:del`
|
|
292
356
|
* of a replacement, which the insertion must follow.
|
|
293
357
|
*/
|
|
294
358
|
private insertTracked;
|
|
359
|
+
/**
|
|
360
|
+
* An insertion put at `at`, `before` and `after` being the segments either side of it once the runs
|
|
361
|
+
* are split there: never inside another's revision.
|
|
362
|
+
*/
|
|
363
|
+
private placeInsertion;
|
|
295
364
|
/**
|
|
296
365
|
* Splits runs so that every run holding text in [start, end) holds nothing else, and returns
|
|
297
366
|
* the segments inside the span. `splitAt` does the `w:t` boundaries; this also moves the items
|
|
@@ -303,4 +372,5 @@ export declare class Paragraph {
|
|
|
303
372
|
/** Moves the items after `seg` into a run of their own, behind `seg`'s run. */
|
|
304
373
|
private splitRunAfter;
|
|
305
374
|
}
|
|
375
|
+
type RevisionHolderOf = NonNullable<TextSegment['revision']>;
|
|
306
376
|
export { W_NS };
|